Unity实战——牧师与魔鬼

Unity实战——牧师与魔鬼

项目源码

最终效果

牧师与魔鬼游戏效果



背景描述

牧师与魔鬼是一款益智游戏,您将帮助牧师与魔鬼在规定时间内过河。河边有三个牧师和三个魔鬼。他们都想去这条河的对岸,但只有一艘船,这艘船每次只能载两个人。而且必须有一个人把船从一边开到另一边。在flash游戏中,您可以单击它们移动它们,然后单击go按钮将船移动到另一个方向。如果神父的人数超过了河两边的魔鬼,他们就会被杀死,游戏就结束了。你可以用很多方法来尝试。让所有牧师都活着!祝你好运!

Objects

河岸(×2),河,船,牧师,魔鬼

规则表

动作 条件 事件
点击人物 游戏未结束&船未满&船没有到对岸 上船
点击船 游戏未结束&船上至少有一个任务 船移动到对岸

MVC设计模式

在这里插入图片描述

简单来说,就是将项目分成Model、Controller、View三个层面

  • Model. 存储数据对象
  • Controller. 接受用户事件,在这里主要是鼠标点击
  • View. 显示模型,转发人机交互事件

开始!

设置游戏对象

根据前面的分析,做几个游戏对象

魔鬼和牧师:
在这里插入图片描述

扫描二维码关注公众号,回复: 15066771 查看本文章

小河:

在这里插入图片描述

陆地:

在这里插入图片描述

船:

在这里插入图片描述

将他们拖到Assets中成为预制

Model

在Asset中创建Models文件夹,存放model的脚本

Boat.cs:船模型

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

public class Boat
{
    public GameObject boat;
    public Role[] roles;   // 船上的角色
    public bool isRight;   // 判断船是否在右侧
    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>();
        
    }
}

Role.cs:角色模型,包括牧师和魔鬼

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;
        role = GameObject.Instantiate(Resources.Load("Prefabs/" + (isPriest ? "Priest" : "Devil"), typeof(GameObject))) as GameObject;
        role.transform.localScale = new Vector3(0.7f,0.7f,0.7f);
        role.transform.position = position;
        role.name = "role" + id;
        role.AddComponent<Click>();
        role.AddComponent<BoxCollider>();
    }
}

River.cs:河流

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

public class River
{
    public GameObject river;

    public River(Vector3 position){
        river = GameObject.Instantiate(Resources.Load("Prefabs/River", typeof(GameObject))) as GameObject;
        river.name = "river";
        river.transform.position = position;
    }
}

Land.cs:陆地

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.cs:为了移动更加方便,设置一个类存在各种对象的位置

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

public class Position
{
    public static Vector3 left_land = new Vector3(-8,-3,0);
    public static Vector3 right_land = new Vector3(8,-3,0);
    public static Vector3 river = new Vector3(0,-4,0);

    // 船在左岸的位置
    public static Vector3 left_boat = new Vector3(-2.3f,-2.3f,-0.4f);

    // 船在右岸的位置
    public static Vector3 right_boat = new Vector3(2.4f, -2.3f, -0.4f);

    // 岸上的角色应该站的位置
    public static Vector3[] role_shore = new Vector3[] {new Vector3(0.4f,0.77f,0), new Vector3(0.2f,0.77f,0), new Vector3(0,0.77f,0), new Vector3(-0.2f,0.77f,0), new Vector3(-0.4f,0.77f,0), new Vector3(-0.6f,0.77f,0)};
    
    // 船上的两个位置
    public static Vector3[] role_boat = new Vector3[] {new Vector3(0.2f,3,0), new Vector3(-0.2f,3,0)};
    
}

Click.csClickAction.cs

Click 继承了ClickAction 接口

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

public class Click : MonoBehaviour
{
    ClickAction clickAction;
    public void setClickAction(ClickAction clickAction) {
        this.clickAction = clickAction;
    }
    void OnMouseDown() {
        clickAction.ClickOnObject();
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface ClickAction
{
    void ClickOnObject();
}

Controller

BoatControl.cs:控制船只动作

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 GetBoat(){
        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--;
                }
            }
        }
    }
}

RoleControl.cs:控制角色运动

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 GetRole(){
        return role;
    }
}

LandControl.cs

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

public class LandControl
{
    Land land;
    public void CreateLand(Vector3 position) {
        if (land == null) {
            land = new Land(position);
        }
    }

