diff --git a/About/Animation.md b/About/Animation.md index e4ae1a8..763dd87 100644 --- a/About/Animation.md +++ b/About/Animation.md @@ -3,13 +3,18 @@ Provides components / systems / authorings / data structures to simulate sprite It just shifts UVs over time which looks like different sprite rendered. While it just UV shifting animation sprite sequence should be a solid texture sheet. +## How it works +All animation data lives in provided `ScriptableObject`s (mentioned below). +In baking phase it bakes all immutable animation data into blob (see `SpriteAnimationAuthoring`). +Then in runtime it changes `UVAtlas` component value over time to perform flipbook animation. + ## [`SpriteAnimationAuthoring`](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Animation/Authoring/SpriteAnimationAuthoring.cs) Inherited from [`SpriteRenderAuthoring`](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Base/Authoring/SpriteRendererAuthoring.cs) it also bakes all needed animation data provided as [`SpriteAnimationSet`](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Animation/Data/SpriteAnimationSet.cs). If you want to implement your own authoring you can still use static methods provided by this class to perform same baking. ## Prepare assets -To work with animation part you will also need to create [`SpriteAnimationSet`](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Animation/Data/SpriteAnimationSet.cs) and bunch of [`SpriteAnimation`](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Animation/Data/SpriteAnimation.cs). -You can create them like most of `ScriptableObjects` by calling context menu in project and selecting `Create/NSprites/Animation Set` or `Create/Nsprites/Animation (sprite sequence)`. +To work with animation part you need to create [`SpriteAnimationSet`](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Animation/Data/SpriteAnimationSet.cs) and bunch of [`SpriteAnimation`](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Animation/Data/SpriteAnimation.cs). +You can create them like most of `ScriptableObjects` by calling context menu in project and selecting `Create/NSprites/Animation Set` / `Create/Nsprites/Animation (sprite sequence)`. ### `SpriteAnimation` A `ScriptableObject` containing sprite sequence (as solid sprite sheet) where each sprite has duration of how long it stays before switch to next frame. This class also requires additional data like frame count resolution. @@ -18,6 +23,29 @@ A `ScriptableObject` containing set of `SpriteAnimation`s with string names (whi ### `SpriteAnimationBlobData` A `struct` blob to contain runtime immutable animation data. Contains `int` ID which corresponds to animation name with help of `Animator.StringToHash`, atlas UVs of sprite sheet, it's frame resolution, `BlobArray` of frame durations and sum of all frames duration. +## Change animation during runtime +### Using `AnimatorAspect` +You can use this [aspect](https://docs.unity3d.com/Packages/com.unity.entities@1.0/manual/aspects-intro.html) to change animation by it's ID in a simple way. +```csharp +// this example is from Age-of-Sprites project https://github.com/Antoshidza/Age-of-Sprites/blob/main/Assets/Sources/Rome/Systems/MovableAnimationControlSystem.cs +[BurstCompile] +private partial struct ChangeAnimationJob : IJobEntity +{ + public int SetToAnimationID; + public double Time; + + private void Execute(ref AnimatorAspect animator) + { + animator.SetAnimation(SetToAnimationID, Time); + } +} +``` + +### Manually +Basically to change animation we should set `AnimationIndex` to another index and reset `AnimationTimer` and `FrameIndex` and also calculate proper `UVAtlas` of 1st frame of animation you choosed. Though the short way is to just change `AnimationIndex`, set `FrameIndex` to last frame index in choosed animation and set `AnimationTimer` to current `Time.ElapsedTime` which will trigger `SpriteUVAnimationSystem` to calculate next frame which should be the 1st frame of choosed animation. + +You can inspect example of doing this by looking at `AnimatorAspect` source code. + ## Components |Type|Description| |----|-----------| @@ -26,5 +54,3 @@ A `struct` blob to contain runtime immutable animation data. Contains `int` ID w |`FrameIndex`|Currently displayed frame from sprite sheet texture| |`AnimationTimer`|Timer which has value of global time + frame duration. When timer excided (timer value equals current global time) frame index increases| -## How to change animations during runtime -Basically to change animation we should set `AnimationIndex` to another index and reset `AnimationTimer` and `FrameIndex` and also calculate proper `UVAtlas` of 1st frame of animation you choosed. Though the short way is to just change `AnimationIndex`, set `FrameIndex` to last frame index in choosed animation and set `AnimationTimer` to current `Time.ElapsedTime` which will trigger `SpriteUVAnimationSystem` to calculate next frame which should be the 1st frame of choosed animation. diff --git a/Animation/Aspects.meta b/Animation/Aspects.meta new file mode 100644 index 0000000..c3aea3b --- /dev/null +++ b/Animation/Aspects.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b505099e1ecc4a4588adca657de66429 +timeCreated: 1680455781 \ No newline at end of file diff --git a/Animation/Aspects/AnimatorAspect.cs b/Animation/Aspects/AnimatorAspect.cs new file mode 100644 index 0000000..f51a0da --- /dev/null +++ b/Animation/Aspects/AnimatorAspect.cs @@ -0,0 +1,51 @@ +using Unity.Entities; + +namespace NSprites +{ + public readonly partial struct AnimatorAspect : IAspect + { +#if UNITY_EDITOR || DEVELOPMENT_BUILD + private readonly Entity _entity; +#endif + private readonly RefRW _animationIndex; + private readonly RefRW _animationTimer; + private readonly RefRW _frameIndex; + private readonly RefRO _animationSetLink; + + public void SetAnimation(int toAnimationIndex, in double worldTime) + { + // find animation by animation ID + ref var animSet = ref _animationSetLink.ValueRO.value.Value; + var setToAnimIndex = -1; + for (int i = 0; i < animSet.Length; i++) + if (animSet[i].ID == toAnimationIndex) + { + setToAnimIndex = i; + break; + } + + if (setToAnimIndex == -1) + throw new NSpritesException($"{nameof(AnimatorAspect)}.{nameof(SetAnimation)}: incorrect {nameof(toAnimationIndex)} was passed. {_entity} has no animation with such ID ({toAnimationIndex}) was found"); + + if (_animationIndex.ValueRO.value != setToAnimIndex) + { + ref var animData = ref animSet[setToAnimIndex]; + _animationIndex.ValueRW.value = setToAnimIndex; + // here we want to set last frame and timer to 0 (equal to current time) to force animation system instantly switch + // animation to 1st frame after we've modified it + _frameIndex.ValueRW.value = animData.FrameDurations.Length - 1; + _animationTimer.ValueRW.value = worldTime; + } + } + + public void SetToFrame(int frameIndex, in double worldTime) + { + ref var animData = ref _animationSetLink.ValueRO.value.Value[_animationIndex.ValueRO.value]; + _frameIndex.ValueRW.value = frameIndex; + _animationTimer.ValueRW.value = worldTime + animData.FrameDurations[frameIndex]; + } + + public void ResetAnimation(in double worldTime) => + SetToFrame(0, worldTime); + } +} \ No newline at end of file diff --git a/Animation/Aspects/AnimatorAspect.cs.meta b/Animation/Aspects/AnimatorAspect.cs.meta new file mode 100644 index 0000000..b64d949 --- /dev/null +++ b/Animation/Aspects/AnimatorAspect.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8d56345ad69a4e5b870e366d062f34e7 +timeCreated: 1680455793 \ No newline at end of file diff --git a/Animation/Components/FrameGrid.cs b/Animation/Components/FrameGrid.cs deleted file mode 100644 index a951e71..0000000 --- a/Animation/Components/FrameGrid.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Unity.Entities; -using Unity.Mathematics; - -public struct FrameGrid : IComponentData -{ - public int2 size; -} diff --git a/Animation/Components/FrameGrid.cs.meta b/Animation/Components/FrameGrid.cs.meta deleted file mode 100644 index 23b936e..0000000 --- a/Animation/Components/FrameGrid.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: cbcfff1b345bb6e4fb038d0afa240cac -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Animation/Systems/SpriteUVAnimationSystem.cs b/Animation/Systems/SpriteUVAnimationSystem.cs index 356e1a0..8affa92 100644 --- a/Animation/Systems/SpriteUVAnimationSystem.cs +++ b/Animation/Systems/SpriteUVAnimationSystem.cs @@ -15,7 +15,7 @@ public partial struct SpriteUVAnimationSystem : ISystem [WithNone(typeof(CullSpriteTag))] private partial struct AnimationJob : IJobEntity { - public double time; + public double Time; private void Execute(ref AnimationTimer animationTimer, ref FrameIndex frameIndex, @@ -23,7 +23,7 @@ private void Execute(ref AnimationTimer animationTimer, in AnimationSetLink animationSet, in AnimationIndex animationIndex) { - var timerDelta = time - animationTimer.value; + var timerDelta = Time - animationTimer.value; if (timerDelta >= 0f) { @@ -44,7 +44,7 @@ private void Execute(ref AnimationTimer animationTimer, nextFrameDuration -= extraTime; } - animationTimer.value = time + nextFrameDuration; + animationTimer.value = Time + nextFrameDuration; var frameSize = new float2(animData.UVAtlas.xy / animData.GridSize); var framePosition = new int2(frameIndex.value % animData.GridSize.x, frameIndex.value / animData.GridSize.x); @@ -56,7 +56,7 @@ private void Execute(ref AnimationTimer animationTimer, [BurstCompile] public void OnUpdate(ref SystemState state) { - var animationJob = new AnimationJob { time = SystemAPI.Time.ElapsedTime }; + var animationJob = new AnimationJob { Time = SystemAPI.Time.ElapsedTime }; state.Dependency = animationJob.ScheduleParallelByRef(state.Dependency); } } diff --git a/package.json b/package.json index 4c3ce70..6e16e4c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.tonymax.nsprites.foundation", - "version": "3.0.0", + "version": "3.1.0", "displayName": "NSprites Foundation", "description": "Contains solutions based on NSprites package such as authoring sprite data, animation, sorting, culling systems.", "unity": "2022.2",