Unity3D实现模型体积拖拽变化

实现模型拖拽体积改变功能算法:

Unity3D实现模型体积拖拽变化

        public Transform crossLeft;
        public Transform cro***ight;
        public Transform arrowUp;
        public Transform arrowDown;
        
        //模型结构子对象
        public Transform legLeftUp;
        public Transform legRightUp;
        public Transform legLeftDown;
        public Transform legRightDown;
        public Transform arrow;

        ///         /// 传动带模型MeshFilter
        ///         public MeshFilter conveyorMeshFilter;
        ///         /// 传送带边沿护栏模型MeshFilter
        ///         public MeshFilter guardBarMeshFilter;

        public BoxCollider boxCollider;
        
        //Mesh保存
        private Dictionary conveyorMeshLeftVertices;
        private Dictionary conveyorMeshRightVertices;

        private Dictionary conveyorMeshUpVertices;
        private Dictionary conveyorMeshDownVertices;

        private Dictionary guardBarMeshLeftVertices;
        private Dictionary guardBarMeshRightVertices;

        private Dictionary guardBarMeshUpVertices;
        private Dictionary guardBarMeshDownVertices;
        
        
        //交互所用变量
        private float firstDistanceToOtherCross;
        private Vector3 nowInputMousePosition;
        float endDistance;
        private Transform otherCross;
        private Vector3 otherCrossScreenPostion;
        private Vector3 lastInputMousePoistion;

