[3D游戏编程]Priests And Devils——动作分离版

前情提要

上次已经实现了Priests And Devils小游戏,链接如下(游戏效果和上一次一样,就不再制作视频了):

[3D游戏编程]Priests And Devils-CSDN博客

本次任务

在上一次的代码中,可以看到FirstController里完成了几乎所有操作,包括人物状态的记录,人物的上下船,游戏结束的判断等等,使得FirstController非常繁杂和臃肿。

本次任务就是要在上次代码的基础上,将动作分离给更多的角色实现。

实现效果

将之前写在FirstController中的PriestsStatus,DevilsStatus,BoatBehaviour独立出来,并提供必要的Get和Set函数作为接口获取和修改类里面的值。

增加了一个IGameJudge类,负责实现各种判断,比如哪个人物可以上下船,游戏结束等等。

游戏框架设计

具体代码

主要是FirstController和IGameJudge有比较大的变化,所以只展示这两个类的代码。由于FirstController和IGameJudge紧密关联,所以在解释其中的函数时会一起讲。

FirstController.priestsGetOn与FirstController.devilsGetOn

两个函数实现逻辑相似,只展示priestsGetOn

    public void priestsGetOn()
    {
        // 如果船正在动,那么不能响应用户事件
        if (judge.BoatIsMoving())
            return;
        List<int> temp = judge.PriestGotoBoat();
        // 如果temp为空,说明没找到该上船的priest
        if(temp.Count == 0) 
            return;
    }

其中调用了IGameJudge中的BoatIsMoving函数,用于判断船是否在动

    // 判断船是否在动
    public bool BoatIsMoving()
    {
        return boatBehaviour.GetisMoving();
    }

还调用了 IGameJudge中的PriestGotoBoat函数,该函数实现了找岸上是否有priest可以上船,同样的,这里只展示船在左岸,左岸上有priest并且船左边有空位的判断逻辑。

    // 返回哪个priest应该上船
    public List<int> PriestGotoBoat()
    {
        List<int> temp = new List<int>(); //第一个参数是哪个priest,第二个是船位置,第三个是岸位置
        // 船在左边
        if (boatBehaviour.GetatLeftSide())
        {
            for (int i = 0; i < 3; i++)
            {
                // 左侧岸上有牧师
                if (p_status[i].GetonBankLeft())
                {
                    // 上船位置
                    if (boatBehaviour.GetleftPosEmpty())
                    {
                        temp.Add(i);
                        temp.Add(0);
                        temp.Add(1);
                        return temp;
                    }
                    if (boatBehaviour.GetrightPosEmpty())
                    {}
                }
            }
        }
        else
        {}
        return temp;
    }

可以看到,如果没有找到priest,返回的temp将为空,这也就正好和if(temp.Count == 0)相对应。

接下来继续看priestsGetOn(只展示船在左岸,priest上船左边):

    public void priestsGetOn()
    {    
        // 接上文
        int i = temp[0];
        p_status[i].SetonBankLeft(false);
        p_status[i].SetonBankRight(false);
        judge.ModifyPersonCountOnBank(false, true, temp[2]);
        judge.ModifyPersonCountOnBoat(true, true);
        // 上船的左边
        if (temp[1] == 0)
        {
            p_status[i].SetonBoatLeft(true);
            myBoatBehaviour.SetleftPosEmpty(false);
            // 船在左岸
            if (myBoatBehaviour.GetatLeftSide())
                Priests[i].transform.position = new Vector3(-3.3f, 1.5f, 0);
            else
                Priests[i].transform.position = new Vector3(1, 1.5f, 0);
        }
        else
        {}
    }

可以看到,这里调用了judge的两个函数ModifyPersonCountOnBank和ModifyPersonCountOnBoat

ModifyPersonCountOnBank用于修改当前岸上人数还有多少个(只展示左岸priest加人):

    // 修改岸上priest和devil的值
    // 第一个参数表示加减,第二个参数表示身份,第三个参数表示哪个岸
    public void ModifyPersonCountOnBank(bool plus, bool identify, int bank)
    {
        // 区分加减
        if (plus)
        {
            // 区分priest和devil
            if (identify)
            {   
                // 区分左右岸
                if (bank == 1)
                    leftBankPriests++;
                else
                    rightBankPriests++;
            }
            else
            {}
        }
        else
        {}
    }

ModifyPersonCountOnBoat用于修改当前船上还有多少人(只展示priest加人):

    // 修改船上priest和devil的值
    // 第一个参数表示加减,第二个参数表示身份
    public void ModifyPersonCountOnBoat(bool plus, bool identify)
    {
        // 区分加减
        if(plus) 
        {
            // 区分priest和devil
            if(identify)
                boatPriest++;
            else
                boatDevil++;
        }
        else 
        {}
    }

