unity实现3D电线连接(Vectrosity和MegaWire插件)

使用的插件

当前Vectrosity的版本有问题,尽量用5以上的版本

整体,参数有线的材质,线的大小,已经一些UI组件

每个需要连线的点都需要挂载当前脚本方便标识

using UnityEngine;

public class WireConnectionPoint : MonoBehaviour

{

    public string pointName; // 连接点的名称

    private void OnDrawGizmos()

    {

        // 在场景中可视化连接点

        Gizmos.color = Color.red;

        Gizmos.DrawSphere(transform.position, 0.1f);

    }

}

实现整体逻辑代码

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using Vectrosity;

using UnityEngine.UI;

public class DynamicWire : MonoBehaviour

{

    public Material wireMaterial; // 线缆的材质

    public float wireSize = 0.1f; // 线缆的半径

    private MegaWire wire; // MegaWire 线缆对象

    private List<WireConnectionPoint> connectionPoints; // 存储连接点的列表

    public List<MegaWireSpan> activeWires; // 存储当前激活的线缆

    private GameObject currentWire; // 当前正在绘制的线缆

    private bool isDrawing = false; // 绘制状态

    private WireConnectionPoint startPoint; // 线缆的起始连接点

    private VectorLine currentLine;         // 当前正在拖拽的线条

    private int indexSpanNum = -1;  //记录当前线段

    public Button clearLinesBtn;

    void Start()

    {

        connectionPoints = new List<WireConnectionPoint>(); // 初始化连接点列表

        activeWires = new List<MegaWireSpan>(); // 初始化激活的线缆列表

        clearLinesBtn.onClick.AddListener(()=> {

            if (wire!=null&&wire.spans.Count>0)

            {

                wire.RemoveWire();

                activeWires.Clear();

                indexSpanNum = -1;

            }

        });

    }

    int index = 0;

    void Update()

    {

        if (Input.GetMouseButtonDown(0))

        {

            // 获取当前鼠标点击的连接点

            WireConnectionPoint clickedPoint = GetClickedConnectionPoint();

            if (clickedPoint != null)

            {

                startPoint = clickedPoint; // 设置起始点

                //currentWire = new GameObject("Wire"); // 创建新的线缆对象

                //AddColliderToWire(currentWire); // 添加 Collider 以便选中

                //currentWire.transform.SetParent(clickedPoint.transform);

                // 创建新的 VectorLine

                currentLine = new VectorLine("WireLine", new List<Vector3>(), wireSize, LineType.Continuous, Joins.Weld);

                currentLine.material = wireMaterial;

                // 添加起始点和一个初始的终点

                currentLine.points3.Add(startPoint.transform.position);  // 起始点

                currentLine.points3.Add(startPoint.transform.position);  // 添加一个默认的终点(与起点相同)

                isDrawing = true; // 开始绘制状态

            }

        }

 if (isDrawing && Input.GetMouseButton(0))

        {

            // 持续更新线缆位置

            UpdateWirePosition();

        }

        if (Input.GetMouseButtonUp(0))

        {

            if (currentLine!=null&& currentLine.points3.Count>0) {

                currentLine.points3.Clear();    // 清除线条点

                VectorLine.Destroy(ref currentLine);

            }

          

            // 完成线缆绘制

            WireConnectionPoint endPoint = GetClickedConnectionPoint();

            if (endPoint != null && endPoint != startPoint)

            {

                // 如果连接到另一个点,创建线缆

                CreateWire(endPoint);

            }

            else

            {

                // 否则,删除未连接的线缆

                //Destroy(currentWire);

            }

            isDrawing = false; // 结束绘制状态

        }

    if (Input.GetMouseButtonDown(1))

        {

            // 右键点击:选择并删除线条

            MegaWireSpan selectedWire = GetClickedWire();

            if (selectedWire != null)

            {

                DeleteWire(selectedWire);

            }

            if (indexSpanNum>=0) {

                //从最后一位删除

                DeleteWire(activeWires[indexSpanNum]);

            }

         

        }

    }

 WireConnectionPoint GetClickedConnectionPoint()

    {

        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        if (Physics.Raycast(ray, out RaycastHit hit))

        {

            // 检测到的连接点

            return hit.collider.GetComponent<WireConnectionPoint>();

        }

        return null;

    }

    void UpdateWirePosition()

