unity3D---实现柔软水管(蛇的移动)效果一(无重力)

   毕设想添加一个消防栓,其中水管头跟随主角移动,而尾部固定在一处,水管是软的,效果如下

做了个样例,突然想到贪吃蛇,哈哈,所以以后要实现蛇的效果好像也可以用哎,就在标题来添加啦。

主要把这个水管分为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<Segment2> segments;


    

	// Use this for initialization
	void Start () {
        segments = new List<Segment2>();
        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<NewBehaviourScript>().OnPeopleRun();


    }
}

 

  • 9
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值