Unity学习记录——空间与运动

前言


​ 本文是中山大学软件工程学院2020级3d游戏编程与设计的作业3

编程题


1. 模拟太阳系

​ 首先向unity中Assets添加所找的贴图素材Solar Textures | Solar System Scope

​ 再在Scene中建立十个Sphere以表示八个行星和月球太阳

​ 建立完成十个SPhere之后,将对应的星球贴图拖动到星球之上。此时Assets之中会生成Materials文件夹,里面为十个星球的材质。

​ 完成简单的贴图以及位置排序之后各个行星排列如下所示

​ 对模拟太阳系进行进一步优化,如下

​ 删除原先默认建立的光源,在太阳上建立一个点光源,如下

​ 再在太阳的材质处进行修改,添加Emission,使之发光

​ 此时在Assets区建立C#代码,命名为MoveBehavior,用于进行八大行星和月球的自转以及公转。

​ 代码如下:

public class MoveBehaviourScript : MonoBehaviour
{// 公转中心public Transform center;// 公转速度public float around_speed;// 自转速度public float self_speed;// 旋转所绕的轴public float x = 0, y, z;// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){Vector3 axis = new Vector3(x, y, z);// 自转this.transform.Rotate(Vector3.up * self_speed * Time.deltaTime);// 公转this.transform.RotateAround(center.position, axis, around_speed * Time.deltaTime);}
}

​ 将各个代码拖入进行自转与公转的行星,设置旋转中心以及速度等数值

​ 给各个行星对象设置拖尾渲染器,使得行星运行效果更为明显

​ 再将摄像机的背景色设置为黑色

运行效果如下:

gif太大无法上传至csdn,可于gitee查看,链接如下:
hw3/img/P9.gif · XiaoChen04_3/3D_Computer_Game_Programming

2.牧师与魔鬼

  • 游戏规则如下:

​ Priests and Devils is a puzzle game in which you will help the Priests and Devils to cross the river within the time limit. There are 3 priests and 3 devils at one side of the river. They all want to get to the other side of this river, but there is only one boat and this boat can only carry two persons each time. And there must be one person steering the boat from one side to the other side. In the flash game, you can click on them to move them and click the go button to move the boat to the other direction. If the priests are out numbered by the devils on either side of the river, they get killed and,the game is ovet You can ry it in many→ ways. Keep all priests alive! Good luck!

  • 游戏中提及的事物(Object)包括:牧师,魔鬼,船,河,陆地

  • 玩家动作表如下

动作 条件 结果
点击角色(牧师或魔鬼) 角色与船同岸;角色在船上 角色上岸
点击角色(牧师或魔鬼) 角色与船同岸;角色在岸上 角色上船
点击船 船上存在一或两个角色 船开到对岸
  • MCV架构以及其介绍

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

1. Model

​ 此部分代码用于模型的初始化加载,项目中的Model包括Role(牧师,魔鬼),Boat(船),Water(河),Land(陆地)。此处代码都整合至Model.cs之中。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;namespace ModelApplication
{public class Water{GameObject obj_water;public Water(){obj_water = Object.Instantiate(Resources.Load<GameObject>("Prefabs/Water"),Vector3.zero, Quaternion.identity) as GameObject;obj_water.name = "water";}}public class Land{public GameObject obj_land;public int landSign;public Vector3[] positions;public Land(string str){positions = new Vector3[] {new Vector3(6.35F,2F,0), new Vector3(7.35f,2F,0), new Vector3(8.35f,2F,0),new Vector3(9.35f,2F,0), new Vector3(10.35f,2F,0), new Vector3(11.35f,2F,0)};if (str == "start") landSign = 1;else landSign = -1;obj_land = Object.Instantiate(Resources.Load<GameObject>("Prefabs/Land"),new Vector3(9 * landSign, 1, 0), Quaternion.identity) as GameObject;obj_land.name = str + "Land";}}public class Boat{public GameObject obj_boat;public int boatSign;public Vector3[] startPos, endPos;public Boat(){obj_boat = Object.Instantiate(Resources.Load<GameObject>("Prefabs/Boat"),new Vector3(5, 0.5f, 0), Quaternion.identity) as GameObject;boatSign = 1;startPos = new Vector3[] { new Vector3(5.5f, 1, 0), new Vector3(4.5f, 1, 0) };endPos = new Vector3[] { new Vector3(-4.5f, 1, 0), new Vector3(-5.5f, 1, 0) };obj_boat.name = "boat";}}public class Role{public GameObject obj_role;public int roleSign;public int onBoat;public int landSign;public Role(string name, Vector3 pos){if (name == "priest"){obj_role = Object.Instantiate(Resources.Load<GameObject>("Prefabs/Priest"),pos, Quaternion.Euler(0, -90, 0)) as GameObject;roleSign = 0;}else{obj_role = Object.Instantiate(Resources.Load<GameObject>("Prefabs/Devil"),pos, Quaternion.Euler(0, -90, 0)) as GameObject;roleSign = 1;}landSign = 1;}}
}
2. Controller

