Unity3D学习笔记(4)-牧师与魔鬼游戏改进

这次实现的还是牧师与魔鬼游戏,不过在此基础上添加了一个动作管理器
把动作管理和游戏场景分离出来,上一个版本的链接在这里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);

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值