[Unity3D课堂作业] Priests and Devils 牧师与恶魔

#感觉这门课作业不提前写真搞不定啊_(:зゝ∠)_

#文末有全部代码以及操作方法


先把游戏效果po一下吧(白色胶囊体代表牧师、红色胶囊体代表魔鬼、蓝色代表船、两条白色圆柱体代表两岸):



这次作业与TA的实现方法稍有不同,多用了两个类:PersonStatus(动态加载到6个牧师和恶魔上)用来管理角色上船(即下岸)以及上岸(即下船)的行为;BoatBehaviour(动态加载到船上)用来管理船的移动行为。同时增加了一个IGameJudge接口,用于判断胜利/失败行为。其他的应该大致相同,UML图大概像下面的(第一次画UML图, 不知道有没有错……):



【作业要求】:

1、BaseCode 脚本:

        此脚本主要作用的在同一个命名空间内定义单例类、定义接口。

由于需要使用单例模式,所以先声明一个命名空间Com.MyGame。然后在里面定义单例类mainSceneController。由于仅定义了一个单例类,所以并不需要挂载到Main Camera上。


2、GenGameObjects 脚本:

此脚本主要作用是创建所有的游戏对象GameObject,同时实现一些游戏操作逻辑。

        (1) 这个脚本需要挂载到Main Camera上。

        


         (2) 在此脚本需要先创建牧师、恶魔、船、两岸这些GameObject(用几何体代替)。创建后还需要给游戏对象加上名字(有些需要 加上tag用于后面辨识),设置大小、旋转角度、颜色、位置等属性;对于牧师、恶魔、船这几种游戏对象,还要分别绑定上面提到的PersonStatus、BoatBehaviour脚本。(下面仅放其中一种游戏对象的创建代码):

Priests = new List<GameObject>();
for (int i = 0; i < 3; i++) {
    GameObject priests = GameObject.CreatePrimitive(PrimitiveType.Capsule);
    priests.name = "Priest " + (i + 1);
    priests.tag = "Priest";
    priests.GetComponent<MeshRenderer>().material.color = Color.white;
    priests.AddComponent<PersonStatus>();
    Priests.Add(priests);
}
Priests[0].transform.position = LOCATION_SET.priests_1_LOC;
Priests[1].transform.position = LOCATION_SET.priests_2_LOC;
Priests[2].transform.position = LOCATION_SET.priests_3_LOC;

值得注意的是 LOCATION_SET.priests_1_LOC 是什么??

这是我在BaseCode 脚本里面的Com.MyGame命名空间内先把所有人和物的位置(上岸、下船等一系列位置)先确定,然后在其他的脚本就可以调用静态变量获得位置的值了,像下面的:

public class LOCATION_SET {
    public static Vector3 priests_1_LOC = new Vector3(5, 3, 0);
    public static Vector3 priests_2_LOC = new Vector3(6.3f, 3, 0);
    public static Vector3 priests_3_LOC = new Vector3(7.6f, 3, 0);
    public static Vector3 devils_1_LOC = new Vector3(9.5f, 3, 0);
    public static Vector3 devils_2_LOC = new Vector3(10.8f, 3, 0);
    public static Vector3 devils_3_LOC = new Vector3(12.1f, 3, 0);
    public static Vector3 boat_left_LOC = new Vector3(-3, 0, 0);
    public static Vector3 boat_right_LOC = new Vector3(3, 0, 0);
    public static Vector3 bank_left_LOC = new Vector3(-8.5f, 1.5f, 0);
    public static Vector3 bank_right_LOC = new Vector3(8.5f, 1.5f, 0);

    public static Vector3 boatLeft_Pos_1 = new Vector3(-3.7f, 1.5f, 0);
    public static Vector3 boatLeft_Pos_2 = new Vector3(-2.3f, 1.5f, 0);
    public static Vector3 boatRight_Pos_1 = new Vector3(2.3f, 1.5f, 0);
    public static Vector3 boatRight_Pos_2 = new Vector3(3.7f, 1.5f, 0);
}


3、mainSceneController与GenGameObjects 的交互:把GenGameObjects 注入到mainSceneController单例模式作为子对象

