unity3D小游戏-牧师与魔鬼MVC版

一、介绍

帮助三个牧师与三个魔鬼过河。过程中,河的两岸分别要满足:牧师数量不能少于魔鬼的数量。

二、实现

1、框架

Model:

(1)包含船、陆地、角色等游戏中涉及到的模型(物体、物件),

它们的基础类型都是GameObject,区别它们的是各自使用的预制件、初始化的位置等等

这些模型仅仅定义了其本身的属性(位置等),并不提供运动等操作函数。

(2)包含click、move两个“特殊”的模型:

click的点击事件(函数)触发的是Contorller中的IObjectController定义的点击函数;

同时船、陆地、角色等模型在定义时被赋予“click”(可点击?)

move:用于实现模型的移动(判断是否在移动、Update函数更新位置)

同样,这两个模型并没有自发的功能实现,更类似于可供其他类使用的“工具”。

View:

用户(玩家)操作的按钮等界面

Controller:

(1)Controllers文件夹包含各种控制器。FirstContorller是“主脑”,由它生成并管理其他控制器的实例(如船、陆地、角色等的控制器)

(2)船、陆地、角色等控制器定义了各种数据(位置、座位数等辅助数据)以及各种功能函数(创建物体、如何入座、点击事件等)

(3)这些物件都有一些共同的动作或功能函数,于是创建一些接口来统一定义:

    IObjectController定义了物体的点击、生成、重置等函数

    IUserAction定义了物体动作、场景状态等函数(物体动作、场景状态(重新开始等)都是由玩家来操控,所以叫IUserAction)    

(4)ISceneController定义了场景初始化函数

    (3)(4)这些controller只是对函数的“声明”(类似于基类,由firstcontroller继承?),具体的函数实现由firstcontroller完成。

只有当FirstController创建了船等其他控制器、调用其他控制器的“创建物件”函数,游戏实体才被创建出来。同样,只有当FirstController调用了其他控制器的功能函数,游戏实体才能实现运动。

玩家行为:

玩家动作效果备注
点击牧师或魔鬼牧师或魔鬼:离岸上船、下船上岸需要点中对象
点击船体船从一岸移动到另一岸             1<=船上人数<=2

UML图:

2、实现:

Scripts脚本文件夹中分成三部分:Controllers、Models、Views,分别实现上述对应的代码。

在这里我参照了这位博主的博客https://www.cnblogs.com/LC32/p/15420714.html(或者说,我只是在他的代码、框架上做小修改,在此特别感谢)

3、游戏逻辑介绍

角色分为牧师与魔鬼

船上只可乘坐一个或两个角色(对应的,在boatcontroller定义座位数),无人时不可移动。

boatController(部分):

    ......

    public int[] seat; // 座位数组,存储船上的乘客座位号
    public Boat boatModel; // 船的模型对象
    public int seatNum=2; //船的座位   //添加这个是为了方便控制船的位置数
                                      //在下面的初始化、循环中统一用seatNum
    public BoatController()
    {
        userAction = SSDirector.GetInstance().CurrentSceneController as         IUserAction; // 获取当前场景的用户操作接口
        seat = new int[seatNum]; // 初始化座位数组
        Reset(); // 重置船的状态
    }
    ......

点击岸上、船上的角色,对应角色上船、下船。点击船体,船左右移动。船体或角色移动过程中,不响应其他点击事件。

角色上岸(回到左岸或上到右岸),则回到岸上一个空位置上(对应的,landconcroller定义位置等参数)

角色在左岸、右岸、船上转移,对应的rolecontroller定义角色位置等参数

最后,在游戏的适当时机(船载着角色移动时、角色上到右岸时),执行“check”,检查游戏状态:是否成功或者失败(所有角色到达右岸则为成功;存在某一岸上的魔鬼数量>牧师数量,则游戏失败)

firstController:

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

public class FirstController : MonoBehaviour, ISceneController, IUserAction
{
    public static int LEFTLAND = 0;
    public static int RIGHTLAND = 1;
    public static int BOAT = 2;

    public static int PRIEST = 0;
    public static int DEVIL = 1;

    public static int PLAYING = 0;
    public static int WIN = 1;
    public static int FAILED = 2;

    BoatController BoatCtrl;
    RoleController[] RoleCtrl = new RoleController[6];
    LandController[] LandCtrl = new LandController[2];
    MoveController MoveCtrl;

    int[] rolesID = new int[6]{0,1,2,3,4,5};
    int gameState;

    void Awake(){
        SSDirector director = SSDirector.GetInstance();
        director.CurrentSceneController = this;
        director.CurrentSceneController.Initialize();
    }

