相对于线的长度向 LineRenderer 添加力?

Adding force to LineRenderer relative to the length of the line?

我在这里潜伏了很长时间,通过其他人的问题找到了很多帮助。但是经过大量搜索,我找不到 post 来帮助我找到解决我遇到的问题的方法,所以我决定 post 在这里提出我自己的问题,如果它得到回答,它可能会以类似的方式帮助其他人!

我在为 linerenderer 增加力时遇到了一些问题。基本思想是我有一个物体,我通过向相反方向拖动一条线来向前射击。现在所缺少的是射击具有相对于“拉索”长度的力,就像物体被拉动的“强度”一样。我在这方面遇到了一些麻烦,所以我想我应该问问比我更聪明、更有经验的人!

这是我绘制吊索的脚本:

public class DragIndicatorScript : MonoBehaviour

{

    Vector3 startPos;
    Vector3 endPos;
    Camera camera;
    LineRenderer lineRenderer;

    Vector3 camOffset = new Vector3(0, 0, 10);

    [SerializeField] AnimationCurve animCurve;

    // Start is called before the first frame update
    void Start()
    {
        camera = Camera.main;
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            if (lineRenderer == null)
            {
                lineRenderer = gameObject.AddComponent<LineRenderer>();
            }
            lineRenderer.enabled = true;
            lineRenderer.positionCount = 2;
            startPos = camera.ScreenToWorldPoint(Input.mousePosition) + camOffset;
            lineRenderer.SetPosition(0, startPos);
            lineRenderer.useWorldSpace = true;
            lineRenderer.widthCurve = animCurve;
            lineRenderer.numCapVertices = 10;
            lineRenderer.material = new Material(Shader.Find("Hidden/Internal-Colored"));
            lineRenderer.startColor = Color.magenta;
            lineRenderer.endColor = Color.cyan;
        }
        if (Input.GetMouseButton(0))
        {
            endPos = camera.ScreenToWorldPoint(Input.mousePosition) + camOffset;
            lineRenderer.SetPosition(1, endPos);
        }
        if (Input.GetMouseButtonUp(0))
        {
            lineRenderer.enabled = false;
        }
    }
}

这是我控制物体射击的脚本:

public class Shoot : MonoBehaviour
{
    Rigidbody2D rigidigidy;
    Vector2 startpos;
    Vector2 endpos;
    [SerializeField]  float power = 10f;

    void Start()
    {
        rigidigidy = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        if (Input.GetMouseButtonUp(0))
        {
            endpos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            Launch();
        }
    }

    void OnMouseDown()
    {
        startpos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
    }

    void Launch()
    {
        Vector2 direction = (startpos - endpos).normalized; 
        rigidigidy.AddForce(direction * power, ForceMode2D.Impulse);
    }
}

提前致谢!我已经连续使用 Google 数小时并编写了几行代码,但我觉得我就是找不到我要找的东西。

附加问题 1) 如何将 linerenderer 固定在可拉物体所在的位置?我希望让玩家可以在可玩区域的任何地方拖动,但是 linerenderer 总是在有问题的对象上实例化(它总是同一个对象,因为它是“玩家模型”)。

附加问题 2) 我知道如何在脚本中更改 linerenderer 的 material,但我还没有真正找到从我的资产中调用 material 的正确方法(我制作了一个 material想用作牵引线),所以作为占位符我只是使用:

Material(Shader.Find("Hidden/Internal-Colored"));
            lineRenderer.startColor = Color.magenta;
            lineRenderer.endColor = Color.cyan;