public class mainSceneController : System.Object, IUserActions, IGameJudge {
    private static mainSceneController instance;
    private GenGameObjects myGenGameObjects;

    public static mainSceneController getInstance() {
        if (instance == null)
            instance = new mainSceneController();
        return instance;
    }

    internal void setGenGameObjects(GenGameObjects _myGenGameObjects) {
        if (myGenGameObjects == null) {
            myGenGameObjects = _myGenGameObjects;
        }
    }
}
同时在GenGameObjects 脚本Start()函数里:

mainSceneController.getInstance().setGenGameObjects(this);

4、接下来是玩家操作,少的可以分5种:船的移动、牧师上船、牧师上岸、恶魔上船、恶魔上岸;多的可以分7种,即两种人物上岸可以上左岸或右岸。我这里只让玩家做5种操作(上左/右岸会按照船的停靠位置来确定,可以自动识别)。

(1) 在BaseCode 脚本添加IUserActions接口:

public interface IUserActions {
    void boatMove();
    void priestsGetOn();
    void priestsGetOff();
    void devilsGetOn();
    void devilsGetOff();
}

(2) 然后在mainSceneController实现IUserActions接口:由于mainSceneController有GenGameObjects子对象,且所有GameObject都在GenGameObjects脚本里创建,所以我在GenGameObjects里真正实现IUserActions接口的五个方法,而在mainSceneController仅通过GenGameObjects子对象调用自身的方法即可:

public class mainSceneController : System.Object, IUserActions {
    private static mainSceneController instance;
    private GenGameObjects myGenGameObjects;

    public static mainSceneController getInstance() {
        if (instance == null)
            instance = new mainSceneController();
        return instance;
    }

    internal void setGenGameObjects(GenGameObjects _myGenGameObjects) {
        if (myGenGameObjects == null) {
            myGenGameObjects = _myGenGameObjects;
        }
    }

    /**
    * 实现IUserActions接口
    **/
    public void boatMove() {
        myGenGameObjects.boatMove();
    }

    public void devilsGetOff() {
        myGenGameObjects.devilsGetOff();
    }

    public void devilsGetOn() {
        myGenGameObjects.devilsGetOn();
    }

    public void priestsGetOff() {
        myGenGameObjects.priestsGetOff();
    }

    public void priestsGetOn() {
        myGenGameObjects.priestsGetOn();
    }
}
5个函数的具体逻辑实现在这里就不放出来了,因为挺繁琐的_(:зゝ∠)_。


5、UserInterface脚本:

此脚本的主要作用是:监听玩家的操作,并调用IUserActions接口的方法。

我是用MonoBehaviour提供的OnGUI()方法设置了5个按钮Button分别监听。代码就不在这放了,详见文末完整代码。

然后创建一个Empty对象,并挂载上去。


6、使用 C# 集合类型组织对象,我是使用List<GameObject>,感觉这个挺好用的。mainSceneController 对象与GenGameObjects 互动完成游戏逻辑上面也提到了。下面提一下新添的两个类一个新添的接口吧:

(1) PersonStatus类:

这个类动态绑定到每个牧师和恶魔上。主要作用是定义控制自身行为,即上船/上岸两个方法,并提供给GenGameObjects 在合适情况下调用。同时,PersonStatus类有 位置 和 在船上/岸上 等状态的成员变量,实现了每个牧师/恶魔自己管理自己(上船/上岸 自身的位置交换),而不需要在一个类里面统一管理,更加方便而且直观。


(2) BoatBehaviour类:

这个类动态绑定到船上。主要作用是控制船的自身移动,而不需要在其他类里面管理(由于船的移动是通过Update()方法一点点的修

改位置来变化)。此类会提供方法给GenGameObjects 在合适情况下调用,使船移动,同时检测是否靠岸。

(3) IGameJudge接口:

此接口通过mainSceneController实现。mainSceneController 内会先声明一些变量来提示岸上/船上的牧师/恶魔的数量,

IGameJudge接口同样有改变那几个变量的函数(牧师/恶魔上船/上岸的时候PersonStatus类会调用接口的方法),同时有一个检测

游戏是否胜利/失败的函数船靠岸的时候BoatBehaviour类会调用接口的方法)。

