智能巡逻兵
游戏规则
游戏规则
使用WSAD或方向键上下左右移动player,进入巡逻兵的追捕后逃脱可积累一分,若与巡逻兵碰撞则游戏结束,收集完地图上的所有水晶即可获胜。游戏设计要求:
- 创建一个地图和若干巡逻兵(使用动画);
- 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址。即每次确定下一个目标位置,用自己当前位置为原点计算;
- 巡逻兵碰撞到障碍物,则会自动选下一个点为目标;
- 巡逻兵在设定范围内感知到玩家,会自动追击玩家;
- 失去玩家目标后,继续巡逻;
- 计分:玩家每次甩掉一个巡逻兵计一分,与巡逻兵碰撞游戏结束;
程序设计要求:
- 必须使用订阅与发布模式传消息
- 工厂模式生产巡逻兵
游戏制作过程:
人物预设:
地图预设:
玩家摆脱巡逻兵
- SSActionManager
当玩家逃离巡逻兵触发器的范围的时候(此时巡逻兵的跟随玩家的动作会调用回调函数,分数会增加
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();
}
}
玩家和巡逻兵碰撞
- PlayerCollide
巡逻兵身上的碰撞器触碰到玩家的碰撞器将会使游戏结束,并且各自播放对应动画
public class PlayerCollide : MonoBehaviour
{
void OnCollisionEnter(Collision other)
{
//当玩家与巡逻兵相撞
if (other.gameObject.tag == "Player")
{
other.gameObject.GetComponent<Animator>().SetTrigger("death");
this.GetComponent<Animator>().SetTrigger("shoot");
//游戏结束,发布消息
Singleton<GameEventManager>.Instance.PlayerGameover();
}
}
}
发布事件类
- GameEventManager
定义一个专门发布事件的类,订阅者可以订阅该类的事件,当其他类发生改变的时候,会使用GameEventManager的方法发布消息,触发相应事件
public class GameEventManager : MonoBehaviour
{
//分数变化
public delegate void ScoreEvent();
public static event ScoreEvent ScoreChange;
//游戏结束变化
public delegate void GameoverEvent();
public static event GameoverEvent GameoverChange;
//水晶数量变化
public delegate void CrystalEvent();
public static event CrystalEvent CrystalChange;
//玩家逃脱
public void PlayerEscape()
{
if (ScoreChange != null)
{
ScoreChange();
}
}
//玩家被捕
public void PlayerGameover()
{
if (GameoverChange != null)
{
GameoverChange();
}
}
//减少水晶数量
public void ReduceCrystalNum()
{
if (CrystalChange != null)
{
CrystalChange();
}
}
}
订阅者
- 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();
}
水晶触碰
- CrystalCollide
当玩家触碰到水晶的时候,水晶消失,水晶数量减少
public class CrystalCollide : MonoBehaviour
{
void OnTriggerEnter(Collider collider)
{
if (collider.gameObject.tag == "Player" && this.gameObject.activeSelf)
{
this.gameObject.SetActive(false);
//减少水晶数量,发布消息
Singleton<GameEventManager>.Instance.ReduceCrystalNum();
}
}
}
小结
这次作业我感觉是难度最大的一次,其中发布和订阅模式并不像想象中那么简单,其次是人物模型的制作实在是太难了,所以就借用了大佬们的模型,本来想加入第三人称视角的,但在一系列摸索当中还是发现自己的水平有限,无法很好的将摄像机的代码编写完整,出现摄像机不跟随player的情况,或者摄像机被场景给挡住,最后还是放弃了这个想法
视屏地址:点击打开链接