Unity小游戏-牧师与魔鬼

首先十分感谢学姐的参考博客Unity实战——牧师与魔鬼!!!

相关资源

演示视频
代码仓库

游戏背景

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

Unity组件

河岸、河流、人物模型(牧师、恶魔)、船

规则表

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

MVC模式

在这里插入图片描述

游戏文件组织结构

在这里插入图片描述

  • 分为三个部分
  • Resources中定义了Model
  • Scripts中定义了View和Controller
  • 更具体的文件可以到项目地址中找到

Model

  1. 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>();
        
    }
}

  1. Role.cs:人物模型
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Role 
{
    public GameObject role;//model对应的游戏对象
    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.6f,0.6f, 0.6f);
        role.transform.position = position;
        role.name = "role" + id;
        role.AddComponent<Click>();
        role.AddComponent<BoxCollider>();
    }
}

  1. 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;
    }
}

  1. 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;
    }
}

  1. 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)};
    
}

  1. Click.cs
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();
    }
}

  1. ClickAction.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface ClickAction
{
    void ClickOnObject();
}

Controller

  1. 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--;
                }
            }
        }
    }
}

  1. 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;
    }
}

  1. 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--;
    }
}

  1. Move.cs,MoveControl.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);
        }
    }
}

  1. 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;
    }
}

  1. ISceneController.cs:控制场景变化
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface ISceneController
{
    void LoadResources();
}

  1. IUserAction.cs:控制用户事件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

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

  1. 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() {
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值