public interface IGameJudge {
    void modifyBoatPriestsNum(bool isAdd);
    void modifyBoatDevilsNum(bool isAdd);
    void modifyBankPriestsNum(bool isLeftBank, bool isAdd);
    void modifyBankDevilsNum(bool isLeftBank, bool isAdd);
    void judgeTheGame(bool isBoatLeft);
}

7、船未靠岸通过一个bool变量isMoving来控制玩家不能够操作。


8、游戏胜利、结束的提示文字需要先把GUI文字做出prefab,然后游戏结束的时候动态生成

void showGameText(string textContent) {
    GameObject Canvas = Camera.Instantiate(Resources.Load("Prefab/Canvas")) as GameObject;
    GameObject GameText = Camera.Instantiate(Resources.Load("Prefab/GameText"), Canvas.transform) as GameObject;
    GameText.transform.position = Canvas.transform.position;
    GameText.GetComponent<Text>().text = textContent;
}
项目的组织结构:


9、整个游戏没有出现 Find 游戏对象, SendMessage 这类突破程序结构的通讯耦合语句。


写这篇东西真够呛_(:зゝ∠)_

写这篇东西真够呛_(:зゝ∠)_

写这篇东西真够呛_(:зゝ∠)_

重要事情说三遍……不敢想象后面的作业……


好吧,下面就是完整的代码:

1、BaseCode.cs(不需要挂载到主摄像机):

using UnityEngine;
using System.Collections;
using System;
using UnityEngine.UI;

namespace Com.MyGame {
    public class DIRECTION {
        public static bool Left = true;
        public static bool Right = false;
    }
    public class MODIFICATION {
        public static bool Add = true;
        public static bool Sub = false;
    }
    public class LOCATION_SET {
        public static Vector3 priests_1_LOC = new Vector3(5, 3, 0);
        public static Vector3 priests_2_LOC = new Vector3(6.3f, 3, 0);
        public static Vector3 priests_3_LOC = new Vector3(7.6f, 3, 0);
        public static Vector3 devils_1_LOC = new Vector3(9.5f, 3, 0);
        public static Vector3 devils_2_LOC = new Vector3(10.8f, 3, 0);
        public static Vector3 devils_3_LOC = new Vector3(12.1f, 3, 0);
        public static Vector3 boat_left_LOC = new Vector3(-3, 0, 0);
        public static Vector3 boat_right_LOC = new Vector3(3, 0, 0);
        public static Vector3 bank_left_LOC = new Vector3(-8.5f, 1.5f, 0);
        public static Vector3 bank_right_LOC = new Vector3(8.5f, 1.5f, 0);

        public static Vector3 boatLeft_Pos_1 = new Vector3(-3.7f, 1.5f, 0);
        public static Vector3 boatLeft_Pos_2 = new Vector3(-2.3f, 1.5f, 0);
        public static Vector3 boatRight_Pos_1 = new Vector3(2.3f, 1.5f, 0);
        public static Vector3 boatRight_Pos_2 = new Vector3(3.7f, 1.5f, 0);
    }

    public interface IUserActions {
        void boatMove();
        void priestsGetOn();
        void priestsGetOff();
        void devilsGetOn();
        void devilsGetOff();
    }

    public interface IGameJudge {
        void modifyBoatPriestsNum(bool isAdd);
        void modifyBoatDevilsNum(bool isAdd);
        void modifyBankPriestsNum(bool isLeftBank, bool isAdd);
        void modifyBankDevilsNum(bool isLeftBank, bool isAdd);
        void judgeTheGame(bool isBoatLeft);
    }

    public class mainSceneController : System.Object, IUserActions, IGameJudge {
        private static mainSceneController instance;
        private GenGameObjects myGenGameObjects;

        private int BoatPriestsNum, BoatDevilsNum, BankLeftPriestsNum,
            BankRightPriestsNum, BankLeftDevilsNum, BankRightDevilsNum;  //人员数量,用于判断游戏胜负

        public static mainSceneController getInstance() {
            if (instance == null)
                instance = new mainSceneController();
            return instance;
        }

