参考资料
https://blog.csdn.net/ke1950523491/article/details/80287848
提交要求
游戏设计要求:
- 创建一个地图和若干巡逻兵(使用动画);
- 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址。即每次确定下一个目标位置,用自己当前位置为原点计算;
- 巡逻兵碰撞到障碍物,则会自动选下一个点为目标;
- 巡逻兵在设定范围内感知到玩家,会自动追击玩家;
- 失去玩家目标后,继续巡逻;
- 计分:玩家每次甩掉一个巡逻兵计一分,与巡逻兵碰撞游戏结束;
程序设计要求:
- 必须使用订阅与发布模式传消息
subject:OnLostGoal
Publisher: ?
Subscriber: ? - 工厂模式生产巡逻兵
游戏设计
游戏UML图如下
- 工厂模式:使用PatrolFactory实例进行Patrol的生产
- 订阅者模式:ScoreRecorder进行订阅,当某些游戏事件发生时会收到通知,更改自己的score
FirstController
加载资源,包括player、Patrol、plane的预制,PatrolFactory、ScoreRecorder实例化,player的移动
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
public enum GameState { BEGIN, END };
public class FirstController: MonoBehaviour ,ISceneController,IUserAction
{
private PatrolFactory patrolFactory;
public GameObject player;
public List<GameObject> patrols;
public GameObject plane;
public GameState gameState;
public ScoreRecorder scoreRecorder;
GameObject rush;
void Awake()
{
SSDirector director = SSDirector.getInstance();
director.currentScenceController = this;
patrolFactory = Singleton<PatrolFactory>.Instance;
LoadResources();
gameState = GameState.BEGIN;
PatrolCollide.catchSuccess += Gameover;
scoreRecorder = Singleton<ScoreRecorder>.Instance;
}
public void LoadResources()
{
plane = Instantiate(Resources.Load<GameObject>("Prefabs/Plane"));
plane.transform.position = Vector3.zero;
patrols = patrolFactory.GetPatrols();
player= Instantiate(Resources.Load<GameObject>("Prefabs/Player"));
player.transform.position = new Vector3(1.8f, -0.35f,1.8f);
//player.transform.Rotate(0, 180, 0);
}
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;
}
public void Gameover()
{
gameState = GameState.END;
}
public void PlayerMove(Vector3 pos)
{
player.transform.Translate(pos);
}
}
PatrolFactory
负责Patrol的生产和回收
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
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;
}
}
ScoreRecorder
订阅消息
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ScoreRecorder : MonoBehaviour
{
int Score = 0;
void SetScore()
{
Score++;
}
// Use this for initialization
void Start()
{
AreaCollide.addScore += SetScore;//订阅事件
}
public int GetScore()
{
return Score;
}
}
CameraMove
让摄像头随玩家移动
using System;
using System.Collections.Generic;
using UnityEngine;
public class CameraMove : MonoBehaviour
{
public GameObject player;
public FirstController sceneController;
private Vector3 offset;
// Use this for initialization
void Start()
{
sceneController = (FirstController)SSDirector.getInstance().currentScenceController;
player = sceneController.player;
offset = player.transform.position - this.transform.position;
}
// Update is called once per frame
void Update()
{
player = sceneController.player;
if (sceneController.gameState == GameState.BEGIN)
this.transform.position = player.transform.position - offset;
}
}
Player
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class Player : MonoBehaviour
{
public void FixedUpdate()
{
gameObject.GetComponent<Rigidbody>().freezeRotation = true;
gameObject.GetComponent<Rigidbody>().velocity = new Vector3(0, 0, 0);
}
}
UI
游戏界面,代理scorerecorder显示分数
using System;
using System.Collections.Generic;
using UnityEngine;
public interface IUserAction
{
void ReStart();//重新开始
}
public class UI : MonoBehaviour
{
public GameObject player;
public IUserAction action;
public FirstController sceneController;
private float speed = 3f;
void Start()
{
sceneController = SSDirector.getInstance().currentScenceController as FirstController;
action = (FirstController)SSDirector.getInstance().currentScenceController as IUserAction;
player = sceneController.player;
}
void OnGUI()
{
if (GUI.Button(new Rect(0, 0, 120, 40), "RESTART"))
{
action.ReStart();
}
if(sceneController.gameState == GameState.END)
{
GUI.Label(new Rect(Screen.width / 2-100, 50, 120, 50),"Game Over!");
}
GUI.Label(new Rect(Screen.width / 2 - 100 , 10, 120, 50), "Score: " + sceneController.scoreRecorder.GetScore().ToString());
}
private void Update()
{
if(sceneController.gameState == GameState.BEGIN)
{
float translationX = Input.GetAxis("Horizontal") * speed;
float translationZ = Input.GetAxis("Vertical") * speed;
translationX *= Time.deltaTime;
translationZ *= Time.deltaTime;
sceneController.PlayerMove(new Vector3(translationX,0,translationZ));
}
}
}
Singleton、SSDirector、ISceneController类和之前的类似。