feat: Animation improvements fromSpriteSheetCoordinates + EventEmitter (#2666)
This PR adds a few improvements to animations that have been discussed offline
* Adds new `EventEmitter` type which is a better typed event implementation
* Updates the `.events` type to be the new `EventEmitter`
* Adds the `frameIndex` of the current frame to the animation event
* Adds a new static builder for constructing animations from SpriteSheets
```typescript
const spriteSheet = SpriteSheet.fromImageSource({...});
const anim = Animation.fromSpriteSheetCoordinates({
spriteSheet,
frameCoordinates: [
{x: 0, y: 5, duration: 100},
{x: 1, y: 5, duration: 200},
{x: 2, y: 5, duration: 100},
{x: 3, y: 5, duration: 500}
],
strategy: AnimationStrategy.PingPong
});
```
feat: Add missing Sound features `.seek()`, `.duration`, & `getTotalPlaybackDuration()` (#2340)
This PR adds the ability to `ex.Sound.seek()` to a specific position in the sound, it also adds the `ex.Sound.getTotalPlaybackDuration()` so you may know how long in seconds the sound file is. Lastly `ex.Sound.duration` if set will limit the duration of the clip from where played();
In order to accomplish this, `ex.Sound()` was refactored using a small `ex.StateMachine` implementation
Example
```typescript
const machine = ex.StateMachine.create({
start: 'STOPPED',
states: {
PLAYING: {
onEnter: () => {
console.log("playing");
},
transitions: ['STOPPED', 'PAUSED']
},
STOPPED: {
onEnter: () => {
console.log("stopped");
},
transitions: ['PLAYING']
},
PAUSED: {
onEnter: () => {
console.log("paused")
},
transitions: ['PLAYING', 'STOPPED']
}
}
});
```
## Changes:
- Adds `ex.Sound.seek()`
- Adds `ex.Sound.duration`
- Adds `ex.Sound.getTotalPlaybackDuration()`
- Adds new `ex.StateMachine()`