        internal void setGenGameObjects(GenGameObjects _myGenGameObjects) {
            if (myGenGameObjects == null) {
                myGenGameObjects = _myGenGameObjects;
                BoatPriestsNum = BoatDevilsNum = BankLeftPriestsNum = BankLeftDevilsNum = 0;
                BankRightPriestsNum = BankRightDevilsNum = 3;
            }
        }


        /**
        * 实现IUserActions接口
        **/
        public void boatMove() {
            myGenGameObjects.boatMove();
        }

        public void devilsGetOff() {
            myGenGameObjects.devilsGetOff();
        }

        public void devilsGetOn() {
            myGenGameObjects.devilsGetOn();
        }

        public void priestsGetOff() {
            myGenGameObjects.priestsGetOff();
        }

        public void priestsGetOn() {
            myGenGameObjects.priestsGetOn();
        }

        /**
        * 实现IGameJudge接口
        **/
        public void modifyBoatPriestsNum(bool isAdd) {
            if (isAdd)
                BoatPriestsNum++;
            else
                BoatPriestsNum--;
        }

        public void modifyBoatDevilsNum(bool isAdd) {
            if (isAdd)
                BoatDevilsNum++;
            else
                BoatDevilsNum--;
        }
        
        public void modifyBankDevilsNum(bool isLeftBank, bool isAdd) {
            if (isLeftBank) {
                if (isAdd)
                    BankLeftDevilsNum++;
                else
                    BankLeftDevilsNum--;
            }
            else {
                if (isAdd)
                    BankRightDevilsNum++;
                else
                    BankRightDevilsNum--;
            }
        }

        public void modifyBankPriestsNum(bool isLeftBank, bool isAdd) {
            if (isLeftBank) {
                if (isAdd)
                    BankLeftPriestsNum++;
                else
                    BankLeftPriestsNum--;
            }
            else {
                if (isAdd)
                    BankRightPriestsNum++;
                else
                    BankRightPriestsNum--;
            }
        }

        public void judgeTheGame(bool isBoatLeft) {
            if (isBoatLeft) {
                if ((BankLeftPriestsNum + BoatPriestsNum > 0 
                    && BankLeftDevilsNum + BoatDevilsNum > BankLeftPriestsNum + BoatPriestsNum)
                    || (BankRightDevilsNum > BankRightPriestsNum && BankRightPriestsNum > 0)) {
                    showGameText("Failed !");
                }

                if (BankLeftDevilsNum + BoatDevilsNum == 3 && BankLeftPriestsNum + BoatPriestsNum == 3) {
                    showGameText("Victory !");
                }
            }
            else {
                if ((BankRightPriestsNum + BoatPriestsNum > 0
                    && BankRightDevilsNum + BoatDevilsNum > BankRightPriestsNum + BoatPriestsNum)
                    || (BankLeftDevilsNum > BankLeftPriestsNum && BankLeftPriestsNum > 0)) {
                    showGameText("Failed !");
                }
            }
        }
        void showGameText(string textContent) {
            GameObject Canvas = Camera.Instantiate(Resources.Load("Prefab/Canvas")) as GameObject;
            GameObject GameText = Camera.Instantiate(Resources.Load("Prefab/GameText"), Canvas.transform) as GameObject;
            GameText.transform.position = Canvas.transform.position;
            GameText.GetComponent<Text>().text = textContent;
        }
    }
}

2、GenGameObjects.cs(挂载到主摄像机)

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

public class GenGameObjects : MonoBehaviour {
    public List<GameObject> Priests, Devils;
    public GameObject boat, bankLeft, bankRight;

    private BoatBehaviour myBoatBehaviour;

