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

下面是效果

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

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

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

 

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

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

 using AYUI.UIFrame;
using DG.Tweening;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI; public class EraseMask : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
{ //是否擦除了
public bool isStartEraser; //是否擦除结束了
public bool isEndEraser; //开始事件
public Action eraserStartEvent; //结束事件
public Action eraserEndEvent; public RawImage uiTex;
Texture2D tex;
Texture2D MyTex;
int mWidth;
int mHeight; [Header("Brush Size")]
public int brushSize = ; [Header("Rate")]
public int rate = ; float maxColorA;
float colorA; void Awake()
{
tex = (Texture2D)uiTex.mainTexture;
MyTex = new Texture2D(tex.width, tex.height, TextureFormat.ARGB32, false);
mWidth = MyTex.width;
mHeight = MyTex.height; MyTex.SetPixels(tex.GetPixels());
MyTex.Apply();
uiTex.texture = MyTex;
maxColorA = MyTex.GetPixels().Length;
colorA = ;
isEndEraser = false;
isStartEraser = false; } /// <summary>
/// 贝塞尔平滑
/// </summary>
/// <param name="start">起点</param>
/// <param name="mid">中点</param>
/// <param name="end">终点</param>
/// <param name="segments">段数</param>
/// <returns></returns>
public Vector2[] Beizier(Vector2 start, Vector2 mid, Vector2 end, int segments)
{
float d = 1f / segments;
Vector2[] points = new Vector2[segments - ];
for (int i = ; i < points.Length; i++)
{
float t = d * (i + );
points[i] = ( - t) * ( - t) * mid + * t * ( - t) * start + t * t * end;
}
List<Vector2> rps = new List<Vector2>();
rps.Add(mid);
rps.AddRange(points);
rps.Add(end);
return rps.ToArray();
} bool startDraw = false;
bool twoPoints = false;
Vector2 lastPos;//最后一个点
Vector2 penultPos;//倒数第二个点
float radius = 12f;
float distance = 1f; #region 事件
public void OnPointerDown(PointerEventData eventData)
{
if (isEndEraser) { return; }
startDraw = true;
penultPos = eventData.position;
CheckPoint(penultPos);
} public void OnDrag(PointerEventData eventData)
{
if (isEndEraser) { return; }
if (twoPoints && Vector2.Distance(eventData.position, lastPos) > distance)//如果两次记录的鼠标坐标距离大于一定的距离,开始记录鼠标的点
{
Vector2 pos = eventData.position;
float dis = Vector2.Distance(lastPos, pos); CheckPoint(eventData.position);
int segments = (int)(dis / radius);//计算出平滑的段数
segments = segments < ? : segments;
if (segments >= ) { segments = ; }
Vector2[] points = Beizier(penultPos, lastPos, pos, segments);//进行贝塞尔平滑
for (int i = ; i < points.Length; i++)
{
CheckPoint(points[i]);
}
lastPos = pos;
if (points.Length > )
penultPos = points[points.Length - ];
}
else
{
twoPoints = true;
lastPos = eventData.position;
}
} public void OnPointerUp(PointerEventData eventData)
{
if (isEndEraser) { return; }
//CheckPoint(eventData.position);
startDraw = false;
twoPoints = false;
} #endregion void CheckPoint(Vector3 pScreenPos)
{
Vector3 worldPos = Camera.main.ScreenToWorldPoint(pScreenPos);
Vector3 localPos = uiTex.gameObject.transform.InverseTransformPoint(worldPos); if (localPos.x > -mWidth / && localPos.x < mWidth / && localPos.y > -mHeight / && localPos.y < mHeight / )
{
for (int i = (int)localPos.x - brushSize; i < (int)localPos.x + brushSize; i++)
{
for (int j = (int)localPos.y - brushSize; j < (int)localPos.y + brushSize; j++)
{
if (Mathf.Pow(i - localPos.x, ) + Mathf.Pow(j - localPos.y, ) > Mathf.Pow(brushSize, ))
continue;
if (i < ) { if (i < -mWidth / ) { continue; } }
if (i > ) { if (i > mWidth / ) { continue; } }
if (j < ) { if (j < -mHeight / ) { continue; } }
if (j > ) { if (j > mHeight / ) { continue; } } Color col = MyTex.GetPixel(i + (int)mWidth / , j + (int)mHeight / );
if (col.a != 0f)
{
col.a = 0.0f;
colorA++;
MyTex.SetPixel(i + (int)mWidth / , j + (int)mHeight / , col);
}
}
} //开始刮的时候 去判断进度
if (!isStartEraser)
{
isStartEraser = true;
InvokeRepeating("getTransparentPercent", 0f, 0.2f);
if (eraserStartEvent != null)
eraserStartEvent.Invoke();
} MyTex.Apply();
}
} double fate; /// <summary>
/// 检测当前刮刮卡 进度
/// </summary>
/// <returns></returns>
public void getTransparentPercent()
{
if (isEndEraser) { return; } fate = colorA / maxColorA * ; fate = (float)Math.Round(fate, ); // Debug.LogError("当前百分比: " + fate); if (fate >= rate)
{
isEndEraser = true;
CancelInvoke("getTransparentPercent");
gameObject.SetActive(false); //触发结束事件
if (eraserEndEvent != null)
eraserEndEvent.Invoke(); }
} }

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

提取码:da7t

