小工具知识网

当前位置: 首页 > 行业知识 > 【Unity小技巧】Unity中实现带有Sprite Shape的2D水效果(附项目源码)

行业知识

【Unity小技巧】Unity中实现带有Sprite Shape的2D水效果(附项目源码)

2026-11-06 13:00:26 来源:互联网转载

文章目录

  • 先看实现的最终效果
  • 前言
  • 模拟水面的波动效果
  • 制作2d水面
  • 实现物体落入水中互动效果
  • 给水面添加浮力效果
  • 最终效果
  • 源码
  • 参考
  • 完���

    先看实现的最终效果

    前言

    本文是自己的学习笔记,最近发现一个很有意思的2d水效果,所以把它的实现过程写下来分享给大家。

    当在 Unity 中实现带有 Sprite Shape 的 2D 水效果时,首先需要理解 Sprite Shape 和水效果的基本概念和工作原理。Sprite Shape 是 Unity 提供的一种 2D 图形工具,用于创建基于轮廓的精灵形状,并可以根据路径进行变形和填充。而 2D 水效果通常涉及模拟水体的行为,包括波纹、浪花、浮力等物理特性的表现。

    总的来说,结合 Sprite Shape 和水效果需要综合运用 Unity 中的图形技术、物理模拟和动画效果,以达到模拟逼真的水体效果。这样的设计可以为游戏场景增添视觉上的沉浸感和互动性,为玩家带来更加生动的游戏体验。

    模拟水面的波动效果

    新增WaterSpring

    public class WaterSpring : MonoBehaviour{    public float velocity = 0;    public float force = 0;    // 当前高度    public float height = 0f;    // 目标高度    public float target_height = 0f;    // 带有阻尼的弹簧更新    public void WaveSpringUpdate(float springStiffness, float dampening)    {        height = transform.localPosition.y; // 获取当前高度        // 计算弹簧的最大拉伸距离        var x = height - target_height;        // 计算阻尼力        var loss = -dampening * velocity;        // 计算作用力        force = -springStiffness * x + loss;        // 激活物理引擎        velocity += force;        // 将物体位置调整为新的高度        var y = transform.localPosition.y;        transform.localPosition = new Vector3(transform.localPosition.x, y + velocity, transform.localPosition.z);    }}

    新建一个2d球挂载上去

    新增WaterShapeController

    [SerializeField]private float springstiffness = 0.1f; // 弹簧刚度系数[SerializeField]private List springs = new List(); // 所有水弹簧的列表[SerializeField]private float dampening = 0.03f; // 阻尼系数public float spread = 0.006f; // 弹簧之间的间隔 void FixedUpdate(){    // 对所有水弹簧进行更新    foreach (WaterSpring waterSpringComponent in springs)    {        waterSpringComponent .WaveSpringUpdate(springstiffness, dampening);    }}

    新建个空物体,挂载脚本并配置参数

    一个球的效果

    复制多个球模拟水面波动

    效果

    制作2d水面

    安装插件

    新增

    配置4个节点

    最终效果

    修改WaterSpring

    public class WaterSpring : MonoBehaviour{    private int waveIndex = 0; // 当前水泉所在的曲线上的节点索引    [SerializeField]    private static SpriteShapeController spriteShapeController = null; // 水面曲线对应的SpriteShapeController组件    [System.NonSerialized]    public float velocity = 0; // 当前水泉的速度    private float force = 0; // 当前水泉的力    [System.NonSerialized]    public float height = 0f; // 当前水泉的高度    private float target_height = 0f; // 目标高度    private float resistance = 30f; // 抵抗力,表示当有物体落入水面时,水泉速度增加的系数    // 初始化函数,用于设置当前水泉所在的曲线节点索引、SpriteShapeController组件以及初始化速度、高度    public void Init(SpriteShapeController ssc)    {        var index = transform.GetSiblingIndex();        waveIndex = index + 1;        spriteShapeController = ssc;        velocity = 0;        height = transform.localPosition.y;        target_height = transform.localPosition.y;    }    // 更新函数,用于更新水泉的状态,传入参数为弹性系数和阻尼系数    public void WaveSpringUpdate(float springStiffness, float dampening)    {        height = transform.localPosition.y;        // 最大伸长距离        var x = height - target_height;        var loss = -dampening * velocity;        force = -springStiffness * x + loss;        velocity += force;        var y = transform.localPosition.y;        transform.localPosition = new Vector3(transform.localPosition.x, y + velocity, transform.localPosition.z);    }    // 更新水面曲线上的节点高度    public void WavePointUpdate()    {        if (spriteShapeController != null)        {            Spline waterSpline = spriteShapeController.spline;            Vector3 wavePosition = waterSpline.GetPosition(waveIndex);            waterSpline.SetPosition(waveIndex, new Vector3(wavePosition.x, transform.localPosition.y, wavePosition.z));        }    }    private void OnTriggerEnter2D(Collider2D other)    {        Debug.Log(2222);        if (other.gameObject.tag.Equals("FallingObject"))        {            FallingObject fallingObject = other.gameObject.GetComponent();            Rigidbody2D rb = fallingObject.GetComponent();            var speed = rb.velocity;            velocity += speed.y / resistance;        }    }}

    给球挂载脚本,添加触发器和配置区域

    修改WaterShapeController,当一个脚本类被标记为 [ExecuteAlways] 时,它的 Update、LateUpdate 和 FixedUpdate 等方法会在编辑模式下以及运行时都被执行,而不仅仅是在播放模式下执行。

    [ExecuteAlways]public class WaterShapeController : MonoBehaviour{    private int CorsnersCount = 2; // 水形状的边角数    [SerializeField]    private SpriteShapeController spriteShapeController; // 水形状控制器    [SerializeField, Header("波浪点预设物体")]    private GameObject wavePointPref;    [SerializeField, Header("波浪点父物体")]    private GameObject wavePoints;    [SerializeField, Header("波浪数量")]    [Range(1, 100)]    private int WavesCount;    private List springs = new(); // 存储水波浪效果的弹簧节点    [Header("弹簧的强度常数")]    public float springStiffness = 0.1f;    [Header("阻力,用于减缓弹簧的运动")]    public float dampening = 0.03f;    [Header("扩散常数,用于将节点的影响传递给它附近的节点")]    public float spread = 0.006f;    void Start()    {    }    void OnValidate()    {        // 清空水波浪点和弹簧        StartCoroutine(CreateWaves());    }    IEnumerator CreateWaves()    {        foreach (Transform child in wavePoints.transform)        {            StartCoroutine(Destroy(child.gameObject));        }        yield return null;        SetWaves();        yield return null;    }    IEnumerator Destroy(GameObject go)    {        yield return null;        DestroyImmediate(go);    }    private void SetWaves()    {        Spline waterSpline = spriteShapeController.spline; // 获取水形状的样条曲线        int waterPointsCount = waterSpline.GetPointCount(); // 获取水形状的点数        // 移除中间点,只保留边角的两个点        // 每次移除第一个点,则第二个点成为新的第一个点        for (int i = CorsnersCount; i  0; i--)        {            int index = CorsnersCount;            float xPosition = waterTopLeftCorner.x + (spacingPerWave * i);            Vector3 wavePoint = new Vector3(xPosition, waterTopLeftCorner.y, waterTopLeftCorner.z);            waterSpline.InsertPointAt(index, wavePoint);            waterSpline.SetHeight(index, 0.1f);            waterSpline.SetCorner(index, false);            waterSpline.SetTangentMode(index, ShapeTangentMode.Continuous);        }        springs = new();        for (int i = 0; i             int index = i + 1;            Smoothen(waterSpline, index); // 平滑水形状的曲线            GameObject wavePoint = Instantiate(wavePointPref, wavePoints.transform, false);            wavePoint.transform.localPosition = waterSpline.GetPosition(index);            WaterSpring waterSpring = wavePoint.GetComponent        Vector3 position = waterSpline.GetPosition(index); // 获取节点位置        Vector3 positionPrev = position;        Vector3 positionNext = position;        if (index  1)        {            positionPrev = waterSpline.GetPosition(index - 1); // 获取上一个节点的位置        }        if (index - 1             positionNext = waterSpline.GetPosition(index + 1); // 获取下一个节点的位置        }        Vector3 forward = gameObject.transform.forward;        float scale = Mathf.Min((positionNext - position).magnitude, (positionPrev - position).magnitude) * 0.33f;        Vector3 leftTangent = (positionPrev - position).normalized * scale;        Vector3 rightTangent = (positionNext - position).normalized * scale;        SplineUtility.CalculateTangents(position, positionPrev, positionNext, forward, scale, out rightTangent, out leftTangent);        waterSpline.SetLeftTangent(index, leftTangent); // 设置左切向量        waterSpline.SetRightTangent(index, rightTangent); // 设置右切向量    }    void FixedUpdate()    {        foreach (WaterSpring waterSpringComponent in springs)        {            waterSpringComponent.WaveSpringUpdate(springStiffness, dampening); // 更新弹簧效果            waterSpringComponent.WavePointUpdate(); // 更新节点位置        }        UpdateSprings(); // 更新所有弹簧的速度    }    private void UpdateSprings()    {        int count = springs.Count;        float[] left_deltas = new float[count];        float[] right_deltas = new float[count];        for (int i = 0; i = 0 && index  

    挂载脚本,并配置参数

    效果

    实现物体落入水中互动效果

    修改WaterSpring

    //。。。 // 当有物体进入水面时的触发检测函数,如果该物体被标记为FallingObject,则将水泉速度增加一定值 private void OnTriggerEnter2D(Collider2D other) {     if (other.gameObject.tag.Equals("FallingObject"))     {         FallingObject fallingObject = other.gameObject.GetComponent();         Rigidbody2D rb = fallingObject.GetComponent();         var speed = rb.velocity;         velocity += speed.y / resistance;     } } 

    新增FallingObject脚本,控制物体下落

    public class FallingObject : MonoBehaviour{    [Header("物体下落的速度")]    public float forceAmount = 5f;    private Rigidbody2D rb; // 物体的刚体组件    void Start()    {        rb = GetComponent();        // 将物体的速度设置为向下的 forceAmount 速度        rb.velocity = Vector3.down * forceAmount;    }}

    新建个box物体,挂载脚本,配置参数,记得修改物体标签为FallingObject

    效果

    给水面添加浮力效果

    添加Buoyancy Effector 2D(浮力效应器)和多边形碰撞器。浮力效应器用于模拟游戏对象在水中受到的浮力影响,编辑多边形碰撞器配置覆盖整个水体

    效果

    最终效果

    源码

    整理好后我会放上了

    参考

    如果觉得本文实现的效果不错的话,非常推荐大家去支持一下原作者

    【视频】https://www.youtube.com/watch?v=69sBjqMtZCc

    完结

    赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

    好了,我是向宇,https://xiangyu.blog.csdn.net

    一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

上一篇:晋亨生活下载攻略,一键获取,轻松体验生活应用!

下一篇:服务器华为型号怎么查的?