    void Start () {
        Priests = new List<GameObject>();
        for (int i = 0; i < 3; i++) {
            GameObject priests = GameObject.CreatePrimitive(PrimitiveType.Capsule);
            priests.name = "Priest " + (i + 1);
            priests.tag = "Priest";
            priests.GetComponent<MeshRenderer>().material.color = Color.white;
            priests.AddComponent<PersonStatus>();
            Priests.Add(priests);
        }
        Priests[0].transform.position = LOCATION_SET.priests_1_LOC;
        Priests[1].transform.position = LOCATION_SET.priests_2_LOC;
        Priests[2].transform.position = LOCATION_SET.priests_3_LOC;

        Devils = new List<GameObject>();
        for (int i = 0; i < 3; i++) {
            GameObject devils = GameObject.CreatePrimitive(PrimitiveType.Capsule);
            devils.name = "Devil " + (i + 1);
            devils.tag = "Devil";
            devils.GetComponent<MeshRenderer>().material.color = Color.red;
            devils.AddComponent<PersonStatus>();
            Devils.Add(devils);
        }
        Devils[0].transform.position = LOCATION_SET.devils_1_LOC;
        Devils[1].transform.position = LOCATION_SET.devils_2_LOC;
        Devils[2].transform.position = LOCATION_SET.devils_3_LOC;

        boat = GameObject.CreatePrimitive(PrimitiveType.Cube);
        boat.name = "Boat";
        boat.AddComponent<BoatBehaviour>();
        myBoatBehaviour = boat.GetComponent<BoatBehaviour>();
        boat.GetComponent<MeshRenderer>().material.color = Color.blue;
        boat.transform.localScale = new Vector3(3, 1, 1);
        boat.transform.position = LOCATION_SET.boat_right_LOC;

        bankLeft = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
        bankLeft.name = "BankLeft";
        bankLeft.transform.Rotate(new Vector3(0, 0, 90));
        bankLeft.transform.localScale = new Vector3(1, 4, 1);
        bankLeft.transform.position = LOCATION_SET.bank_left_LOC;

        bankRight = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
        bankRight.name = "BankRight";
        bankRight.transform.Rotate(new Vector3(0, 0, 90));
        bankRight.transform.localScale = new Vector3(1, 4, 1);
        bankRight.transform.position = LOCATION_SET.bank_right_LOC;

        mainSceneController.getInstance().setGenGameObjects(this);
    }
	
	void Update () {
	
	}

    public void boatMove() {
        myBoatBehaviour.setBoatMove();
    }

    //牧师上船
    public void priestsGetOn() {
        if (myBoatBehaviour.isMoving)
            return;

        if (!myBoatBehaviour.isBoatAtLeftSide()) {  //船在右侧
            for (int i = 0; i < Priests.Count; i++) {
                if (Priests[i].GetComponent<PersonStatus>().onBankRight) {
                    //右侧岸上有牧师
                    detectEmptySeat(true, i, DIRECTION.Right);
                    break;
                }
            }
        }
        else {  //船在左侧
            for (int i = 0; i < Priests.Count; i++) {
                if (Priests[i].GetComponent<PersonStatus>().onBankLeft) {
                    //左侧岸上有牧师
                    detectEmptySeat(true, i, DIRECTION.Left);
                    break;
                }
            }
        }
    }
    //恶魔上船
    public void devilsGetOn() {
        if (myBoatBehaviour.isMoving)
            return;

        if (!myBoatBehaviour.isBoatAtLeftSide()) {  //船在右侧
            for (int i = 0; i < Devils.Count; i++) {
                if (Devils[i].GetComponent<PersonStatus>().onBankRight) {
                    //右侧岸上有恶魔
                    detectEmptySeat(false, i, DIRECTION.Right);
                    break;
                }
            }
        }
        else {  //船在左侧
            for (int i = 0; i < Devils.Count; i++) {
                if (Devils[i].GetComponent<PersonStatus>().onBankLeft) {
                    //左侧岸上有恶魔
                    detectEmptySeat(false, i, DIRECTION.Left);
                    break;
                }
            }
        }
    }
    //当岸上有牧师/恶魔的时候,检测船上是否有空位
    void detectEmptySeat(bool isPriests, int index, bool boatDir) {
        if (myBoatBehaviour.isLeftSeatEmpty()) {        //船上左位置没人
            seatThePersonAndModifyBoat(isPriests, index, boatDir, DIRECTION.Left);
        }
        else if (myBoatBehaviour.isRightSeatEmpty()) {  //船上左位置有人,右位置没人
            seatThePersonAndModifyBoat(isPriests, index, boatDir, DIRECTION.Right);
        }
    }
    //牧师/恶魔上船,并调整船的属性
    void seatThePersonAndModifyBoat(bool isPriests, int index, bool boatDir, bool seatDir) {
        if (isPriests) {
            Priests[index].GetComponent<PersonStatus>().personSeatOnBoat(boatDir, seatDir);
            Priests[index].transform.parent = boat.transform;
        }
        else {
            Devils[index].GetComponent<PersonStatus>().personSeatOnBoat(boatDir, seatDir);
            Devils[index].transform.parent = boat.transform;
        }
        myBoatBehaviour.seatOnPos(seatDir);
    }


