Unity游戏制作-牧师与魔鬼MVC版

游戏演示

你家牧师会这样?

游戏介绍

本游戏为牧师与魔鬼过河游戏。

需要将牧师从左岸全部运送到右岸,运送过程中不能出现同一岸(包括靠岸的船)魔鬼的数量超过牧师的数量。

游戏设计过程

包含模型介绍

游戏包含以下预设

玩家交互表格

玩家行为执行条件执行结果
点击船船靠岸并且船上有角色船移动到另一岸
点击角色

角色在船上:船靠岸且没有其他角色移动

角色在岸上:船在同一岸且船上未满两角色

角色在船上:角色移动至岸上

角色在岸上:角色移动到船上

点击Restart按钮任何时候可执行资源重置,游戏重新开始

注:以上前两条行为均有游戏未结束的前提条件(游戏失败或胜利视为游戏结束)

MVC架构代码

MVC架构图

 代码实现(部分)

Model部分

Role

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

public class Role{
    public GameObject role;
    public bool isPriest;
    public bool inBoat;
    public bool onRight;
    public int id;

    public Role(Vector3 position,bool isPriest,int id){
        this.isPriest = isPriest;
        this.id = id;
        onRight = false;
        inBoat = false;
        Debug.Log("Prefabs/"+(isPriest ? "Priest" : "Devil"));
        role = GameObject.Instantiate(Resources.Load("Prefabs/"+(isPriest ? "Priest" : "Devil"),typeof(GameObject))) as GameObject;
        role.transform.localScale = new Vector3(0.77019f,1,0.6349832f);
        role.name = "role"+id;
        role.AddComponent<Click>();
        role.AddComponent<BoxCollider>();
    }
}

Boat

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

public class Boat
{
    public GameObject boat;
    public bool isRight;
    public Role[] roles;
    public int priestCount,devilCount;

    // 船类初始化
    public Boat(Vector3 position){
        boat = GameObject.Instantiate(Resources.Load("Prefabs/Boat",typeof(GameObject))) as GameObject;
        boat.name = "boat";
        boat.transform.position = position;
        boat.transform.localScale = new Vector3(2.8f,0.4f,2);

        roles = new Role[2];
        isRight = false;
        priestCount = devilCount = 0;

        boat.AddComponent<BoxCollider>();
        boat.AddComponent<Click>();
    }
     
}

Land

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

public class Land{
    public GameObject land;
    public int priestCount;
    public int devilCount;
    public Land(Vector3 position){
        land = GameObject.Instantiate(Resources.Load("Prefabs/Land",typeof(GameObject))) as GameObject;
        land.name = "Land";
        land.transform.position = position;
        priestCount = 0;
        devilCount = 0;
    }
}

Position

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

public class Position{
    public static Vector3 leftLand = new Vector3(-6.99f,-0.77f,-2.3f);
    public static Vector3 rightLand = new Vector3(4.52f,-0.77f,-2.3f);
    public static Vector3 river = new Vector3(-1.2f,-2.6f,-2.77f);

    //船左右岸位置
    public static Vector3 leftBoat = new Vector3(-2.3f,-0.55f,-2.39f);
    public static Vector3 rightBoat = new Vector3(-0.3f,-0.55f,-2.39f);

    //岸上角色位置
    public static Vector3[] role_shore = new Vector3[]{
        new Vector3(0.4f,0.77f,0),
        new Vector3(0.25f,0.77f,0),
        new Vector3(0.1f,0.77f,0),
        new Vector3(-0.05f,0.77f,0),
        new Vector3(-0.2f,0.77f,0),
        new Vector3(-0.35f,0.77f,0)
    };

    //船上的位置
    public static Vector3[] role_boat = new Vector3[]{
        new Vector3(0.2f,2.5f,0),
        new Vector3(-0.2f,2.5f,0),
    };
}
 View部分

UserGUI

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

public class UserGUI : MonoBehaviour
{
    IUserAction userAction;
    JudgeController judgeController;
    public string gameMessage ;
    GUIStyle style, bigstyle;
    // Start is called before the first frame update
    void Start()
    {
        userAction = SSDirector.GetInstance().CurrentSceneController as IUserAction;

        style = new GUIStyle();
        style.normal.textColor = Color.white;
        style.fontSize = 30;

        bigstyle = new GUIStyle();
        bigstyle.normal.textColor = Color.white;
        bigstyle.fontSize = 50;

        
        
    }