FirstController.priestsGetOff与FirstController.devilsGetOff

两个函数实现逻辑相似,只展示priestsGetOff(且只展示船在左岸的判断逻辑)

priestsGetOff和priestsGetOn判断逻辑其实几乎一样,主要不同点只是在于调用函数时输入的参数要变。

public void priestsGetOff()
    {
        if (judge.BoatIsMoving())
            return;
        List<int> temp = judge.PriestGoOffBoat();
        // 如果temp为空,说明没找到该上船的priest
        if (temp.Count == 0)
            return;
        int i = temp[0];
        judge.ModifyPersonCountOnBank(true, true, temp[2]);
        judge.ModifyPersonCountOnBoat(false, true);
        p_status[i].SetonBoatLeft(false);
        p_status[i].SetonBoatRight(false);
        // 船在左岸
        if (temp[2] == 1)
        {
            p_status[i].SetonBankLeft(true);
            Priests[i].transform.position = new Vector3((-8.6f + i * 1.3f), 3, 0);
            if (temp[1] == 0)
                myBoatBehaviour.SetleftPosEmpty(true);
            else
                myBoatBehaviour.SetrightPosEmpty(true);
        }
        else
        {}
    }

FirstController.boatMove和FirstController.onBoatMoving

这两个函数和上一次任务实现逻辑基本相同,只是将确定船上有什么人物的逻辑移到IGameJudge中实现,在IGameJudge中,PersonOnBoat函数实现了找人逻辑,并返回船上人物的下标。

    // 0-2代表priest,3-5代表devil
    // 找出船上有谁
    public List<int> PersonOnBoat()
    {
        List<int> ans = new();
        int i1 = -1;
        int i2 = -1;
        for (int i = 0; i < 3; i++)
        {
            if (p_status[i].GetonBoatLeft() || p_status[i].GetonBoatRight())
            {
                i1 = i;
                break;
            }
            if (d_status[i].GetonBoatLeft() || d_status[i].GetonBoatRight())
            {
                i1 = i + 3;
                break;
            }
        }
        for (int i = 0; i < 3; i++)
        {
            //第一个选了priest
            if (i == i1)
            {
                if (d_status[i].GetonBoatLeft() || d_status[i].GetonBoatRight())
                {
                    i2 = i + 3;
                    break;
                }
            }
            //第一个选了devil
            else if (i == i1 - 3)
            {
                if (p_status[i].GetonBoatLeft() || p_status[i].GetonBoatRight())
                {
                    i2 = i;
                    break;
                }
            }
            else
            {
                if (p_status[i].GetonBoatLeft() || p_status[i].GetonBoatRight())
                {
                    i2 = i;
                    break;
                }
                if (d_status[i].GetonBoatLeft() || d_status[i].GetonBoatRight())
                {
                    i2 = i + 3;
                    break;
                }
            }
        }
        ans.Add(i1);
        ans.Add(i2);
        return ans;
    }

IGameJudge.GameOver

此外,原来在FirstController中实现的GameOver函数,现在移到IGameJudge中实现

    // 判断游戏结束
    public int GameOver()
    {
        // 船靠岸分情况讨论
        if (boatBehaviour.GetatLeftSide())
        {
            if ((leftBankPriests + boatPriest > 0
                    && leftBankDevils + boatDevil > leftBankPriests + boatPriest)
                    || (rightBankDevils > rightBankPriests && rightBankPriests > 0))
            {
                return 1;
            }
        }
        else
        {
            if ((rightBankPriests + boatPriest > 0
                && rightBankDevils + boatDevil > rightBankPriests + boatPriest)
                || (leftBankDevils > leftBankPriests && leftBankPriests > 0))
            {
                return 1;
            }
            if (rightBankDevils + boatDevil == 3 && rightBankPriests + boatPriest == 3)
            {
                return 2;
            }
        }
        return 0;
    }

总结

这次的代码在实现逻辑上,是和上次的代码一样的,不同点在于,通过添加更多的“角色”,分担了FirstController的任务。首先,原本在FirstController中定义的有关状态的类,都独立出来,并通过提供接口实现获取和修改值的操作;其次,原本在FirstController中有关判断的逻辑,都在IGameJudge中实现。这种做法使得FirstController变得简洁,符合面向对象基于职责的原则。

代码大放送

使用方法:将FirstController和UserInterface挂载到MainCamera就可以使用了