SSDirector

​ SSDirector:使用单例模式创建,并且继承于System.Object保持一直存在,不受Unity内存管理。导演类负责控制当前场景的运行,切换,游戏的暂停恢复和退出,设定配置等等

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

ModelController

ModelController:Model的进一步操作的函数,包括:

​ LandModel:控制陆地模型。可以通过LandModel添加或删除本块Land上的Role(即Role上下陆地),以及判断Land上面的Role数量,此处使用一个二元int数组才记录本块陆地上的Role数量,即[牧师数量,魔鬼数量],以此判断游戏的进行程度

public class LandModel
{Land land;List<RoleModel> roles = new List<RoleModel>(){null,null,null,null,null,null};public LandModel(string str){land = new Land(str);}public int getLandSign(){return land.landSign;}public int getEmptyNumber(){for (int i = 0; i < 6; i++){if (roles[i] == null)return i;}return -1;}public Vector3 getEmptyPos(){Vector3 res = land.positions[getEmptyNumber()];res.x = res.x * land.landSign;return res;}public int[] getRoleNum(){int[] res = { 0, 0 };for (int i = 0; i < 6; i++){if (roles[i] != null){if (roles[i].getSign() == 0) res[0]++;else res[1]++;}}return res;}public void addRole(RoleModel role){roles[getEmptyNumber()] = role;}public RoleModel deleteRole(string name){for (int i = 0; i < 6; i++){if (roles[i] != null && roles[i].getName() == name){RoleModel res = roles[i];roles[i] = null;return res;}}return null;}
}

​ BoatModel:控制船模型。BoatModel中含括了船移动的函数,由于一条船只能承载两个Role,所以使用getEmptyNumber()函数判断船是否满员。同时使用与上面LandModel中类似的函数进行上下船操作。同时使用了两个固定的位置作为船移动的起点终点进行船的移动。

public class BoatModel
{Boat boat;List<RoleModel> roles = new List<RoleModel>(){null,null,null,null,null,null};Move move;Click click;public BoatModel(){boat = new Boat();move = boat.obj_boat.AddComponent(typeof(Move)) as Move;click = boat.obj_boat.AddComponent(typeof(Click)) as Click;click.setBoat(this);}public int getBoatSign(){return boat.boatSign;}public int getEmptyNumber(){for (int i = 0; i < 2; i++){if (roles[i] == null)return i;}return -1;}public Vector3 getEmptyPos(){Vector3 res;if (boat.boatSign == 1) res = boat.startPos[getEmptyNumber()];else res = boat.endPos[getEmptyNumber()];return res;}public int[] getRoleNum(){int[] res = { 0, 0 };for (int i = 0; i < 2; i++){if (roles[i] != null){if (roles[i].getSign() == 0) res[0]++;else res[1]++;}}return res;}public void addRole(RoleModel role){roles[getEmptyNumber()] = role;}public RoleModel deleteRole(string name){for (int i = 0; i < 2; i++){if (roles[i] != null && roles[i].getName() == name){RoleModel res = roles[i];roles[i] = null;return res;}}return null;}public void boatMove(){if (boat.boatSign == -1) move.MovePosition(new Vector3(5, 0.5f, 0));else move.MovePosition(new Vector3(-5, 0.5f, 0));boat.boatSign *= -1;}public GameObject getBoat(){return boat.obj_boat;}public bool empty(){for (int i = 0; i < 2; i++){if (roles[i] != null) return false;}return true;}
}

