Unity3D 检测鼠标位置的Sprite像素颜色

思路

  1. 获取鼠标所在屏幕坐标(Vector2)
  2. 通过相机ScreenToWorldPoint(Vector3)转为世界坐标 (注意Vector3的z是距离相机的距离,相机需要正交)
  3. 通过SpriteRenderer访问边界Bounds
  4. 通过Bounds.Contain检测世界坐标是否在SpriteBounds内
  5. 通过比例计算来确定在Sprite内的UV坐标,并根据像素长宽确定像素坐标

float pixelX = (worldPositiopn.x - bounds.min.x) / bounds.size.x * bgSprite.texture.width;
float pixelY = (worldPositiopn.y - bounds.min.y) / bounds.size.y * bgSprite.texture.height;

部分编辑器依赖于OdinInspector,不用可以把红线都删了

实现的效果类似这样,根据边界贴图检测鼠标画线位置是否在范围内请添加图片描述

using Sirenix.OdinInspector;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

namespace Yueh0607.ClothOperations
{
    public class CutBehaviour : MonoBehaviour
    {


        [ShowIf("IsRuntime")]
        [ReadOnly]
        [SerializeField]
        Sprite bgSprite, lineStyleSprite, edgeSprite;
        [ShowIf("IsRuntime")]
        [ReadOnly]
        [SerializeField]
        SpriteRenderer bgRenderer, lineStyleRenderer;
        [SerializeField] Color edgeColor = Color.black;




        bool initialized = false;

#if UNITY_EDITOR
        bool IsRuntime() => Application.isPlaying;
#endif

        /// <summary>
        /// 初始化裁剪行为
        /// </summary>
        /// <param name="bgSprite">背景精灵图</param>
        /// <param name="lineStyleSprite">裁剪线样式精灵图</param>
        /// <param name="edgeSprite">边界范围精灵图(RBGA 0-1 使用(0,0,0,1)表示裁剪线范围)</param>
        public void Initialize(Sprite bgSprite, Sprite lineStyleSprite, Sprite edgeSprite)
        {
            this.bgSprite = bgSprite;
            this.edgeSprite = edgeSprite;
            this.lineStyleSprite = lineStyleSprite;

            bool sizeMatch = (lineStyleSprite.texture.width == bgSprite.texture.width && edgeSprite.texture.width == bgSprite.texture.width)
                && (lineStyleSprite.texture.height == bgSprite.texture.height && edgeSprite.texture.height == bgSprite.texture.height);
            bool rectMatch = (lineStyleSprite.rect == bgSprite.rect && edgeSprite.rect == bgSprite.rect);

            if (!sizeMatch) throw new System.Exception("贴图尺寸不合规");
            if (!rectMatch) throw new System.Exception("精灵尺寸不合规");


            DynamicInitialize();

            initialized = true;
        }

        /// <summary>
        /// 动态内容的初始化
        /// </summary>
        private void DynamicInitialize()
        {
            GameObject bg = new GameObject("CutBackgroundImage");
            bg.transform.SetParent(transform);
            bg.transform.position = Vector3.zero;
            bgRenderer = bg.AddComponent<SpriteRenderer>();
            bgRenderer.sprite = bgSprite;
            GameObject lineStyle = new GameObject("LineStyle");
            lineStyle.transform.SetParent(transform);
            lineStyle.transform.position = Vector3.zero;
            lineStyleRenderer = lineStyle.AddComponent<SpriteRenderer>();
            lineStyleRenderer.sprite = lineStyleSprite;
        }

        /// <summary>
        /// 检查裁剪行为初始化
        /// </summary>
        /// <exception cref="System.Exception"></exception>
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        private void ExceptionCheck()
        {
            if (!initialized) throw new System.Exception("未初始化裁剪行为!");
        }

        /// <summary>
        /// 将世界坐标转换到像素坐标
        /// </summary>
        /// <param name="worldPositiopn"></param>
        /// <param name="pixelPosition"></param>
        /// <returns></returns>
        public bool TransPoint(Vector2 worldPositiopn, out Vector2Int pixelPosition)
        {
            ExceptionCheck();
            Bounds bounds= bgRenderer.bounds;
            if (bounds.Contains(worldPositiopn))
            {
                //get pixelX and pixelY
                float pixelX = (worldPositiopn.x - bounds.min.x) / bounds.size.x * bgSprite.texture.width;
                float pixelY = (worldPositiopn.y - bounds.min.y) / bounds.size.y * bgSprite.texture.height;



                //float pixelX = (worldPositiopn.x - bounds.) / bgSprite.rect.width * bgSprite.texture.width;
                //float pixelY = (worldPositiopn.y - bgSprite.rect.y) / bgSprite.rect.height * bgSprite.texture.height;
                pixelPosition = new Vector2Int(Mathf.RoundToInt(pixelX), Mathf.RoundToInt(pixelY));
                return true;
            }

            pixelPosition = Vector2Int.zero;
            return false;
        }

        /// <summary>
        /// 判断某个世界坐标是否在裁剪线范围内
        /// </summary>
        /// <param name="worldPosition">Sprite所在的坐标系坐标</param>
        /// <returns></returns>
        public bool IsInEdgeRange(Vector2 worldPosition)
        {
            ExceptionCheck();
            bool result = TransPoint(worldPosition, out Vector2Int pixelPosition);
            if (!result) return false;

            Color color = edgeSprite.texture.GetPixel(pixelPosition.x, pixelPosition.y);
            if (color == edgeColor) return true;

            return false;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YUE ZHEN PENG

码字不易,如果你想请我喝杯果汁

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值