3D游戏(6)——物理系统与碰撞
文章目录
1、改进飞碟(Hit UFO)游戏:
游戏内容要求
- 按 adapter模式 设计图修改飞碟游戏
- 使它同时支持物理运动与运动学(变换)运动
游戏设计
这一次作业是在上一次作业的基础上做改进的,因而直接延用上一次的代码。
适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
因而,新的设计就如下图所示:
在这里,我的RoundController
直接就是FirstController
了。虽然分离出一个新的类也不是什么困难的事
因而,直接设计一个IActionManager
接口,
public interface IActionManager
{
void Fly(GameObject obj, float speed, Vector3 direction);
}
以往的CCActionManager
并不需要大变动,只是要实现这个IActionManager
接口
因为以往的是运动学(变换)运动,现在要做的是同时支持物理运动与运动学(变换)运动,因而先前的CCFlyAction
的Start函数需要设置为运动学(变换)运动。
public override void Start()
{
gameObject.GetComponent<Rigidbody>().isKinematic = true;
}
同理,在之后的物理运动里面需要将isKinematic设置为false。
接下来,要实现的就是物理运动了,要实现PhysisActionManager
和PhysisFlyAction
了。实质上,跟先前的CCActionManager
和CCFlyAction
并没有什么太大的区别,就连代码也只是直接copy过去再稍微修改的。
public class PhysisActionManager : SSActionManager, ISSActionCallback, IActionManager
{
public PhysisFlyAction flyAction;
public FirstController controller;
protected new void Start()
{
controller=SSDirector.getInstance().currentSceneController as FirstController;
}
public void Fly(GameObject obj, float speed, Vector3 direction){
flyAction=PhysisFlyAction.GetSSAction(direction,speed);
this.RunAction(obj,flyAction,this);
}
public void SSActionEvent(SSAction source,
SSActionEventType events=SSActionEventType.Competed,
int intParam=0,
string strParam=null,
Object objectParam=null){
controller.ufoFactory.FreeUFO(source.gameObject);
}
}
copy先前的CCActionManager再改改变量名就好了。
public class PhysisFlyAction : SSAction
{
float speed;
Vector3 direction;
public static PhysisFlyAction GetSSAction(Vector3 direction, float speed){
PhysisFlyAction action = ScriptableObject.CreateInstance<PhysisFlyAction>();
action.speed = speed;
action.direction = direction;
return action;
}
// Start is called before the first frame update
public override void Start()
{
gameObject.GetComponent<Rigidbody>().isKinematic = false;
gameObject.GetComponent<Rigidbody>().velocity = speed * direction;
}
// Update is called once per frame
public override void Update()
{
if (this.transform.position.y<-10){
this.destroy=true;
this.enable=false;
this.callback.SSActionEvent(this);
}
}
}
至于物理运动的话,就不用像先前那样计算一系列的变换,而只需要加初速度,加重力就可以了。
如此一来,物理运动与运动学(变换)运动都实现好了。接下来只需要实现这两者的变换即可。
IUserAction
需要新增一个模式转换的接口。
public interface IUserAction
{
void Restart();
void ChangeMode();
//void Check();
}
然后在FirstController
里面,通过IActionManager
接口来实现两种运动模式的转换。
private int model;
private IActionManager actionManager;
public void ChangeMode(){
model=1-model;
if(model==0){
actionManager=this.gameObject.GetComponent<CCActionManager>();
}
else{
actionManager=this.gameObject.GetComponent<PhysisActionManager>();
}
}
FirstController
完整代码:
public class FirstController : MonoBehaviour, ISceneController, IUserAction {
private bool isRuning;
public UFOFactory ufoFactory;
private int[] roundUFOs;
private int score;
private int round;
private int trial;
private float sendTime;
private int model;
private IActionManager actionManager;
// the first scripts
void Awake () {
SSDirector director = SSDirector.getInstance ();
director.setFPS (60);
director.currentSceneController = this;
director.currentSceneController.LoadResources ();
this.gameObject.AddComponent<UserGUI>();
this.gameObject.AddComponent<CCActionManager>();
this.gameObject.AddComponent<PhysisActionManager>();
ufoFactory=UFOFactory.getInstance();
roundUFOs=new int[]{2,3,3,4,4,4,5,5,5,5};
score=round=trial=0;
sendTime=0;
model=0;
actionManager=this.gameObject.GetComponent<CCActionManager>();
}
// loading resources for the first scence
public void LoadResources () {
isRuning=true;
}
public void SendUFO(){
GameObject ufo=ufoFactory.GetUFO(round);
ufo.transform.position=new Vector3(ufo.GetComponent<UFOData>().direction.x>0? -9:9,UnityEngine.Random.Range(0f,8f),0);
ufo.SetActive(true);
actionManager.Fly(ufo,ufo.GetComponent<UFOData>().speed,ufo.GetComponent<UFOData>().direction);
}
public bool GetIsRuning(){
return isRuning;
}
public void JudgeCallback(bool isRuning,int score){
this.score+=score;
this.gameObject.GetComponent<UserGUI>().score=this.score;
this.isRuning=isRuning;
}
public void Pause ()
{
throw new System.NotImplementedException ();
}
public void Resume ()
{
throw new System.NotImplementedException ();
}
#region IUserAction implementation
public void Restart ()
{
isRuning=true;
this.gameObject.GetComponent<UserGUI>().gameMessage="";
this.gameObject.GetComponent<UserGUI>().score=0;
score=round=trial=0;
sendTime=0;
ufoFactory.FreeALL();
}
public void ChangeMode(){
model=1-model;
if(model==0){
actionManager=this.gameObject.GetComponent<CCActionManager>();
}
else{
actionManager=this.gameObject.GetComponent<PhysisActionManager>();
}
}
#endregion
// Use this for initialization
void Start () {
//give advice first
}
// Update is called once per frame
void Update () {
//give advice first
if(isRuning){
sendTime+=Time.deltaTime;
if(sendTime>1){
sendTime=0;
int count=(int)UnityEngine.Random.Range(0f,roundUFOs[round]);
for(int i=0;i<count;i++){
SendUFO();
}
if(round==9){
gameObject.GetComponent<UserGUI>().gameMessage = "Game Over!";
isRuning=false;
}
if(trial==10){
round++;
trial=0;
}
else trial++;
}
}
}
}
最后,在UserGUI
里面新增一个模式转换的按钮就大功告成了。
string tempStr;
if (model==0) {
tempStr = "Kinematics";
}
else {
tempStr = "Physis";
}
if (GUI.Button(new Rect(width * 2, 0, width, height), tempStr)) {
model = 1-model;
action.ChangeMode();
}
加了刚体属性之后,玩法倒是跟之前一样,只不过呢,,,刚体就会有碰撞,会出现两个飞碟之间发发生碰撞的情况,撞完之后就会有翻滚,看起来也异常的逗。