游戏开发中的物理抛物运动

一、理解抛物线

  • 抛射物是在上抛过程中受到唯一重力影响。举一个抛射物的例子,一颗从加农炮中射出的炮弹;一块被扔到空中的石头;或者一个从桌边掉落的小球;这些物体走过的曲线路径称之为运动轨迹。当空气阻力被忽略时,其运动的路径是抛物线形状。

二、抛物运动的分类

许多类型的抛物运动不仅遵循垂直运动,也遵循水平运动。也就是说,抛物运动在水平方向移动的同时,也在做垂直方向的运动。表明抛物运动包含水平和垂直两方向的运动。

  • 垂直运动(上抛)

在垂直运动过程中,重力作用于物体,并给与物体一个反方向的加速度“-9.8m/s²"(地球的重力加速度)。这就意味着物体的速度在单位时间内降低”-9.8m/s²“。自由落地的速度为:

V y = g t V_y=gt

如果物体具有初速度,那么下落物体的速度方程为(g的值为-9.8m/s²):

V y = V 0 + g t ; V_y=V_0+gt;

自由落体的距离公式为:

S = 1 / 2 g t 2 S=1/2*g*t^2

基于物体具有初速度的情况,物体的位移公式为:

S v = V 0 t 1 / 2 g t 2 S_v=V_0t-1/2*g*t^2

此为物体的上抛运动,重力方向向下。

  • 水平运动

在水平运动过程中,运动将是恒定的,因为没有力作用于物体(忽略空气阻力)。因此,速度在水平方向的分量是恒定的,其加速度为0,则水平方向的位移公式为:

S h = V 0 t S_h=V_0*t


三、具体实现

下方的C#代码将展示当加农炮发射炮弹时,炮弹的运动轨迹。

添加下面的脚本到一个加农炮对象上。为炮弹和轨迹点制作预制件(prefab),它们将会在运行时被实例化,炮弹必须具有Collider组件和Rigidbody组件

截图


在这里插入图片描述

  • 核心代码如下所示:
/// <summary>
	/// 设置弹道点的位置
	/// </summary>
	/// <param name="startPos">炮弹的起始坐标</param>
	/// <param name="pVelocity">炮弹在对应时间点的速度</param>
	public void SetTrajectPointPos(Vector3 startPos,Vector3 pVelocity){

		float velocity=Mathf.Sqrt((pVelocity.x*pVelocity.x)+(pVelocity.y*pVelocity.y));
		float angle=Mathf.Atan2(pVelocity.y,pVelocity.x)*Mathf.Rad2Deg;

		float stepTime=0;
		stepTime+=0.1f;

		for (int i = 0; i < trajectPointsList.Count; i++)
		{
			float dx=velocity*stepTime*Mathf.Cos(angle*Mathf.Deg2Rad);
			float dy=velocity*stepTime*Mathf.Sin(angle*Mathf.Deg2Rad)-			
			(Physics.gravity.magnitude*stepTime*stepTime/2);
			Vector3 pos=new Vector3(startPos.x+dx,startPos.y+dy,2);
			trajectPointsList[i].transform.position=pos;
			trajectPointsList[i].GetComponent<SpriteRenderer>().enabled=true;
			trajectPointsList[i].transform.eulerAngles=
			new Vector3(0,0,
			Mathf.Atan2(pVelocity.y - (Physics.gravity.magnitude)*stepTime,pVelocity.x)*
			Mathf.Rad2Deg);
			stepTime+=0.1f;
		}
	}
  • 大致思路如下图:

在这里插入图片描述

  • 发射控制的核心代码如下
void Update () {
		if (isFalling) return;
		if (Input.GetMouseButtonDown (0)) {
			isPressed = true;
			if (currentBulletObj == null) {
				currentBulletObj = CreateBullet (cannonTrans.position);
			}
		} else if (Input.GetMouseButtonUp (0)) {
			if (currentBulletObj == null) return;
			isPressed = false;
			if (isFalling == false) {
				FireBullet (CalculationFireForce (currentBulletObj.transform.position,
					Camera.main.ScreenToWorldPoint (Input.mousePosition)));
			}
		}
		if (isPressed) {
		Vector3 direction = CalculationFireForce (currentBulletObj.transform.position,
			Camera.main.ScreenToWorldPoint (Input.mousePosition));
			float angle = Mathf.Atan2 (direction.y, direction.x) * Mathf.Rad2Deg;
			cannonTrans.eulerAngles = new Vector3 (0, 0, angle);
			parabolaController.SetTrajectPointPos (cannonTrans.position, 
			direction / currentBulletObj.GetComponent<Rigidbody> ().mass);
		}
	}
	/// <summary>
	/// 计算发射时,鼠标按下位置到炮弹初始位置的向量(方向)
	/// </summary>
	/// <param name="fromPos">炮弹的位置</param>
	/// <param name="toPos">鼠标按下时的位置</param>
	/// <returns></returns>
	private Vector2 CalculationFireForce (Vector3 fromPos, Vector3 toPos) {
		return (new Vector2 (toPos.x, toPos.y) - 
		new Vector2 (fromPos.x, fromPos.y)) * firePower;
	}

自此,实现的大致思路就是这样,具体大家可以在公众号里下载Demo研究下。

翻译自: http://www.theappguruz.com/blog/display-projectile-trajectory-path-in-unity

  • 代码做了一些修改。运行环境Unity 2017-4.10

扫码关注->历史消息->当前文章->末尾->Demo地址:


在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/JianZuoGuang/article/details/88355142