• 巡逻兵

    • 游戏演示
    • 准备工作
      • 人物的动作
      • 碰撞检测
    • 代码实现
      • 动作代码的实现
      • 门面模式
      • 工厂模式
      • 发布与订阅模式(观察者模式)
    • 总结
  • github代码及视频链接

巡逻兵

游戏设计要求

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

程序设计要求

  • 必须使用订阅与发布模式传消息、工厂模式生产巡逻兵

游戏演示

演示了玩家左键劈砍,右键范围攻击,space跳跃,
巡逻兵触发追踪时候扑到动作,以及碰到玩家挥砍动作
还有玩家攻击时候碰到巡逻兵,巡逻兵会直接消失

准备工作

首先需要下载模型,推荐一个网站还算比较好的免费网站,其中我的作业模型就是从里面下载的,场景模型本来也下载了,但是建立一个场景实在太费时间,所以就直接借用了之前大佬的场景。

人物的动作

首先打开下载好的人物模型,点开人物旁边的按钮可以看到很多部件以及动作,可以点开玩一下。如果决定用这个人物模型,就放置到Resources中的Prefabs文件夹里。放到

在Prefabs中的人物就没有那些动作了,这时候就需要自己设计AnimatorController。

新建一个文件夹AnimatorController,里面用来控制动作,在里面Create,Animator Controller,就比如新建了一个skeleton。

双击skeleton打开,我已经建立好了,稍微有点复杂,首先在左边的Parameters新建变量,我建立了五个变量,bool型的run,bool型的death,以及Trigger型的attack1,attack2,jump。Trigger类型给的解释是,先设置true,然后自动设置为false,但似乎运行的时候有点奇怪,这个是作为skeleton的动作设计,鼠标左键,从右向左劈砍,鼠标右键,旋转劈砍,空格键跳跃。所以从AnyState开始有三个动作,都是Trigger触发,执行完毕后进入到idle状态,在idle状态下,如果run为true就run,death为true就death,其他同理,这时候不能连到Exit,原因是连到Exit就会从入口再次进入,就会发现死了一遍又又一遍。

状态绑定动作,就是Motion那里选择动作,一定要记住将动作的Animation Type改成Generic,才可以从Motion里面选择,并且会生成结尾为Avatar的东西,这个在与物体绑定的时候有用。

下面是转换时候的设置,至于下面为什么有两个run,这个原因是有时候动作切换很不自然,或者延迟太高,多个组合的话会比较好调整,具体设计方法,把loop打勾,然后apply一下就好。这里还有个小技巧,就是两个状态之间的连线怎么删掉的问题,在Transition下面的点减号就行。

然后在人物增加新组件,Animator,在Controller和Avatar,选择刚刚做好和生成的文件。这样的话一个具有动作的人物就设置好了。

碰撞检测

这个需要设置碰撞盒,这个是我player的碰撞盒,差不多是药丸形状的,注意IsTrigger不打勾,说明碰到了就是碰到了,而不是碰到了触发一下。

巡逻兵也需要设置碰撞盒,但是比玩家复杂一点,因为巡逻兵需要检测玩家的范围,所以还要给巡逻兵建立一个box Collider,用户触发追踪事件。

人物效果看起来是这样的

当然场景也是需要设置9个碰撞盒的,并且勾上IsTrigger,用来判断人物在哪一块区域。

到此为止准备工作算是做完了。

代码实现

这次我整理和参考了以前的PPT和大佬的代码,严格按照所将的设计模式组织代码。

动作代码的实现

首先动作代码可以复用的,一点都不用改的是,SSActionManager.csSSAction.csISSActionInterface.cs其中ISSActionInterface.csISSActionCallback接口。需要改动的就是CCSequenceAction.csCCMoveToAction.cs以及CCActionManager.cs,似乎CC开头的都是自己定义的。这个图还是牧师与魔鬼那章PPT的图,其中CCSequenceAction.cs是定义动作序列,因为坐船是,人物先移动船的上方,在移到船上面,相当于两个动作,所以用动作序列,而船的移动只有左右,所以用CCMoveToAction.cs实现单个动作。本次作业设计的动作也就两个,第一个是PatrolAction.cs实现巡逻动作,一个是PatrolFollowAction.cs实现跟踪动作,然后这个两个动作的管理在PatrolActionManager.cs中,因为PatrolActionManager.cs实现了ISSActionCallback的接口,所有动作的都是靠这个接口来完成的,所以具体的动作管理,也是靠这个接口。

