[Unity] 使用多个 Spring Joint 2D 和 Sprite Shape 制作 2D 样条变形体 SoftBody2D

444 阅读1分钟

1.简单六边形

教程视频:youtu.be/F82BlnW5z6g

做七个 Circle,中心的圆作为父节点,命名为 SoftBody2D,其他节点摆成六边形

image.png

六边形边上的圆与它周围的三个圆通过 Spring Joint 2D 连接

image.png

image.png

每个圆都有 RigidBody 2D 和 Circle Collider 2D

那么这七个圆已经组成了一个可以变形的整体

调整 Spring Joint 2D 的 Frequency 可以调整恢复形状的强度与速度(虽然写的是频率……神奇欸

这个时候再在 SoftBody2D 下面加上一个 Closed Sprite Shape

image.png

使用 Edit Spline 左键单击样条空白处可以插入节点,左键单击样条节点可以拖动该节点

将样条的六个节点摆在六个圆上

再新建一个脚本,控制 Spline 的节点的位置和切线方向:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.U2D;

    public class SoftBody2D : MonoBehaviour
    {
        #region Constants
        private const float splineOffset = 0.5f;
        #endregion
    
        #region
        [SerializeField]
        public SpriteShapeController spriteShape;
        [SerializeField]
        public Transform[] points;
        #endregion

        #region MonoBehaviour Callback
        private void Awake()
        {
            UpdateVerticies();
        }

        private void Update()
        {
            UpdateVerticies();
        }
        #endregion

        #region privateMethods
        private void UpdateVerticies()
        {
            for(int i = 0;i < points.Length;i++)
            {
                Vector2 _vertex = points[i].localPosition;

                Vector2 _towardsCenter = (Vector2.zero - _vertex).normalized;

                float _colliderRadius = points[i].gameObject.GetComponent<CircleCollider2D>().radius;

                try
                {
                    spriteShape.spline.SetPosition(i, (_vertex - _towardsCenter * _colliderRadius));
                }
                catch
                {
                    Debug.Log("Spline points are too close, recalcuate...");
                    spriteShape.spline.SetPosition(i, (_vertex - _towardsCenter * (_colliderRadius + splineOffset)));
                }

                Vector2 _lt = spriteShape.spline.GetLeftTangent(i);

                Vector2 _newRt = - (Vector2.Perpendicular(_towardsCenter) * _lt.magnitude);
                Vector2 _newLt = - (_newRt);

                spriteShape.spline.SetLeftTangent(i,_newLt);
                spriteShape.spline.SetRightTangent(i,_newRt);
            }
        }
        #endregion
    }

其中,样条节点位置为

样条节点切线为

代码中与视频不一样的是 UpdateVerticies() 中改成了 for(int i = 0;i < points.Length;i++)

原视频是把 SoftBody2D 放在 public Transform[] points 的最后一个元素

因为我不知道把 SoftBody2D 放进来有什么用,所以没放进来,所以就不需要避开数组最后一个元素了

还有,能工作的切线方向和原视频是相反的,可能 Unity 改过吧

2.更多节点

可以参考 youtu.be/h_bSGoztB2g

这个文章也给出了另一种控制 sprite 形态的方法:使用骨骼 zhuanlan.zhihu.com/p/432385770

此外还有材质是怎么做的问题……懒得做了hhh