前言

中山大学数据科学与计算机学院3D游戏课程学习记录博客。
游戏代码:gitee
游戏视频:bilibili
参考师兄的博客: 师兄博客

游戏要求

  • 列出游戏中提及的事物(Objects)
    对象:牧师、魔鬼、船、河、陆地

  • 用表格列出玩家动作表(规则表)

动作 条件 角色
点击牧师或魔鬼 游戏未结束;角色与船同岸;角色在船上 角色上岸
点击牧师或魔鬼 游戏未结束;角色与船同岸;角色在岸上 角色上船
点击船 船上存在一个角色 船开到对岸
点击重新开始 重新开始
  • 将游戏中对象做成预制
    预制的制作方法还是比较简单的,直接把列表里的物体拉到下面的文件夹即可。但是太丑了,不如直接copy师兄用的精美预制。

  • 在场景控制器 LoadResources 方法中加载并初始化 长方形、正方形、球 及其色彩代表游戏中的对象。

  • 使用 C# 集合类型有效组织对象

  • 整个游戏仅 主摄像机 和 一个 Empty 对象, 其他对象必须代码动态生成!!! 。

  • 整个游戏不许出现 Find 游戏对象, SendMessage 这类突破程序结构的 通讯耦合 语句。

  • 使用MVC 结构程序

  • 注意细节

游戏实现

  • 介绍MVC架构

    M是Model:代表游戏中所有的游戏对象,它们受各自的Controller控制。Model是游戏中存在的实体。
    V是View:代表游戏呈现出的界面。主要包括GUI和Click两部分,GUI负责展示游戏结果,Click负责处理用户点击事件。
    C是Controller:代表游戏中的控制器,分为FitstController(场景控制器)和SSDirector(导演)。由于本游戏只有一个场景,所以导演只用负责退出和暂停;场景控制器需要控制场景中的所有物体。

    一共创建7个C#脚本来支持MVC架构:

  • 实现
    这个游戏看起来还是比较容易的,我们一步步来实现所有的要求,首先实现游戏对象的内部逻辑。

1.游戏对象内部逻辑的实现(ModelController.cs):

  • 水(Water)
    在这个游戏中,水不需要动,只需要写一个函数使用预设创建水的对象即可。
public class Water{            GameObject water;  public Water(){ //使用预制创建水的游戏对象        }
}
  • 陆地(LandModel)
    陆地有出发点和目的地两种,需要进行区分,需要变量landSign;
    陆地需要存储角色的位置,需要Vector3数组进行保存,共6个位置;
    陆地需要存储角色的信息,需要RoleMode数组进行保存,共6个角色;
    陆地也需要一系列的成员函数来更改成员变量实现角色的上船和上岸动作。
public class LandModel{        GameObject land;        int landSign;        Vector3[] position;        RoleModel[] roles;public LandModel(string str){            //使用预制创建陆地的对象            //初始化成员变量            //str用于区分出发点和目的地        }//一系列用于处理角色上岸和上船的成员函数        public int getLandSign(){            return landSign;        }        public int getEmptyNumber(){            //返回空位置下标        }        public int[] getRoleNum(){            //返回角色数量,牧师/魔鬼        }public void addRole(RoleModel role){            roles[getEmptyNumber()]=role;        }        public RoleModel deleteRole(string name){            //删除对应的角色,角色上船        }
}
  • 船(BoatModel)
    船可以被点击和移动,所以需要Move对象和Click对象(后面回提到);
    船需要记录移动方向,所以需要变量boatSign;
    船需要保存角色的位置,所以需要Vector3数组startPos和endPos;
    船需要保存角色的信息,所以需要RoleModel数组roles;
    船也需要一系列成员函数来移动和支持角色上船以及上岸动作。
public class BoatModel{        GameObject boat;        int boatSign;        Vector3[] startPos,endPos;        RoleModel[] roles;        Move move; Click click;public BoatModel(){            //用预制创建船的对象            //初始化成员变量        }//一系列用于处理角色上岸和上船以及船移动的成员函数        public int getBoatSign(){            return boatSign;        }        public int getEmptyNumber(){            //返回空位置下标        }        public int[] getRoleNum(){            //返回角色数量,牧师/魔鬼        }public addRole(RoleModel role){            roles[getEmptyNumber()]=role;        }        public RoleModel deleteRole(string name){            //删除对应的角色,角色上岸      }public void boatMove(){            //船移动        }
}
  • 角色/牧师和魔鬼(RoleMode)
    角色需要标记身份,是否在船上,在哪块陆地上,因此需要变量roleSign,onBoat,landSign;
    角色可以移动和被点击,因此需要Move和Click;
    角色也需要一系列状态set和get函数,以及移动函数。
public class RoleModel{        GameObject role;        int roleSign;        int onBoat;        int landSign;        Move move;        Click click;public RoleModel(string name,Vector3 pos){            //用预制创建角色的对象            //初始化成员变量        }//一系列set和get函数,略        public void roleMove(){            //角色移动        }
}

实现以上四个类之后就完成了对游戏对象的创建以及对内部逻辑的实现,接下来就实现控制类,让游戏运转起来。

2.控制类的实现
(SSDirect.cs/Interfaces.cs/FirstController.cs/MoveController.cs/ClickController.cs):
SSDirect.cs使用单例模式,掌控全局;FirstController.cs是控制这个场景的,不过这个游戏只有一个场景,实际上SSDirect和FirstController的功能重复了;Interfaces.cs是给FirstController.cs提供接口的,规范FirstController.cs的内容。MoveController.cs是用来控制物体的移动功能,ClickController.cs是用来控制物体被点击的动作。接下来就把它们分别实现。

