先上效果图,红色部分为涂色:
场景节点
绘制节点
// 挂在UICamera上
public class UIManager : MonoBehaviour {
public static UIManager Instance;
public Camera camera;
public Canvas canvas;
void Awake () {
Instance = this;
camera = GetComponent<Camera>();
canvas = camera.transform.GetChild(0).GetComponent<Canvas>();
}
}
涂色类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class DrawItem : MonoBehaviour {
public Color drawColor = Color.red; // 绘画颜色
private RawImage drawImage; // Image的Texture是只读的,如果要进行操作则用RawImage
private Texture2D drawTexture; // 绘制的材质
private Vector3 preMouseClickPos;
private bool isDrawing;
private Canvas canvas;
private Vector2 canvasSize;
void Start () {
drawImage = GetComponent<RawImage>();
drawTexture = Instantiate(drawImage.mainTexture) as Texture2D; // 绘制的材质,需要新建一个,避免影响原来的图片,注意类型为2D
drawImage.texture = drawTexture;
isDrawing = false;
canvas = UIManager.Instance.canvas;
canvasSize = canvas.GetComponent<CanvasScaler>().referenceResolution;
}
void Update () {
// 鼠标点击
if (Input.GetMouseButtonDown(0))
{
// EventSystem是UI的事件系统,所以IsPointerOverGameObject中的GameObject是针对UI的,而不是普遍意义上的GameObject
if (EventSystem.current.IsPointerOverGameObject())
{
isDrawing = true;
preMouseClickPos = Input.mousePosition;
//Debug.Log("preMouseClickPos=" + preMouseClickPos);
Draw(Input.mousePosition);
}
}
else if (Input.GetMouseButton(0))
{
if (isDrawing && preMouseClickPos != Input.mousePosition)
{
Draw(Input.mousePosition);
//LerpDraw(Input.mousePosition);
preMouseClickPos = Input.mousePosition;
}
}
else if (Input.GetMouseButtonUp(0))
{
if (EventSystem.current.IsPointerOverGameObject())
{
isDrawing = false;
}
}
}
private void Draw(Vector2 mousePos2D)
{
//Debug.Log("绘画");
// 将鼠标位置转换为在绘制材质的坐标
Vector2 clickTexturePos;
//Vector2 mousePos2D = Input.mousePosition;
Vector2 textureSize = new Vector2(drawTexture.width, drawTexture.height);
RectTransform rectTran = transform as RectTransform;
// 获取绘制材质在uicamera的屏幕坐标
Vector2 textureCameraPos = RectTransformUtility.WorldToScreenPoint(UIManager.Instance.camera, rectTran.position);
// 当前绘制材质左下角第一个点的实际屏幕坐标
Vector2 firsePointPos = textureCameraPos - textureSize / 2; // 默认RectTransform的Anchors和Pivot参数都为0.5
// 鼠标在绘制材质的坐标
clickTexturePos = mousePos2D - firsePointPos;
//float preAlpha;
// 遍历材质的像素,并进行涂色
for (int x = 0; x < drawTexture.width; x++)
{
for (int y = 0; y < drawTexture.height; y++)
{
if (Vector2.Distance(new Vector2(x, y), clickTexturePos) < 10) // 在一定距离内的都涂上颜色
{
//preAlpha = drawTexture.GetPixel(x, y).a;
//drawColor.a = preAlpha; // 透明度不变
drawTexture.SetPixel(x, y, drawColor);
}
}
}
drawTexture.Apply(); // 修改完后需要应用才能生效
}
// 差值涂色,可以避免鼠标拖动过快,涂色不连续的问题。但是拖动越快越卡
// 在两次涂色中间插值涂色
Vector2 _lastPoint = Vector2.zero;
float _brushLerpSize = 10;
private void LerpDraw(Vector2 point)
{
Draw(point);
if (_lastPoint == Vector2.zero)
{
_lastPoint = point;
return;
}
float dis = Vector2.Distance(point, _lastPoint);
if (dis > _brushLerpSize)
{
Vector2 dir = (point - _lastPoint).normalized;
int num = (int)(dis / _brushLerpSize);
for (int i = 0; i < num; i++)
{
Vector2 newPoint = _lastPoint + dir * (i + 1) * _brushLerpSize;
Draw(newPoint);
}
}
_lastPoint = point;
}
}
材质类型为Sprite,属性必须选择可读写
IsPointerOverGameObject函数,兼容安卓端使用:
if (Input.GetMouseButtonDown(0) || (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began))
{
#if UNITY_ANDROID && !UNITY_EDITOR
if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
#else
if (EventSystem.current.IsPointerOverGameObject())
#endif
Debug.Log("当前触摸在UI上");
else
Debug.Log("当前没有触摸在UI上");
}
适配不同分辨率
其中Canvas节点的Canvas Scaler组件的UI Scale Mode为Scale With Screen Size
修改上面涂色方法里面的计算鼠标点击材质位置即可。
Vector2 clickTexturePos;
Vector2 scaleFacor = new Vector2(Screen.width / referenceResolution.x, Screen.height / referenceResolution.y); // 缩放系数,当前屏幕分辨率/解决方案的大小
Vector2 textureSize = new Vector2(m_tex2D.width * scaleFacor.x, m_tex2D.height * scaleFacor.y);
RectTransform rectTran = transform as RectTransform;
// 获取绘制材质在uicamera的屏幕坐标
Vector2 textureCameraPos = RectTransformUtility.WorldToScreenPoint(m_camera, rectTran.position);
// 当前绘制材质左下角第一个点的实际屏幕坐标
Vector2 firsePointPos = textureCameraPos - textureSize / 2; // 默认RectTransform的Anchors和Pivot参数都为0.5
// 鼠标点击位置在绘制材质的坐标
clickTexturePos = mousePos2D - firsePointPos;
clickTexturePos = new Vector2(clickTexturePos.x / scaleFacor.x, clickTexturePos.y / scaleFacor.y);