SSDirector

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SSDirector : System.Object
{
    // singlton instance
    private static SSDirector _instance;

    public ISceneController currentSceneController { get; set; }


    // get instance anytime anywhare!
    public static SSDirector getInstance()
    {
        if (_instance == null)
        {
            _instance = new SSDirector();
        }
        return _instance;
    }

    public int getFPS()
    {
        return Application.targetFrameRate;
    }

    public void setFPS(int fps)
    {
        Application.targetFrameRate = fps;
    }

    public void NextScene()
    {
        Debug.Log("Waiting next Scene now...");
#if UNITY_EDITOR
        UnityEditor.EditorApplication.isPlaying = false;
        //UnityEditor.EditorApplication.Exit(0);
#else
		Application.Quit();  
#endif
    }
}

IUserAction

using System;


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


 ISceneController

using System;


/// <summary>
/// Abstact Scene Controller. Interface between scene controllers and the director
/// </summary>
public interface ISceneController
{
    void LoadResources();
    int GameOver();
    void restart();
}


UserInterface

using UnityEngine;
using System.Collections;

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

    void Start()
    {
        mySceneController = SSDirector.getInstance().currentSceneController;
        myActions = mySceneController as IUserAction;
    }

    void Update()
    {

    }

    void OnGUI()
    {
        //游戏正常进行
        if (mySceneController.GameOver() == 0)
        {
            if (GUI.Button(new Rect(btnWidth / 2, 250, btnWidth, btnHeight), "Priests GetOn"))
            {
                myActions.priestsGetOn();
            }
            if (GUI.Button(new Rect(btnWidth / 2 + btnWidth, 250, btnWidth, btnHeight), "Priests GetOff"))
            {
                myActions.priestsGetOff();
            }
            if (GUI.Button(new Rect(btnWidth / 2 + 2 * btnWidth, 250, btnWidth, btnHeight), "Go!"))
            {
                myActions.boatMove();
            }
            if (GUI.Button(new Rect(btnWidth / 2 + 3 * btnWidth, 250, btnWidth, btnHeight), "Devils GetOn"))
            {
                myActions.devilsGetOn();
            }
            if (GUI.Button(new Rect(btnWidth / 2 + 4 * btnWidth, 250, btnWidth, btnHeight), "Devils GetOff"))
            {
                myActions.devilsGetOff();
            }
        }
        //lose
        else if (mySceneController.GameOver() == 1)
        {
            GUI.Box(new Rect(2 * btnWidth, btnHeight, 2 * btnWidth, btnHeight), "\nYOU LOSE");
            if (GUI.Button(new Rect(2.5f * btnWidth, 2 * btnHeight, btnWidth, btnHeight), "Restart"))
            {
                mySceneController.restart();
            }
        }
        //win
        else
        {
            GUI.Box(new Rect(2 * btnWidth, btnHeight, 2 * btnWidth, btnHeight), "\nYOU WIN");
            if (GUI.Button(new Rect(2.5f * btnWidth, 2 * btnHeight, btnWidth, btnHeight), "Restart"))
            {
                mySceneController.restart();
            }
        }

    }
}

PriestsStatus 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PriestsStatus
{
    private bool onBoatLeft, onBoatRight;
    private bool onBankLeft, onBankRight;

    public PriestsStatus()
    {
        this.onBoatLeft = false;
        this.onBoatRight = false;
        this.onBankLeft = true;
        this.onBankRight = false;
    }


    // 一些必要的get函数
    public bool GetonBoatLeft() { return onBoatLeft; }
    public bool GetonBoatRight() { return onBoatRight; }
    public bool GetonBankLeft() { return onBankLeft; }
    public bool GetonBankRight() { return onBankRight; }

    // 一些必要的set函数
    public void SetonBoatLeft(bool value) { onBoatLeft= value; }
    public void SetonBoatRight(bool value) { onBoatRight= value; }
    public void SetonBankLeft(bool value) { onBankLeft= value; }
    public void SetonBankRight(bool value) { onBankRight= value;}
    // Start is called before the first frame update
    void Start()
    {
        
    }
    
    // Update is called once per frame
    void Update()
    {
        
    }
}

