一、背景描述
牧师与魔鬼是一款益智游戏,您将帮助牧师与魔鬼在规定时间内过河。河边有三个牧师和三个魔鬼。他们都想去这条河的对岸,但只有一艘船,这艘船每次只能载两个人。而且必须有一个人把船从一边开到另一边。在flash游戏中,您可以单击它们移动它们,然后单击go按钮将船移动到另一个方向。如果神父的人数超过了河两边的魔鬼,他们就会被杀死,游戏就结束了。你可以用很多方法来尝试。让所有牧师都活着!祝你好运!

牧师与魔鬼.jpg
(图片来源:百度百科)

二、MVC设计模式
MVC设计模式是一种软件架构模式,它将软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。模型负责封装与业务逻辑相关的数据和方法,视图负责显示模型的数据,控制器负责处理用户的请求和更新模型和视图。MVC设计模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。MVC设计模式也有利于提高程序的可测试性、可维护性和可扩展性。

3fb15665714a8f434c0cdd8f5334fea.png
三、项目介绍

1、对象

对象数量
牧师3
魔鬼3
1
陆地2
河流1

2、动作

动作条件效果
玩家点击岸上角色船上有空位角色上船
玩家点击船上角色 角色上岸
玩家点击船船上有至少一个角色开船
玩家点击restart 重新开始游戏

3、代码

4、项目展示

5、实现过程

(1)Director
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;
}

}

这段代码是用C#语言实现的单例模式(Singleton Pattern)的一个例子。单例模式是一种创建型设计模式,它保证一个类只有一个实例,并提供一个全局访问点。

这段代码定义了一个名为Director的类,它有以下特点:

  • 它有一个私有的静态字段_instance,用来存储唯一的实例。
  • 它有一个私有的无参构造函数,防止其他类通过new关键字创建它的实例。
  • 它有一个公共的静态方法getInstance,用来获取或创建唯一的实例。如果_instance为空,就创建一个新的Director对象并赋值给它;如果不为空,就直接返回它。
  • 它有一个公共的属性currentSceneController,用来设置或获取当前的场景控制器。

(2)Controller:代码
这段代码定义了一个名为FirstController的类,它继承了MonoBehaviour类,并实现了SceneController和UserAction两个接口。它有以下特点:

public CoastController fromCoast;
    public CoastController toCoast;
    public BoatController boat;
    private MyCharacterController[] characters;

它有一个常量water_pos,用来表示水面的位置。

它有一个UserGUI类型的字段userGUI,用来显示用户界面。

它有两个CoastController类型的字段fromCoast和toCoast,分别表示起始岸和目标岸。

它有一个BoatController类型的字段boat,表示船。

它有一个MyCharacterController类型的数组characters,用来存储六个角色对象(三个牧师和三个魔鬼)。

void Awake() {
        Director director = Director.getInstance ();
        director.currentSceneController = this;
        userGUI = gameObject.AddComponent <UserGUI>() as UserGUI;
        characters = new MyCharacterController[6];
        loadResources ();
    }

重写了Awake方法,在该方法中获取Director单例对象,并将自己设置为当前的场景控制器。然后添加UserGUI组件,并初始化characters数组。最后调用loadResources方法加载资源。

public void loadResources() {
        GameObject water = Instantiate (Resources.Load ("Perfabs/Water", typeof(GameObject)), water_pos, Quaternion.identity, null) as GameObject;
        water.name = "water";

        fromCoast = new CoastController ("from");
        toCoast = new CoastController ("to");
        boat = new BoatController ();

        loadCharacter ();
    }

实现了loadResources方法,在该方法中实例化水面对象,并给它命名为"water"。然后创建fromCoast、toCoast和boat对象,并调用loadCharacter方法加载角色对象。

private void loadCharacter() {
        for (int i = 0; i < 3; i++) {
            MyCharacterController cha = new MyCharacterController ("priest");
            cha.setName("priest" + i);
            cha.setPosition (fromCoast.getEmptyPosition ());
            cha.getOnCoast (fromCoast);
            fromCoast.getOnCoast (cha);

            characters [i] = cha;
        }

        for (int i = 0; i < 3; i++) {
            MyCharacterController cha = new MyCharacterController ("devil");
            cha.setName("devil" + i);
            cha.setPosition (fromCoast.getEmptyPosition ());
            cha.getOnCoast (fromCoast);
            fromCoast.getOnCoast (cha);

            characters [i+3] = cha;
        }
    }

实现了loadCharacter方法,在该方法中循环创建三个牧师和三个魔鬼对象,并给它们命名为"priest0"到"priest2"和"devil0"到"devil2"。然后将它们放置在fromCoast的空位上,并让它们上岸。同时将它们添加到fromCoast和characters数组中。

public void moveBoat() {
        if (userGUI.status != 0 ) return;
        if (boat.isEmpty ())
            return;
        boat.Move ();
        userGUI.status = check_game_over ();
    }

