创建自上而下的 2D 鞭子机制

Creating top down 2D whip mechanic

What Whip should look like

我正在尝试创建一个鞭子,它可以在按下某个按钮后向鼠标面向的任何方向延伸。如果路上有“可抓取”的物体,例如敌人或盒子,它应该抓住这些物体并将它们拉来拉去与其他物体碰撞一定时间。 我知道我需要鞭子伸出和锁定的不同 sprite 镜头来制作动画,但我不知道如何在代码中实现这一点,也不知道如何让鞭子在检测到“可抓取”对象时停下来。

将此脚本附加到您的播放器,这应该可以完成工作:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{

    public Transform player = null;
    public float speed = 30f;
    public string grabbableTag = "grabbable";
    private LineRenderer line = null;
    private float timer = 0f;
    private bool grabbing = false;
    private bool reached = false;
    private Vector2 from = Vector2.zero;
    private Vector2 to = Vector2.zero;
    private Vector2 target = Vector2.zero;
    private Transform grabbable = null;

    private void Start()
    {
        player = transform;
        line = new GameObject("Line").AddComponent<LineRenderer>();
        line.startColor = Color.red;
        line.endColor = Color.red;
        // Assign a material
        line.gameObject.SetActive(false);
        reached = false;
        grabbing = false;
    }

    private void Update()
    {
        if(grabbing)
        {
            Grabbing();
        }
        else
        {
            if (Input.GetMouseButtonDown(0))
            {
                Grab();
            }
        }
    }

    private void Grab()
    {
        Vector3 mousePosition = Input.mousePosition;
        mousePosition.z = Vector3.Distance(player.position, Camera.main.transform.position);
        to = Camera.main.ScreenToWorldPoint(mousePosition);
        from = player.position;
        Vector2 direction = (to - from).normalized;
        float distance = Vector2.Distance(from, to);
        RaycastHit2D[] hits = Physics2D.RaycastAll(from, direction, distance);
        grabbable = null;
        for (int i = 0; i < hits.Length; i++)
        {
            if (hits[i].transform.tag == grabbableTag)
            {
                grabbable = hits[i].transform;
                break;
            }
        }
        if (grabbable != null)
        {
            distance = Vector2.Distance(player.position, grabbable.position);
            to = from + direction * distance;
        }
        grabbing = true;
        reached = false;
        target = from;
        timer = 0;
        line.gameObject.SetActive(true);
        line.positionCount = 2;
        line.SetPosition(0, from);
        line.SetPosition(1, from);
    }

    private void Grabbing()
    {
        if (reached)
        {
            target = Vector2.Lerp(target, from, speed * Time.deltaTime);
            if (target == from)
            {
                GrabDone(grabbable);
                grabbing = false;
                line.gameObject.SetActive(false);
            }
        }
        else
        {
            target = Vector2.Lerp(target, to, speed * Time.deltaTime);
            if(target == to)
            {
                reached = true;
            }
        }
        line.SetPosition(1, target);
        if (reached && grabbable != null)
        {
            grabbable.position = target;
        }
    }

    private void GrabDone(Transform grabbed)
    {
        if(grabbed != null)
        {
            // Do somthing ...
            Destroy(grabbed.gameObject);
        }
    }

}