1 游戏要求

1.1 游戏设计要求:

  • 创建一个地图和若干巡逻兵(使用动画);
  • 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址。即每次确定下一个目标位置,用自己当前位置为原点计算;
  • 巡逻兵碰撞到障碍物,则会自动选下一个点为目标;
  • 巡逻兵在设定范围内感知到玩家,会自动追击玩家;
  • 失去玩家目标后,继续巡逻;
  • 计分:玩家每次甩掉一个巡逻兵计一分,与巡逻兵碰撞游戏结束;

1.2 程序设计要求:

  • 必须使用订阅与发布模式传消息

    • subject:OnLostGoal
    • Publisher: ?
    • Subscriber: ?
  • 工厂模式生产巡逻兵

1.3 友善提示1:生成 3~5个边的凸多边型

  • 随机生成矩形
  • 在矩形每个边上随机找点,可得到 3 - 4 的凸多边型
  • 5 ?

1.4 友善提示2:参考以前博客,给出自己新玩法

2 项目资源

代码资源

演示视频

3 游戏截图

游戏开始,显示10s游戏规则:(游戏规则为方向盘控制前进,左右旋转,前后移动,成功躲避巡逻兵追捕一次加1分,采集完所有的金矿即可获胜,滚轮可以实现镜头缩进和拉远,按着鼠标右键可以实现视角转动)

可以通过鼠标滚轮实现镜头缩进和拉远,按着鼠标右键实现视角转动,来观察游戏全貌

被巡逻兵抓住,游戏失败:

找到所有的金矿,游戏成功:

4 项目配置

下载代码资源(见上)地址中的Assets,新建unity3D项目,将下载的Assets文件夹替换掉新建项目的中的Assets文件夹,选择AssetsScenes文件夹下的myScenes场景,点击运行按钮,即可开始游戏。

5 架构设计

6 创建预制

6.1 导入资源

创建一个地图和若干巡逻兵,可以先到unity资源商店中,在角色和环境大类中挑选出免费的且符合要求的资源,如下:


在unity中下载并导入到项目中。

6.2 创建预制

利用导入的资料包中的Prefabs文件夹下的预制,制作出我们所需要的人物和地图,拉到Resources/Prefabs下,并对其进行命以游戏中的名称,方便我们调用。

6.2.1 地图

地图制作如下:

出来调整大小以及对地图内部加入木块进行隔离外,为了对实现对碰撞的监测,我们需要加入Mesh Collider.

该场景中有9个格子,每个格子为一个区域,每个区域设置了一个BoxCollider用于检测玩家是否进入该区域。

6.2.2 金矿

同理,为了对实现对碰撞的监测,我们需要加入Mesh Collider.对is Trigger进行打勾,脚本要根据玩家碰撞到该金矿,进行相应的动作。

6.2.3 巡逻兵和玩家

巡逻兵如下:

玩家如下:

请添加图片描述
其中为了使得人物具有具有使用物理引擎和碰撞检测的能力,我们需要为巡逻兵和玩家预制添加RigidbodyCapsule Collider两个部件;

Rigidbody需要对Freeze Rotation各个方向进行打勾,这样但人物发生碰撞时,就不会因为有转动力而一直保持选择了;

Capsule Collider需要调整组件中的RadiusHeight两个属性使得人物外围的球形边框与之大致重合,因为这代表人物的碰撞检测范围。

对于巡逻兵我们还需要点击Hips,添加Box Collider组件,改变Size来改变框的大小,并在is Trigger的方框后面打勾,这是用来作为巡逻兵的检测范围,一旦玩家进入该范围,巡逻兵就追逐他。

6.3 动画器预制

在Assets文件夹中新建一个AnimatorController文件夹,创建PatrolControllerPlayerController两个Animator Controller
动画器从导入的资源包中的Animations文件夹下查找

6.3.1 PatrolController

按照游戏设计,对于巡逻兵,我们需要他在游戏未开始时候静止,在游戏开始时候巡逻,在玩家进入巡逻范围时,追逐玩家,在追到玩家的时候,对玩家进行攻击,因此我们只需要idlerunattack三个动画,做出来的PatrolController如下:

