Unity编程实战--牧师与魔鬼

魔鬼与牧师
游戏目标:将3个牧师和3个魔鬼从河的一端安全地送到河的另一端。
游戏规则:在运送过程中,船可以搭载两个人,而且必须有一人掌船。
游戏结果:无论何时,只要河一边的魔鬼数量多于牧师的数量,游戏就会以失败结束。当三个牧师与魔鬼都平安到达河的另一端时胜利。
游戏对象的行为
角色:上下船、划船
魔鬼:当两岸任意一边人数多于牧师时杀死牧师,游戏结束
船:有人时可以动
参考上级同学实现MVC架构:
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
师兄博客传送门:Klog师兄的牧师与魔鬼
UML图

代码实现

文件结构我使用的文件结构:
文件结构
预制:prefabs
介绍prefabs的博客:作者000000000000O–Unity Prefabs
使用预制可以创建游戏对象后设置好再拉到预制,之后只要把对象删除就好!在Asset里面可以创建Material来给预制上色之类。
这里我把河岸、河还有岸上的树当作一个主物体,会动的priest devil boat则不用管
我的预制
以M开头的就是Material
在代码中可用Resources.Load 和 Instantiate来加载预制!加载出来的名字是”xx(Clone)”
Scripts
自己很难明白怎么做,还好有学长们的博客哈哈
脚本
其中SceneHandle和UserAction是接口:由FirstControllor来具体实现
接口知识:c#接口

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

public interface SceneHandle {
    void Load ();
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface UserAction{
    void priestGetOn ();
    void priestGetOff ();
    void devilGetOn ();
    void devilGetOff ();
    void moveBoat ();
    void restart ();
    int result ();
    int getResult ();
}

SDirector即所谓单例类,是全局中只能存在唯一一个对象的类,通过函数getInstance()可以获得这个类的实例对象。通过这唯一一个全局可访问的对象即使不用SendMessage之类的方法也可以实现类之间的通信,从而保有了代码的MVC架构

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

public class SDirector : System.Object {
    private static SDirector _instance;
    public SceneHandle currentSceneController {get; set;}

    public static SDirector getInstance() {
        if (_instance == null) {
            _instance = new SDirector();
        }
        return _instance;
    }
}

myGui时对游戏场景Button等的构建,FirstControllor对游戏进行了逻辑实现,值得一提的是在restart()方法里重新加载场景所调用的EditorSceneManager.LoadScene方法会造成场景变暗,但改进的话要创建灯光之类的看不太明白…
还有就是判定结果是否输赢我最开始是在点击GetOff方法时进行判定,但玩游戏的时候发现不是这时判定的,但在点Go时判定又有些早,所以应该是Go时判定,但当船到对岸时再出游戏结果。因为这个问题发现的很晚没来得及仔细实现,只好在myGUI类里加上了判定,才让游戏看起来比较合理

using System.Collections;
using System.Collections.Generic;
using UnityEditor.SceneManagement;
using UnityEngine;

public class FirstControllor : MonoBehaviour, SceneHandle, UserAction {
    SDirector MySD;
    public int boatState = 0;
    //0=start,1=end,2=move from start shore,3=move from end shore

    public int gameResult = 0;
    //1=win,2=lose

    GameObject[] onBoat=new GameObject[2];
    GameObject boat;

    float gap = 1.5f;

    Stack<GameObject> SPriest = new Stack<GameObject>();
    Stack<GameObject> EPriest = new Stack<GameObject>();
    Stack<GameObject> SDevil = new Stack<GameObject>();
    Stack<GameObject> EDevil = new Stack<GameObject>();

    Vector3 boatStart = new Vector3 (-2f, 0.5f, 0);
    Vector3 boatEnd = new Vector3 (2f, 0.5f, 0);

    float speed=10;

