115 lines
2.9 KiB
CoffeeScript
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
|