Unity3d学习笔记(3)--牧师与魔鬼游戏

牧师与魔鬼游戏简介:

一个牧师与魔鬼的游戏,3个牧师与3个魔鬼都在河的一边,他们都想要度过一条河,但是只有一条船而且这条船一次只能搭载两个人,

而且每次都需要有一个人把船从河的一边划到另一边,你可以点击他们把它们移动,点击go按钮可以移动船到另一边,如果任一边魔鬼的数

量多于牧师的数量,游戏就结束了。


整个游戏的源代码在最下面,想要整个代码的可以在下面找

首先,先上一张最终的结果图,白球代表牧师,红色的正方形代表魔鬼,两个比较大的长方形代表岸边,剩下的小长方形代表小船



为了起到游戏原来的效果,下面是一些提前的设置,把3D物体投影到x-y平面,可以起到2D的效果



把摄像机的position,Background,Projection,Size设置成如下



把FristSceneController.cs和UserGUI.cs作为组件挂到摄像机或一个空对象上


文件总共包括六个文件,如下:

Director.cs

FristSceneController.cs

On_Off.cs

UserGUI.cs

IUserAction.cs

ISceneController.cs


UML图:


好了,下面就开始写游戏代码了:


public enum GameState { WIN, FAILED, NOT_ENDED } //表示游戏的状态

    public enum BoatState { MOVING, STOPLEFT,STOPRIGHT} //表示船的状态
    public GameObject Shore_l;
    public GameObject Shore_r;
    public GameObject boat;
    public Dictionary<int, GameObject> On_Boat = new Dictionary<int, GameObject>();  
    public Dictionary<int, GameObject> On_Shore_r = new Dictionary<int, GameObject>();
    public Dictionary<int, GameObject> On_Shore_l = new Dictionary<int, GameObject>();
用三个字典来组织人物,在船上的人物会被加入On_Boat,其它也如此

资源的加载,包括3个牧师和3个恶魔,2个岸边和一个小船,以及它们初始位置的设置,这里是直接用代码生成的

这里对牧师和魔鬼做了一个编号,固定了它们在岸边的位置以及判断它们是在船上还是在岸边,牧师的编号是0~2,恶魔的编号是3~5,


public void GenGameObjects()
    {
        Shore_l = GameObject.CreatePrimitive(PrimitiveType.Cube);
        Shore_l.name = "Shore_l";
        Shore_l.transform.localScale = new Vector3(10, 2, 1);
        Shore_l.transform.position = new Vector3(-17, -9, 0);
        Shore_r = Instantiate<GameObject>(Shore_l, new Vector3(17, -9, 0), Quaternion.identity);
        Shore_r.name = "Shore_r";
       
        boat = GameObject.CreatePrimitive(PrimitiveType.Cube); ;
        boat.transform.localScale = new Vector3(3, 1, 1);
        boat.transform.position = new Vector3(10.4f, -9.5f, 0);
        boat.name = "boat";

        GameObject temp_priest = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        temp_priest.transform.localScale = new Vector3(1, 1, 1);
        temp_priest.AddComponent<On_Off>(); //为牧师添加上下船的组件

        GameObject temp_devil = GameObject.CreatePrimitive(PrimitiveType.Cube);
        temp_devil.transform.localScale = new Vector3(1, 1, 1);
        temp_devil.AddComponent<On_Off>(); //为魔鬼添加上下船的组件


        for (int i = 0; i < 3; i++)
        {
            
            On_Shore_r.Add(i, Instantiate<GameObject>(temp_priest, new Vector3(12.5f + i * gab, -7.5f, 0), Quaternion.identity));
            On_Shore_r[i].name = i.ToString();
        }

        for (int i = 3; i < 6; i++)
        {
            
            GameObject tmp = Instantiate<GameObject>(temp_devil, new Vector3(12.5f + i * gab, -7.5f, 0), Quaternion.identity);
            tmp.name = i.ToString();
            tmp.GetComponent<Renderer>().material.color = Color.red;
            On_Shore_r.Add(i, tmp);
        }
        
        boat_capicity = 2;  //限制船最多有2个人
        b_state = BoatState.STOPLEFT;
        Destroy(temp_devil);
        Destroy(temp_priest);
       
    }