    // Update is called once per frame
    void OnGUI() {
        userAction.Check();
        GUI.Label(new Rect(230, Screen.height * 0.1f, 700, 200), "Priests and Devils", bigstyle);
        GUI.Label(new Rect(350, 100, 50, 200), gameMessage, style);
        if(GUI.Button(new Rect(0,0,100,40),"Restart")){
            userAction.reStart();
        }
    }
}
Control部分

RoleControl

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

public class RoleControl : ClickAction
{
    Role role;
    IUserAction userAction;

    // 实现ClickAction接口
    public void ClickOnObject() {
        // 点击role,role移动
        userAction.MoveRole(role);
    }

    public RoleControl(){
        userAction = SSDirector.GetInstance().CurrentSceneController as IUserAction;
    }

    public void CreateRole(Vector3 position, bool isPriest, int id){
        if(role != null){
            // role已经存在
            Object.DestroyImmediate(role.role);
        }
        role = new Role(position, isPriest, id);
        role.role.GetComponent<Click>().setClickAction(this);

    }

    public Role GetRoleModel(){
        return role;
    }

    public void Delect(){
        Object.DestroyImmediate(role.role);
    }
}

 BoatControl

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

// 控制Boat的运动
public class BoatControl : ClickAction
{
    Boat boatModel;
    IUserAction userAction;
    
    // 实现ClickAction接口
    public void ClickOnObject() {
        // 点击船,船移动
        // 通过userAction中的方法实现移动
        // 前置条件:船上有role
        if(boatModel.roles[0] != null || boatModel.roles[1] != null){
            userAction.MoveBoat();
        }
    }

    public BoatControl() {
        userAction = SSDirector.GetInstance().CurrentSceneController as IUserAction;
    }

    public void CreateBoat(Vector3 position){
        if(boatModel != null){
            // boat已经存在
            Object.DestroyImmediate(boatModel.boat);
        }

        boatModel = new Boat(position);
        boatModel.boat.GetComponent<Click>().setClickAction(this);
    }

    public Boat GetBoatModel(){
        return boatModel;
    }

    // 角色从岸上移动到船上
    public Vector3 AddRole(Role r){
        // 前置条件:船没有满员
        // 如果能上船,角色应到的位置就是船所在的位置
        // 如果不能上船,角色应到的位置就是原来的位置
        int emptySeat = -1;
        if(boatModel.roles[0] == null)  emptySeat = 0;
        else if (boatModel.roles[1] == null)  emptySeat = 1;

        // 船上无空位
        if(emptySeat == -1){
            return r.role.transform.localPosition;
        }
        else{
            boatModel.roles[emptySeat] = r;     // 装到boat上
            r.inBoat = true;
            r.role.transform.parent = boatModel.boat.transform;   // 将role挂在boat下
            if(r.isPriest){
                boatModel.priestCount++;
            }
            else{
                boatModel.devilCount++;
            }
            return Position.role_boat[emptySeat];

        }

    }
    
    // 角色从船上移动到岸上
    public void RemoveRole(Role r){
        for(int i = 0; i < 2; i++){
            if(boatModel.roles[i] == r){
                boatModel.roles[i] = null;
                if(r.isPriest){
                    boatModel.priestCount--;
                }
                else{
                    boatModel.devilCount--;
                }
            }
        }
    }

    public void Delect(){
        Object.DestroyImmediate(boatModel.boat);
    }
}

FirstController

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

public class FirstController : MonoBehaviour, ISceneController, IUserAction {
    // JudgeController judgeController;
    public LandControl leftLandController, rightLandController;
    River river;
    public BoatControl boatController;
    RoleControl[] roleControllers;
    MoveControl moveController;
    public bool isRunning;

    public void LoadResources() {
        // judgeController = new JudgeController();
        //role
        roleControllers = new RoleControl[6];
        for (int i = 0; i < 6; ++i) {
            roleControllers[i] = new RoleControl();
            roleControllers[i].CreateRole(Position.role_shore[i], i < 3 ? true : false, i);
        }

        //land
        leftLandController = new LandControl();
        leftLandController.CreateLand(Position.leftLand);
        leftLandController.GetLand().land.name = "left_land";
        rightLandController = new LandControl();
        rightLandController.CreateLand(Position.rightLand);
        rightLandController.GetLand().land.name = "right_land";

        //将人物添加并定位至左岸  
        foreach (RoleControl roleController in roleControllers)
        {
            roleController.GetRoleModel().role.transform.localPosition = leftLandController.AddRole(roleController.GetRoleModel());
        }
        //boat
        boatController = new BoatControl();
        boatController.CreateBoat(Position.leftBoat);

        //river
        river = new River(Position.river);

        //move
        moveController = new MoveControl();

        isRunning = true;


    }

