转载链接:https://www.cnblogs.com/lyh916/p/10415954.html
[Unity算法]斜抛运动(变种)
之前的斜抛运动,如果运动到游戏中,显然是太呆板了,那么可以试着加入一些效果,让它看起来更生动一些,类似游戏中的击飞或者掉落效果:
1.在达到最高点的时间点±X的时间段内,会有“减速”效果,形成一种在空中停留的感觉
2.落地后,反弹一次,再落地,就像是与地面发生了碰撞
相关公式:
```csharp
using System;
using UnityEngine;
public class ObliqueThrow : MonoBehaviour {
private float gravity; //重力加速度(当前)
private float gravityValue = -9.8f; //重力加速度值1
private Vector2 horizontalDir; //水平方向
private float startSpeed; //初速度
private float sinValue; //sin值
private float cosValue; //cos值
private Vector3 startPos; //开始位置
private float endY; //结束高度(地面高度)
private float timer; //运动消耗时间
private Action<GameObject> finishCallBack; //落地后的回调
private bool canMove = false; //能否运动
private float timeScale = 1; //时间系数
private float reboundTimes = 1; //反弹次数
private bool isInRebound = false; //是否在反弹中
private float lastX; //落地点x
private float lastZ; //落地点z
private float hightestPointTime; //到达最高点所用的时间
private float hightestPointStayTime = 0.1f; //最高点减速范围的时间段
void Update()
{
if (!canMove)
{
return;
}
//移动过程
timer = timer + Time.deltaTime * timeScale;
float xOffset = startSpeed * timer * cosValue * horizontalDir.x;
float zOffset = startSpeed * timer * cosValue * horizontalDir.y;
float yOffset = startSpeed * timer * sinValue + 0.5f * gravity * timer * timer;
Vector3 endPos;
if (!isInRebound) //非反弹过程
{
endPos = startPos + new Vector3(xOffset, yOffset, zOffset);
if (Mathf.Abs(timer - hightestPointTime) < hightestPointStayTime)
{
timeScale = 0.5f;
}
else
{
timeScale = 1f;
}
}
else //反弹过程
{
endPos = new Vector3(lastX, yOffset, lastZ);
}
//落地
if (endPos.y < endY)
{
endPos.y = endY;
reboundTimes = reboundTimes - 1;
if (reboundTimes < 0) //移动结束
{
canMove = false;
}
else //落地反弹
{
gravity = gravityValue * 2;
horizontalDir = Vector2.zero;
startSpeed = startSpeed * 0.8f;
sinValue = 1;
cosValue = 0;
timer = 0;
isInRebound = true;
lastX = endPos.x;
lastZ = endPos.z;
}
}
transform.position = endPos;
//移动结束
if (!canMove)
{
finishCallBack(gameObject);
Destroy(this);
}
}
public void StartMove(Vector2 horizontalDir, float startSpeed, float angle, float endY, Action<GameObject> finishCallBack)
{
gravity = gravityValue;
this.horizontalDir = horizontalDir;
this.startSpeed = startSpeed;
sinValue = Mathf.Sin(Mathf.Deg2Rad * angle);
cosValue = Mathf.Cos(Mathf.Deg2Rad * angle);
startPos = transform.position;
this.endY = endY;
timer = 0;
this.finishCallBack = finishCallBack;
canMove = true;
hightestPointTime = Mathf.Abs(startSpeed * sinValue / gravity);
}
}
using UnityEngine;
using System.Collections.Generic;
public class TestThrow : MonoBehaviour {
public GameObject testGo;
private bool isDebug = false;
private List<GameObject> drawGoList = new List<GameObject>();
void Update ()
{
if (Input.GetKeyDown(KeyCode.Q))
{
//半径为1的方向圆
float randomNum = Random.Range(0f, 1f);//[0, 1]
float x = randomNum * 2 - 1;//[-1, 1]
float z = Mathf.Sqrt(1 - x * x);
if (Random.Range(0f, 1f) > 0.5f)
{
z = -z;
}
isDebug = true;
ObliqueThrow obliqueThrow = testGo.AddComponent<ObliqueThrow>();
obliqueThrow.StartMove(new Vector2(1, 0), 5f, 45f, 0f, (go) => {
isDebug = false;
Debug.Log("移动结束");
});
}
else if(Input.GetKeyDown(KeyCode.W))
{
testGo.transform.position = new Vector3(0f, 5f, 0f);
for (int i = 0; i < drawGoList.Count; i++)
{
Destroy(drawGoList[i]);
}
drawGoList.Clear();
}
if (isDebug)
{
GameObject go = GameObject.CreatePrimitive(PrimitiveType.Sphere);
go.transform.position = testGo.transform.position;
go.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
drawGoList.Add(go);
}
}
}