Пример #1
0
        public void Blend(Godot.Animation animation, float influence = 1f)
        {
            Ensure.Any.IsNotNull(animation, nameof(animation));

            var slot = Enumerable
                       .Range(1, _overridableSlots)
                       .FirstOrDefault(i => !_overrides.ContainsKey(i));

            if (slot == default(int))
            {
                throw new InvalidOperationException(
                          $"No overridable slots left: total = {_overridableSlots}.");
            }

            var blendNode = OverrideBlendNodePrefix + slot;

            _overrides[slot] = animation.GetName();

            TreePlayer.AnimationNodeSetAnimation(OverrideNodePrefix + slot, animation);
            TreePlayer.Blend2NodeSetAmount(blendNode, influence);

            var reset = Player.GetAnimation(ResetAnimation);

            if (reset == null)
            {
                return;
            }

            var filtered = new HashSet <string>(FindTransformTracks(animation).Select(p => p.ToString()));

            FindTransformTracks(reset)
            .ToList()
            .ForEach(p => TreePlayer.Blend2NodeSetFilterPath(blendNode, p, !filtered.Contains(p.ToString())));
        }
Пример #2
0
        protected virtual void PlayAnimation(
            IEquipmentHolder holder,
            Equipment equipment,
            Option <Node> dropTo,
            Godot.Animation animation,
            IAnimationManager animationManager,
            InteractionContext context)
        {
            animationManager.OnAnimationEvent
            .OfType <TriggerEvent>()
            .Where(e => e.Name == "Action" && e.Argument.Contains(Key))
            .Take(1)
            .TakeUntil(Disposed.Where(identity))
            .Subscribe(_ => Unequip(holder, equipment, dropTo, context), this);

            if (animationManager is IAnimationStateManager stateManager &&
                AnimatorPath.IsSome && StatesPath.IsSome)
            {
                (
                    from animator in AnimatorPath.Bind(stateManager.FindAnimator)
                    from states in StatesPath.Bind(stateManager.FindStates)
                    from state in ActionState
                    select(animator, states, state)).Iter(t =>
                {
                    t.animator.Animation = animation;
                    t.states.Playback.Travel(t.state);
                });
            }
Пример #3
0
        protected static IEnumerable <NodePath> FindTransformTracks(Godot.Animation animation)
        {
            Ensure.That(animation, nameof(animation)).IsNotNull();

            return(Enumerable
                   .Range(0, animation.GetTrackCount())
                   .Select(i => (path: animation.TrackGetPath(i), type: animation.TrackGetType(i)))
                   .Where(t => t.type == Godot.Animation.TrackType.Transform)
                   .Select(t => t.path));
        }
Пример #4
0
        private static IEnumerable <NodePath> FindTransformTracks(Godot.Animation animation)
        {
            var tracks = animation.GetTrackCount();

            return(Enumerable
                   .Range(0, tracks)
                   .Select(i => (animation.TrackGetPath(i), animation.TrackGetType(i)))
                   .Where(t => t.Item2 == Godot.Animation.TrackType.Transform)
                   .Select(t => t.Item1));
        }
Пример #5
0
        public override void Play(Godot.Animation animation, System.Action onFinish = null)
        {
            _oneShotAnimationCallback?.Dispose();

            TreePlayer.AnimationNodeSetAnimation(OneShotNode, animation);
            TreePlayer.OneshotNodeStart(OneShotTriggerNode);

            if (onFinish != null)
            {
                _oneShotAnimationCallback = _scheduler?.Schedule(
                    TimeSpan.FromSeconds(animation.Length), onFinish);
            }
        }
Пример #6
0
        private void AddTrack(Godot.Animation animation)
        {
            var args = new Dictionary <object, object>
            {
                { "method", "Reset" },
                { "args", new string[0] }
            };

            var track = animation.AddTrack(Godot.Animation.TrackType.Method);

            animation.TrackSetPath(track, GetPath());
            animation.TrackInsertKey(track, 0, args);
            animation.TrackInsertKey(track, animation.Length, args);
        }
Пример #7
0
        public static string AddAnimation(this AnimationPlayer player, Godot.Animation animation)
        {
            Ensure.That(player, nameof(player)).IsNotNull();
            Ensure.That(animation, nameof(animation)).IsNotNull();

            var name = animation.GetKey();

            Debug.Assert(name != null, "name != null");

            if (!player.HasAnimation(name))
            {
                player.AddAnimation(name, animation).ThrowOnError();
            }

            return(name);
        }
        internal void CreateAnimation(
            string animationName,
            IEnumerable <MWAnimationKeyframe> keyframes,
            IEnumerable <MWAnimationEvent> events,
            MWAnimationWrapMode wrapMode,
            MWSetAnimationStateOptions initialState,
            bool isInternal,
            bool managed,
            Action onCreatedCallback)
        {
            var continuation = new MWContinuation(AttachedActor, null, (result) =>
            {
                var animationPlayer = GetOrCreateGodotAnimationPlayer(animationName);
                var animation       = new GodotAnimation();
                animation.Loop      = wrapMode.IsInterpolationLoopWrap();

                var curves = new Dictionary <string, int>();

                int GetOrCreateCurve(Type type, string propertyName)
                {
                    if (!curves.TryGetValue(propertyName, out int trackIndex))
                    {
                        trackIndex = animation.AddTrack(GodotAnimation.TrackType.Bezier);
                        curves.Add(propertyName, trackIndex);
                    }

                    return(trackIndex);
                }

                void AddFloatPatch(Type type, string propertyName, float time, float?value)
                {
                    if (value.HasValue)
                    {
                        var trackIndex = GetOrCreateCurve(type, propertyName);
                        animation.TrackSetPath(trackIndex, propertyName);
                        animation.BezierTrackInsertKey(trackIndex, time, value.Value);
                    }
                }

                void AddVector3Patch(Type type, string propertyName, float time, Vector3Patch value)
                {
                    AddFloatPatch(type, String.Format("{0}:x", propertyName), time, value?.X);
                    AddFloatPatch(type, String.Format("{0}:y", propertyName), time, value?.Y);
                    AddFloatPatch(type, String.Format("{0}:z", propertyName), time, value?.Z);
                }

                void AddQuaternionPatch(Type type, string propertyName, float time, QuaternionPatch value)
                {
                    AddFloatPatch(type, String.Format("{0}:x", propertyName), time, value?.X);
                    AddFloatPatch(type, String.Format("{0}:y", propertyName), time, value?.Y);
                    AddFloatPatch(type, String.Format("{0}:z", propertyName), time, value?.Z);
                    AddFloatPatch(type, String.Format("{0}:w", propertyName), time, value?.W);
                }

                void AddTransformPatch(float time, ScaledTransformPatch value)
                {
                    // Work around a Unity bug/feature where all position components must be specified
                    // in the keyframe or the missing fields get set to zero.
                    Vector3Patch position = value?.Position;
                    if (position != null && position.IsPatched())
                    {
                        if (!position.X.HasValue)
                        {
                            position.X = Transform.origin.x;
                        }
                        if (!position.Y.HasValue)
                        {
                            position.Y = Transform.origin.y;
                        }
                        if (!position.Z.HasValue)
                        {
                            position.Z = Transform.origin.z;
                        }
                    }
                    // Work around a Unity bug/feature where all scale components must be specified
                    // in the keyframe or the missing fields get set to one.
                    Vector3Patch scale = value?.Scale;
                    if (scale != null && scale.IsPatched())
                    {
                        if (!scale.X.HasValue)
                        {
                            scale.X = Scale.x;
                        }
                        if (!scale.Y.HasValue)
                        {
                            scale.Y = Scale.y;
                        }
                        if (!scale.Z.HasValue)
                        {
                            scale.Z = Scale.z;
                        }
                    }
                    AddVector3Patch(typeof(Transform), "..:translation", time, value?.Position);
                    var ratation = value?.Rotation;
                    var quat     = new Quat(ratation.X.Value, ratation.Y.Value, ratation.Z.Value, ratation.W.Value);
                    var vector3  = quat.GetEuler();
                    AddVector3Patch(typeof(Transform), "..:rotation_degrees", time, new Vector3Patch(vector3));
                    AddVector3Patch(typeof(Transform), "..:scale", time, value?.Scale);
                }

                void AddActorPatch(float time, ActorPatch value)
                {
                    AddTransformPatch(time, value?.Transform.Local);
                }

                void AddKeyframe(MWAnimationKeyframe keyframe)
                {
                    AddActorPatch(keyframe.Time, keyframe.Value);
                    if (animation.Length < keyframe.Time)
                    {
                        animation.Length = keyframe.Time;
                    }
                }

                foreach (var keyframe in keyframes)
                {
                    AddKeyframe(keyframe);
                }

                _animationData[animationName] = new AnimationData()
                {
                    IsInternal = isInternal,
                    Managed    = managed
                };

                float initialTime   = 0f;
                float initialSpeed  = 1f;
                bool initialEnabled = false;

                if (initialState != null)
                {
                    initialTime    = initialState.Time ?? initialTime;
                    initialSpeed   = initialState.Speed ?? initialSpeed;
                    initialEnabled = initialState.Enabled ?? initialEnabled;
                }

                animationPlayer.AddAnimation(animationName, animation);
                animationPlayer.AssignedAnimation = animationName;

                SetAnimationState(animationName, initialTime, initialSpeed, initialEnabled);

                onCreatedCallback?.Invoke();
            });

            continuation.Start();
        }
Пример #9
0
        public MeleeToolConfiguration(
            string key,
            string slot,
            Set <string> additionalSlots,
            Set <string> tags,
            Option <IInputBindings> armInput,
            Option <IInputBindings> swingInput,
            Godot.Animation swingAnimation,
            string statesPath,
            string seekerPath,
            string idleState,
            string swingState,
            Range <float> animationRange,
            IPlayerControl playerControl,
            bool active,
            ILoggerFactory loggerFactory) : base(key, slot, additionalSlots, tags, active, loggerFactory)
        {
            Ensure.That(swingAnimation, nameof(swingAnimation)).IsNotNull();
            Ensure.That(statesPath, nameof(statesPath)).IsNotNullOrEmpty();
            Ensure.That(seekerPath, nameof(seekerPath)).IsNotNullOrEmpty();
            Ensure.That(idleState, nameof(idleState)).IsNotNullOrEmpty();
            Ensure.That(swingState, nameof(swingState)).IsNotNullOrEmpty();
            Ensure.That(playerControl, nameof(playerControl)).IsNotNull();

            SwingAnimation = swingAnimation;
            StatesPath     = statesPath;
            SeekerPath     = seekerPath;
            IdleState      = idleState;
            SwingState     = swingState;
            AnimationRange = animationRange;
            PlayerControl  = playerControl;

            OnPlayerChange = OnHolderChange
                             .CombineLatest(PlayerControl.OnCharacterChange, (h, p) => h.Filter(v => p.Contains(v)))
                             .Select(p => p.ToObservable())
                             .Switch();

            SwingInput = swingInput
                         .Bind(i => i.AsVector2Input())
                         .MatchObservable(identity, Empty <Vector2>)
                         .Where(_ => Valid)
                         .Select(v => v * 2f);

            ArmInput = armInput.Bind(i => i.FindTrigger().HeadOrNone())
                       .MatchObservable(identity, Empty <bool>)
                       .Where(_ => Valid);

            var manager = OnPlayerChange
                          .Select(p => p.AnimationManager)
                          .OfType <IAnimationStateManager>();

            var states = manager
                         .Select(m => m.FindStates(StatesPath).ToObservable())
                         .Switch();

            var seeker = manager
                         .Select(m => m.FindSeekableAnimator(SeekerPath).ToObservable())
                         .Switch();

            var blender = manager
                          .Select(m => AnimationBlend.Bind(m.FindBlender).ToObservable())
                          .Switch();

            OnArm = OnPlayerChange
                    .Select(_ => ArmInput.Where(identity))
                    .Switch()
                    .AsUnitObservable()
                    .WithLatestFrom(states, (a, s) => s.State == IdleState ? Return(a) : Empty <Unit>())
                    .Switch();

            OnDisarm = Merge(
                ArmInput.Where(v => !v).AsUnitObservable(),
                OnHolderChange.Where(v => v.IsNone).AsUnitObservable(),
                Disposed.Where(identity).AsUnitObservable())
                       .WithLatestFrom(states, (a, s) => s.State == SwingState ? Return(a) : Empty <Unit>())
                       .Switch();

            OnSwing = OnArm
                      .Select(_ => SwingInput.TakeUntil(OnDisarm).Select(v => v.y).DistinctUntilChanged())
                      .Switch()
                      .Scan(0f, (s, v) => Mathf.Clamp(s + v, 0f, 600f))
                      .Select(v => v / 600f);

            bool Conflicts(IInput input) => swingInput.Bind(i => i.Inputs.Values).Exists(input.ConflictsWith);

            ConflictingInputs = playerControl.Inputs.Filter(i => i.Active).Filter(Conflicts);
        }