牧师与魔鬼

一、动作分离和MVC的区别

动作分离和MVC是两种常用的软件架构设计模式,它们的区别在于实现方式和重点。

动作分离(AA)是一种轻量级架构,它基于观察者模式实现。应用程序由多个独立的模块组成,这些模块被设计为只负责将信息从一个模块传递到另一个,模块之间没有直接的耦合关系。当一个事件发生时,事件的产生者会通知所有观察者,观察者可以根据事件的类型对事件进行处理。动作分离的重点在于分离视图和模型,以及事件的处理。

MVC模式(Model-View-Controller)是一种更为复杂的架构,它将应用程序的三个基本部分进行分离:数据模型、用户界面和控制器。MVC模式的核心是控制器,它接受用户的交互请求,并负责调用合适的模型来处理请求,最后更新用户界面。MVC模式的重点在于分离模型、视图和控制器,以及实现数据的变更通知和视图的更新。

二、动作管理器的设计

9d21217772c6c96b1d30f362da508f2.png

要求:
设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束。

三、视频演示

实现效果与上一次实验效果一致,具体可看视频

四、代码解释

本次实验比上次多了裁判类

裁判类Judge:
裁判类实际上是把原来FirstController中的check_game_over单独分离出来成为一个类,而check_game_over中主要需要这三个对象的属性来进行判断:

    private CoastController fromCoast;
    private CoastController toCoast;
    private BoatController boat;

构造函数Judge用于初始化这三个成员变量。

public Judge(CoastController cfrom, CoastController cto, BoatController b){
        fromCoast = cfrom;
        toCoast = cto;
        boat = b;
    }

check_game_over()方法用于检查游戏是否结束。它首先统计起始岸和目标岸上的牧师和魔鬼的数量,然后根据一些规则判断游戏的结果。如果目标岸上的牧师和魔鬼的数量之和等于6,则游戏胜利,返回2;如果起始岸上的牧师数量小于魔鬼数量,并且牧师数量大于0,则游戏失败,返回1;如果目标岸上的牧师数量小于魔鬼数量,并且牧师数量大于0,则游戏失败,返回1;否则,游戏还未结束,返回0。

FristController:
FristController中创建了FirstSceneActionManager这个类的对象

private FirstSceneActionManager actionManager;

FirstSceneActionManager:

    public class FirstSceneActionManager:ActionManager {
        public void moveBoat(BoatController boat) {
            MoveToAction action = MoveToAction.getAction(boat.getDestination(), boat.movingSpeed);
            this.addAction(boat.getGameobj(), action, this);
        }

        public void moveCharacter(MyCharacterController characterCtrl, Vector3 destination) {
            Vector3 currentPos = characterCtrl.getPos();
            Vector3 middlePos = currentPos;
            if (destination.y > currentPos.y) {        //from low(boat) to high(coast)
                middlePos.y = destination.y;
            } else {    //from high(coast) to low(boat)
                middlePos.x = destination.x;
            }
            ObjAction action1 = MoveToAction.getAction(middlePos, characterCtrl.movingSpeed);
            ObjAction action2 = MoveToAction.getAction(destination, characterCtrl.movingSpeed);
            ObjAction seqAction = SequenceAction.getAction(1, 0, new List<ObjAction>{action1, action2});
            this.addAction(characterCtrl.getGameobj(), seqAction, this);
        }
    }

FirstController就是通过FirstSceneActionManager来管理所有动作,可以看到它里面包括了:

Awake()方法中,获取Director实例,并将当前的场景控制器设置为自身。
loadResources()方法中,实例化水面对象,并设置其位置和旋转。
loadCharacter()方法用于加载角色。
moveBoat()方法用于移动船只。
characterIsClicked()方法用于处理角色被点击的事件。
restart()方法用于重新开始游戏。它重置船只、岸边控制器和角色的状态。

相较于之前MVC架构,使用了actionManager的moveCharacter()方法来移动角色,

动作管理类ActionManager:
动作分离是一种设计原则,它将游戏中的行为逻辑与显示逻辑分离开来,使得二者可以独立变化。在游戏开发中,动作分离可以使代码更加模块化和可复用,提高开发效率和代码可维护性。
所以在本次实现中去掉baseCode中Moveable这个类,而选用动作管理器ActionManager来实现。
具体来说,动作分离将游戏中的行为逻辑抽象为一个个独立的动作(Action),每个动作都有自己的执行逻辑和完成条件。游戏对象(如角色、道具等)通过执行不同的动作来实现不同的行为。这样,游戏中的行为逻辑就可以独立于游戏对象的实现,使得行为逻辑可以被复用和扩展。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Mygame;


namespace Com.Mygame
{
    public class ActionManager: MonoBehaviour, ActionCallback {
        private Dictionary<int, ObjAction> actions = new Dictionary<int, ObjAction>();
        private List<ObjAction> waitingToAdd = new List<ObjAction>();
        private List<int> watingToDelete = new List<int>();

        protected void Update() {
            foreach(ObjAction ac in waitingToAdd) {
                actions[ac.GetInstanceID()] = ac;
            }
            waitingToAdd.Clear();

            foreach(KeyValuePair<int, ObjAction> kv in actions) {
                ObjAction ac = kv.Value;
                if (ac.destroy) {
                    watingToDelete.Add(ac.GetInstanceID());
                } else if (ac.enable) {
                    ac.Update();
                }
            }

            foreach(int key in watingToDelete) {
                ObjAction ac = actions[key];
                actions.Remove(key);
                DestroyObject(ac);
            }
            watingToDelete.Clear();
        }

        public void addAction(GameObject gameObject, ObjAction action, ActionCallback whoToNotify) {
            action.gameObject = gameObject;
            action.transform = gameObject.transform;
            action.whoToNotify = whoToNotify;
            waitingToAdd.Add(action);
            action.Start();
        }
        public void actionDone(ObjAction source) {}
    }
}

动作基类Objection:
ActionManager与ObjAction
ActionManager是动作对象管理器的基类,实现了所有动作的基本管理。而ObjAction是所有动作的基类,ActionManager就是通过ObjAction这个接口来管理动作的。

namespace Com.Mygame
{
    public class ObjAction : ScriptableObject
    {

        public bool enable = true;
        public bool destroy = false;

        public GameObject gameObject;
        public Transform transform;
        public ActionCallback whoToNotify;

        public virtual void Start()
        {
            throw new System.NotImplementedException();
        }

        public virtual void Update()
        {
            throw new System.NotImplementedException();
        }
    }

    
}

Start():一个虚拟方法,表示动作的开始执行。在子类中可以重写该方法以实现具体的动作逻辑。
Update():一个虚拟方法,表示动作的更新。在子类中可以重写该方法以实现动作的持续更新逻辑。
代码中的ObjAction类并没有实现具体的动作逻辑,而是提供了一个基类,供其他具体的动作类继承并实现自己的动作逻辑。

五、参考资料

学习Unity(7)小游戏架构改进——实现动作管理器
Unity3D游戏编程-牧师与恶魔 动作分离版


Kim_Yang
1 声望1 粉丝