​ RoleModel:Role模型的移动以及判断大部分代码都在上面的LandModel和BoatModel中实现,所以此处RoleModel中大部分函数都是对上面进行的移动以及判断提供必要的返回值和对一部分数据进行重设

public class RoleModel
{Role role;Move move;Click click;public RoleModel(string name, Vector3 pos){role = new Role(name, pos);move = role.obj_role.AddComponent(typeof(Move)) as Move;click = role.obj_role.AddComponent(typeof(Click)) as Click;click.setRole(this);}public string getName(){return role.obj_role.name;}public int getLandSign(){return role.landSign;}public void setLandSign(int land){role.landSign = land;}public int getSign(){return role.roleSign;}public int getOnBoat(){return role.onBoat;}public void setOnBoat(int a){role.onBoat = a;}public void setName(string name){role.obj_role.name = name;}public GameObject getRole(){return role.obj_role;}public void roleMove(Vector3 pos){move.MovePosition(pos);}
}

FirstController

​ FirstController负责游戏中第一个场景的搭载,即Start(),在其中调用LoadResoureces()动态生成本次项目的场景。在FirstController之中还编写了MoveRole()MoveBoat()实现游戏项目之中仅有的两种操作。同时也在FirstController中实现了游戏成败的判断,以及重新开始按钮的实现

using UnityEngine.SceneManagement;
using UnityEngine;
using ModelApplication;
using ControllerApplication;
using InterfaceApplication;
using System.Collections.Generic;public class FirstController : MonoBehaviour, ISceneController, IUserAction
{public LandModel startLand;public LandModel endLand;public Water water;public BoatModel boat;public List<RoleModel> roles;public UserGUI GUI;// 资源加载public void LoadResoureces(){water = new Water();startLand = new LandModel("start");endLand = new LandModel("end");boat = new BoatModel();roles = new List<RoleModel>();for (int i = 0; i < 3; i++){RoleModel role = new RoleModel("priest", startLand.getEmptyPos());role.setName("priest" + i);startLand.addRole(role);roles.Add(role);}for (int i = 0; i < 3; i++){RoleModel role = new RoleModel("devil", startLand.getEmptyPos());role.setName("devil" + i);startLand.addRole(role);roles.Add(role);}}// 移动船public void moveBoat(){if (boat.empty() || GUI.sign != 0) return;boat.boatMove();GUI.sign = check();}// 移动角色public void moveRole(RoleModel role){if (GUI.sign != 0) return;if (role.getOnBoat() == 1){boat.deleteRole(role.getName());role.setOnBoat(0);role.getRole().transform.parent = null;if (boat.getBoatSign() == 1){role.roleMove(startLand.getEmptyPos());role.setLandSign(1);startLand.addRole(role);}else{role.roleMove(endLand.getEmptyPos());role.setLandSign(-1);endLand.addRole(role);}}else{if (role.getLandSign() == 1){if (boat.getEmptyNumber() == -1 || role.getLandSign() != boat.getBoatSign()) return;startLand.deleteRole(role.getName());role.roleMove(boat.getEmptyPos());role.getRole().transform.parent = boat.getBoat().transform;role.setOnBoat(1);boat.addRole(role);}else{if (boat.getEmptyNumber() == -1 || role.getLandSign() != boat.getBoatSign()) return;endLand.deleteRole(role.getName());role.roleMove(boat.getEmptyPos());role.getRole().transform.parent = boat.getBoat().transform;role.setOnBoat(1);boat.addRole(role);}}GUI.sign = check();}// 重新开始public void reStart(){SceneManager.LoadScene(0);}// 游戏进度判断public int check(){int[] boatRole = boat.getRoleNum();Debug.Log(string.Format("{0},{1}",boatRole[0],boatRole[1]));int[] startRole = startLand.getRoleNum();Debug.Log(string.Format("{0},{1}",startRole[0],startRole[1]));int[] endRole = endLand.getRoleNum();Debug.Log(string.Format("{0},{1}",endRole[0],endRole[1]));if (endRole[0] + endRole[1] == 6) return 1;if (boat.getBoatSign() == 1){startRole[0] += boatRole[0];startRole[1] += boatRole[1];}else{endRole[0] += boatRole[0];endRole[1] += boatRole[1];}if ((endRole[0] > 0 && endRole[1] > endRole[0]) || (startRole[0] > 0 && startRole[1] > startRole[0]))return -1;return 0;}// 游戏开始void Start(){SSDirector director = SSDirector.GetInstance();director.CurrentSceneController = this;GUI = gameObject.AddComponent<UserGUI>() as UserGUI;LoadResoureces();}
}