    {

        Vector3 mousePos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 10f));

        currentLine.points3[1] = mousePos;  // 动态更新终点位置

        currentLine.Draw3D();  // 绘制线条

        //if (currentWire != null)

        //{

        //    // 更新线缆的终点位置

        //    Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        //    if (Physics.Raycast(ray, out RaycastHit hit))

        //    {

        //        currentWire.transform.position = hit.point; // 设置线缆的位置

        //    }

        //}

    }

 void CreateWire(WireConnectionPoint endPoint)

    {

        indexSpanNum++;

        List<GameObject> points = new List<GameObject> { startPoint.gameObject, endPoint.gameObject };

        if (wire == null)

        {

            wire = MegaWire.Create(wire, points, wireMaterial, "Wire", null, wireSize, 1.0f);

            //设置物理效果

            wire.Mass = 0.1f;

            wire.stretch = 0.1f;

            wire.massRand = 0.1f;

            //wire.hidespans = false;

            wire.doCollisions = true;

            activeWires.Add(wire.spans[0]); // 将创建的线缆添加到激活列表

        }

        else {

             // 重写下插件内部方法,微调下

            for (int i = 0; i < points.Count - 1; i++)

            {

                GameObject pole = new GameObject();

              

                pole.name = name + " Span Mesh " + i;

                pole.transform.parent = wire.gameObject.transform;

                MegaWireSpan span = pole.AddComponent<MegaWireSpan>();

                span.start = points[i].transform;

                span.end = points[i + 1].transform;

                MeshFilter mf = pole.GetComponent<MeshFilter>();

                mf.sharedMesh = new Mesh();

                MeshRenderer mr = pole.GetComponent<MeshRenderer>();

                Material[] mats = new Material[1];

                mats[0] = wire.material;

                mr.sharedMaterials = mats;

                span.mesh = mf.sharedMesh;

                span.mesh.name = name + " Wire Mesh " + i;

                span.Init(wire, indexSpanNum);

                Debug.Log("indexSpanNum=>" + indexSpanNum);

             

                wire.spans.Add(span);

                activeWires.Add(span); // 将创建的线缆添加到激活列表

                wire.poles.Add(points[i + 1].transform);

              

            }

        }

        wire.RebuildWire();

        //AddColliderToWire(wire.gameObject); // 添加 Collider 以便选中

    }

 MegaWireSpan GetClickedWire()

    {

        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        if (Physics.Raycast(ray, out RaycastHit hit))

        {

            // 检查点击的对象是否在 activeWires 列表中

            //if (activeWires.Find(x=>x.gameObject==hit.collider.gameObject))

            //{

            //    return hit.collider.gameObject;

            //}

            Debug.Log("hit=>"+ hit.collider.gameObject.name);

            foreach (var item in activeWires)

            {

                if (item.gameObject== hit.collider.gameObject)

                {

                    return item;

                }

            }

        }

        return null;

    }

    public void DeleteWire(MegaWireSpan wireToDelete)

    {

        if (activeWires.Contains(wireToDelete))

        {

            Debug.Log("wireToDelete==>" + activeWires.IndexOf(wireToDelete));

            indexSpanNum--;

            wire.RemoveWire(wireToDelete); // 删除线缆

            activeWires.Remove(wireToDelete);

        }

    }

}

需要注意的是插件的代码是开源的,上述代码有部分功能需要在插件代码里去自定义实现

插件  MegaWire.cs  在Create函数中找到span.Init的方法

static public MegaWire Create(MegaWire wire, List<GameObject> objs, Material mat, string name, MegaWire copyfrom, float wiresize, float str)

         {

        ...

        //暂时只需要一条 后期多条会报错需要修改

                   span.Init(wire,0);

        ...

    }

在修改完MegaWire里初始化线段的方法同时也需要给线段的脚本MegaWireSpan.cs增加一个标识符,方便日后操作指定的某一条线段(目前功能代码暂时不需要加也能正常运行)

public class MegaWireSpan : MonoBehaviour

{

    ...

    public int spanId;  // 唯一标识符

   

    ...

    public void Init(MegaWire wire,int id)

         {

                   spanId = id;

        ...

         }

}

同时MegaWire.cs 代码里还需要自定义删除的方法,加在代码最后面就可以了,前面代码调用过单击右键就可以按顺序删除已添加的线段

public class MegaWire : MonoBehaviour

{

    ...

   

    // 自定义指定删除方法

    //清空所有

    public void RemoveWire()

    {

        // 清除 wire 内部的 span 及相关数据

        foreach (var span in spans)

        {

            if (span != null)

            {

                Destroy(span.gameObject);

            }

        }

        spans.Clear();

        // 清除 poles 和 connections

        poles.Clear();

        connections.Clear();

        // 销毁 MegaWire 的 GameObject

        Destroy(this.gameObject);

    }

         //清除单个线段

         public void RemoveWire(MegaWireSpan span) {

                   spans.Remove(span);

                   Destroy(span.gameObject);

         }

}

最后效果展示

前面写的DynamicWire.cs有个地方可以初始化线段物理效果,根据需求可以自己设置值的大小

public class DynamicWire : MonoBehaviour

{

    ...

    void CreateWire(WireConnectionPoint endPoint)

    {

        //设置物理效果

            wire.Mass = 0.1f;

            wire.stretch = 0.1f;

            wire.massRand = 0.1f;

    }

}

现在属于线段紧绷的物理状态,因为我们把值设置的很小

如果使用插件默认的值,只需要把我们刚刚设置的值注释掉就可以了

public class DynamicWire : MonoBehaviour

{

    ...

    void CreateWire(WireConnectionPoint endPoint)

    {

        //设置物理效果

           // wire.Mass = 0.1f;

            //wire.stretch = 0.1f;

            //wire.massRand = 0.1f;

    }

}

很明显,受到物理效果,质量和重力等一系列参数增大后,线段就会变软下垂的物理效果。

这就是Vectrosity和MegaWire两个插件结合使用的3D画线功能

(注:当前使用的unity版本是2019.4.5的,其他版本暂未测试)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值