概述
因近期项目有要求使用到水管这种软性管的模拟,该篇主要说明软管的实现和应用,参考自:unity3D---实现柔软水管(蛇的移动)效果一(无重力)_unity 软管_ayouayouwei的博客-CSDN博客
效果
实现代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class HoseScript : MonoBehaviour
{
[Header("起点位置")]
public Vector3 StartPos = new Vector3(0, 0, 0);
[Header("目标物体-终点物体")]
public GameObject role;
public List<Segment2> segments;
[Header("长度(0-1)")]
public float Length;
[Header("宽度(0-1)")]
public Vector3 Size;
[Header("曲率(20-100)")]
public float Step;
void Start()
{
segments = new List<Segment2>();
for (int i = 0; i < Step; i++)
{
if (i == 0)
{
var seg = new Segment2(new Vector3(0, 1, 0.5f), Length, 0, 0, transform, Size);
segments.Add(seg);
seg.Set();
}
else
{
Segment2 seg = new Segment2(segments[i - 1], Length, 0, 0, transform, Size);
segments.Add(seg);
seg.Set();
}
}
}
private void Update()
{
OnPeopleRun();
}
public void OnPeopleRun()
{
for (int i = segments.Count - 1; i >= 0; i--)
{
if (i == segments.Count - 1)
{
segments[i].Follow(role.transform.position);
}
else
{
segments[i].Follow(segments[i + 1].a);
}
segments[i].update();
}
segments[0].SetA(StartPos);
for (int i = 1; i < segments.Count; i++)
{
segments[i].SetA(segments[i - 1].b);
}
}
}
//用于处理每一段
public class Segment2
{
public Vector3 a; //起点
public Vector3 b; //终点
public float len; //长度
public float angle1; //向量b-a 在xoz面的投影,与x轴的夹角
public float angle2; //向量b-a 与y轴的夹角
public GameObject sphere; //关节处添加一个球体
public GameObject sylinder = null; //每一段用一个圆柱体来连接
public Transform _par;
public Vector3 size;
public Segment2(Segment2 parent_, float len_, float angle1_, float angle2_, Transform par,Vector3 _size)
{
a = new Vector3(parent_.b.x, parent_.b.y, parent_.b.z);
len = len_;
angle1 = angle1_;
angle2 = angle2_;
_par = par;
size = _size;
calculateB();
sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.parent = _par;
sphere.transform.position = a;
sphere.transform.localScale = _size;
sphere.GetComponent<SphereCollider>().enabled = false;
DrawLine();
}
public Segment2(Vector3 vector3, float len_, float angle1_, float angle2_, Transform par, Vector3 _size)
{
a = vector3;
len = len_;
angle1 = angle1_;
angle2 = angle2_;
_par = par;
size = _size;
calculateB();
sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.parent = _par;
sphere.transform.localPosition = a;
sphere.transform.localScale = _size;
sphere.GetComponent<SphereCollider>().enabled = false;
DrawLine();
}
public void calculateB()
{
float dy = len * Mathf.Cos(angle2);
float dx = len * Mathf.Sin(angle2) * Mathf.Cos(angle1);
float dz = len * Mathf.Sin(angle2) * Mathf.Sin(angle1);
b = new Vector3(a.x + dx, a.y + dy, a.z + dz);
}
//目标位置pos,根据目标位置确定a的位置
public void Follow(Vector3 pos)
{
Vector3 dir = pos - a; //单位向量
angle1 = Mathf.Atan2(dir.z, dir.x);
angle2 = Mathf.Atan2(Mathf.Sqrt(dir.x * dir.x + dir.z * dir.z), dir.y);
dir = Vector3.Normalize(dir);
dir = dir * len * (-1f);
a = pos + new Vector3(dir.x, dir.y, dir.z);
}
public void SetA(Vector3 a_)
{
a = a_;
update();
}
public void update()
{
calculateB();
sphere.transform.position = a;
DrawLine();
}
//根据起点和终点来确定圆柱体的位置和旋转角度
public void DrawLine()
{
if (sylinder == null)
{
sylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
sylinder.transform.parent = _par;
}
Vector3 position = (b + a) / 2.0f;
Vector3 rotation = b - a;
float length = Vector3.Distance(a, b) / 2;
sylinder.transform.position = position;
sylinder.transform.localRotation = Quaternion.FromToRotation(Vector3.up, rotation);
//sylinder.transform.localScale = new Vector3(1, length, 1);
}
public void Set()
{
sylinder.transform.localScale = size;
sylinder.GetComponent<CapsuleCollider>().enabled = false;
}
}
1.在Unity中创建一个空物体,挂载HoseScript.cs脚本
2.创建一个基础物体,将基础物体赋值到HoseScript.cs的Role参数上
运行后在Scene视图下拖拽Role即可看到实现效果,具体实现思路可参考文中第一段的原创链接,本篇只是根据原创进行二次整合后的使用层讲解。
整合了Demo样例只要一点点积分,如果没有积分也可私聊我免费获取
Unity软性管的实现资源-CSDN文库