Unity实现一个简单的勾物品的功能
场景布置
运行效果:
层次面板
实现方法
-
使用LineRenderer作为钩链
- 在BeginPoint物体上添加LineRenderer组件,记得取消勾选 use world space
-
使用小球(Hook)作为钩子
-
当发射时对钩子进行碰撞检测
-
检测到敌人便将敌人作为钩子的子物体
-
添加胶囊体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;
}
}
}
完