unity3d制作魔鬼与牧师 动作分离版

上次用了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)
  1. 定义动作基类:使用 virtual 申明虚方法,通过重写实现多态。这样继承者就明确使用Start 和 Update 编程游戏对象行为,利用接口实现消息通知,避免与动作管理者直接依赖。
public class SSAction : ScriptableObject
    {
        public bool enable = true;
        public bool distroy = false;
        // Use this for initialization
        public 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 frame
        public 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 initialization
        public 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 initialization
    void Start () {
        scene = Director.getInstance().currentSceneController as FirstController;
        scene.actionManger = this;
    }

    // Update is called once per frame
    void 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);
    }
}

最后小小抱怨一句:实训已经开始了,希望潘老师在接下来几周呢手下留情一定

猜你喜欢

转载自blog.csdn.net/qq_36297981/article/details/79886475
今日推荐