Unity 2019.3.7f1 2D愤怒小鸟式发射轨迹线弯曲问题排查
嘿,我来帮你搞定这个2D抛物线路径的问题!你要的是愤怒小鸟那种拉拽蓄力后的精确轨迹,还要带碰撞检测和长度控制,现在代码只能画直线对吧?没问题,咱们一步步把它改好。
修复方案:2D抛物线路径绘制 + 碰撞检测
核心原理
咱们要模拟的是恒定重力下的抛体运动,物理公式很清晰:
- 水平方向(X轴):因为无摩擦,所以是匀速运动,位置随时间线性变化
- 垂直方向(Y轴):受恒定重力影响,是匀变速运动,位置会有二次曲线的变化
对应的公式是:
x = 初始X + 水平速度 * 时间 y = 初始Y + 垂直速度 * 时间 + 0.5 * 重力加速度 * 时间²
我们可以通过逐时间步计算位置点,再把这些点传给Line Renderer,就能画出完美的抛物线了。
完整修改后的TrajectoryShower脚本
using UnityEngine; public class TrajectoryShower : MonoBehaviour { [Header("轨迹设置")] public LineRenderer lineRenderer; public Transform launchPoint; // 发射起点(比如弹弓位置) public float maxForce = 10f; // 最大蓄力力量 public float timeStep = 0.1f; // 每两个轨迹点的时间间隔 public int maxPointCount = 50; // 轨迹最大点数(控制轨迹长度) public LayerMask collisionLayers; // 需要检测碰撞的图层 private Vector2 initialVelocity; // 发射初始速度 private void Awake() { // 初始化Line Renderer lineRenderer.positionCount = 0; lineRenderer.useWorldSpace = true; lineRenderer.loop = false; } // 调用这个方法更新轨迹(比如在拉拽蓄力时调用) public void UpdateTrajectory(Vector2 pullDirection, float pullDistance) { // 把拉拽的距离和方向转换成初始速度(限制最大力量) float force = Mathf.Clamp(pullDistance, 0f, maxForce); initialVelocity = -pullDirection.normalized * force; // 负号是因为拉拽方向和发射方向相反 CalculateAndDrawTrajectory(); } private void CalculateAndDrawTrajectory() { lineRenderer.positionCount = 0; Vector2 currentPosition = launchPoint.position; float elapsedTime = 0f; // 添加第一个点(发射起点) AddTrajectoryPoint(currentPosition); for (int i = 0; i < maxPointCount; i++) { elapsedTime += timeStep; // 用物理公式计算下一个位置 Vector2 nextPosition = new Vector2( currentPosition.x + initialVelocity.x * elapsedTime, currentPosition.y + initialVelocity.y * elapsedTime + 0.5f * Physics2D.gravity.y * elapsedTime * elapsedTime ); // 检测当前点到下一个点之间是否有碰撞 RaycastHit2D hit = Physics2D.Linecast(currentPosition, nextPosition, collisionLayers); if (hit.collider != null) { // 碰到物体,把碰撞点作为最后一个点 AddTrajectoryPoint(hit.point); break; } // 添加正常轨迹点 AddTrajectoryPoint(nextPosition); currentPosition = nextPosition; } } private void AddTrajectoryPoint(Vector2 point) { lineRenderer.positionCount++; lineRenderer.SetPosition(lineRenderer.positionCount - 1, point); } // 隐藏轨迹(比如发射后调用) public void HideTrajectory() { lineRenderer.positionCount = 0; } }
关键细节说明
- 蓄力转速度:拉拽方向和发射方向是相反的,所以用
-pullDirection来修正,同时用Mathf.Clamp限制最大力量,避免速度超标。 - 碰撞检测:用
Physics2D.Linecast检测每一段轨迹的线段,如果碰到目标图层的物体,就停止绘制并把碰撞点作为终点,完美解决穿透问题。 - 轨迹长度控制:通过
maxPointCount和timeStep共同控制,比如timeStep=0.1+maxPointCount=50就是最多显示5秒的轨迹,你可以根据需求调整这两个参数。 - Line Renderer设置:一定要开启
useWorldSpace,因为我们计算的是世界坐标下的位置。另外可以调整startWidth和endWidth让轨迹线更美观。
使用方法
- 把这个脚本挂到任意GameObject上,比如弹弓对象。
- 给
lineRenderer赋值一个Line Renderer组件,调整好材质和宽度。 - 设置
launchPoint为发射的起点(比如弹弓的发射位置)。 - 在你的蓄力逻辑里(比如触摸/鼠标拉拽时),调用
UpdateTrajectory(pullDirection, pullDistance)方法,传入拉拽的方向和距离。 - 发射后调用
HideTrajectory()隐藏轨迹。
这样就能画出精确的抛物线路径,还能自动检测碰撞停止绘制,完全符合你的需求啦!
内容的提问来源于stack exchange,提问作者Jonathan