核心方法:

         
        //初始化 
        void Init()
        {
            conveyorMeshLeftVertices = FiltrateVertices(conveyorMeshFilter.mesh,  VecticeDir.Left);
            conveyorMeshRightVertices = FiltrateVertices(conveyorMeshFilter.mesh, VecticeDir.Right);
            conveyorMeshUpVertices = FiltrateVertices(conveyorMeshFilter.mesh, VecticeDir.Up);
            conveyorMeshDownVertices = FiltrateVertices(conveyorMeshFilter.mesh, VecticeDir.Down);

            guardBarMeshLeftVertices = FiltrateVertices(guardBarMeshFilter.mesh, VecticeDir.Left);
            guardBarMeshRightVertices = FiltrateVertices(guardBarMeshFilter.mesh, VecticeDir.Right);
            guardBarMeshUpVertices = FiltrateVertices(guardBarMeshFilter.mesh, VecticeDir.Up);
            guardBarMeshDownVertices = FiltrateVertices(guardBarMeshFilter.mesh, VecticeDir.Down);
            
            //length = 1;
            //heigth = 1;

            boxCollider = gameObject.GetComponent();
            if (name.Contains("left"))
            {
                otherCross = converyEntityMediator.converyEntityView.cro***ight;
                isLeft = true;
            }
            else
            {
                otherCross = converyEntityMediator.converyEntityView.crossLeft;
                isLeft = false;
            }
        }
         
        ///         
        /// 筛选顶点,分成左右两堆
        ///                
        /// 顶点方向       
         Dictionary FiltrateVertices(Mesh mesh, VecticeDir dir)
        {
            Dictionary result = new Dictionary();
            for (int i = 0; i < mesh.vertices.Length; i++)
            {
                switch (dir)
                {
                    case VecticeDir.Left:
                        if (mesh.vertices[i].z > 0)
                        {
                            result.Add(i, mesh.vertices[i]);
                        }
                        break;
                    case VecticeDir.Up:
                        if (mesh.vertices[i].x > 0)
                        {
                            result.Add(i, mesh.vertices[i]);
                        }
                        break;
                    case VecticeDir.Right:
                        if (mesh.vertices[i].z < 0)
                        {
                            result.Add(i, mesh.vertices[i]);
                        }
                        break;
                    case VecticeDir.Down:
                        if (mesh.vertices[i].x < 0)
                        {
                            result.Add(i, mesh.vertices[i]);
                        }
                        break;
                }
            }
            return result;
        }
        
           //宽度
          public void ChangeWidth(float width,Vector3 dir, bool isUp)
        {
            List conveyorMeshVertices = new List(conveyorMeshFilter.mesh.vertices);
            List guardBarMeshVertices = new List(guardBarMeshFilter.mesh.vertices);

            float halfWidth = width / 2;
            transform.position += halfWidth * (transform.rotation * dir).normalized;
            //this.length += length;
            //改变板和边栏的长度
            foreach (KeyValuePair item in conveyorMeshUpVertices)
            {
                conveyorMeshVertices[item.Key] += Vector3.right * halfWidth;
            }

           
            foreach (KeyValuePair item in conveyorMeshDownVertices)
            {
                conveyorMeshVertices[item.Key] -= Vector3.right * halfWidth;
            }

            foreach (KeyValuePair item in guardBarMeshUpVertices)
            {
                guardBarMeshVertices[item.Key] += Vector3.right * halfWidth;
            }

            foreach (KeyValuePair item in guardBarMeshDownVertices)
            {
                guardBarMeshVertices[item.Key] -= Vector3.right * halfWidth;
            }

            
            if (isUp)
            {
                //设置子物体的位置
                legLeftUp.localPosition += halfWidth * dir;
                legRightUp.localPosition += halfWidth * dir;
                legLeftDown.localPosition -= halfWidth * dir;
                legRightDown.localPosition -= halfWidth * dir;
                arrowUp.localPosition += halfWidth * dir;
                arrowDown.localPosition -= halfWidth * dir;

            }
            else
            {
                //设置子物体的位置
                legLeftUp.localPosition -= halfWidth * dir;
                legRightUp.localPosition -= halfWidth * dir;
                legLeftDown.localPosition += halfWidth * dir;
                legRightDown.localPosition += halfWidth * dir;
                arrowUp.localPosition -= halfWidth * dir;
                arrowDown.localPosition += halfWidth * dir;
            }
            float arrowScale = Mathf.Clamp(((ConveyorEntity)entity).conveyorProperty.Width * 2f, 0.2f, 1);
            arrow.localScale = new Vector3(arrowScale, 1, arrowScale);
            conveyorMeshFilter.mesh.SetVertices(conveyorMeshVertices);
            guardBarMeshFilter.mesh.SetVertices(guardBarMeshVertices);

            //设置collider
            boxCollider.size += Vector3.right * width;
        }
        
        
        /// 改变传送带长度
        ///         
        /// 传送带长度       
        /// 是否选择的左边移动      
        public void ChangeLength(float length, Vector3 dir,bool isChoiceLeft = false)
        {
            List conveyorMeshVertices = new List(conveyorMeshFilter.mesh.vertices);
            List guardBarMeshVertices = new List(guardBarMeshFilter.mesh.vertices);

            float halfLength = length / 2;
            transform.position += halfLength *( transform.rotation * dir).normalized;
            //改变板和边栏的长度
            foreach (KeyValuePair item in conveyorMeshLeftVertices)
            {
                conveyorMeshVertices[item.Key] += Vector3.forward * halfLength;
            }

            foreach (KeyValuePair item in guardBarMeshLeftVertices)
            {
                guardBarMeshVertices[item.Key] += Vector3.forward * halfLength;
            }

            foreach (KeyValuePair item in conveyorMeshRightVertices)
            {
                conveyorMeshVertices[item.Key] -= Vector3.forward * halfLength;
            }

            foreach (KeyValuePair item in guardBarMeshRightVertices)
            {
                guardBarMeshVertices[item.Key] -= Vector3.forward * halfLength;
            }

            if (isChoiceLeft)
            {
                //设置子物体的位置
                legLeftUp.localPosition += halfLength * dir;
                legRightUp.localPosition -= halfLength * dir;
                legLeftDown.localPosition += halfLength * dir;
                legRightDown.localPosition -= halfLength * dir;
                crossLeft.localPosition += halfLength * dir;
                cro***ight.localPosition -= halfLength * dir;
            }
            else
            {
                //设置子物体的位置
                legLeftUp.localPosition -= halfLength * dir;
                legRightUp.localPosition += halfLength * dir;
                legLeftDown.localPosition -= halfLength * dir;
                legRightDown.localPosition += halfLength * dir;
                crossLeft.localPosition -= halfLength * dir;
                cro***ight.localPosition += halfLength * dir;
            }

            //float arrowScale = Mathf.Clamp(((ConveyorEntity)entity).conveyorProperty.Length * 2f, 0.2f, 1);
            //arrow.localScale = new Vector3(arrowScale, 1, arrowScale);
            conveyorMeshFilter.mesh.SetVertices(conveyorMeshVertices);
            guardBarMeshFilter.mesh.SetVertices(guardBarMeshVertices);

            //设置collider
            boxCollider.size += Vector3.forward * length;
            ChangeBounds(100);//拉伸mesh会导致原bound不在摄像机视角下,造成传送带不渲染 (Frustum Culling)
        }

        
        private void ChangeBounds(float boundLength)
        {
            Vector3 bound = new Vector3(boundLength, boundLength, boundLength);
            conveyorMeshFilter.mesh.bounds = new Bounds(transform.position, bound);
            guardBarMeshFilter.mesh.bounds = new Bounds(transform.position, bound);
        }