对于巡逻兵各个动作之间的切换,通过变量来触发,设计布尔变量run,以及Trigger类型变量shoot

runflase的时候,巡逻兵静止(动作为idle),当runtrue时候,巡逻兵奔跑(动作为run),当shoot变量呗触发的时候,巡逻兵发动攻击(动作为attack)。

设置方法如下,以巡逻兵从静止(idle)到奔跑(run)的触发设置为例,点击动作器图中idle指向run的白色箭头,出现以下画面,添加指定的conditions,调整settings中的时间条,调整为自己想要的转换动画效果。其他的动作转变设置同理。

6.3.2 PlayerController

按照游戏设计,对于玩家,我们需要他在游戏未开始时候静止,在游戏开始时候run,在被巡逻兵追到的时候,倒地(die),因此我们只需要idle,run和die三个动画,做出来的PatrolController如下:

对于巡逻兵各个动作之间的切换,通过变量来触发,设计布尔变量run,以及Trigger类型变量death

当run为flase的时候,玩家静止(动作为idle),当run为true时候,玩家兵奔跑(动作为run),当death变量被触发的时候,玩家倒地(动作为die)。

动作转变的设置方法和上面是相同的,这里就不重复介绍了。

6.4 挂载脚本

为了在玩家,巡逻兵,金矿,每个区域检测到碰撞,程序作出相应的反应,我们需要分别在上面挂载脚本PlayerCollide,PatrolCollide,GoldmineCollideAreaCollide

其次为了记录巡逻兵地属性,我们需要分别巡逻兵在上面挂载脚本PatrolData

这些脚本将在下面的模块介绍中展开说明。

7 模块介绍

7.1 碰撞脚本

7.1.1 PlayerCollide

