1.简答并用程序验证
(1) 游戏对象运动的本质是什么?
游戏对象运动是游戏对象按照预设好的方式向某个方向、或者围绕某个物体进行运动,其本质是相对于原点坐标的位置的变化,体现在unity中就是transform中position的各个值的改变。
(2)请用三种方法以上方法,实现物体的抛物线运动。
a.创建一个新的vector3属性
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class move1 : MonoBehaviour
{
int speed;
// Start is called before the first frame update
void Start()
{
speed = 1;
}
// Update is called once per frame
void Update()
{
float x = this.transform.position.x;
float newX = x + speed*Time.deltaTime;
this.transform.position = new Vector3(newX, newX*(newX-4));
}
}
效果如下:
b.直接修改position
由于抛体运动在水平方向上做匀速运动,在竖直方向上做匀加速运动,因此可以将其分解为这两个方向上的运动,然后再进行合成。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class move2 : MonoBehaviour
{
int speedx;
int speedy;
// Start is called before the first frame update
void Start()
{
speedx = 1;
speedy = -2;
}
// Update is called once per frame
void Update()
{
this.transform.position += Vector3.right*speedx;
this.transform.position += Vector3.up*speedy;
speedy++;
}
}
这种方式理论上可以实现抛体运动,但是由于Update函数的执行频率太高了,因此效果不明显,看到的就是物体一下就飞到很远的地方去了,因此就不放图了。
c.使用translate方法
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class move3 : MonoBehaviour
{
int speedx;
int speedy;
// Start is called before the first frame update
void Start()
{
speedx = 1;
speedy = -2;
}
// Update is called once per frame
void Update()
{
Vector3 move = new Vector3(Time.deltaTime*speedx, Time.deltaTime*speedy, 0);
speedy++;
transform.Translate(move);
}
}
其实和上一种方法十分类似,也是会因为update执行过快而无法看到效果。
代码传送门:GitHub
(3)写一个程序,实现一个完整的太阳系, 其他星球围绕太阳的转速必须不一样,且不在一个法平面上。
公转代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class revolution : MonoBehaviour
{
public Transform center;
public float speed;
public float x, y, z;
// Start is called before the first frame update
void Start()
{
x = Random.Range(20, 100);
y = Random.Range(20, 100);
z = Random.Range(20, 100);
speed = Random.Range(8, 25);
}
// Update is called once per frame
void Update()
{
this.transform.RotateAround(center.position, new Vector3(x,y,0), speed*Time.deltaTime);
}
}
可见使用了random函数来随机赋予法平面的角度(经过试验发现z=0效果较好)和公转速度,编写好脚本之后只需将其依次拉入已经创建好的“行星”,然后将center设为sun即可。
公转可以使用trail render特效来描绘出轨迹,利于观察,具体可参考博客介绍
效果:
自转代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class rotation : MonoBehaviour
{
public int speed;
// Start is called before the first frame update
void Start()
{
speed = Random.Range(4, 10);
}
// Update is called once per frame
void Update()
{
this.transform.RotateAround(this.transform.position, Vector3.up, speed*Time.deltaTime);
}
}
然后将自转代码拖到各个行星上即可。
但是此时发现背景太空了,因此还要给“模拟太阳系”添加一个背景图。
创建一个新的material,在shader属性中选Skybox/Panoramic,然后把自己想要的背景图片加上去:
然后在camera的add component中rendering添加skybox,在customer skybox中选择刚刚创建的background即可。
最终效果:
源代码传送门:Github
2. 编程实践——Priests and Devils
(1)列出游戏中提及的事物(Objects)
牧师、魔鬼、船、河岸、河
(2)用表格列出玩家动作表(规则表),注意,动作越少越好
角色 | 动作 |
---|---|
牧师/魔鬼 | 点击岸上的牧师/魔鬼,如果船当前在该角色的岸边且船上人数少于2则上船 |
牧师/魔鬼 | 点击船上的牧师/魔鬼,则牧师/魔鬼从船上转移到岸上 |
船 | 行驶到另一侧的河岸 |
(3)将游戏对象做成预设
(4)在场景控制器 LoadResources 方法中加载并初始化 长方形、正方形、球 及其色彩代表游戏中的对象。
public void LoadResources(){
Debug.Log("DD");
GameObject water = Instantiate(Resources.Load("Prefabs/Water", typeof(GameObject)), new Vector3(0,-1,0), Quaternion.identity) as GameObject;
water.name = "water";
start_land = new LandModel("start");
end_land = new LandModel("end");
boat = new BoatModel();
role = new RoleModel[6];
for (int i = 0; i < 3; i++){
RoleModel r = new RoleModel("priest");
r.SetName("priest" + i);
r.SetPosition(start_land.GetEmptyPosition());
r.GoLand(start_land);
start_land.AddRole(r);
role[i] = r;
}
for (int i = 3; i < 6; i++){
RoleModel r = new RoleModel("devil");
r.SetName("devil" + i);
r.SetPosition(start_land.GetEmptyPosition());
r.GoLand(start_land);
start_land.AddRole(r);
role[i] = r;
}
}
(5)使用 C# 集合类型 有效组织对象。整个游戏仅主摄像机和一个 Empty 对象, 其他对象必须代码动态生成!
(6)请使用课件架构图编程,不接受非 MVC 结构程序
M(Model):ModelController,其中实现了boat、land、role的各个函数。
V(View):UserGUI中实现了一个简易GUI。
C(Controller):SSDirector是创建导演,一个游戏只有一个;Controller是管理各个model之间的行为的类;
除此之外,Click是相应鼠标点击的类,InterfaceController是为了降低各个类的耦合而制作的接口,用于各个model之间的调用。
运行时只需要将controller拖入创建的空对象中即可。
源代码传送门:GitHub
最终效果:
获胜:
失败:
参考
https://blog.csdn.net/TempterCyn/article/details/101110379
由于我自己写的游戏最后还是有许多bug没有解决,最终是跟着这个师兄的思路完成的。
https://www.jianshu.com/p/07028b3da573
除此之外还有很多其他博客也给我提供了帮助,地址没有一一保存了。
3.思考题
使用向量与变换,实现并扩展 Tranform 提供的方法,如 Rotate、RotateAround 等。
Rotate:
void Rotate(Transform t,Vector3 axis,float angle){
var rot=Quaternion.AngleAxis(angle,axis);
t.rotation*=rot;
}
RotateAround:
void RotateAround(Transform t,Vector3 center,Vector axis,float angle){
var rot=Quaternion.AngleAxis(angle,axis);
t.position=(center+(t.position-center)*rot);
t.rotation=t.rotation*rot;
}(这里会报错?说position不能与rotation运算?)