github传送门:https://github.com/dongzizhu/unity3DLearning/tree/master/hw5/enhancedDisk
有关Rigibody
Rigidbody是Unity自带的物理引擎中的刚体组件,可以直接通过Add Component添加。
我们能够通过这个组件来让Object按照真实的物理规律运动。其中属性的含义以此是
- Mass 质量
- Drag 阻力
- Angular Drag 角阻力
- Use Gravity 使用重力
- Is Kinematic 是否运动学控制
- Interpolate 差值
- Collision Detection 碰撞检测
- Constraints 运动的自由度
- Info 运动的信息
本次完成的打飞碟小游戏升级版就应用到了Rigidbody来实现飞碟符合物理规律的运动。
Adapter模式
Adapter模式又称适配器模式,就是定义一个Adapter类,起到一个转换插头的作用,将原本不能用统一的代码来调用的多个类转换成成一样的接口,这样可以统一调用,是一种封装的常用做法。在本次的项目中,我们将物理模式和上一个版本的直接发射模式的两种AcitionManager都接上Adapter这个转换插头,然后在ActionManager中统一调用。
有关这个设计模式的具体讲解见链接:http://c.biancheng.net/view/1361.html,这个说的很清楚了。
打飞碟小游戏升级版
在上次时间直接位移的Emit.cs 后,这次我们利用Rigidbody来实现一个符合物理规律的移动方法。
// PhysicsEmit.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MyGame;
public class PhysicsEmit : SSAction
{
bool enableEmit = true;
Vector3 force;
float startX;
float targetZ = 50;
public FirstController sceneControler = (FirstController)Director.getInstance().sceneCtrl;
public override void Start() {
startX = 6 - Random.value * 12;
this.Transform.position = new Vector3(startX, 0, 0);
force = new Vector3(3 * Random.Range(-1, 1), 3 * Random.Range(0.5f, 5), 5 + 3 * sceneControler.user.round);
}
public static PhysicsEmit GetSSAction() {
PhysicsEmit action = ScriptableObject.CreateInstance<PhysicsEmit>();
return action;
}
public override void Update() {
if (!this.destroy) {
if (enableEmit) {
GameObject.GetComponent<Rigidbody>().useGravity = true;
GameObject.GetComponent<Rigidbody>().velocity = Vector3.zero;
GameObject.GetComponent<Rigidbody>().AddForce(force, ForceMode.Impulse);
enableEmit = false;
}
}
if (this.Transform.position.z >= targetZ || GameObject.GetComponent<DiskController>().hit) {
GameObject.SetActive(false);
GameObject.transform.position = new Vector3(startX, 0, 0);
sceneControler.factory.freeDisk(GameObject);
this.destroy = true;
this.Callback.ActionDone(this);
GameObject.GetComponent<DiskController>().hit = false;
}
}
}
其中核心的部分就是一下三句。
GameObject.GetComponent<Rigidbody>().useGravity = true;
GameObject.GetComponent<Rigidbody>().velocity = Vector3.zero;
GameObject.GetComponent<Rigidbody>().AddForce(force, ForceMode.Impulse);
第一句将useGravity设为true,那么当前GameObject就会一直受到一个向下的重力;第二句,将当前的GameObject的速度重置为0,因为是从工厂模式的free队列中取出来的,所以如果不置零则会保留之前的速度;最后一句通过AddForce给当前物体加上一个瞬间的力从而给予其一个初始速度。
其中ForceMode一共有四种:
- ForceMode.Force:给物体添加一个持续的力并使用其质量。
- ForceMode.Acceleration::给物体添加一个持续的加速度,但是忽略其质量。
- ForceMode.Impulse;:给物体添加一个瞬间的力并使用其质量
- ForceMode.VelocityChange;:给物体添加一个瞬间的加速度,但是忽略其质量
另外,Adapter的代码如下:
public class ActionManagerAdapter {
ActionManager normalAM;
PhysicsActionManager PhysicsAM;
public int mode = 0; // 0->normal, 1->physics
public ActionManagerAdapter(GameObject main) {
normalAM = main.AddComponent<ActionManager>();
PhysicsAM = main.AddComponent<PhysicsActionManager>();
mode = 0;
}
public void SwitchActionMode() {
mode = 1 - mode;
}
public void PlayDisk(int round) {
if (mode == 0) {
Debug.Log("normalAM");
normalAM.playDisk(round);
}
else {
Debug.Log("physicsAM");
PhysicsAM.playDisk(round);
}
}
public void SetNormalAM(ActionManager am) {
normalAM = am;
}
public void SetPhysicsAM(PhysicsActionManager pam) {
PhysicsAM = pam;
}
public ActionManager GetNormalAM() {
return normalAM;
}
public PhysicsActionManager GetPhysicsAM() {
return PhysicsAM;
}
}
这样在firstConctrl调用playDisk的时候,由Adapter根据此时的mode来选择射出的飞碟是什么模式的;这样来将两种飞碟封装起来,实现统一调用。
其他的改动就是增加一个PhysicsActionManager,代码与原来的ActionManager几乎一样,只不过是调用了PhysicsEmit来执行Action而已;然后在FirstController以及一些其他的地方将ActionManager改为Adapter。这里代码就不贴上来了,感兴趣的可以去github上查看。