本文基于Unity3D 免费插件 FreeDraw 增改

1.主要是两个list ,一个记录已经画下的,一个记录要回退的

直接复制 ,按鼠标键,A D 键使用。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;namespace FreeDraw
{[RequireComponent(typeof(SpriteRenderer))][RequireComponent(typeof(Collider2D))]  // REQUIRES A COLLIDER2D to function// 1. Attach this to a read/write enabled sprite image// 2. Set the drawing_layers  to use in the raycast// 3. Attach a 2D collider (like a Box Collider 2D) to this sprite// 4. Hold down left mouse to draw on this texture!/* 1。将此附加到启用读/写的sprite图像/  2。设置要在光线投射中使用的绘图层/ / 3。将一个二维对撞机(就像一个盒子对撞机2d)附加到这个精灵上/ / 4。按住鼠标左键绘制此纹理!*/public class Drawable : MonoBehaviour{// 画笔颜色public static Color Pen_Colour = Color.red;     // 更改这些设置以更改默认图形设置// 画笔宽度(实际上是半径,以像素为单位)public static int Pen_Width = 3;public delegate void Brush_Function(Vector2 world_position);//这是当左键单击发生时调用的函数。//传入您自己的自定义画笔以更改画笔类型//在唤醒方法中设置默认函数public Brush_Function current_brush;public LayerMask Drawing_Layers;// 画布每次重置为 0000的颜色public Color Reset_Colour = new Color(0, 0, 0, 0);  // 默认情况下,将画布重置为透明// 用于引用此特定文件,而不将所有方法设置为静态public static Drawable drawable;// 必须在Unity的文件编辑器中设置了读/写功能Sprite drawable_sprite;Texture2D drawable_texture;Vector2 previous_drag_position;Color[] clean_colours_array;    //全部情况 Color transparent;Color32[] cur_colors;           //当前需要改变颜色的位置Color32[] start_colors;         //初始空白画面,用作清空处理使用bool mouse_was_previously_held_down = false;bool no_drawing_on_current_drag = false;void Awake(){drawable = this;// 此处设置默认画笔current_brush = PenBrush;drawable_sprite = this.GetComponent<SpriteRenderer>().sprite;drawable_texture = drawable_sprite.texture;// 初始化要使用的干净像素clean_colours_array = new Color[(int)drawable_sprite.rect.width * (int)drawable_sprite.rect.height];for (int x = 0; x < clean_colours_array.Length; x++)clean_colours_array[x] = Reset_Colour;//  每次开启都重置画布图像ResetCanvas();start_colors = drawable_texture.GetPixels32();}// 默认画笔类型。有宽度和颜色。//以世界坐标传递一个点//将世界周围的像素点更改为静态钢笔颜色public void PenBrush(Vector2 world_point){//获得世界坐标对应的像素Vector2 pixel_pos = WorldToPixelCoordinates(world_point);cur_colors = drawable_texture.GetPixels32(); //获得 所有值if (previous_drag_position == Vector2.zero){// 第一次点击画线,起始点在鼠标MarkPixelsToColour(pixel_pos, Pen_Width, Pen_Colour);}else{// 第二帧开始,从起始点到鼠标移动的位置ColourBetween(previous_drag_position, pixel_pos, Pen_Width, Pen_Colour);}ApplyMarkedPixelChanges();previous_drag_position = pixel_pos;}// UI使用的辅助方法来设置用户想要的画笔//为实现的任何新画笔创建一个新的画笔public void SetPenBrush(){// PenBrush是要设置为当前画笔的方法的名称current_brush = PenBrush;}private bool isDraw = false;//update//检测用户单击的时间,然后调用相应的函数void Update(){// 用户是否按住鼠标左键?bool mouse_held_down = Input.GetMouseButton(0);if (mouse_held_down && !no_drawing_on_current_drag){// 将鼠标坐标转换为世界坐标Vector2 mouse_world_position = Camera.main.ScreenToWorldPoint(Input.mousePosition);// 检查当前鼠标位置是否与我们的图像重叠Collider2D hit = Physics2D.OverlapPoint(mouse_world_position, Drawing_Layers.value);if (hit != null && hit.transform != null){//我们正在使用我们正在绘制的纹理! //使用当前画笔的任何功能isDraw = true;current_brush(mouse_world_position);}else{// 没有超过边框 纹理previous_drag_position = Vector2.zero;if (!mouse_was_previously_held_down){// 这是一个新的拖动,用户左键单击画布//确保在开始新拖动之前不进行绘制no_drawing_on_current_drag = true;}}}// 如果鼠标已释放else if (!mouse_held_down){previous_drag_position = Vector2.zero;no_drawing_on_current_drag = false;}mouse_was_previously_held_down = mouse_held_down;// 按鼠标左键 画线并记录 if (Input.GetMouseButtonUp(0)){if (isDraw){//鼠标释放的时候记录数据Record();isDraw = false;}}//后腿if (Input.GetKeyDown(KeyCode.A)){RemoveLastColor();}//前进if (Input.GetKeyDown(KeyCode.D)){RestoreBackColor();}}public void Record(){last = drawable_texture.GetPixels32();    //记录当前画面线在哪recordColors.Add(last);RestoreColors.Clear();}private Color32[] last = new Color32[1];   //最后一个  用作撤销使用List<Color32[]> recordColors = new List<Color32[]>(1);// Color32[] backColors = new Color32[1] ;        //用于撤销之前再还原private List<Color32[]> RestoreColors = new List<Color32[]>(1); //用于撤销之前再还原/// <summary>/// 撤销最后一个/// </summary>public void RemoveLastColor(){if (recordColors.Count == 0) return;Debug.Log("撤销的数量" + recordColors.Count);if (isOnClane == false)RestoreColors.Add(drawable_texture.GetPixels32()); // 再删除之前添加到还原记录 0 -1 -2elseisOnClane = false;if (recordColors.Count > 1)      // 默认里面有一个空白的(start 执行添加) 从第二个开始才是记录第一笔{int index = recordColors.Count - 2;Color32[] color = recordColors[index];drawable_texture.SetPixels32(color);drawable_texture.Apply();//删除最后一个画线// last = recordColors[recordColors.Count - 1];    last = drawable_texture.GetPixels32();}else if (recordColors.Count == 1){drawable_texture.SetPixels32(start_colors);drawable_texture.Apply();}recordColors.RemoveAt(recordColors.Count - 1);}/// <summary>/// 还原 /// </summary>public void RestoreBackColor(){if (RestoreColors.Count <= 0) return;Debug.Log("还原的:" + RestoreColors.Count);//得到当前画面的画线int index = RestoreColors.Count - 1;Color32[] color = RestoreColors[index];  //应用复原 0 - 1 -2drawable_texture.SetPixels32(color);drawable_texture.Apply();last = drawable_texture.GetPixels32();   //在还原之前,得到记录的值//复原后,需要把记录的数据添加一次 ,添加到复原的画面recordColors.Add(last);RestoreColors.RemoveAt(RestoreColors.Count - 1);Debug.Log("还原后再添加到撤销:" + recordColors.Count);//last = RestoreColors[recordColors.Count - 1];}private bool isOnClane = false;  //是否按下了/// <summary>/// 清空当面面板的记录数据/// </summary>public void Clane_LastColor(){drawable_texture.SetPixels32(start_colors);drawable_texture.Apply();if (!recordColors.Contains(start_colors)){recordColors.Add(start_colors);}Debug.Log("清除之后" + recordColors.Count);isOnClane = true;RestoreColors.Clear();}// 将像素的颜色设置为从起点到终点的直线,以确保中间的所有内容都是彩色的。public void ColourBetween(Vector2 start_point, Vector2 end_point, int width, Color color){// 从开始到结束的距离float distance = Vector2.Distance(start_point, end_point);Vector2 direction = (start_point - end_point).normalized;Vector2 cur_position = start_point;// 根据自上次更新以来经过的时间量,计算应该在起始点和结束点之间插入多少次float lerp_steps = 1 / distance;for (float lerp = 0; lerp <= 1; lerp += lerp_steps){cur_position = Vector2.Lerp(start_point, end_point, lerp);MarkPixelsToColour(cur_position, width, color);}}/// <summary>/// 将像素标记为彩色/// </summary>/// <param name="center_pixel">开始点到结束点</param>/// <param name="pen_thickness">画笔的宽度</param>/// <param name="color_of_pen">画笔的颜色</param>public void MarkPixelsToColour(Vector2 center_pixel, int pen_thickness, Color color_of_pen){// 计算出我们需要在每个方向(x和y)上色多少像素。int center_x = (int)center_pixel.x;int center_y = (int)center_pixel.y;//int extra_radius = Mathf.Min(0, pen_thickness - 2);for (int x = center_x - pen_thickness; x <= center_x + pen_thickness; x++){// 检查X是否环绕图像,这样我们就不会在图像的另一侧绘制像素。if (x >= (int)drawable_sprite.rect.width || x < 0)continue;for (int y = center_y - pen_thickness; y <= center_y + pen_thickness; y++){if(y!=1800) //如果超过了1080 就不用修改了MarkPixelToChange(x, y, color_of_pen);}}}/// <summary>/// 获得标记要更改的像素/// </summary>/// <param name="x"></param>/// <param name="y"></param>/// <param name="color"></param>public void MarkPixelToChange(int x, int y, Color color){// 需要将x和y坐标转换为数组的平面坐标int array_pos = y * (int)drawable_sprite.rect.width + x;// 检查这个位置是否有效if (array_pos > cur_colors.Length || array_pos < 0)return;cur_colors[array_pos] = color;}/// <summary>/// 应用标记的像素更改/// </summary>public void ApplyMarkedPixelChanges(){drawable_texture.SetPixels32(cur_colors);drawable_texture.Apply();}/// <summary>/// 世界到像素坐标/// </summary>/// <param name="world_position"></param>/// <returns></returns>public Vector2 WorldToPixelCoordinates(Vector2 world_position){// 将坐标更改为此图像的本地坐标Vector3 local_pos = transform.InverseTransformPoint(world_position);// 将这些更改为像素坐标float pixelWidth = drawable_sprite.rect.width;float pixelHeight = drawable_sprite.rect.height;float unitsToPixels = pixelWidth / drawable_sprite.bounds.size.x * transform.localScale.x;//需要把我们的坐标居中float centered_x = local_pos.x * unitsToPixels + pixelWidth / 2;float centered_y = local_pos.y * unitsToPixels + pixelHeight / 2;// 将当前鼠标位置舍入到最近的像素Vector2 pixel_pos = new Vector2(Mathf.RoundToInt(centered_x), Mathf.RoundToInt(centered_y));return pixel_pos;}/// <summary>/// 重置功能  将每个像素更改为重置颜色/// </summary>public void ResetCanvas(){drawable_texture.SetPixels(clean_colours_array);drawable_texture.Apply();RestoreColors.Clear();recordColors.Clear();}// 直接为像素上色。此方法比使用markpixelstocolour慢,然后使用applymarkedpixelchanges// setpixels32比setpixel快得多// 基于中心厚度(笔半径),中心像素和中心像素周围的像素数目public void ColourPixels(Vector2 center_pixel, int pen_thickness, Color color_of_pen){// 计算出我们需要在每个方向(x和y)上色多少像素。int center_x = (int)center_pixel.x;int center_y = (int)center_pixel.y;//int extra_radius = Mathf.Min(0, pen_thickness - 2);for (int x = center_x - pen_thickness; x <= center_x + pen_thickness; x++){for (int y = center_y - pen_thickness; y <= center_y + pen_thickness; y++){drawable_texture.SetPixel(x, y, color_of_pen);}}drawable_texture.Apply();}private void OnDestroy(){ResetCanvas();}}
}