    public void MoveBoat() {
        if (isRunning == false || moveController.GetIsMoving()) return;
        if (boatController.GetBoatModel().isRight) {
            moveController.SetMove(Position.leftBoat, boatController.GetBoatModel().boat,false);
        }
        else {
            moveController.SetMove(Position.rightBoat, boatController.GetBoatModel().boat,false);
        }
        boatController.GetBoatModel().isRight = !boatController.GetBoatModel().isRight;
    }

    public void MoveRole(Role roleModel) {
        if (isRunning == false || moveController.GetIsMoving()) return;
        if (roleModel.inBoat) {
            if (boatController.GetBoatModel().isRight) {
                moveController.SetMove(rightLandController.AddRole(roleModel), roleModel.role,true);
            }
            else {
                moveController.SetMove(leftLandController.AddRole(roleModel), roleModel.role,true);
            }
            roleModel.onRight = boatController.GetBoatModel().isRight;
            boatController.RemoveRole(roleModel);
        }
        else {
            if (boatController.GetBoatModel().isRight == roleModel.onRight) {
                if (roleModel.onRight) {
                    rightLandController.RemoveRole(roleModel);
                }
                else {
                    leftLandController.RemoveRole(roleModel);
                }
                moveController.SetMove(boatController.AddRole(roleModel), roleModel.role,false);
            }
        }
    }

    public void Check() {
        
    }

    public void reStart(){
        Destroy(GetComponent<JudgeController>());
        foreach (RoleControl roleController in roleControllers)
        {
            roleController.Delect();
        }
        boatController.Delect();
    //     for (int i = 0; i < 6; ++i) {
    //         roleControllers[i] = new RoleControl();
    //         roleControllers[i].CreateRole(Position.role_shore[i], i < 3 ? true : false, i);
    //     }
    //     boatController = new BoatControl();
    //     boatController.CreateBoat(Position.leftBoat);
    //    foreach (RoleControl roleController in roleControllers)
    //     {
    //         roleController.GetRoleModel().role.transform.localPosition = leftLandController.AddRole(roleController.GetRoleModel());
    //     }
    //     boatController.CreateBoat(Position.leftBoat);
        LoadResources();
        this.gameObject.AddComponent<JudgeController>();
        this.gameObject.GetComponent<UserGUI>().gameMessage = "";
    }


    void Awake() {
        SSDirector.GetInstance().CurrentSceneController = this;
        LoadResources();
        this.gameObject.AddComponent<UserGUI>();
        this.gameObject.AddComponent<JudgeController>();
    }

    void Update() {
    }
}

Move

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

public class Move : MonoBehaviour
{
    public bool canMove = false;
    public float speed = 5;
    public Vector3 destination;
    public Vector3 mid_destination;

    void Update(){
        if (transform.localPosition == destination) {
            canMove = false;
            return;
        }
        canMove = true;
        if (transform.localPosition.x != destination.x && transform
        .localPosition.y != destination.y) {
            transform.localPosition = Vector3.MoveTowards(transform.localPosition, mid_destination, speed * Time.deltaTime);
        }
        else {
            transform.localPosition = Vector3.MoveTowards(transform.localPosition, destination, speed * Time.deltaTime);
        }
    }
}

MoveControl

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

public class MoveControl
{
    GameObject moveObj;

    public bool GetIsMoving() {
        return (moveObj != null && moveObj.GetComponent<Move>().canMove == true);
    }

    public void SetMove(Vector3 destination, GameObject moveObj,bool inBoat)
    {
        Move test;
        this.moveObj = moveObj;
        if (!moveObj.TryGetComponent<Move>(out test)) {
            moveObj.AddComponent<Move>();
        }

        this.moveObj.GetComponent<Move>().destination = destination;
        if(inBoat){
            this.moveObj.GetComponent<Move>().mid_destination = new Vector3(this.moveObj.transform.localPosition.x, destination.y, destination.z);

        }
        else{
            this.moveObj.GetComponent<Move>().mid_destination = new Vector3(destination.x, this.moveObj.transform.localPosition.y, destination.z);
        }
    }
}

后记

本项目参考小原味鹦鹉的博客

在其基础上进行了修改和改进,同时进一步实现了裁判类。

完整代码:gitee项目地址

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值