Unity3d 学习之路——简单巡逻兵
游戏规则与游戏要求
智能巡逻兵
- 游戏规则
使用WSAD或方向键上下左右移动player,进入巡逻兵的追捕后逃脱可积累一分,若与巡逻兵碰撞则游戏结束,收集完地图上的所有水晶即可获胜。 游戏设计要求:
- 创建一个地图和若干巡逻兵(使用动画);
- 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址。即每次确定下一个目标位置,+ 用自己当前位置为原点计算;
- 巡逻兵碰撞到障碍物,则会自动选下一个点为目标;
- 巡逻兵在设定范围内感知到玩家,会自动追击玩家;
- 失去玩家目标后,继续巡逻;
- 计分:玩家每次甩掉一个巡逻兵计一分,与巡逻兵碰撞游戏结束;
程序设计要求:
- 必须使用订阅与发布模式传消息
subject:OnLostGoal
Publisher: ?
Subscriber: ? - 工厂模式生产巡逻兵
- 必须使用订阅与发布模式传消息
成品图
先看一下成品图吧,感觉是除了第一次作业之外,这次是自己做得最好的一次了。
做了整整两天,界面还没很完美。
游戏UML图
游戏实现
用到了C#的委托和事件实现发布与订阅模式,没有实现动作分离管理。
+ SSDirector,IUserAction,和ISceneController和之前的差不多甚至一样
+ 地图的绘制
建好一个Plane,再绘制好围墙,和几个触发器:
- 巡逻兵的动作(Patrol.cs):
- 属性与变量
public enum PatrolState { PATROL,FOLLOW};
public int sign; //the patrol in which area
public bool isFollowPlayer = false;
public GameObject player=null; //the player
public Vector3 startPos,nextPos;
private float minPosX,minPosZ; // the range of this patrol can move;
private bool isMoving = false;
private float distance;
private float speed = 1.2f;
PatrolState state = PatrolState.PATROL;
- 玩家没进到该巡逻兵管辖的领地时,巡逻兵到处随机巡逻:
public void GoPatrol()
{
if (isMoving)
{
transform.position = Vector3.MoveTowards(this.transform.position, nextPos, speed * Time.deltaTime);
distance = Vector3.Distance(this.transform.position, nextPos);
if(distance < 0.5)
{
isMoving = false;
}
return;
}
float posX = Random.Range(0f, 5f);
float posZ = Random.Range(0f, 5f);
nextPos = new Vector3(minPosX+posX, 0, minPosZ+posZ);
isMoving = true;
}
- 当有玩家进入它的领地,追踪玩家,巡逻兵朝着玩家的位置移动,移动结束的条件是玩家离开该区域内了:
public void Follow()
{
if(player != null)
{
nextPos = player.transform.position;
transform.position = Vector3.MoveTowards(this.transform.position, nextPos, speed * Time.deltaTime);
}
}
- 巡逻兵工厂(PatrolFactory.cs)
这次直接创建了3个巡逻兵,因为场景一开始就需要3个了
public class PatrolFactory:MonoBehaviour
{
private List<GameObject> used = new List<GameObject>(); // the used patrol
private Vector3[] PatrolPos = new Vector3[3];
private bool isProduce = false;
FirstController firstController;
private void Start()
{
firstController = SSDirector.getInstance().currentScenceController as FirstController;
}
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;
}
}
- 场景类(FirstController.cs)感觉没什么好说的,主要是加载资源和管理一下游戏的状态,讲一下本次作业重点的内容:发布与订阅模式,这里推荐一个很详细地讲解这个模式的博客:C#中的委托和事件。
首先在触发器(AreaCollide.cs)里定义事件
//AreaCollide.cs
public delegate void CanFollow(int state,bool isEnter);
public static event CanFollow canFollow;
关心该事件的是巡逻兵,因为当玩家进来它要追踪,玩家出去了它要继续巡逻,所以巡逻兵要订阅或者说注册该事件:
//Patrol.cs
private void Start()
{
// ...
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;
}
}
另外还有一个要发布与订阅的事件,就是当玩家逃脱了巡逻兵的追捕记分员要计分,这件事是记分员感兴趣的:
//AreaCollide.cs
public delegate void AddScore();
public static event AddScore addScore;
ScoreRecorder订阅该事件:
//ScoreRecorder.cs
void Start()
{
AreaCollide.addScore += SetScore;//订阅事件
}
总结一下自己对发布与订阅模式的理解,有点想回调的用法,就是订阅者对那些事件感兴趣,他就去告知发布者一声,如果该事件发生了,发布者就通知订阅者执行相应的代码。比如说你要去一家餐厅吃饭,但没位置了,你告知那里的店长(注册时间(订阅事件)),有位置时打电话给你,你就会马上赶过去。所以,当有位置了(事件触发条件),店长就会打电话给你(发布),你就会赶过去(对应的事件)。
总结
这两天真的是盯着电脑做这次作业,感觉过得很充实,学了很多东西,不仅对unity的使用进了一步,还学会了一种新的设计模式。
详细代码可以看我的GitHub——传送门,里面有游戏视频的地址。
扫描二维码关注公众号,回复:
1128410 查看本文章