    //牧师下船
    public void priestsGetOff() {
        if (myBoatBehaviour.isMoving)
            return;

        if (!myBoatBehaviour.isBoatAtLeftSide()) {  //船在右侧
            for (int i = Priests.Count - 1; i >= 0; i--) {
                if (detectIfPeopleOnBoat(true, i, DIRECTION.Right))
                    break;
            }
        }
        else {  //船在左侧
            for (int i = Priests.Count - 1; i >= 0; i--) {
                if (detectIfPeopleOnBoat(true, i, DIRECTION.Left))
                    break;
            }
        }
    }
    //恶魔下船
    public void devilsGetOff() {
        if (myBoatBehaviour.isMoving)
            return;

        if (!myBoatBehaviour.isBoatAtLeftSide()) {  //船在右侧
            for (int i = Devils.Count - 1; i >= 0; i--) {
                if (detectIfPeopleOnBoat(false, i, DIRECTION.Right))
                    break;
            }
        }
        else {  //船在左侧
            for (int i = Devils.Count - 1; i >= 0; i--) {
                if (detectIfPeopleOnBoat(false, i, DIRECTION.Left))
                    break;
            }
        }
    }
    //检测是否有牧师/恶魔在船上
    bool detectIfPeopleOnBoat(bool isPriests, int i, bool boatDir) {
        if (isPriests) {
            if (Priests[i].GetComponent<PersonStatus>().onBoatLeft
            || Priests[i].GetComponent<PersonStatus>().onBoatRight) {
                //在船上
                myBoatBehaviour.jumpOutOfPos(Priests[i].GetComponent<PersonStatus>().onBoatLeft);
                Priests[i].GetComponent<PersonStatus>().landTheBank(boatDir);
                Priests[i].transform.parent = boat.transform.parent;

                return true;
            }
            return false;
        }
        else {
            if (Devils[i].GetComponent<PersonStatus>().onBoatLeft
            || Devils[i].GetComponent<PersonStatus>().onBoatRight) {
                //在船上
                myBoatBehaviour.jumpOutOfPos(Devils[i].GetComponent<PersonStatus>().onBoatLeft);
                Devils[i].GetComponent<PersonStatus>().landTheBank(boatDir);
                Devils[i].transform.parent = boat.transform.parent;

                return true;
            }
            return false;
        }
    }

}

3、PersonStatus.cs(会动态挂载)

using UnityEngine;
using System.Collections;
using Com.MyGame;

public class PersonStatus : MonoBehaviour {
    private Vector3 originalPos;
    public bool onBoatLeft, onBoatRight;
    public bool onBankLeft, onBankRight;

    private IGameJudge gameJudge;

    void Start () {
        originalPos = this.transform.position;
        onBoatLeft = false;
        onBoatRight = false;
        onBankLeft = false;
        onBankRight = true;

        gameJudge = mainSceneController.getInstance() as IGameJudge;
    }
	
	void Update () {
	
	}

    //人上船(下岸)
    public void personSeatOnBoat(bool boatAtLeft, bool seatAtLeft) {
        if (seatAtLeft) {
            if (boatAtLeft)
                this.transform.position = LOCATION_SET.boatLeft_Pos_1;
            else
                this.transform.position = LOCATION_SET.boatRight_Pos_1;
            onBoatLeft = true;
        }
        else {
            if (boatAtLeft)
                this.transform.position = LOCATION_SET.boatLeft_Pos_2;
            else
                this.transform.position = LOCATION_SET.boatRight_Pos_2;
            onBoatRight = true;
        }
        onBankLeft = false;
        onBankRight = false;

        if (this.tag.Equals("Priest")) {
            gameJudge.modifyBoatPriestsNum(MODIFICATION.Add);
            gameJudge.modifyBankPriestsNum(boatAtLeft, MODIFICATION.Sub);
        }
        else {
            gameJudge.modifyBoatDevilsNum(MODIFICATION.Add);
            gameJudge.modifyBankDevilsNum(boatAtLeft, MODIFICATION.Sub);
        }
    }