Unity 实现橡皮擦效果的更多相关文章

  1. 2015.4.25-2015.5.1 字符串去重,比例圆设计,中奖机和canvas橡皮擦效果等

    1.字符串去重,html模板取值   2.javascript正则表达式之$1...$9   3.jquery插件   4.返回上一页并刷新 解决方法: <a href ="javas ...

  2. unity传送门类似效果实现

    简述 在传送门中,核心的玩法是在地上或者墙上打开2个可以联通的洞来实现传送的效果.以此扩展加入解谜要素构成游戏的核心. 这里尝试使用unity来实现传送门的核心功能,具体功能分析如下: 1.传送门的模 ...

  3. Unity Shader - 消融效果原理与变体

    基本原理与实现 主要使用噪声和透明度测试,从噪声图中读取某个通道的值,然后使用该值进行透明度测试. 主要代码如下: fixed cutout = tex2D(_NoiseTex, i.uvNoiseT ...

  4. unity,荧光效果(bloom)实现过程

    两个月前,刚接触unity的时候费了半天劲儿做了个荧光效果(见:http://www.cnblogs.com/wantnon/p/4430749.html),今天终于抽空整理了一下,把过程写下来. 荧 ...

  5. 关于Unity中粒子效果的使用

    粒子效果1: 游戏中会有很炫酷的特效,比如爆炸,水花,火焰等;2: unity提供粒子编辑器,方便特效人员来开发很炫酷的特效;3.粒子效果一般有专门的粒子特效师来做,我们只需要拿来用就好了,很多参数没 ...

  6. unity 图片 粉碎效果 破碎效果

    效果: 点击按钮后: 这些碎片具有物理碰撞效果,下面会有隐形的支柱垫着碎片,n秒后支柱消失,碎片落下 当然你也可以控制生成的碎片,让他们从下而上一块一块地落下 插件源码: https://github ...

  7. Unity光晕剑效果的Shader简单实现

    最近遇到了一个需求,想要一种在刀剑上带有光晕的酷炫效果,甚至是还想要有闪烁呼吸效果,于是就写了一个简单的叫LightSwrod的Shader去实现,先上图看看效果吧. 简单展示 这是剑本身的样子 这是 ...

  8. Unity音乐喷泉效果

    本文参考了该文,其素材也取之于该处 效果 实现效果(根据音乐的高低会产生不同的波纹): 可以观看视频来获得更好的体验. 波纹的实现 先模拟出如下效果: 通过鼠标的点击,产生一个扩散的圆圈. 如上图所示 ...

  9. android 实现橡皮擦效果以及保存涂鸦的功能

    实现涂鸦.擦除.保存的功能 设置画笔为橡皮擦功能 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 如果你的画出来的是 ...

随机推荐

  1. webpack4 Cannot find module '@babel/core'

    Error: // webpackCannot find module '@babel/core'解决办法一: 原因"babel-loader": "^8.0.0&quo ...

  2. MySQL安装到最后一步未响应MySQL Server Instance Configuration Wizard

    MySQL安装到最后一步未响应 第一个方法: 打开C盘,并且显示隐藏文件,然后在C盘下就能找到一个文件夹叫  "ProgamData"  ,打开它,删除里面的  "mys ...

  3. 使用jdk自带的线程池。加载10个线程。

    在开发中使用线程,经常不经意间就new Thread()一个出来,然后发现,这样做不是很好,特别是很多线程同时处理的时候,会出现CPU被用光导致机器假死,线程运行完成自动销毁后,又复活的情况. 所以在 ...

  4. C# 判断一个string型的时间格式是否正确

    在项目开发过程中,由于各种坑爹的需求,我们可能需要用户自己手动输入时间,不过这种功能一般都出现在自己家的后台里面,咳咳,言归正传.既然如此,那么这个时候我们就需要对用户手动输入的时间格式进行验证,方法 ...

  5. python修改linux主机ip

    修改虚拟机的主机ip 和hostname import os, sys def conf_ip(ip): iplist = [] f = open("/etc/sysconfig/netwo ...

  6. MNIST 数据集介绍

    在学习机器学习的时候,首要的任务的就是准备一份通用的数据集,方便与其他的算法进行比较. MNIST数据集是一个手写数字数据集,每一张图片都是0到9中的单个数字,比如下面几个:     MNIST数据库 ...

  7. AtCoder Beginner Contest 116 C题 【题意:可以在任意区间【L,R】上加1,求通过最少加1次数得到题目给定的区间】】{思维好题}

    C - Grand Garden In a flower bed, there are NN flowers, numbered 1,2,......,N1,2,......,N. Initially ...

  8. LOJ #121. 「离线可过」动态图连通性 LCT维护最大生成树

    这个还是比较好理解的. 你考虑如果所有边构成一棵树的话直接用 LCT 模拟一波操作就行. 但是可能会出现环,于是我们就将插入/删除操作按照时间排序,然后依次进行. 那么,我们就要对我们维护的生成树改变 ...

  9. luogu2034

    /* * 正难则反 * f[i] 表示前 i 个数中被删除的数的最小和 * f[i] = min(f[j]) + num, i - k + 1 <= j < i; * 单调队列维护 */ ...

  10. LOJ6436. 「PKUSC2018」神仙的游戏 [NTT]

    传送门 思路 首先通过各种手玩/找规律/严谨证明,发现当\(n-i\)为border当且仅当对于任意\(k\in[0,i)\),模\(i\)余\(k\)的位置没有同时出现0和1. 换句话说,拿出任意一 ...