文章目录
1、简答并用程序验证【建议做】
1.1 游戏对象运动的本质是什么?
游戏对象运动的本质是位移,也就是坐标的变换。一个对象的位置由(x,y,z,w)确定,当使用矩阵变换(平移、旋转、缩放)改变了其中的某个值,游戏对象就实现了运动。
1.2 请用三种方法以上方法,实现物体的抛物线运动。(如,修改Transform属性,使用向量Vector3的方法…)
- 直接修改Transform部件的Position属性
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class parabolicV : MonoBehaviour
{
public float dTime = 0f;//已经过去的时间
public float speedx0 = 5.0f;
public float speedy0 = 1.0f;
public float ay = 1.0f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
float time = dTime + Time.deltaTime;
float dx = speedx0 * Time.deltaTime;
float dy = (float)(speedy0 * Time.deltaTime + 0.5 * ay * (time * time - dTime * dTime));
this.transform.position += Vector3.right * dx;
this.transform.position += Vector3.down * dy;
dTime = time;
}
}
- 声明创建一个Vector3变量,用这个变量修改Transform部件的Position值
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class parabolicV : MonoBehaviour
{
public float dTime = 0f;//已经过去的时间
public float speedx0 = 5.0f;
public float speedy0 = 1.0f;
public float ay = 1.0f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
float time = dTime + Time.deltaTime;
float dx = speedx0 * Time.deltaTime;
float dy = (float)(speedy0 * Time.deltaTime + 0.5 * ay * (time * time - dTime * dTime));
this.transform.position += new Vector3(dx, -dy);
dTime = time;
}
}
- 利用transform中的translate函数来进行改变position,也要传入一个Vector3变量
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class parabolicTRANS : MonoBehaviour
{
public float dTime = 0f;//已经过去的时间
public float speedx0 = 5.0f;
public float speedy0 = 1.0f;
public float ay = 1.0f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
float time = dTime + Time.deltaTime;
float dx = speedx0 * Time.deltaTime;
float dy = (float)(speedy0 * Time.deltaTime + 0.5 * ay * (time * time - dTime * dTime));
this.transform.Translate(new Vector3(dx, -dy));
dTime = time;
}
}
1.3 写一个程序,实现一个完整的太阳系, 其他星球围绕太阳的转速必须不一样,且不在一个法平面上。
利用TransForm 部件中的两个函数
- public void Rotate(Vector3 eulers, Space relativeTo = Space.Self);
eulers:旋转的欧拉角,欧拉角(eulerAngles):x、y和z角表示围绕z轴的旋转z度、围绕x轴的旋转x度和围绕y轴的旋转y度。
relativeTo决定旋转相对于Space.Self(the local space and axes of the GameObject)还是Space.World(the space and axes in relation to the /Scene/)
用于实现星球自转 - public void RotateAround(Vector3 point, Vector3 axis, float angle);
围绕穿过point点的axis轴以angle速度转动
用于实现星球公转
- 创建星球
-
创建材料
-
创建游戏对象(按星球大小排序)
太阳系中对象组成空间树
使用预定义的材料
调整每个对象的大小
- 用程序规定对象的行为,实现一个完整的太阳系
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RoundSun : MonoBehaviour{
public Transform Sun, Mercury, Venus, Earth, Moon, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto;
Vector3 axisMercury, axisVenus, axisEarth, axisMoon, axisMars, axisJupiter, axisSaturn, axisUranus, axisNeptune, axisPluto;
// Use this for initialization
void Start()
{
Sun.position = Vector3.zero;
Mercury.position = new Vector3(8, 0, 0);
Venus.position = new Vector3(10, 0, 0);
Earth.position = new Vector3(15, 0, 0);
Moon.position = new Vector3((float)(17.05), 0, 0);
Mars.position = new Vector3(24, 0, 0);
Jupiter.position = new Vector3(34, 0, 0);
Saturn.position = new Vector3(44, 0, 0);
Uranus.position = new Vector3(51, 0, 0);
Neptune.position = new Vector3(55, 0, 0);
Pluto.position = new Vector3(58, 0, 0);
axisMercury = new Vector3(3, 11, 0);
axisVenus = new Vector3(2, 3, 0);
axisEarth = new Vector3(0, 1, 0);
axisMoon = Vector3.up;
axisMars = new Vector3(1, 5, 0);
axisJupiter = new Vector3(1, 5, 0);
axisSaturn = new Vector3(1, 9, 0);
axisUranus = new Vector3(2, 7, 0);
axisNeptune = new Vector3(1, 5, 0);
axisPluto = new Vector3(1, 3, 0);
}
// Update is called once per frame
void Update()
{
Mercury.RotateAround(Sun.position, axisMercury, 10 * Time.deltaTime);
Venus.RotateAround(Sun.position, axisVenus, 30 * Time.deltaTime);
Earth.RotateAround(Sun.position, axisEarth, 20 * Time.deltaTime);
Moon.RotateAround(Earth.position, Vector3.up, 359 * Time.deltaTime);
Mars.RotateAround(Sun.position, axisMars, 60 * Time.deltaTime);
Jupiter.RotateAround(Sun.position, axisJupiter, 5 * Time.deltaTime);
Saturn.RotateAround(Sun.position, axisSaturn, 6 * Time.deltaTime);
Uranus.RotateAround(Sun.position, axisUranus, 35 * Time.deltaTime);
Neptune.RotateAround(Sun.position, axisNeptune, 10 * Time.deltaTime);
Pluto.RotateAround(Sun.position, axisPluto, 20 * Time.deltaTime);
Mercury.Rotate(Vector3.up * 600 * Time.deltaTime);
Venus.Rotate(Vector3.up * 400 * Time.deltaTime);
Earth.Rotate(Vector3.up * 360 * Time.deltaTime); //自转
Moon.Rotate(Vector3.up * 1000 * Time.deltaTime);
Mars.Rotate(Vector3.up * 300 * Time.deltaTime);
Jupiter.Rotate(Vector3.up * 300 * Time.deltaTime);
Saturn.Rotate(Vector3.up * 200 * Time.deltaTime);
Uranus.Rotate(Vector3.up * 400 * Time.deltaTime);
Neptune.Rotate(Vector3.up * 500 * Time.deltaTime);
Pluto.Rotate(Vector3.up * 400 * Time.deltaTime);
}
}
将建立好的游戏对象赋给脚本中的变量
2、编程实践
阅读以下游戏脚本
Priests and Devils
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 over. You can try it in many > ways. Keep all priests alive! Good luck!
程序需要满足的要求:
- play the game ( http://www.flash-game.net/game/2535/priests-and-devils.html )
- 列出游戏中提及的事物(Objects)
- 用表格列出玩家动作表(规则表),注意,动作越少越好
- 请将游戏中对象做成预制
- 在场景控制器 LoadResources 方法中加载并初始化 长方形、正方形、球 及其色彩代表游戏中的对象。
- 使用 C# 集合类型 有效组织对象
- 整个游戏仅 主摄像机 和 一个 Empty 对象, 其他对象必须代码动态生成!!! 。 整个游戏不许出现 Find 游戏对象, SendMessage 这类突破程序结构的 通讯耦合 语句。 违背本条准则,不给分
- 请使用课件架构图编程,不接受非 MVC 结构程序
- 注意细节,例如:船未靠岸,牧师与魔鬼上下船运动中,均不能接受用户事件!
列出游戏中提及的事物(Objects)
左岸、右岸、船、牧师、恶魔
玩家动作表(规则表)
玩家动作 (事件) | 条件 | 结果(游戏对象动作) |
---|---|---|
点击岸上的角色 | 船靠角色所在岸且船上有空位 | 角色上船 |
点击船上的角色 | 角色上岸 | |
点击船 | 船上有角色 | 船开向对岸 |
重启游戏 | 游戏回到初始状态 |
将游戏中对象做成预制
LoadResources 方法动态加载游戏对象
GameObject bank = Instantiate<GameObject>(Resources.Load("Prefabs/bank"), new Vector3(-12, -1, 0), Quaternion.identity) as GameObject;
bank.name=leftbank;
以此类推
使用课件架构图编程
- 组织游戏资源
- 创建场景启动对象和控制器
构造 Main 空对象,并挂载 FirstController 代码,使得游戏加载行为在你的控制下。
注意细节,例如:船未靠岸,牧师与魔鬼上下船运动中,均不能接受用户事件!
在SSDirector类内添加成员
public bool moving=false;
移动开始时设为true,结束设为false
在UserGUI中,仅当游戏未结束且moving值为false时才接受用户事件
(但是不知道为什么没起作用
程序设计
使用MVC架构
- 模型(Model):场景中的所有GameObject
- 控制器(Controller):接受用户事件,控制模型的变化
- Director是最高层的控制器,通过一个抽象的场景接口访问不同场景,管理游戏全局状态
- 一个场景一个主控制器(XXXSceneController,例如 FirstSceneController),管理本次场景所有的游戏对象,响应外部输入事件
- 每个游戏对象由其控制器管理(“GameObject”+Controller)
- 至少实现与玩家交互的接口(IUserAction)
- 实现或管理运动(Move)
- 界面(View):显示模型,将人机交互事件交给控制器处理(UserGUI)
- 处收 Input 事件
- 渲染 GUI ,接收事件
接口
public interface ISceneController
定义场景的操作(加载资源、暂停、恢复等)
由不同的XXXSceneController多态实现并调用public interface IUserAction
为用户与游戏交互的接口,定义用户能进行的所有操作
被XXXGUI调用,由XXXSceneController 实现
SSDirector
职责如下
- 获取当前游戏的场景
- 控制场景运行、切换、入栈与出栈
- 暂停、恢复、退出
- 管理游戏全局状态
- 设定游戏的配置
- 设定游戏全局视图
它是单实例的。具有典型单实例类编程特征
它拥有一些全局属性,如 running,fps等,这样可以让任何地方的代码访问它
它继承至 C# 根对象,所以不会受 Unity 引擎管理,也不要加载
它通过一个抽象的场景接口访问不同场的场记(控制器)
例如:它不知道每个场景需要加载哪些资源
它可以与实现ISceneController
的不同场记对话
FirstController
- 实现接口
ISceneController
,IUserAction
中定义的所有函数 - 动态加载本场景中的所有游戏对象,通过对应的控制器(“GameObject”+Controller)管理本次场景所有的游戏对象
- 响应外部输入事件,渲染GUI (利用UserGUI)
"GameObject"+Controller
- 包括
CharactersController
,BoatController
,BankController
- 每个类中包含一个GameObject变量,即该控制器管理的游戏对象
- 包含控制所管理的游戏对象的逻辑(方法)
- 游戏对象之间的通讯只能由其各自的控制器通过
FirstController
进行消息传递
UserGUI
用户交互界面,接收用户传递的信息,将信息交由控制器处理,渲染 GUI,呈现结果
Move
用于挂载脚本组件,抽象出来的一个类,实现角色的移动功能(上船、下船)
失败
成功