    public void Initialize(){
        //如果有,则释放原有的GameObject
        for(int i = 0; i < 6; i++){
            if(RoleCtrl[i] != null){
                Destroy(RoleCtrl[i].GetModelGameObject());
            }
        }
        for(int i = 0; i < 2; i++){
            if(LandCtrl[i] != null){
                Destroy(LandCtrl[i].GetModelGameObject());
            }
        }
        if(BoatCtrl != null){
            Destroy(BoatCtrl.GetModelGameObject());
        }
        // 加载控制器和模型
        BoatCtrl = new BoatController();
        BoatCtrl.CreateModel();

        for(int i = 0; i < 6; i++){
            int roleType = (i < 3) ? PRIEST : DEVIL;
            RoleCtrl[i] = new RoleController(roleType, rolesID[i]);
            RoleCtrl[i].CreateModel();
        }
        LandCtrl[0] = new LandController(LEFTLAND, rolesID);
        LandCtrl[1] = new LandController(RIGHTLAND, rolesID);
        LandCtrl[0].CreateModel();
        LandCtrl[1].CreateModel();
        MoveCtrl = new MoveController();
        //开始游戏
        gameState = PLAYING;
    }

    //将角色的ID转换成数组的下标
    int IDToNumber(int ID){
        for(int i = 0; i < 6; i++){
            if(rolesID[i] == ID){
                return i;
            }
        }
        return -1;
    }

    //点击船时执行
    public void MoveBoat(){
        if(gameState != PLAYING || MoveCtrl.IsMoving() || BoatCtrl.isEmpty()) return;
        CheckAndSetGameState();
        if(BoatCtrl.onLeftside){
            MoveCtrl.SetMove(BoatCtrl.GetModelGameObject(), Position.boatRightPos);
            for(int i = 0; i < BoatCtrl.seatNum; i++){
                if(BoatCtrl.seat[i] != -1){
                    RoleController r = RoleCtrl[IDToNumber(BoatCtrl.seat[i])];
                    MoveCtrl.SetMove(r.GetModelGameObject(), Position.seatRightPos[i]);
                }
            }
        }
        else{
            MoveCtrl.SetMove(BoatCtrl.GetModelGameObject(), Position.boatLeftPos);
            for(int i = 0; i < BoatCtrl.seatNum; i++){
                if(BoatCtrl.seat[i] != -1){
                    RoleController r = RoleCtrl[IDToNumber(BoatCtrl.seat[i])];
                    MoveCtrl.SetMove(r.GetModelGameObject(), Position.seatLeftPos[i]);
                }
            } 
        }
        BoatCtrl.onLeftside = !BoatCtrl.onLeftside;
    }

    //点击角色时执行
    public void MoveRole(int id){
        int num = IDToNumber(id);
        if(gameState != PLAYING || MoveCtrl.IsMoving()) return;
        
        int seat;
        switch(RoleCtrl[num].roleState){
            case 0: // LEFTLAND
                if(!BoatCtrl.onLeftside || (BoatCtrl.getEmptySeat() == -1)) return;//增加判断getEmptySeat :
                LandCtrl[0].LeaveLand(id);                                         //如果上不了船,就直接返回,而
                seat = BoatCtrl.embark(id);                                        //不用改动role、land、boat的位置参数
                RoleCtrl[num].GoTo(BOAT);
                if(seat == -1) return;   //增加判断getEmptySeat后,这句应该可以略去
                MoveCtrl.SetMove(RoleCtrl[num].GetModelGameObject(), Position.seatLeftPos[seat]);
                break;
            case 1: // RIGHTLAND
                if(BoatCtrl.onLeftside || (BoatCtrl.getEmptySeat() == -1)) return;//同上
                LandCtrl[1].LeaveLand(id);
                seat = BoatCtrl.embark(id);
                RoleCtrl[num].GoTo(BOAT);
                if(seat == -1) return;
                MoveCtrl.SetMove(RoleCtrl[num].GetModelGameObject(), Position.seatRightPos[seat]);
                break;
            case 2: //BOAT
                if(BoatCtrl.onLeftside){
                    seat = LandCtrl[0].getEmptySeat();
                    BoatCtrl.disembark(id);
                    LandCtrl[0].GoOnLand(id);
                    RoleCtrl[num].GoTo(LEFTLAND);
                    MoveCtrl.SetMove(RoleCtrl[num].GetModelGameObject(), Position.roleLeftPos[seat]);
                }
                else{
                    
                    UnityEngine.Debug.Log("mid_d");
                    seat = LandCtrl[1].getEmptySeat();
                    BoatCtrl.disembark(id);
                    LandCtrl[1].GoOnLand(id);
                    RoleCtrl[num].GoTo(RIGHTLAND);
                    CheckAndSetGameState();//新添加一个在这里,在最后一个角色上右岸之后判定成功
                    MoveCtrl.SetMove(RoleCtrl[num].GetModelGameObject(), Position.roleRightPos[seat]);
                }
                break;
            default: break;
        }
    }