    public Land GetShore() {
        return land;
    }

    // 将角色加到岸上
    public Vector3 AddRole(Role r){
        r.role.transform.parent = land.land.transform;
        r.inBoat = false;
        if(r.isPriest)  land.priestCount++;
        else  land.devilCount++;

        return Position.role_shore[r.id];
    }

    // 将角色从岸上移除
    public void RemoveRole(Role r){
        if (r.isPriest) land.priestCount--;
        else land.devilCount--;
    }
}

Move.csMoveControl.cs 控制移动

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);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MoveControl
{
    GameObject moveObj;
    // Start is called before the first frame update

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

    // Update is called once per frame
    public void SetMove(Vector3 destination, GameObject moveObj)
    {
        Move test;
        this.moveObj = moveObj;
        if (!moveObj.TryGetComponent<Move>(out test)) {
            moveObj.AddComponent<Move>();
        }

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

SSDirector.cs:导演

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

public class SSDirector : System.Object
{
    static SSDirector _instance;
    public ISceneController CurrentSceneController {get; set;}
    public static SSDirector GetInstance() {
        if (_instance == null) {
            _instance = new SSDirector();
        }
        return _instance;
    }
}

ISceneController.cs:控制场景变化

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

public interface ISceneController
{
    void LoadResources();
}

IUserAction.cs:控制用户事件

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

public interface IUserAction
{
    void MoveBoat();
    void MoveRole(Role role);                    
    void Check();
}

FirstController.cs:统筹整一个游戏的控制器

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

public class FirstController : MonoBehaviour, ISceneController, IUserAction {
    LandControl leftLandController, rightLandController;
    River river;
    BoatControl boatController;
    RoleControl[] roleControllers;
    MoveCtrl moveController;
    bool isRunning;
    float time;

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

        //land
        leftLandController = new LandControl();
        leftLandController.CreateLand(Position.left_land);
        leftLandController.GetLand().land.name = "left_land";
        rightLandController = new LandControl();
        rightLandController.CreateLand(Position.right_land);
        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.left_boat);

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

        //move
        moveController = new MoveCtrl();

        isRunning = true;
        time = 60;


    }

    public void MoveBoat() {
        if (isRunning == false || moveController.GetIsMoving()) return;
        if (boatController.GetBoatModel().isRight) {
            moveController.SetMove(Position.left_boat, boatController.GetBoatModel().boat);
        }
        else {
            moveController.SetMove(Position.right_boat, boatController.GetBoatModel().boat);
        }
        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);
            }
            else {
                moveController.SetMove(leftLandController.AddRole(roleModel), roleModel.role);
            }
            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);
            }
        }
    }

    public void Check() {
        if (isRunning == false) return;
        this.gameObject.GetComponent<UserGUI>().gameMessage = "";
        if (rightLandController.GetLand().priestCount == 3) {
            this.gameObject.GetComponent<UserGUI>().gameMessage = "You Win!";
            isRunning = false;
        }
        else {
            int leftPriestCount, rightPriestCount, leftDevilCount, rightDevilCount;
            leftPriestCount = leftLandController.GetLand().priestCount + (boatController.GetBoatModel().isRight ? 0 : boatController.GetBoatModel().priestCount);
            rightPriestCount = rightLandController.GetLand().priestCount + (boatController.GetBoatModel().isRight ? boatController.GetBoatModel().priestCount : 0);
            leftDevilCount = leftLandController.GetLand().devilCount + (boatController.GetBoatModel().isRight ? 0 : boatController.GetBoatModel().devilCount);
            rightDevilCount = rightLandController.GetLand().devilCount + (boatController.GetBoatModel().isRight ? boatController.GetBoatModel().devilCount : 0);
            if (leftPriestCount != 0 && leftPriestCount < leftDevilCount || rightPriestCount != 0 && rightPriestCount < rightDevilCount) {
                this.gameObject.GetComponent<UserGUI>().gameMessage = "Game Over!";
                isRunning = false;
            }
        }
    }

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

    void Update() {
    }
}

View

UserGUI.cs

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

public class UserGUI : MonoBehaviour
{
    IUserAction userAction;
    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(160, Screen.height * 0.1f, 50, 200), "Preists and Devils", bigstyle);
        GUI.Label(new Rect(250, 100, 50, 200), gameMessage, style);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_51930942/article/details/127478770
今日推荐