unity|Unity3D游戏编程-牧师与恶魔

Unity3D游戏编程-牧师与恶魔
文章目录

  • Unity3D游戏编程-牧师与恶魔
    • 前置说明
      • 牧师与恶魔
      • MVC架构
    • 作业要求
    • 项目配置
    • Object
    • 玩家动作(规则表)
    • 项目演示
      • 视频演示
      • 项目下载
      • 文字说明
      • 项目截图
    • 实现过程和方法(算法)
      • Director
      • Controller
        • SceneController
        • Moveable
        • CharacterController
        • CoastController
        • BoatController
      • UserAction
        • UserAction
        • ClickGUI
        • UserGUI
      • FirstController
    • 参考资料

前置说明 牧师与恶魔
牧师与恶魔需要从岸的一端到达另一端,河上只有一条船,一条船只能坐两个角色,并且至少需要一个角色在船上船才可以行驶。并且,如果在某一侧(包括岸上和船上),恶魔的数量大于牧师的数量,牧师就会被恶魔吃掉(如果仅有恶魔则无事发生),游戏失败。玩家要安排牧师与恶魔的过河顺序,让牧师与恶魔全部到达另一边岸上,才能游戏通关。
MVC架构
MVC是界面人机交互程序设计的一种架构模式。它把程序分为三个部分:
  1. 模型(Model):数据对象及关系
    · 游戏对象、空间关系
  2. 控制器(Controller):接受用户事件,控制模型的变化
    · 一个场景一个主控制器
    · 至少实现与玩家交互的接口(IPlayerAction)
    · 实现或管理运动
  3. 界面(View):显示模型,将人机交互事件交给控制器处理
    · 处收Input 事件
    · 渲染GUI ,接收事件
例子:
应用程序浏览网页,是一个把信息拉取下来并显示到页面上的过程,页面就是view,拉取信息的类就是model,当用户进行了点击后,负责通知model去拉去信息,并且通知view进行显示的就是controller。
【unity|Unity3D游戏编程-牧师与恶魔】而基于职责的设计与游戏的MVC总体框架包括:
  1. 导演,1名(仅要一个)
    ·类型:SSDriector
    ·职责:把握全局;控制场景
  2. 场记若干,话剧有很多场,每场需要一个。
    ·抽象类型(角色):ISceneController
    ·具体类型:FirstController
    ·职责:第一场的场记,控制布景、演员的上下场、管理动作等执行
  3. 吃瓜群众,1个
    · 抽象类型:IUserAction
    · 具体类型:IUserAction
    · 职责:门面,与controller沟通
两种结合,导演和场记相当于controller,游戏中的object就是model,GUI就是view。
作业要求 完成牧师与恶魔游戏,程序需要满足要求:
· play the game
· 列出游戏中提及的事物(Objects)
· 用表格列出玩家动作表(规则表)
· 将游戏中对象做成预制
· 在 GenGameObjects 中创建长方形、正方形、 及其色彩代表游戏中的对象。
· 使用C#集合类型有效组织对象
· 整个游戏仅主摄像机和一个Empty对象,其他对象必须代码动态生成。整个游戏不许出现Find游戏对象,SendMessage这类突破程序结构的通讯耦合语句。
· 使用课件架构图编程,不接受非MVC结构程序
· 船未靠岸,牧师与魔鬼上下船运动中,均不能接受用户事件
项目配置 Windows 10
Unity 2020.3.17f1c1
Object 游戏中主要包括的Object有以下:
object 数量
牧师 3
恶魔 3
1
1
岸边 2
玩家动作(规则表)
动作 条件 效果
玩家点击岸上角色 船上有空位 角色上船
玩家点击船上角色 角色上岸
玩家点击船 船上有至少一个角色 开船
玩家点击restart 重新开始游戏
项目演示 视频演示
点击此处可以前往
项目下载
下载Assets文件夹,项目代码在Assets>Scripts中
点击此处可以前往gitee
文字说明
  1. 创建unity专案后,将保存的文件夹中的Assets替换成在上面项目下载的Assets文件夹
  2. 打开专案,然后点选Assets中的ass加载场景
  3. 运行即可开始游戏
  4. 白色长方体为牧师,红色圆球为恶魔
项目截图
unity|Unity3D游戏编程-牧师与恶魔
文章图片

unity|Unity3D游戏编程-牧师与恶魔
文章图片

unity|Unity3D游戏编程-牧师与恶魔
文章图片

实现过程和方法(算法) Director
首先是Director的部分,Director的建立基本是默认的:
public class Director : System.Object {private static Director _instance; public SceneController currentSceneController { get; set; }public static Director getInstance() {if (_instance == null) {_instance = new Director (); } return _instance; } }

这个Director是单例模式并且是懒汉模式的,因此如果在程序的其他地方进行调用getInstance,得到的_instance会是同一个,就可以实现类之间的通信。
  1. 单例模式:一些东西在整个游戏中只有一个,而又想可以方便地随时访问它,这时就可以考虑单例模式。单例模式保证应用只有全局惟一的实例,并且提供一个访问它的全局访问点。单例包含一个静态方法,叫做getInstance(),调用这个静态方法,它就立刻现身,随时可以工作。
  2. 懒汉模式:在启动时并不创建单例对象,仅在调用getInstance()的时候才创建。程序运行中,调用Director.getInstance会判断_instance是否为空。如果为空,就创建一个返回。如果不为空,说明之前已经创建过了,直接返回。
Controller
然后是场记的部分,对于不同的对象设置不同的Controller:
SceneController Director中有:
public SceneController currentSceneController { get; set; }

而SceneController是一个接口:
public interface SceneController {void loadResources (); }

SceneController是导演Director控制场景控制器的渠道,Director可以调用SceneController接口中的方法。而实现SceneController的currentSceneController类,在FirstSceneController中就会被定义为FirstSceneController本身,loadResources需要在FirstSceneController中实现。
Moveable (程序在BaseCode.cs中的31行开始)
Moveable是为了给角色对象、船只移动而准备的类,因此需要先写。
update主要利用MoveTowards来使得对象移动到目的位置。
当角色对象控制器和船只控制器需要移动某一个对象时,可以调用setDestination函数来进行移动。
Moveable中还设置了reset用于重新开始,初始化游戏对象的移动状态。
CharacterController (程序在BaseCode.cs中的73行开始)
MyCharacterController类主要用于控制游戏中的牧师与恶魔,其构造函数会根据传入的字符串来创建牧师/恶魔对象,并且给他们每一个对象挂载ClickGUI函数用于判断用户点击,由于角色对象会运动,所以也需要挂载Moveable类。
类中还有其他可调用的函数:
  1. setName设置名称(如“牧师1/恶魔1”)
  2. setPosition设置对象位置
  3. moveToPosition设置对象移动到目标位置,调用moveable的setDestination
  4. getType返回对象的类型(如“牧师”、“恶魔”)
  5. getName返回对象的名称(如“牧师1/恶魔1”)
  6. getOnBoat对象上船,并且修改对象的状态(_isOnBoat)
  7. getOnCoast对象下船,并且修改对象的状态(_isOnBoat)
  8. isOnBoat返回对象_isOnBoat的状态
  9. getCoastController返回岸边控制器
  10. reset用于重新初始化
CoastController (程序在BaseCode.cs中的148行开始)
CoastController用于控制河岸对象,而河岸因为要用于判断获胜条件,也需要像角色对象分为牧师与恶魔一样,分成此岸和对岸(from和to)。
因为河岸需要给角色对象站立,游戏中的角色对象总共有六个,因此在构造函数需要构造六个空对象,并且根据传入的字符串,标记此次创建的是此岸还是对岸。
其他函数:
  1. getEmptyIndex获取岸上的空位置的下标,passengerPlaner是用来记录在一个河岸上的角色位置,如果为NULL表示该位置为空没有角色站立在此。
  2. getEmptyPosition获取岸上的空位置
  3. getOnCoast有角色下船,修改对应的岸上状态
  4. getOffCoast有角色上船,修改对应的岸上状态
  5. get_to_or_from返回这个河岸是此岸还是对岸
  6. getCharacterNum返回当前河岸牧师与恶魔的数量
  7. reset重置