实现了moveBoat方法,在该方法中判断游戏状态是否为0(未结束),如果不是则返回。然后判断船是否为空,如果是则返回。否则调用boat的Move方法移动船,并更新游戏状态。

public void characterIsClicked(MyCharacterController characterCtrl) {
        if (userGUI.status != 0 ) return;
        if (characterCtrl.isOnBoat ()) {
            CoastController whichCoast;
            if (boat.get_to_or_from () == -1) { // to->-1; from->1
                whichCoast = toCoast;
            } else {
                whichCoast = fromCoast;
            }

            boat.GetOffBoat (characterCtrl.getName());
            characterCtrl.moveToPosition (whichCoast.getEmptyPosition ());
            characterCtrl.getOnCoast (whichCoast);
            whichCoast.getOnCoast (characterCtrl);

        } else {                                    // character on coast
            CoastController whichCoast = characterCtrl.getCoastController ();

            if (boat.getEmptyIndex () == -1) {        // boat is full
                return;
            }

            if (whichCoast.get_to_or_from () != boat.get_to_or_from ())    // boat is not on the side of character
                return;

            whichCoast.getOffCoast(characterCtrl.getName());
            characterCtrl.moveToPosition (boat.getEmptyPosition());
            characterCtrl.getOnBoat (boat);
            boat.GetOnBoat (characterCtrl);
        }
        userGUI.status = check_game_over ();
    }

实现了characterIsClicked方法,在该方法中判断游戏状态是否为0(未结束),如果不是则返回。然后判断角色对象是否在船上,如果是则执行下列操作:

声明一个CoastController类型的变量whichCoast,用来表示目标岸。
判断船的位置是在起始岸还是目标岸,如果是目标岸,则将whichCoast赋值为toCoast;如果是起始岸,则将whichCoast赋值为fromCoast。
调用boat的GetOffBoat方法让角色对象下船,并传入角色对象的名字作为参数。
调用角色对象的moveToPosition方法让角色对象移动到whichCoast的空位上,并传入空位坐标作为参数。
调用角色对象的getOnCoast方法让角色对象上岸,并传入whichCoast作为参数。
调用whichCoast的getOnCoast方法让whichCoast记录角色对象,并传入角色对象作为参数。
如果角色对象不在船上,则执行下列操作:

声明一个CoastController类型的变量whichCoast,用来表示当前岸,并调用角色对象的getCoastController方法获取当前岸。
判断船是否已满,如果是则返回。
判断船的位置是否与当前岸一致,如果不是则返回。
调用whichCoast的getOffCoast方法让角色对象下岸,并传入角色对象的名字作为参数。
调用角色对象的moveToPosition方法让角色对象移动到船的空位上,并传入空位坐标作为参数。
调用角色对象的getOnBoat方法让角色对象上船,并传入boat作为参数。
调用boat的GetOnBoat方法让船记录角色对象,并传入角色对象作为参数。
最后更新游戏状态。

int check_game_over() {    // 0->not finish, 1->lose, 2->win
        int from_priest = 0;
        int from_devil = 0;
        int to_priest = 0;
        int to_devil = 0;

        int[] fromCount = fromCoast.getCharacterNum ();
        from_priest += fromCount[0];
        from_devil += fromCount[1];

        int[] toCount = toCoast.getCharacterNum ();
        to_priest += toCount[0];
        to_devil += toCount[1];

        if (to_priest + to_devil == 6)        // win
            return 2;

        int[] boatCount = boat.getCharacterNum ();
        if (boat.get_to_or_from () == -1) {    // boat at toCoast
            to_priest += boatCount[0];
            to_devil += boatCount[1];
        } else {    // boat at fromCoast
            from_priest += boatCount[0];
            from_devil += boatCount[1];
        }
        if (from_priest < from_devil && from_priest > 0) {        // lose
            return 1;
        }
        if (to_priest < to_devil && to_priest > 0) {
            return 1;
        }
        return 0;            // not finish
    }

实现了check_game_over方法,在该方法中判断游戏是否结束,如果结束则返回相应的状态码,如果未结束则返回0。判断游戏是否结束的逻辑如下:

声明四个整型变量from_priest、from_devil、to_priest和to_devil,分别表示起始岸和目标岸的牧师和魔鬼数量,并初始化为0。
调用fromCoast和toCoast的getCharacterNum方法获取各自的牧师和魔鬼数量,并分别累加到相应的变量中。
如果目标岸的牧师和魔鬼数量之和等于6,说明所有角色都过河了,游戏胜利,返回2。
调用boat的getCharacterNum方法获取船上的牧师和魔鬼数量,并根据船的位置累加到相应的变量中。
如果起始岸或目标岸的魔鬼数量多于牧师数量,且牧师数量大于0,说明有牧师被吃掉了,游戏失败,返回1。
否则游戏未结束,返回0。

四、参考资料:
牧师与魔鬼
Unity3D游戏编程-牧师与恶魔
Unity使用MVC架构制作牧师与魔鬼小游戏


Kim_Yang
1 声望1 粉丝