毕设想添加一个消防栓,其中水管头跟随主角移动,而尾部固定在一处,水管是软的,效果如下
做了个样例,突然想到贪吃蛇,哈哈,所以以后要实现蛇的效果好像也可以用哎,就在标题来添加啦。
主要把这个水管分为n段,每段是一个类
类的内容如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
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 Segment2(Segment2 parent_, float len_, float angle1_, float angle2_)
{
a = new Vector3(parent_.b.x, parent_.b.y, parent_.b.z);
len = len_;
angle1 = angle1_;
angle2 = angle2_;
calculateB();
sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = a;
DrawLine();
}
public Segment2(Vector3 vector3, float len_, float angle1_, float angle2_)
{
a = vector3;
len = len_;
angle1 = angle1_;
angle2 = angle2_;
calculateB();
sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = a;
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);
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);
}
}
相关注释在上面,很清楚啦!
接下下来就是放在物体身上的脚本了,可以新建一个空物体,或者直接放在目标物体上,主要流程是先新建n个上述类,赋初值。每次目标点移动时先从最后一个开始,依次计算位置,这时得到的是不固定起点时候的位置数据,然后反向,给第一个确定位置,依次二三四直到最后一个,角度不变,只是起点终点位置换换。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour {
public GameObject role; //目标位置
public List segments;
// Use this for initialization
void Start () {
segments = new List();
for (int i = 0; i < 8; i++)
{
if (i == 0)
{
var seg = new Segment2(new Vector3(0, 0, 0.5f), 5, 0, 0);
segments.Add(seg);
}
else
{
Segment2 seg = new Segment2(segments[i - 1], 5, 0, 0);
segments.Add(seg);
}
}
}
// Update is called once per frame
void Update () {
}
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(new Vector3(0, 0, 0.5f));
for (int i = 1; i < segments.Count; i++)
{
segments[i].SetA(segments[i - 1].b);
}
}
}
最后加上物体移动的代码把
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move : MonoBehaviour {
public float moveSpeed=2.0f;
public GameObject pipe;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if(Input.GetKey(KeyCode.A))
{
transform.Translate(Vector3.left*moveSpeed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.D))
{
transform.Translate(Vector3.right *moveSpeed* Time.deltaTime);
}
if (Input.GetKey(KeyCode.W))
{
transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.S))
{
transform.Translate(Vector3.back * moveSpeed * Time.deltaTime);
}
if (Input.GetMouseButton(0))
{
transform.Translate(Vector3.up * moveSpeed * Time.deltaTime);
}
if (Input.GetMouseButton(1))
{
transform.Translate(Vector3.down * moveSpeed * Time.deltaTime);
}
if (Input.GetKeyUp(KeyCode.A) || Input.GetKeyUp(KeyCode.S) || Input.GetKeyUp(KeyCode.W) || Input.GetKeyUp(KeyCode.D) || Input.GetMouseButtonUp(0) || Input.GetMouseButtonUp(1))
pipe.GetComponent().OnPeopleRun();
}
}