当前位置: 首页 > news >正文

手机网站建设公司排名wordpress chastity

手机网站建设公司排名,wordpress chastity,找地推平台,商标查询入口官网在前面的两篇博客中#xff0c;我已实现了一个FPS游戏的大部分功能#xff0c;包括了第一人称的主角运动控制#xff0c;武器射击以及敌人的智能行为。这里我将继续完善这个游戏#xff0c;包括以下几个方面#xff1a; 增加一个真实的游戏场景#xff0c;模拟一个废弃的…在前面的两篇博客中我已实现了一个FPS游戏的大部分功能包括了第一人称的主角运动控制武器射击以及敌人的智能行为。这里我将继续完善这个游戏包括以下几个方面 增加一个真实的游戏场景模拟一个废弃的工厂环境完善NPC的智能行为增加巡逻警戒躲避战术编队等行为。增加子弹与场景物体交互的效果。游戏道具的拾取。完善UI界面增加场景的任务描述任务完成或失败的判定展示。 以下是完成后的演示。 mission_critical 游戏场景设计 这是一个很大的课题暂时不是我关注的重点为此我先直接采用Unity商店的一个免费的资源RPG/FPS Game Assets for PC/Mobile (Industrial Set v2.0) | 3D 工业场景 | Unity Asset Store。 NPC智能行为 在之前的博客已经实现了NPC的部分智能行为包括了随机搜索以及跟踪玩家的行为。在这里我将添加巡逻警戒躲藏、战术编队等行为。 巡逻警戒 首先是实现巡逻功能这个可以通过定义巡逻路线经过的关键点然后利用Unity自带的寻路功能来实现。为此我们需要对场景的道路进行烘培点击Window-AI-Navigation然后选择Bake选项对场景的可导航路线进行烘培。烘培完成后需要给Enemy这个预制件增加一个NavMesh Agent的组件然后在代码中就可以指定目标点的坐标让Agent自己导航到目的地。 其次是增加警戒模式这个模式比较简单就是传入一个警戒点的坐标然后敌人就在警戒点不定期的随机搜索四周。以下是对WanderingAI的代码进行修改增加巡逻和警戒这两个行为 [Header(Enemy behavior)] ... public bool patrolBehavior false; public Vector3[] patrolPoints null; public bool guardBehavior false; public float guardAngle 60f; public float guardMaxRotatePeriod 10.0f; public float initialGuardAngle 0f;private long _guardTS 0; private float _guardChangeTime 0;[Flags] private enum EnemyStatus { ...Patrol,Guard }void Start() {_animator GetComponentAnimator();muzzleEffect GetComponentMuzzleEffect();_agent GetComponentNavMeshAgent();currentAmmo ammo;if (patrolBehavior patrolPoints.Length 2) {status EnemyStatus.Patrol;_agent.autoBraking false;_agent.destination patrolPoints[destPoint];transform.forward patrolPoints[destPoint] - patrolPoints[0];_animator.SetTrigger(E_Walk);} else if (guardBehavior) {status EnemyStatus.Guard;transform.localEulerAngles new Vector3(0f, initialGuardAngle, 0f);_guardTS DateTime.UtcNow.Ticks;_guardChangeTime UnityEngine.Random.Range(1.0f, guardMaxRotatePeriod);_animator.SetTrigger(E_Guard);} else {status EnemyStatus.Idle;} }// Update is called once per frame void Update() { if (status EnemyStatus.AimLeft || status EnemyStatus.AimRight) {AimMove();} else if (status EnemyStatus.Reload || status EnemyStatus.Death) {return;} else if (status EnemyStatus.Aim) {TurnToPlayer();} else if (status EnemyStatus.Hide) {Hide();} else if (status EnemyStatus.Damage) {TurnToDamage();if (!_animator.GetBool(E_IsDamage)) {status EnemyStatus.Idle;prevPlayerPosition new Vector3(100f, 100f, 100f);}} else {if (status EnemyStatus.Walk) {Walk();}if (status EnemyStatus.Sprint) {Sprint();}if (status EnemyStatus.Patrol) {Patrol();}if (status EnemyStatus.Guard) {Guard();}DetectPlayer();} }void Patrol() {if (!_agent.pathPending _agent.remainingDistance 0.5f) {Vector3 prevPosition patrolPoints[destPoint];destPoint (destPoint 1) % patrolPoints.Length;_agent.destination patrolPoints[destPoint];transform.forward patrolPoints[destPoint] - prevPosition;} }public void SetPatrolPoints(Vector3[] points) {patrolPoints points; }private void Guard() {float interval (DateTime.UtcNow.Ticks - _guardTS)/10000000.0f;if (interval _guardChangeTime) {_guardTS DateTime.UtcNow.Ticks;_guardChangeTime UnityEngine.Random.Range(1.0f, guardMaxRotatePeriod);float rotateAngle UnityEngine.Random.Range(-guardAngle, guardAngle);transform.localEulerAngles new Vector3(0f, initialGuardAngle rotateAngle, 0f);} } 从以上代码可以看到要设定敌人的行为是巡逻需要传入巡逻点的坐标然后依次把巡逻点的坐标设置为Agent的目的地即可在巡逻的过程中敌人同样需要检测玩家如果发现玩家则改变为瞄准行为这个和之前的随机搜索的行为切换是保持一致的。当行为是警戒时将随机不定时的转动一些角度来探测玩家。 装弹躲藏 进一步改进敌人在交战时的行为当敌人打完子弹时现在的行为是站定了换子弹为了提高难度我们可以设计当敌人打完子弹自动跑到一些隐藏点来重新装弹之后再出来和玩家交战。为此我们需要设计一些隐藏点。我采取的方法是在场景中选取一些隐藏点在每个地点放置一个小的正方体Game Object然后在游戏装载场景时读取这些Game Object的坐标然后把这些Object都设置为SetActive(false)进行隐藏把这些坐标传给敌人然后当需要跑去隐藏点时判断距离最近并且不被玩家发现的隐藏点并自动导航。代码改动如下 private Vector3[] _hidePoints;private enum EnemyStatus { ...Hide }public void SetHidePoints(ListVector3 points) {_hidePoints points.ToArray(); }private void Shoot() {if (currentAmmo0) {Hide();return;}... }private Vector3 FindNearestHidePoint() {GameObject player GameObject.Find(Player);Vector3 playerPosition player.transform.position;float distance 0f;Vector3 selectedPosition Vector3.up;RaycastHit info new RaycastHit();int layermask LayerMask.GetMask(Character, Default);for (int i0;i_hidePoints.Length;i) {Vector3 hidePosition _hidePoints[i];float tempDistance (transform.position - hidePosition).magnitude;if (tempDistance eyeviewDistance) {continue;} else {float playerDistance (playerPosition - hidePosition).magnitude;if (tempDistance playerDistance) {continue;} else {Physics.Raycast(hidePositionVector3.up, playerPosition - hidePosition - Vector3.up, out info, eyeviewDistance, layermask);if (info.collider.name Player) {continue;} else {if (distance 0 || tempDistance distance) {distance tempDistance;selectedPosition hidePosition;}}}}}return selectedPosition; }private void Hide() {if (status EnemyStatus.Hide) {if (!_agent.pathPending _agent.remainingDistance 0.1f) {_agent.isStopped true;if (currentAmmo 0) {status EnemyStatus.Reload;corReload StartCoroutine(Reload());}} else {return;}} else {Vector3 hidePoint FindNearestHidePoint();if (hidePoint ! Vector3.up) {transform.forward hidePoint - transform.position;_agent.isStopped false;_agent.destination hidePoint;_agent.speed sprintSpeed;status EnemyStatus.Hide;_animator.SetTrigger(E_Sprint);} else {status EnemyStatus.Reload;corReload StartCoroutine(Reload());}} } 听觉识别 当射击开火时可以设置在某个范围内的敌人会识别声音的方向并跑到交火的位置附近进行增援。 修改WanderingAI的代码增加一个方法 public void HearShoot(Vector3 position) {if (status EnemyStatus.Walk || status EnemyStatus.Idle || status EnemyStatus.Patrol) {status EnemyStatus.Sprint;_agent.destination position;_agent.isStopped false;_animator.SetTrigger(E_Sprint);_agent.updateRotation true;} } 然后当玩家开火时我们可以检测在开火的某个范围内是否有敌人存在如果有则调用敌人的WanderingAI的HearShoot方法把玩家当前的坐标通知给敌人如果敌人当前处在空闲随机搜索或巡逻状态时则会切换为快跑状态快速跑到玩家位置进行攻击。 修改玩家的PlayerController的代码在Shoot函数中增加以下部分 [Header(Notify enemy)] public float soundDistance 30.0f;private void Shoot() {if (_input.shoot _currentBulletVolume0) {if (!_animator.GetBool(IsReload)) {long nowTS DateTime.UtcNow.Ticks;float shootInterval (nowTS - _input.shootPressTS)/10000000.0f;if (shootInterval 0.08 || _input.firstShoot) {_animator.SetTrigger(Shoot);bullet Instantiate(bulletPrefab, _muzzle.position, _muzzle.rotation);bullet.GetComponentRigidbody().velocity _muzzle.forward * 800.0f;casing Instantiate(casingPrefab, _eject.position, _eject.rotation);muzzleEffect.Effect(_muzzle.position);_input.shootPressTS nowTS;_input.firstShoot false;_currentBulletVolume--;ExecuteEvents.ExecuteIGameMessage(_gameManager, null, (x,y)x.ArmoMessage(_currentBulletVolume));// Simulate the enemy can hear the shoot sound_spottedEnemies Physics.OverlapSphere(transform.position, soundDistance, LayerMask.GetMask(Enemy));for (int i0;i_spottedEnemies.Length;i) {WanderingAI behavior _spottedEnemies[i].gameObject.GetComponentWanderingAI();behavior.HearShoot(transform.position);}}} } } 战术组队 考虑最简单的一种三角形编队即领队走在最前面后面另外两个人和领队呈三角形分布。当发现玩家时即采取包抄的战术。 对WanderingAI代码改动一下增加和编队相关的几个属性 [Header(Enemy Role)] public bool formation false; public int formationType 0; // formation type 0: triangle public int roleId 0; // role 0: leader, 1: left follower, 2: right follower public float followDistance 5.0f; // How far the follower behind the leaderprivate GameObject _leader; private Vector3 _adjustFormationDistance; private ListGameObject _teamMembers new ListGameObject();public void SetLeader(GameObject leader) {_leader leader; }public void AddMember(GameObject member) {_teamMembers.Add(member); } 如果设置了formation为true那么即表示这个NPC处于编队状态formationType控制不同的编队类型当前只实现三角形编队roleID为0表示这个NPC是领队领队初始行为是随机搜索其他roleID的NPC是队员需要跟着领队因此设置了一个followDistance来设置其跟随领队的距离。_adjustFormationDistance用于根据followDistance来生成一个Vector3向量进行距离调整。如果NPC是领队那么需要保存队员的GameObject到一个list中如果NPC是队员那么需要保存领队的GameObject这样可以方便互相之间的通讯。 增加一个新的状态值用于表示队员NPC是否处于跟随队长的状态 [Flags] private enum EnemyStatus { ...FollowLeader } 在Start函数中对formation状态进行初始化设置 if (formation) {status EnemyStatus.Walk;_animator.SetTrigger(E_Walk);_adjustFormationDistance new Vector3(followDistance, 0f, 0f); } 初始设置编队时我们可以通过初始化NPC的坐标来保持三角形编队但是当后续游戏进行时如果队员遇到障碍物时需要避让障碍物之后仍能保持队形。我采取一个简便的方法来解决这个问题那就是让队员遇到障碍物时去到队长当前的位置而不是随机转向之后再重新调整队员位置使得能维持队形。 重新修改Walk方法并新增一个FollowLeader的方法代码如下 void Walk() {if (sprintTS ! 0) {long nowTS DateTime.UtcNow.Ticks;float interval (nowTS - sprintTS)/10000000.0f;if (interval sprintSearchPeriod) {sprintTS 0;}}float distance DetectObstacle(transform.forward);if (distance obstacleRange) {// For NPC if not the leader, should not random rotate, need to follow to the current leader position.if (formation roleId ! 0 _leader) {_agent.destination _leader.transform.position;_agent.isStopped false;status EnemyStatus.FollowLeader;return;} else {float angle;if (sprintTS 0) {angle UnityEngine.Random.Range(-randomAngle, randomAngle);} else {angle UnityEngine.Random.Range(-sprintSearchAngle, sprintSearchAngle);}transform.Rotate(0, angle, 0);}}if (formation roleId ! 0 _leader) {float angle Vector3.Angle(_leader.transform.forward, _leader.transform.position - transform.position);if (angle 30) {transform.forward _leader.transform.forward;}}transform.Translate(0, 0, speed * Time.deltaTime); }void FollowLeader() {if (_agent.remainingDistance 0.5f) {_agent.isStopped true;randomSearch true;_animator.SetTrigger(E_Walk);status EnemyStatus.Walk;// ReformationVector3 direction;if (roleId 1) {direction _leader.transform.position - _adjustFormationDistance - transform.position;} else {direction _leader.transform.position _adjustFormationDistance - transform.position;}transform.forward direction;} else {FaceTarget();} } 当队员遇到障碍时设置状态为FollowLeader并且通过NavmeshAgent自动导航到队长当前位置。当处于FollowLeader状态时如果接近队长位置则重新调整方向设置状态为Walk然后在Walk方法中判断队员与队长的方向的夹角和距离如果满足条件则重新调整方向使得重新维持队形不变。 最后就是考虑到当队长NPC挂掉时要通知队员解散编队为此定义一个Deformation方法 public void DeFormation() {foreach (GameObject _member in _teamMembers) {if (_member) {WanderingAI _behavior _member.GetComponentWanderingAI();_behavior.formation false;_behavior.roleId 0;}} } 考虑到当前游戏场景的位置比较狭小不方便队员在发现玩家时进行包抄所以暂时不添加更多的战术功能只实现一个编队搜索。 子弹与场景物体的交互 为了使游戏更真实我们可以让子弹在射击到水泥墙面或者金属物体时产生碰撞效果和留下弹痕当射击到油罐之类的物体时可以引爆油罐。 下面来实现子弹撞击物体的效果。 模拟灰尘溅射 首先是模拟子弹撞击水泥物体之后产生的灰尘溅射。在Asset的Texture目录下导入一张灰尘的图片设置里面要勾选Alpha is Transparancy。例如下图 在Asset的Material目录下新建一个material文件命名为M_Smoke。Shader选择Particles/Standard SurfaceRendering mode选择Fade。Main Option勾选Two Sided和Camera Fading。把刚才导入的材质贴图拖动到Maps的Albedo贴图中。这样就定义好材质了。 新建一个空的GameObject命名为Impact Effect保存为Prefab然后进行编辑。 新增一个子物体命名为Concrete Effect添加一个Particle System的Component具体设置如下 模拟弹孔 在Asset的Texture目录导入一张弹孔的图片作为Texture如下图 在Asset的Material目录新建一个材质文件命名为M_Impact_Concreteshader选择Legacy Shaders/Particles/VertexLit Blended然后把之前新建的Texture拖动到Particle Texture中。 在Impact Effect这个Prefab下新建一个子物体命名为Bullet Hole新建一个Particle System的Component设置如下 模拟水泥碎片 同样是找一个水泥碎片的图片导入到Asset的Texture目录中如下图 然后同样是新建一个材质如之前弹孔的操作步骤。 在Impact Effect这个Prefab下新建一个子物体命名为Concrete Debris添加Particle system配置如下 代码实现 最后就是在Impact Effect这个Prefab上新增一个脚本代码播放声音以及控制多长时间销毁代码如下 public class Impact : MonoBehaviour {[Header(Impact Despawn Timer)]//How long before the impact is destroyedpublic float despawnTimer 10.0f;[Header(Audio)]public AudioClip[] impactSounds;public AudioSource audioSource;// Start is called before the first frame updatevoid Start(){StartCoroutine (DespawnTimer ());//Get a random impact sound from the arrayaudioSource.clip impactSounds[Random.Range(0, impactSounds.Length)];//Play the random impact soundaudioSource.Play();}// Update is called once per framevoid Update(){}private IEnumerator DespawnTimer() {//Wait for set amount of timeyield return new WaitForSeconds (despawnTimer);//Destroy the impact gameobjectDestroy (gameObject);} } 编辑Bullet的脚本文件增加以下代码 ... [Header(Impact Effect Prefabs)] public Transform [] concreteImpactPrefabs;private void OnCollisionEnter(Collision collision) {...if (collision.gameObject.CompareTag(Concrete)) {//Instantiate random impact prefab from arrayInstantiate (concreteImpactPrefabs [0], transform.position, Quaternion.LookRotation (collision.contacts [0].normal));//Destroy bullet objectDestroy(gameObject);}... } 然后我们把场景中的水泥墙的预制件的Tag都设置为Concrete这样当子弹发射碰撞到水泥墙时就能看到相应的效果了。 实现爆炸效果 当子弹打中油桶之类的物体时可以触发爆炸效果。 首先需要制作油桶爆炸后分成的碎块效果可以通过Blender来实现。 把模型导入到Blender然后安装Cell Fracture插件选择物体-快速效果-Cell Fracture调整Souce Limit的数值这个表示物体破碎为多少块这样插件就会自动进行随机的破碎然后我们只保留破碎后的物体即可导出为FBX格式。如下图所示 由于油桶为空心物体现在这样制作的爆炸碎片是实心的为了进一步改进我们可以复制多一个油桶物体稍微缩小一点然后放置在原来油桶里面通过Blender的Object Bool Tool插件来进行布尔差值切割这样就能制作一个空心的油桶了然后再进行Cell Fracture效果更好。 把导出的模型添加到Assets-Models目录然后拖动到场景再拖动到Assets-Prefabs目录保存为一个Prefab。需要注意这个Prefab下的所有碎片子物体需要全部添加Rigidbody组件并且不要勾选Kinematic。如果我们希望破碎后保留这些碎片那么还需要增加Mesh Collider组件并勾选Vertex不然的话破碎之后时看不到这些碎片的。 为了实现爆炸的粒子效果我们可以下载Unity Asset Store里面的Particle Pack插件里面提供了很多效果的粒子系统实现非常好用。 对于原始的未爆炸的油桶Prefab为其新增一个Explode的Tag并且添加一个名为Debris的脚本文件代码如下 public class Debris : MonoBehaviour {public GameObject Explosive_debris;// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){}public void OnDestroy(){GameObject o Instantiate(Explosive_debris, transform.position, transform.rotation);o.GetComponentExplode().Explodsion();Destroy(gameObject);} } 然后把我们刚才制作的爆炸后的油桶Prefab拖动到这个Script的Explosive_debris中。 在新的爆炸后的油桶Prefab上新增一个名为Explode的脚本文件代码如下 public class Explode : MonoBehaviour {public GameObject explodeEffect;public float force 500f;public float radius 5f;public float destroyAfter 2f;// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){}public void Explodsion() {StartCoroutine(PlayExplodeEffect ());var rbs GetComponentsInChildrenRigidbody();foreach(var rb in rbs) {rb.AddExplosionForce(1000f, transform.position, 10f);}}private IEnumerator PlayExplodeEffect () {GameObject o Instantiate(explodeEffect, transform.position, transform.rotation);yield return new WaitForSeconds (destroyAfter);Destroy(o);} } 然后把Particle Pack的BigExplosion拖动到这个Script的explosionEffect中。 最后就是修改一下Bullet的脚本文件代码如下 private void OnCollisionEnter(Collision collision) {...if (collision.gameObject.CompareTag(Explode)) {Debris dest collision.gameObject.GetComponentDebris();if (dest ! null) {dest.OnDestroy();}}Destroy(this.gameObject); } 现在爆炸的效果就制作好了。  游戏道具的拾取 为了增加游戏的趣味性需要设计一些游戏道具例如医药包弹药等。 从网上找一个白色十字的3D模型作为医药包导入到Assets-Models目录然后保存为Prefab。 编辑这个Prefab添加Rigidbody和Box Collider组件其中Rigidbody需要勾选Is KinematicBox Collider需要勾选Is Trigger。 在Assets-Scripts目录新增一个Pickup的代码文件代码如下 [RequireComponent(typeof(Rigidbody), typeof(Collider))] public class Pickup : MonoBehaviour {[Tooltip(Frequency at which the item will move up and down)]public float VerticalBobFrequency 1f;[Tooltip(Distance the item will move up and down)]public float BobbingAmount 1f;[Tooltip(Rotation angle per second)] public float RotatingSpeed 360f;[Tooltip(Sound played on pickup)] public AudioClip PickupSfx;[Tooltip(VFX spawned on pickup)] public GameObject PickupVfxPrefab;public Rigidbody PickupRigidbody { get; private set; }Collider m_Collider;Vector3 m_StartPosition;bool m_HasPlayedFeedback;protected virtual void Start(){PickupRigidbody GetComponentRigidbody();m_Collider GetComponentCollider();// ensure the physics setup is a kinematic rigidbody triggerPickupRigidbody.isKinematic true;m_Collider.isTrigger true;// Remember start position for animationm_StartPosition transform.position;}void Update(){// Handle bobbingfloat bobbingAnimationPhase ((Mathf.Sin(Time.time * VerticalBobFrequency) * 0.5f) 0.5f) * BobbingAmount;transform.position m_StartPosition Vector3.up * bobbingAnimationPhase;// Handle rotatingtransform.Rotate(Vector3.up, RotatingSpeed * Time.deltaTime, Space.Self);}void OnTriggerEnter(Collider other){PlayerController pickingPlayer other.GetComponentPlayerController();if (pickingPlayer ! null){OnPicked(pickingPlayer);}}protected virtual void OnPicked(PlayerController playerController){PlayPickupFeedback();}public void PlayPickupFeedback(){if (m_HasPlayedFeedback)return;if (PickupSfx){//AudioUtility.CreateSFX(PickupSfx, transform.position, AudioUtility.AudioGroups.Pickup, 0f);}if (PickupVfxPrefab){var pickupVfxInstance Instantiate(PickupVfxPrefab, transform.position, Quaternion.identity);}m_HasPlayedFeedback true;} } 这个代码定义了所有道具的基本Pickup行为 对于医药包道具的Pickup除了基本行为之外还有个特殊的行为就是给玩家加血因此定义一个HealthPickup的代码如下: public class HealthPickup : Pickup {[Header(Parameters)] [Tooltip(Amount of health to heal on pickup)]public int HealAmount 2;protected override void OnPicked(PlayerController player) {player.Heal(HealAmount);Destroy(gameObject);} } 把这个代码添加到医药包Prefab上。 当玩家触碰到医药包时就会回调PlayerController脚本的Heal方法因此添加一个Heal方法代码如下 public void Heal(int point) {if (_healthpoint PlayerHealth) {_health PlayerHealth;} else {_health point;}float healthValue (float) _health/PlayerHealth;ExecuteEvents.ExecuteIGameMessage(_gameManager, null, (x,y)x.HealthMessage(healthValue)); } 之后我们可以实现一个木箱子的破碎效果当木箱子被打破后就会露出医药包。具体定义木箱子破碎的过程和之前的类似只是破碎效果不要选择爆炸而是DustExplodsion。 完善UI界面 任务简介 最后就是完善整个游戏的UI界面在游戏一开始增加任务介绍当任务完成或失败时展示相应的界面。 首先是增加任务简介在GameScreen这个Prefab下新建一个Text TMP命名为Task然后输入任务简介。编辑GameLevelLoader脚本文件增加代码如下 ... private long _startTick 0; private GameObject _task;void Start() {..._startTick DateTime.UtcNow.Ticks;_task GameObject.Find(GameScreen/Task); }void Update() {long nowTS DateTime.UtcNow.Ticks;float interval (nowTS - _startTick)/10000000.0f;if (interval 10f) {if (_task) {_task.SetActive(false);}} } 这个代码表示在游戏开始的头10秒显示这一关任务的简介。 任务完成或失败的场景显示 当这一关任务完成或失败时应该显示对应的场景。 在Assets-Scenes的目录下新建两个场景分别命名为WinScene和LoseScene每个场景都增加一个Canvas然后在Canvas下新增一个背景图片一个文字描述和一个按钮如下图所示 定义一个消息接口文件GameFlowMessage用来传递设定场景任务以及消灭敌人等消息的传递如以下代码 public interface IGameFlowMessage : IEventSystemHandler {void KillEnemyMessage();void FindTargetMessage();void SetObjectiveMessage(int killEnemyNumber, int findTargetNumber);void PlayerDeathMessage(); } 然后定义一个GameFlowController脚本文件实现以上接口的方法如以下代码 public class GameFlowController : MonoBehaviour, IGameFlowMessage {[Header(Win)] [Tooltip(This string has to be the name of the scene you want to load when winning)]public string WinSceneName WinScene;[Header(Lose)] [Tooltip(This string has to be the name of the scene you want to load when winning)]public string LoseSceneName LoseScene;private int _killEnemyNumber;private int _currentKillEnemy 0;private int _findTargetNumber;private int _currentFindTarget 0;public void KillEnemyMessage() {_currentKillEnemy;Debug.LogFormat(Kill Enemy, current:{0}, target:{1}, _currentKillEnemy, _killEnemyNumber);if (_currentKillEnemy _killEnemyNumber _currentFindTarget _findTargetNumber) {WinOrLose(true);}}public void FindTargetMessage() {_currentFindTarget;if (_currentKillEnemy _killEnemyNumber _currentFindTarget _findTargetNumber) {WinOrLose(true);}}public void SetObjectiveMessage(int killEnemyNumber, int findTargetNumber) {_killEnemyNumber killEnemyNumber;_findTargetNumber findTargetNumber;}public void PlayerDeathMessage() {WinOrLose(false);}public void WinOrLose(bool win) {Cursor.lockState CursorLockMode.None;Cursor.visible true;if (win) {SceneManager.LoadScene(WinSceneName);} else {SceneManager.LoadScene(LoseSceneName);}} } 把这个Script加到GameLoader这个GameObject上面然后编辑GameLevelLoader脚本设定这一关任务代码如下 ... private GameFlowController _gameFlowController;void Start() {..._gameFlowController GetComponentGameFlowController();_gameFlowController.SetObjectiveMessage(9, 0); } 修改NPC的WanderingAI代码当NPC被消灭时发送KillEnemyMessage代码如下 ... private GameObject _gameLoader;void Start() {..._gameLoader GameObject.Find(GameLoader); }private IEnumerator Death() {...ExecuteEvents.ExecuteIGameFlowMessage(_gameLoader, null, (x,y)x.KillEnemyMessage()); } 总结 以上就是一个FPS游戏的制作过程后续将继续完善玩家的换武器以及关卡的设计。
http://www.zqtcl.cn/news/745058/

