这次实现的还是牧师与魔鬼游戏,不过在此基础上添加了一个动作管理器
把动作管理和游戏场景分离出来,上一个版本的链接在这里http://blog.csdn.net/x2_yt/article/details/61912680,有兴趣的朋友可以
去看看。
以下是整个文件的UML图:
- SSActionManager类是动作管理的基类,所有动作管理器都要继承于它
- CCActionManager是SSAction Manager的一个子类,动作管理主要是由这个类实现
- SSAction是动作的基类,所有的动作都必须继承它
- CCMoveToAction和CCOn_OffAction是连个具体的动作
- ISSActionCallback接口是动作管理器与动作通信的接口
以下是整个程序所有的源代码
UserGUI.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UserGUI : MonoBehaviour
{
private IUserAction action;
// Use this for initialization
void Start () {
action = Director.getInstance().currentSceneControl as IUserAction;
}
private void OnGUI()
{
if (GUI.Button(new Rect(700, 100, 90, 90), "GO") && action.getGameState() == GameState.NOT_ENDED)
{
action.MoveBoat();
}
if (action.getGameState() == GameState.WIN)
{
GUI.Label(new Rect(700, 300, 400, 400), "you win");
GUI.color = Color.red;
}
if ((action.getGameState() == GameState.FAILED)) {
action.GameOver();
}
}
}
IUserAction.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum GameState { WIN, FAILED, NOT_ENDED }
public interface IUserAction {
void MoveBoat();
void GameOver();
GameState getGameState();
}
ISceneControl.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface ISceneControl {
void GenGameObjects();
}
Director.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Director : System.Object {
public ISceneControl currentSceneControl { get; set; }
private static Director director;
private Director()
{
}
public static Director getInstance()
{
if (director == null)
{
director = new Director();
}
return director;
}
}
FirstSceneControl.cs
/* 这个文件是用来控制主游戏场景的,负责第一个游戏场景的初始化,主要是游戏资源的加载,
* 场景船的状态和游戏状态的管理,牧师和魔鬼位置状态的管理
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FirstSceneControl : MonoBehaviour, ISceneControl, IUserAction {
public CCActionManager actionManager { get; set; }
public enum BoatState { MOVING, STOPLEFT,STOPRIGHT}
public GameObject Shore_l; //左岸游戏对象
public GameObject Shore_r; //右岸游戏对象
public GameObject boat; //船游戏对象
public Dictionary<int, GameObject> On_Boat = new Dictionary<int, GameObject>(); //管理在船上的人物游戏对象
public Dictionary<int, GameObject> On_Shore_r = new Dictionary<int, GameObject>(); //管理在左岸的人物游戏对象
public Dictionary<int, GameObject> On_Shore_l = new Dictionary<int, GameObject>(); //管理在右岸的人物游戏对象
//船在左右两岸停靠的位置
public Vector3 Boat_Left = new Vector3(-10.4f, -9.5f, 0);
public Vector3 Boat_Right = new Vector3(10.4f, -9.5f, 0);
public GameState game_state; //管理游戏状态
float gab = 1.5f; //在岸上游戏对象的位置间隔
public int boat_capicity; //船的容量
public BoatState b_state; //船的状态
void Awake () {
Director director = Director.getInstance();
director.currentSceneControl = this;
director.currentSceneControl.GenGameObjects();
}
//该函数用来生成该游戏场景所需的资源
public void GenGameObjects()
{
Shore_l = GameObject.CreatePrimitive(PrimitiveType.Cube);
Shore_l.name = "Shore_l";
Shore_l.transform.localScale = new Vector3(10, 2, 1);
Shore_l.transform.position = new Vector3(-17, -9, 0);
Shore_r = Instantiate<GameObject>(Shore_l, new Vector3(17, -9, 0), Quaternion.identity);
Shore_r.name = "Shore_r";
boat = GameObject.CreatePrimitive(PrimitiveType.Cube); ;
boat.transform.localScale = new Vector3(3, 1, 1);
boat.transform.position = Boat_Right;
boat.name = "boat";
GameObject temp_priest = GameObject.CreatePrimitive(PrimitiveType.Sphere);
temp_priest.transform.localScale = new Vector3(1, 1, 1);
temp_priest.AddComponent<On_Off>();
GameObject temp_devil = GameObject.CreatePrimitive(PrimitiveType.Cube);
temp_devil.transform.localScale = new Vector3(1, 1, 1);
temp_devil.AddComponent<On_Off>();
for (int i = 0; i < 3; i++)
{
On_Shore_r.Add(i, Instantiate<GameObject>(temp_priest, new Vector3(12.5f + i * gab, -7.5f, 0), Quaternion.identity));
On_Shore_r[i].name = i.ToString();
}
for (int i = 3; i < 6; i++)
{
GameObject tmp = Instantiate<GameObject>(temp_devil, new Vector3(12.5f + i * gab, -7.5f, 0), Quaternion.identity);
tmp.name = i.ToString();
tmp.GetComponent<Renderer>().material.color = Color.red;
On_Shore_r.Add(i, tmp);
}
boat_capicity = 2;
b_state = BoatState.STOPLEFT;
Destroy(temp_devil);
Destroy(temp_priest);
}
private void Update()
{
game_state = check();
// 更新维护船的状态
if (boat.transform.position == Boat_Right)
{
b_state = BoatState.STOPRIGHT;
}
else if (boat.transform.position == Boat_Left)
{
b_state = BoatState.STOPLEFT;
}
else
{
b_state = BoatState.MOVING;
}
// 更新左右两岸和船上游戏对象的位置状态
for (int i = 0; i < 6; i++)
{
if (On_Shore_l.ContainsKey(i)) On_Shore_l[i].transform.position = new Vector3(-12.5f - i * gab, -7.5f, 0);
if (On_Shore_r.ContainsKey(i)) On_Shore_r[i].transform.position = new Vector3(12.5f + i * gab, -7.5f, 0);
}
int signed = 1;
for (int i = 6; i < 12; i++)
{
if (On_Boat.ContainsKey(i))
{
On_Boat[i].transform.localPosition = new Vector3(signed * 0.3f, 1, 0);
signed = -signed;
}
}
}
// 当点击GO按钮时,判断船的停靠位置,并激活相应的动作,具体的动作管理有动作管理器负责
public void MoveBoat()
{
if (On_Boat.Count != 0)
{
if (b_state == BoatState.STOPLEFT)
{
actionManager.moveToRight.enable = true;
}
if (b_state == BoatState.STOPRIGHT)
{
actionManager.moveToLeft.enable = true;
}
}
}
public void GameOver()
{
GUI.color = Color.red;
GUI.Label(new Rect(700, 300, 400, 400), "GAMEOVER");
}
public int get_num(Dictionary<int, GameObject> dict, int ch)
{
var keys = dict.Keys;
int d_num = 0;
int p_num = 0;
foreach(int i in keys)
{
if (i < 3 || (i >= 6 && i <= 8))
{
p_num++;
}
else
{
d_num++;
}
}
return (ch == 1 ? p_num : d_num);
}
//该函数负责游戏状态的更新
GameState check()
{
if (On_Shore_l.Count == 6)
{
return GameState.WIN;
}
else if (b_state == BoatState.STOPLEFT)
{
if (get_num(On_Boat, 1) + get_num(On_Shore_l, 1) != 0
&& get_num(On_Boat, 1) + get_num(On_Shore_l, 1) < (get_num(On_Boat, -1) + get_num(On_Shore_l, -1)))
{
return GameState.FAILED;
}
if(get_num(On_Shore_r, 1) != 0 && get_num(On_Shore_r, 1) < get_num(On_Shore_r, -1))
{
return GameState.FAILED;
}
}
else if (b_state == BoatState.STOPRIGHT)
{
if (get_num(On_Boat, 1) + get_num(On_Shore_r, 1) != 0
&& get_num(On_Boat, 1) + get_num(On_Shore_r, 1) < (get_num(On_Boat, -1) + get_num(On_Shore_r, -1)))
{
return GameState.FAILED;
}
if (get_num(On_Shore_l, 1) != 0 && get_num(On_Shore_l, 1) < get_num(On_Shore_l, -1))
{
return GameState.FAILED;
}
}
return GameState.NOT_ENDED;
}
public GameState getGameState()
{
return game_state;
}
}
SSActionManager.cs
/* 这个文件写的类是所有动作管理器的基类
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SSActionManager : MonoBehaviour {
private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>(); //保存所以已经注册的动作
private List<SSAction> waitingAdd = new List<SSAction>(); //动作的等待队列,在这个对象保存的动作会稍后注册到动作管理器里
private List<int> waitingDelete = new List<int>(); //动作的删除队列,在这个对象保存的动作会稍后删除
// Use this for initialization
protected void Start()
{
}
// Update is called once per frame
protected void Update()
{
//把等待队列里所有的动作注册到动作管理器里
foreach (SSAction ac in waitingAdd) actions[ac.GetInstanceID()] = ac;
waitingAdd.Clear();
//管理所有的动作,如果动作被标志为删除,则把它加入删除队列,被标志为激活,则调用其对应的Update函数
foreach (KeyValuePair<int, SSAction> kv in actions)
{
SSAction ac = kv.Value;
if (ac.destroy)
{
waitingDelete.Add(ac.GetInstanceID());
}
else if (ac.enable)
{
ac.Update();
}
}
//把删除队列里所有的动作删除
foreach (int key in waitingDelete)
{
SSAction ac = actions[key];
actions.Remove(key);
DestroyObject(ac);
}
}
//初始化一个动作
public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager)
{
action.gameobject = gameobject;
action.transform = gameobject.transform;
action.callback = manager;
waitingAdd.Add(action);
action.Start();
}
}
CCActionManager.cs
/* 这个文件是用来管理游戏动作的,负责管理船向左移,向右移和人物移动的管理
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CCActionManager : SSActionManager, ISSActionCallback {
public FirstSceneControl sceneController;
public CCMoveToAction moveToLeft, moveToRight;
public Dictionary<int, CCOn_OffAction> on_off = new Dictionary<int, CCOn_OffAction>();
protected new void Start()
{
float speed = 5f;
sceneController = (FirstSceneControl)Director.getInstance().currentSceneControl;
sceneController.actionManager = this;
//注册船向左移和向右移的动作和每个人物对应的上下船的动作
moveToLeft = CCMoveToAction.GetSSAction(sceneController.Boat_Left, speed);
moveToRight = CCMoveToAction.GetSSAction(sceneController.Boat_Right, speed);
foreach (KeyValuePair<int, GameObject> obj in sceneController.On_Shore_r)
{
on_off[obj.Key] = CCOn_OffAction.GetSSAction();
}
//启动所有注册的动作
this.RunAction(sceneController.boat, moveToLeft, this);
this.RunAction(sceneController.boat, moveToRight, this);
foreach (KeyValuePair<int, GameObject> obj in sceneController.On_Shore_r)
{
this.RunAction(obj.Value, on_off[obj.Key], this);
}
}
public void SSActionEvent(SSAction source,
SSActionEventType events = SSActionEventType.Competeted,
int intParam = 0,
string strParam = null,
Object objectParam = null)
{
}
}
SSAction.cs
/* 这个文件是所有动作的基类
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SSAction : ScriptableObject {
public bool enable = false;
public bool destroy = false;
public GameObject gameobject { get; set; }
public Transform transform { get; set; }
public ISSActionCallback callback { get; set; }
protected SSAction() { }
public virtual void Start () {
throw new System.NotImplementedException();
}
// Update is called once per frame
public virtual void Update () {
throw new System.NotImplementedException();
}
}
CCMoveToAction.cs
/* 这个文件是移动动作的类,主要用来实现船的向左移动和向右移动
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CCMoveToAction : SSAction {
public Vector3 target; //要移到的位置
public float speed; //移动的速度
//获取一个移动动作的实例对象
public static CCMoveToAction GetSSAction(Vector3 target, float speed)
{
CCMoveToAction action = ScriptableObject.CreateInstance<CCMoveToAction>();
action.target = target;
action.speed = speed;
Debug.Log(speed.ToString());
return action;
}
// Use this for initialization
public override void Start () {
}
// Update is called once per frame
public override void Update () {
this.transform.position = Vector3.MoveTowards(this.transform.position, target, speed * Time.deltaTime);
if (this.transform.position == target)
{
//this.destroy = true;
this.enable = false;
this.callback.SSActionEvent(this); //因为SSActionEvent这个函数并没有实现,所以这里并没有什么作用
}
}
}
CCOn_OffAction.cs
/* 这个文件用来实现人物的上下船的动作
*/
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CCOn_OffAction : SSAction {
private FirstSceneControl firstSceneControl;
enum Pos { ON_BOAT, ON_SHORE } //管理人物游戏对象的位置
//判断人物游戏对象的位置
Pos find_Pos(int id)
{
if (id >= 6) return Pos.ON_BOAT;
return Pos.ON_SHORE;
}
public static CCOn_OffAction GetSSAction()
{
CCOn_OffAction action = ScriptableObject.CreateInstance<CCOn_OffAction>();
return action;
}
// Use this for initialization
public override void Start () {
firstSceneControl = (FirstSceneControl)Director.getInstance().currentSceneControl;
}
/* 通过id来判断人物游戏对象的位置,
* 每个人物对象在不同的位置都有一个id,
* 在右岸时,从左到右编号为0~5,人物在左岸的
* id与右岸相同,如果人物上船,那么它对应的id就
* 加6,如果人物下船,那么它对应的id就减6,另外
* 人物的id与它们的名字时刻对应,id改变,名字也
* 会改变
*/
public override void Update () {
if (firstSceneControl.game_state == GameState.NOT_ENDED)
{
if (firstSceneControl.b_state == FirstSceneControl.BoatState.MOVING) return;
int id = Convert.ToInt32(gameobject.name);
if (firstSceneControl.b_state == FirstSceneControl.BoatState.STOPRIGHT)
{
if (firstSceneControl.On_Shore_r.ContainsKey(id))
{
if (find_Pos(id) == Pos.ON_SHORE && firstSceneControl.boat_capicity != 0)
{
firstSceneControl.On_Boat.Add(id + 6, firstSceneControl.On_Shore_r[id]);
firstSceneControl.On_Shore_r.Remove(id);
gameobject.name = (id + 6).ToString();
gameobject.transform.parent = firstSceneControl.boat.transform;
firstSceneControl.boat_capicity--;
}
}
if (find_Pos(id) == Pos.ON_BOAT)
{
firstSceneControl.On_Shore_r.Add(id - 6, firstSceneControl.On_Boat[id]);
firstSceneControl.On_Boat.Remove(id);
gameobject.name = (id - 6).ToString();
gameobject.transform.parent = null;
firstSceneControl.boat_capicity++;
}
}
if (firstSceneControl.b_state == FirstSceneControl.BoatState.STOPLEFT)
{
if (find_Pos(id) == Pos.ON_SHORE && firstSceneControl.boat_capicity != 0)
{
if (firstSceneControl.On_Shore_l.ContainsKey(id))
{
firstSceneControl.On_Boat.Add(id + 6, firstSceneControl.On_Shore_l[id]);
firstSceneControl.On_Shore_l.Remove(id);
gameobject.name = (id + 6).ToString();
gameobject.transform.parent = firstSceneControl.boat.transform;
firstSceneControl.boat_capicity--;
}
}
if (find_Pos(id) == Pos.ON_BOAT)
{
firstSceneControl.On_Shore_l.Add(id - 6, firstSceneControl.On_Boat[id]);
firstSceneControl.On_Boat.Remove(id);
gameobject.name = (id - 6).ToString();
gameobject.transform.parent = null;
firstSceneControl.boat_capicity++;
}
}
int new_id = Convert.ToInt32(gameobject.name);
if (id != new_id)
{
this.enable = false;
this.callback.SSActionEvent(this);
}
}
}
}
On_Off.cs
/* 这个文件要挂载到所有的人物对象上,用来监听鼠标的点击事件,
* 对应的具体的动作在CCOn_OffAction.cs文件里面实现
*/
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class On_Off : MonoBehaviour
{
// Use this for initialization
private FirstSceneControl firstSceneControl;
void Start()
{
firstSceneControl = (FirstSceneControl)Director.getInstance().currentSceneControl;
}
private void OnMouseDown()
{
int id = Convert.ToInt32(this.name);
if (firstSceneControl.b_state != FirstSceneControl.BoatState.MOVING)
{
if (firstSceneControl.actionManager.on_off.ContainsKey(id)) firstSceneControl.actionManager.on_off[id].enable = true;
if (firstSceneControl.actionManager.on_off.ContainsKey(id - 6)) firstSceneControl.actionManager.on_off[id - 6].enable = true;
}
}
}
ISSActionCallback.cs
/* 这个文件所写接口是负责动作管理器和其管理的动作之间的通信
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum SSActionEventType:int { Started, Competeted }
public interface ISSActionCallback {
void SSActionEvent(SSAction source,
SSActionEventType events = SSActionEventType.Competeted,
int intParam = 0,
string strParam = null,
Object objectParam = null);
}