    //人上岸(下船)
    public void landTheBank(bool boatAtLeft) {
        if (boatAtLeft) {
            this.transform.position = new Vector3(-originalPos.x, originalPos.y, originalPos.z);
            onBankLeft = true;
        }
        else {
            this.transform.position = originalPos;
            onBankRight = true;
        }
        onBoatLeft = false;
        onBoatRight = false;

        if (this.tag.Equals("Priest")) {
            gameJudge.modifyBoatPriestsNum(MODIFICATION.Sub);
            gameJudge.modifyBankPriestsNum(boatAtLeft, MODIFICATION.Add);
        }
        else {
            gameJudge.modifyBoatDevilsNum(MODIFICATION.Sub);
            gameJudge.modifyBankDevilsNum(boatAtLeft, MODIFICATION.Add);
        }
    }
}

4、BoatBehaviour.cs (会动态挂载)

using UnityEngine;
using System.Collections;
using Com.MyGame;

public class BoatBehaviour : MonoBehaviour {
    private Vector3 moveDir = new Vector3(-0.1f, 0, 0);
    public bool isMoving;
    public bool atLeftSide;
    public bool leftPosEmpty, rightPosEmpty;

    private IGameJudge gameJudge;

    void Start () {
        isMoving = false;
        atLeftSide = DIRECTION.Right;
        leftPosEmpty = true;
        rightPosEmpty = true;

        gameJudge = mainSceneController.getInstance() as IGameJudge;
    }
	
	void Update () {
        moveTheBoat();
    }

    private void moveTheBoat() {
        if (isMoving) {
            if (!isMovingToEdge()) {
                this.transform.Translate(moveDir);
            }
        }
    }
    //检测靠岸
    private bool isMovingToEdge() {
        if (moveDir.x < 0 && this.transform.position.x <= LOCATION_SET.boat_left_LOC.x) {  //向左,已到
            gameJudge.judgeTheGame(DIRECTION.Left);
            isMoving = false;
            atLeftSide = DIRECTION.Left;
            moveDir = new Vector3(-moveDir.x, 0, 0);
            return true;
        }
        else if (moveDir.x > 0 && this.transform.position.x >= LOCATION_SET.boat_right_LOC.x) {  //向右,已到
            gameJudge.judgeTheGame(DIRECTION.Right);
            isMoving = false;
            atLeftSide = DIRECTION.Right;
            moveDir = new Vector3(-moveDir.x, 0, 0);
            return true;
        }
        else {  //还没靠岸
            return false;
        }
    }

    /**
    * 提供给GenGameObjects脚本调用
    * 点击Go按钮触发船移动:需要船静止 + 船上有人(至少一个位置不空)
    **/
    public void setBoatMove() {
        if (!isMoving && (!leftPosEmpty || !rightPosEmpty)) {
            isMoving = true;
        }
    }
    public bool isBoatAtLeftSide() {
        return atLeftSide;
    }


    public bool isLeftSeatEmpty() {
        return leftPosEmpty;
    }
    public bool isRightSeatEmpty() {
        return rightPosEmpty;
    }


    public void seatOnPos(bool isLeft) {
        if (isLeft)
            leftPosEmpty = false;
        else
            rightPosEmpty = false;
    }
    public void jumpOutOfPos(bool isLeft) {
        if (isLeft)
            leftPosEmpty = true;
        else
            rightPosEmpty = true;
    }
}

5、UserInterface.cs (挂载到Empty对象上)

using UnityEngine;
using System.Collections;
using Com.MyGame;

public class UserInterface : MonoBehaviour {
    IUserActions myActions;
    float btnWidth = (float)Screen.width / 6.0f;
    float btnHeight = (float)Screen.height / 6.0f;

    void Start () {
        myActions = mainSceneController.getInstance() as IUserActions;
    }
	
	void Update () {
	
	}