    //判断游戏状态
    public void CheckAndSetGameState(){
        if(gameState != PLAYING) return;
        //判断是否失败
        int[,] rolePos = new int[2, 3]{{0, 0, 0}, {0, 0, 0}};
        foreach(RoleController r in RoleCtrl){
            rolePos[r.roleType, r.roleState]++;  //roletype: 0天使、1魔鬼
        }                                        //rolestate:0左岸、1右岸、2船上
        if((rolePos[0,0]>0 && rolePos[0,0]<rolePos[1,0]) ||   //左岸存在天使 && 左岸的天使数量少于左岸魔鬼的数量
           (rolePos[0,1]>0 && rolePos[0,1]<rolePos[1,1]) ||   //右岸存在天使 && 右岸的天使数量少于右岸魔鬼的数量
           (rolePos[0,2]>0 && rolePos[0,2] < rolePos[1,2])){  //船上最多只能承载两个角色时,这行可以删去
            gameState = FAILED;
            return;
        }  
        //判断是否成功
        foreach(RoleController r in RoleCtrl){
            if(r.roleState != RIGHTLAND){//存在角色未到达右岸,则直接返回 //r.roleType == 0 && 
                UnityEngine.Debug.Log("这里");
                return;
            }
        }
        UnityEngine.Debug.Log("其实是这里");
        gameState = WIN;  //上面的情况都不符合,则说明所有角色都安全到达右岸,win
        return;
    }

    //Reset按钮执行的功能
    public void Restart(){
        Initialize();
        gameState = PLAYING;
    }

    //获取游戏当前状态
    public int GetGameState(){
        return gameState;
    }
}

视频链接:unity3D小游戏-牧师与魔鬼MVC版_哔哩哔哩_bilibili

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数字乡村和智慧农业的数字化转型是当前农业发展的新趋势,旨在通过应用数字技术,实现农业全流程的再造和全生命周期的管理服务。中国政府高度重视这一领域的发展,提出“数字中国”和“乡村振兴”战略,以提升国家治理能力,推动城乡融合发展。 数字乡村的建设面临乡村治理、基础设施、产业链条和公共服务等方面的问题,需要分阶段实施《数字乡村发展战略纲要》来解决。农业数字化转型的需求包括满足市民对优质农产品的需求、解决产销对接问题、形成优质优价机制、提高农业劳动力素质、打破信息孤岛、提高农业政策服务的精准度和有效性,以及解决农业融资难的问题。 数字乡村建设的关键在于构建“1+3+4+1”工程,即以新技术、新要素、新商业、新农民、新文化、新农村为核心,推进数据融合,强化农业大数据的汇集功能。数字农业大数据解决方案以农业数字底图和数据资源为基础,通过可视化监管,实现区域农业的全面数字化管理。 数字农业大数据架构基于大数据、区块链、GIS和物联网技术,构建农业大数据中心、农业物联网平台和农村综合服务指挥决策平台三大基础平台。农业大数据中心汇聚各类涉农信息资源和业务数据,支持大数据应用。信息采集系统覆盖市、县、乡、村多级,形成高效的农业大数据信息采集体系。 农业物联网平台包括环境监测系统、视频监控系统、预警预报系统和智能控制系统,通过收集和监测数据,实现对农业环境和生产过程的智能化管理。综合服务指挥决策平台利用数据分析和GIS技术,为农业决策提供支持。 数字乡村建设包括三大服务平台:治理服务平台、民生服务平台和产业服务平台。治理服务平台通过大数据和AI技术,实现乡村治理的数字化;民生服务平台利用互联网技术,提供各类民生服务;产业服务平台融合政企关系,支持农业产业发展。 数字乡村的应用场景广泛,包括农业生产过程、农产品流通、农业管理和农村社会服务。农业生产管理系统利用AIoT技术,实现农业生产的标准化和智能化。农产品智慧流通管理系统和溯源管理系统提高流通效率和产品追溯能力。智慧农业管理通过互联网+农业,提升农业管理的科学性和效率。农村社会服务则通过数字化手段,提高农村地区的公共服务水平。 总体而言,数字乡村和智慧农业的建设,不仅能够提升农业生产效率和管理水平,还能够促进农村地区的社会经济发展,实现城乡融合发展,是推动中国农业现代化的重要途径。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值