ClickController

​ Click类负责检测船和角色是否被点击,通过ModelController中相关函数的调用来响应用户的点击以进行游戏

public class Click : 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);}
}

Interface

​ 其中包含两个类,为其他类提供接口。其中ISceneController提供场景接口,实现场景的生成;IUserAction提供用户交互接口,包括移动船、移动人物、重开、检查游戏状态的函数

using ControllerApplication;
namespace InterfaceApplication
{public interface ISceneController{void LoadResoureces();}public interface IUserAction{void moveBoat();void moveRole(RoleModel role);void reStart();int check();}
}
3. View

OnGui

​ Views搭建游戏的UI,设置UI与用户进行交互,主要为重新开始按钮,以及游戏成功与失败的提示。

using UnityEngine;
using InterfaceApplication;public class UserGUI : MonoBehaviour
{public IUserAction action;public int sign = 0;void Start(){action = SSDirector.GetInstance().CurrentSceneController as IUserAction;}void OnGUI(){GUIStyle text_style;GUIStyle button_style;GUIStyle titleStyle;text_style = new GUIStyle(){fontSize = 30,alignment = TextAnchor.MiddleCenter,};button_style = new GUIStyle("button"){fontSize = 15,alignment = TextAnchor.MiddleCenter,};titleStyle = new GUIStyle(){fontSize = 40,alignment = TextAnchor.MiddleCenter,};titleStyle.normal.textColor = Color.black;if (sign == -1){GUI.Label(new Rect(0, 0, Screen.width, Screen.height * 0.5f), "Gameover!", text_style);}else if (sign == 1){GUI.Label(new Rect(0, 0, Screen.width, Screen.height * 0.5f), "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;}GUI.Label(new Rect(0, 0, Screen.width, Screen.height * 1.6f), "牧师与恶魔", titleStyle);}
}

运行效果

​ 运行效果如下:

​ (选择了简略抽象路线的牧师与魔鬼,白色正方体为牧师,红色球为魔鬼,棕色长方形为陆地,蓝色长方形为水,黄色长方形为船)

代码位置


​ 代码以及文档均已经上传至hw3 · XiaoChen04_3/3D_Computer_Game_Programming - gitee

​ Asset中包含了PriestsAndDevils和SolarSystem两个文件夹,分别为本次两道编程题目所对应的代码。

​ 查看代码效果,只需要将Assets文件夹复制到本地unity项目之中并打开对应Scene文件即可。

Unity学习记录——空间与运动相关推荐

  1. Unity学习记录——模型与动画

    Unity学习记录--模型与动画 前言 ​ 本文是中山大学软件工程学院2020级3d游戏编程与设计的作业7 编程题:智能巡逻兵 1.学习参考 ​ 除去老师在课堂上讲的内容,本次作业代码与操作主要参考了 ...

  2. unity学习记录第九章-过关和UI

    unity学习记录第九章 要点 胜利过关 UI文本 笔记 1.创建一个脚本控制开门动画 2.在GameMannager里设置一个类类型的变量,用来传递方法 3.当列表中的收集物为0时开门通关 4.使用 ...

  3. unity 学习记录

    世界第九条约定 缘起 嗯,其实一开始我知道unity是个弄游戏的,也知道好像神庙逃亡,炉石都是出自unity,然后舍友都报了,我也觉得这个东西挺高大上的,所以忍不住自己的双手,报了名,确实,这能学到很 ...

  4. Unity学习记录:使用触发器制作人物靠近物体后交互的方法

    使用Tigger触发器来制作靠近后出现交互图标的方法 本文基于Unity2019.3.2f1版本 最近想做一个第一人称的游戏出来,关于人物与物体的交互想做成很多游戏都采用的,人物靠近到一定的距离就会在 ...

  5. Unity学习记录:制作双屏垃圾分类小游戏

    一:逻辑梳理 要实现的功能 游戏操作 在规定时间内,垃圾通过拖拽进入正确垃圾桶的容器,垃圾在这里消失,飞入第二个屏上对应垃圾桶的位置并实现加分和加时间的效果,垃圾拖拽进入不正确的垃圾桶,垃圾会返回到原 ...

  6. 【unity学习记录】TileMap基础知识(详细版)

  7. 空间计量模型学习记录

    空间计量模型学习记录 空间计量模型模型分类 OSL模型 空间滞后模型 空间误差模型 自变量空间滞后模型 空间杜宾模型 空间杜宾误差模型 操作方式参考 参考文章 空间自回归模型-OLS.SLM.SEM理 ...

  8. [Unity 学习] Unity 入门学习及第一个游戏

    [Unity 学习] Unity 入门学习及第一个游戏 跟着教程做的一个小游戏,基本上说就算我这样的零基础,两个小时就能实现. 主要就是熟悉一下 C#和 Unity,做一个能跑的东西. 简单的 Dem ...

  9. Enigma Protector脱壳学习记录

    Enigma Protector脱壳学习记录 空间 步聚: 1:由于ENG这个壳是由一个DLL来实现加壳,因此F2断点很容易被检测,所以下二次断点, 第一次下VirtualAlloc下断,断下后在40 ...

最新文章

  1. 如何查看自己在CSDN的排名
  2. Apache solr(二).
  3. pytorch已经安装成功了为什么不能使用import_使用auto keras的过程
  4. OpenGL中的二维编程——从简单的矩形开始
  5. 预充电电路工作原理_LED触摸调光台灯控制电路板的工作原理
  6. 4 月 10 截止 | 南开大学百名青年学科带头人孙宝发课题组招生
  7. Python3.5安装与ChatterBot聊天机器人使用
  8. DFS--01背包问题
  9. 数据挖掘之模型选择和融合
  10. 0405_hxtx_主题游常用联系人功能代码实现
  11. hdu 1010 Tempter of the Bone(dfs+奇偶剪枝)
  12. VM虚拟机系统时间同步网络时间并登录用户自动校正时间
  13. ARP 地址分类 NAT技术
  14. mPaaS 小程序新手指南 | 《mPaaS 小程序自定义开发》
  15. php中用div句子给背景图片添加文字,PHP给图片添加文字水印实例
  16. 【华录杯】深度学习吸烟打电话识别
  17. oracle用于限制分组函数的返回值,Oracle考试试题(带答案)
  18. 深度剖析QQ密码被盗原因
  19. 漫话:为什么生僻字计算机上打不出来,或者打出来也无法显示呢?
  20. EXCEL相对引用,绝对引用和混合引用的区别

热门文章

  1. 安卓手机由USB数据线通过电脑上网方法
  2. HTB-Popcorn
  3. 牛吃草问题(解系数方程)
  4. MySQL中日期和时间类型
  5. android简单布局素材(2)—渐出底部标题栏
  6. Linux小记--centos,debian系统挂载镜像方式
  7. 关联规则挖掘算法研究
  8. python自学训练营 免费_李笑来《Python入门自学训练营》课程全集下载链接 | 挖宝否...
  9. 错误HikariPool-1 - Exception during..+ Access denied for user ‘root‘@‘localhost‘ (using password: YES)
  10. xamarin Android 截屏,xamarin开发android收集的一些工具