彩球2048贴片实现

Posted CZandQZ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了彩球2048贴片实现相关的知识,希望对你有一定的参考价值。

好久没有更新blog,趁着工作不是很忙来写一篇blog,之前玩游戏的时候玩到一款球球2048,遇到一个问题是如何在一个球上贴一个数字 并且这个数字还会变化 并不是固定的一些数字比如2,4,8,16等 后面会很大,如果做到2的32次幂那么美术需要出32张图片,如果后面越玩越后面的话可以说这个数字应该是比较大的,至于多大的话 美术是无法满足需求的,但是美术可以做一些基础的数字,比如0到9这样的数字 如果数字太大的可以用K,M,Q这样的字母加数字代替更大的数字。所以这里就需要动态的生成一些图片,同时需要一个可以接受光照的shader同时可以贴上这样一张图片。最近公司也要做这样一个2048的游戏,所以最后定的方案是美术出一些基础图片,然后通过程序来合成所需要的图片,然后通过特殊的shader把材质附到对应的模型上,具体的图片如下:

然后我们根据这些图片进行生成图片,这里每张图片大小不一样,长和宽可以不统一,加入数字为“32”,我们就需要取“3”和“2”这2张图片然后计算出2张图片长度,首先我们以图片的中心点为原点 ,然后根据图片的总长度来计算起始点,例如图片的大小为200x200,首先先生成一张图片,

首先计算起始位置:

p的定义是根据所贴数字的长度来计算图片大小比例,假如就一个数字的话,我们定义为1,假如2个数字的话可能为0.8f,以此类推,然后就是对每个像素进行填色,首先我们需要对图片进行涂成透明色,代码如下:

最后就是对每张图片上的颜色每个像素和整张图片像素位置进行对应,其中最简单的做法就是直接映射,假如有图片A,合成后的图片称为B,首先取图片A上的像素点(x,y)然后映射到图片B上假如A图片有缩下的情况,缩放的比例为P,假定图片A的长宽分别为h,w。然后经过缩放后的图片再B的长宽应该为 p*h,p*w。那么映射到B上像素坐标应该为,x/w*p*w,y坐标以此类推,因为所有的这些都是整型,同时缩小后的像素取值可能导致图片的精度丢失,因为好多像素并没有被采集到,假如P=0.5f,那么像素点为(0,0)对应B图片中像素位置假如为x1,y1,同样像素点为(1,1)同样也应该为x1,y1.因为1*0.5和0*0.5取整之后的结果是一样的所以最后x1,y1所存的颜色应该是A图片中(1,1)的像素,一次类推就会导致整个图片采样出现偏差 就会出现过渡不是很缓和,会出现明显的锯齿,所以这个地方应该采用双线性插值,双线性插值算法是OpenCV中默认的图片压缩算法,并且效果也比较稳定,计算复杂度并不算太高,所以感觉挺适合手机,

 双线性插值 算法和最近邻插值算法比较类似。在最近邻插值算法中,目标图像中的某个点(x,y)是去源图像中找最邻近的一个点(x0, y0)即可。目标图像中的点(x, y)对应于源图像中的点(x0',y0'),x0'、y0'很可能不是整数,而是小数,而最近邻插值算法是找其邻近整型值(int(x0'+0.5f),int(y0'+0.5f))(上篇文章中没有进行四舍五入)。我们现在找x0', y0'所在位置旁边的四个点,根据这四个点与(x0',y0')距离的关系计算目标图像中(x,y)一点的像素值。算法描述如下:

 

具体的代码如下:

所以核心算法是实在最后一个插值,根据周围相近的点通过插值计算出最终的颜色。

 int textureWidth = 200;
            int textureHeight = 200;

            Texture2D combine = new Texture2D(textureWidth, textureHeight, TextureFormat.RGBA32, false);

            float p = GetWidth(str);
            int w = GetTotalWidth(str);

            int startPosX = textureWidth / 2 - (int)(w * p / 2);
            int width = 0;
            int height = 0;

            for (int i = 0; i < textureWidth; i++)
            
                for (int j = 0; j < textureWidth; j++)
                
                    combine.SetPixel(i, j, new Color(1, 1, 1, 0));
                
            
            for (int i = 0; i < str.Length; i++)
            
                var t = str[i].ToString();

                int maxX = _cache[t].width - 1;
                int maxY = _cache[t].height - 1;
                width = Mathf.CeilToInt(_cache[t].width * p);
                height = Mathf.CeilToInt(_cache[t].height * p);

                for (int j = 0; j < width; j++)
                
                    int startPosY = textureHeight / 2 - height / 2;
                    for (int k = 0; k < height; k++)
                    
                        float targetX = j * 1.0f / p;
                        float targetY = k * 1.0f / p;
                        int x1 = Mathf.Min(maxX, Mathf.FloorToInt(targetX));
                        int y1 = Mathf.Min(maxY, Mathf.FloorToInt(targetY));
                        int x2 = Mathf.Min(maxX, x1 + 1);
                        int y2 = Mathf.Min(maxY, y1 + 1);

                        float u = targetX - x1;
                        float v = targetY - y1;
                        float w1 = (1 - u) * (1 - v);
                        float w2 = u * (1 - v);
                        float w3 = (1 - u) * v;
                        float w4 = u * v;
                        Color color1 = _cache[t].GetPixel(x1, y1);
                        Color color2 = _cache[t].GetPixel(x2, y1);
                        Color color3 = _cache[t].GetPixel(x1, y2);
                        Color color4 = _cache[t].GetPixel(x2, y2);
                        Color color = new Color(Mathf.Clamp01(color1.r * w1 + color2.r * w2 + color3.r * w3 + color4.r * w4),
                            Mathf.Clamp01(color1.g * w1 + color2.g * w2 + color3.g * w3 + color4.g * w4),
                            Mathf.Clamp01(color1.b * w1 + color2.b * w2 + color3.b * w3 + color4.b * w4),
                            Mathf.Clamp01(color1.a * w1 + color2.a * w2 + color3.a * w3 + color4.a * w4)
                        );

                        int x = startPosX + j;
                        int y = startPosY + k;
                        combine.SetPixel(x, y, color);
                    
                
                startPosX += width;
            
            combine.Apply();

整个方法就是在计算像素然后赋值到一个新图片中去。希望这篇blog对某些人有用吧,希望可以帮到你们,不懂得问题可以问我 我的qq号:1850761495,

以上是关于彩球2048贴片实现的主要内容,如果未能解决你的问题,请参考以下文章

unity使用贴图时为啥调整为sprite

游戏美术中最常见的故障及其解决方案

java数组实现买彩票(二个一维数组的比较思想)

各种抗锯齿效果的记录

hihocoder1777 彩球

使用 GhostScript 以固定大小导出 PNG