Unity绘画功能实现(包含涂鸦、颜色一键填充、撤销操作、保存图像)

3 篇文章 0 订阅

Unity绘画功能实现包含涂鸦、颜色一键填充、撤销操作、保存图像

写在前面

项目需要,要实现在图像上进行绘画,看来网上的很多Unity绘画代码,感觉挺复杂的而且功能不全,这里我自己实现了一个在图像上进行绘画的代码,包含了涂鸦、一键填充颜色、撤销上一次操作、保存图片功能。
本项目是在http://www.qb5200.com/article/391439.html上进行了魔改。

效果

左键涂鸦、右键一键填充、空格撤销上一次操作、程序关闭自动保存图像
在这里插入图片描述

项目地址

https://github.com/hahahappyboy/ImageDrawProject

关键讲解

1、图片的设置
为了让图片可以编辑,在图片的Inspector窗口要把这两个地方改一下
在这里插入图片描述
2、我这里用的是射线检测,没有用UGUI的事件触发API所以要改一下相机和画布的设置
相机改为正交
在这里插入图片描述
画布改为屏幕空间Camera模式
在这里插入图片描述
只有这样才能进行鼠标点击的射线才能打到图像。
3、坐标转化,如何获取鼠标点击的图片的哪个像素
(1)用Vector3 mouseWorldPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition)将鼠标坐标转化为世界坐标.其中Input.mousePosition屏幕坐标的起点位置 左下角为(0,0)点,右上角为(Screen.width,Screen.height) 。mouseWorldPosition的z轴为摄像机的z轴位置。
(2)再用Vector2 localPos = transform.InverseTransformPoint(mouseWorldPosition);将世界坐标转化为图片的本地坐标位置,z轴直接不要。transformA.InverseTransformPoint(transformB.position)就是获取transfromB相对于transformA的局部坐标。
此时如果图像为(512,512)大小,则图像左下角(-256,-256)右上角(256,256)
(3)最后用将坐标转为左下角(0,0)右上角(512,512)这是为了之后便于计算

float pixelWidth = drawSprite.rect.width;//512
float pixelHeight = drawSprite.rect.height;//512
float centeredX = localPos.x + pixelWidth / 2;
float centeredY = localPos.y + pixelHeight / 2;
//左下角(0,0)右上角(512,512)
Vector2 pixel_pos = new Vector2(Mathf.RoundToInt(centeredX), Mathf.RoundToInt(centeredY));

4、获取图片像素
核心是用currentColorArray = drawableTexture2D.GetPixels32();获取图像的每个点像素值,这个GetPixels32()方法会返回Color32[]的数组,如果图像是(512,512)大小,那么这是数组的大小就为512×512。数组第0个元素为图片左下角的像素,第512×512个元素为图片右上角的像素。这就是为什么我们在3中要进行坐标转化的原因,因为要一一对应。
5、涂鸦
在3中知道鼠标点击的是哪个像素点,4中又知道了图像的所有点像素值,找到对应点更改Color32[]数组中的颜色即可,改完了记得设置回图片。

drawableTexture2D.SetPixels32(currentColorArray);
drawableTexture2D.Apply();

涂鸦代码详见MarkPixelsToColour()函数
注意一下,为了防止鼠标滑动太快导致涂鸦点间断的问题,这里使用了插值方法,根据前一个点和后一个点的的距离,叉出中间点。

//计算当前的位置和上一次记录的位置之间的距离,然后平滑的画,这是为了防止鼠标移动太快,画的点不连续
float distance = Vector2.Distance(previousDragPosition, pixelPos);
float steps = 1 / distance;
for (float lerp = 0; lerp <= 1; lerp += steps)
{
    //插值
    Vector2 curPosition = Vector2.Lerp(previousDragPosition, pixelPos, lerp);
    //画
    PenDraw(curPosition);
}
previousDragPosition = pixelPos;

6、一键填充
用到基于栈的非递归泛洪填充算法,不要用的递归去做因为unity会报栈溢出。
泛洪填充算法详见https://blog.csdn.net/jia20003/article/details/8908464/
主要是栈来存储一个点周围可能要填充的点(进栈)。在循环里一直进栈一个点周围要填充的点,然后出栈要填充的点,再判断出栈点周围的点是否进栈。
详见FloodFillScanLineWithStack()函数
7、撤销上一步
Stack<Color32[]>栈实现,就是绘画时记录一下绘画前的像素。撤回时就出栈。
8、保存

byte[] bytes = drawableTexture2D.EncodeToPNG();
File.WriteAllBytes(Application.dataPath + "/SavedScreen.png", bytes);
drawableTexture2D.SetPixels32(orignalColorArray);
drawableTexture2D.Apply();

写在后面

未闻花名,但识花香,再遇花时,泪已千行。

  • 9
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
Unity是一款强大的绘画游戏引擎,可以通过填充代码来制作绘画游戏。在Unity中,我们可以使用C#语言来编写代码。 首先,我们需要创建一个新的游戏对象并给它一个Sprite渲染器组件,用于显示绘画的背景。可以选择一个适合绘画图像作为背景。 接下来,我们需要添加一个脚本组件来处理绘画行为。我们可以在画板上点击鼠标左键,然后根据鼠标位置在画板上绘制一条直线。我们可以使用鼠标事件和LineRenderer组件来实现这个功能。 在鼠标按下事件中,我们可以获取鼠标点击的位置,并将其保存绘画的起始点。然后,在鼠标拖拽事件中,我们可以获取鼠标当前位置,并绘制一条连接起始点和当前点的直线。 为了实现绘画的效果,我们可以为画板创建一个空的游戏对象,并给它一个LineRenderer组件。在每次绘制直线的时候,我们可以将直线的起始点和终点添加到LineRenderer的位置列表中,并更新LineRenderer的显示。 此外,我们还可以通过使用不同的颜色和粗细来实现绘画的多样化效果。可以添加一个颜色选择器和粗细调节器,让玩家可以根据自己的喜好来选择绘画的样式。 除了绘画功能,我们还可以为游戏添加其他的功能,比如保存绘画内容、清空画板、撤销和重做等。通过添加对应的按钮以及相应的代码逻辑,可以实现这些功能。 总的来说,通过在Unity填充绘画游戏代码,我们可以实现一个简单而有趣的绘画应用,同时还可以添加更多的功能和玩法,让玩家可以尽情发挥创造力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值