  • 实现SSDirect.cs:
    写一个单例模式即可。
public class SSDirect : System.Object{    private static SSDirect instance;    public ISceneController CurrentSceneController{ get; set;}public static SSDirect getInstance(){        if(instance==null) instance=new SSDirect();        return instance;    }
}
  • 实现Interfaces.cs:
    其中包含两个类,为FirstController.cs提供接口。
    ISceneController提供场景接口,IUserAction提供用户动作接口。
//场景接口
public interface ISceneController{         void LoadResoureces();
}
//用户动作接口
public interface IUserAction{        void moveBoat();        void moveRole(RoleModel role);        void reStart();        void check();
}
  • 实现FirstController.cs:
    其中具有之前的模型;
    也要包含Interface中所有的成员函数。
public class FirstController : MonoBehaviour,ISceneController,IUserAction{public LandModel startLand;    public LandModel endLand;    public Water water;    public BoatModel boat;    public RoleModel[] roles;    public UserGUI GUI;void Start(){        SSDirector director=SSDirector.GetInstance();           director.CurrentSceneController=this;        GUI=gameObject.AddComponent<UserGUI>() as UserGUI;        LoadResources();    }public void loadResources(){        //调用各对象的构造函数创建对象    }    public void moveBoat(){        //移动船    }public void moveRole(){        //移动角色    }    public void reStart(){        SceneManager.LoadScene(0);    }    public int check(){        //0-游戏1继续;1-游戏成功;-1-游戏失败    }
}
check方法的实现:
先统计船上,出发点和目的地的角色数量
假如在目的地存在6个角色,则胜利
假如在任何时候,船上及岸同侧存在魔鬼多与牧师,则失败
除此以外,游戏继续
  • 实现MoveController.cs:
public class MoveController : MonoBehaviour{      float moveSpeed=150f;    int moveSign=0;    Vector3 endPos,midPos;void Update(){        if(moveSign==1){            transform.position=Vector3.MoveTowards(transform.position,midPos,moveSpeed*deltaTime);            if(transform.position==midPos){                moveSign=2;            }        }else if(moveSign==2){            transform.position=Vector3.MoveTowards(transform.position,endPos,moveSpeed*deltaTime);            if(transform.position==endPos){                moveSign=0;            }        }    }public void MovePosition(Vector3 position){        endPos=position;        if(position.y == transform.position.y){            moveSign=2;            return;        }else if(position.y<transform.position.y){            midPos=new Vector3(position.x,transform.position.y,position.z);        }else{            midPos=new Vector3(transform.position.x,position.y,position.z);        }       moveSign=1;    }
}
  • 实现ClickController.cs:
public class ClickController : MonoBehaviour{    IUserAction action;    RoleModel role=null;    BoatModel boat=null;    public void setRole(RoleModel role){        this.role=role;    }    public void setBoat(BoatModel boat){        this.boat=boat;    }void Start(){        action=SSDirector.GetInstance().CurrentSceneController as IUserAction;}    void OnMouseDown(){        if(boat==null && role==null) return;if(boat!=null) action.MoveBoat();        else if(role!=null) action.MoveRole(role);    }
}

实现上述内容后就完成了对于控制器的设计。整个游戏的逻辑已经被设计出来,接下来需要的就是用V的部分把内容以GUI的形式呈现给玩家。

3.GUI类(UserGUI.cs):

  • 实现UserGUI.cs:
    主要绘制文本框和按钮即可,游戏对象不通过GUI展现。
    需要一个变量sign标记游戏的胜负;
    一个按钮来实现重新开始;
    一个文本框公布游戏结果。
public class UserGUI : MonoBehaviour{    public IUserAction action;    public int sign=0;    void Start() {        action = SSDirector.GetInstance().CurrentScenceController as IUserAction;    }    void OnGUI() {        GUIStyle text_style;        GUIStyle button_style;        text_style = new GUIStyle() {            fontSize = 30        };        button_style = new GUIStyle("button") {            fontSize = 15        };if(sign==1) {           GUI.Label(new Rect(Screen.width/2-90,Screen.height/2-120,100,50),"Gameover!",text_style);          }else if(sign==2) {            GUI.Label(new Rect(Screen.width/2-80,Screen.height/2-120,100,50),"You Win!",text_style);        }if (GUI.Button(new Rect(Screen.width/2-50,Screen.height/2-200,100,50),"Restart",button_style)) {            action.Restart();            sign = 0;        }    }
}

至此游戏的所有内容就被完全实现。具体的代码和预制可以看gitee,演示视频可以看bilibili。

Unity 3D游戏三:牧师与魔鬼相关推荐

