一、作业要求
智能巡逻兵
游戏设计要求:
- 创建一个地图和若干巡逻兵;
- 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址。即每次 确定下一个目标位置,用自己当前位置为原点计算;
- 巡逻兵碰撞到障碍物如树,则会自动选下一个点为目标;
- 巡逻兵在设定范围内感知到玩家,会自动追击玩家;
- 失去玩家目标后,继续巡逻;
- 计分:每次甩掉一个巡逻兵计一分,与巡逻兵碰撞游戏结束;
程序设计要求:
- 必须使用订阅与发布模式传消息、工厂模式生产巡逻兵
二、相关知识
1.订阅与发布模式(观察者模式)
也称为观察者模式(Observer Pattern)
- 发布者与订阅者没有直接的耦合
- 是实现模型与视图分离的重要手段
- 例如:数据DataSource对象,就是Subject。任何使用该数据源 的显示控件,如Grid都会及时更新。
实现:
定义事件源
2.工厂模式的设计
为什么需要工厂对象
- 游戏对象的创建与销毁高成本,必须减少销毁次数。如:游戏中子弹
- 屏蔽创建与销毁的业务逻辑,使程序易于扩展
实现示例DiskFactory:
设计读图:这是一个带游戏对象缓存的工厂类
- 前面游戏,由导演、场记、运动管理师、演员构成。
- 新游戏中,场记请了记分员、飞碟管理员
- 其中记分员按飞碟的数据计分,记分员拥有计分规则
- 场记只需要管理出飞碟规则与管理碰撞就可以了
三、关键部分的实现
1.巡逻兵工厂
主要负责用预制创建四个士兵、点击重新开始之后销毁士兵并重新创建。
public List<GameObject> GetPatrols()
{
firstController = SSDirector.getInstance().currentScenceController as FirstController;
if (!isProduce)
{
int index = 0;
float[] posZ = { 3.75f, -3.75f };
float[] posX = { 3.75f, -3.75f };
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
if(posX[j] > 0 && posZ[i] > 0)
{
continue;
}
PatrolPos[index++] = new Vector3(posX[j], 0, posZ[i]);
}
}
for (int i = 0; i < 3; i++)
{
GameObject patrol = Instantiate(Resources.Load<GameObject>("Prefabs/Patrol"));
patrol.transform.parent = firstController.plane.transform;
patrol.transform.position = PatrolPos[i];
patrol.GetComponent<Patrol>().sign = i + 1;
patrol.GetComponent<Patrol>().startPos = PatrolPos[i];
used.Add(patrol);
}
isProduce = true;
}
return used;
}
public void destoryFactory()
{
foreach(var a in used)
{
DestroyImmediate(a);
}
used = new List<GameObject>();
isProduce = false;
}
//销毁的使用
public void ReStart()
{
rush = player;
rush.SetActive(false);
player = null;
player = Instantiate(Resources.Load<GameObject>("Prefabs/Player"));
player.transform.position = new Vector3(1.8f, -0.35f, 1.8f);
patrolFactory.destoryFactory();
patrols = patrolFactory.GetPatrols();
DestroyImmediate(rush);
gameState = GameState.BEGIN;
}
2.订阅与发布模式传递消息
定义事件源:
public class AreaCollide : MonoBehaviour
{
public int sign;
//注册两个事件
//事件一:追踪
//定义回调函数,定义subject
public delegate void CanFollow(int state,bool isEnter);
public static event CanFollow canFollow;
//事件二:分数
public delegate void AddScore();
public static event AddScore addScore;
//发出通知
void OnTriggerEnter(Collider collider)
{
if (collider.gameObject.tag == "Player")
{
canFollow(sign,true);
}
}
private void OnTriggerExit(Collider collider)
{
if (collider.gameObject.tag == "Player")
{
canFollow(sign,false);
addScore();
}
}
}
订阅(注册)以上事件:
//订阅追踪的巡逻兵
private void Start()
{
minPosX = startPos.x - 2.5f;
minPosZ = startPos.z - 2.5f;
isMoving = false;
AreaCollide.canFollow += changeStateToFollow;
}
public void changeStateToFollow(int sign_,bool isEnter)
{
if(sign == sign_ )
{
if (isEnter)
{
state = PatrolState.FOLLOW;
player = (SSDirector.getInstance().currentScenceController as FirstController).player;
isFollowPlayer = true;
}
else
{
isFollowPlayer = false;
state = PatrolState.PATROL;
player = null;
isMoving = false;
}
}
}
//订阅分数增加的记分Recoder
void Start(){
AreaCollide.addScore += SetScore;
}
四、成品
最后,谢谢师兄的博客帮助!
视频传送门