好久没写博客了,这次我们来实现一个基于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

posted on 2020-07-13 16:23  百晓灵狐  阅读(2090)  评论(0编辑  收藏  举报