如何锁定Unity的LineRenderer,使其仅沿单一方向跟随触摸?
问题需求
我有两个预设点,需要在它们之间绘制一条线。目前绘制线条和对齐到最终位置都没有问题,但希望绘制过程中将线条限制在两点之间,而不是让它跟随触摸位置任意移动。
效果对比
- 当前效果:

- 期望效果(手指仍在屏幕上):

- 最终效果(手指抬起后):

当前代码
public class Path : MonoBehaviour { [SerializeField] private Vector3[] positions; [SerializeField] private GameObject child1, child2; private Vector3 startPos, currentPos, endPos; [SerializeField] private bool _firstChildSelected = false; [SerializeField] private bool _secondChildSelected = false; [SerializeField] private LineRenderer line; Vector3 direction; Touch touch; // Start is called before the first frame update void Start() { positions = new Vector3[4]; endPos = child2.transform.position; } // Update is called once per frame void Update() { if (Input.touchCount > 0) { touch = Input.GetTouch(0); RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(touch.position), Vector2.zero); if (touch.phase == TouchPhase.Moved || touch.phase == TouchPhase.Stationary) { if (hit) { // If it collides with the first checkpoint for the first time... if (hit.transform.gameObject == child1 && !_firstChildSelected) { positions[0] = child1.transform.position; line.SetPosition(0, positions[0]); line.SetPosition(1, Camera.main.ScreenToWorldPoint(touch.position)); _firstChildSelected = true; } // If it collides with the second checkpoint for the first time, and already passed by the first one... if (hit.transform.gameObject == child2 && _firstChildSelected && !_secondChildSelected) { _secondChildSelected = true; } } // Follow the touch.position until it reached the final position... else if (_firstChildSelected) { currentPos = Camera.main.ScreenToWorldPoint(touch.position) + new Vector3(0, 0, 10); direction = (endPos - positions[0]).normalized; line.SetPosition(1, currentPos); } // When both have been selected, lock the line in if (_firstChildSelected == true && _secondChildSelected == true) { currentPos = child2.transform.position; line.SetPosition(1, currentPos); } } // Clear all on finger lift, but keep the line drawn if (touch.phase == TouchPhase.Ended) { Array.Clear(positions, 0, positions.Length); _firstChildSelected = false; _secondChildSelected = false; } } } }
修改方案
核心是将触摸点投影到两个预设点的线段上,确保线条末端始终落在这条线段范围内。关键步骤:
- 计算起点到终点的线段向量
- 计算触摸点到起点的向量
- 用点积计算触摸点在线段上的投影比例,限制比例在
0~1之间(避免超出线段) - 通过比例计算出线段上的目标位置,作为线条末端
修改后的完整代码
using System; using UnityEngine; public class Path : MonoBehaviour { [SerializeField] private GameObject child1, child2; [SerializeField] private LineRenderer line; private Vector3 _startPos; private Vector3 _endPos; [SerializeField] private bool _firstChildSelected = false; [SerializeField] private bool _secondChildSelected = false; Touch _touch; void Start() { _endPos = child2.transform.position; line.positionCount = 2; } void Update() { if (Input.touchCount <= 0) return; _touch = Input.GetTouch(0); Vector3 touchWorldPos = Camera.main.ScreenToWorldPoint(_touch.position); touchWorldPos.z = 10; RaycastHit2D hit = Physics2D.Raycast(touchWorldPos, Vector2.zero); if (_touch.phase is TouchPhase.Moved or TouchPhase.Stationary) { if (hit) { if (hit.transform.gameObject == child1 && !_firstChildSelected) { _startPos = child1.transform.position; _startPos.z = 10; line.SetPosition(0, _startPos); _firstChildSelected = true; } if (hit.transform.gameObject == child2 && _firstChildSelected && !_secondChildSelected) { _secondChildSelected = true; line.SetPosition(1, _endPos); } } if (_firstChildSelected && !_secondChildSelected) { Vector3 segmentVector = _endPos - _startPos; Vector3 touchToStart = touchWorldPos - _startPos; float dotProduct = Vector3.Dot(touchToStart, segmentVector); float segmentLengthSqr = segmentVector.sqrMagnitude; float t = Mathf.Clamp01(dotProduct / segmentLengthSqr); Vector3 targetPos = _startPos + t * segmentVector; line.SetPosition(1, targetPos); } } if (_touch.phase == TouchPhase.Ended) { _firstChildSelected = false; _secondChildSelected = false; } } }
关键修改说明
- 移除冗余的
positions数组,直接用_startPos和_endPos管理两点位置 - 添加
line.positionCount = 2确保LineRenderer只有两个有效点 - 统一触摸点和预设点的Z轴为10,避免坐标混乱
- 核心逻辑:通过向量点积计算投影比例,用
Mathf.Clamp01限制范围,确保线条末端始终在两点线段内 - 简化代码结构,移除无效变量和逻辑
内容的提问来源于stack exchange,提问作者Syz
相关产品推荐
相关产品推荐