DevilsStatus

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DevilsStatus
{
    private bool onBoatLeft, onBoatRight;
    private bool onBankLeft, onBankRight;
    public DevilsStatus() 
    {
        this.onBoatLeft = false;
        this.onBoatRight = false;
        this.onBankLeft = true;
        this.onBankRight = false;
    }
    // 一些必要的get函数
    public bool GetonBoatLeft() { return onBoatLeft; }
    public bool GetonBoatRight() { return onBoatRight; }
    public bool GetonBankLeft() { return onBankLeft; }
    public bool GetonBankRight() { return onBankRight; }

    // 一些必要的set函数
    public void SetonBoatLeft(bool value) { onBoatLeft = value; }
    public void SetonBoatRight(bool value) { onBoatRight = value; }
    public void SetonBankLeft(bool value) { onBankLeft = value; }
    public void SetonBankRight(bool value) { onBankRight = value; }

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

BoatBehaviour

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BoatBehaviour
{
    private bool isMoving;
    private bool atLeftSide;
    private bool leftPosEmpty, rightPosEmpty;

    public BoatBehaviour()
    {
        this.isMoving = false;
        this.atLeftSide = true;
        this.leftPosEmpty = true;
        this.rightPosEmpty = true;
    }

    // 一些必要的get函数
    public bool GetisMoving() { return isMoving; }
    public bool GetatLeftSide() { return atLeftSide; }
    public bool GetleftPosEmpty() { return leftPosEmpty; }
    public bool GetrightPosEmpty() { return rightPosEmpty; }

    // 一些必要的set函数
    public void SetisMoving(bool value) { isMoving = value; }
    public void SetatLeftSide(bool value) { atLeftSide = value;}
    public void SetleftPosEmpty(bool value) { leftPosEmpty = value;}
    public void SetrightPosEmpty(bool value) { rightPosEmpty = value;}

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

IGameJudge

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class IGameJudge
{
    public List<PriestsStatus> p_status;
    public List<DevilsStatus> d_status;
    public BoatBehaviour boatBehaviour;

    // 记录船上有多少个priest(devil)
    private int boatPriest, boatDevil;
    // 记录某个位置有多少个priest(devil)
    private int leftBankPriests, rightBankPriests;
    private int leftBankDevils, rightBankDevils;
    public IGameJudge()
    {
        boatPriest = 0;
        boatDevil = 0;
        leftBankPriests = 3;
        rightBankPriests = 0;
        leftBankDevils = 3;
        rightBankDevils = 0;
        p_status = new List<PriestsStatus>();
        d_status = new List<DevilsStatus>();
        boatBehaviour = new BoatBehaviour();
    }
    // 实时修改状态值
    public void reflash()
    {
        // priests devils
        p_status = new List<PriestsStatus>();
        d_status = new List<DevilsStatus>();
        for (int i = 0; i < 3; i++)
        {
            p_status.Add(new PriestsStatus());
            d_status.Add(new DevilsStatus());
        }
        //boat
        boatBehaviour = new BoatBehaviour();

        // 初始化
        leftBankDevils = 3;
        leftBankPriests = 3;
        rightBankDevils = 0;
        rightBankPriests = 0;
        boatPriest = 0;
        boatDevil = 0;
    }
    // 修改船上priest和devil的值
    // 第一个参数表示加减,第二个参数表示身份
    public void ModifyPersonCountOnBoat(bool plus, bool identify)
    {
        // 区分加减
        if (plus) 
        {
            // 区分priest和devil
            if (identify)
                boatPriest++;
            else
                boatDevil++;
        }
        else 
        {
            if(identify)
                boatPriest--;
            else
                boatDevil--;
        }
    }
    // 修改岸上priest和devil的值
    // 第一个参数表示加减,第二个参数表示身份,第三个参数表示哪个岸
    public void ModifyPersonCountOnBank(bool plus, bool identify, int bank)
    {
        // 区分加减
        if (plus)
        {
            // 区分priest和devil
            if (identify)
            {   
                // 区分左右岸
                if (bank == 1)
                    leftBankPriests++;
                else
                    rightBankPriests++;
            }
            else
            {
                if (bank == 1)
                    leftBankDevils++;
                else
                    rightBankDevils++;
            }
        }
        else
        {
            if (identify)
            {
                if (bank == 1)
                    leftBankPriests--;
                else
                    rightBankPriests--;
            }
            else
            {
                if (bank == 1)
                    leftBankDevils--;
                else
                    rightBankDevils--;
            }
        }
    }
    // 找出船上有谁
    // 0-2代表priest,3-5代表devil
    public List<int> PersonOnBoat()
    {
        List<int> ans = new();
        int i1 = -1;
        int i2 = -1;
        for (int i = 0; i < 3; i++)
        {
            if (p_status[i].GetonBoatLeft() || p_status[i].GetonBoatRight())
            {
                i1 = i;
                break;
            }
            if (d_status[i].GetonBoatLeft() || d_status[i].GetonBoatRight())
            {
                i1 = i + 3;
                break;
            }
        }
        for (int i = 0; i < 3; i++)
        {
            //第一个选了priest
            if (i == i1)
            {
                if (d_status[i].GetonBoatLeft() || d_status[i].GetonBoatRight())
                {
                    i2 = i + 3;
                    break;
                }
            }
            //第一个选了devil
            else if (i == i1 - 3)
            {
                if (p_status[i].GetonBoatLeft() || p_status[i].GetonBoatRight())
                {
                    i2 = i;
                    break;
                }
            }
            else
            {
                if (p_status[i].GetonBoatLeft() || p_status[i].GetonBoatRight())
                {
                    i2 = i;
                    break;
                }
                if (d_status[i].GetonBoatLeft() || d_status[i].GetonBoatRight())
                {
                    i2 = i + 3;
                    break;
                }
            }
        }
        ans.Add(i1);
        ans.Add(i2);
        return ans;
    }
    // 判断船能不能动
    public bool CanMove()
    {
        // 船在动或者船上没人时不能开船
        if (!boatBehaviour.GetisMoving() && (boatPriest + boatDevil > 0))
        {
           return true;
        }
        return false;
    }
    // 判断船是否在动
    public bool BoatIsMoving()
    {
        return boatBehaviour.GetisMoving();
    }
    // 返回哪个priest应该上船
    public List<int> PriestGotoBoat()
    {
        List<int> temp = new List<int>(); //第一个参数是哪个priest,第二个是船位置,第三个是岸位置
        // 船在左边
        if (boatBehaviour.GetatLeftSide())
        {
            for (int i = 0; i < 3; i++)
            {
                // 左侧岸上有牧师
                if (p_status[i].GetonBankLeft())
                {
                    // 上船位置
                    if (boatBehaviour.GetleftPosEmpty())
                    {
                        temp.Add(i);
                        temp.Add(0);
                        temp.Add(1);
                        return temp;
                    }
                    if (boatBehaviour.GetrightPosEmpty())
                    {
                        temp.Add(i);
                        temp.Add(1);
                        temp.Add(1);
                        return temp;
                    }
                }
            }
        }
        else
        {
            for (int i = 0; i < 3; i++)
            {
                //右侧岸上有牧师
                if (p_status[i].GetonBankRight())
                {
                    // 上船位置
                    if (boatBehaviour.GetleftPosEmpty())
                    {
                        temp.Add(i);
                        temp.Add(0);
                        temp.Add(0);
                        return temp;
                    }
                    if (boatBehaviour.GetrightPosEmpty())
                    {
                        temp.Add(i);
                        temp.Add(1);
                        temp.Add(0);
                        return temp;
                    }
                }
            }
        }
        return temp;
    }
    // 返回哪个priest应该下船
    public List<int> PriestGoOffBoat()
    {
        List<int> temp = new List<int>(); //第一个参数是哪个priest,第二个是船位置,第三个是岸位置
        // 船在左边
        if (boatBehaviour.GetatLeftSide())
        {
            for (int i = 0; i < 3; i++)
            {
                //船左侧有priest
                if (p_status[i].GetonBoatLeft())
                {
                    temp.Add(i);
                    temp.Add(0);
                    temp.Add(1);
                    return temp;
                }
                //船右侧有priest
                if (p_status[i].GetonBoatRight())
                {
                    temp.Add(i);
                    temp.Add(1);
                    temp.Add(1);
                    return temp;
                }
            }
        }
        else
        {
            for (int i = 0; i < 3; i++)
            {
                //船左侧有priest
                if (p_status[i].GetonBoatLeft())
                {
                    temp.Add(i);
                    temp.Add(0);
                    temp.Add(0);
                    return temp;
                }
                //船右侧有priest
                if (p_status[i].GetonBoatRight())
                {
                    temp.Add(i);
                    temp.Add(1);
                    temp.Add(0);
                    return temp;
                }
            }
        }
        return temp;
    }
    // 返回哪个devil应该上船
    public List<int> DevilGotoBoat()
    {
        List<int> temp = new List<int>(); //第一个参数是哪个devil,第二个是船位置,第三个是岸位置
        // 船在左边
        if (boatBehaviour.GetatLeftSide())
        {
            for (int i = 0; i < 3; i++)
            {
                // 左侧岸上有恶魔
                if (d_status[i].GetonBankLeft())
                {
                    // 上船位置
                    if (boatBehaviour.GetleftPosEmpty())
                    {
                        temp.Add(i);
                        temp.Add(0);
                        temp.Add(1);
                        return temp;
                    }
                    if (boatBehaviour.GetrightPosEmpty())
                    {
                        temp.Add(i);
                        temp.Add(1);
                        temp.Add(1);
                        return temp;
                    }

                }
            }
        }
        else
        {
            for (int i = 0; i < 3; i++)
            {
                //右侧岸上有恶魔
                if (d_status[i].GetonBankRight())
                {
                    // 上船位置
                    if (boatBehaviour.GetleftPosEmpty())
                    {
                        temp.Add(i);
                        temp.Add(0);
                        temp.Add(0);
                        return temp;
                    }
                    if (boatBehaviour.GetrightPosEmpty())
                    {
                        temp.Add(i);
                        temp.Add(1);
                        temp.Add(0);
                        return temp;
                    }
                }
            }
        }
        return temp;
    }
    // 返回哪个priest应该下船
    public List<int> DevilGoOffBoat()
    {
        List<int> temp = new List<int>(); //第一个参数是哪个devil,第二个是船位置,第三个是岸位置
        // 船在左边
        if (boatBehaviour.GetatLeftSide())
        {
            for (int i = 0; i < 3; i++)
            {
                //船左侧有devil
                if (d_status[i].GetonBoatLeft())
                {
                    temp.Add(i);
                    temp.Add(0);
                    temp.Add(1);
                    return temp;
                }
                //船右侧有devil
                if (d_status[i].GetonBoatRight())
                {
                    temp.Add(i);
                    temp.Add(1);
                    temp.Add(1);
                    return temp;
                }
            }
        }
        else
        {
            for (int i = 0; i < 3; i++)
            {
                //船左侧有devil
                if (d_status[i].GetonBoatLeft())
                {
                    temp.Add(i);
                    temp.Add(0);
                    temp.Add(0);
                    return temp;
                }
                //船右侧有devil
                if (d_status[i].GetonBoatRight())
                {
                    temp.Add(i);
                    temp.Add(1);
                    temp.Add(0);
                    return temp;
                }
            }
        }
        return temp;
    }
    // 判断游戏结束
    public int GameOver()
    {
        // 船靠岸分情况讨论
        if (boatBehaviour.GetatLeftSide())
        {
            if ((leftBankPriests + boatPriest > 0
                    && leftBankDevils + boatDevil > leftBankPriests + boatPriest)
                    || (rightBankDevils > rightBankPriests && rightBankPriests > 0))
            {
                return 1;
            }
        }
        else
        {
            if ((rightBankPriests + boatPriest > 0
                && rightBankDevils + boatDevil > rightBankPriests + boatPriest)
                || (leftBankDevils > leftBankPriests && leftBankPriests > 0))
            {
                return 1;
            }
            if (rightBankDevils + boatDevil == 3 && rightBankPriests + boatPriest == 3)
            {
                return 2;
            }
        }
        return 0;
    }
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
    }
}

 FirstController

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Scene Controller
/// Usage: host on a gameobject in the scene   
/// responsiablities:
///   acted as a scene manager for scheduling actors.log something ...
///   interact with the director and players
/// </summary>
public class FirstController : MonoBehaviour, ISceneController, IUserAction
{
    // 对每种物体新建类记录当前状态

    // 记录物体样式、位置等等
    public List<GameObject> Priests, Devils;
    public GameObject boat, bankLeft, bankRight;

    // 物体状态
    public List<PriestsStatus> p_status;
    public List<DevilsStatus> d_status;
    public BoatBehaviour myBoatBehaviour;

    // GameJudge
    public IGameJudge judge;

    // the first scripts
    void Awake()
    {
        SSDirector director = SSDirector.getInstance();
        director.setFPS(60);
        director.currentSceneController = this;
        director.currentSceneController.LoadResources();
    }

    // loading resources for the first scence
    public void LoadResources()
    {
        // GameJudge
        judge = new IGameJudge();

        // priests
        Priests = new List<GameObject>();
        p_status = judge.p_status;
        for (int i = 0; i < 3; i++)
        {
            GameObject priests = Instantiate<GameObject>(
                                Resources.Load<GameObject>("Prefabs/Priests"),
                                Vector3.zero, Quaternion.identity);
            priests.name = "Priest " + (i + 1);
            //priests.tag = "Priest";
            Priests.Add(priests);
        }

        //devils
        Devils = new List<GameObject>();
        d_status = judge.d_status;
        for (int i = 0; i < 3; i++)
        {
            GameObject devils = Instantiate<GameObject>(
                                Resources.Load<GameObject>("Prefabs/Devils"),
                                Vector3.zero, Quaternion.identity);
            devils.name = "Devil " + (i + 1);
            //devils.tag = "Devil";
            Devils.Add(devils);
        }

        //boat
        boat = Instantiate<GameObject>(
               Resources.Load<GameObject>("Prefabs/Boat"),
               Vector3.zero, Quaternion.identity);
        boat.name = "Boat";

        //bank
        bankLeft = Instantiate<GameObject>(
               Resources.Load<GameObject>("Prefabs/Shore"),
               Vector3.zero, Quaternion.identity);
        bankLeft.name = "BankLeft";

        bankRight = Instantiate<GameObject>(
               Resources.Load<GameObject>("Prefabs/Shore"),
               Vector3.zero, Quaternion.identity);
        bankRight.name = "BankRight";

        
        // 初始化
        restart();
    }

    public void boatMove()
    {
        // 船在动或者船上没人时不能开船
        if (judge.CanMove())
        {
            myBoatBehaviour.SetisMoving(true);
        }
    }
    public void onBoatMoving()
    {
        if (myBoatBehaviour.GetisMoving())
        {
            Vector3 moveDir;
            // 判断向左向右走
            List<int> place = judge.PersonOnBoat();
            if (place.Count == 0)
                return;
            // 向左
            int i1 = place[0];
            int i2 = place[1]; 
            if (!myBoatBehaviour.GetatLeftSide())
            {
                moveDir = new Vector3(-0.1f, 0, 0);
                boat.transform.Translate(moveDir);
                // 判断第一个位置
                if (i1 != -1)
                {
                    if (i1 < 3)
                        Priests[i1].transform.Translate(moveDir);
                    else
                        Devils[i1 - 3].transform.Translate(moveDir);
                }
                // 判断第二个位置
                if (i2 != -1)
                {
                    if (i2 < 3)
                        Priests[i2].transform.Translate(moveDir);
                    else
                        Devils[i2 - 3].transform.Translate(moveDir);
                }
                //到达对岸
                if (boat.transform.position.x == -2.4f)
                {
                    myBoatBehaviour.SetisMoving(false);
                    myBoatBehaviour.SetatLeftSide(true);
                }

            }
            // 向右
            else
            {
                moveDir = new Vector3(0.1f, 0, 0);
                boat.transform.Translate(moveDir);
                // 判断第一个位置
                if (i1 != -1)
                {
                    if (i1 < 3)
                        Priests[i1].transform.Translate(moveDir);
                    else
                        Devils[i1 - 3].transform.Translate(moveDir);
                }
                // 判断第二个位置
                if (i2 != -1)
                {
                    if (i2 < 3)
                        Priests[i2].transform.Translate(moveDir);
                    else
                        Devils[i2 - 3].transform.Translate(moveDir);
                }
                //到达对岸
                if (boat.transform.position.x == 1.7f)
                {
                    myBoatBehaviour.SetisMoving(false);
                    myBoatBehaviour.SetatLeftSide(false);
                }
            }
        }
    }
    public void priestsGetOn()
    {
        // 如果船正在动,那么不能响应用户事件
        if (judge.BoatIsMoving())
            return;
        List<int> temp = judge.PriestGotoBoat();
        // 如果temp为空,说明没找到该上船的priest
        if(temp.Count == 0) 
            return;
        int i = temp[0];
        p_status[i].SetonBankLeft(false);
        p_status[i].SetonBankRight(false);
        judge.ModifyPersonCountOnBank(false, true, temp[2]);
        judge.ModifyPersonCountOnBoat(true, true);
        // 上船的左边
        if (temp[1] == 0)
        {
            p_status[i].SetonBoatLeft(true);
            myBoatBehaviour.SetleftPosEmpty(false);
            // 船在左岸
            if (myBoatBehaviour.GetatLeftSide())
                Priests[i].transform.position = new Vector3(-3.3f, 1.5f, 0);
            else
                Priests[i].transform.position = new Vector3(1, 1.5f, 0);
        }
        else
        {
            p_status[i].SetonBoatRight(true);
            myBoatBehaviour.SetrightPosEmpty(false);
            // 船在右岸
            if (myBoatBehaviour.GetatLeftSide())
                Priests[i].transform.position = new Vector3(-1.8f, 1.5f, 0);
            else
                Priests[i].transform.position = new Vector3(2.5f, 1.5f, 0);
        }
    }
    public void priestsGetOff()
    {
        if (judge.BoatIsMoving())
            return;
        List<int> temp = judge.PriestGoOffBoat();
        // 如果temp为空,说明没找到该上船的priest
        if (temp.Count == 0)
            return;
        int i = temp[0];
        judge.ModifyPersonCountOnBank(true, true, temp[2]);
        judge.ModifyPersonCountOnBoat(false, true);
        p_status[i].SetonBoatLeft(false);
        p_status[i].SetonBoatRight(false);
        // 船在左岸
        if (temp[2] == 1)
        {
            p_status[i].SetonBankLeft(true);
            Priests[i].transform.position = new Vector3((-8.6f + i * 1.3f), 3, 0);
            if (temp[1] == 0)
                myBoatBehaviour.SetleftPosEmpty(true);
            else
                myBoatBehaviour.SetrightPosEmpty(true);
        }
        else
        {
            p_status[i].SetonBankRight(true);
            Priests[i].transform.position = new Vector3((6 + i * 1.3f), 3, 0);
            if (temp[1] == 0)
                myBoatBehaviour.SetleftPosEmpty(true);
            else
                myBoatBehaviour.SetrightPosEmpty(true);
        }
    }
    public void devilsGetOn()
    {
        // 如果船正在动,那么不能响应用户事件
        if (judge.BoatIsMoving())
            return;
        List<int> temp = judge.DevilGotoBoat();
        // 如果temp为空,说明没找到该上船的devil
        if (temp.Count == 0)
            return;
        int i = temp[0];
        d_status[i].SetonBankLeft(false);
        d_status[i].SetonBankRight(false);
        judge.ModifyPersonCountOnBank(false, false, temp[2]);
        judge.ModifyPersonCountOnBoat(true, false);
        // 上船的左边
        if (temp[1] == 0)
        {
            d_status[i].SetonBoatLeft(true);
            myBoatBehaviour.SetleftPosEmpty(false);
            // 船在左岸
            if (myBoatBehaviour.GetatLeftSide())
                Devils[i].transform.position = new Vector3(-3.3f, 1.5f, 0);
            else
                Devils[i].transform.position = new Vector3(1, 1.5f, 0);
        }
        else
        {
            d_status[i].SetonBoatRight(true);
            myBoatBehaviour.SetrightPosEmpty(false);
            // 船在右岸
            if (myBoatBehaviour.GetatLeftSide())
                Devils[i].transform.position = new Vector3(-1.8f, 1.5f, 0);
            else
                Devils[i].transform.position = new Vector3(2.5f, 1.5f, 0);
        }
    }
    public void devilsGetOff()
    {
        if (judge.BoatIsMoving())
            return;
        List<int> temp = judge.DevilGoOffBoat();
        // 如果temp为空,说明没找到该上船的devil
        if (temp.Count == 0)
            return;
        int i = temp[0];
        judge.ModifyPersonCountOnBank(true, false, temp[2]);
        judge.ModifyPersonCountOnBoat(false, false);
        d_status[i].SetonBoatLeft(false);
        d_status[i].SetonBoatRight(false);
        // 船在左岸
        if (temp[2] == 1)
        {
            d_status[i].SetonBankLeft(true);
            Devils[i].transform.position = new Vector3((-12.9f + i * 1.3f), 3, 0);
            if (temp[1] == 0)
                myBoatBehaviour.SetleftPosEmpty(true);
            else
                myBoatBehaviour.SetrightPosEmpty(true);
        }
        else
        {
            d_status[i].SetonBankRight(true);
            Devils[i].transform.position = new Vector3((10.3f + i * 1.3f), 3, 0);
            if (temp[1] == 0)
                myBoatBehaviour.SetleftPosEmpty(true);
            else
                myBoatBehaviour.SetrightPosEmpty(true);
        }
    }
    public int GameOver()
    {
        return judge.GameOver();
    }
    public void restart()
    {
        // priests
        Priests[0].transform.position = new Vector3(-8.6f, 3, 0);
        Priests[1].transform.position = new Vector3(-7.3f, 3, 0);
        Priests[2].transform.position = new Vector3(-6, 3, 0);

        //devils
        Devils[0].transform.position = new Vector3(-12.9f, 3, 0);
        Devils[1].transform.position = new Vector3(-11.6f, 3, 0);
        Devils[2].transform.position = new Vector3(-10.3f, 3, 0);

        //boat
        boat.transform.position = new Vector3(-2.4f, 0.5f, 0);

        //bank
        bankLeft.transform.position = new Vector3(-8.5f, 1.5f, 0);
        bankRight.transform.position = new Vector3(8.5f, 1.5f, 0);

        judge.reflash();
    }
    // Use this for initialization
    void Start()
    {
        //give advice first
    }

    // Update is called once per frame
    void Update()
    {
        //give advice first
        // 将状态实时修改传回FirstController
        p_status = judge.p_status;
        d_status = judge.d_status;
        myBoatBehaviour = judge.boatBehaviour;
        //用于船和人的移动
        onBoatMoving();
    }

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值