我所实现的橡皮擦效果是设置图片某点的像素的透明度为0,来简单实现擦除效果的;

     下面是效果

  首先需要注意两点:1:设置 Main Camera 的 projection 属性为Orthographic

                                    2:设置Canvas 的Render Mode 为 Screen Space - Camera

然后找一张图片,导入Unity 中并修改它的读写权限,创建Raw Imager

 

 这样启动之后就可以测试效果了。

附上代码:(代码中有解释)

  1 using AYUI.UIFrame;
  2 using DG.Tweening;
  3 using System;
  4 using System.Collections;
  5 using System.Collections.Generic;
  6 using UnityEngine;
  7 using UnityEngine.EventSystems;
  8 using UnityEngine.UI;
  9
 10 public class EraseMask : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
 11 {
 12
 13     //是否擦除了
 14     public bool isStartEraser;
 15
 16     //是否擦除结束了
 17     public bool isEndEraser;
 18
 19     //开始事件
 20     public Action eraserStartEvent;
 21
 22     //结束事件
 23     public Action eraserEndEvent;
 24
 25     public RawImage uiTex;
 26     Texture2D tex;
 27     Texture2D MyTex;
 28     int mWidth;
 29     int mHeight;
 30
 31     [Header("Brush Size")]
 32     public int brushSize = 50;
 33
 34     [Header("Rate")]
 35     public int rate = 90;
 36
 37     float maxColorA;
 38     float colorA;
 39
 40     void Awake()
 41     {
 42         tex = (Texture2D)uiTex.mainTexture;
 43         MyTex = new Texture2D(tex.width, tex.height, TextureFormat.ARGB32, false);
 44         mWidth = MyTex.width;
 45         mHeight = MyTex.height;
 46
 47         MyTex.SetPixels(tex.GetPixels());
 48         MyTex.Apply();
 49         uiTex.texture = MyTex;
 50         maxColorA = MyTex.GetPixels().Length;
 51         colorA = 0;
 52         isEndEraser = false;
 53         isStartEraser = false;
 54
 55     }
 56
 57
 58     /// <summary>
 59     /// 贝塞尔平滑
 60     /// </summary>
 61     /// <param name="start">起点</param>
 62     /// <param name="mid">中点</param>
 63     /// <param name="end">终点</param>
 64     /// <param name="segments">段数</param>
 65     /// <returns></returns>
 66     public Vector2[] Beizier(Vector2 start, Vector2 mid, Vector2 end, int segments)
 67     {
 68         float d = 1f / segments;
 69         Vector2[] points = new Vector2[segments - 1];
 70         for (int i = 0; i < points.Length; i++)
 71         {
 72             float t = d * (i + 1);
 73             points[i] = (1 - t) * (1 - t) * mid + 2 * t * (1 - t) * start + t * t * end;
 74         }
 75         List<Vector2> rps = new List<Vector2>();
 76         rps.Add(mid);
 77         rps.AddRange(points);
 78         rps.Add(end);
 79         return rps.ToArray();
 80     }
 81
 82
 83
 84     bool startDraw = false;
 85     bool twoPoints = false;
 86     Vector2 lastPos;//最后一个点
 87     Vector2 penultPos;//倒数第二个点
 88     float radius = 12f;
 89     float distance = 1f;
 90
 91
 92
 93     #region 事件
 94     public void OnPointerDown(PointerEventData eventData)
 95     {
 96         if (isEndEraser) { return; }
 97         startDraw = true;
 98         penultPos = eventData.position;
 99         CheckPoint(penultPos);
100     }
101
102     public void OnDrag(PointerEventData eventData)
103     {
104         if (isEndEraser) { return; }
105         if (twoPoints && Vector2.Distance(eventData.position, lastPos) > distance)//如果两次记录的鼠标坐标距离大于一定的距离,开始记录鼠标的点
106         {
107             Vector2 pos = eventData.position;
108             float dis = Vector2.Distance(lastPos, pos);
109
110             CheckPoint(eventData.position);
111             int segments = (int)(dis / radius);//计算出平滑的段数                                              
112             segments = segments < 1 ? 1 : segments;
113             if (segments >= 10) { segments = 10; }
114             Vector2[] points = Beizier(penultPos, lastPos, pos, segments);//进行贝塞尔平滑
115             for (int i = 0; i < points.Length; i++)
116             {
117                 CheckPoint(points[i]);
118             }
119             lastPos = pos;
120             if (points.Length > 2)
121                 penultPos = points[points.Length - 2];
122         }
123         else
124         {
125             twoPoints = true;
126             lastPos = eventData.position;
127         }
128     }
129
130     public void OnPointerUp(PointerEventData eventData)
131     {
132         if (isEndEraser) { return; }
133         //CheckPoint(eventData.position);
134         startDraw = false;
135         twoPoints = false;
136     }
137
138
139     #endregion
140
141
142
143     void CheckPoint(Vector3 pScreenPos)
144     {
145         Vector3 worldPos = Camera.main.ScreenToWorldPoint(pScreenPos);
146         Vector3 localPos = uiTex.gameObject.transform.InverseTransformPoint(worldPos);
147
148         if (localPos.x > -mWidth / 2 && localPos.x < mWidth / 2 && localPos.y > -mHeight / 2 && localPos.y < mHeight / 2)
149         {
150             for (int i = (int)localPos.x - brushSize; i < (int)localPos.x + brushSize; i++)
151             {
152                 for (int j = (int)localPos.y - brushSize; j < (int)localPos.y + brushSize; j++)
153                 {
154                     if (Mathf.Pow(i - localPos.x, 2) + Mathf.Pow(j - localPos.y, 2) > Mathf.Pow(brushSize, 2))
155                         continue;
156                     if (i < 0) { if (i < -mWidth / 2) { continue; } }
157                     if (i > 0) { if (i > mWidth / 2) { continue; } }
158                     if (j < 0) { if (j < -mHeight / 2) { continue; } }
159                     if (j > 0) { if (j > mHeight / 2) { continue; } }
160
161                     Color col = MyTex.GetPixel(i + (int)mWidth / 2, j + (int)mHeight / 2);
162                     if (col.a != 0f)
163                     {
164                         col.a = 0.0f;
165                         colorA++;
166                         MyTex.SetPixel(i + (int)mWidth / 2, j + (int)mHeight / 2, col);
167                     }
168                 }
169             }
170
171
172             //开始刮的时候 去判断进度
173             if (!isStartEraser)
174             {
175                 isStartEraser = true;
176                 InvokeRepeating("getTransparentPercent", 0f, 0.2f);
177                 if (eraserStartEvent != null)
178                     eraserStartEvent.Invoke();
179             }
180
181             MyTex.Apply();
182         }
183     }
184
185
186
187     double fate;
188
189
190     /// <summary>
191     /// 检测当前刮刮卡 进度
192     /// </summary>
193     /// <returns></returns>
194     public void getTransparentPercent()
195     {
196         if (isEndEraser) { return; }
197
198
199         fate = colorA / maxColorA * 100;
200
201         fate = (float)Math.Round(fate, 2);
202
203         // Debug.LogError("当前百分比: " + fate);
204
205         if (fate >= rate)
206         {
207             isEndEraser = true;
208             CancelInvoke("getTransparentPercent");
209             gameObject.SetActive(false);
210
211             //触发结束事件
212             if (eraserEndEvent != null)
213                 eraserEndEvent.Invoke();
214
215         }
216     }
217
218 }
View Code

另附一张好用的图片 :https://pan.baidu.com/s/1Z_GTuwPouFtiSgVcFfrAcg

提取码:da7t

02-12 14:09