Unity DOTS纯ECS写一个类似UGUI的EventSystem(实现IPointerDownHandler/IPointerUpHandler/IBeginDragHandler等)

这篇文章主要展示下在Unity的ProjectTiny环境中用纯ECS代码实现UGUI里的EventSystem,包括常用的IPointerDownHandler、IPointerUpHandler、IBeginDragHandler、IDragHandler、IEndDragHandler、IPointerEnterHandler、IPointerExitHandler、IPointerClickHandler等功能。

虽然ProjectTiny里有自带的Button等UI,但是它的点击事件并不是通用的,无法随便给想要的2D entity加上点击事件。不过ProjectTiny提供了最基本的InputSystem,可以获得输入数据。根据这些数据,再处理下,就可以实现UGUI里的那几个Handler了,然后就可以让任意的2D entity(带RectTransform的entity)响应按下抬起点击滑动等事件,还有游戏中常用的鼠标滑动到物品icon上就弹出一个tip,滑出icon后tip消失(也就是IPointerEnter/IPointerExit的功能)。

需要注意一点,由于IComponentData中不能存放NativeList这种Container,所以用的是IBufferElementData,跟数组用法差不多,可以动态增长,但是增删比较麻烦。也可以直接在System里用一个NativeList来存放数据,但是这样不够ECS,而且数据不多,遍历几遍数组对性能影响不会太大。

看代码。代码只是展示一下实现方法,可以继续优化。

using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
using Unity.Tiny.UI;
using Unity.Tiny;
using Unity.Tiny.Input;
using Unity.Tiny.Rendering;
using Unity.Collections;

namespace wangtal.EventSystem {
   
    public interface IPointerDownHandler {
   }

    public interface IPointerUpHandler {
   }

    public interface IPointerClickHandler {
   }

    public interface IPointerEnterHandler {
   }

    public interface IPointerExitHandler {
   }

    public interface IBeginDragHandler {
   }

    public interface IDragHandler {
   }

    public interface IEndDragHandler {
   }

    public interface ICancelHandler {
   }

    internal struct PointerEventData : IBufferElementData {
   
        internal enum TriggerState : byte {
   
            None = 0 << 0,
            PointerDown = 1 << 0,
            PointerUp = 1 << 1,
            PointerClick = 1 << 2,
            BeginDrag = 1 << 3,
            Drag = 1 << 4,
            EndDrag = 1 << 5,
            PointerEnter = 1 << 6,
            PointerExit = 1 << 7
        }

        public TriggerState State;

        public int PointerId;

        public Entity Target;

        // 当前位置
        public float2 Position;

        // 滑动间隔
        public float2 Delta;

        // 按下时的位置
        public float2 PressPosition;
    }

	public class InputSystemGroup : ComponentSystemGroup
    {
   
        const int MaxTriggerEvent = 10;

        protected override void OnCreate()
        {
   
            base.OnCreate();
            var entity = EntityManager.CreateEntity();
            var buffer = EntityManager.AddBuffer<PointerEventData>(entity);
            for (int i = 0; i < MaxTriggerEvent; i++) {
   
                PointerEventData data = new PointerEventData {
   
                    State = PointerEventData.TriggerState.None, PointerId = -1, Target = Entity.Null, Position = float2.zero, Delta = float2.zero, PressPosition = float2.zero
                };
                buffer.Add(data);
            }
        }
    }

	[UpdateInGroup(typeof(InputSystemGroup))]
    unsafe public class EventSystem : SystemBase
    {
   
        private ScreenToWorld screenToWorld;

        private InputSystem inputSystem;

        protected override void OnCreate()
        {
   
            base.OnCreate();

            screenToWorld = World.GetExistingSystem<ScreenToWorld>();
            inputSystem = World.GetExistingSystem<InputSystem>();
        }

        protected override void OnUpdate()
        {
   
            var input = inputSystem;
            Entities.ForEach((Entity entity, ref DynamicBuffer<PointerEventData> eventDatas) => {
   
                PointerEventData* p = (PointerEventData*)eventDatas.GetUnsafePtr();
                for (int i = 0; i < eventDatas.Length; i++, p++) {
   
                    ref var eventData = ref UnsafeUtility.AsRef<PointerEventData>(p);//eventDatas[i];
                    if (eventData.State == PointerEventData.TriggerState.PointerDown ||
                        eventData.State == PointerEventData.TriggerState.PointerUp ||
                        eventData.State == PointerEventData.TriggerState.BeginDrag ||
                        eventData.State == PointerEventData.TriggerState
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我正在帮您寻找相关资源并准备回答您的问题。 以下是一个抗锯齿的 Unity UGUI Shader 实现的示例代码: ``` Shader "Custom/UGUI-AntiAliasing" { Properties { _MainTex ("Texture", 2D) = "white" {} _Color ("Color", Color) = (1,1,1,1) _Multiplier ("Multiplier", Range(0, 1)) = 0.5 _Outline ("Outline", Range(0, 1)) = 0.2 } SubShader { Tags {"Queue"="Transparent" "RenderType"="Transparent"} LOD 100 Pass { ZWrite Off Cull Off Fog { Mode Off } Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; fixed4 color : COLOR; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; float4 color : COLOR; }; sampler2D _MainTex; float _Multiplier; float _Outline; fixed4 _Color; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; o.color = v.color * _Color; return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv) * i.color; float dist = length(ddx(i.vertex.xy) + ddy(i.vertex.xy)); float alpha = smoothstep(_Outline-_Multiplier, _Outline, dist); col.a *= alpha; return col; } ENDCG } } FallBack "UI/Default" } ``` 您可以将上述代码保存到一个`.shader` 文件中,再将其添加到您的 Unity 项目中,即可使用此Shader。 请注意:Shader中的`_Multiplier`和`_Outline`参数是用来控制描边和抗锯齿程度的。您可以根据自己的需求进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值