PatrolAction.cs 巡逻动作实现

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 move_sign = true;              //是否到达目的地private Dirction dirction = Dirction.EAST;  //移动的方向private PatrolData data;                    //侦察兵的数据private GoPatrolAction() { }public static GoPatrolAction GetSSAction(Vector3 location){GoPatrolAction action = CreateInstance<GoPatrolAction>();action.pos_x = location.x;action.pos_z = location.z;//移动的距离随机,在4-7之间action.move_length = Random.Range(4, 7);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);}//巡逻的动作Gopatrol();//如果有跟随的玩家,并且玩家在自己所在的区域,就会调用ISSActionCallback接口中的函数//所以说动作的管理是靠ISSActionCallback实现的,同样在跟踪的时候的动作也会有切换到巡逻状态的方法。if (data.follow_player && data.wall_sign == data.sign){//当前动作摧毁掉this.destroy = true;//切换到追踪状态this.callback.SSActionEvent(this,0,this.gameobject);}}public override void Start(){this.gameobject.GetComponent<Animator>().SetBool("run", true);data  = this.gameobject.GetComponent<PatrolData>();}void Gopatrol(){if (move_sign){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;}move_sign = 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;}move_sign = true;}}
}

这段代码可以和CCMoveToActon的代码比较一下,因为两个是同一个框架的不同实现,可以发现除了实现细节不一样,其他都一样,包括函数类型都一样。可以看到这部分的代码,只要实现特定的动作,所以以后在写新动作处理的时候,可以直接在这部分修改,或者另开一个文件继承SSAction

PatrolFollowAction.cs 追踪动作实现

using System.Collections;
using System.Collections.Generic;
using UnityEngine;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();//如果没有跟随的玩家,或者玩家不在自己所在的区域,就会调用ISSActionCallback接口中的函数,切换到巡逻状态//所以说动作的管理是靠ISSActionCallback实现的,同样在巡逻的时候的动作也会有切换到追踪状态的方法。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);}
}

这部分代码和之前的代码框架一样,不做过多的解释。

PatrolActionManager.cs 具体的动作管理

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PatrolActionManager : SSActionManager, ISSActionCallback
{//这个函数是游戏初始化的时候用到,最重要的实现还是在SSActionEvent函数中实现,也就是ISSActionCallback接口的函数public void GoPatrol(GameObject patrol){GoPatrolAction go_patrol = GoPatrolAction.GetSSAction(patrol.transform.position);this.RunAction(patrol, go_patrol, this);}//停止所有动作public void DestroyAllAction(){DestroyAll();}//动作管理最终要的部分,实现各个动作的切换,以及条件判断。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直接生成实例,调用PlayerEscape就相当于发出通知,那么在OnEnable函数就会触发加分的函数Singleton<GameEventManager>.Instance.PlayerEscape();}}
}

这段代码再和CCActionManager比较下,发现最重要的还是SSActionEvent函数的实现,start和Update,可以换成其他函数,直接被调用,而不是默认调用,大同小异。

门面模式

对于单个场景的游戏来说,完全不用改动的代码是SSDirector.csISenceInterface.cs,需要改动的是FirstSceneController.csUserGUI.csIUserInterface.cs,其中FirstSceneController.cs主要处理场景的资载入,并且实现IUserAction接口,由于是但场景,对ISceneController接口实现的并不多。UserGuI主要实现界面的呈现,用户交互,其中的接口是在FirstController中实现,所以通过UserGuI可以控制游戏人物,以及游戏的重新开始之类的。

