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