Unity實現一個可擦除的畫板


  好久沒寫博客了,這次我們來實現一個基於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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM