unity实现牧师与魔鬼&问题回答

简答题

  • 游戏对象运动的本质是什么?
    游戏运动本质就是使用矩阵变换(平移、旋转、缩放)改变游戏对象的空间属性。
  • 请用三种方法以上方法,实现物体的抛物线运动。(如,修改Transform属性,使用向量Vector3的方法…)
    ①使用vector3:给小球一个固定的水平初速度,和一个向下的加速度,则小球会向下的速度会不断增加,形成抛物线运动。
 public int speed = 2;public float speed2 = 2;void Update () {this.transform.position += speed * Vector3.right * Time.deltaTime;speed2 += 2*Time.deltaTime;this.transform.position += speed2 * Vector3.down * Time.deltaTime;}

②修改Transform属性

public int speed = 2;
void Update()
{this.transform.position += new Vector3(Time.deltaTime * speed, -Time.deltaTime * speed * (2 * transform.position.x + Time.deltaTime * speed), 0);
}

③使用Translate

public int speed = 2;
public int speed2 = 2;
public int T = 1;
void Update()
{transform.Translate(Vector3.right * Time.deltaTime * speed + Vector3.down * Time.deltaTime * speed2 * Time.deltaTime * T);T++;
}
  • 写一个程序,实现一个完整的太阳系, 其他星球围绕太阳的转速必须不一样,且不在一个法平面上。
    先创建十个对象,分别是太阳、八大行星和月亮,写一个初始化十个球体位置的脚本,八大行星按照与太阳的距离由近到远分别是水星、金星、地球、火星、木星、土星、天王星、海王星。初始化代码如下:
public Transform sun;public Transform earth;public Transform moon;public Transform Mercury; //水public Transform Venus; //金public Transform Mars; //火public Transform Jupiter; //木public Transform Saturn; //土public Transform Uranus; //天public Transform Neptune; //海void Start(){sun.position = Vector3.zero;earth.position = new Vector3(4,0,0);moon.position = new Vector3(5,0,0);Mercury.position = new Vector3(2,0,0) ; //水Venus.position = new Vector3(3,0,0); //金Mars.position = new Vector3(5,0,0); //火Jupiter.position = new Vector3(7.5f,0,0); //木Saturn.position = new Vector3(9,0,0); //土Uranus.position = new Vector3(10,0,0); //天Neptune.position = new Vector3(12,0,0); //海}

接下来就是设置每个球体旋转的角度及公转的速度,可以手动对每个球体设置这些数值,但若用随机数随机生成旋转角度和公转速度的话,可以大大简化设置数值代码的量。因此,采用随机数随机设置各球体的旋转角度和公转速度。

    public Transform center;public float speed;public float x, y;void Start () {speed = Random.Range(5,20);x = Random.Range(0,10);y = Random.Range(0,10);}void Update () {Vector3 vec = new Vector3(0, x, y);this.transform.RotateAround(center.position, vec, speed * Time.deltaTime);}

将该脚本分别拖动到八大行星中,由于八大行星围绕着太阳公转,因此center因设置为太阳,表示行星以太阳为球心公转,类似地,月亮的center应该设置为地球,表示月亮绕着地球转。再根据自己的理解设置每个球体的大小,一个简易太阳系就完成了。

编程实践-牧师与魔鬼

  • 列出游戏中提及的事物(Objects)
    牧师、魔鬼、船、河流、河岸

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

玩家动作(事件) 条件 结果(游戏对象动作)
点击牧师 游戏未结束,牧师处于静止,牧师在岸上并与船在同一侧 牧师上船
点击牧师 游戏未结束,牧师处于静止,牧师在船上 牧师上同一侧的岸
点击魔鬼 游戏未结束,魔鬼处于静止,魔鬼在岸上并与船在同一侧 魔鬼上船
点击魔鬼 游戏未结束,魔鬼处于静止,魔鬼在船上 魔鬼上同一侧的岸
点击Restart 游戏已结束 重新开始游戏
  • 游戏架构
    程序使用MVC结构。

    • 模型(Model):游戏中的所有对象,包括船、牧师、魔鬼、河岸。每个对象都写在一个对应的类里面,由该类控制对象的各种行为。
    • 控制器(Controller):控制场景,使用单例模式创建导演类,导演只有一个,管理本次场景所有的游戏对象并控制着场景的切换,角色的移动,游戏结果的判断,对外界输入事件的响应。
    • 界面(View):
      接受用户输入,展示游戏结果。

各类的架构

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

导演类是单实例的,其继承至 C# 根对象,导演类一直存在,不会受 Unity 引擎管理。可以控制场景运行、切换并管理游戏全局状态。

  • ISceneController接口
 public interface ISceneController{void LoadResources();}

通过该接口,导演可以自由的切换场景,使得不同场景加载不同资源。

  • IUserAction接口
    public interface IUserAction{void MoveRole(Role role);void MoveBoat();void Restart();int check();}

该接口定义了一组用户操作,通过实现该接口,用户可以通过这些操作去对游戏对象发出相应的指令,使其响应。

  • Move类
    组件,可以挂载到游戏对象中,例如牧师、魔鬼和船,游戏对象通过挂载该组件,可以实现游戏对象的移动。由于船只需要水平移动,牧师与魔鬼需要一个垂直方向的移动,因此需要在该类里面定义不同的移动函数,以区分不同对象的移动。
    public class Move : MonoBehaviour{Vector3 pos1;Vector3 pos2;int con = 0;int speed = 3;Role role = null;Boat boat = null;public void Setcon(){con = 0;}public void SetRole(Role role){this.role = role;}public void SetBoat(Boat boat){this.boat = boat;}void Update(){if(con == 1){transform.position = Vector3.MoveTowards(transform.position, pos1, speed * Time.deltaTime);  //水平移动if(transform.position == pos1){con = 0;if(boat != null){boat.ChangeIsMove();//boat.ChangeRoleIsMove();}if(role != null){//role.ChangeIsMove();role.NotMoving();}}}if(con == 2){transform.position = Vector3.MoveTowards(transform.position, pos2, speed * Time.deltaTime);  //垂直移动if(transform.position == pos2)con = 1;}}public void move_boat(Vector3 pos){pos1 = pos;con = 1;}public void move_role_to_boat(Vector3 pos){pos2 = new Vector3(transform.position.x, transform.position.y + 0.25f, transform.position.z);pos1 = new Vector3(pos.x, pos2.y, transform.position.z);con = 2;}public void move_role_to_bank(Vector3 pos){pos1 = pos;con = 1;}}
  • Click类
    组件,可以挂载到游戏对象中,用来检测游戏对象是否被点击,对象被点击的时候若其他条件满足则触发相应的事件,例如游戏对象的移动。
    public class Click : MonoBehaviour{IUserAction action;Role role = null;Boat boat = null;public void SetRole(Role role){this.role = role;}public void SetBoat(Boat boat){this.boat = boat;}void Start(){action = SSDirector.GetInstance().CurrentScenceController as IUserAction;}void OnMouseDown(){if(action.check() != 0)return;if (boat == null && role == null) return;if (boat != null && !boat.RoleISGetBoat()) return;//if (boat != null && boat.GetIsMove() == false && !boat.IsEmpty()){boat.ChangeIsMove();//boat.ChangeRoleIsMove();action.MoveBoat();}else if (role != null){role.Moving();action.MoveRole(role);}else return;}}
游戏对象类
  • Role类
    对角色GameObject进行封装,因此其包含角色对象,由于角色需要点击来触发移动,因此应该包含Move和Click两个组件。除此之外,为了区分游戏对象的类型、移动状态和位置,定义三个属性RoleType、IsMove和on_bank,还要定义相应的get,set函数。
        GameObject role;int on_bank;    //right 1,left -1, on_boat 2Move move;Click click;string RoleType;bool IsMove = false;
  • Bank类
    对河岸GameObject进行封装,因此其包含河岸对象,由于河岸需要记录角色的位置,和自身的位置(左岸/右岸),因此定义相应属性如下
        GameObject bank;int flag;  //1,right  -1,leftRole[] roles = new Role[6];Vector3[] pos;
  • Boat类
    对船GameObject进行封装,因此其包含船对象,由于船需要点击来触发移动,因此应该包含Move和Click两个组件。船最多可以载两个角色,因此需要记录角色信息,除此之外,还需要判断船停靠在哪边河岸和船的移动状态。
        GameObject boat;Move move;Click click;int boat_bank; //1 right -1 leftpublic Role[] roles = new Role[2];bool IsMove = false;
控制器
  • Controll类
    控制器,继承了ISceneController,IUserAction接口,实现了内部的方法。通过该控制器,可以加载游戏场景;操控游戏中的对象,使其进行移动。
    主要代码如下:
    public Role[] roles;public Boat boat;public Bank left_bank;public Bank right_bank;UserGUI User;void Start(){SSDirector director = SSDirector.GetInstance();//得到导演实例director.CurrentScenceController = this;User = gameObject.AddComponent<UserGUI>() as UserGUI;LoadResources();  //加载场景}public void LoadResources(){//实现资源的加载}public void MoveBoat(){//控制船的移动}public void MoveRole(Role role){//控制角色的移动}public int check(){//检查游戏结果}public void Restart(){//重新开始游戏}
用户界面
  • UserGUI
    包含规则的介绍,游戏的重新开始
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Model;
public class UserGUI : MonoBehaviour
{private IUserAction action;public int check = 0;void Start(){action = SSDirector.GetInstance().CurrentScenceController as IUserAction;}void OnGUI(){GUIStyle fontStyle = new GUIStyle();fontStyle.fontSize = 30;GUI.Label(new Rect(Screen.width / 2 - 300, 10, 420, 30), "红色代表恶魔,白色代表牧师。");GUI.Label(new Rect(Screen.width / 2 - 300, 40, 420, 30), "游戏目标:将所有牧师和恶魔移到河对岸。");GUI.Label(new Rect(Screen.width / 2 - 300, 70, 420, 30), "规则一:船一次最多载两个人,至少要有一个人才能开船。");GUI.Label(new Rect(Screen.width / 2 - 300, 100, 420, 30), "规则二:两岸边若有牧师,则对应岸边恶魔的数量不能多于牧师的数量。");if(check == 1){    //successGUI.Label(new Rect(Screen.width / 2 - 50, 30, 60, 40), "You Win!", fontStyle);if (GUI.Button(new Rect(Screen.width / 2 - 40, Screen.height-100, 70, 40), "Restart")){action.Restart();check = 0;}}else if(check == 2){   //failGUI.Label(new Rect(Screen.width / 2 - 50, 30, 60, 40), "Game Over!", fontStyle);if (GUI.Button(new Rect(Screen.width / 2 - 40, Screen.height-100, 70, 40), "Restart")){action.Restart();check = 0;}}}
}

类的大体结构已经完成,只需对各方法进行完善即可,为了使得游戏对象能够移动,已经设置了一个Move组件,但是在游戏对象只有在特定的条件下才能移动,例如牧师与魔鬼与船在同一侧并且船是静止时牧师与魔鬼才能上下船、船在移动过程中不能改变方向。为了完成这些限制条件,还需要在游戏对象中设置相应的方法,使得不满足条件时点击游戏对象将会无响应。

船的移动条件:
  1. 船上有角色
  2. 船不能处于移动过程中,即船不能在途中改变移动方向。
  3. 角色上船的行为已经结束,即船不能在角色上船上到一半的时候就开走了。
    因此,需要在船控制类中添加一个IsEmpty()方法,判断船上是否有角色。
    一个GetIsMove()方法来判断船是否在移动过程中。还需要一个RoleISGetBoat()方法来判断角色是否上好船了。
    对应方法如下
public bool IsEmpty(){      //判断船上是否有角色if(roles[0] == null && roles[1] == null) return true;else return false;
}
public bool GetIsMove(){    //得到船当前的状态return IsMove;
}
public void ChangeIsMove(){  //修改船当前的状态IsMove = !IsMove;
}
public bool RoleISGetBoat(){  //当角色的状态是静止的时候,返回真if(roles[0] != null && roles[0].GetIsMove() == true)return false;if(roles[1] != null && roles[1].GetIsMove() == true)return false;return true;
}
if (boat != null && boat.GetIsMove() == false && !boat.IsEmpty()){boat.ChangeIsMove();                            //修改船的移动状态action.MoveBoat();                              //开船
}
角色的移动条件
  1. 角色要与船在同一侧
  2. 船要是静止状态
  3. 若要上船,船上要有空位
    相关方法或判断条件如下:
int temp = 0;
temp = boat.SetRoles(role);       //返回一个空位置,若没有则返回-1
if(temp == -1)return;             //boat is full
if(role.GetOnBank() == -boat.Get_boat_bank()) return;//角色与船不在同一侧
if(boat.GetIsMove() == true)return;   //船正在移动

另外,点击角色时还需要判断角色是上岸还是上船,在岸上则上船,在船上则上岸。

if(role.GetOnBank() == 1 || role.GetOnBank() == -1){ //1代表在右岸,-1代表在左岸,2代表在船上//move role to boat
}
else if(role.GetOnBank() == 2){ //move role to bank
}

控制对象移动的大致思路就是如此,还有一些细节部分请查看完整代码。

运行截图:



项目资源和代码
https://gitee.com/xukangze/ThreeD-games/tree/master/PriestsAndDevils.

项目运行视频
https://www.bilibili.com/video/BV1op4y1a7pd/.

特地感谢师兄留下的代码,在本次作业中给予我帮助。
https://blog.csdn.net/c486c/article/details/79795708.

unity实现牧师与魔鬼问题回答相关推荐

  1. unity实现牧师与魔鬼2.0(动作分离版) 基本操作演练

    unity实现牧师与魔鬼2.0(动作分离版)& 基本操作演练 & 材料与渲染联系 基本操作演练 下载 Fantasy Skybox FREE, 构建自己的游戏场景 在Window-&g ...

  2. Unity实战——牧师与魔鬼

    Unity实战--牧师与魔鬼 项目源码 最终效果 牧师与魔鬼游戏效果 背景描述 牧师与魔鬼是一款益智游戏,您将帮助牧师与魔鬼在规定时间内过河.河边有三个牧师和三个魔鬼.他们都想去这条河的对岸,但只有一 ...

  3. Unity 游戏 牧师与魔鬼

    Unity游戏设计 牧师与魔鬼 MVC游戏架构 MVC的全名是Model View Controller,是模型(Model)-视图(view)-控制器(controller)的缩写,是一种设计模式. ...

  4. Unity实现牧师与魔鬼动作分离版

    牧师与魔鬼动作分离版 项目地址 动作管理器的设计 程序设计框架: 为了用一组简单的动作组合成复杂的动作,我们采用 cocos2d 的方案,建立与 CCAtion 类似的类. 通过门面模式(控制器模式) ...

  5. Unity实战之牧师与魔鬼(动作分离版)

    Unity实战之牧师与魔鬼(动作分离版) 项目链接 整体描述 本次项目在第一版牧师与魔鬼的基础上,将动作从场记中分离出来,并设计一个裁判类实时监测游戏进行的情况.这样改进的优点有很多: 降低了不同功能 ...

  6. Unity牧师与魔鬼小游戏(动作分离版)

    Unity牧师与魔鬼小游戏(动作分离版) 前言 这是中大计算机学院3D游戏编程课的一次作业,在这里分享一下设计思路. 主要代码上传到了gitee上,请按照后文的操作运行. 项目地址:https://g ...

  7. Unity编程实战--牧师与魔鬼

    游戏目标:将3个牧师和3个魔鬼从河的一端安全地送到河的另一端. 游戏规则:在运送过程中,船可以搭载两个人,而且必须有一人掌船. 游戏结果:无论何时,只要河一边的魔鬼数量多于牧师的数量,游戏就会以失败结 ...

  8. Unity使用MVC架构制作牧师与魔鬼小游戏

    Unity使用MVC架构制作牧师与魔鬼小游戏 MVC架构简介 MVC概述 MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller) ...

  9. unity 实现游戏——牧师与魔鬼

    unity 实现游戏--牧师与魔鬼 一.游戏介绍 Priests and Devils Priests and Devils is a puzzle game in which you will he ...

最新文章

  1. 你为什么“啃不动”你手中的技术书?
  2. ubuntu 16.04 分辨率只有800×600问题解决
  3. mysql发生系统错误2系统找不到指定文件_电脑运行错误代码大全,遇到报错请自己对照断电原因所在吧...
  4. 设计模式(10)-装饰模式详解(易懂)
  5. vue main.js中引入js_web前端的同学不容错过,大厂Vue最佳实践总结,提高竞争力...
  6. 网络知识:路由器不关闭这个功能,视频越刷越卡!
  7. C++ 运算符优先级
  8. Handler源码解析2
  9. 问题 C: 判断三角形的性质
  10. 未能对git remote进行身份验证_用好Git和SVN,再也不怕跑路了!
  11. Linux软件安装及修改软件源
  12. 2019最新Python学习教程_Python学习视频_Python学习路线:学Python,这次你可得认真看完了!
  13. 睡眠革命——摘抄总结大纲
  14. python 股票竞价数据_百度竞价的数据分析怎么做
  15. Ubuntu18.04启动后键盘和鼠标失灵
  16. 湖大OJ-实验A---- ADFA的可判定性
  17. winform实现pictureBox显示成圆形形状,并实现pictureBox透明
  18. (转)马邑之战与项目管理
  19. 前端系列——与众不同的移动端底部固定栏 fixed、absolute 兼容 iOS 和 Android 方案...
  20. 权威解读医学影像AI路线图:AI未来会在很大程度上取代医生读片

热门文章

  1. Word 2007 2010 书法字帖 停止保护
  2. 蒸汽流量计算软件_涡街流量计的基本测量原理及选型
  3. UiPath被Everest Group评为PEAK Matrix®流程挖掘产品领导者和明星企业
  4. java后台批量下载文件并压缩成zip下载
  5. 丰田生产方式(TPS)的本质
  6. 关于使用校园网的时候使用阿里云视频点播上传服务失败的解决方法
  7. MSF后门生成及免杀思想
  8. [译] 2019 年了,为什么我还在用 jQuery?
  9. 如何用计算机算利率,信用卡怎么算的利息怎么算的?信用卡利息计算器
  10. 团体天梯 L2-030 冰岛人 (25 分)(思路、测试点分析)