接下来来写魔鬼与牧师上下船的脚本,这是可以实现点击人物使其移动,主要用了OnMouseDown事件,

如果它们上船,就把它们的编号加6,如果下船,就减6

enum Pos { ON_BOAT, ON_SHORE} //用来表示人物的位置

private void OnMouseDown()
    {
        if (firstSceneControl.game_state == GameState.NOT_ENDED)
        {
            if (firstSceneControl.b_state == FirstSceneControl.BoatState.MOVING) return;
            
            int id = Convert.ToInt32(this.name);
            if (firstSceneControl.b_state == FirstSceneControl.BoatState.STOPRIGHT)
            {
                if (firstSceneControl.On_Shore_r.ContainsKey(id))
                {
                    if (find_Pos(id) == Pos.ON_SHORE && firstSceneControl.boat_capicity != 0) //find_Pos函数是根据人物的key来确定人物的位置,在船上或岸上
                    {
                        firstSceneControl.On_Boat.Add(id + 6, firstSceneControl.On_Shore_r[id]);
                        firstSceneControl.On_Shore_r.Remove(id);
                        this.name = (id + 6).ToString();
                        this.transform.parent = firstSceneControl.boat.transform;
                        firstSceneControl.boat_capicity--;
                    }
                }


                if (find_Pos(id) == Pos.ON_BOAT)
                {

                    firstSceneControl.On_Shore_r.Add(id - 6, firstSceneControl.On_Boat[id]);
                    firstSceneControl.On_Boat.Remove(id);
                    this.name = (id - 6).ToString();
                    this.transform.parent = null;
                    firstSceneControl.boat_capicity++;
                }
            }
            if (firstSceneControl.b_state == FirstSceneControl.BoatState.STOPLEFT)
            {

                if (find_Pos(id) == Pos.ON_SHORE && firstSceneControl.boat_capicity != 0)
                {
                    if (firstSceneControl.On_Shore_l.ContainsKey(id))
                    {
                        firstSceneControl.On_Boat.Add(id + 6, firstSceneControl.On_Shore_l[id]);
                        firstSceneControl.On_Shore_l.Remove(id);
                        this.name = (id + 6).ToString();
                        this.transform.parent = firstSceneControl.boat.transform;
                        firstSceneControl.boat_capicity--;
                    }

                }

                if (find_Pos(id) == Pos.ON_BOAT)
                {
                    firstSceneControl.On_Shore_l.Add(id - 6, firstSceneControl.On_Boat[id]);
                    firstSceneControl.On_Boat.Remove(id);
                    this.name = (id - 6).ToString();
                    this.transform.parent = null;
                    firstSceneControl.boat_capicity++;
                }
            }


        }
    }    

接下来是船移动的函数,这里实现的比较简陋,是直接改变船的位置

public void MoveBoat()
    {
        if (On_Boat.Count != 0)
        {
            if (b_state == BoatState.STOPLEFT)
            {
                boat.transform.position = new Vector3(10.3f, -9.5f, 0);
                
            }

            if (b_state == BoatState.STOPRIGHT)
            {
              
                boat.transform.position = new Vector3(-10.3f, -9.5f, 0);
                
            }
        }

    }

最后,说下检查游戏状态的函数

GameState check()
    {
        
        if (On_Shore_l.Count == 6)
        {
            return GameState.WIN;
        }
        
        else if (b_state == BoatState.STOPLEFT)
        {
            
           if (get_num(On_Boat, 1) + get_num(On_Shore_l, 1) != 0
                    && get_num(On_Boat, 1) + get_num(On_Shore_l, 1) < (get_num(On_Boat, -1) + get_num(On_Shore_l, -1))) //get_num是用来获取牧师或魔鬼的数量
            {														//第一个参数是地点,第二个参数1表示
               														//牧师,否则是魔鬼
                return GameState.FAILED;
            }
           if(get_num(On_Shore_r, 1) != 0 && get_num(On_Shore_r, 1) < get_num(On_Shore_r, -1))
            {
                
                return GameState.FAILED;
            }
        }

        else if (b_state == BoatState.STOPRIGHT)
        {
            if (get_num(On_Boat, 1) + get_num(On_Shore_r, 1) != 0
                     && get_num(On_Boat, 1) + get_num(On_Shore_r, 1) < (get_num(On_Boat, -1) + get_num(On_Shore_r, -1)))
            {
                
                return GameState.FAILED;
            }
            if (get_num(On_Shore_l, 1) != 0 && get_num(On_Shore_l, 1) < get_num(On_Shore_r, -1))
            {
                
                return GameState.FAILED;
            }
        }
        return GameState.NOT_ENDED;

    }


