Unity中如何实现类似乒乓球的射线反射轨迹?
问题与解决方案
我的代码如下:
using System.Collections.Generic; using UnityEngine; public class Test : MonoBehaviour { [SerializeField] private Vector2 _vector; [SerializeField] private int _reflectionCount; [SerializeField] private float _distance; private void Update() { Vector2[] points = GetReflectionPoints(transform.position, _vector, _reflectionCount, _distance, Physics2D.AllLayers); for (int i = 0; i < points.Length; i++) { if (i + 1 == points.Length) break; Debug.DrawLine(points[i], points[i + 1], Color.red); } } public static Vector2[] GetReflectionPoints(Vector2 currentPosition, Vector2 vector, int reflectionCount, float distance, int layerMask) { List<Vector2> points = new(reflectionCount); vector.Normalize(); points.Add(currentPosition); for (int i = 0; i < reflectionCount; i++) { RaycastHit2D hit = Physics2D.Raycast(currentPosition, vector, distance, layerMask); points.Add(hit.point); vector = Vector2.Reflect(vector, -hit.normal); } return points.ToArray(); } }
运行结果:
图中红色是当前得到的轨迹,绿色是期望的轨迹。我看过很多相关视频,它们要么使用Rigidbody2D.velocity要么使用循环实现,请问是否有其他方法(比如通过点积)来实现该效果?
问题根源与修复
你的代码核心问题是每次射线都从初始位置发射,没有更新当前位置到上一次的碰撞点,导致所有反射线段起点重合,出现错误轨迹。先修正这个问题,再看用点积实现反射的方法。
用点积手动实现反射向量
Vector2.Reflect本质就是基于点积推导的公式,你可以手动实现这个逻辑,公式如下:
反射向量 = 入射向量 - 2 * (入射向量 · 单位法线) * 单位法线
Unity中hit.normal是指向碰撞体外的单位向量,需注意入射方向与法线方向的对应关系。
修正后的代码(含点积实现反射)
using System.Collections.Generic; using UnityEngine; public class Test : MonoBehaviour { [SerializeField] private Vector2 _vector; [SerializeField] private int _reflectionCount; [SerializeField] private float _distance; private void Update() { Vector2[] points = GetReflectionPoints(transform.position, _vector, _reflectionCount, _distance, Physics2D.AllLayers); for (int i = 0; i < points.Length - 1; i++) { Debug.DrawLine(points[i], points[i + 1], Color.red); } } public static Vector2[] GetReflectionPoints(Vector2 currentPosition, Vector2 vector, int reflectionCount, float distance, int layerMask) { List<Vector2> points = new(reflectionCount + 1); // 初始点+反射点,总数量需+1 Vector2 direction = vector.normalized; points.Add(currentPosition); for (int i = 0; i < reflectionCount; i++) { RaycastHit2D hit = Physics2D.Raycast(currentPosition, direction, distance, layerMask); // 未命中时停止循环,避免添加无效点 if (!hit) break; points.Add(hit.point); // 用点积手动计算反射向量 float dotProduct = Vector2.Dot(direction, hit.normal); direction = direction - 2 * dotProduct * hit.normal; // 更新当前位置到碰撞点,下一次射线从这里发射 currentPosition = hit.point; } return points.ToArray(); } }
关键改动说明
- 更新当前位置:每次碰撞后将
currentPosition设为hit.point,保证下一次射线从碰撞点出发,轨迹连贯。 - 手动计算反射向量:用点积实现与
Vector2.Reflect完全一致的逻辑,本质是同一数学原理的手动展开。 - 修正列表容量:初始点加反射点总数量为
reflectionCount + 1,避免列表容量不足。 - 增加命中判断:未命中时终止循环,防止生成无效轨迹点。
修改后红色轨迹会与绿色期望轨迹一致,同时通过点积实现了反射计算,无需依赖Vector2.Reflect或Rigidbody组件。
内容的提问来源于stack exchange,提问作者Kyzlyk
相关产品推荐
相关产品推荐

