3D游戏(6)——物理系统与碰撞

1、改进飞碟(Hit UFO)游戏:

游戏内容要求

  1. adapter模式 设计图修改飞碟游戏
  2. 使它同时支持物理运动与运动学(变换)运动

游戏设计

这一次作业是在上一次作业的基础上做改进的,因而直接延用上一次的代码

适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。

因而,新的设计就如下图所示:

在这里插入图片描述

在这里,我的RoundController直接就是FirstController了。虽然分离出一个新的类也不是什么困难的事

因而,直接设计一个IActionManager接口,

public interface IActionManager
{
    void Fly(GameObject obj, float speed, Vector3 direction);
}

以往的CCActionManager并不需要大变动,只是要实现这个IActionManager接口

在这里插入图片描述

因为以往的是运动学(变换)运动,现在要做的是同时支持物理运动与运动学(变换)运动,因而先前的CCFlyActionStart函数需要设置为运动学(变换)运动。

public override void Start()
{
    gameObject.GetComponent<Rigidbody>().isKinematic = true;
}

同理,在之后的物理运动里面需要将isKinematic设置为false。

接下来,要实现的就是物理运动了,要实现PhysisActionManagerPhysisFlyAction了。实质上,跟先前的CCActionManagerCCFlyAction并没有什么太大的区别,就连代码也只是直接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();
}

在这里插入图片描述

加了刚体属性之后,玩法倒是跟之前一样,只不过呢,,,刚体就会有碰撞,会出现两个飞碟之间发发生碰撞的情况,撞完之后就会有翻滚,看起来也异常的逗。

我的完整代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值