整个游戏的主要内容就完了,下面是全部文件的源代码:

Director.cs

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

public class Director : System.Object {

    public ISceneControl currentSceneControl { get; set; }
    private static Director director;

    private Director()
    {

    }

	public static Director getInstance()
    {
        if (director == null)
        {
            director = new Director();
        }
        return director;
    }
}


FristSceneController.cs

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

public class FirstSceneControl : MonoBehaviour, ISceneControl, IUserAction {

    // Use this for initialization
    //public enum GameState { WIN, FAILED, NOT_ENDED }
    public enum BoatState { MOVING, STOPLEFT,STOPRIGHT}
    public GameObject Shore_l;
    public GameObject Shore_r;
    public GameObject boat;
    public Dictionary<int, GameObject> On_Boat = new Dictionary<int, GameObject>();
    public Dictionary<int, GameObject> On_Shore_r = new Dictionary<int, GameObject>();
    public Dictionary<int, GameObject> On_Shore_l = new Dictionary<int, GameObject>();
    //public Vector3 Boat_Left = new Vector3(-10.3f, -9.5f, 0);
    //public Vector3 Boat_Right = new Vector3(10.3f, -9.5f, 0);
    //public Vector3 Shore_Left = new Vector3(-12.5f, -7.5f, 0);
    //public Vector3 Shore_Right = new Vector3(19.5f, -7.5f, 0);
    public GameState game_state;
    float gab = 1.5f;
    public int boat_capicity;
    public BoatState b_state;
    void Awake () {
        Director director = Director.getInstance();
        director.currentSceneControl = this;
        director.currentSceneControl.GenGameObjects();
       
    }
	

    public void GenGameObjects()
    {
        Shore_l = GameObject.CreatePrimitive(PrimitiveType.Cube);
        Shore_l.name = "Shore_l";
        Shore_l.transform.localScale = new Vector3(10, 2, 1);
        Shore_l.transform.position = new Vector3(-17, -9, 0);
        Shore_r = Instantiate<GameObject>(Shore_l, new Vector3(17, -9, 0), Quaternion.identity);
        Shore_r.name = "Shore_r";
       
        boat = GameObject.CreatePrimitive(PrimitiveType.Cube); ;
        boat.transform.localScale = new Vector3(3, 1, 1);
        boat.transform.position = new Vector3(10.4f, -9.5f, 0);
        boat.name = "boat";

        GameObject temp_priest = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        temp_priest.transform.localScale = new Vector3(1, 1, 1);
        temp_priest.AddComponent<On_Off>();

        GameObject temp_devil = GameObject.CreatePrimitive(PrimitiveType.Cube);
        temp_devil.transform.localScale = new Vector3(1, 1, 1);
        temp_devil.AddComponent<On_Off>();

        //Shore_l = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/Shore"), new Vector3(-17, -9, 0), Quaternion.identity);
        //Shore_r = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/Shore"), new Vector3(17, -9, 0), Quaternion.identity);
        //boat = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/boat"), new Vector3(10.3f, -9.5f, 0), Quaternion.identity);
        for (int i = 0; i < 3; i++)
        {
            // On_Shore_r.Add(i, Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/Priests"), new Vector3(12.5f + i * gab, -7.5f, 0), Quaternion.identity));
            On_Shore_r.Add(i, Instantiate<GameObject>(temp_priest, new Vector3(12.5f + i * gab, -7.5f, 0), Quaternion.identity));
            On_Shore_r[i].name = i.ToString();
        }

        for (int i = 3; i < 6; i++)
        {
            //GameObject tmp = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/Devils"), new Vector3(12.5f + i * gab, -7.5f, 0), Quaternion.identity);
            GameObject tmp = Instantiate<GameObject>(temp_devil, new Vector3(12.5f + i * gab, -7.5f, 0), Quaternion.identity);
            tmp.name = i.ToString();
            tmp.GetComponent<Renderer>().material.color = Color.red;
            On_Shore_r.Add(i, tmp);
        }
        
        boat_capicity = 2;
        b_state = BoatState.STOPLEFT;
        Destroy(temp_devil);
        Destroy(temp_priest);
       
    }