BoatController (程序在BaseCode.cs中的230行开始)
BoatController用于控制船只,因为船只会移动到两个岸边,因此它的状态也分成在此岸或对岸(from和to)。
因为船上拥有两个位置,因此需要构造两个空对象;并且由玩家点击船只行驶,需要挂载ClickGUI类判断用户点击;由于船只会运动,所以也需要挂载Moveable类。
其他函数:
  1. Move控制船只在两岸中移动
  2. getEmptyIndex返回船上空余位置下标
  3. getEmptyPosition返回船上空余位置
  4. isEmpty返回船只是否空的
  5. GetOnBoat有角色上船,修改船的属性
  6. GetOffBoat角色下船,修改船的属性
  7. getGameobj返回船本体的游戏对象
  8. get_to_or_from返回船只当前所在河岸
  9. getCharacterNum返回船上牧师和恶魔的数量
  10. reset重置船只
UserAction
UserAction UserAction是门面模式,与用户交互相关的,与玩家动作有关:
public interface UserAction {void moveBoat(); void characterIsClicked(MyCharacterController characterCtrl); void restart(); }

这里就包括了移动船只,角色被点击,游戏重新开始这三个动作,UserAction接收到UI传来的信号,告知FirstSceneController调用对应动作的函数作出反应。而UserAction里面的函数就要在FirstSceneController中定义。而ClickGUI与UserGUI则通过UserAction这个门面接口来与FirstSceneController打交道。
  1. 门面模式:定义一个用户动作接口,实现用户行为与游戏系统规则计算的分离,称这个接口就是游戏逻辑与用户之间交互的门面(Fasàde)。
ClickGUI ClickGUI是用以判断用户点击了游戏对象(牧师、恶魔、船)的类
public class ClickGUI : MonoBehaviour { UserAction action; MyCharacterController characterController; public void setController(MyCharacterController characterCtrl) {characterController = characterCtrl; } void Start() {action = Director.getInstance ().currentSceneController as UserAction; } void OnMouseDown() {if (gameObject.name == "boat") {action.moveBoat (); } else {action.characterIsClicked (characterController); } } }

ClickGUI判断被鼠标点击的对象是谁来进行下一步操作,调用UserAction(action)的接口来完成功能。
UserGUI UserGUI是用于当游戏结束(失败或者成功)时显示说明文字和重玩游戏按钮的。
游戏状态分别为:0-游戏进行中,1-游戏失败,2-游戏通关。
FirstController
FirstController就要负责实现loadResources、moveBoat、characterIsClicked、restart函数。
  1. Awake函数是负责游戏的初始化加载
  2. loadResources是从Aseets中取出对象,生成水面、船只、两个河岸,以及调用loadCharacter生成牧师和恶魔。
  3. loadCharacter负责在出发的河岸上生成三个牧师和三个恶魔。
  4. moveBoat检测船只上的人员是否为空,如果不是的话则可以移动船只,并且判断游戏的状态(是不是gameover)
  5. characterIsClicked检查被点击的对象,
    若处于船上:取得船在哪个岸边、人物下船、调用函数修改游戏属性(包括船、河岸);
    若处于岸上:取得人物所在哪个岸边、判断船还有没有空位、判断船和人物是否处于同一侧岸、调用函数修改游戏属性(包括船、河岸);
    最后也要判断游戏的状态(是不是gameover)。
  6. check_game_over就是数出发岸和目标岸(包括船上)各自的牧师与恶魔数量,如果目标岸的角色总数=6,则游戏通关(状态为2);如果某一个岸恶魔的数量大于牧师,则游戏失败(状态为1);其余情况游戏继续(状态为0);
  7. restart重置游戏,分别调用各个对象自己的reset。
参考资料 1.学习Unity(5)小游戏实例——牧师与魔鬼
2.Unity中的单例模式
3.Unity3d-learning 牧师与恶魔

    推荐阅读