这次我们来做一个智能巡逻兵的游戏,先看看需求
首先我想着要做什么样的地图呢?单纯正方形没啥意思,突然想到之前看的一个户外真人闯关的综艺节目,和我们的游戏很像,它是蜂窝的形状的地图,由很多小的正六边形拼起来的大六边形。但是Unity3D没有正六边形的方块(但是自己挖的坑再大也要跳),我只能用正方体来组装成一个正六边形方块。
接着是上围墙,围墙就建几个长方体围住就行,长方体加上贴图就成了墙,只是正六面体需要旋转45,135度之类的
接着是巡逻兵制作,因为老师要求做成巡逻兵预制,即让巡逻兵自己拥有巡逻追捕功能。脚本如下:
public class GuardController : MonoBehaviour {
private float pos_X,pos_Z;
public float speed = 0.5f;
private float dis = 0;
private bool flag = true;
public int state = 0;
public GameObject role;//追捕的主角
int n = 0;
public SceneController sceneController;
// Use this for initialization
void Start () {
sceneController = (SceneController)SSDirector.getInstance().currentScenceController;
role = sceneController.role;//获得主角对象
pos_X = this.transform.position.x;
pos_Z = this.transform.position.z;
//获得巡逻兵的位置,因为是同一平面所以无需改变y
}
// FixedUpdate is called once per frame //因为我将Guard设置为刚体
void FixedUpdate () {
//根据状态选择动作
if(state == 0)
{
patrol();//巡逻
}
else if(state == 1)
{
chase(role);//追捕
}
}
void patrol()//按照正六边形行走
{
if (flag)
{
switch (n)
{
case 0:
pos_X += 1;
pos_Z -= 1;
break;
case 1:
pos_X += 2;
break;
case 2:
pos_X += 1;
pos_Z += 1;
break;
case 3:
pos_X -= 1;
pos_Z += 1;
break;
case 4:
pos_X -= 2;
break;
case 5:
pos_X -= 1;
pos_Z -= 1;
break;
}
flag = false;
}
dis = Vector3.Distance(transform.position, new Vector3(pos_X, 0, pos_Z));
if (dis > 0.7)
{
transform.position = Vector3.MoveTowards(this.transform.position, new Vector3(pos_X, 0, pos_Z), speed * Time.deltaTime);
}
else
{
n++;
n %= 6;
flag = true;
}
}
void chase(GameObject role)
{
transform.position = Vector3.MoveTowards(this.transform.position, role.transform.position, 0.5f * speed * Time.deltaTime);
}
}
然后考虑下如何什么情况下触发巡逻兵状态,因为我想根据距离但是可能role还没到另一个巡逻兵巡逻的地图,巡逻兵就追过来了。所以最后我改用触发器。在各个入口设置触发器。
但是问题来了,要让触发器触发的恰好是我们这个地图上的巡逻兵而不是其他巡逻兵。我在每个地图上挂载脚本获得当前Guard。
public class GetGuard : MonoBehaviour {
public GameObject guard;
void OnCollisionEnter(Collision collider)
{
Debug.Log(collider.gameObject.tag);
if(collider.gameObject.tag == "Guard")
{
Debug.Log(collider.gameObject.name);
guard = collider.gameObject;
}
}
}
然后在触发器写脚本,当然这里用到订阅与发布模式,进来然后能够出去即成功逃掉一次,发布事件,让记分员去订阅它,加分。
public class Gate : MonoBehaviour {
public delegate void AddScore();//委托
public static event AddScore addScore;//事件
// Use this for initialization
void OnTriggerEnter(Collider collider)
{
if (collider.gameObject.tag == "Player")
{
if (this.transform.parent.GetComponent<GetGuard>().guard.GetComponent<GuardController>().state == 0)
this.transform.parent.GetComponent<GetGuard>().guard.GetComponent<GuardController>().state = 1;
else
{
this.transform.parent.GetComponent<GetGuard>().guard.GetComponent<GuardController>().state = 0;
escape();
}
}
if(collider.gameObject.tag == "Guard")
{
this.transform.parent.GetComponent<GetGuard>().guard.GetComponent<GuardController>().state = 0;
}
}
void escape()
{
if(addScore != null)
{
addScore();//发布事件
}
}
}
然后在记分员里面订阅
public class ScoreRecorder : MonoBehaviour {
public Text ScoreText;
int Score = 0;
void GetScore()
{
Score++;
}
// Use this for initialization
void Start () {
Gate.addScore += GetScore;//订阅事件
}
// Update is called once per frame
void Update () {
ScoreText.text = "Score:" + Score.ToString();//更新分数
}
}
然后在role主角写脚本判断与Guard碰撞,即为被抓
public class RoleTrigger : MonoBehaviour {
public delegate void GameOver();//委托
public static event GameOver gameOver;//事件
void OnCollisionEnter(Collision other)
{
if(other.gameObject.tag == "Guard")
{
if(gameOver != null)
{
gameOver();//发布事件
}
}
}
}
然后写一下用户接口和场记就行(导演默认你们写好了,前面的博客有)
public interface IUserAction
{
void ShowDetail();//显示规则
void ReStart();//重新开始
}
public class UserInterface : MonoBehaviour {
private IUserAction action;
public GameObject role;
public float speed = 1;
public SceneController sceneController;
// Use this for initialization
void Start () {
action = SSDirector.getInstance().currentScenceController as IUserAction;
sceneController = (SceneController)SSDirector.getInstance().currentScenceController;
role = sceneController.role;
}
void OnGUI()
{
GUIStyle fontstyle1 = new GUIStyle();
fontstyle1.fontSize = 50;
fontstyle1.normal.textColor = new Color(255, 255, 255);
if (GUI.RepeatButton(new Rect(0, 0, 120, 40), "ESCAPE"))
{
action.ShowDetail();
}
if (GUI.Button(new Rect(0, 60, 120, 40), "RESTART"))
{
action.ReStart();
}
}
// Update is called once per frame
void Update () {
if(sceneController.game != 0)//游戏开始状态才可以接受用户输入移动主角
{
float translationX = Input.GetAxis("Horizontal") * speed;
float translationZ = Input.GetAxis("Vertical") * speed;
translationX *= Time.deltaTime;
translationZ *= Time.deltaTime;
role.transform.Translate(translationX, 0, 0);
role.transform.Translate(0, 0, translationZ);
}
}
}
实现导演要要载入资源用代码将多个正六边形拼接起来(自己作死)自己先手动计算偏移量,然后代码实现
public class SceneController : MonoBehaviour, ISceneController, IUserAction
{
public GameObject role;
public Text FinalText;
public int game = 1;
int size = 5;
void Awake()
//创建导演实例并载入资源
{
SSDirector director = SSDirector.getInstance();
director.setFPS(60);
director.currentScenceController = this;
director.currentScenceController.LoadResources();
}
public void LoadResources() //载入资源
{
Instantiate(Resources.Load("Prefabs/Light"));
role = Instantiate(Resources.Load("Prefabs/role")) as GameObject;
int pos_Z = 0, pos_X = 0,k;
for(int i = 0; i < size; i++)
{
pos_X = i * 6;
if (i <= size / 2)
{
k = i;
pos_Z = -k * 2;
}
else
{
k = (size - i - 1);
pos_Z = - k * 2;
}
for (int j = 0; j <= k; j++)
{
Instantiate(Resources.Load("Prefabs/Maze"), new Vector3(pos_X, 0, pos_Z), Quaternion.identity);
Instantiate(Resources.Load("Prefabs/Guard"), new Vector3(pos_X - 2, 0, pos_Z), Quaternion.identity);//每个地图初始化一个巡逻兵,因为我觉得这样写更简单所以我没写工厂了
pos_Z += 4;
}
}
}
// Use this for initialization
void Start () {
RoleTrigger.gameOver += GameOver;//订阅事件
}
// Update is called once per frame
void Update () {
}
void GameOver()
{
FinalText.text = "Game Over!!!";
game = 0;
}
//实现IUserAction的接口
public void ShowDetail() {
GUIStyle fontstyle1 = new GUIStyle();
fontstyle1.fontSize = 20;
fontstyle1.normal.textColor = new Color(255, 255, 255);
GUI.Label(new Rect(220, 50, 500, 500), "In the Maze you play a role, Try to escape away from\n Guard. Each success escape for one point.if you are\n caught by Guard, Game Over!!! Good Luck",fontstyle1);
}
//实现IUserAction的接口
public void ReStart() {
SceneManager.LoadScene("Task1");
game = 1;
}
}
然后我加了个摄像机随主角移动脚本
public class CameraMove : MonoBehaviour {
public GameObject role;
public SceneController sceneController;
private Vector3 offset;
// Use this for initialization
void Start () {
sceneController = (SceneController)SSDirector.getInstance().currentScenceController;
role = sceneController.role;
offset = role.transform.position - this.transform.position;
}
// Update is called once per frame
void Update () {
this.transform.position = role.transform.position - offset;
}
}
看看地图效果
这次作业就这样了,等以后有时间再改进,我想加入自动门功能,还有难度梯度,和动画人物模型。不过一切等我计组CPU,实训打完再说
![哭](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![哭](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![哭](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)