相关文章:

  • 河北建设工程信息网站网站的建设要多少钱
  • 玉林住房和城乡建设局网站官网google广告在wordpress
  • 海淀网站建设公司wordpress 招聘网站模板
  • 手机网站在哪里找到网上能免费做网站发布叼
  • 网站设置英文怎么说广州优质网站建设案例
  • 外贸怎样做网站临汾花果街网站建设
  • 专业集团门户网站建设方案南昌医院网站建设
  • 用php做美食网站有哪些新建网站如何做关键词
  • 企业网站建设招标微信公众平台官网登录入口网页版
  • 网站宣传图网站程序预装
  • 网站设计论文选题seo排名优化推广报价
  • wordpress图床网站百度链接收录
  • 八年级信息网站怎么做电商网站的支付接入该怎么做呢
  • wordpress 的应用大兴安岭地网站seo
  • 网站建站作业做直播网站赚钱
  • 网站建设虍金手指花总简单免费制作手机网站
  • 京东网站是刘强冬自己做的吗献县网站建设价格
  • 余姚什么网站做装修比较好邢台企业做网站哪儿好
  • 网站建设后端国外购物平台排行榜前十名
  • 西安做百度推广网站 怎样备案简述商务网站建设
  • 如何建设本地网站东莞常平限电通知2021
  • 成都网站建设cdajcx重庆推广网站排名价格
  • 建网站的价格网店设计方案计划书
  • 长沙做公司网站如何制作个人网站教程
  • 做一个网站怎么做的仿qq网站程序
  • 曲靖市建设局网站官网织梦可以放两个网站
  • 网站建设方案ppt模板网站怎么做用户登录数据库
  • 做3d图的网站有哪些软件有哪些专业设计企业网站
  • 青海省wap网站建设公司做美工比较好的网站
  • 1个云虚拟主机怎么做多个网站网站规划与建设实验心得