    private void Update()
    {
        game_state = check();
        if (game_state == GameState.NOT_ENDED)
        {
            if (boat.transform.position.x < 10.2f && boat.transform.position.x > -10.2f)
            {
                b_state = BoatState.MOVING;
            }
            else if (boat.transform.position.x > 10.2f)
            {
                b_state = BoatState.STOPRIGHT;
            }
            else
            {
                b_state = BoatState.STOPLEFT;
            }

            for (int i = 0; i < 6; i++)
            {
                if (On_Shore_l.ContainsKey(i)) On_Shore_l[i].transform.position = new Vector3(-12.5f - i * gab, -7.5f, 0);

                if (On_Shore_r.ContainsKey(i)) On_Shore_r[i].transform.position = new Vector3(12.5f + i * gab, -7.5f, 0);
            }
            int signed = 1;
            for (int i = 6; i < 12; i++)
            {
                if (On_Boat.ContainsKey(i))
                {
                    On_Boat[i].transform.localPosition = new Vector3(signed * 0.3f, 1, 0);
                    signed = -signed;
                }
            }
        }
    }

    public void MoveBoat()
    {
        if (On_Boat.Count != 0)
        {
            if (b_state == BoatState.STOPLEFT)
            {
                //Debug.Log("left");
                //boat.transform.position = new Vector3(10.3f, -9.5f, 0);
                boat.transform.position = new Vector3(10.3f, -9.5f, 0);
                //Vector3.MoveTowards(boat.transform.position, new Vector3(10.3f, -9.5f, 0), 1 * Time.deltaTime);
            }

            if (b_state == BoatState.STOPRIGHT)
            {
               // Debug.Log("right");
                boat.transform.position = new Vector3(-10.3f, -9.5f, 0);
                //Vector3.MoveTowards(boat.transform.position, new Vector3(-10.3f, -9.5f, 0), 1 * Time.deltaTime);
            }
        }

    }



    public void GameOver()
    {
        GUI.color = Color.red;
        GUI.Label(new Rect(700, 300, 400, 400), "GAMEOVER");
        
    }

    public int get_num(Dictionary<int, GameObject> dict, int ch)
    {
        var keys = dict.Keys;
        int d_num = 0;
        int p_num = 0;
        foreach(int i in keys)
        {
            if (i < 3 || (i >= 6 && i <= 8))
            {
                p_num++;
            }
            else
            {
                d_num++;
            }
        }
        return (ch == 1 ? p_num : d_num);
    }

    GameState check()
    {
        
        if (On_Shore_l.Count == 6)
        {
            return GameState.WIN;
        }
        
        else if (b_state == BoatState.STOPLEFT)
        {
            
           if (get_num(On_Boat, 1) + get_num(On_Shore_l, 1) != 0
                    && get_num(On_Boat, 1) + get_num(On_Shore_l, 1) < (get_num(On_Boat, -1) + get_num(On_Shore_l, -1)))
            {
               
                return GameState.FAILED;
            }
           if(get_num(On_Shore_r, 1) != 0 && get_num(On_Shore_r, 1) < get_num(On_Shore_r, -1))
            {
                
                return GameState.FAILED;
            }
        }

        else if (b_state == BoatState.STOPRIGHT)
        {
            if (get_num(On_Boat, 1) + get_num(On_Shore_r, 1) != 0
                     && get_num(On_Boat, 1) + get_num(On_Shore_r, 1) < (get_num(On_Boat, -1) + get_num(On_Shore_r, -1)))
            {
                
                return GameState.FAILED;
            }
            if (get_num(On_Shore_l, 1) != 0 && get_num(On_Shore_l, 1) < get_num(On_Shore_r, -1))
            {
                
                return GameState.FAILED;
            }
        }
        return GameState.NOT_ENDED;

    }