    public void Load(){
        GameObject myGO = Instantiate<GameObject> (Resources.Load<GameObject> ("prefabs/main"), Vector3.zero, Quaternion.identity);
        myGO.name = "main";
        boat = Instantiate (Resources.Load ("prefabs/boat"), boatStart, Quaternion.identity)as GameObject;
        for (int i = 0; i < 3; i++) {
            SPriest.Push (Instantiate (Resources.Load ("prefabs/priest")) as GameObject);
            SDevil.Push (Instantiate (Resources.Load ("prefabs/devil"))as GameObject);
        }
    }       

    void Awakemethod(){
        SDirector d = SDirector.getInstance ();
        d.currentSceneController = this;
        d.currentSceneController.Load ();
    }

    void Awake(){
        Awakemethod ();
    }

    int boatCapacity(){
        int cnt = 0;
        for(int i=0;i<2;i++){
            if (onBoat [i] == null)
                cnt++;
        }
        return cnt;
    }

    void setCharacterPositions(Stack<GameObject> que, Vector3 pos) {
        GameObject[] array = que.ToArray();
        for (int i = 0; i < que.Count; ++i) {  
            array[i].transform.position = new Vector3(pos.x + gap*i, pos.y, pos.z);  
        }  
    }

    public void getOn(GameObject obj){
        if (boatCapacity () != 0) {
            obj.transform.parent = boat.transform;
            if (onBoat [0] == null) {
                onBoat [0] = obj;
                obj.transform.localPosition = new Vector3 (-0.2f, 1f, 0);
            } else {
                onBoat [1] = obj;
                obj.transform.localPosition = new Vector3 (0.2f, 1f, 0);
            }
        }
    }

    public void priestGetOn(){
        if (SPriest.Count != 0 && boatCapacity () != 0 && this.boatState == 0) {
            getOn (SPriest.Pop ());
        } else if (EPriest.Count != 0 && boatCapacity () != 0 && this.boatState == 1) {
            getOn (EPriest.Pop ());
        }
    }

    public void devilGetOn(){
        if (SDevil.Count != 0 && boatCapacity () != 0 && this.boatState == 0) {
            getOn (SDevil.Pop ());
        } else if (EDevil.Count != 0 && boatCapacity () != 0 && this.boatState == 1) {
            getOn (EDevil.Pop ());
        }
    }

    public void priestGetOff(){
        for(int i=0;i<2;i++){
            if(onBoat[i]!=null){
                if(this.boatState==1){
                    if(onBoat[i].name=="priest(Clone)"){
                        EPriest.Push (onBoat [i]);
                        onBoat[i].transform.parent=null;
                        onBoat [i] = null;
                        break;
                    }
                }
                else if(this.boatState==0){
                    if(onBoat[i].name=="priest(Clone)"){
                        SPriest.Push (onBoat [i]);
                        onBoat[i].transform.parent=null;
                        onBoat[i]=null;
                        break;
                    }
                }
            }
        }
    }

    public void devilGetOff(){
        for(int i=0;i<2;i++){
            if(onBoat[i]!=null){
                if(this.boatState==1){
                    if(onBoat[i].name=="devil(Clone)"){
                        EDevil.Push (onBoat [i]);
                        onBoat[i].transform.parent=null;
                        onBoat [i] = null;
                        break;
                    }
                }
                else if(this.boatState==0){
                    if(onBoat[i].name=="devil(Clone)"){
                        SDevil.Push (onBoat [i]);
                        onBoat[i].transform.parent=null;
                        onBoat[i]=null;
                        break;
                    }
                }
            }
        }
    }   

    public void moveBoat(){
        if(boatCapacity()==2)return ;
        /*if (boatState == 0)
            boatState = 2;
        else if (boatState == 1)
            boatState = 3;*/
        this.boatState += 2;
        //Debug.Log (boatState);
    }

    public void restart(){
        //Awakemethod ();
        EditorSceneManager.LoadScene(EditorSceneManager.GetActiveScene().name);
        boatState = gameResult = 0;
    }

    public int getResult(){
        return gameResult;
    }

