281 lines
9.2 KiB
C#
281 lines
9.2 KiB
C#
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.UI;
|
|
|
|
namespace AibisDream
|
|
{
|
|
/// <summary>
|
|
/// 画板组件,支持鼠标拖动绘制(UI Space)
|
|
/// 需要挂载在带有RectTransform和RawImage的GameObject上
|
|
/// </summary>
|
|
[RequireComponent(typeof(RectTransform))]
|
|
[RequireComponent(typeof(RawImage))]
|
|
public class SignArea : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
|
|
{
|
|
[Header("画板设置")]
|
|
[SerializeField] private int textureWidth = 512;
|
|
[SerializeField] private int textureHeight = 512;
|
|
[SerializeField] private Color32 backgroundColor = Color.clear;
|
|
|
|
[Header("画笔设置")]
|
|
[SerializeField] private Color drawColor = Color.black;
|
|
[SerializeField] private int brushSize = 5;
|
|
[SerializeField] private bool smoothDrawing = true; // 是否平滑绘制(连接两点之间的所有点)
|
|
|
|
private Texture2D drawTexture;
|
|
private RawImage drawImage;
|
|
private RectTransform rectTransform;
|
|
|
|
private Vector2 lastDrawPoint;
|
|
private bool isDrawing = false;
|
|
|
|
private void Awake()
|
|
{
|
|
drawImage = GetComponent<RawImage>();
|
|
rectTransform = GetComponent<RectTransform>();
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
InitializeTexture();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 初始化画布纹理
|
|
/// </summary>
|
|
private void InitializeTexture()
|
|
{
|
|
// 创建可读写的纹理
|
|
drawTexture = new Texture2D(textureWidth, textureHeight, TextureFormat.RGBA32, false);
|
|
drawTexture.filterMode = FilterMode.Bilinear;
|
|
|
|
// 填充背景色
|
|
Color[] pixels = new Color[textureWidth * textureHeight];
|
|
for (int i = 0; i < pixels.Length; i++)
|
|
{
|
|
pixels[i] = backgroundColor;
|
|
}
|
|
drawTexture.SetPixels(pixels);
|
|
drawTexture.Apply();
|
|
|
|
// 设置到RawImage
|
|
drawImage.texture = drawTexture;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 将屏幕坐标转换为纹理坐标
|
|
/// </summary>
|
|
private bool ScreenToTextureCoord(Vector2 screenPos, out Vector2 textureCoord)
|
|
{
|
|
textureCoord = Vector2.zero;
|
|
|
|
// 将屏幕坐标转换为UI本地坐标
|
|
if (UIManager.Instance.ScreenPointToLocalPointInRectangle(rectTransform, screenPos, out Vector2 localPoint))
|
|
{
|
|
// 检查是否在RectTransform范围内
|
|
Rect rect = rectTransform.rect;
|
|
if (!rect.Contains(localPoint))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 转换为纹理坐标 (0,0) 到 (textureWidth, textureHeight)
|
|
// localPoint的范围是 (-rect.width/2, -rect.height/2) 到 (rect.width/2, rect.height/2)
|
|
float normalizedX = (localPoint.x + rect.width / 2) / rect.width;
|
|
float normalizedY = (localPoint.y + rect.height / 2) / rect.height;
|
|
|
|
textureCoord.x = normalizedX * textureWidth;
|
|
textureCoord.y = normalizedY * textureHeight;
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 在指定位置绘制
|
|
/// </summary>
|
|
private void DrawAtPoint(Vector2 point)
|
|
{
|
|
int centerX = Mathf.RoundToInt(point.x);
|
|
int centerY = Mathf.RoundToInt(point.y);
|
|
|
|
// 绘制圆形笔刷
|
|
for (int x = -brushSize; x <= brushSize; x++)
|
|
{
|
|
for (int y = -brushSize; y <= brushSize; y++)
|
|
{
|
|
// 检查是否在圆形范围内
|
|
float distance = Mathf.Sqrt(x * x + y * y);
|
|
if (distance <= brushSize)
|
|
{
|
|
int px = centerX + x;
|
|
int py = centerY + y;
|
|
|
|
// 检查边界
|
|
if (px >= 0 && px < textureWidth && py >= 0 && py < textureHeight)
|
|
{
|
|
// 根据距离计算透明度,实现柔和的笔刷效果
|
|
float alpha = 1f - (distance / brushSize);
|
|
Color finalColor = drawColor;
|
|
finalColor.a *= alpha;
|
|
|
|
// 混合颜色
|
|
Color existingColor = drawTexture.GetPixel(px, py);
|
|
Color blendedColor = Color.Lerp(existingColor, finalColor, finalColor.a);
|
|
drawTexture.SetPixel(px, py, blendedColor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 在两点之间绘制线条(平滑绘制)
|
|
/// </summary>
|
|
private void DrawLine(Vector2 start, Vector2 end)
|
|
{
|
|
float distance = Vector2.Distance(start, end);
|
|
int steps = Mathf.CeilToInt(distance);
|
|
|
|
for (int i = 0; i <= steps; i++)
|
|
{
|
|
float t = steps > 0 ? (float)i / steps : 0;
|
|
Vector2 point = Vector2.Lerp(start, end, t);
|
|
DrawAtPoint(point);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 应用绘制更改到纹理
|
|
/// </summary>
|
|
private void ApplyDrawing()
|
|
{
|
|
if (drawTexture != null)
|
|
{
|
|
drawTexture.Apply();
|
|
// 确保RawImage显示更新
|
|
if (drawImage != null && drawImage.texture != drawTexture)
|
|
{
|
|
drawImage.texture = drawTexture;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 清除画布
|
|
/// </summary>
|
|
public void Clear()
|
|
{
|
|
Color[] pixels = new Color[textureWidth * textureHeight];
|
|
for (int i = 0; i < pixels.Length; i++)
|
|
{
|
|
pixels[i] = backgroundColor;
|
|
}
|
|
drawTexture.SetPixels(pixels);
|
|
drawTexture.Apply();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置画笔颜色
|
|
/// </summary>
|
|
public void SetDrawColor(Color color)
|
|
{
|
|
drawColor = color;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置画笔大小
|
|
/// </summary>
|
|
public void SetBrushSize(int size)
|
|
{
|
|
brushSize = Mathf.Max(1, size);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置背景颜色
|
|
/// </summary>
|
|
public void SetBackgroundColor(Color color)
|
|
{
|
|
backgroundColor = color;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存画布为PNG图片
|
|
/// </summary>
|
|
public byte[] SaveToPNG()
|
|
{
|
|
return drawTexture.EncodeToPNG();
|
|
}
|
|
|
|
// EventSystem接口实现
|
|
public void OnPointerDown(PointerEventData eventData)
|
|
{
|
|
if (eventData.button != PointerEventData.InputButton.Left)
|
|
return;
|
|
|
|
if (ScreenToTextureCoord(eventData.position, out Vector2 textureCoord))
|
|
{
|
|
isDrawing = true;
|
|
// 确保第一次点击也能绘制
|
|
lastDrawPoint = textureCoord;
|
|
DrawAtPoint(textureCoord);
|
|
ApplyDrawing();
|
|
|
|
// 强制更新RawImage显示
|
|
if (drawImage != null && drawTexture != null)
|
|
{
|
|
drawImage.texture = drawTexture;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void OnDrag(PointerEventData eventData)
|
|
{
|
|
if (!isDrawing)
|
|
return;
|
|
|
|
if (ScreenToTextureCoord(eventData.position, out Vector2 textureCoord))
|
|
{
|
|
if (smoothDrawing)
|
|
{
|
|
// 平滑绘制:连接两点之间的所有点
|
|
// 如果两点距离太近,直接绘制当前点(避免DrawLine计算出错)
|
|
float distance = Vector2.Distance(lastDrawPoint, textureCoord);
|
|
if (distance < 0.1f)
|
|
{
|
|
DrawAtPoint(textureCoord);
|
|
}
|
|
else
|
|
{
|
|
DrawLine(lastDrawPoint, textureCoord);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 直接绘制当前点
|
|
DrawAtPoint(textureCoord);
|
|
}
|
|
|
|
ApplyDrawing();
|
|
lastDrawPoint = textureCoord;
|
|
}
|
|
}
|
|
|
|
public void OnPointerUp(PointerEventData eventData)
|
|
{
|
|
isDrawing = false;
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
// 清理纹理资源
|
|
if (drawTexture != null)
|
|
{
|
|
Destroy(drawTexture);
|
|
}
|
|
}
|
|
}
|
|
}
|