3D游戏设计与分析-牧师与魔鬼

3D游戏设计与分析-牧师与魔鬼

目标

​使用unity3D做出一个牧师与魔鬼的游戏,程序需要满足以下要求:

  1. play the game ( http://www.flash-game.net/game/2535/priests-and-devils.html )
  2. 列出游戏中提及的事物(Objects)
  3. 用表格列出玩家动作表(规则表),注意,动作越少越好
  4. 请将游戏中对象做成预制
  5. 在 GenGameObjects 中创建 长方形、正方形、球 及其色彩代表游戏中的对象。
  6. 使用 C# 集合类型 有效组织对象
  7. 整个游戏仅 主摄像机 和 一个 Empty 对象, 其他对象必须代码动态生成!!! 。 整个游戏不许出现 Find 游戏对象, SendMessage 这类突破程序结构的 通讯耦合 语句。 违背本条准则,不给分
  8. 请使用课件架构图编程,不接受非 MVC 结构程序
  9. 注意细节,例如:船未靠岸,牧师与魔鬼上下船运动中,均不能接受用户事件!

列出游戏中提及的事物

名称实现方式
牧师正方体
恶魔球体
河岸长方体
长方体

表格列出玩家动作表

动作条件
开船船上必须有一个人
牧师在左岸上船左岸必须有牧师,船上有空位,船在左岸
牧师在右岸上船右岸必须有牧师,船上有空位,船在右岸
牧师在左岸下船船上有牧师,船在左岸
牧师在右岸下船船上有牧师,船在有岸
恶魔在左岸上船左岸必须有恶魔,船上有空位,船在左岸
恶魔在右岸上船右岸必须有恶魔,船上有空位,船在右岸
恶魔在左岸下船船上有恶魔,船在左岸
恶魔在右岸下船船上有恶魔,船在右岸

具体实现

在Assets中创建Resources文件夹,在Resources中创建Prefabs文件夹,将做好的对象拖入Prefabs中成为预制。在Assets文件下创建Scripts文件用以放置C#文件。

Director

Director类利用了单例模式,第一次调用getInstance()时,因为instance为null,所以instance会保存一个新的Director对象。往后的每次getInstance(),都会获得相同的值。也就是说所有的C#文件都将获得相同的Director对象,从而可以获得一个相同的controller,实现不同类之间的通信。

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

//Director.cs
public class Director : System.Object
{

    private static Director instance;
    public Controller controller;

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

Controller

Controller类实现了IUserActions接口的方法,并通过一个GenGameObject类型的model变量对游戏对象进行操作。Awake()将Controller注入到单实例中。

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

//IUserActions.cs
public interface IUserActions
{
    void priestOn();
    void priestOnEnd();
    void devilOn();
    void devilOnEnd();
    void changeState();
    int Check();
    void priestOff();
    void devilOff();
    void Restart();
}

//Controller.cs
public class Controller : MonoBehaviour, IUserActions
{

    private GenGameObject model;


    private void Awake()
    {
        Director director = Director.getInstance();
        director.controller = this;
    }

    public void setModel(GenGameObject Model)
    {
        model = Model;
    }

    public void priestOn()
    {
        model.priestOn();
    }

    public void devilOn()
    {
        model.devilOn();
    }

    public void changeState()
    {
        model.change_state();
    }

    public void priestOnEnd()
    {
        model.priestOnEnd();
    }

    public void devilOnEnd()
    {
        model.devilOnEnd();
    }

    public int Check()
    {
        return model.Check();
    }

    public void priestOff()
    {
        model.priestOff();
    }

    public void devilOff()
    {
        model.devilOff();
    }

    public void Restart()
    {
        model.Restart();
    }
}

GenGameObject

GenGameObject类定义了一系列变量。其中priests_start保存左岸牧师的游戏对象,priests_end保存右岸牧师的游戏对象,恶魔同理。onBoat用于存储当前船只上物体的数量。boat_state记录船只的状态,boat_state为1时,船在左岸;值为0时,船在右岸。通过Check(),可以判断游戏是否结束,当Check()返回1时,游戏胜利并结束;返回2时,游戏失败并结束;返回3时游戏进行中。具体代码如下。

using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using UnityEngine;

public class GenGameObject : MonoBehaviour
{
    private Director instance;
    int onBoat;
    public int speed;
    int boat_state = 1;
    GameObject[] objectOnBoat = new GameObject[2];
    readonly Vector3 shore_begin = new Vector3(10, 0, 0);
    readonly Vector3 shore_end = new Vector3(-10, 0, 0);
    readonly Vector3 boat_begin = new Vector3(-3, 0, 0);
    readonly Vector3 boat_end = new Vector3(3, 0, 0);
    readonly Vector3 priests_begin = new Vector3(-9f, 2, 0);
    readonly Vector3 priests_last = new Vector3(9f, 2, 0);
    readonly Vector3 devils_begin = new Vector3(-15f, 2, 0);
    readonly Vector3 devils_last = new Vector3(15f, 2, 0);
    readonly Vector3 gap = new Vector3(-1.5f, 0, 0);
    Stack<GameObject> priests_start = new Stack<GameObject>();
    Stack<GameObject> devils_start = new Stack<GameObject>();
    Stack<GameObject> priests_end = new Stack<GameObject>();
    Stack<GameObject> devils_end = new Stack<GameObject>();
    GameObject boat;


    private void Start()
    {
        speed = 10;
        onBoat = 0;
        boat_state = 1;
        instance = Director.getInstance();
        instance.controller.setModel(this);
        Load();
    }

    private void Load()
    {
        Instantiate(Resources.Load("Prefabs/Shore"), shore_begin, Quaternion.identity);
        Instantiate(Resources.Load("Prefabs/Shore"), shore_end, Quaternion.identity);
        boat = Instantiate(Resources.Load("Prefabs/Boat"), boat_begin, Quaternion.identity) as GameObject;
        boat.name = "boat";
        for (int i = 0; i < 3; i++)
        {
            GameObject priest = Instantiate(Resources.Load("Prefabs/Priest"), (priests_begin - gap * i), Quaternion.identity) as GameObject;
            priest.name = "Priest";
            priests_start.Push(priest);
            GameObject devil = Instantiate(Resources.Load("Prefabs/Devil"), (devils_begin - gap * i), Quaternion.identity) as GameObject;
            devil.name = "Devil";
            devils_start.Push(devil);
        }
    }

    public int Check()
    {
        int devilleft, devilright, preleft, preright;
        devilleft = devilright = preleft = preright = 0;
        devilleft += devils_start.Count;
        devilright += devils_end.Count;
        preleft += priests_start.Count;
        preright += priests_end.Count;
        if(boat_state==1 && onBoat>0)
        {
            for(int i=0;i<2;i++)
            {
                if (objectOnBoat[i] != null && objectOnBoat[i].name == "Devil")
                    devilleft += 1;
                else if (objectOnBoat[i] != null && objectOnBoat[i].name == "Priest")
                    preleft += 1;
                
            }
        }
        else if(boat_state==0 && onBoat>0)
        {
            for (int i = 0; i < 2; i++)
            {
                if (objectOnBoat[i]!=null && objectOnBoat[i].name == "Devil")
                    devilright += 1;
                else if (objectOnBoat[i] != null && objectOnBoat[i].name == "Priest")
                    preright += 1;
            }
        }

        if (devils_end.Count == 3 && priests_end.Count == 3)
        {
            return 1;
        }
        if (devilleft>preleft && preleft>0)
        {
           // UnityEngine.Debug.Log(preleft);
            return 2;

        }
        else if(devilright >preright && preright>0)
        {
          //  UnityEngine.Debug.Log(preright);
            return 2;
        }

        return 3;
    }

    private void Update()
    {
        Check();
    }

    public void priestOn()
    {
        if (priests_start.Count == 0)
            return;
        if (onBoat < 2)
        {
            GameObject temp = priests_start.Pop();
            temp.transform.parent = boat.transform;
            if (objectOnBoat[0] == null)
            {
                temp.transform.localPosition = new Vector3(0.3f, 1.5f, 0);
                objectOnBoat[0] = temp;
            }
            else
            {
                temp.transform.localPosition = new Vector3(-0.3f, 1.5f, 0);
                objectOnBoat[1] = temp;
            }
            onBoat++;
        }
        
    }

    public void priestOff()
    {
        for (int i = 0; i < 2; i++)
        {
            if (objectOnBoat[i] != null && objectOnBoat[i].name == "Priest")
            {
                if (boat.transform.position != boat_begin && boat.transform.position != boat_end)
                    return;
                GameObject pri = objectOnBoat[i];
                pri.transform.parent = null;
                if (boat.transform.position == boat_end)
                {
                    pri.transform.position = priests_last + gap * priests_end.Count;
                    priests_end.Push(pri);
                }
                else if (boat.transform.position == boat_begin)
                {
                    pri.transform.position = priests_begin - gap * priests_start.Count;
                    priests_start.Push(pri);
                }
                objectOnBoat[i] = null;
                onBoat--;
                return;
            }
        }
    }

    public void devilOn()
    {
        if (devils_start.Count == 0)
            return;
        if (onBoat < 2)
        {
            GameObject temp = devils_start.Pop();
            temp.transform.parent = boat.transform;
            if (objectOnBoat[0]==null)
            {
                temp.transform.localPosition = new Vector3(0.3f, 1.5f, 0);
                objectOnBoat[0] = temp;
            }
            else
            {
                temp.transform.localPosition = new Vector3(-0.3f, 1.5f, 0);
                objectOnBoat[1] = temp;
            }
            onBoat++;
           // UnityEngine.Debug.Log(onBoat);
        }
    }

    public void devilOff()
    {
        
        for (int i = 0; i < 2; i++)
        {
            if (objectOnBoat[i] != null && objectOnBoat[i].name == "Devil")
            {
                
                if (boat.transform.position != boat_begin && boat.transform.position != boat_end)
                    return;
                GameObject pri = objectOnBoat[i];
                pri.transform.parent = null;
                if (boat_state==0)
                {
                    pri.transform.position = devils_last + gap * devils_end.Count;
                    devils_end.Push(pri);
            //        UnityEngine.Debug.Log(devils_end.Count);
                }
                else if (boat_state == 1)
                {
                    pri.transform.position = devils_begin - gap * devils_start.Count;
                    devils_start.Push(pri);
                }
                objectOnBoat[i] = null;
                onBoat--;
                return;
            }
        }
    }

    public void Restart()
    {
        int num = priests_end.Count;
        for (int i = 0; i < num; i++)
        {
            GameObject temp = priests_end.Pop();
            temp.transform.position = priests_begin - gap * priests_start.Count;
            priests_start.Push(temp);
        }
        num = devils_end.Count;
        for (int i = 0; i < num; i++)
        {
            GameObject temp = devils_end.Pop();
            temp.transform.position = devils_begin - gap * devils_start.Count;
            devils_start.Push(temp);
        }
        if(onBoat>0)
        for (int i = 0; i < 2; i++)
        {
            if (objectOnBoat[i] == null)
            {
                    continue;
            }
            GameObject temp = objectOnBoat[i];
            temp.transform.parent = null;
            if (temp.name == "Priest")
            {
                temp.transform.position = priests_begin - gap * priests_start.Count;
                priests_start.Push(temp);
            }
            else
            {
                temp.transform.position = devils_begin - gap * devils_start.Count;
                priests_start.Push(temp);
            }
            objectOnBoat[i] = null;
        }
        onBoat = 0;
        boat.transform.position = boat_begin;
        boat_state = 1;
    }

    public void priestOnEnd()
    {
        if (priests_end.Count == 0)
            return;
        if (onBoat < 2)
        {
            GameObject temp = priests_end.Pop();
            temp.transform.parent = boat.transform;
            if (objectOnBoat[0] == null)
            {
                temp.transform.localPosition = new Vector3(0.3f, 1.5f, 0);
                objectOnBoat[0] = temp;
            }
            else
            {
                temp.transform.localPosition = new Vector3(-0.3f, 1.5f, 0);
                objectOnBoat[1] = temp;
            }
            onBoat++;
        }
    }

    public void devilOnEnd()
    {
        if (devils_end.Count == 0)
            return;
        if (onBoat < 2)
        {
            GameObject temp = devils_end.Pop();
            temp.transform.parent = boat.transform;
            if (objectOnBoat[0] == null)
            {
                temp.transform.localPosition = new Vector3(0.3f, 1.5f, 0);
                objectOnBoat[0] = temp;
            }
            else
            {
                temp.transform.localPosition = new Vector3(-0.3f, 1.5f, 0);
                objectOnBoat[1] = temp;
            }
            onBoat++;
        }
    }

    public void boatMove()
    {
        if (onBoat != 0)
        {
            if (boat_state == 0)
                boat.transform.position = boat_end;
            else
                boat.transform.position = boat_begin;

        }
       
    }

    public void change_state()
    {
        if (boat_state == 0)
            boat_state = 1;
        else
            boat_state = 0;
        boatMove();
    }

}

UI

为界面添加按钮,并调用按钮对应的接口函数

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

public class UserInterface : MonoBehaviour
{
    Director instance;
    IUserActions action;

    void Start()
    {
        instance = Director.getInstance();
        action = instance.controller as IUserActions;
    }

    private void OnGUI()
    {
        GUIStyle fontStyle = new GUIStyle();
        fontStyle.fontSize = 40;
        fontStyle.normal.textColor = new Color(255, 255, 255);

        if (action.Check() == 1)
        {
            GUI.Label(new Rect(440, 200, 100, 100), "Win", fontStyle);
            if (GUI.Button(new Rect(435, 360, 80, 50), "Restart"))
            {
                action.Restart();
            }
        }
        if (action.Check() == 2)
        {
            GUI.Label(new Rect(390, 200, 100, 100), "GameOver", fontStyle);
            if (GUI.Button(new Rect(435, 360, 80, 50), "Restart"))
            {
                action.Restart();
            }
        }
        if (GUI.Button(new Rect(130, 0, 50, 50), "On"))
        {
            action.devilOn();
        }
        if (GUI.Button(new Rect(270, 0, 50, 50), "On"))
        {
            action.priestOn();
        }
        if (GUI.Button(new Rect(600, 0, 50, 50), "On"))
        {
            action.priestOnEnd();
        }
        if (GUI.Button(new Rect(750, 0, 50, 50), "On"))
        {
            action.devilOnEnd();
        }
        if (GUI.Button(new Rect(450, 0, 50, 50), "Move"))
        {
            action.changeState();
        }
        if (GUI.Button(new Rect(450, 50, 50, 50), "POff"))
        {
            action.priestOff();
        }
        if (GUI.Button(new Rect(450, 100, 50, 50), "DOff"))
        {
            action.devilOff();
        }
    }
}

代码与素材

gitee仓库.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值