  1. 3D游戏设计-牧师与魔鬼_动作分离版

    天空盒 天空盒 前情提要 3D游戏设计-牧师与魔鬼 游戏改进 将每个需要移动的游戏对象的移动方法提取出来,建立一个动作管理器来管理这些移动方法. 优点: 程序更能适应需求变化 对象更容易被复用 程序更 ...

  2. 3D游戏设计-牧师与魔鬼

    游戏简介 3个牧师和3个恶魔要过河,可小船每次只能搭乘2个人.可怕的是无论在岸的哪边,如果牧师的人数比恶魔少,牧师就会被恶魔杀死.发挥你的才智,帮他们想出一条过河的办法. 游戏规则设计 初始时3个牧师 ...

  3. 3D游戏编程 作业三 牧师与魔鬼

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.任务要求 二. 任务分析 1.游戏规则 2.游戏对象 3.动作表 二. 项目展示 1.mvc架构 导演 SSDir ...

  4. 【3D游戏编程与设计】四 游戏对象与图形基础 : 构建游戏场景+牧师与魔鬼 动作分离版

    [3D游戏编程与设计]四 游戏对象与图形基础 : 构建游戏场景+牧师与魔鬼 动作分离版 基本操作演练 下载 Fantasy Skybox FREE, 构建自己的游戏场景 下载 Fantasy Skyb ...

  5. Unity 3D游戏代码编程学习教程 Full Guide To Unity 3D C#: Learn To Code Making 3D Games

    Unity 3D游戏代码编程学习教程 Full Guide To Unity 3D & C#: Learn To Code Making 3D Games Full Guide To Unit ...

  6. 【Unity 3D游戏开发】在Unity使用NoSQL数据库方法介绍

    随着游戏体积和功能的不断叠加,游戏中的数据也变得越来越庞杂,这其中既包括玩家产生的游戏存档等数据,例如关卡数.金币等,也包括游戏配置数据,例如每一关的配置情况.尽管Unity提供了PlayerPref ...

  7. Unity 3D 环境特效||Unity 3D 游戏场景设计实例

    Unity 3D 环境特效 一般情况下,要在游戏场景中添加雾特效和水特效较为困难,因为需要开发人员懂得着色器语言且能够熟练地使用它进行编程. Unity 3D 游戏开发引擎为了能够简单地还原真实世界中 ...

  8. Unity 3D游戏开发项目《战斗吧!勇士》

    目录 版权声明:本博客涉及的内容是对本人游戏作品<战斗吧!勇士>项目的总结,发布在网络上,旨在大家交流学习.互相促进.严禁用于其他一切用途. 摘要 游戏开发技术概述 Unity 3D 游戏 ...

  9. Unity 3D - 游戏开发中的Lua

    Unity 3D - 游戏开发中的Lua : 本文作者:秦元培, 本文出处:http://blog.csdn.net/qinyuanpei/article/details/39826323 前言 : ...

最新文章

  1. 精品软件 推荐 硬盘物理序列号修改专家
  2. windows boot files
  3. Lesson 4.6 逻辑回归的手动实现
  4. bzoj 1968: [Ahoi2005]COMMON 约数研究【枚举】
  5. 海华模组:WIFI、BT、SoC模组列表
  6. 蓝桥杯 ADV-178 算法提高 简单加法
  7. 同一个路由器下的不同网段如何实现ping通
  8. 拓端tecdat|R语言网络分析友谊悖论案例
  9. 怎么把activeform生成的相关的js全给删除 版本yii2.0+[证实可行]
  10. 电信4区服务器未响应进网通六区,7月16日电信六区,网通经典区合服公告
  11. matlab求数组转置,数组与矩阵运算 - MATLAB Simulink - MathWorks 中国
  12. 苏宁易购:苏宁小店将获4.5亿美元增资
  13. 图片转换js (img对象,file对象,base64,canvas对象),以及图片压缩方式
  14. 【蓝桥杯集训·每日一题】AcWing 3777. 砖块
  15. 计算机关机桌面就还原,电脑重启后桌面还原怎么办
  16. 5.表达式求值(1)
  17. Manjaro引导项丢失修复
  18. 怎么用计算机算出出生日期,算农历出生日期计算器,根据出生日期怎么算年龄?...
  19. System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes”
  20. 求字符串中的回文数或者是回文单词

热门文章

  1. 控制安卓手机物理返回键
  2. mathtype小窍门
  3. javaScript 之淘宝购物车(课程总复习,个人小项目)
  4. 华为OD机试 - 射击比赛(Python)
  5. JAVA_SE_Day02
  6. mongo备份索引_MongoDB——备份 恢复 索引 hashed片键
  7. Excel中如何使用AVERAGEIF函数
  8. 线程间通信---数字交替打印(循环打印abc)
  9. 关于清理C盘的休眠文件
  10. PHP学习笔记——索引博文