目录
游戏要求
游戏设计要求
- 创建一个地图和若干巡逻兵(使用动画);
- 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址。即每次确定下一个目标位置,用自己当前位置为原点计算;
- 巡逻兵碰撞到障碍物,则会自动选下一个点为目标;
- 巡逻兵在设定范围内感知到玩家,会自动追击玩家;
- 失去玩家目标后,继续巡逻;
- 计分:玩家每次甩掉一个巡逻兵计一分,与巡逻兵碰撞游戏结束;
程序设计要求
- 必须使用订阅与发布模式传消息
- 工厂模式生产巡逻兵
游戏规则
主角被置身于一个长满各种植物的花园中,为了逃离这个困境,需要集齐隐藏于花丛中的12颗水晶。通过方向键控制主角移动,同时躲避每个区域的巡逻兵,开启召唤神龙之旅吧~巡逻兵可能也会藏在草丛中哦~
游戏效果
见视频链接:https://www.bilibili.com/video/av23220658/
UML图
游戏设计
这次游戏设计比之前复杂挺多,代码也较多,这里只把核心部分展示出来,完整代码可见github。
整个游戏实现思路如下:单例SSDirector导演持有currentSceneController对象,场记通过IUserAction接口与用户交互,通过ScoreController管理记分操作,摄像师CameraMan负责跟踪主角移动;场记还通过巡逻兵工厂和水晶工厂来获得巡逻兵实例和水晶实例,然后巡逻兵动作管理员管理巡逻动作和跟踪动作;同时场记还订阅了事件管理器,当水晶碰撞器和玩家碰撞器发布碰撞通知时,事件管理器接收并通知场记发生了具体的碰撞事件,从而执行相应的操作。
控制主角移动
用户GUI中检测方向键,这里把上下左右分别用整数0,2,-1,1表示,好处是当按下方向键需要改变主角的朝向的时候可能根据这几个整数,将其rotation设为欧拉角new Vector3(0, dir * 90, 0)对应的四元数实例。然后判断方向改变主角在对应方向的坐标。
// UserInterface
void Update () {
if (Input.GetKey(KeyCode.UpArrow))
{
action.MovePlayer(Diretion.UP);
}
if (Input.GetKey(KeyCode.DownArrow))
{
action.MovePlayer(Diretion.DOWN);
}
if (Input.GetKey(KeyCode.LeftArrow))
{
action.MovePlayer(Diretion.LEFT);
}
if (Input.GetKey(KeyCode.RightArrow))
{
action.MovePlayer(Diretion.RIGHT);
}
}
// SceneController
public void MovePlayer(int dir)
{
if (!isGameOver)
{
player.transform.rotation = Quaternion.Euler(new Vector3(0, dir * 90, 0));
player.GetComponent<Animator>().SetBool("run", true);
switch (dir)
{
case Diretion.UP:
player.transform.position += new Vector3(0, 0, 0.1f);
break;
case Diretion.DOWN:
player.transform.position += new Vector3(0, 0, -0.1f);
break;
case Diretion.LEFT:
player.transform.position += new Vector3(-0.1f, 0, 0);
break;
case Diretion.RIGHT:
player.transform.position += new Vector3(0.1f, 0, 0);
break;
}
}
}
主摄像机跟踪主角移动
实现思路是在初始化的时候保存摄像机到主角的相对位置,在之后每一帧中保持这个相对位置不变,即可实现相机跟随。
public class CameraMan : MonoBehaviour {
public GameObject target;
// 相机跟随玩家的速度
public float followSpeed = 5f;
Vector3 distance;
// Use this for initialization
void Start () {
distance = transform.position - target.transform.position;
}
// Update is called once per frame
void Update () {
transform.position = Vector3.Lerp(transform.position, target.transform.position + distance, followSpeed * Time.deltaTime);
}
}
<