好久没写博客了,这次我们来实现一个基于Unity的画板。
首先简单搭建场景,我们需要一个画布DrawCanvas, 一个RawImage, 三个按钮(Eraser, Pencil, Clear)
我们的核心逻辑就是获取RawImage的Texture,然后在鼠标点击处将我们设置好的颜色给赋值给Texture
然后我们将挂载MainPaint.cs脚本到DrawCanvas上
具体代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MainPaint : MonoBehaviour {
PaintComponent paintCpnt; // 执行绘画的类,
Texture texture; // RawImage的texture
public float minLenth = 0.5f; // 最大绘画距离,过大的话,绘画内容会变成一串不连续的点
public Color color = Color.red; // 预设的颜色
private bool first = true; // 判断要绘制的当前点,是不是本次绘画的第一笔
Vector2 vec;
Vector2 pre_vec;
Vector2 com_vec;
Vector2 final_vec;
void Awake()
{
baseInit(); // 先执行,初始化paintCpnt(绘画组件)
paintCpnt.clear(); // 清空texture的内容
registEvent(); // 注册事件(铅笔,橡皮,清空三个按钮)
}
void Start () {
}
void Update () {
for (int time = 0; time < 5; time++)
{
paintByCpnt();
}
}
// 初始化绘画组件
void baseInit()
{
GameObject obj = GameObject.Find("DrawCanvas/RawImage");
if (obj != null) {
paintCpnt = new PaintComponent(obj.GetComponent<RawImage>(), new Texture2D(Screen.width, Screen.height));
texture = paintCpnt.getTexture();
IDraw draw = new DrawLineType();
paintCpnt.setDraw(draw);
}
}
// 注册事件
void registEvent()
{
// 点击铅笔,将绘画组件中的绘画接口,替换为实现了IDraw 接口的DrawLineType的实例用于画线
ActionMrg.Instance.addEvent("Pen", () =>
{
IDraw draw = new DrawLineType();
paintCpnt.setDraw(draw);
});
// 点击铅笔,将绘画组件中的绘画接口,替换为实现了IDraw 接口的CleanLineType的实例用于橡皮擦除
ActionMrg.Instance.addEvent("Eraser", () =>
{
IDraw draw = new CleanLineType();
paintCpnt.setDraw(draw);
});
// 点击铅笔,调用清除方法,进行清除
ActionMrg.Instance.addEvent("Clear", () =>
{
paintCpnt.clear();
});
}
// 绘画方法
void paintByCpnt()
{
if (Input.GetMouseButton(0))
{
vec = Input.mousePosition;
if (first)
{
final_vec = vec;
paintCpnt.paint(final_vec, color);
first = false;
}
else
{
com_vec = vec - pre_vec;
if (com_vec.magnitude > minLenth)
{
final_vec = pre_vec + com_vec.normalized * minLenth; // 插值
paintCpnt.paint(final_vec, color);
}
else
{
final_vec = vec;
paintCpnt.paint(final_vec, color);
}
}
pre_vec = final_vec;
}
if (Input.GetMouseButtonUp(0))
{
first = true;
}
}
}
MainPaint.cs介绍完了,接下来是PaintComponent.cs类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PaintComponent{
public PaintComponent() {
}
// 创建对象时,我们这里,需要得刀RawImage的 Texture
public PaintComponent(RawImage rImage, Texture2D texture)
{
setRawImage(rImage);
setTexture(texture);
prepareCpnt();
}
private RawImage rawImage;
public void setRawImage(RawImage image)
{
this.rawImage = image;
}
public RawImage getRawImage()
{
return this.rawImage;
}
private Texture2D texture;
public void setTexture(Texture2D tex)
{
this.texture = tex;
}
public Texture2D getTexture()
{
return this.texture;
}
private IDraw drawType;
public void setDraw(IDraw draw) {
// 设置绘画接口,通过设置不同的绘制接口实例来达到不同的功能
this.drawType = draw;
}
public void prepareCpnt() {
if(this.rawImage != null && this.texture != null)
{
this.rawImage.texture = this.texture;
}
}
// 清除功能
public void clear()
{
// 原理跟其他的绘制一样,也是通过IDraw接口的不同实例来实现清除功能
IDraw clearType = new ClearType();
clearType.paint(this.texture, new Vector3(0, 0, 0), new Color(0, 0, 0, 0));
}
// 绘制功能,调用之前设置的drawType来进行绘制
public void paint(Vector3 vec, Color color)
{
if (this.drawType != null)
{
this.drawType.paint(this.texture, vec, color);
}
}
}
接下来我们介绍绘制接口IDraw和三个实现了该接口的类
首先是IDraw接口
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IDraw{
void paint(Texture2D text, Vector3 vec, Color color);
}
其实只有一个方法需要实现类去实现
然后是DrawLineType.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DrawLineType : IDraw
{
public void paint(Texture2D text, Vector3 vec, Color color)
{
if (text != null && vec != null && color != null)
{
for (int x = -2; x < 3; x++)
{
for (int y = -2; y < 3; y++)
{
if ((x * x + y * y) <= 25 && (int)vec.x + x < 350)
{
text.SetPixel((int)vec.x + x, (int)vec.y + y, color); // 其实就是在鼠标指向的像素赋值
}
}
}
text.Apply(); // 应用
}
}
}
紧接着是CleanLineType.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CleanLineType : IDraw
{
private Color clearColor = new Color(0, 0, 0, 0); // 其实就是把鼠标指向的Texture的颜色,赋值成透明的零色【瞎取得名字 哈哈哈】
public void paint(Texture2D text, Vector3 vec, Color color)
{
if (text != null && vec != null && color != null)
{
for (int x = -10; x < 11; x++)
{
for (int y = -10; y < 11; y++)
{
if ((x * x + y * y) <= 25 && (int)vec.x + x < 410)
{
text.SetPixel((int)vec.x + x, (int)vec.y + y, clearColor);
}
}
}
text.Apply();
}
}
}
最后是ClearType.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ClearType : IDraw
{
public void paint(Texture2D text, Vector3 vec, Color color)
{
if (text != null)
{
for (int i = 0; i < text.height; i++)
{
for (int k = 0; k < text.width; k++)
{
text.SetPixel(k, i, color); // 全部赋值成零色
}
}
text.Apply();
}
}
}
然后我们还需要在三个按钮的父物体上挂在Button组管理的脚本,这个脚本在我两年前的博客里介绍过了
这里就不说了;BtnGroupManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class BtnGroupManager : MonoBehaviour
{
// 脚本挂在一个Canvas上,其子物体上有两个Button:Button 喝 Button(1)
delegate void argument(string str);
void Start()
{
argument arg = new argument(test);
for (int i = 0; i < gameObject.GetComponentsInChildren<Button>().Length; i++)
{
Button btn = gameObject.GetComponentsInChildren<Button>()[i];
btn.onClick.RemoveAllListeners();
btn.onClick.AddListener(() =>
{
if (arg != null)
{
arg(btn.name);
}
});
}
}
void onclicked()
{
}
public void test(string str)
{
ActionMrg.Instance.emitEvent(str); // 这里的ActionMrg是用来分发事件的稍后也贴出来
}
}
接下来是我们今天最后一个脚本ActionMrg。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class ActionMrg{
private static ActionMrg instance;
public static ActionMrg Instance
{
get
{
if (instance == null)
{
instance = new ActionMrg();
}
return instance;
}
}
private Dictionary<string, UnityAction> dic = new Dictionary<string, UnityAction>();
public void addEvent(string name, UnityAction action)
{
dic[name] = action;
}
public void removeEvent(string name)
{
dic[name] = null;
}
public void emitEvent(string name)
{
UnityAction uAction = dic[name];
if (uAction != null)
{
uAction.Invoke();
}
}
}
效果:
项目地址:失效可联系作者链接:
https://pan.baidu.com/s/1JHkdnAI-goEF-xVXIKXRZQ
提取码:se5x