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

这篇具有很好参考价值的文章主要介绍了【Unity小技巧】Unity中实现带有Sprite Shape的2D水效果(附项目源码)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

先看实现的最终效果

untiy 2d水特效,# unity实战,unity,游戏引擎,游戏

前言

本文是自己的学习笔记,最近发现一个很有意思的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球挂载上去
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏

新增WaterShapeController

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

新建个空物体,挂载脚本并配置参数
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏

一个球的效果
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏
复制多个球模拟水面波动
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏
效果
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏

制作2d水面

安装插件
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏
新增
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏
配置4个节点
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏
最终效果
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏
修改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<FallingObject>();
            Rigidbody2D rb = fallingObject.GetComponent<Rigidbody2D>();
            var speed = rb.velocity;

            velocity += speed.y / resistance;
        }
    }
}

给球挂载脚本,添加触发器和配置区域
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏
修改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<WaterSpring> 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 < waterPointsCount - CorsnersCount; i++)
        {
            waterSpline.RemovePointAt(CorsnersCount);
        }

        Vector3 waterTopLeftCorner = waterSpline.GetPosition(1); // 水形状左上角的顶点位置
        Vector3 waterTopRightCorner = waterSpline.GetPosition(2); // 水形状右上角的顶点位置
        float waterWidth = waterTopRightCorner.x - waterTopLeftCorner.x; // 水形状的宽度

        float spacingPerWave = waterWidth / (WavesCount + 1); // 计算每个波浪之间的间隔
                                                              // 在水形状中添加波浪点
        for (int i = WavesCount; 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 <= WavesCount + 1; 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<WaterSpring>();
            waterSpring.Init(spriteShapeController);
            springs.Add(waterSpring);
        }
    }
    private void Smoothen(Spline waterSpline, int index)
    {
        Vector3 position = waterSpline.GetPosition(index); // 获取节点位置
        Vector3 positionPrev = position;
        Vector3 positionNext = position;
        if (index > 1)
        {
            positionPrev = waterSpline.GetPosition(index - 1); // 获取上一个节点的位置
        }
        if (index - 1 <= WavesCount)
        {
            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 < count; i++)
        {
            if (i > 0)
            {
                left_deltas[i] = spread * (springs[i].height - springs[i - 1].height);
                springs[i - 1].velocity += left_deltas[i];
            }
            if (i < springs.Count - 1)
            {
                right_deltas[i] = spread * (springs[i].height - springs[i + 1].height);
                springs[i + 1].velocity += right_deltas[i];
            }
        }
    }
    private void Splash(int index, float speed)
    {
        if (index >= 0 && index < springs.Count)
        {
            springs[index].velocity += speed;
        }
    }
}

挂载脚本,并配置参数
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏
效果
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏

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

修改WaterSpring

//。。。

 // 当有物体进入水面时的触发检测函数,如果该物体被标记为FallingObject,则将水泉速度增加一定值
 private void OnTriggerEnter2D(Collider2D other)
 {
     if (other.gameObject.tag.Equals("FallingObject"))
     {
         FallingObject fallingObject = other.gameObject.GetComponent<FallingObject>();
         Rigidbody2D rb = fallingObject.GetComponent<Rigidbody2D>();
         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<Rigidbody2D>();
        // 将物体的速度设置为向下的 forceAmount 速度
        rb.velocity = Vector3.down * forceAmount;
    }
}

新建个box物体,挂载脚本,配置参数,记得修改物体标签为FallingObject
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏
效果
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏

给水面添加浮力效果

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

效果
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏

最终效果

untiy 2d水特效,# unity实战,unity,游戏引擎,游戏

源码

整理好后我会放上了

参考

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

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

完结

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

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

一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
untiy 2d水特效,# unity实战,unity,游戏引擎,游戏文章来源地址https://www.toymoban.com/news/detail-833585.html