因为我想要一些比默认的粉红色更赏心悦目的东西。

  1. 主要问题我有点不清楚。您已经拥有 startpos-endpos。这不就是包含您要查找的幅度的矢量吗?

    我可能宁愿合并你的两个脚本,而不是让它们独立处理输入和位置。

    我会让你的 Shoot 处理输入并只将它转发给 DragIndicatorScript 因为顾名思义:它应该只是一个指标,而不应该是决定最终拍摄的组件实力.

    因此 Shoot 应该计算输入向量,将其固定并仅将其传递给指标,然后指标可以根据锚点(见下文)和向量更新其结束位置。

  2. 附加问题 1:

    我会简单地记住锚点和 startPos 之间的偏移量。然后你可以稍后通过简单地考虑这个偏移量来计算端点。

    为了能够在屏幕上的任何位置拖动,您不应该使用 OnMouseDown,它仅在鼠标实际位于对撞机上方时才有效,而是按照您在 DragIndicatorScript 中所做的方式使用 GetMouseButtonDown(0).

    听起来你还想要线的最大长度,并将这个最大长度也用作最大射击功率。多了一个论点,如前所述,为什么我会让拍摄控制一切。

  3. 附加问题 2:

    您可以简单地在检查器的一个槽中引用您的 material。但总的来说,我建议事先添加 LineRenderer 并完全设置它。那么你甚至不需要通过代码来完成!

所以看起来有点像

public class Shoot : MonoBehaviour
{
    [SerializeField] private DragIndicatorScript _dragIndicator;

    [SerializeField] private Rigidbody2D _rigidBody;
    [SerializeField] private float power = 10f;

    [SerializeField] private Camera _camera;

    // This script should clamp the input
    [SerializeField] private float maxLength;

    private Vector2 inputStartPosition;

    private void Awake()
    {
        if(!_rigidBody) _rigidBody = GetComponent<Rigidbody2D>();
        if(!_camera) _camera = Camera.main;
    }

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // store the initial input position
            inputStartPosition = camera.ScreenToWorldPoint(Input.mousePosition);

            // Enable the indicator and for now set the endpoint also on the anchor since there wasn't any input yet
            _dragIndicator.SetIndicator(Vector2.zero);
        }
        if (Input.GetMouseButton(0))
        {
            // Get the current position
            Vector2 inputCurrentPosition = camera.ScreenToWorldPoint(Input.mousePosition);

            // Get the input delta between the current and initial position
            var input = inputCurrentPosition - inputStartPosition;

            // Now clamp this vector to the max length
            input = Vector2.ClampMagnitude(input, maxLength);

            _dragIndicator.SetIndicator(input);
        }
        if (Input.GetMouseButtonUp(0))
        {
            // Just to be sure recalculate from the current position
            Vector2 inputCurrentPosition = camera.ScreenToWorldPoint(Input.mousePosition);
            var input = inputCurrentPosition - inputStartPosition;

            // Now clamp this to the max length
            input = Vector2.ClampMagnitude(input, maxLength);
            
            _dragIndicator.HideIndicator();

            // Directly pass in the final input vector, this way you don't need to store it in a field
            Launch(input);
        }
    }

    private void Launch(Vector2 input)
    {
        // Input already contains the direction and magnitude of the user input
        _rigidBody.AddForce(-input * power, ForceMode2D.Impulse);
    }
}

DragIndicatorScript 只接收这些命令:

public class DragIndicatorScript : MonoBehaviour
{
    [SerializeField] private LineRenderer _lineRenderer;

    // For the EXTRA QUESTION 1
    [SerializeField] private Transform _lineAnchor;

    // For EXTRA QUESTION 2
    [SerializeField] private Material _lineMaterial;

    [SerializeField] private AnimationCurve animCurve;

    private void Awake()
    {
        if(!TryGetComponent<LineRenderer>(out _lineRenderer))
        {
            _lineRenderer = gameObject.AddComponent<LineRenderer>();
        }

        // Setup your Line ONCE
        _lineRenderer.positionCount = 2;
        _lineRenderer.useWorldSpace = true;
        _lineRenderer.widthCurve = animCurve;
        _lineRenderer.numCapVertices = 10;
        _lineRenderer.material = _lineMaterial;
        _lineRenderer.startColor = Color.magenta;
        _lineRenderer.endColor = Color.cyan;

        _lineRenderer.SetPosition(0, _lineAnchor.position);
        _lineRenderer.enabled = false;
    }

    public void HideIndicator()
    {
        _lineRenderer.enabled = false;
    }

    public void SetIndicator(Vector3 input)
    {
        lineRenderer.SetPosition(1, _lineAnchor.position + input);
        _lineRenderer.enabled = true;
    } 
}