avocado-old/packages/timing/animation.coffee
2019-03-17 23:45:48 -05:00

115 lines
2.9 KiB
CoffeeScript

import Promise from 'bluebird'
import {
EventEmitter, Mixin, Property
} from '@avocado/composition'
import {Rectangle, Vector} from '@avocado/math'
import {Resource} from '@avocado/resource'
import {setterName} from '@avocado/string'
import {
TimedIndexMixin as TimedIndex
} from './timed-index'
export class Animation extends Mixin(Resource).with(
EventEmitter
Property 'direction', default: 0
Property 'directionCount', default: 1
TimedIndex 'frame'
Property 'frameSize', default: [0, 0]
Property 'imageUri', default: ''
Vector.Mixin(
'position', 'x', 'y'
x: default: 0
y: default: 0
)
Property 'sourceRectangle', default: [0, 0, 0, 0]
Property 'uri', default: ''
)
@load: @createLoad Animation
@reduce: (O) ->
O = Object.assign (new Animation()).toJSON(), O
O.directionCount = parseInt O.directionCount
O.direction = parseInt O.direction ? 0
O.frameCount = parseInt O.frameCount
O.frameRate = parseInt O.frameRate
O.frameSize = O.frameSize.map (x) -> parseInt x
O.uri or= ''
O.imageUri or= O.uri.replace '.animation.json', '.png'
return O
constructor: ->
super()
@on [
'directionChanged', 'frameSizeChanged', 'indexChanged'
], => @setSourceRectangle @rawSourceRectangle @index()
@on 'directionCountChanged', => @setDirection @direction()
clampDirection: (direction) ->
return 0 if @directionCount() is 1
direction = Math.min 7, Math.max direction, 0
direction = {
4: 1
5: 1
6: 3
7: 3
}[direction] if @directionCount() is 4 and direction > 3
direction
# Only mutates if not Vector.equals size, [0, 0]
deriveFrameSize: (size) ->
return frameSize unless Vector.isZero frameSize = @frameSize() ? [0, 0]
return [0, 0] if Vector.isZero size
return [0, 0] if @directionCount() is 0
return [0, 0] if @frameCount() is 0
# If the frame size isn't explicitly given, then calculate the
# size of one frame using the total number of frames and the total
# spritesheet size. Width is calculated by dividing the total
# spritesheet width by the number of frames, and the height is the
# height of the spritesheet divided by the number of directions
# in the animation.
return Vector.div size, [@frameCount(), @directionCount()]
rawSourceRectangle: (index) ->
return [0, 0, 0, 0] unless frameCount = @frameCount()
frameSize = @frameSize()
Rectangle.compose(
Vector.mul frameSize, [
(index ? @index()) % frameCount
@direction()
]
frameSize
)
setDirection: (direction) -> super @clampDirection parseInt direction
setDirectionCount: (directionCount) -> super parseInt directionCount
toJSON: ->
defaultImageUri = @uri().replace '.animation.json', '.png'
directionCount: @directionCount()
frameRate: @frameRate()
frameCount: @frameCount()
frameSize: @frameSize()
imageUri: @imageUri() if @imageUri() isnt defaultImageUri