到了这里,关于【Unity小技巧】Unity中实现带有Sprite Shape的2D水效果(附项目源码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity2D Sprite尺寸与UI在场景视图和游戏视图显示不一致问题解决方案

    在Unity3D中,当开发2D游戏时,经常会遇到Sprite尺寸与UI在场景视图和游戏视图中显示不一致的问题。这个问题可能导致UI元素变形或者在不同分辨率的设备上显示不正确。本文将为您提供解决这个问题的方法,并附带相应的源代码。 问题分析: Sprite是2D游戏中最常用的图像资

    2024年02月05日
    浏览(41)
  • Unity中实现2D遮罩

    一:前言 可以使用SpriteMask用作控制图形显示区域,SpriteRenderer用作显示图形,在SpriteRenderer中选择MaskInteraction遮罩类型 二:基础使用 创建一个空物体,添加SpriteMask组件,设置遮罩图片。创建一个空物体,添加SpriteRenderer组件用作显示图,设置SpriteRenderer的MaskInteraction遮罩类型

    2024年02月16日
    浏览(55)
  • unity中实现经典的2d横版单向跳跃平台

    经常玩2d横版游戏的朋友们相信一定对这种单向跳跃平台很熟悉:我希望我的角色可以通过 跳跃跳上平台,然后在平台之上按下键盘的下键后从平台上落下 。 那么想要实现这样的效果具体要怎么做呢?我们还是先将想要实现的效果进行一个逻辑上的拆分: (1)单向平台,即

    2024年02月03日
    浏览(29)
  • 【Unity Optimize】使用图集(Sprite Atlas)优化项目

    Unity中的图集(Sprite Atlas)是一种用于优化游戏性能和内存的纹理集。Sprite Atlas 可以应用于 2D 和 3D 项目中的 UI、粒子系统、贴图等等。 使用Unity可以很方便地创建Sprite Atlas,只需要创建一个Sprite Atlas GameObject,然后将纹理分配给它。在创建Sprite Atlas时,需要将纹理名称按角色

    2024年02月14日
    浏览(28)
  • Unity关于新手引导中实现遮罩镂空效果

    在新手引导每一步中实现可以遮掉其他部分而显示当前需要点击的部分,只需要在每一步引导的时候设置对应的镂空区域的RectTransform.效果如下图: 代码:

    2024年01月20日
    浏览(38)
  • unity中实现碰撞效果(无废话),不用代码,简单好抄

     1.首先建立2个物理静态精灵并设置他们的颜色。 2.给两个物体添加碰撞器组件     3.给物体添加刚体属性将静态的改为Dynamic,这里可以两个都添加,也可以只添加其中一个物体的  4.将重力大小设置为0,不然运行的时候物体会直接掉下去  5.运行游戏并随便选择旁边刚刚创

    2024年01月17日
    浏览(58)
  • unity 2D中,实现点击按钮可以游戏暂停的效果

    在Unity 2D中,可以通过以下步骤和代码来设置一个按钮,实现游戏暂停的效果: 创建一个空对象,命名为\\\"GameManager\\\",用于管理游戏状态。 在GameManager对象上添加一个脚本,命名为\\\"PauseManager\\\"。 在脚本中添加以下代码: 在场景中创建一个Canvas对象,用于放置按钮。 在Canvas下创

    2024年02月03日
    浏览(38)
  • 使用DoTween插件在Unity中实现物体或场景的振动效果

    在Unity中,我们可以使用DoTween插件来实现物体或场景的振动效果。DoTween是一个功能强大的插件,可以简化动画的创建和管理过程,并提供了丰富的插值和缓动函数,使得振动效果的实现变得更加容易。 首先,我们需要确保已经安装了DoTween插件,并将其导入到Unity项目中。接

    2024年04月17日
    浏览(45)
  • 【Unity实战篇 】| 游戏中实现镂空遮罩效果【矩形、圆形镂空遮罩】

    前言 本文来写一下怎样在Unity中完成一个 镂空遮罩 的效果。 镂空遮罩 比较常用的有两种ÿ

    2024年02月15日
    浏览(74)
  • 【unity小技巧】Unity2D TileMap+柏林噪声生成随机地图(附源码)

    我的上一篇文章介绍了TileMap的使用,主要是为我这篇做一个铺垫,看过上一篇文章的人,应该已经很好的理解TileMap的使用了,这里我就不需要过多的解释一些繁琐而基础的知识了,省去很多时间。所有没看过上一篇文章的小伙伴我强烈建议先去看看:

    2024年02月07日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包