    public int result(){
        if (EPriest.Count == 3 && EDevil.Count == 3) {
            gameResult = 1;
        }
        int cntPriest = 0, cntDevil = 0;
        for (int i = 0; i < 2; i++) {
            if (onBoat [i] != null) {
                if (onBoat [i].name == "priest(Clone)")
                    cntPriest++;
                else
                    cntDevil++;
            }
        }
        int cntPriestStart = 0, cntPriestEnd = 0;
        int cntDevilStart = 0, cntDevilEnd = 0;
        if (boatState == 0) {
            cntPriestStart = SPriest.Count + cntPriest;
            cntDevilStart = SDevil.Count + cntDevil;
            cntPriestEnd = EPriest.Count;
            cntDevilEnd = EDevil.Count;
        } else if (boatState == 1) {
            cntPriestStart = SPriest.Count;
            cntDevilStart = SDevil.Count;
            cntPriestEnd = EPriest.Count + cntPriest;
            cntDevilEnd = EDevil.Count + cntDevil;
        }
        /*cntPriestStart = SPriest.Count;
        cntDevilStart = SDevil.Count;
        cntPriestEnd = EPriest.Count;
        cntDevilEnd = EDevil.Count;*/
        if ((cntPriestStart != 0 && cntPriestStart < cntDevilStart) || (cntPriestEnd != 0 && cntPriestEnd < cntDevilEnd)) {
            gameResult = 2;
        }
        return gameResult;
    }

    // Use this for initialization
    void Start () {

    }


    // Update is called once per frame
    void Update () {
        setCharacterPositions (SPriest, new Vector3 (-13f, 3, 0));
        setCharacterPositions (EPriest, new Vector3 (9f, 3, 0));
        setCharacterPositions (SDevil, new Vector3 (-8f, 3, 0));
        setCharacterPositions (EDevil, new Vector3 (4f, 3, 0));
        if (boatState == 2) {
            boat.transform.position = Vector3.MoveTowards (boat.transform.position, boatEnd, speed * Time.fixedDeltaTime);
            if (boat.transform.position == boatEnd) {
                boatState = 1;
                result ();
            }

        } else if (boatState == 3) {
            boat.transform.position = Vector3.MoveTowards (boat.transform.position, boatStart, speed * Time.fixedDeltaTime);
            if (boat.transform.position == boatStart) {
                boatState = 0;
                result ();
            }
        } 
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class myGUI : MonoBehaviour {
    private UserAction action;

    // Use this for initialization
    void Start () {
        action = SDirector.getInstance ().currentSceneController as UserAction;
    }

    // Update is called once per frame
    void OnGUI()
    {
        GUIStyle fontStyle = new GUIStyle();
        fontStyle.normal.background = null;
        fontStyle.normal.textColor = new Color(1, 0, 0);
        fontStyle.fontSize = 20;

        float width = Screen.width / 6;
        float height = Screen.height / 12;
        if (action.getResult()==1)
        { //赢了的话
            GUI.Label(new Rect(Screen.width/2, 15, 100, 100), "Win!", fontStyle);
            if (GUI.Button(new Rect(0, Screen.height - height, Screen.width, height), "Restart!"))
            {
                action.restart();
            }
        }
        else if (action.getResult()==2)
        { //输了的话
            GUI.Label(new Rect(Screen.width/2,15, 100, 100), "Lose!", fontStyle);
            if (GUI.Button(new Rect(0, Screen.height - height, Screen.width, height), "Restart!"))
            {
                action.restart();
            }
        }
        else
        { 
            if (GUI.Button(new Rect(0, 0, width, height), "PriestOnBoat"))
            {

                action.priestGetOn();
            }

            if (GUI.Button(new Rect( width, 0, width, height), "PriestOffBoat"))
            {
                action.result ();
                action.priestGetOff();
            }

            if (GUI.Button(new Rect(0, height, width, height), "DevilOnBoat"))
            {
                action.devilGetOn();
            }

            if (GUI.Button(new Rect(width, height, width, height), "DevilOffBoat"))
            {
                action.result ();
                action.devilGetOff();
            }

            if (GUI.Button(new Rect(2 * width, 0, width, height), "GO"))
            {
                action.moveBoat();
            }
            if (GUI.Button (new Rect (2 * width, height, width, height), "restart")) {
                action.restart ();
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值