模拟小球的抛物线运动,如图所示:
这里有点像打台球游戏,模拟在发射之前模拟其轨迹。
划线用的是LineRenderer,不清楚的童鞋可以自行查阅咯。其实也很简单就是挂个LineRenderer脚本,设置它的坐标点就行了,关键是这坐标点如何计算的问题了。
高中物理知识,科普一波 首先位移公式,S = V0t+1/2at^2。此次位移的分解,物体在Y轴方向做加速度为重力加速度g的加速运动,在X轴方向匀速运动。则物体在X轴的位移为:Sx=Vxt ,Y轴位移Sy = Vyt+1/2gt^2。
知道公式之后,我们就可以按时间点计算物体的位移了,而unity中都是用坐标表示那么这种公式转换为代码的逻辑就更加简单了:
int posCount = 50;
List<Vector3> posList = new List<Vector3>();
for (int i = 1; i < posCount ; i++)
{
float x = Vec0.x * deltaTime*i;
float y = 1f / 2f * Physics.gravity.y * Mathf.Pow(deltaTime, 2) + Vec0.y * deltaTime*i;
posList.Add(oldPos + new Vector2(x, y));
}
这样就计算了出来了50个点,将这50个点全部赋值给LineRenderer就基本模拟完成了。
public void SetPoint(List<Vector2> posList)
{
lineRenderer.positionCount = posList.Count;
for (int i = 0; i < posList.Count; i++)
{
lineRenderer.SetPosition(i, posList[i]);
}
}
为什么要说基本完成呢,这种模拟只是模拟球的最开始的轨迹,在游戏中球会发生碰撞,碰撞之后会反弹,那么这种反弹的轨迹如何实现呢?如图:
首先要知道球在什么时候发生碰撞,碰撞的面法向量是啥?如果知道面的法向量,入射角那么就可以求出线的反射角了。如何知道在什么时候发生碰撞呢?
这里我用的方法是计算每一段时间球的位移,将这一段时间的位移看作是直线,然后利用unity提供的射线来检测是否碰撞,这种方法由于每一段是直线所以检测出来碰撞值也是近似值,当然也没有考虑球碰撞时的摩擦力对球的影响,总之算是一个粗略的解决方法,如果大家有什么更好的方法,希望评论告知,在下感激不尽,首先抛砖迎玉,实现的具体代码如下:
public List<Vector2> CalculateTrajectory(Vector2 startVel)
{
List<Vector2> posList = new List<Vector2>();
Vector2 curPos = Vector2.zero;
Vector2 changePos = Vector2.zero;
float detlaTime =0.01f;
Vector2 vel0 = startVel;
Vector2 nextPos = Vector2.zero;
int timeCount = 0;
Vector2 direction = startVel.normalized; //速度的实时方向
for (int i = 0; i < 100; i++)
{
//总的时间
float time = detlaTime * timeCount;
float x = vel0.x * time;
float y = 1f / 2f * Physics.gravity.y * Mathf.Pow(time, 2) + vel0.y * time;
nextPos = changePos + new Vector2(x, y);
// Ray ray = new Ray(curPos + (Vector2)OriginalPos, curSpeedVec);
direction = new Vector2(vel0.x, Physics.gravity.y * time + vel0.y).normalized;
RaycastHit hit;
if (Physics.SphereCast(curPos + (Vector2)OriginalPos, ballCollider.radius, direction, out hit, Vector2.Distance(curPos, nextPos), ~LayerMask.GetMask("Ball")))
{
Vector2 N = hit.normal;
changePos = nextPos;// hit.point - OriginalPos + hit.normal * ballCollider.radius;
vel0 = new Vector2(vel0.x, Physics.gravity.y * time + vel0.y);
vel0 = vel0 - 2 * (Vector2.Dot(vel0, N)) * N;//改变初始度
timeCount = 0;
}
timeCount++;
posList.Add(curPos + (Vector2)OriginalPos);
curPos = nextPos;
}
return posList;
}