网站 工信部备案 收回搜索引擎网址
上次用了unity3d做了一个,虽然用了MVP的的设计模式,但是把动作管理放在场景里让项目的耦合程度太高,所以应该把动作从场景类分离出来,场景只需要控制视图就可以了。(这都是我随便乱吹的,其实我也不清楚为什么要动作分离)
盗用别人的uml图
1. 向上周的作业一样,先把场景构建好
basecode
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.MyGame;
namespace Com.MyGame
{public class Director : System.Object{private static Director _instance;public SceneController currentSceneController { get; set; }public static Director getInstance(){if (_instance == null){_instance = new Director();}return _instance;}}public interface SceneController{void loadResources();}
}
UserGUI
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.MyGame;public class UserGUI : MonoBehaviour
{public FirstController scene;public int status = 0;GUIStyle style;GUIStyle buttonStyle;float time = 60;float second = 0;void Start(){scene = Director.getInstance().currentSceneController as FirstController;style = new GUIStyle();style.fontSize = 40;style.alignment = TextAnchor.MiddleCenter;buttonStyle = new GUIStyle("button");buttonStyle.fontSize = 30;}private void Update(){scene.check_game_over();}void OnGUI(){second += Time.deltaTime / 2;if (second >= 1){time--;second = 0;}if (time > 0 && status == 0){GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 2 - 85, 100, 50), time.ToString(), style);}if (status == 1 || time <= 0){GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 2 - 85, 100, 50), "You Fail!", style);if (GUI.Button(new Rect(Screen.width / 2 - 70, Screen.height / 2, 140, 70), "Restart", buttonStyle)){status = 0;time = 60;second = 0;scene.restart();}}else if (status == 2){GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 2 - 85, 100, 50), "You win!", style);if (GUI.Button(new Rect(Screen.width / 2 - 70, Screen.height / 2, 140, 70), "Restart", buttonStyle)){status = 0;time = 60;second = 0;scene.restart();}}}
}
FirtstController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.MyGame;public class FirstController2 : MonoBehaviour, SceneController
{public CCActionManager actionManger { get; set; }public List<GameObject> LeftObjList { get; set; }public List<GameObject> RightObjList { get; set; }public GameObject[] boat_people { get; set; }Vector3 river_pos = new Vector3(0, 0, 0);public GameObject startShore { get; set; }public GameObject endShore { get; set; }public GameObject boat { get; set; }Vector3 startShorePos = new Vector3(11, 0.5f, 0);Vector3 endShorePos = new Vector3(-11, 0.5f, 0);Vector3 boatStartPos = new Vector3(4, 0.7f, 0);Vector3 boatEndPos = new Vector3(-4, 0.7f, 0);UserGUI userGUI;void Awake(){LeftObjList = new List<GameObject>();RightObjList = new List<GameObject>();boat_people = new GameObject[2];Director director = Director.getInstance();director.currentSceneController = this;userGUI = gameObject.AddComponent<UserGUI>() as UserGUI;loadResources();}public void loadResources(){GameObject river = Instantiate(Resources.Load("prefab/river", typeof(GameObject)), river_pos, Quaternion.identity, null) as GameObject;river.name = "river";startShore = Instantiate(Resources.Load("prefab/coast", typeof(GameObject)), startShorePos, Quaternion.identity, null) as GameObject;startShore.name = "startShore";endShore = Instantiate(Resources.Load("prefab/coast", typeof(GameObject)), endShorePos, Quaternion.identity, null) as GameObject;endShore.name = "endShore";boat = Instantiate(Resources.Load("prefab/boat", typeof(GameObject)), boatStartPos, Quaternion.identity, null) as GameObject;boat.name = "boat";boat.transform.parent = startShore.transform;GameObject priest, devil;for (int i = 0; i < 3; ++i){priest = Instantiate(Resources.Load("prefab/priest")) as GameObject;priest.name = i.ToString();priest.transform.position = new Vector3(7f + i * 1.5f, 2f, 0);priest.transform.parent = startShore.transform;LeftObjList.Add(priest);devil = Instantiate(Resources.Load("prefab/devil")) as GameObject;devil.name = (i + 3).ToString();devil.transform.position = new Vector3(7f + (i + 3) * 1.5f, 2f, 0);devil.transform.parent = startShore.transform;LeftObjList.Add(devil);}}public void check_game_over(){int start_priests = 0;int start_devil = 0;int end_priests = 0;int end_devil = 0;foreach(GameObject gb in LeftObjList){if (gb.transform.tag == "priest"){start_priests++;}else{start_devil++;}}foreach(GameObject gb in RightObjList){if (gb.transform.tag == "priest"){end_priests++;}else{end_devil++;}}foreach(GameObject gb in boat_people){if (gb == null)continue;if (boat.transform.parent == startShore .transform){if (gb.transform.tag == "priest"){start_priests++;}else{start_devil++;}}else{if (gb.transform.tag == "priest"){end_priests++;}else{end_devil++;}}}if (end_priests + end_devil == 6){userGUI.status = 2;return;}if ((start_priests < start_devil && start_priests > 0 )|| (end_priests < end_devil && end_priests > 0)){userGUI.status = 1;return;}userGUI.status = 0;}public void restart(){Application.LoadLevel(Application.loadedLevelName);}}
接下来就是动作管理了(主要是参考老师的ppt)
- 定义动作基类:使用 virtual 申明虚方法,通过重写实现多态。这样继承者就明确使用Start 和 Update 编程游戏对象行为,利用接口实现消息通知,避免与动作管理者直接依赖。
public class SSAction : ScriptableObject{public bool enable = true;public bool distroy = false;// Use this for initializationpublic GameObject gameObject { get; set; }public Transform transform { get; set; }public ISSActionCallback callback { get; set; }public virtual void Start(){throw new System.NotImplementedException();}// Update is called once per framepublic virtual void Update(){throw new System.NotImplementedException();}}
2.简单的动作实现(船移动,牧师魔鬼移动)
public class CCMoveAction : SSAction{public Vector3 target;public float speed;public static CCMoveAction GetCCMoveAction(Vector3 target, float speed){CCMoveAction action = ScriptableObject.CreateInstance<CCMoveAction>();action.target = target;action.speed = speed;return action;}public override void Start(){}public override void Update(){this.transform.position = Vector3.MoveTowards(this.transform.position, target, speed * Time.deltaTime);if (this.transform.position == target){this.distroy = true;this.callback.SSActionEvent(this);}}}
- 组合动作实现,组合动作可以用来定义一系列动作,让这一系列动作可以按顺序执行(借用了老师的代码)
public class CCSequenceAction : SSAction, ISSActionCallback{public List<SSAction> sequence;public int repeat = -1;public int start = 0;public static CCSequenceAction GetSSAction(int repeat, int start, List<SSAction> sequence){CCSequenceAction action = ScriptableObject.CreateInstance<CCSequenceAction>();action.repeat = repeat;action.sequence = sequence;action.start = start;return action;}public override void Update(){if (sequence.Count == 0) return;if (start < sequence.Count){sequence[start].Update();}}public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted, int Param = 0, string strParam = null, Object objectParam = null){source.distroy = false;this.start++;if (this.start >= sequence.Count){this.start = 0;if (repeat > 0) repeat--;if (repeat == 0){this.distroy = true;this.callback.SSActionEvent(this);}}}// Use this for initializationpublic override void Start(){foreach (SSAction action in sequence){action.gameObject = this.gameObject;action.transform = this.transform;action.callback = this;action.Start();}}void OnDestory() { }}
- 动作时间接口定义
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);}
- 动作管理器基类
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>();protected void Update(){foreach (SSAction ac in waitingAdd){actions[ac.GetInstanceID()] = ac;}waitingAdd.Clear();foreach (KeyValuePair<int, SSAction> kv in actions){SSAction ac = kv.Value;if (ac.distroy){waitingDelete.Add(ac.GetInstanceID());}else if (ac.enable){ac.Update();}}foreach (int key in waitingDelete){SSAction ac = actions[key];actions.Remove(key);DestroyObject(ac);}waitingDelete.Clear();}public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager){action.gameObject = gameobject;action.transform = gameobject.transform;action.callback = manager;waitingAdd.Add(action);action.Start();}protected void Start() {}
- 从动作管理器基类派生出一个类来管理具体过河动作
public class CCActionManager :SSActionManager, ISSActionCallback {public SSAction action1, action2;public CCSequenceAction sAction;public FirstController scene;float speed = 20f;void ISSActionCallback.SSActionEvent(SSAction source, SSActionEventType events, int intParam, string strParam, Object objectParam){}// Use this for initializationvoid Start () {scene = Director.getInstance().currentSceneController as FirstController;scene.actionManger = this;}// Update is called once per framevoid Update () {GameObject gameObj = null;base.Update();if (Input.GetMouseButtonDown(0)){Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if (Physics.Raycast(ray, out hit)) gameObj = hit.transform.gameObject;}if (gameObj != null){if (gameObj.transform.tag == "priest" || gameObj.transform.tag == "devil"){int seatNum, shoreNum;if (gameObj.transform.parent == scene.boat.transform.parent && (scene.boat_people[0] == null || scene.boat_people[1] == null)){seatNum = scene.boat_people[0] == null ? 0 : 1;if (gameObj.transform.parent == scene.startShore.transform){shoreNum = 0;for (int i = 0; i < scene.LeftObjList.Count; ++i){if (gameObj.name == scene.LeftObjList[i].name){getOnBoat(gameObj, shoreNum, seatNum);scene.LeftObjList.Remove(gameObj);}}}else{shoreNum = 1;for (int i = 0; i < scene.RightObjList.Count; ++i){if (gameObj.name == scene.RightObjList[i].name){getOnBoat(gameObj, shoreNum, seatNum);scene.RightObjList.Remove(gameObj);}}}scene.boat_people[seatNum] = gameObj;base.Update();gameObj.transform.parent = scene.boat.transform;}else if (gameObj.transform.parent == scene.boat.transform){shoreNum = scene.boat.transform.parent == scene.startShore.transform ? 0 : 1;seatNum =(scene.boat_people[0]!=null && scene.boat_people[0] == gameObj) ? 0 : 1;getOffBoat(gameObj, shoreNum);base.Update();scene.boat_people[seatNum] = null;if (shoreNum == 0){scene.LeftObjList.Add(gameObj);gameObj.transform.parent = scene.startShore.transform;}else{scene.RightObjList.Add(gameObj);gameObj.transform.parent = scene.endShore.transform;}}}else if(gameObj.transform.name == "boat"){if (scene.boat_people[0] != null || scene.boat_people[1] != null){moveBoat(scene.boat);scene.boat.transform.parent = scene.boat.transform.parent == scene.startShore.transform ?scene.endShore.transform : scene.startShore.transform;}}}scene.check_game_over();}public void moveBoat(GameObject boat){Vector3 pos = boat.transform.position == new Vector3(4, 0.7f, 0) ? new Vector3(-4, 0.7f, 0) : new Vector3(4, 0.7f, 0);action1 = CCMoveAction.GetCCMoveAction(pos, speed);this.RunAction(boat, action1, this);}public void getOnBoat(GameObject people, int shore, int seat){if (shore == 0 && seat == 0){action1 = CCMoveAction.GetCCMoveAction(new Vector3(3f, 2f, 0), speed);action2 = CCMoveAction.GetCCMoveAction(new Vector3(3f, 1.5f, 0), speed);}else if (shore == 0 && seat == 1){action1 = CCMoveAction.GetCCMoveAction(new Vector3(4.5f, 2f, 0), speed);action2 = CCMoveAction.GetCCMoveAction(new Vector3(4.5f, 1.5f, 0), speed);}else if (shore == 1 && seat == 0){action1 = CCMoveAction.GetCCMoveAction(new Vector3(-5f, 2f, 0), speed);action2 = CCMoveAction.GetCCMoveAction(new Vector3(-5f, 1.5f, 0), speed);}else if (shore == 1 && seat == 1){action1 = CCMoveAction.GetCCMoveAction(new Vector3(-3.5f, 2f, 0), speed);action2 = CCMoveAction.GetCCMoveAction(new Vector3(-3.5f, 1.5f, 0), speed);}CCSequenceAction saction = CCSequenceAction.GetSSAction(0, 0, new List<SSAction> { action1, action2 });this.RunAction(people, saction, this);}public void getOffBoat(GameObject people, int shoreNum){action1 = CCMoveAction.GetCCMoveAction(new Vector3(people.transform.position.x, 2f, 0), speed);if (shoreNum == 0) action2 = CCMoveAction.GetCCMoveAction(new Vector3(7 + 1.5f * System.Convert.ToInt32(people.name), 2f, 0), speed);else action2 = CCMoveAction.GetCCMoveAction(new Vector3(-7f - 1.5f * System.Convert.ToInt32(people.name), 2f, 0), speed);CCSequenceAction saction = CCSequenceAction.GetSSAction(0, 0, new List<SSAction> { action1, action2 });this.RunAction(people, saction, this);}
}
最后小小抱怨一句:实训已经开始了,希望潘老师在接下来几周呢手下留情一定