Unity实现一个简单的勾物品的功能

场景布置

在这里插入图片描述
在这里插入图片描述

运行效果:

在这里插入图片描述

层次面板

在这里插入图片描述

实现方法

  1. 使用LineRenderer作为钩链

    1. 在BeginPoint物体上添加LineRenderer组件,记得取消勾选 use world space
  2. 使用小球(Hook)作为钩子

  3. 当发射时对钩子进行碰撞检测

  4. 检测到敌人便将敌人作为钩子的子物体

  5. 添加胶囊体Enemy,并将tag设置"Enemy"

代码部分

附件于Hand上

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

public class Hook: MonoBehaviour
{

    public LineRenderer hookObj;                //钩子起始点 附加有LineRenderer组件
    public float hookSpeed = 10f;               //钩子发射速度
    public float totalDistance = 3f;            //钩子最大长度
    public bool isOut = false;                  //钩子发射或者收回标记
    public Transform hookTransform;             //钩子物体(即小球)

    private Collider[] colCollection;           //发射中碰撞到的物体
    private float oriZvalue;                    
    private bool isStop = true;                 //用来判断钩子是否停止
    private float tempZvalue;
    // Use this for initialization
    void Start() {
        oriZvalue = hookTransform.localPosition.z;
        tempZvalue = oriZvalue;
    }

    // Update is called once per frame
    void Update() {
        checkCollider();                //检测发射过程中碰到的碰撞体
        CheckLength();                  //检测是否超过钩子长度
        if (Input.GetKeyDown(KeyCode.H)) {
            isOut = true;
        }
        //发射钩子
        if (isOut) {
            hookTransform.Translate(0, 0, hookSpeed * Time.deltaTime);
            hookObj.SetPosition(1, hookTransform.localPosition);
        }
        //收回钩子
        else {
            if (hookTransform.localPosition.z > oriZvalue) {
                hookTransform.Translate(0, 0, -hookSpeed * Time.deltaTime);
                hookObj.SetPosition(1, hookTransform.localPosition);
            }
        }

        //判断钩子是否为停止状态
        if (hookTransform.childCount > 0) {
            isStop = Mathf.Abs(hookTransform.localPosition.z - tempZvalue) <= 0 ? true : false;
        }
        else
            isStop = false;
        //将敌人够到身前后,放开钩子
        if (isStop) RealeaseChild();
    }

    private void LateUpdate() {
        tempZvalue = hookTransform.localPosition.z;
    }
    void CheckLength() {
        if (Vector3.Distance(hookTransform.position, hookObj.transform.position) > totalDistance) {
            isOut = false;
        }
    }


    void checkCollider() {
        //对钩子进行球形检测,返回所有碰到或者在球范围内的碰撞体数组     
        //注意将人称控制器及其子物体的Layer修改为不是Default的一个层,否则钩子会检测到自身的碰撞体
        colCollection = Physics.OverlapSphere(hookTransform.position, 0.2f, 1 << LayerMask.NameToLayer("Default"));
        if (colCollection.Length > 0) {
            foreach (Collider item in colCollection) {
                //将敌人的tag设置为“Enemy”
                if (item.gameObject.tag.Equals("Enemy"))
                    item.transform.SetParent(hookTransform);
            }
            isOut = false;
        }
    }
    
    void RealeaseChild() {
        if (hookTransform.childCount > 0) {
            for (int i = 0; i < hookTransform.childCount; i++) {
                hookTransform.GetChild(i).transform.SetParent(null);
            }
        }
    }
}

附加于Enemy上 进行pingpong运动

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

public class Enemymove : MonoBehaviour {

    public float moveSpeed = 3;
    public float zVlaue=5;

    private Vector3 ori;
    private float timer = 0;
    private Vector3 targetPoi = Vector3.zero;
    private Quaternion oriRot;
	// Use this for initialization
	void Start () {
        ori = transform.position;
        oriRot = transform.rotation;
	}
	
	// Update is called once per frame
	void Update () {
        //当没被钩中时,进行pingpong运动
        if (transform.parent == null) {
            transform.rotation = oriRot;            //更新为初始旋转,否则在放钩后旋转会改变
            timer += Time.deltaTime*2;
            zVlaue = Mathf.PingPong(timer, 7);
            targetPoi = transform.right * zVlaue;
            transform.position = ori + targetPoi;
        }
        //当背钩中时
        else {
            ori = new Vector3(transform.position.x, 0.98f, transform.position.z);
            timer = 0;
        }
    }
}