    public GameState getGameState()
    {
        return game_state;
    }
}

On_Off.cs

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

public class On_Off : MonoBehaviour
{

    // Use this for initialization
    private FirstSceneControl firstSceneControl;
    enum Pos { ON_BOAT, ON_SHORE}

    Pos find_Pos(int id)
    {
        if (id >= 6) return Pos.ON_BOAT;
        return Pos.ON_SHORE;
    }

    void Start()
    {
        firstSceneControl = (FirstSceneControl)Director.getInstance().currentSceneControl;
    }


    private void OnMouseDown()
    {
        if (firstSceneControl.game_state == GameState.NOT_ENDED)
        {
            if (firstSceneControl.b_state == FirstSceneControl.BoatState.MOVING) return;
            // firstSceneControl.boat_capicity--;
            // this.transform.parent = firstSceneControl.boat.transform;
            int id = Convert.ToInt32(this.name);
            if (firstSceneControl.b_state == FirstSceneControl.BoatState.STOPRIGHT)
            {
                if (firstSceneControl.On_Shore_r.ContainsKey(id))
                {
                    if (find_Pos(id) == Pos.ON_SHORE && firstSceneControl.boat_capicity != 0)
                    {
                        firstSceneControl.On_Boat.Add(id + 6, firstSceneControl.On_Shore_r[id]);
                        firstSceneControl.On_Shore_r.Remove(id);
                        this.name = (id + 6).ToString();
                        this.transform.parent = firstSceneControl.boat.transform;
                        firstSceneControl.boat_capicity--;
                    }
                }


                if (find_Pos(id) == Pos.ON_BOAT)
                {

                    firstSceneControl.On_Shore_r.Add(id - 6, firstSceneControl.On_Boat[id]);
                    firstSceneControl.On_Boat.Remove(id);
                    this.name = (id - 6).ToString();
                    this.transform.parent = null;
                    firstSceneControl.boat_capicity++;
                }
            }
            if (firstSceneControl.b_state == FirstSceneControl.BoatState.STOPLEFT)
            {

                if (find_Pos(id) == Pos.ON_SHORE && firstSceneControl.boat_capicity != 0)
                {
                    if (firstSceneControl.On_Shore_l.ContainsKey(id))
                    {
                        firstSceneControl.On_Boat.Add(id + 6, firstSceneControl.On_Shore_l[id]);
                        firstSceneControl.On_Shore_l.Remove(id);
                        this.name = (id + 6).ToString();
                        this.transform.parent = firstSceneControl.boat.transform;
                        firstSceneControl.boat_capicity--;
                    }

                }

                if (find_Pos(id) == Pos.ON_BOAT)
                {
                    firstSceneControl.On_Shore_l.Add(id - 6, firstSceneControl.On_Boat[id]);
                    firstSceneControl.On_Boat.Remove(id);
                    this.name = (id - 6).ToString();
                    this.transform.parent = null;
                    firstSceneControl.boat_capicity++;
                }
            }


        }
    }    
}


UserGUI.cs

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

public class UserGUI : MonoBehaviour
{
    private IUserAction action;
	// Use this for initialization
	void Start () {
        action = Director.getInstance().currentSceneControl as IUserAction;
	}

    private void OnGUI()
    {
        if (GUI.Button(new Rect(700, 100, 90, 90), "GO") && action.getGameState() == GameState.NOT_ENDED)
        {
            action.MoveBoat();
        }
        if (action.getGameState() == GameState.WIN)
        {
            GUI.Label(new Rect(700, 300, 400, 400), "you win");
            GUI.color = Color.red;
        }
        if ((action.getGameState() == GameState.FAILED)) {
            action.GameOver();
        }
    }

   
}


IUserAction.cs

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

public enum GameState { WIN, FAILED, NOT_ENDED }

public interface IUserAction {
    void MoveBoat();
    void GameOver();
    GameState getGameState();
}


ISceneController.cs

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

public interface ISceneControl  {
    void GenGameObjects();
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值