实验要求
- 游戏设计要求
- 创建一个地图和若干巡逻兵(使用动画);
- 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址。即每次确定下一个目标位置,用自己当前位置为原点计算;
- 巡逻兵碰撞到障碍物,则会自动选下一个点为目标;
- 巡逻兵在设定范围内感知到玩家,会自动追击玩家;
- 失去玩家目标后,继续巡逻;
- 程序设计要求
- 必须使用订阅与发布模式传消息
- subject:OnLostGoal
- Publisher: ?
- Subscriber: ?
- 工厂模式生产巡逻兵
相关代码
场景
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameController : SSActionManager, ISSActionCallback
{
Vector3[] posset = new Vector3[] { new Vector3(1, 0.25f, 1), new Vector3(1, 0.25f, -1), new Vector3(-1, 0.25f, -1), new Vector3(-1, 0.25f, 1) };
Vector3[] Random = new Vector3[] { new Vector3(3, 0, 0), new Vector3(0, 0, 3), new Vector3(-3, 0, 0), new Vector3(0, 0, -3) };
int rollnum = 0;
private static GameController instance;
public bool isOver = false;
public GameObject player, guard,environment;
private GameObject _player, scene;
private List<GameObject> GuardSet;
// Use this for initialization
new void Start () {
_player = Instantiate(player);
_player.name = "player";
scene = Instantiate(environment);
instance = this;
initGuard();
}
public static GameController getInstance()
{
return instance;
}
void initGuard()
{
GuardSet = new List<GameObject>(4);
for(int i=0;i<4;i++)
{
GameObject newone = Instantiate(guard);
newone.name = "guard" + i;
newone.transform.position = posset[i];
}
}
// Update is called once per frame
public int getPlayerArea()
{
return _player.GetComponent<playerStatus>().areaIndex;
}
public void goCatch(GameObject guard)
{
addSingleMoving(guard, _player.transform.position, 0.05f, false);
}
public void goBack(GameObject guard,bool aaa)
{
string name = guard.gameObject.name;
char cindex = name[name.Length - 1];
int index = cindex - '0';
addSingleMoving(guard, posset[index], 0.05f, false);
}
public void goarround(GameObject guard, int dir)
{
string name = guard.gameObject.name;
char cindex = name[name.Length - 1];
int index = cindex - '0';
Vector3 oriTarget = Random[dir];
oriTarget += guard.transform.position ;
addSingleMoving(guard, oriTarget, 0.05f, false);
}
void addSingleMoving(GameObject sourceObj, Vector3 target, float speed, bool isCatching)
{
this.runAction(sourceObj, CCMoveToAction.CreateSSAction(target, speed, isCatching), this);
}
public bool nearby(Vector3 a,Vector3 b)
{
float x1, x2, z1, z2;
x1 = a.x;
x2 = b.x;
z1 = a.z;
z2 = b.z;
if (Math.Abs(x1 - x2) < 0.9f && Math.Abs(z1 - z2) < 0.9f)
{
//Debug.Log("pos:" + Math.Abs(x1 - x2) + "," + Math.Abs(z1 - z2));
return true;
}
else return false;
}
public void patrolHitHeroAndGameover()
{
isOver = true;
}
public void SSActionEvent(SSAction source, SSActionEventType eventType = SSActionEventType.Completed, SSActionTargetType intParam = SSActionTargetType.Normal, string strParam = null, object objParam = null)
{
//throw new NotImplementedException();
}
}
巡逻兵
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class guardStatus : MonoBehaviour {
Vector3[] posset = new Vector3[] { new Vector3(1, 0.25f, 1), new Vector3(1, 0.25f, -1), new Vector3(-1, 0.25f, -1), new Vector3(-1, 0.25f, 1) };
Vector3[] Random = new Vector3[] { new Vector3(3, 0, 0), new Vector3(0, 0, 3), new Vector3(-3, 0, 0), new Vector3(0, 0, -3) };
Vector3 prepos;
private int ownIndex = -1;
public bool isCatching;
public bool isIdle;
int dir = 0;
public GameController _controller;
// Use this for initialization
void Start () {
ownIndex = getOwnIndex();
dir = ownIndex;
if (dir == 3) dir = 1;
else if (dir == 1) dir = 3;
isCatching = false;
isIdle = true;
_controller = GameController.getInstance() as GameController;
}
// Update is called once per frame
void Update () {
checkPlayerCome();
}
int getOwnIndex()
{
string name = this.gameObject.name;
char cindex = name[name.Length - 1];
int result = cindex - '0';
return result;
}
void checkPlayerCome()
{
if (_controller.getPlayerArea() == ownIndex)
{ //只有当走进自己的区域
if (!isCatching)
{
isCatching = true;
isIdle = false;
}
_controller.goCatch(this.gameObject);
}
else
{
if (isCatching)
{ //刚才为捕捉状态,但此时hero已经走出所属区域
//gameStatusOp.heroEscapeAndScore();
isCatching = false;
resetdir();
_controller.goBack(this.gameObject, isIdle);
}
else
{
//gameStatusOp.heroEscapeAndScore();
}
if(!isIdle)
{
checkIsIdle();
}
else
{
if(this.transform.position == prepos + Random[dir])
{
turn();
prepos = transform.position;
_controller.goarround(this.gameObject, dir);
}
}
}
}
void OnCollisionStay(Collision e)
{
//撞击hero,游戏结束
if (e.gameObject.name.Contains("player"))
{
_controller.patrolHitHeroAndGameover();
Debug.Log("Game Over!");
}
}
void resetdir()
{
dir = ownIndex;
if (dir == 3) dir = 1;
else if (dir == 1) dir = 3;
}
void checkIsIdle()
{
Vector3 a = this.transform.position;
Vector3 b = posset[ownIndex];
if (a == b)
{
isIdle = true;
prepos = posset[ownIndex];
_controller.goarround(this.gameObject, dir);
}
}
public void turn()
{
dir++;
if (dir > 3) dir = 0;
Debug.Log(dir + "turn");
}
}
UI
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UI : MonoBehaviour {
// Use this for initialization
void Start () {
}
public class Diretion
{
public const int UP = 0;
public const int DOWN = 2;
public const int LEFT = -1;
public const int RIGHT = 1;
}
// Update is called once per frame
void Update () {
if (Input.GetKey(KeyCode.UpArrow))
{
heroMove(Diretion.UP);
}
if (Input.GetKey(KeyCode.DownArrow))
{
heroMove(Diretion.DOWN);
}
if (Input.GetKey(KeyCode.LeftArrow))
{
heroMove(Diretion.LEFT);
}
if (Input.GetKey(KeyCode.RightArrow))
{
heroMove(Diretion.RIGHT);
}
}
public void heroMove(int dir)
{
transform.rotation = Quaternion.Euler(new Vector3(0, dir * 90, 0));
switch (dir)
{
case Diretion.UP:
transform.position += new Vector3(0, 0, 0.1f);
break;
case Diretion.DOWN:
transform.position += new Vector3(0, 0, -0.1f);
break;
case Diretion.LEFT:
transform.position += new Vector3(-0.1f, 0, 0);
break;
case Diretion.RIGHT:
transform.position += new Vector3(0.1f, 0, 0);
break;
}
}
}
大致是这样,详情请看GitHub
https://github.com/wakaka001/3d-game-learning/tree/master/Homework6