From acea7b2e728787a0d83bbf83c8c1f042d2c32e7e Mon Sep 17 00:00:00 2001 From: chai <215380520@qq.com> Date: Mon, 3 Jun 2024 10:15:45 +0800 Subject: + plugins project --- .../source/MonoGame.Extended.Tweening/Tweener.cs | 133 +++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 Plugins/MonoGame.Extended/source/MonoGame.Extended.Tweening/Tweener.cs (limited to 'Plugins/MonoGame.Extended/source/MonoGame.Extended.Tweening/Tweener.cs') diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tweening/Tweener.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tweening/Tweener.cs new file mode 100644 index 0000000..61b55f9 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tweening/Tweener.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using Microsoft.Xna.Framework; + +namespace MonoGame.Extended.Tweening +{ + public class Tweener : IDisposable + { + public Tweener() + { + } + + public void Dispose() + { + CancelAll(); + _activeTweens.Clear(); + _memberCache.Clear(); + } + + public long AllocationCount { get; private set; } + + private readonly List _activeTweens = new List(); + + public Tween TweenTo(TTarget target, Expression> expression, TMember toValue, float duration, float delay = 0f) + where TTarget : class + where TMember : struct + { + switch (toValue) + { + case Color toValueColor: + return (Tween)(object)TweenTo(target, expression as Expression>, toValueColor, duration, delay); + default: + return TweenTo>(target, expression, toValue, duration, delay); + } + + } + + public Tween TweenTo(TTarget target, Expression> expression, TMember toValue, float duration, float delay = 0f) + where TTarget : class + where TMember : struct + where TTween : Tween + { + var memberExpression = (MemberExpression)expression.Body; + var memberInfo = memberExpression.Member; + var member = GetMember(target, memberInfo.Name); + var activeTween = FindTween(target, member.Name); + + activeTween?.Cancel(); + + AllocationCount++; + var tween = (TTween)Activator.CreateInstance(typeof(TTween), + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, + new object[]{target, duration, delay, member, toValue}, null); + _activeTweens.Add(tween); + return tween; + } + + public void Update(float elapsedSeconds) + { + for (var i = _activeTweens.Count - 1; i >= 0; i--) + { + var tween = _activeTweens[i]; + + tween.Update(elapsedSeconds); + + if (!tween.IsAlive) + _activeTweens.RemoveAt(i); + } + } + + public Tween FindTween(object target, string memberName) + { + return _activeTweens.FirstOrDefault(t => t.Target == target && t.MemberName == memberName); + } + + public void CancelAll() + { + foreach (var tween in _activeTweens) + tween.Cancel(); + } + + public void CancelAndCompleteAll() + { + foreach (var tween in _activeTweens) + tween.CancelAndComplete(); + } + + private struct TweenMemberKey + { +#pragma warning disable 414 + public object Target; + public string MemberName; +#pragma warning restore 414 + } + + private readonly Dictionary _memberCache = new Dictionary(); + + private TweenMember GetMember(object target, string memberName) + where T : struct + { + var key = new TweenMemberKey { Target = target, MemberName = memberName }; + + if (_memberCache.TryGetValue(key, out var member)) + return (TweenMember) member; + + member = CreateMember(target, memberName); + _memberCache.Add(key, member); + return (TweenMember) member; + } + + private TweenMember CreateMember(object target, string memberName) + where T : struct + { + AllocationCount++; + + var type = target.GetType(); + var property = type.GetTypeInfo().GetProperty(memberName); + + if (property != null) + return new TweenPropertyMember(target, property); + + var field = type.GetTypeInfo().GetField(memberName); + + if (field != null) + return new TweenFieldMember(target, field); + + throw new InvalidOperationException($"'{memberName}' is not a property or field of the target"); + } + } +} -- cgit v1.1-26-g67d0