牧师与魔鬼
一、动作分离和MVC的区别
动作分离和MVC是两种常用的软件架构设计模式,它们的区别在于实现方式和重点。
动作分离(AA)是一种轻量级架构,它基于观察者模式实现。应用程序由多个独立的模块组成,这些模块被设计为只负责将信息从一个模块传递到另一个,模块之间没有直接的耦合关系。当一个事件发生时,事件的产生者会通知所有观察者,观察者可以根据事件的类型对事件进行处理。动作分离的重点在于分离视图和模型,以及事件的处理。
MVC模式(Model-View-Controller)是一种更为复杂的架构,它将应用程序的三个基本部分进行分离:数据模型、用户界面和控制器。MVC模式的核心是控制器,它接受用户的交互请求,并负责调用合适的模型来处理请求,最后更新用户界面。MVC模式的重点在于分离模型、视图和控制器,以及实现数据的变更通知和视图的更新。
二、动作管理器的设计
要求:
设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束。
三、视频演示
实现效果与上一次实验效果一致,具体可看视频
四、代码解释
本次实验比上次多了裁判类
裁判类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类并没有实现具体的动作逻辑,而是提供了一个基类,供其他具体的动作类继承并实现自己的动作逻辑。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。