Unity3D FreeDraw 画图画线 涂鸦 清空 撤销 功能齐全相关推荐

  1. Android简单涂鸦以及撤销、重做的实现方法

    前段时间研究了下涂鸦功能的实现,其实单独的涂鸦实现起来还是挺简单的,关键的技术难点是撤销与重做功能的实现.但是这里暂时只说明下涂鸦功能的实现,高手勿喷哈,而且该功能在Android SDK提供的API ...

  2. Canvas画各种线

    Canvas画各种线 阅读数:562 在Canvas中绘制路径,最好加上beginPath()和closePath(). 结合lineTo()绘制不同的路径 closePath()方法创建从当前点到开 ...

  3. python能画k线图吗_python画k线图(一天的k线图怎么画)

    1.大智慧软件在日线窗口的左上角标有主图的公式名称,(如ma sar bbi )等, 如果不是ma指标,请输入ma,回车.2.如果输入ma后还是没有均线,请按 f7 键,弹出 最好能举个例子的.非常感 ...

  4. 百度地图MapV实现海量数据画线、点聚合等功能

    前言 MapVGL,是一款基于WebGL的地理信息可视化库,可以用来展示大量基于3D的地理信息点线面数据.设计初衷主要是为了解决大数据量的三维地理数据展示问题及一些炫酷的三维效果. 官网地址:MapV ...

  5. canvas擦除画的线但不擦除背景

    canvas擦除画的线但不擦除背景 首先html文件中如下写,图片的话,自己随便找一张. <!DOCTYPE html> <html lang="en"> ...

  6. 画箱线图_箱线图的N种画法

    图中标示了箱线图中每条线和点表示的含义,其中应用到了分位数的概念 线的主要包含五个数据节点,将一组数据从大到小排列,分别计算出他的上边缘(Maximum),上四分位数(Q3),中位数(Median), ...

  7. Matplotlib学习---用matplotlib画误差线(errorbar)

    误差线用于显示数据的不确定程度,误差一般使用标准差(Standard Deviation)或标准误差(Standard Error). 标准差(SD):是方差的算术平方根.如果是总体标准差,那么用σ表 ...

  8. python移动平均线绘图_对python pandas 画移动平均线的方法详解

    数据文件 66001_.txt 内容格式: date,jz0,jz1,jz2,jz3,jz4,jz5 2012-12-28,0.9326,0.8835,1.0289,1.0027,1.1067,1.0 ...

  9. 小学用计算机画画的课件,用计算机画图画.ppt

    用计算机画图画 用计算机画图画 熟悉画图程序 启动画图 画图窗口的组成 画图的基本步骤 使用绘图工具 图画的修改与变形 图块的操作 图画的保存与使用 使用剪切板 综合练习 第一节熟悉画图程序 启动画图 ...

