在Unity里将多个Sprite(精灵图)动态合成一个Sprite 您所在的位置:网站首页 如何把2个spine动画合在一起 在Unity里将多个Sprite(精灵图)动态合成一个Sprite

在Unity里将多个Sprite(精灵图)动态合成一个Sprite

#在Unity里将多个Sprite(精灵图)动态合成一个Sprite| 来源: 网络整理| 查看: 265

一、描述 1. 这是一个什么效果?

类似于PS里面的图层混合,这将在游戏运行过程中将多个Sprite合并为一个Sprite,可以应用于2D游戏物体或UI。 类似以下的效果: 需要注意的是在图片叠加时不仅仅是覆盖,还可以应用任意的图片混合类型。

2. 这有什么用?

你可能会说,不就个笑脸加个圆吗,我直接加两个游戏物体一边挂一个不就完事儿了吗?我直接PS混合导出不就完事了吗? 确实,如果你的图片叠加的情况数少且可确定,我建议还是直接用PS,或直接挂在几个游戏物体上做成预制体。

但如果叠加情况数多或者层数不确定,无论是PS还是做成预制体,相比之下都非常不优雅了。

试想:我有10张图,游戏进程中可能需要在其中选x张混合成一张

如果用PS导出,则需要预先导出 2 10 2^{10} 210张图,别说人工导出过程复杂,连硬盘都要蚌埠住了,而且游戏中并不一定出现全部情况,其实许多都是无用功。

如果用子物体,那么就需要在一瞬间生成10个子物体,而且很可能同时需要存在多个类似效果,那么场景就会多达成百上千个物体,届时电脑也直接蚌埠住了。

因此比较优雅的是,在代码里动态混合图片素材,游戏运行时,一个效果只挂载到一个游戏物体上。 这就是这篇文章需要达到的最终目的。

二、准备工作 1. 图片素材

准备需要在游戏中混合的图片素材,确保每张大小一致。 如不一致请使用PS等软件补充透明区域,再重新裁剪、导出为一致大小。

这是因为在代码里处理大小不一的图片比较复杂。 当然如果你有自己的想法,也可以大胆尝试,我是怕了。

2. 导入Unity

将所有素材拖入Unity。全选素材图片并在Inspector中勾选Read/Write Enabled

3. 创建脚本

创建用于执行该操作的脚本。生成的过程只需要访问素材和混合规则。 因此无需继承MonoBehaviour,设置为static类即可。

using UnityEngine; public static class SpriteCreator { //将在此添加所有字段和方法 } 三、脚本编写 1. 函数参数

最关键的就是生成的函数了,它需要返回最终生成的Sprite。

参数用于控制最终Sprite的样式,因此应包含所有生成规则,比如指定叠加的源?叠加几次?混合模式? 这由你决定

public static Sprite GetSprite(/*添加你的生成规则,或传入素材*/) { } 2. 获取、创建Texture2D

Texture2D是2D图片的材质,说白了它记录了一张图片所有像素点的颜色数据(以及其它信息)。我们需要读取素材Sprite的Texture2D,并以此为依据生成新的Texture2D。

获取Sprite的Texture2D: 如果你有一个名为mySprite的Sprite类型引用,可以这么做:

Texture2D texFromSprite = mySprite.texture;

事实上,你可以通过定义Texture2D的变量并序列化至Inspector,然后拖动你的Sprite到该变量位置,可以直接提取到图片的Texture2D: 好,现在就假定你已经获取到了你Sprite的Texture2D啦

然后我们需要创建新的Texture2D,用于存放我们组合后的材质 因此生成函数的画风现在是这样的:

public static Sprite GetSprite(/*添加你的生成规则,或传入素材*/) { Texture2D background = //你的Texture2D,这是叠在下面的那张 Texture2D cover = //你的Texture2D,这是叠在上面的那张 //新tex,大小用哪个都无所谓,因为之前保证了所有素材大小一致 Texture2D newTex = new Texture2D(background.width, background.height); } 3. 遍历像素

我们需要遍历每个像素点,并处理它们各自的颜色:

先获得素材的颜色 Texture2D中有两个获取颜色的函数,分别是 Color GetPixel(int x, int y):获取指定坐标值的颜色 Color[] GetPixels():按行遍历顺序获取所有坐标值的颜色

为了减少函数调用,这里直接用GetPixels一次性全部获取 类似地,设置新Texture2D的颜色时也一次性全部设置,以减少函数调用 因此需要定义3个数组存放颜色

开始处理

Color[] bgColors = background.GetPixels(); Color[] cvColors = cover.GetPixels(); Color[] newColors = new Color[background.width * background.height]; for (int x = 0; x float CoverAlpha = cover.a; Color blendColor; blendColor.r = cover.r * CoverAlpha + background.r * (1 - CoverAlpha); blendColor.g = cover.g * CoverAlpha + background.g * (1 - CoverAlpha); blendColor.b = cover.b * CoverAlpha + background.b * (1 - CoverAlpha); blendColor.a = 1; return blendColor; }

更新循环

for (int x = 0; x public static Sprite GetSprite(/*添加你的生成规则,或传入素材*/) { Texture2D background = ;//你的Texture2D,这是叠在下面的那张 Texture2D cover = ;//你的Texture2D,这是叠在上面的那张 //新tex,大小用哪个都无所谓,因为之前保证了所有素材大小一致 Texture2D newTex = new Texture2D(background.width, background.height); Color[] bgColors = background.GetPixels(); Color[] cvColors = cover.GetPixels(); Color[] newColors = new Color[background.width * background.height]; for (int x = 0; x float CoverAlpha = cover.a; Color blendColor; blendColor.r = cover.r * CoverAlpha + background.r * (1 - CoverAlpha); blendColor.g = cover.g * CoverAlpha + background.g * (1 - CoverAlpha); blendColor.b = cover.b * CoverAlpha + background.b * (1 - CoverAlpha); blendColor.a = 1; return blendColor; } //你可以增加其它Blend模式,替换NormalBlend即可 }

至此,我们结束了脚本的创建

四、一点优化

可以根据你创建Sprite的逻辑,用字典等方式把已创建的Sprite存储起来,当创建相同类型Sprite时,直接返回已有的Sprite,可以避免重复运算。

public static Sprite GetSprite(/*添加你的生成规则,或传入素材*/) { if (/*已有相同Sprite*/) return /*字典或列表里面的Sprite*/; //否则照常创建Sprite //把Sprite加入字典或列表,下次有相同直接重用 return newSprite; } 五、我的应用

我把一个钻石分成了5个图片,分别是4个部分和1个光影,根据游戏逻辑给4个部分上不同的颜色,然后叠加上光影让它看起来没那么廉价(bushi)

因此我觉得用这种动态缝合非常爽 比如这个 冰火两重天

六、参考资料

How to Combine Sprites in Unity! Modular Textures in Unity



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有