public override void Start() { base.Start(); if (AnimationComponent == null) throw new InvalidOperationException("The animation component is not set"); if (AnimationIdle == null) throw new InvalidOperationException("Idle animation is not set"); if (AnimationWalk == null) throw new InvalidOperationException("Walking animation is not set"); if (AnimationRun == null) throw new InvalidOperationException("Running animation is not set"); if (AnimationPunch == null) throw new InvalidOperationException("Punching animation is not set"); // By setting a custom blend tree builder we can override the default behavior of the animation system // Instead, BuildBlendTree(FastList<AnimationOperation> blendStack) will be called each frame AnimationComponent.BlendTreeBuilder = this; animEvaluatorIdle = AnimationComponent.Blender.CreateEvaluator(AnimationIdle); animEvaluatorWalk = AnimationComponent.Blender.CreateEvaluator(AnimationWalk); animEvaluatorRun = AnimationComponent.Blender.CreateEvaluator(AnimationRun); animEvaluatorPunch = AnimationComponent.Blender.CreateEvaluator(AnimationPunch); // Initial walk lerp walkLerpFactor = 0; animEvaluatorWalkLerp1 = animEvaluatorIdle; animEvaluatorWalkLerp2 = animEvaluatorWalk; animationClipWalkLerp1 = AnimationIdle; animationClipWalkLerp2 = AnimationWalk; }
public override void Start() { base.Start(); if (AnimationComponent == null) throw new InvalidOperationException("The animation component is not set"); if (AnimationIdle == null) throw new InvalidOperationException("Idle animation is not set"); if (AnimationWalk == null) throw new InvalidOperationException("Walking animation is not set"); if (AnimationShoot == null) throw new InvalidOperationException("Shooting animation is not set"); if (AnimationReload == null) throw new InvalidOperationException("Reloading animation is not set"); // By setting a custom blend tree builder we can override the default behavior of the animation system // Instead, BuildBlendTree(FastList<AnimationOperation> blendStack) will be called each frame AnimationComponent.BlendTreeBuilder = this; animEvaluatorIdle = AnimationComponent.Blender.CreateEvaluator(AnimationIdle); animEvaluatorWalk = AnimationComponent.Blender.CreateEvaluator(AnimationWalk); animEvaluatorShoot = AnimationComponent.Blender.CreateEvaluator(AnimationShoot); animEvaluatorReload = AnimationComponent.Blender.CreateEvaluator(AnimationReload); currentEvaluator = animEvaluatorIdle; currentClip = AnimationIdle; }
private void UpdateWalking() { if (runSpeed < WalkThreshold) { walkLerpFactor = runSpeed / WalkThreshold; walkLerpFactor = (float)Math.Sqrt(walkLerpFactor); // Idle-Walk blend looks really werid, so skew the factor towards walking animEvaluatorWalkLerp1 = animEvaluatorIdle; animEvaluatorWalkLerp2 = animEvaluatorWalk; animationClipWalkLerp1 = AnimationIdle; animationClipWalkLerp2 = AnimationWalk; } else { walkLerpFactor = (runSpeed - WalkThreshold) / (1.0f - WalkThreshold); animEvaluatorWalkLerp1 = animEvaluatorWalk; animEvaluatorWalkLerp2 = animEvaluatorRun; animationClipWalkLerp1 = AnimationWalk; animationClipWalkLerp2 = AnimationRun; } // Use DrawTime rather than UpdateTime var time = Game.DrawTime; // This update function will account for animation with different durations, keeping a current time relative to the blended maximum duration long blendedMaxDuration = 0; blendedMaxDuration = (long)MathUtil.Lerp(animationClipWalkLerp1.Duration.Ticks, animationClipWalkLerp2.Duration.Ticks, walkLerpFactor); var currentTicks = TimeSpan.FromTicks((long)(currentTime * blendedMaxDuration)); currentTicks = blendedMaxDuration == 0 ? TimeSpan.Zero : TimeSpan.FromTicks((currentTicks.Ticks + (long)(time.Elapsed.Ticks * TimeFactor)) % blendedMaxDuration); currentTime = ((double)currentTicks.Ticks / (double)blendedMaxDuration); }
/// <summary> /// Creates a new animation pop operation. /// </summary> /// <param name="evaluator">The evaluator.</param> /// <param name="time">The time.</param> /// <returns></returns> public static AnimationOperation NewPop(AnimationClipEvaluator evaluator, TimeSpan time) { return new AnimationOperation { Type = AnimationOperationType.Pop, Evaluator = evaluator, Time = time }; }
/// <summary> /// Creates a new animation push operation. /// </summary> /// <param name="evaluator">The evaluator.</param> /// <returns></returns> public static AnimationOperation NewPush(AnimationClipEvaluator evaluator) { return new AnimationOperation { Type = AnimationOperationType.Push, Evaluator = evaluator, Time = TimeSpan.Zero }; }
public AnimationClipEvaluator CreateEvaluator(AnimationClip clip) { // Check if this clip has already been used if (clips.Add(clip)) { // If new clip, let's scan its channel to add new ones. foreach (var curve in clip.Channels) { Channel channel; if (channelsByName.TryGetValue(curve.Key, out channel)) { // TODO: Check if channel matches } else { // New channel, add it to every evaluator // Find blend type BlendType blendType; var elementType = curve.Value.ElementType; if (elementType == typeof(Quaternion)) { blendType = BlendType.Quaternion; } else if (elementType == typeof(float)) { blendType = BlendType.Float1; } else if (elementType == typeof(Vector2)) { blendType = BlendType.Float2; } else if (elementType == typeof(Vector3)) { blendType = BlendType.Float3; } else if (elementType == typeof(Vector4)) { blendType = BlendType.Float4; } else { blendType = BlittableHelper.IsBlittable(elementType) ? BlendType.Blit : BlendType.Object; } // Create channel structure channel.BlendType = blendType; channel.Offset = blendType == BlendType.Object ? objectsSize : structureSize; channel.PropertyName = curve.Key; channel.Size = curve.Value.ElementSize; // Add channel channelsByName.Add(channel.PropertyName, channel); channels.Add(channel); if (blendType == BlendType.Object) { objectsSize++; } else { // Update new structure size // We also reserve space for a float that will specify channel existence and factor in case of subtree blending structureSize += sizeof(float) + channel.Size; } // Add new channel update info to every evaluator // TODO: Maybe it's better lazily done? (avoid need to store list of all evaluators) foreach (var currentEvaluator in evaluators) { currentEvaluator.AddChannel(ref channel); } } } } // Update results to fit the new data size lock (availableResultsPool) { foreach (var result in availableResultsPool) { if (result.DataSize < structureSize) { result.DataSize = structureSize; result.Data = new byte[structureSize]; } } } // Create evaluator and store it in list of instantiated evaluators AnimationClipEvaluator evaluator; lock (evaluatorPool) { if (evaluatorPool.Count > 0) { evaluator = evaluatorPool.Pop(); } else { evaluator = new AnimationClipEvaluator(); } } evaluator.Initialize(clip, channels); evaluators.Add(evaluator); return(evaluator); }
public AnimationClipEvaluator CreateEvaluator(AnimationClip clip) { // Check if this clip has already been used if (clips.Add(clip)) { // If new clip, let's scan its channel to add new ones. foreach (var curve in clip.Channels) { Channel channel; if (channelsByName.TryGetValue(curve.Key, out channel)) { // TODO: Check if channel matches } else { // New channel, add it to every evaluator // Find blend type BlendType blendType; var elementType = curve.Value.ElementType; if (elementType == typeof(Quaternion)) { blendType = BlendType.Quaternion; } else if (elementType == typeof(float)) { blendType = BlendType.Float1; } else if (elementType == typeof(Vector2)) { blendType = BlendType.Float2; } else if (elementType == typeof(Vector3)) { blendType = BlendType.Float3; } else if (elementType == typeof(Vector4)) { blendType = BlendType.Float4; } else { blendType = BlittableHelper.IsBlittable(elementType) ? BlendType.Blit : BlendType.Object; } // Create channel structure channel.BlendType = blendType; channel.Offset = blendType == BlendType.Object ? objectsSize : structureSize; channel.PropertyName = curve.Key; channel.Size = curve.Value.ElementSize; // Add channel channelsByName.Add(channel.PropertyName, channel); channels.Add(channel); if (blendType == BlendType.Object) { objectsSize++; } else { // Update new structure size // We also reserve space for a float that will specify channel existence and factor in case of subtree blending structureSize += sizeof(float) + channel.Size; } // Add new channel update info to every evaluator // TODO: Maybe it's better lazily done? (avoid need to store list of all evaluators) foreach (var currentEvaluator in evaluators) { currentEvaluator.AddChannel(ref channel); } } } } // Update results to fit the new data size lock (availableResultsPool) { foreach (var result in availableResultsPool) { if (result.DataSize < structureSize) { result.DataSize = structureSize; result.Data = new byte[structureSize]; } } } // Create evaluator and store it in list of instantiated evaluators AnimationClipEvaluator evaluator; lock (evaluatorPool) { if (evaluatorPool.Count > 0) { evaluator = evaluatorPool.Pop(); } else { evaluator = new AnimationClipEvaluator(); } } evaluator.Initialize(clip, channels); evaluators.Add(evaluator); return evaluator; }
public void ReleaseEvaluator(AnimationClipEvaluator evaluator) { lock (evaluatorPool) { evaluators.Remove(evaluator); evaluator.Cleanup(); evaluatorPool.Push(evaluator); } }
/// <summary> /// Creates a new animation pop operation. /// </summary> /// <param name="evaluator">The evaluator.</param> /// <param name="time">The time.</param> /// <returns></returns> public static AnimationOperation NewPop(AnimationClipEvaluator evaluator, TimeSpan time) { return(new AnimationOperation { Type = AnimationOperationType.Pop, Evaluator = evaluator, Time = time }); }
/// <summary> /// Creates a new animation push operation. /// </summary> /// <param name="evaluator">The evaluator.</param> /// <returns></returns> public static AnimationOperation NewPush(AnimationClipEvaluator evaluator) { return(new AnimationOperation { Type = AnimationOperationType.Push, Evaluator = evaluator, Time = TimeSpan.Zero }); }
private void SwitchToDefaultState() { currentTime = (state == defaultState) ? currentTime : 0; state = defaultState; if (state == AnimationState.Idle) { currentClip = AnimationIdle; currentEvaluator = animEvaluatorIdle; } else { currentClip = AnimationWalk; currentEvaluator = animEvaluatorWalk; } }
public override void Update() { runSpeedEvent.TryReceive(out runSpeed); defaultState = (runSpeed > 0.15f) ? AnimationState.Walking : AnimationState.Idle; WeaponFiredResult weaponResult; var didFire = weaponFiredEvent.TryReceive(out weaponResult); bool isReloading; var didReload = isReloadingEvent.TryReceive(out isReloading); isReloading |= didReload; // Update current animation var currentTicks = TimeSpan.FromTicks((long)(currentTime * currentClip.Duration.Ticks)); var updatedTicks = currentTicks.Ticks + (long)(Game.DrawTime.Elapsed.Ticks * TimeFactor); var currentClipFinished = (updatedTicks >= currentClip.Duration.Ticks); currentTicks = TimeSpan.FromTicks(updatedTicks % currentClip.Duration.Ticks); currentTime = ((double)currentTicks.Ticks / (double)currentClip.Duration.Ticks); // State change if necessary if (isReloading) { if (state != AnimationState.Reloading) { currentTime = 0; state = AnimationState.Reloading; currentClip = AnimationReload; currentEvaluator = animEvaluatorReload; } } else if (didFire) { if (state != AnimationState.Shooting) { currentTime = 0; state = AnimationState.Shooting; currentClip = AnimationShoot; currentEvaluator = animEvaluatorShoot; } } else if (currentClipFinished) { SwitchToDefaultState(); } else if ((state == AnimationState.Idle || state == AnimationState.Walking) && state != defaultState) { SwitchToDefaultState(); } }