最新文章

  1. VC++ 开发pop3收邮件程序的相关问题
  2. c语言定义函数insert,c语言编写函数insert(char s1[ ],char s2[ ],int pos),实现在字符串s1中的指定位置pos处插入字符串s2。...
  3. MobX - 基于响应式的状态管理
  4. Lady Bird
  5. integer 最大值_JAVA源码之Integer
  6. _wsplitpath_s
  7. 自动化测试是测试人员的遮羞布?
  8. hive plsql使用示例
  9. cx_Oracle连接数据库报DPI-1047: Cannot locate a 64-bit Oracle Client library
  10. NXP JN5169使用UART发送数据
  11. java 快速判断对象是否为null的快捷方法
  12. VennDiagram包绘制Venn图
  13. python 作用域知识点整理
  14. pyqt5 失焦 监听无操作 定时器
  15. vscode创建工作区_VSCode 多文件夹工作区
  16. 开发快手爬票项目(中)
  17. 百度飞桨亮相2019 AIIA,四大领先技术剑指落地引开发者点赞
  18. 图像处理------图像加噪
  19. JavaEE12_EL和JSTL
  20. TCPDF生成PDF文件方法教程说明

热门文章

  1. 完美解决夏天电脑cpu发烫问题
  2. ubuntu下pdf中文乱码解决
  3. 【企动力 “信“为本】华胜信泰ToprowDB-企业数据信息管理的神兵利器
  4. 塔望 · ​食业​中国|文化对消费者行为的影响
  5. rbd image rbd/kubernetes.. is still being used
  6. WPF 自实现Arc控件和Pie控件(根据起止角度画圆弧或扇形)
  7. 离线数仓搭建_02_服务器配置与数据生产
  8. OpenWrt之IPv6设置详解
  9. 刀具管理之首页性能优化
  10. 翻译D26(附AC码 POJ 24:Divisor and Multiple)