UserGUI.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class UserGUI : MonoBehaviour {private IUserAction action;private GUIStyle score_style = new GUIStyle();private GUIStyle text_style = new GUIStyle();private GUIStyle over_style = new GUIStyle();private int show_time = 8;void Start (){action = SSDirector.GetInstance().CurrentScenceController as IUserAction;text_style.normal.textColor = new Color(205, 179, 128, 1);text_style.fontSize = 16;score_style.normal.textColor = new Color(3,101,100,1);score_style.fontSize = 16;over_style.fontSize = 25;//好的方法实现一个时间差,StartCoroutine函数和yield return成对出现。StartCoroutine(ShowTip());}void Update(){//人物的动作和移动,得到水平两个方向的偏移量来控制移动,通过按键控制动作。float translationX = Input.GetAxis("Horizontal");float translationZ = Input.GetAxis("Vertical");action.MovePlayer(translationX, translationZ);action.Attack();}private void OnGUI(){GUI.Label(new Rect(10, 5, 200, 50), "分数:", text_style);GUI.Label(new Rect(55, 5, 200, 50), action.GetScore().ToString(), score_style);if(action.GetGameover() && action.GetScore() != 10){GUI.Label(new Rect(Screen.width / 2 - 50, Screen.width / 2 - 250, 100, 100), "游戏结束", over_style);if (GUI.Button(new Rect(Screen.width / 2 - 50, Screen.width / 2 - 150, 100, 50), "重新开始")){//重新开始action.Restart();return;}}else if(action.GetScore() == 10){GUI.Label(new Rect(Screen.width / 2 - 50, Screen.width / 2 - 250, 100, 100), "恭喜胜利!", over_style);if (GUI.Button(new Rect(Screen.width / 2 - 50, Screen.width / 2 - 150, 100, 50), "重新开始")){//重新开始action.Restart();return;}}if(show_time > 0){GUI.Label(new Rect(Screen.width / 2 - 87 ,10, 100, 100), "按WSAD或方向键移动", text_style);GUI.Label(new Rect(Screen.width / 2 - 87, 30, 100, 100), "成功躲避巡逻兵追捕加1分", text_style);GUI.Label(new Rect(Screen.width / 2 - 87, 50, 100, 100), "获得十分就胜利", text_style);}}public IEnumerator ShowTip(){while (show_time >= 0){yield return new WaitForSeconds(1);show_time--;}}
}

结构类似于PPT的结构,这部分大部分都是界面要素,接口的使用很简单

FirstSceneController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class FirstSceneController : MonoBehaviour, IUserAction, ISceneController
{public PatorlFactory _PatorlFactory;                             //巡逻者工厂public ScoreRecorder _ScoreRecorder;                             //记录员public PatrolActionManager _PatrolActionManager;                 //运动管理器public int wall_sign = -1;                                       //当前玩家所处哪个格子public GameObject player;                                        //玩家public Camera main_camera;                                       //主相机private List<GameObject> patrols;                                //场景中巡逻者列表private float player_speed = 5;                                  //玩家移动速度private float rotate_speed = 135f;                               //玩家旋转速度private bool game_over = false;                                  //游戏结束void Update(){for (int i = 0; i < patrols.Count; i++){patrols[i].gameObject.GetComponent<PatrolData>().wall_sign = wall_sign;}//20分结束游戏if(_ScoreRecorder.score == 20){Gameover();}}void Start(){//这一块注意一下,关于实例化,和实例化的查找//首先director是单例模式,所以用GetInstance方法,即使没有实例也会创建实例,有实例就确保只有一个实例//那么_PatorlFactory和_PatrolActionManager是怎么回事//首先看到代码可以这样写,用Singleton,这个是直接查找有没有这个类,没有就报错了//所以使用这个有个前提条件,就是必须已经存在了,所以在游戏开始之前必须把代码绑定到对应的物体上//如果不采用这种方法怎么办,可以手动添加,用AddComponent就相当于把手动添加的部分,用代码实现了,就是注释掉的部分SSDirector director = SSDirector.GetInstance();director.CurrentScenceController = this;_PatorlFactory = Singleton<PatorlFactory>.Instance;_PatrolActionManager = Singleton<PatrolActionManager>.Instance;//_PatrolActionManager = gameObject.AddComponent<PatrolActionManager>() as PatrolActionManager;//ISceneController接口中函数的实现LoadResources();//设置摄像机跟随的对象,也就是玩家,如果不用工厂模式的话,直接在场景中生成玩家,然后把玩家拖到摄像机的Targer就可以了//这一块也要注意,main_camera的位置必须在LoadResources之后,因为main_camera跟随的对象是player,如果player没有实例化就无法运行//所以如果一开始在场景中就有player的话,下面的代码位置就可以随便放。main_camera.GetComponent<CameraFlow>().follow = player;_ScoreRecorder = Singleton<ScoreRecorder>.Instance;}public void LoadResources(){player = Instantiate(Resources.Load("Prefabs/Player"), new Vector3(0, 9, 0), Quaternion.identity) as GameObject;//导入资源的时候为了巡逻兵有动作patrols = _PatorlFactory.GetPatrols();for (int i = 0; i < patrols.Count; i++){_PatrolActionManager.GoPatrol(patrols[i]);}}public void Attack(){if (!game_over){//Fire1对应鼠标左键if(Input.GetButtonDown("Fire1")){player.GetComponent<Animator>().SetTrigger("attack1");}//Fire2对应鼠标右键if (Input.GetButtonDown("Fire2")){player.GetComponent<Animator>().SetTrigger("attack2");}//Jump对应空格键spaceif (Input.GetButtonDown("Jump")){player.GetComponent<Animator>().SetTrigger("jump");}}}public void MovePlayer(float translationX, float translationZ){if(!game_over){//移动的时候播放run动画,否则停止run动画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 _ScoreRecorder.score;}public bool GetGameover(){return game_over;}public void Restart(){SceneManager.LoadScene("Scenes/mySence");}//发布与订阅模式void OnEnable(){GameEventManager.ScoreChange += AddScore;GameEventManager.GameoverChange += Gameover;}void OnDisable(){GameEventManager.ScoreChange -= AddScore;GameEventManager.GameoverChange -= Gameover;}void AddScore(){_ScoreRecorder.score++;}void Gameover(){game_over = true;_PatorlFactory.StopPatrol();_PatrolActionManager.DestroyAllAction();}
}

整体框架类似于PPT中的,另外实现接口类的函数就可以了

工厂模式

工厂模式相对来说比较简单,一般来说一个类型有一个工厂,由于本例是一个玩家角色,所以直接把玩家和巡逻兵放在一起生产了。其中只要写Factory就好了。

其中可以发现DiskFactory上面有Singleton,是用来找DiskFactory用的

PatrolFactory.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PatorlFactory : MonoBehaviour {//工厂模式就负责生产,其他的不负责,所以可以看到这个类只和角色有关系和其他所有代码都没有关系private GameObject player = null;                                      //玩家private GameObject patrol = null;                                     //巡逻兵private List<GameObject> patrolList = new List<GameObject>();        //正在被使用的巡逻兵private Vector3[] vec = new Vector3[9];                             //保存每个巡逻兵的初始位置public GameObject LoadPlayer(){player = Instantiate(Resources.Load("Prefabs/Player"), new Vector3(0, 9, 0), Quaternion.identity) as GameObject;return player;}public List<GameObject> LoadPatrol(){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++){vec[index] = new Vector3(pos_x[i], 0, pos_z[j]);index++;}}for(int i=0; i < 9; i++){patrol = Instantiate(Resources.Load<GameObject>("Prefabs/Patrol1"));patrol.transform.position = vec[i];patrol.GetComponent<PatrolData>().sign = i + 1;patrol.GetComponent<PatrolData>().start_position = vec[i];patrolList.Add(patrol);}   return patrolList;}//游戏结束的时候会暂停所有动作public void StopPatrol(){for (int i = 0; i < patrolList.Count; i++){patrolList[i].gameObject.GetComponent<Animator>().SetBool("run", false);}}
}

发布与订阅模式(观察者模式)

借用一下大佬的图,用观察者模式写代码会觉得很清爽,首先CystalCollide和PlayerCollide是直接挂载在相对应的物体上的,可以事先写好,然后用里面的函数触发GameEventManager。

PlayerInDetection.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;//玩家进入巡逻兵的追踪范围
public class PlayerInDetection : MonoBehaviour
{//玩家进入巡逻兵的追踪范围void OnTriggerEnter(Collider collider){//加上判断Player的原因是,人物会与地板碰撞if (collider.gameObject.tag == "Player"){this.gameObject.transform.parent.GetComponent<PatrolData>().follow_player = true;this.gameObject.transform.parent.GetComponent<PatrolData>().player = collider.gameObject;//触发巡逻兵向前扑的动作this.gameObject.transform.parent.GetComponent<Animator>().SetTrigger("shock");}}//玩家离开巡逻兵的追踪范围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;}}
}

PlayerCollideDetection.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;//玩家与巡逻兵碰撞
public class PlayerCollideDetection : MonoBehaviour {//当玩家与巡逻兵碰撞void OnCollisionEnter(Collision other){//在这里皮了一下,因为一开始是想做攻击判定的,但是剑和人的模型是一起的//没法单独给剑加一个碰撞盒,所以只好放弃//于是想攻击的时候直接让巡逻兵的碰撞盒半径为0,然后播放死亡动画也可以达到目的//然后发现会鬼畜,就注释掉了,现在只要在攻击的时候碰到巡逻兵,巡逻兵会直接消失//一般情况下的,玩家会自己挂掉,并且播放死亡动画,巡逻兵也会砍一刀然后死掉。if (other.gameObject.tag == "Player" && other.gameObject.GetComponent<Animator>().GetBool("attack1")){//this.gameObject.GetComponent<CapsuleCollider>().radius = 0;this.gameObject.SetActive(false);return;}else if (other.gameObject.tag == "Player"){other.gameObject.GetComponent<Animator>().SetBool("death",true);this.GetComponent<Animator>().SetTrigger("shoot");Singleton<GameEventManager>.Instance.PlayerGameover();}}
}

GameEventManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class GameEventManager : MonoBehaviour
{//玩家躲开追踪时候触发public delegate void ScoreEvent();public static event ScoreEvent ScoreChange;//玩家碰撞到巡逻兵的时候触发public delegate void GameoverEvent();public static event GameoverEvent GameoverChange;public void PlayerEscape(){if (ScoreChange != null){ScoreChange();}}public void PlayerGameover(){if (GameoverChange != null){GameoverChange();}}
}

这样所有的代码都已经说完了。

总结

所有C#文件,一共20个文件。

其中可以挂载在预制物体上的有5个。

  • AreaDetection.cs挂载在场景的9个方格中,用于检测玩家是否进入该方格
  • CameraFlow.cs挂载在摄像机上,用于实现第三人称视角
  • PatrolData.cs挂载在巡逻兵上,用于表示巡逻兵的数据结构
  • PlayerInDetection.cs挂载在巡逻兵上,用于检测玩家是否进入追踪范围
  • PlayerCollideDetection.cs挂载在巡逻兵上,用于检测玩家是否与巡逻兵碰撞

其中动作设计的部分有6个

  • SSDirector.cs完全不用改动
  • SSActionManager.cs完全不用改动
  • PatrolAction.cs
  • PatrolActionManager.cs
  • PatrolFollowAction.cs
  • ISSActionInterface.cs完全不用改动

其中门面模式的部分

  • FirstSceneController.cs
  • ISenceInterface.cs单场景完全不用改动
  • IUserInterface.cs
  • UserGUI.cs
  • SSDirector.cs完全不用改动

工厂模式的部分

  • PatorlFactory.cs
  • Singleton.cs其实也不算工厂特有,都可以用,完全不用改动

    观察者模式

  • PlayerCollideDetection.cs

  • PlayerInDetection.cs
  • GameEventManager.cs

github代码及视频链接

资源以及视频演示

3D游戏编程7--巡逻兵(总结之前所有出现过的设计模式)相关推荐

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

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

  2. 3D游戏编程学习笔记(七):模型与动画

    一.前言 本次3D游戏编程我们将设计一个智能巡逻兵游戏. 二.游戏基本内容及规定 游戏内容部分 创建一个地图和若干巡逻兵(使用动画): 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址.即每次 ...

  3. 设计模式与3D游戏编程

    设计模式与3D游戏编程 前言 这是中山大学数据科学与计算机学院2019年3D游戏编程与设计的约稿博客,主要是总结课程一个学期以来学习的设计模式以及将其用于Unity3D编程的个人经验. 所有项目与代码 ...

  4. 3D游戏编程与设计-井字棋

    3D游戏编程与设计-井字棋 目录 3D游戏编程与设计-井字棋 A. 简答题 1. 解释游戏对象(GameObjects)和资源(Assets)的区别与联系 ① 游戏对象 ② 资源 2. 下载几个游戏案 ...

  5. 3d游戏编程(转帖)

    3d游戏编程(转帖) 我先声明,我不是编程高手,我还只是个初学者,但我觉得我所知道的对刚入门3D游戏编程的新手,应该能让他们少走弯路,我也很想用朝语来写,但是朝语的词 汇库很久没有更新过了,有些专业的 ...

  6. 3D游戏编程与设计作业10

    3D游戏编程与设计作业10 环境说明 Unity3D 导航与寻路 Agent 和 Navmesh 练习 Obstacle和Off-Mesh-Link练习 P&D 过河游戏智能帮助实现 状态图 ...

  7. 3D游戏编程与设计——游戏的本质章节作业与练习

    3D游戏编程与设计--游戏的本质章节作业与练习 18342138 郑卓民 3D游戏编程与设计--游戏的本质章节作业与练习 作业与练习: 游戏名称及简介: 游戏的随机性 游戏的玩法与目标 游戏的冲突 游 ...

  8. 3D 游戏编程与设计:第3次作业

    3D 游戏编程与设计:第3次作业 姓名:韩宝欣 学号:20331013 代码仓库:https://gitee.com/sse_20331013/3d-game.git 文章目录 3D 游戏编程与设计: ...

  9. 开始利用CSDN做学习笔记,从windows 游戏编程大师技巧和3D游戏编程大师开始

    利用两个月的空余时间将windows 游戏编程大师技巧和3D游戏编程大师技巧看了一遍. 第一遍读的并不深入,代码也没有仔细研究.特别是3D下册,基本只是草草浏览了一遍而已.这一遍是为了对整体有个印象和 ...

最新文章

  1. linux备份sqlserver数据库,Linux sqlServer数据库还原办法
  2. python网页交互引擎_【Kivy Python UI 框架】模板化交互界面引擎
  3. java scala_经过几天的Scala回归Java的10个最烦人的事情
  4. ITK读图VTK显示
  5. mysql数据库连接不稳定_连接 MySQL 数据库失败频繁的原因探秘
  6. truffle unbox webpack报错
  7. python docx 表格打印不显示_python-docx 设置 word 文档中表格格式
  8. win10以管理员身份解压缩WinRAR文件
  9. mysql入门很简单习题答案_《MySQL入门很简单》练习6.6
  10. 计算机在旅游管理方面的应用,谈旅游管理信息系统的设计与应用
  11. 时间序列的平稳性检验方法汇总
  12. 熵值法、灰色关联分析与层次分析法
  13. 扫呗扫码点餐,如何在扫呗后台给这个商户配一下支付授权地址
  14. OA系统是什么意思?企业为什么要用OA办公系统软件?
  15. .Net6.0系列-6 .Net 6LinQ(二)常用扩展方法
  16. eclipse的放大字体
  17. telephony相关修改点
  18. 163邮箱注册哪个好?电子邮箱怎么申请?
  19. A005:python 时间处理
  20. Reduce-Rank Regression通俗解释及与其他降维方法的关系

热门文章

  1. 风光摄影常遇到的问题nbsp;从零基…
  2. jpython LookupError: unknown encoding 'ms936' 问题解决
  3. 鸿蒙OS的设计理念,EMUI11的UX设计理念 与鸿蒙OS共筑一致用户体验
  4. 求网络推广的大师收徒弟
  5. 统计全球每年的最高/最低气温
  6. 手把手带你写一份优秀的开发求职简历(七)写项目经历的内功心法
  7. 医疗保健领域的人工智能:2023年的新兴趋势
  8. l2实时接口在手机APP上的使用方法介绍
  9. 中国卫浴行业迎来万亿市场,九牧打响“科技卫浴”第一枪!
  10. fluent-ffmpeg图片合成视频(一)