交互输入:

        private void OnMouseDown()
        {
            endAddDistance = 0;
            otherArrowScreenPostion = Camera.main.WorldToScreenPoint(otherArrow.position);
            lastInputMousePoistion = Input.mousePosition;
            lastDistanceToOtherCross = Vector2.Distance(otherArrowScreenPostion, lastInputMousePoistion);
        }
            
            
        private void OnMouseDrag()
        {
            
            nowInputMousePosition = Input.mousePosition;
            float distance = Vector2.Distance(nowInputMousePosition, lastInputMousePoistion) * 0.1f;
            float otherDistaceToNowInputMousePosition = Vector2.Distance(otherArrowScreenPostion, nowInputMousePosition);
            
            //减少宽度
            if (lastDistanceToOtherCross > otherDistaceToNowInputMousePosition)
            {
                endAddDistance -= distance;
                ChangeWidth(-distance, (transform.localPosition - otherArrow.localPosition).normalized, isUp);
            }
            //增加宽带
            else if (lastDistanceToOtherCross < otherDistaceToNowInputMousePosition)
            {
                endAddDistance += distance;
                ChangeWidth(distance, (transform.localPosition - otherArrow.localPosition).normalized, isUp);
            }
            
            if (otherDistaceToNowInputMousePosition  otherDistaceToNowInputMousePosition)
            {
                if (Vector3.Distance(transform.localPosition, otherCross.localPosition)  Vector3.Distance(transform.localPosition, otherCross.localPosition))
                {
                    return;
                }
                endDistance -= distance;
                converyEntityMediator.ChangeLength(-distance, (transform.localPosition - otherCross.localPosition).normalized, isLeft);
               
            }
            //增加长度
            else if (firstDistanceToOtherCross < otherDistaceToNowInputMousePosition)
            {
                endDistance += distance;
                converyEntityMediator.ChangeLength(distance, (transform.localPosition - otherCross.localPosition).normalized, isLeft);
            }

            lastInputMousePoistion = Input.mousePosition;
            lastDistanceToOtherCross = Vector2.Distance(otherArrowScreenPostion, lastInputMousePoistion);
        }
        
        private void OnMouseUp()
        {
            if (endAddDistance != 0)
            {
                ChangeWidth(-endAddDistance, (transform.localPosition - otherArrow.localPosition).normalized, isUp);
                ChangeLength(-endDistance, (transform.localPosition - otherCross.localPosition).normalized, isLeft);
            }
            
        }


上一篇:unity3d 热更篇--ILRuntime原理


下一篇:Unity3d C#解决transform.LookAt朝向前后翻转问题(含源码)