    void OnGUI() {
        if (GUI.Button(new Rect(5, 250, btnWidth, btnHeight), "Priests GetOn")) {
            myActions.priestsGetOn();
        }
        if (GUI.Button(new Rect(155, 250, btnWidth, btnHeight), "Priests GetOff")) {
            myActions.priestsGetOff();
        }
        if (GUI.Button(new Rect(305, 250, btnWidth, btnHeight), "Go!")) {
            myActions.boatMove();
        }
        if (GUI.Button(new Rect(455, 250, btnWidth, btnHeight), "Devils GetOn")) {
            myActions.devilsGetOn();
        }
        if (GUI.Button(new Rect(605, 250, btnWidth, btnHeight), "Devils GetOff")) {
            myActions.devilsGetOff();
        }

    }
}

操作:

1、先弄好上面5份代码

2、在下面的点击Create -> Create Empty


3、把GenGameObjects.cs挂载到主摄像机,UserInterface.cs 挂载到Empty对象上。挂载方法:点击Add Component,输入脚本名字,点击脚本,变成右边的样子即可

    

4、按下图构造好项目结构(所有脚本均放在Scripts文件夹里)。


5、蓝色那些是Prefab,构造方法:学第2点,Create -> UI -> Text。然后把Canvas拖到下面的Prefab文件夹。

GameText要设置一下,再拖到Prefab文件夹



这样应该是完成了。如果出问题再按照提示改一下呗~

啊好累……_(:зゝ∠)_







  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C++实现,利用了深度优先搜索和回溯法: ```cpp #include <iostream> #include <vector> using namespace std; const int MAXN = 10; int n, c; // 牧师人数和小船载客人数 int boat_pos; // 小船位置,1表示在起始岸,0表示在目的岸 int priests[MAXN], devils[MAXN]; // 牧师和野人的状态 int priests_on_boat, devils_on_boat; // 小船上的牧师和野人数量 vector<pair<int, int>> path; // 记录路径 bool is_valid() { // 判断当前状态是否合法 if (priests[0] < devils[0] || priests[1] < devils[1]) return false; if (priests_on_boat < devils_on_boat && priests_on_boat > 0) return false; if (priests_on_boat + devils_on_boat > c) return false; return true; } bool dfs() { if (priests[0] == 0 && devils[0] == 0) return true; // 所有人都已到达目的岸 if (!is_valid()) return false; // 当前状态不合法 // 尝试从当前状态转移到下一个状态 for (int i = 0; i <= priests_on_boat; i++) { // 枚举小船上的牧师数量 for (int j = 0; j <= devils_on_boat; j++) { // 枚举小船上的野人数量 if (i + j == 0) continue; // 小船上至少有一个人 if (i + j > c) continue; // 小船上最多只能有c个人 if (i > 0 && i < j) continue; // 牧师人数不能少于野人人数 // 尝试把i个牧师和j个野人从当前岸移动到另一个岸 priests[boat_pos] -= i; devils[boat_pos] -= j; priests[1 - boat_pos] += i; devils[1 - boat_pos] += j; boat_pos = 1 - boat_pos; priests_on_boat = i; devils_on_boat = j; path.push_back({priests[0] * 100 + devils[0], boat_pos}); // 记录路径 if (dfs()) return true; // 搜索下一个状态 else { // 回溯 boat_pos = 1 - boat_pos; priests[1 - boat_pos] -= i; devils[1 - boat_pos] -= j; priests[boat_pos] += i; devils[boat_pos] += j; priests_on_boat = 0; devils_on_boat = 0; path.pop_back(); } } } return false; // 没有找到下一个合法状态 } int main() { cin >> n >> c; priests[0] = priests[1] = n; devils[0] = devils[1] = n; boat_pos = 1; // 小船初始位置为起始岸 priests_on_boat = 0; devils_on_boat = 0; if (dfs()) { // 搜索成功 for (int i = 0; i < path.size(); i++) { int p = path[i].first / 100, d = path[i].first % 100; cout << p << d << path[i].second; if (i < path.size() - 1) cout << "<-<-"; } } else { // 搜索失败 cout << "渡河失败"; } return 0; } ``` 输入格式如下: ``` 2 2 ``` 输出结果如下: ``` 000<-021<-211<-110<-221 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值