当玩家与侦察兵相撞,触发玩家的death变量,使玩家倒地,触发巡逻兵的shoot变量,使巡逻兵发动攻击,调用PlayerGameover表示游戏结束。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PlayerCollide : MonoBehaviour
{void OnCollisionEnter(Collision other){//当玩家与侦察兵相撞if (other.gameObject.tag == "Player"){//触发玩家的death变量,使玩家倒地other.gameObject.GetComponent<Animator>().SetTrigger("death");//触发巡逻兵的shoot变量,使巡逻兵发动攻击this.GetComponent<Animator>().SetTrigger("shoot");//游戏结束Singleton<GameEventManager>.Instance.PlayerGameover();}}
}

7.1.2 PatrolCollide

  • 当玩家进入侦察兵追捕范围,启动追捕模式,并将追捕对象设置为玩家,开始追捕
  • 玩家跑出侦察兵追捕范围,关闭追捕模式,将追捕对象设置为空,结束追捕
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PatrolCollide : MonoBehaviour
{void OnTriggerEnter(Collider collider){//玩家进入侦察兵追捕范围,开始追捕if (collider.gameObject.tag == "Player"){//启动追捕模式this.gameObject.transform.parent.GetComponent<PatrolData>().follow_player = true;//将追捕对象设置为玩家this.gameObject.transform.parent.GetComponent<PatrolData>().player = collider.gameObject;}}void OnTriggerExit(Collider collider){//玩家跑出侦察兵追捕范围,结束追捕if (collider.gameObject.tag == "Player"){//关闭追捕模式this.gameObject.transform.parent.GetComponent<PatrolData>().follow_player = false;//将追捕对象设置为空this.gameObject.transform.parent.GetComponent<PatrolData>().player = null;}}
}

7.1.3 GoldmineCollide

当玩家与金矿相撞,设置金矿消失并减少金矿数量

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class GoldmineCollide : MonoBehaviour
{//当玩家与金矿相撞void OnTriggerEnter(Collider collider){if (collider.gameObject.tag == "Player" && this.gameObject.activeSelf){//设置金矿消失this.gameObject.SetActive(false);//减少金矿数量Singleton<GameEventManager>.Instance.ReduceGoldmineNum();}}
}

7.1.4 AreaCollide

当玩家进入该区域的时候,通过调用sceneController.wall_sign = sign;设置场景控制器的区域标识为自己的标识,这样巡逻兵就知道玩家现在在哪个区域了

public class AreaCollide : MonoBehaviour
{public int sign = 0;FirstSceneController sceneController;private void Start(){sceneController = SSDirector.GetInstance().CurrentScenceController as FirstSceneController;}void OnTriggerEnter(Collider collider){//标记玩家进入自己的区域if (collider.gameObject.tag == "Player"){sceneController.wall_sign = sign;}}
}

7.2 工厂模块

7.2.1 PropFactory

  • 在每个格子内分别创建了1个巡逻兵,还设置了每个巡逻兵所在区域的标志。

  • 随机生成十二个金矿,每个格子可能有多个金矿,也可能只有一个

  • 当游戏结束时候,需要工厂将巡逻兵的动画设置为初始状态。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PropFactory : MonoBehaviour
{private GameObject patrol = null;                              //巡逻兵private List<GameObject> usedPatrol = new List<GameObject>();        //正在被使用的巡逻兵private GameObject goldmine = null;                             //金矿private List<GameObject> usedgoldmine = new List<GameObject>();      //正在被使用的金矿//在每个格子内分别创建了1个巡逻兵public List<GameObject> GetPatrols(){int[] pos_x = { -6, 4, 13 };int[] pos_z = { -4, 6, -13 };int index = 0;//生成不同的巡逻兵初始位置for (int i = 0; i < 3; i++){for (int j = 0; j < 3; j++){Vector3 vec = new Vector3(pos_x[i], 0, pos_z[j]);patrol = Instantiate(Resources.Load<GameObject>("Prefabs/Patrol"));patrol.transform.position = vec;patrol.GetComponent<PatrolData>().sign = index + 1;patrol.GetComponent<PatrolData>().start_position = vec;usedPatrol.Add(patrol);index++;}}return usedPatrol;}//随机生成十二个金矿public List<GameObject> GetGoldmine(){float range = 12;                                      //金矿生成的坐标范围for (int i = 0; i < 12; i++){goldmine = Instantiate(Resources.Load<GameObject>("Prefabs/Goldmine"));float ranx = Random.Range(-range, range);float ranz = Random.Range(-range, range);goldmine.transform.position = new Vector3(ranx, 0, ranz);usedgoldmine.Add(goldmine);}return usedgoldmine;}public void StopPatrol(){int size = usedPatrol.Count;//切换所有侦查兵的动画for (int i = 0; i < size; i++){usedPatrol[i].gameObject.GetComponent<Animator>().SetBool("run", false);}}
}

7.2.2 PatrolData

成员变量如下:

    public int sign;                      //标志巡逻兵在哪一块区域public bool follow_player = false;    //是否跟随玩家public int wall_sign = -1;            //当前玩家所在区域标志public GameObject player;             //玩家游戏对象public Vector3 start_position;        //当前巡逻兵初始位置

7.3 订阅与发布模式

在订阅与发布模式中订阅者没必要知道和功能调用有关的类,只需要知道发布者即可;
而发布者调用对应的方法来进行实际操作,使用这种模式来降低代码的耦合度。

在该程序中,GameEventManager作为发布者,FirstSceneController作为订阅者。

7.3.1 GameEvenManager

作为发布者GameEventManager主要负责三个动作,分数变化、游戏结束、水晶数目

public class GameEventManager : MonoBehaviour
{//分数变化public void PlayerEscape(){if (ScoreChange != null){ScoreChange();}}//游戏结束public void PlayerGameover(){if (GameoverChange != null){GameoverChange();}}//水晶数量public void ReduceCrystalNum(){if (CrystalChange != null){CrystalChange();}}
}

7.3.2 FirstSceneController

作为订阅者,订阅了GameEventManager中的事件,因此只要相应事件发生,就会导致场景控制器调用注册的方法。

void OnEnable()
{//注册事件GameEventManager.ScoreChange += AddScore;GameEventManager.GameoverChange += Gameover;GameEventManager.CrystalChange += ReduceCrystalNumber;
}
void OnDisable()
{//取消注册事件GameEventManager.ScoreChange -= AddScore;GameEventManager.GameoverChange -= Gameover;GameEventManager.CrystalChange -= ReduceCrystalNumber;
}
void ReduceCrystalNumber()
{recorder.ReduceCrystal();
}
void AddScore()
{recorder.AddScore();
}
void Gameover()
{game_over = true;patrol_factory.StopPatrol();action_manager.DestroyAllAction();
}

7.4 动作管理模块

7.4.1 SSActionManager

动作管理器SSActionManager需要控制巡逻兵的动作,使用列表管理巡逻兵追踪或者巡逻,代码和注释如下:


public class SSActionManager : MonoBehaviour, ISSActionCallback
{private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();    //将执行的动作的字典集合private List<SSAction> waitingAdd = new List<SSAction>();                       //等待去执行的动作列表private List<int> waitingDelete = new List<int>();                              //等待删除的动作的key                protected void Update(){//对于等待执行的动作列表,将其添加到执行动作列表中,并将等待列表清空foreach (SSAction ac in waitingAdd){actions[ac.GetInstanceID()] = ac;}waitingAdd.Clear();//对于执行动作列表中的每一个动作,如果动作需要销毁则加入待删除列表中,相反则进行该动作foreach (KeyValuePair<int, SSAction> kv in actions){SSAction ac = kv.Value;if (ac.destroy){waitingDelete.Add(ac.GetInstanceID());}else if (ac.enable){//运动学运动更新ac.Update();}}//对于等待删除列表中的动作,将其在执行列表中删除,并销毁该动作对象。foreach (int key in waitingDelete){SSAction ac = actions[key];actions.Remove(key);DestroyObject(ac);}waitingDelete.Clear();}public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager){//建立动作并将动作添加到等待执行列表中action.gameobject = gameobject;action.transform = gameobject.transform;action.callback = manager;waitingAdd.Add(action);action.Start();}public void SSActionEvent(SSAction source, int intParam = 0, GameObject objectParam = null){if(intParam == 0){//巡逻兵跟随玩家PatrolFollowAction follow = PatrolFollowAction.GetSSAction(objectParam.gameObject.GetComponent<PatrolData>().player);this.RunAction(objectParam, follow, this);}else{//巡逻兵继续巡逻GoPatrolAction move = GoPatrolAction.GetSSAction(objectParam.gameObject.GetComponent<PatrolData>().start_position);this.RunAction(objectParam, move, this);//玩家离开Singleton<GameEventManager>.Instance.PlayerEscape();}}public void DestroyAll(){foreach (KeyValuePair<int, SSAction> kv in actions){SSAction ac = kv.Value;ac.destroy = true;}}
}

7.4.2 PatrolActionManager

场景控制器调用PatrolActionManager中的方法,让巡逻兵开始巡逻,当游戏结束的时候,调用方法让巡逻兵停止巡逻

public class PatrolActionManager : SSActionManager
{private GoPatrolAction go_patrol;                            //巡逻兵巡逻public void GoPatrol(GameObject patrol){go_patrol = GoPatrolAction.GetSSAction(patrol.transform.position);this.RunAction(patrol, go_patrol, this);}//停止所有动作public void DestroyAllAction(){DestroyAll();}
}

7.4.3 PatrolFollowAction

巡逻兵追逐玩家,当玩家离开了巡逻兵触发器的范围或是玩家已经不在该区域内了,巡逻兵停止追逐

public class PatrolFollowAction : SSAction
{private float speed = 2f;            //跟随玩家的速度private GameObject player;           //玩家private PatrolData data;             //侦查兵数据private PatrolFollowAction() { }public static PatrolFollowAction GetSSAction(GameObject player){PatrolFollowAction action = CreateInstance<PatrolFollowAction>();action.player = player;return action;}public override void Update(){if (transform.localEulerAngles.x != 0 || transform.localEulerAngles.z != 0){transform.localEulerAngles = new Vector3(0, transform.localEulerAngles.y, 0);}if (transform.position.y != 0){transform.position = new Vector3(transform.position.x, 0, transform.position.z);}Follow();//如果侦察兵没有跟随对象,或者需要跟随的玩家不在侦查兵的区域内if (!data.follow_player || data.wall_sign != data.sign){this.destroy = true;this.callback.SSActionEvent(this,1,this.gameobject);}}public override void Start(){data = this.gameobject.GetComponent<PatrolData>();}void Follow(){transform.position = Vector3.MoveTowards(this.transform.position, player.transform.position, speed * Time.deltaTime);this.transform.LookAt(player.transform.position);}
}

7.4.4 GoPatrolAction

巡逻兵巡逻,根据四个方向来选择要去到的目的地,当当前位置与目的地相差0.9f的时候,换一个方向继续巡逻

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class GoPatrolAction : SSAction
{private enum Dirction { EAST, NORTH, WEST, SOUTH };private float pos_x, pos_z;                  //移动前的初始x和z方向坐标private float move_length;                   //移动的长度private float move_speed = 1.2f;             //移动速度private bool Is_reach_des = true;            //是否到达目的地private Dirction dirction = Dirction.EAST;   //移动的方向private PatrolData patrol_data;              //侦察兵的数据private GoPatrolAction() { }public static GoPatrolAction GetSSAction(Vector3 location){GoPatrolAction action = CreateInstance<GoPatrolAction>();action.pos_x = location.x;action.pos_z = location.z;//设定移动矩形的边长action.move_length = Random.Range(5, 8);return action;}void Gopatrol(){if (Is_reach_des){switch (dirction){case Dirction.EAST:pos_x -= move_length;break;case Dirction.NORTH:pos_z += move_length;break;case Dirction.WEST:pos_x += move_length;break;case Dirction.SOUTH:pos_z -= move_length;break;}Is_reach_des = false;}this.transform.LookAt(new Vector3(pos_x, 0, pos_z));float distance = Vector3.Distance(transform.position, new Vector3(pos_x, 0, pos_z));//当前位置与目的地距离浮点数的比较if (distance > 0.9){transform.position = Vector3.MoveTowards(this.transform.position, new Vector3(pos_x, 0, pos_z), move_speed * Time.deltaTime);}else //转弯{dirction = dirction + 1;if (dirction > Dirction.SOUTH){dirction = Dirction.EAST;}Is_reach_des = true;}}public override void Update(){//侦察移动Gopatrol();//如果侦察兵需要跟随玩家并且玩家就在侦察兵所在的区域,侦查动作结束if (patrol_data.follow_player && patrol_data.wall_sign == patrol_data.sign){this.destroy = true;this.callback.SSActionEvent(this, 0, this.gameobject);}}public override void Start(){this.gameobject.GetComponent<Animator>().SetBool("run", true);patrol_data = this.gameobject.GetComponent<PatrolData>();}}

7.5 主控制模块

包括IUserAction, SSDirector, ISceneController, FristController

在牧师与魔鬼和Hit UFO都使用过,不展开介绍逻辑,FristController的代码如下:

public class FirstSceneController : MonoBehaviour, IUserAction, ISceneController
{public PropFactory patrol_factory;                               //巡逻者工厂public ScoreRecorder recorder;                                   //记录员public PatrolActionManager action_manager;                       //运动管理器public int wall_sign = -1;                                       //当前玩家所处哪个格子public GameObject player;                                        //玩家public Camera main_camera;                                       //主相机public float player_speed = 5;                                   //玩家移动速度public float rotate_speed = 250f;                                //玩家旋转速度private List<GameObject> patrols;                                //场景中巡逻者列表private List<GameObject> goldmines;                               //场景金矿列表private bool game_over = false;                                  //游戏结束void Update(){for (int i = 0; i < patrols.Count; i++){patrols[i].gameObject.GetComponent<PatrolData>().wall_sign = wall_sign;}//金矿收集完毕if(recorder.GetGoldmineNumber() == 0){Gameover();}}void Start(){SSDirector director = SSDirector.GetInstance();director.CurrentScenceController = this;patrol_factory = Singleton<PropFactory>.Instance;action_manager = gameObject.AddComponent<PatrolActionManager>() as PatrolActionManager;LoadResources();main_camera.GetComponent<CameraFlow>().follow = player;recorder = Singleton<ScoreRecorder>.Instance;}public void LoadResources(){Instantiate(Resources.Load<GameObject>("Prefabs/Plane"));player = Instantiate(Resources.Load("Prefabs/Player"), new Vector3(0, 9, 0), Quaternion.identity) as GameObject;goldmines = patrol_factory.GetGoldmine();patrols = patrol_factory.GetPatrols();//所有侦察兵移动for (int i = 0; i < patrols.Count; i++){action_manager.GoPatrol(patrols[i]);}}//玩家移动public void MovePlayer(float translationX, float translationZ){if(!game_over){if (translationX != 0 || translationZ != 0){player.GetComponent<Animator>().SetBool("run", true);}else{player.GetComponent<Animator>().SetBool("run", false);}//移动和旋转player.transform.Translate(0, 0, translationZ * player_speed * Time.deltaTime);player.transform.Rotate(0, translationX * rotate_speed * Time.deltaTime, 0);//防止碰撞带来的移动if (player.transform.localEulerAngles.x != 0 || player.transform.localEulerAngles.z != 0){player.transform.localEulerAngles = new Vector3(0, player.transform.localEulerAngles.y, 0);}if (player.transform.position.y != 0){player.transform.position = new Vector3(player.transform.position.x, 0, player.transform.position.z);}     }}public int GetScore(){return recorder.GetScore();}public int GetGoldmineNumber(){return recorder.GetGoldmineNumber();}public bool GetGameover(){return game_over;}public void Restart(){SceneManager.LoadScene("Scenes/mySence");}void OnEnable(){GameEventManager.ScoreChange += AddScore;GameEventManager.GameoverChange += Gameover;GameEventManager.GoldmineChange += ReduceGoldmineNumber;}void OnDisable(){GameEventManager.ScoreChange -= AddScore;GameEventManager.GameoverChange -= Gameover;GameEventManager.GoldmineChange -= ReduceGoldmineNumber;}void ReduceGoldmineNumber(){recorder.ReduceGoldmine();}void AddScore(){recorder.AddScore();}void Gameover(){game_over = true;patrol_factory.StopPatrol();action_manager.DestroyAllAction();}
}

8 参考博客

【Unity3D技巧】在Unity中使用事件/委托机制(event/delegate)进行GameObject之间的通信

30分钟学会UML类图

Unity3d学习之路-简单巡逻兵

解决 unity 2d 中人物碰撞后抖动旋转问题

【Unity3D】键盘鼠标控制视角的移动

Unity3D 智能巡逻兵相关推荐

  1. 用Unity3D实现智能巡逻兵游戏

    用Unity3D实现智能巡逻兵游戏 项目地址 智能巡逻兵游戏 完成效果图 类图 要求 游戏设计要求: 创建一个地图和若干巡逻兵(使用动画): 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址. ...

  2. 基于Unity3D开发的智能巡逻兵小游戏

    智能巡逻兵小游戏 作业要求 游戏设计要求:智能巡逻兵 创建一个地图和若干巡逻兵(使用动画): 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址.即每次确定下一个目标位置,用自己当前位置为原点计 ...

  3. 模型与动画——智能巡逻兵

    文章目录 模型与动画--智能巡逻兵 一.提交要求: 二.具体玩法: 三.订阅发布模式MVC框架: 四.程序实现: 4.1 玩家部分实现: 4.1.0 玩家预制和动画设置: 4.1.1 Interfac ...

  4. Unity实现智能巡逻兵小游戏

    Unity实现智能巡逻兵小游戏 项目地址 演示视频 设计模式:对象的行为 行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算 ...

  5. 3D游戏设计-智能巡逻兵

    游戏简介 躲过巡逻兵的追杀. 游戏规则 一共有九个房间,每个房间有一个巡逻兵,玩家进入房间时该房间的巡逻兵会追杀玩家. 玩家从一个房间进入另一个房间(躲过追杀)时加一分. 玩家被巡逻兵追上则死亡,游戏 ...

  6. Unity3D制作巡逻兵小游戏

    一.主体代码架构说明 二.发布与订阅模式 相关类图 C#中的实现:delegate委托类型和event事件机制 意义 在本次游戏中的具体应用 三.游戏主要行为分析 1. 巡逻兵的行为 与其他物体/角色 ...

  7. unity实现智能巡逻兵

    1. 制作预制体 在Asserts store中下载资源,制作预制体 地面: 玩家: 巡逻兵: 水晶: 2. 动画控制器 玩家: 巡逻兵: 3. 代码 碰撞脚本 PlayerCollide 当玩家与侦 ...

  8. Unity —— 智能巡逻兵

    游戏设计要求: 创建一个地图和若干巡逻兵(使用动画): 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址.即每次确定下一个目标位置,用自己当前位置为原点计算: 巡逻兵碰撞到障碍物,则会自动选下 ...

  9. Unity 智能巡逻兵游戏

    一.游戏介绍 在一张地图上有若干个巡逻兵,每个巡逻兵按照矩形路线进行巡逻,当巡逻兵碰到障碍物时会根据当前位置自动进行调整.在巡逻兵巡逻期间,如果玩家进入巡逻范围会自动追击玩家,当玩家消失在巡逻范围内后 ...

  10. Unity3D 从入门到放弃 ——巡逻兵 观察者模式

    Unity3D 从入门到放弃 --巡逻兵 作业需求 游戏规则: 创建一个地图和若干巡逻兵: 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址.即每次确定下一个目标位置,用自己当前位置为原点计算 ...

最新文章

  1. 云视频会议的“多、快、好、省”(下)
  2. C# 使用正则表达式去掉字符串中的数字,或者去掉字符串中的非数字
  3. 2021算法竞赛入门班第二节课【递归、分治、二分】练习题
  4. 曲奇问答CEO:从产品经理的角度玩转社区类产品
  5. boost::hana::max用法的测试程序
  6. 讲真,做Python一定不要只会一个方向!
  7. 【终极方法】应对eclipse不支持Tomcat7、8和Tomcat8.5或者更高版本
  8. Unity3D 物体移动方法总结
  9. 编译型语言VS解释型语言、动态语言、静态语言
  10. java里面string什么意思_java中string什么意思
  11. leveldb学习:DBimpl
  12. mysql主主同步机制+keepalived实现MySQL高可用
  13. 内网渗透-信息收集整合
  14. 超级实用网址合集(必须收藏一波)
  15. VSFTPD 上传文件 200 227 553错误
  16. Mysql从入门到入魔——6. 表联结、组合查询
  17. vue-03-4:vue封装方法到工具类
  18. yxc_第一章 基础算法(三)_离散化
  19. 单片机中常用的串口通信协议帧
  20. android 复制u盘文件到手机本地_如何将手机里的文件 、照片传到手机U盘里去?...

热门文章

  1. MT7628学习笔记(4)——固件烧录(TFTP方式)
  2. Android ExoPlayer源码分析
  3. 流媒体协议(二):RTMP协议
  4. 系统架构设计-企业信息化战略与实施 知识点
  5. iOS修改手游服务器数据,IOS免越狱游戏存档修改教程】成长王国Grow Kingdom为例
  6. 计算机课网络连不了,上网课电脑没有摄像头怎么办
  7. ic启动器我的世界_hmcl启动器下载-我的世界HMCL启动器下载 v3.3.172官方最新版--pc6下载站...
  8. 2016技术众包风云:挑战与机遇并行!
  9. Tcl 语言——流程控制篇
  10. matlab 矩阵 对称,如何使用Matlab产生对称矩阵 | 学步园