Unity 实现橡皮擦效果

     我所实现的橡皮擦效果是设置图片某点的像素的透明度为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

 

posted @ 2019-10-08 12:00  晚安、枕头  阅读(6212)  评论(0编辑  收藏  举报