mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 15:48:11 -05:00
Refactored WebGLSprite to SegmentedSprite and SingularSprite, and refactored renderStrategy (container/spriteSheet) to spriteType (segmented/singular).
This commit is contained in:
parent
3c9b40e8f4
commit
fbbfb6c0cc
9 changed files with 352 additions and 313 deletions
|
@ -302,7 +302,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
|
||||
updateBaseScale: ->
|
||||
scale = 1
|
||||
useRawScale = @isRaster or @thangType.get('renderStrategy') is 'container'
|
||||
useRawScale = @isRaster or @thangType.get('spriteType') is 'container'
|
||||
scale = @thangType.get('scale') or 1 if useRawScale
|
||||
scale /= @options.resolutionFactor unless useRawScale
|
||||
@baseScaleX = @baseScaleY = scale
|
||||
|
|
|
@ -1,32 +1,20 @@
|
|||
SpriteBuilder = require 'lib/sprites/SpriteBuilder'
|
||||
|
||||
module.exports = class WebGLSprite extends createjs.SpriteContainer
|
||||
module.exports = class SegmentedSprite extends createjs.SpriteContainer
|
||||
childMovieClips: null
|
||||
|
||||
|
||||
constructor: (@spriteSheet, @thangType, @spriteSheetPrefix, @resolutionFactor=SPRITE_RESOLUTION_FACTOR) ->
|
||||
@initialize(@spriteSheet)
|
||||
if @thangType.get('renderStrategy') isnt 'container'
|
||||
@singleChildSprite = new createjs.Sprite(@spriteSheet)
|
||||
@addChild(@singleChildSprite)
|
||||
@addEventListener 'tick', @handleTick
|
||||
|
||||
handleTick: (e) =>
|
||||
if @lastTimeStamp
|
||||
@tick(e.timeStamp - @lastTimeStamp)
|
||||
@lastTimeStamp = e.timeStamp
|
||||
|
||||
|
||||
destroy: ->
|
||||
@handleTick = undefined
|
||||
@removeAllEventListeners()
|
||||
|
||||
play: ->
|
||||
@singleChildSprite?.play()
|
||||
@paused = false
|
||||
|
||||
stop: ->
|
||||
@singleChildSprite?.stop()
|
||||
@paused = true
|
||||
|
||||
# CreateJS.Sprite-like interface
|
||||
|
||||
play: -> @paused = false
|
||||
stop: -> @paused = true
|
||||
gotoAndPlay: (actionName) -> @goto(actionName, false)
|
||||
gotoAndStop: (actionName) -> @goto(actionName, true)
|
||||
|
||||
|
@ -34,93 +22,51 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer
|
|||
@currentAnimation = actionName
|
||||
@baseMovieClip = @framerate = null
|
||||
@actionNotSupported = false
|
||||
|
||||
|
||||
action = @thangType.getActions()[actionName]
|
||||
randomStart = actionName.startsWith('move')
|
||||
reg = action.positions?.registration or @thangType.get('positions')?.registration or {x:0, y:0}
|
||||
|
||||
if action.animation
|
||||
@framerate = (action.framerate ? 20) * (action.speed ? 1)
|
||||
|
||||
if @singleChildSprite
|
||||
scale = @resolutionFactor * (action.scale ? @thangType.get('scale') ? 1)
|
||||
@regX = -reg.x * scale
|
||||
@regY = -reg.y * scale
|
||||
func = if @paused then 'gotoAndStop' else 'gotoAndPlay'
|
||||
animationName = @spriteSheetPrefix + actionName
|
||||
@singleChildSprite[func](animationName)
|
||||
if @singleChildSprite.currentFrame is 0
|
||||
@regX = -reg.x
|
||||
@regY = -reg.y
|
||||
@singleChildSprite.stop()
|
||||
@notifyActionNeedsRender(action)
|
||||
bounds = @thangType.get('raw').animations[action.animation].bounds
|
||||
@singleChildSprite.x = bounds[0]
|
||||
@singleChildSprite.y = bounds[1]
|
||||
console.log 'bounds?', bounds
|
||||
@singleChildSprite.scaleX = bounds[2] / (SPRITE_PLACEHOLDER_RADIUS * @resolutionFactor * 2)
|
||||
@singleChildSprite.scaleY = bounds[3] / (SPRITE_PLACEHOLDER_RADIUS * @resolutionFactor * 2)
|
||||
return
|
||||
|
||||
@singleChildSprite.framerate = action.framerate or 20
|
||||
if randomStart and frames = @spriteSheet.getAnimation(animationName)?.frames
|
||||
@singleChildSprite.currentAnimationFrame = Math.floor(Math.random() * frames.length)
|
||||
@regX = -reg.x
|
||||
@regY = -reg.y
|
||||
@childMovieClips = []
|
||||
@baseMovieClip = @buildMovieClip(action.animation)
|
||||
@children = @baseMovieClip.children
|
||||
@frames = action.frames
|
||||
@frames = (parseInt(f) for f in @frames.split(',')) if @frames
|
||||
@animLength = if @frames then @frames.length else @baseMovieClip.frameBounds.length
|
||||
@currentFrame = if randomStart then Math.floor(Math.random() * @animLength) else 0
|
||||
@baseMovieClip.gotoAndStop(@currentFrame)
|
||||
@loop = action.loops isnt false
|
||||
@goesTo = action.goesTo
|
||||
@notifyActionNeedsRender(action) if @actionNotSupported
|
||||
|
||||
else
|
||||
@regX = -reg.x
|
||||
@regY = -reg.y
|
||||
@childMovieClips = []
|
||||
@baseMovieClip = @buildMovieClip(action.animation)
|
||||
@children = @baseMovieClip.children
|
||||
@frames = action.frames
|
||||
@frames = (parseInt(f) for f in @frames.split(',')) if @frames
|
||||
@animLength = if @frames then @frames.length else @baseMovieClip.frameBounds.length
|
||||
@currentFrame = if randomStart then Math.floor(Math.random() * @animLength) else 0
|
||||
@baseMovieClip.gotoAndStop(@currentFrame)
|
||||
@loop = action.loops isnt false
|
||||
@goesTo = action.goesTo
|
||||
@notifyActionNeedsRender(action) if @actionNotSupported
|
||||
|
||||
if action.container
|
||||
else if action.container
|
||||
scale = @resolutionFactor * (action.scale ? @thangType.get('scale') ? 1)
|
||||
|
||||
if @singleChildSprite
|
||||
@regX = -reg.x * scale
|
||||
@regY = -reg.y * scale
|
||||
animationName = @spriteSheetPrefix + actionName
|
||||
@singleChildSprite.gotoAndStop(animationName)
|
||||
if @singleChildSprite.currentFrame is 0
|
||||
@notifyActionNeedsRender(action)
|
||||
bounds = @thangType.get('raw').containers[action.container].b
|
||||
@singleChildSprite.x = bounds[0]
|
||||
@singleChildSprite.y = bounds[1]
|
||||
@singleChildSprite.scaleX = bounds[2] / (SPRITE_PLACEHOLDER_RADIUS * 2)
|
||||
@singleChildSprite.scaleY = bounds[3] / (SPRITE_PLACEHOLDER_RADIUS * 2)
|
||||
return
|
||||
|
||||
@regX = -reg.x
|
||||
@regY = -reg.y
|
||||
@childMovieClips = []
|
||||
containerName = @spriteSheetPrefix + action.container
|
||||
sprite = new createjs.Sprite(@spriteSheet)
|
||||
sprite.gotoAndStop(containerName)
|
||||
if sprite.currentFrame is 0
|
||||
@notifyActionNeedsRender(action)
|
||||
bounds = @thangType.get('raw').containers[action.container].b
|
||||
sprite.x = bounds[0]
|
||||
sprite.y = bounds[1]
|
||||
sprite.scaleX = bounds[2] / (SPRITE_PLACEHOLDER_RADIUS * 2 * scale)
|
||||
sprite.scaleY = bounds[3] / (SPRITE_PLACEHOLDER_RADIUS * 2 * scale)
|
||||
else
|
||||
@regX = -reg.x
|
||||
@regY = -reg.y
|
||||
@childMovieClips = []
|
||||
containerName = @spriteSheetPrefix + action.container
|
||||
sprite = new createjs.Sprite(@spriteSheet)
|
||||
sprite.gotoAndStop(containerName)
|
||||
if sprite.currentFrame is 0
|
||||
@notifyActionNeedsRender(action)
|
||||
bounds = @thangType.get('raw').containers[action.container].b
|
||||
sprite.x = bounds[0]
|
||||
sprite.y = bounds[1]
|
||||
sprite.scaleX = bounds[2] / (SPRITE_PLACEHOLDER_RADIUS * 2 * scale)
|
||||
sprite.scaleY = bounds[3] / (SPRITE_PLACEHOLDER_RADIUS * 2 * scale)
|
||||
else
|
||||
sprite.scaleX = sprite.scaleY = 1 / scale
|
||||
@children = [sprite]
|
||||
|
||||
sprite.scaleX = sprite.scaleY = 1 / scale
|
||||
@children = [sprite]
|
||||
|
||||
return
|
||||
|
||||
|
||||
notifyActionNeedsRender: (action) ->
|
||||
@sprite.trigger('action-needs-render', @sprite, action)
|
||||
|
||||
@sprite?.trigger('action-needs-render', @sprite, action)
|
||||
|
||||
buildMovieClip: (animationName, mode, startPosition, loops) ->
|
||||
raw = @thangType.get('raw')
|
||||
animData = raw.animations[animationName]
|
||||
|
@ -129,7 +75,7 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer
|
|||
locals = {}
|
||||
_.extend locals, @buildMovieClipContainers(animData.containers)
|
||||
_.extend locals, @buildMovieClipAnimations(animData.animations)
|
||||
|
||||
|
||||
toSkip = {}
|
||||
toSkip[shape.bn] = true for shape in animData.shapes
|
||||
toSkip[graphic.bn] = true for graphic in animData.graphics
|
||||
|
@ -201,10 +147,15 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer
|
|||
return false
|
||||
return args
|
||||
|
||||
handleTick: (e) =>
|
||||
if @lastTimeStamp
|
||||
@tick(e.timeStamp - @lastTimeStamp)
|
||||
@lastTimeStamp = e.timeStamp
|
||||
|
||||
tick: (delta) ->
|
||||
return unless @baseMovieClip and @framerate and not @paused
|
||||
return if @paused
|
||||
newFrame = @currentFrame + @framerate * delta / 1000
|
||||
|
||||
|
||||
if newFrame > @animLength
|
||||
if @goesTo
|
||||
@gotoAndPlay(@goesTo)
|
||||
|
@ -215,7 +166,7 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer
|
|||
@dispatchEvent('animationend')
|
||||
else
|
||||
newFrame = newFrame % @animLength
|
||||
|
||||
|
||||
if @frames
|
||||
prevFrame = Math.floor(newFrame)
|
||||
nextFrame = Math.ceil(newFrame)
|
||||
|
@ -230,17 +181,17 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer
|
|||
@baseMovieClip.gotoAndStop(newFrameIndex)
|
||||
else
|
||||
@baseMovieClip.gotoAndStop(newFrame)
|
||||
|
||||
|
||||
@currentFrame = newFrame
|
||||
|
||||
# So, originally I thought I'd have to swap in MovieClips for parallel
|
||||
# SpriteContainers between each frame, but turns out that's not the case.
|
||||
# The WebGL rendering system treats the MovieClip like a SpriteContainer,
|
||||
# which makes things simpler for me...
|
||||
|
||||
|
||||
# For some reason, though, gotoAndStop doesn't seem to advance the children
|
||||
# so I gotta do that manually.
|
||||
movieClip.gotoAndStop(newFrame) for movieClip in @childMovieClips
|
||||
|
||||
|
||||
getBounds: ->
|
||||
@baseMovieClip.getBounds()
|
69
app/lib/surface/SingularSprite.coffee
Normal file
69
app/lib/surface/SingularSprite.coffee
Normal file
|
@ -0,0 +1,69 @@
|
|||
SpriteBuilder = require 'lib/sprites/SpriteBuilder'
|
||||
|
||||
module.exports = class WebGLSprite extends createjs.Sprite
|
||||
childMovieClips: null
|
||||
|
||||
constructor: (@spriteSheet, @thangType, @spriteSheetPrefix, @resolutionFactor=SPRITE_RESOLUTION_FACTOR) ->
|
||||
@initialize(@spriteSheet)
|
||||
|
||||
destroy: ->
|
||||
@removeAllEventListeners()
|
||||
|
||||
gotoAndPlay: (actionName) -> @goto(actionName, false)
|
||||
gotoAndStop: (actionName) -> @goto(actionName, true)
|
||||
_gotoAndPlay: createjs.Sprite.prototype.gotoAndPlay
|
||||
_gotoAndStop: createjs.Sprite.prototype.gotoAndStop
|
||||
|
||||
goto: (actionName, @paused=true) ->
|
||||
@actionNotSupported = false
|
||||
|
||||
action = @thangType.getActions()[actionName]
|
||||
randomStart = actionName.startsWith('move')
|
||||
reg = action.positions?.registration or @thangType.get('positions')?.registration or {x:0, y:0}
|
||||
|
||||
if action.animation
|
||||
@framerate = (action.framerate ? 20) * (action.speed ? 1)
|
||||
|
||||
scale = @resolutionFactor * (action.scale ? @thangType.get('scale') ? 1)
|
||||
@regX = -reg.x * scale
|
||||
@regY = -reg.y * scale
|
||||
func = if @paused then '_gotoAndStop' else '_gotoAndPlay'
|
||||
animationName = @spriteSheetPrefix + actionName
|
||||
@[func](animationName)
|
||||
if @currentFrame is 0
|
||||
@stop()
|
||||
@regX = -reg.x
|
||||
@regY = -reg.y
|
||||
@notifyActionNeedsRender(action)
|
||||
bounds = @thangType.get('raw').animations[action.animation].bounds
|
||||
@x = bounds[0]
|
||||
@y = bounds[1]
|
||||
@scaleX = bounds[2] / (SPRITE_PLACEHOLDER_RADIUS * @resolutionFactor * 2)
|
||||
@scaleY = bounds[3] / (SPRITE_PLACEHOLDER_RADIUS * @resolutionFactor * 2)
|
||||
return
|
||||
|
||||
@framerate = action.framerate or 20
|
||||
if randomStart and frames = @spriteSheet.getAnimation(animationName)?.frames
|
||||
@currentAnimationFrame = Math.floor(Math.random() * frames.length)
|
||||
|
||||
if action.container
|
||||
scale = @resolutionFactor * (action.scale ? @thangType.get('scale') ? 1)
|
||||
|
||||
@regX = -reg.x * scale
|
||||
@regY = -reg.y * scale
|
||||
animationName = @spriteSheetPrefix + actionName
|
||||
@_gotoAndStop(animationName)
|
||||
if @currentFrame is 0
|
||||
@notifyActionNeedsRender(action)
|
||||
bounds = @thangType.get('raw').containers[action.container].b
|
||||
@x = bounds[0]
|
||||
@y = bounds[1]
|
||||
@scaleX = bounds[2] / (SPRITE_PLACEHOLDER_RADIUS * 2)
|
||||
@scaleY = bounds[3] / (SPRITE_PLACEHOLDER_RADIUS * 2)
|
||||
return
|
||||
|
||||
@currentAnimation = actionName
|
||||
return
|
||||
|
||||
notifyActionNeedsRender: (action) ->
|
||||
@sprite.trigger('action-needs-render', @sprite, action)
|
|
@ -1,9 +1,10 @@
|
|||
SpriteBuilder = require 'lib/sprites/SpriteBuilder'
|
||||
CocoClass = require 'lib/CocoClass'
|
||||
WebGLSprite = require './WebGLSprite'
|
||||
SegmentedSprite = require './SegmentedSprite'
|
||||
SingularSprite = require './SingularSprite'
|
||||
{SpriteContainerLayer} = require 'lib/surface/Layer'
|
||||
|
||||
NEVER_RENDER_ANYTHING = true # set to true to test placeholders
|
||||
NEVER_RENDER_ANYTHING = false # set to true to test placeholders
|
||||
|
||||
module.exports = class WebGLLayer extends CocoClass
|
||||
|
||||
|
@ -124,7 +125,7 @@ module.exports = class WebGLLayer extends CocoClass
|
|||
actionNames = (bundle.actionName for bundle in bundleGrouping)
|
||||
args = [thangType, colorConfig, actionNames, builder]
|
||||
if thangType.get('raw')
|
||||
if thangType.get('renderStrategy') is 'container'
|
||||
if thangType.get('spriteType') is 'segmented'
|
||||
@renderContainers(args...)
|
||||
else
|
||||
@renderSpriteSheet(args...)
|
||||
|
@ -305,8 +306,9 @@ module.exports = class WebGLLayer extends CocoClass
|
|||
sprite.gotoAndStop(@renderGroupingKey(cocoSprite.thangType))
|
||||
|
||||
else
|
||||
SpriteClass = if cocoSprite.thangType.get('spriteType') is 'segmented' then SegmentedSprite else SingularSprite
|
||||
prefix = @renderGroupingKey(cocoSprite.thangType, null, cocoSprite.colorConfig) + '.'
|
||||
sprite = new WebGLSprite(@spriteSheet, cocoSprite.thangType, prefix, @resolutionFactor)
|
||||
sprite = new SpriteClass(@spriteSheet, cocoSprite.thangType, prefix, @resolutionFactor)
|
||||
|
||||
sprite.sprite = cocoSprite
|
||||
sprite.layerPriority = cocoSprite.thang?.layerPriority ? cocoSprite.thangType.get 'layerPriority'
|
||||
|
|
121
test/app/lib/surface/SegmentedSprite.spec.coffee
Normal file
121
test/app/lib/surface/SegmentedSprite.spec.coffee
Normal file
|
@ -0,0 +1,121 @@
|
|||
WebGLLayer = require 'lib/surface/WebGLLayer'
|
||||
SegmentedSprite = require 'lib/surface/SegmentedSprite'
|
||||
CocoSprite = require 'lib/surface/CocoSprite'
|
||||
ThangType = require 'models/ThangType'
|
||||
ogreMunchkinThangType = new ThangType(require 'test/app/fixtures/ogre-munchkin-m.thang.type')
|
||||
ogreFangriderThangType = new ThangType(require 'test/app/fixtures/ogre-fangrider.thang.type')
|
||||
|
||||
describe 'SegmentedSprite', ->
|
||||
segmentedSprite = null
|
||||
|
||||
showMe = ->
|
||||
canvas = $('<canvas width="600" height="400"></canvas>').css('position', 'absolute').css('index', 1000).css('background', 'white')
|
||||
$('body').append(canvas)
|
||||
stage = new createjs.SpriteStage(canvas[0])
|
||||
stage.addChild(segmentedSprite)
|
||||
|
||||
ticks = 0
|
||||
listener = {
|
||||
handleEvent: ->
|
||||
return if ticks >= 100
|
||||
ticks += 1
|
||||
segmentedSprite.tick(arguments[0].delta)
|
||||
stage.update()
|
||||
}
|
||||
createjs.Ticker.addEventListener "tick", listener
|
||||
|
||||
describe 'with Ogre Munchkin ThangType', ->
|
||||
beforeEach ->
|
||||
layer = new WebGLLayer()
|
||||
layer.buildAutomatically = false
|
||||
layer.buildAsync = false
|
||||
ogreMunchkinThangType.markToRevert()
|
||||
ogreMunchkinThangType.set('spriteType', 'segmented')
|
||||
actions = ogreMunchkinThangType.getActions()
|
||||
|
||||
# couple extra actions for doing some tests
|
||||
actions.littledance = {animation:'enemy_small_move_side',framerate:1, frames:'0,6,2,6,2,8,0'}
|
||||
actions.onestep = {animation:'enemy_small_move_side', loops: false}
|
||||
|
||||
colorConfig = {team: {hue: 0, saturation: 1, lightness: 0.5}}
|
||||
sprite = new CocoSprite(ogreMunchkinThangType, {colorConfig: colorConfig})
|
||||
layer.addCocoSprite(sprite)
|
||||
sheet = layer.renderNewSpriteSheet()
|
||||
prefix = layer.renderGroupingKey(ogreMunchkinThangType, null, colorConfig) + '.'
|
||||
window.segmentedSprite = segmentedSprite = new SegmentedSprite(sheet, ogreMunchkinThangType, prefix)
|
||||
segmentedSprite.x = 200
|
||||
segmentedSprite.y = 200
|
||||
|
||||
afterEach ->
|
||||
ogreMunchkinThangType.revert()
|
||||
|
||||
it 'has gotoAndPlay, gotoAndStop, currentAnimation, and paused like a MovieClip or Sprite', ->
|
||||
segmentedSprite.gotoAndPlay('move_fore')
|
||||
expect(segmentedSprite.baseMovieClip).toBeDefined()
|
||||
expect(segmentedSprite.paused).toBe(false)
|
||||
segmentedSprite.gotoAndStop('move_fore')
|
||||
expect(segmentedSprite.paused).toBe(true)
|
||||
expect(segmentedSprite.currentAnimation).toBe('move_fore')
|
||||
|
||||
it 'has a tick function which moves the animation forward', ->
|
||||
segmentedSprite.gotoAndPlay('attack')
|
||||
segmentedSprite.tick(100) # one hundred milliseconds
|
||||
expect(segmentedSprite.baseMovieClip.currentFrame).toBe(segmentedSprite.framerate*100/1000)
|
||||
|
||||
it 'will interpolate between frames of a custom frame set', ->
|
||||
segmentedSprite.gotoAndPlay('littledance')
|
||||
segmentedSprite.tick(1000)
|
||||
expect(segmentedSprite.baseMovieClip.currentFrame).toBe(6)
|
||||
segmentedSprite.tick(1000)
|
||||
expect(segmentedSprite.baseMovieClip.currentFrame).toBe(2)
|
||||
segmentedSprite.tick(500)
|
||||
expect(segmentedSprite.baseMovieClip.currentFrame).toBe(4)
|
||||
segmentedSprite.tick(500)
|
||||
expect(segmentedSprite.baseMovieClip.currentFrame).toBe(6)
|
||||
|
||||
it 'emits animationend for animations where loops is false and there is no goesTo', ->
|
||||
fired = false
|
||||
segmentedSprite.gotoAndPlay('onestep')
|
||||
segmentedSprite.on('animationend', -> fired = true)
|
||||
segmentedSprite.tick(1000)
|
||||
expect(fired).toBe(true)
|
||||
|
||||
describe 'with Ogre Fangrider ThangType', ->
|
||||
beforeEach ->
|
||||
layer = new WebGLLayer()
|
||||
layer.buildAutomatically = false
|
||||
layer.buildAsync = false
|
||||
ogreFangriderThangType.markToRevert()
|
||||
ogreFangriderThangType.set('spriteType', 'segmented')
|
||||
colorConfig = {team: {hue: 0, saturation: 1, lightness: 0.5}}
|
||||
sprite = new CocoSprite(ogreFangriderThangType, {colorConfig: colorConfig})
|
||||
layer.addCocoSprite(sprite)
|
||||
sheet = layer.renderNewSpriteSheet()
|
||||
prefix = layer.renderGroupingKey(ogreFangriderThangType, null, colorConfig) + '.'
|
||||
window.segmentedSprite = segmentedSprite = new SegmentedSprite(sheet, ogreFangriderThangType, prefix)
|
||||
segmentedSprite.x = 300
|
||||
segmentedSprite.y = 300
|
||||
|
||||
afterEach ->
|
||||
ogreFangriderThangType.revert()
|
||||
|
||||
it 'synchronizes animations with child movie clips properly', ->
|
||||
segmentedSprite.gotoAndPlay('die')
|
||||
segmentedSprite.tick(100) # one hundred milliseconds
|
||||
expectedFrame = segmentedSprite.framerate*100/1000
|
||||
expect(segmentedSprite.currentFrame).toBe(expectedFrame)
|
||||
for movieClip in segmentedSprite.childMovieClips
|
||||
expect(movieClip.currentFrame).toBe(expectedFrame)
|
||||
|
||||
it 'does not include shapes from the original animation', ->
|
||||
segmentedSprite.gotoAndPlay('attack')
|
||||
segmentedSprite.tick(230)
|
||||
for child in segmentedSprite.children
|
||||
expect(_.isString(child)).toBe(false)
|
||||
|
||||
it 'maintains the right number of shapes', ->
|
||||
segmentedSprite.gotoAndPlay('idle')
|
||||
lengths = []
|
||||
for i in _.range(10)
|
||||
segmentedSprite.tick(10)
|
||||
expect(segmentedSprite.children.length).toBe(20)
|
48
test/app/lib/surface/SingularSprite.spec.coffee
Normal file
48
test/app/lib/surface/SingularSprite.spec.coffee
Normal file
|
@ -0,0 +1,48 @@
|
|||
WebGLLayer = require 'lib/surface/WebGLLayer'
|
||||
SingularSprite = require 'lib/surface/SingularSprite'
|
||||
CocoSprite = require 'lib/surface/CocoSprite'
|
||||
ThangType = require 'models/ThangType'
|
||||
ogreMunchkinThangType = new ThangType(require 'test/app/fixtures/ogre-munchkin-m.thang.type')
|
||||
|
||||
describe 'SingularSprite', ->
|
||||
singularSprite = null
|
||||
|
||||
showMe = ->
|
||||
canvas = $('<canvas width="600" height="400"></canvas>').css('position', 'absolute').css('index', 1000).css('background', 'white')
|
||||
$('body').append(canvas)
|
||||
stage = new createjs.SpriteStage(canvas[0])
|
||||
stage.addChild(singularSprite)
|
||||
|
||||
ticks = 0
|
||||
listener = {
|
||||
handleEvent: ->
|
||||
return if ticks >= 100
|
||||
ticks += 1
|
||||
stage.update()
|
||||
}
|
||||
createjs.Ticker.addEventListener "tick", listener
|
||||
|
||||
describe 'with Ogre Munchkin ThangType and spriteType=spriteSheet', ->
|
||||
beforeEach ->
|
||||
layer = new WebGLLayer()
|
||||
layer.buildAutomatically = false
|
||||
layer.buildAsync = false
|
||||
ogreMunchkinThangType.markToRevert()
|
||||
ogreMunchkinThangType.set('spriteType', 'singular')
|
||||
actions = ogreMunchkinThangType.getActions()
|
||||
|
||||
colorConfig = {team: {hue: 0, saturation: 1, lightness: 0.5}}
|
||||
sprite = new CocoSprite(ogreMunchkinThangType, {colorConfig: colorConfig})
|
||||
layer.addCocoSprite(sprite)
|
||||
sheet = layer.renderNewSpriteSheet()
|
||||
prefix = layer.renderGroupingKey(ogreMunchkinThangType, null, colorConfig) + '.'
|
||||
window.singularSprite = singularSprite = new SingularSprite(sheet, ogreMunchkinThangType, prefix)
|
||||
singularSprite.x = 200
|
||||
singularSprite.y = 200
|
||||
|
||||
afterEach ->
|
||||
ogreMunchkinThangType.revert()
|
||||
|
||||
it 'has the same interface as for when the ThangType uses the container spriteType', ->
|
||||
singularSprite.gotoAndPlay('move_fore')
|
||||
singularSprite.gotoAndStop('attack')
|
|
@ -3,9 +3,9 @@ Camera = require 'lib/surface/Camera'
|
|||
World = require 'lib/world/world'
|
||||
ThangType = require 'models/ThangType'
|
||||
|
||||
treeThangType = new ThangType(require 'test/app/fixtures/tree1.thang.type')
|
||||
ogreMunchkinThangType = new ThangType(require 'test/app/fixtures/ogre-munchkin-m.thang.type')
|
||||
ogreFangriderThangType = new ThangType(require 'test/app/fixtures/ogre-fangrider.thang.type')
|
||||
treeData = require 'test/app/fixtures/tree1.thang.type'
|
||||
munchkinData = require 'test/app/fixtures/ogre-munchkin-m.thang.type'
|
||||
fangriderData = require 'test/app/fixtures/ogre-fangrider.thang.type'
|
||||
|
||||
describe 'SpriteBoss', ->
|
||||
spriteBoss = null
|
||||
|
@ -26,24 +26,23 @@ describe 'SpriteBoss', ->
|
|||
world = new World()
|
||||
world.thangs = [
|
||||
# Set trees side by side with different render strategies
|
||||
{id: 'Tree 1', spriteName: 'Tree 1', exists: true, pos: {x:10, y:-8}, action: 'idle', health: 20, maxHealth: 20, rotation: Math.PI/2, acts: true }
|
||||
{id: 'Tree 2', spriteName: 'Full Render Tree', exists: true, pos: {x:8, y:-8}, action: 'idle', health: 20, maxHealth: 20, rotation: Math.PI/2, acts: true }
|
||||
{id: 'Segmented Tree', spriteName: 'Segmented Tree', exists: true, pos: {x:10, y:-8}, action: 'idle', health: 20, maxHealth: 20, rotation: Math.PI/2, acts: true }
|
||||
{id: 'Singular Tree', spriteName: 'Singular Tree', exists: true, pos: {x:8, y:-8}, action: 'idle', health: 20, maxHealth: 20, rotation: Math.PI/2, acts: true }
|
||||
|
||||
# Include a tree whose existence will change so we can test removing sprites
|
||||
{id: 'Tree Will Disappear', spriteName: 'Tree 1', exists: true, pos: {x:0, y:0}, action: 'idle', health: 20, maxHealth: 20, rotation: Math.PI/2, acts: true }
|
||||
{id: 'Disappearing Tree', spriteName: 'Singular Tree', exists: true, pos: {x:0, y:0}, action: 'idle', health: 20, maxHealth: 20, rotation: Math.PI/2, acts: true }
|
||||
]
|
||||
world.thangMap = {}
|
||||
world.thangMap[thang.id] = thang for thang in world.thangs
|
||||
|
||||
# Set up thang types. Mix renderStrategies.
|
||||
fullRenderOgreMunchkinThangType = ogreMunchkinThangType.clone()
|
||||
fullRenderOgreMunchkinThangType.set({name:'Full Render Ogre', slug:'full-render-ogre'})
|
||||
fullRenderTreeThangType = treeThangType.clone()
|
||||
fullRenderTreeThangType.set({name:'Full Render Tree', slug:'full-render-tree'})
|
||||
ogreMunchkinThangType.set('renderStrategy', 'container')
|
||||
ogreFangriderThangType.set('renderStrategy', 'container')
|
||||
treeThangType.set('renderStrategy', 'container')
|
||||
thangTypes = [treeThangType, ogreMunchkinThangType, ogreFangriderThangType, fullRenderOgreMunchkinThangType, fullRenderTreeThangType]
|
||||
fangrider = new ThangType($.extend({}, fangriderData, {spriteType:'segmented', name:'Fangrider', slug:'fangrider'}))
|
||||
segmentedMunchkin = new ThangType($.extend({}, munchkinData, {spriteType:'segmented', name:'Segmented Munchkin', slug:'segmented-munchkin'}))
|
||||
singularMunchkin = new ThangType($.extend({}, munchkinData, {spriteType:'singular', name:'Singular Munchkin', slug:'singular-munchkin'}))
|
||||
segmentedTree = new ThangType($.extend({}, treeData, {spriteType:'segmented', name:'Segmented Tree', slug: 'segmented-tree'}))
|
||||
singularTree = new ThangType($.extend({}, treeData, {spriteType:'singular', name:'Singular Tree', slug: 'singular-tree'}))
|
||||
|
||||
thangTypes = [fangrider, segmentedMunchkin, singularMunchkin, segmentedTree, singularTree]
|
||||
|
||||
# Build the Stage and SpriteBoss.
|
||||
window.stage = stage = new createjs.SpriteStage(canvas[0])
|
||||
|
@ -69,49 +68,49 @@ describe 'SpriteBoss', ->
|
|||
spriteBoss.update(true)
|
||||
|
||||
# Test that the unrendered, static sprites aren't showing anything
|
||||
midRenderExpectations.push([spriteBoss.sprites['Tree 1'].imageObject.children.length,1,'static container action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Tree 1'].imageObject.children[0].currentFrame,0,'static container action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Tree 1'].imageObject.children[0].paused,true,'static container action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Tree 2'].imageObject.children[0].currentFrame,0,'static spriteSheet action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Tree 2'].imageObject.children[0].paused,true,'static spriteSheet action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Segmented Tree'].imageObject.children.length,1,'static segmented action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Segmented Tree'].imageObject.children[0].currentFrame,0,'static segmented action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Segmented Tree'].imageObject.children[0].paused,true,'static segmented action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Singular Tree'].imageObject.currentFrame,0,'static singular action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Singular Tree'].imageObject.paused,true,'static singular action'])
|
||||
|
||||
defaultLayer.once 'new-spritesheet', ->
|
||||
|
||||
# Now make the world a little more complicated.
|
||||
world.thangs = world.thangs.concat [
|
||||
# four cardinal ogres, to test movement rotation and placement around a center point.
|
||||
{id: 'Ogre N', spriteName: 'Ogre Munchkin M', exists: true, pos: {x:0, y:8}, action: 'move', health: 10, maxHealth: 10, rotation: -Math.PI/2, acts: true, scaleFactorX: 1.5 }
|
||||
{id: 'Ogre W', spriteName: 'Ogre Munchkin M', exists: true, pos: {x:-8, y:0}, action: 'move', health: 5, maxHealth: 10, rotation: 0, acts: true, scaleFactorY: 1.5 }
|
||||
{id: 'Ogre E', spriteName: 'Ogre Munchkin M', exists: true, pos: {x:8, y:0}, action: 'move', health: 5, maxHealth: 10, rotation: Math.PI, acts: true, alpha: 0.5 }
|
||||
{id: 'Ogre S', spriteName: 'Ogre Munchkin M', exists: true, pos: {x:0, y:-8}, action: 'move', health: 5, maxHealth: 10, rotation: Math.PI/2, acts: true }
|
||||
{id: 'Ogre N', spriteName: 'Segmented Munchkin', exists: true, pos: {x:0, y:8}, action: 'move', health: 10, maxHealth: 10, rotation: -Math.PI/2, acts: true, scaleFactorX: 1.5 }
|
||||
{id: 'Ogre W', spriteName: 'Segmented Munchkin', exists: true, pos: {x:-8, y:0}, action: 'move', health: 5, maxHealth: 10, rotation: 0, acts: true, scaleFactorY: 1.5 }
|
||||
{id: 'Ogre E', spriteName: 'Segmented Munchkin', exists: true, pos: {x:8, y:0}, action: 'move', health: 5, maxHealth: 10, rotation: Math.PI, acts: true, alpha: 0.5 }
|
||||
{id: 'Ogre S', spriteName: 'Segmented Munchkin', exists: true, pos: {x:0, y:-8}, action: 'move', health: 5, maxHealth: 10, rotation: Math.PI/2, acts: true }
|
||||
|
||||
# Set ogres side by side with different render strategies
|
||||
{id: 'FROgre', spriteName: 'Full Render Ogre', exists: true, pos: {x:-10, y:-8}, action: 'move', health: 10, maxHealth: 10, rotation: -Math.PI/2, acts: true, alpha: 0.5 }
|
||||
{id: 'NotFROgre', spriteName: 'Ogre Munchkin M', exists: true, pos: {x:-8, y:-8}, action: 'move', health: 10, maxHealth: 10, rotation: -Math.PI/2, acts: true }
|
||||
{id: 'Singular Ogre', spriteName: 'Singular Munchkin', exists: true, pos: {x:-10, y:-8}, action: 'move', health: 10, maxHealth: 10, rotation: -Math.PI/2, acts: true, alpha: 0.5 }
|
||||
{id: 'Segmented Ogre', spriteName: 'Segmented Munchkin', exists: true, pos: {x:-8, y:-8}, action: 'move', health: 10, maxHealth: 10, rotation: -Math.PI/2, acts: true }
|
||||
|
||||
# A line of ogres overlapping to test child ordering
|
||||
{id: 'Ogre 1', spriteName: 'Ogre Munchkin M', exists: true, pos: {x:-14, y:0}, action: 'die', health: 5, maxHealth: 10, rotation: 0, acts: true }
|
||||
{id: 'Ogre 2', spriteName: 'Ogre Munchkin M', exists: true, pos: {x:-13.5, y:1}, action: 'die', health: 5, maxHealth: 10, rotation: 0, acts: true }
|
||||
{id: 'Ogre 3', spriteName: 'Ogre Munchkin M', exists: true, pos: {x:-13, y:2}, action: 'die', health: 5, maxHealth: 10, rotation: 0, acts: true }
|
||||
{id: 'Ogre 4', spriteName: 'Ogre Munchkin M', exists: true, pos: {x:-12.5, y:3}, action: 'die', health: 5, maxHealth: 10, rotation: 0, acts: true }
|
||||
{id: 'Dying Ogre 1', spriteName: 'Segmented Munchkin', exists: true, pos: {x:-14, y:0}, action: 'die', health: 5, maxHealth: 10, rotation: 0, acts: true }
|
||||
{id: 'Dying Ogre 2', spriteName: 'Segmented Munchkin', exists: true, pos: {x:-13.5, y:1}, action: 'die', health: 5, maxHealth: 10, rotation: 0, acts: true }
|
||||
{id: 'Dying Ogre 3', spriteName: 'Segmented Munchkin', exists: true, pos: {x:-13, y:2}, action: 'die', health: 5, maxHealth: 10, rotation: 0, acts: true }
|
||||
{id: 'Dying Ogre 4', spriteName: 'Segmented Munchkin', exists: true, pos: {x:-12.5, y:3}, action: 'die', health: 5, maxHealth: 10, rotation: 0, acts: true }
|
||||
|
||||
# Throw in a ThangType that contains nested MovieClips
|
||||
{id: 'Fangrider 1', spriteName: 'Ogre Fangrider', exists: true, pos: {x:8, y:8}, action: 'move', health: 20, maxHealth: 20, rotation: 0, acts: true }
|
||||
{id: 'Fangrider', spriteName: 'Fangrider', exists: true, pos: {x:8, y:8}, action: 'move', health: 20, maxHealth: 20, rotation: 0, acts: true }
|
||||
]
|
||||
|
||||
_.find(world.thangs, {id: 'Tree Will Disappear'}).exists = false
|
||||
_.find(world.thangs, {id: 'Disappearing Tree'}).exists = false
|
||||
world.thangMap[thang.id] = thang for thang in world.thangs
|
||||
spriteBoss.update(true)
|
||||
|
||||
# Test that the unrendered, animated sprites aren't showing anything
|
||||
midRenderExpectations.push([spriteBoss.sprites['NotFROgre'].imageObject.children.length,10,'animated container action'])
|
||||
for child in spriteBoss.sprites['NotFROgre'].imageObject.children
|
||||
midRenderExpectations.push([child.children[0].currentFrame, 0, 'animated container action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['FROgre'].imageObject.children[0].currentFrame,0,'animated spriteSheet action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['FROgre'].imageObject.children[0].paused,true,'animated spriteSheet action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Segmented Ogre'].imageObject.children.length,10,'animated segmented action'])
|
||||
for child in spriteBoss.sprites['Segmented Ogre'].imageObject.children
|
||||
midRenderExpectations.push([child.children[0].currentFrame, 0, 'animated segmented action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Singular Ogre'].imageObject.currentFrame,0,'animated singular action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Singular Ogre'].imageObject.paused,true,'animated singular action'])
|
||||
|
||||
defaultLayer.once 'new-spritesheet', ->
|
||||
showMe() # Uncomment to display this world when you run any of these tests.
|
||||
# showMe() # Uncomment to display this world when you run any of these tests.
|
||||
done()
|
||||
|
||||
beforeEach (done) -> init(done)
|
||||
|
@ -166,10 +165,10 @@ describe 'SpriteBoss', ->
|
|||
it 'orders sprites in the layer based on thang pos.y\'s', ->
|
||||
container = spriteBoss.spriteLayers.Default.spriteContainer
|
||||
l = spriteBoss.spriteLayers.Default.spriteContainer.children
|
||||
i1 = container.getChildIndex(_.find(container.children, (c) -> c.sprite.thang.id is 'Ogre 1'))
|
||||
i2 = container.getChildIndex(_.find(container.children, (c) -> c.sprite.thang.id is 'Ogre 2'))
|
||||
i3 = container.getChildIndex(_.find(container.children, (c) -> c.sprite.thang.id is 'Ogre 3'))
|
||||
i4 = container.getChildIndex(_.find(container.children, (c) -> c.sprite.thang.id is 'Ogre 4'))
|
||||
i1 = container.getChildIndex(_.find(container.children, (c) -> c.sprite.thang.id is 'Dying Ogre 1'))
|
||||
i2 = container.getChildIndex(_.find(container.children, (c) -> c.sprite.thang.id is 'Dying Ogre 2'))
|
||||
i3 = container.getChildIndex(_.find(container.children, (c) -> c.sprite.thang.id is 'Dying Ogre 3'))
|
||||
i4 = container.getChildIndex(_.find(container.children, (c) -> c.sprite.thang.id is 'Dying Ogre 4'))
|
||||
expect(i1).toBeGreaterThan(i2)
|
||||
expect(i2).toBeGreaterThan(i3)
|
||||
expect(i3).toBeGreaterThan(i4)
|
||||
|
|
|
@ -12,8 +12,8 @@ describe 'WebGLLayer', ->
|
|||
layer.buildAutomatically = false
|
||||
layer.buildAsync = false
|
||||
|
||||
it 'creates containers for animated actions if set to renderStrategy=container', ->
|
||||
ogreMunchkinThangType.set('renderStrategy', 'container')
|
||||
it 'creates containers for animated actions if set to spriteType=segmented', ->
|
||||
ogreMunchkinThangType.set('spriteType', 'segmented')
|
||||
colorConfig = {team: {hue: 0, saturation: 1, lightness: 0.5}}
|
||||
sprite = new CocoSprite(ogreMunchkinThangType, {colorConfig: colorConfig})
|
||||
layer.addCocoSprite(sprite)
|
||||
|
@ -21,16 +21,16 @@ describe 'WebGLLayer', ->
|
|||
key = layer.renderGroupingKey(ogreMunchkinThangType, 'head', colorConfig)
|
||||
expect(key in sheet.getAnimations()).toBe(true)
|
||||
|
||||
it 'creates the container for static actions if set to renderStrategy=container', ->
|
||||
treeThangType.set('renderStrategy', 'container')
|
||||
it 'creates the container for static actions if set to spriteType=segmented', ->
|
||||
treeThangType.set('spriteType', 'segmented')
|
||||
sprite = new CocoSprite(treeThangType)
|
||||
layer.addCocoSprite(sprite)
|
||||
sheet = layer.renderNewSpriteSheet()
|
||||
key = layer.renderGroupingKey(treeThangType, 'Tree_4')
|
||||
expect(key in sheet.getAnimations()).toBe(true)
|
||||
|
||||
it 'creates animations for animated actions if set to renderStrategy=spriteSheet', ->
|
||||
ogreMunchkinThangType.set('renderStrategy', 'spriteSheet')
|
||||
it 'creates animations for animated actions if set to spriteType=singular', ->
|
||||
ogreMunchkinThangType.set('spriteType', 'singular')
|
||||
colorConfig = {team: {hue: 0, saturation: 1, lightness: 0.5}}
|
||||
sprite = new CocoSprite(ogreMunchkinThangType, {colorConfig: colorConfig})
|
||||
layer.addCocoSprite(sprite)
|
||||
|
@ -38,17 +38,17 @@ describe 'WebGLLayer', ->
|
|||
key = layer.renderGroupingKey(ogreMunchkinThangType, 'idle', colorConfig)
|
||||
expect(key in sheet.getAnimations()).toBe(true)
|
||||
|
||||
it 'creates animations for static actions if set to renderStrategy=spriteSheet', ->
|
||||
treeThangType.set('renderStrategy', 'spriteSheet')
|
||||
it 'creates animations for static actions if set to spriteType=singular', ->
|
||||
treeThangType.set('spriteType', 'singular')
|
||||
sprite = new CocoSprite(treeThangType)
|
||||
layer.addCocoSprite(sprite)
|
||||
sheet = layer.renderNewSpriteSheet()
|
||||
key = layer.renderGroupingKey(treeThangType, 'idle')
|
||||
expect(key in sheet.getAnimations()).toBe(true)
|
||||
|
||||
it 'only renders frames used by actions when renderStrategy=spriteSheet', ->
|
||||
it 'only renders frames used by actions when spriteType=singular', ->
|
||||
layer.setDefaultActions(['idle']) # uses the move side animation
|
||||
ogreMunchkinThangType.set('renderStrategy', 'spriteSheet')
|
||||
ogreMunchkinThangType.set('spriteType', 'singular')
|
||||
colorConfig = {team: {hue: 0, saturation: 1, lightness: 0.5}}
|
||||
sprite = new CocoSprite(ogreMunchkinThangType, {colorConfig: colorConfig})
|
||||
layer.addCocoSprite(sprite)
|
||||
|
@ -121,7 +121,7 @@ describe 'WebGLLayer', ->
|
|||
expect(layer._renderNewSpriteSheet).toHaveBeenCalled()
|
||||
|
||||
it 'recycles *containers* from previous sprite sheets, rather than building repeatedly from raw vector data', ->
|
||||
treeThangType.set('renderStrategy', 'container')
|
||||
treeThangType.set('spriteType', 'segmented')
|
||||
sprite = new CocoSprite(treeThangType)
|
||||
layer.addCocoSprite(sprite)
|
||||
spyOn(SpriteBuilder.prototype, 'buildContainerFromStore').and.callThrough()
|
||||
|
@ -130,7 +130,7 @@ describe 'WebGLLayer', ->
|
|||
expect(SpriteBuilder.prototype.buildContainerFromStore.calls.count()).toBe(1)
|
||||
|
||||
it '*does not* recycle *containers* from previous sprite sheets when the resolutionFactor has changed', ->
|
||||
treeThangType.set('renderStrategy', 'container')
|
||||
treeThangType.set('spriteType', 'segmented')
|
||||
sprite = new CocoSprite(treeThangType)
|
||||
layer.addCocoSprite(sprite)
|
||||
spyOn(SpriteBuilder.prototype, 'buildContainerFromStore').and.callThrough()
|
||||
|
@ -140,7 +140,7 @@ describe 'WebGLLayer', ->
|
|||
expect(SpriteBuilder.prototype.buildContainerFromStore.calls.count()).toBe(2)
|
||||
|
||||
it 'recycles *animations* from previous sprite sheets, rather than building repeatedly from raw vector data', ->
|
||||
ogreMunchkinThangType.set('renderStrategy', 'spriteSheet')
|
||||
ogreMunchkinThangType.set('spriteType', 'singular')
|
||||
sprite = new CocoSprite(ogreMunchkinThangType)
|
||||
layer.addCocoSprite(sprite)
|
||||
numFrameses = []
|
||||
|
@ -156,7 +156,7 @@ describe 'WebGLLayer', ->
|
|||
expect(SpriteBuilder.prototype.buildMovieClip.calls.count()).toBe(5)
|
||||
|
||||
it '*does not* recycles *animations* from previous sprite sheets when the resolutionFactor has changed', ->
|
||||
ogreMunchkinThangType.set('renderStrategy', 'spriteSheet')
|
||||
ogreMunchkinThangType.set('spriteType', 'singular')
|
||||
sprite = new CocoSprite(ogreMunchkinThangType)
|
||||
layer.addCocoSprite(sprite)
|
||||
spyOn(SpriteBuilder.prototype, 'buildMovieClip').and.callThrough()
|
||||
|
|
|
@ -1,151 +0,0 @@
|
|||
WebGLLayer = require 'lib/surface/WebGLLayer'
|
||||
WebGLSprite = require 'lib/surface/WebGLSprite'
|
||||
CocoSprite = require 'lib/surface/CocoSprite'
|
||||
ThangType = require 'models/ThangType'
|
||||
treeThangType = new ThangType(require 'test/app/fixtures/tree1.thang.type')
|
||||
ogreMunchkinThangType = new ThangType(require 'test/app/fixtures/ogre-munchkin-m.thang.type')
|
||||
ogreFangriderThangType = new ThangType(require 'test/app/fixtures/ogre-fangrider.thang.type')
|
||||
|
||||
describe 'WebGLSprite', ->
|
||||
webGLSprite = null
|
||||
|
||||
showMe = ->
|
||||
canvas = $('<canvas width="600" height="400"></canvas>').css('position', 'absolute').css('index', 1000).css('background', 'white')
|
||||
$('body').append(canvas)
|
||||
stage = new createjs.SpriteStage(canvas[0])
|
||||
stage.addChild(webGLSprite)
|
||||
|
||||
ticks = 0
|
||||
listener = {
|
||||
handleEvent: ->
|
||||
return if ticks >= 100
|
||||
ticks += 1
|
||||
webGLSprite.tick(arguments[0].delta)
|
||||
stage.update()
|
||||
}
|
||||
createjs.Ticker.addEventListener "tick", listener
|
||||
|
||||
describe 'with Ogre Munchkin ThangType', ->
|
||||
beforeEach ->
|
||||
layer = new WebGLLayer()
|
||||
layer.buildAutomatically = false
|
||||
layer.buildAsync = false
|
||||
ogreMunchkinThangType.markToRevert()
|
||||
ogreMunchkinThangType.set('renderStrategy', 'container')
|
||||
actions = ogreMunchkinThangType.getActions()
|
||||
|
||||
# couple extra actions for doing some tests
|
||||
actions.littledance = {animation:'enemy_small_move_side',framerate:1, frames:'0,6,2,6,2,8,0'}
|
||||
actions.onestep = {animation:'enemy_small_move_side', loops: false}
|
||||
|
||||
colorConfig = {team: {hue: 0, saturation: 1, lightness: 0.5}}
|
||||
sprite = new CocoSprite(ogreMunchkinThangType, {colorConfig: colorConfig})
|
||||
layer.addCocoSprite(sprite)
|
||||
sheet = layer.renderNewSpriteSheet()
|
||||
prefix = layer.renderGroupingKey(ogreMunchkinThangType, null, colorConfig) + '.'
|
||||
window.webGLSprite = webGLSprite = new WebGLSprite(sheet, ogreMunchkinThangType, prefix)
|
||||
webGLSprite.x = 200
|
||||
webGLSprite.y = 200
|
||||
|
||||
afterEach ->
|
||||
ogreMunchkinThangType.revert()
|
||||
|
||||
it 'has gotoAndPlay, gotoAndStop, and paused like a MovieClip or Sprite', ->
|
||||
webGLSprite.gotoAndPlay('move_fore')
|
||||
expect(webGLSprite.baseMovieClip).toBeDefined()
|
||||
expect(webGLSprite.paused).toBe(false)
|
||||
webGLSprite.gotoAndStop('move_fore')
|
||||
expect(webGLSprite.paused).toBe(true)
|
||||
showMe()
|
||||
|
||||
it 'has a tick function which moves the animation forward', ->
|
||||
webGLSprite.gotoAndPlay('attack')
|
||||
webGLSprite.tick(100) # one hundred milliseconds
|
||||
expect(webGLSprite.baseMovieClip.currentFrame).toBe(webGLSprite.framerate*100/1000)
|
||||
|
||||
it 'will interpolate between frames of a custom frame set', ->
|
||||
webGLSprite.gotoAndPlay('littledance')
|
||||
webGLSprite.tick(1000)
|
||||
expect(webGLSprite.baseMovieClip.currentFrame).toBe(6)
|
||||
webGLSprite.tick(1000)
|
||||
expect(webGLSprite.baseMovieClip.currentFrame).toBe(2)
|
||||
webGLSprite.tick(500)
|
||||
expect(webGLSprite.baseMovieClip.currentFrame).toBe(4)
|
||||
webGLSprite.tick(500)
|
||||
expect(webGLSprite.baseMovieClip.currentFrame).toBe(6)
|
||||
|
||||
it 'emits animationend for animations where loops is false and there is no goesTo', ->
|
||||
fired = false
|
||||
webGLSprite.gotoAndPlay('onestep')
|
||||
webGLSprite.on('animationend', -> fired = true)
|
||||
webGLSprite.tick(1000)
|
||||
expect(fired).toBe(true)
|
||||
|
||||
describe 'with Ogre Fangrider ThangType', ->
|
||||
beforeEach ->
|
||||
layer = new WebGLLayer()
|
||||
layer.buildAutomatically = false
|
||||
layer.buildAsync = false
|
||||
ogreFangriderThangType.markToRevert()
|
||||
ogreFangriderThangType.set('renderStrategy', 'container')
|
||||
colorConfig = {team: {hue: 0, saturation: 1, lightness: 0.5}}
|
||||
sprite = new CocoSprite(ogreFangriderThangType, {colorConfig: colorConfig})
|
||||
layer.addCocoSprite(sprite)
|
||||
sheet = layer.renderNewSpriteSheet()
|
||||
prefix = layer.renderGroupingKey(ogreFangriderThangType, null, colorConfig) + '.'
|
||||
window.webGLSprite = webGLSprite = new WebGLSprite(sheet, ogreFangriderThangType, prefix)
|
||||
webGLSprite.x = 300
|
||||
webGLSprite.y = 300
|
||||
|
||||
afterEach ->
|
||||
ogreFangriderThangType.revert()
|
||||
|
||||
it 'synchronizes animations with child movie clips properly', ->
|
||||
webGLSprite.gotoAndPlay('die')
|
||||
webGLSprite.tick(100) # one hundred milliseconds
|
||||
expectedFrame = webGLSprite.framerate*100/1000
|
||||
expect(webGLSprite.currentFrame).toBe(expectedFrame)
|
||||
for movieClip in webGLSprite.childMovieClips
|
||||
expect(movieClip.currentFrame).toBe(expectedFrame)
|
||||
|
||||
it 'does not include shapes from the original animation', ->
|
||||
webGLSprite.gotoAndPlay('attack')
|
||||
webGLSprite.tick(230)
|
||||
for child in webGLSprite.children
|
||||
expect(_.isString(child)).toBe(false)
|
||||
|
||||
it 'maintains the right number of shapes', ->
|
||||
webGLSprite.gotoAndPlay('idle')
|
||||
lengths = []
|
||||
for i in _.range(10)
|
||||
webGLSprite.tick(10)
|
||||
expect(webGLSprite.children.length).toBe(20)
|
||||
|
||||
describe 'with Ogre Munchkin ThangType and renderStrategy=spriteSheet', ->
|
||||
beforeEach ->
|
||||
layer = new WebGLLayer()
|
||||
layer.buildAutomatically = false
|
||||
layer.buildAsync = false
|
||||
ogreMunchkinThangType.markToRevert()
|
||||
ogreMunchkinThangType.set('renderStrategy', 'spriteSheet')
|
||||
actions = ogreMunchkinThangType.getActions()
|
||||
|
||||
# couple extra actions for doing some tests
|
||||
actions.littledance = {animation:'enemy_small_move_side',framerate:1, frames:'0,6,2,6,2,8,0'}
|
||||
actions.onestep = {animation:'enemy_small_move_side', loops: false}
|
||||
|
||||
colorConfig = {team: {hue: 0, saturation: 1, lightness: 0.5}}
|
||||
sprite = new CocoSprite(ogreMunchkinThangType, {colorConfig: colorConfig})
|
||||
layer.addCocoSprite(sprite)
|
||||
sheet = layer.renderNewSpriteSheet()
|
||||
prefix = layer.renderGroupingKey(ogreMunchkinThangType, null, colorConfig) + '.'
|
||||
window.webGLSprite = webGLSprite = new WebGLSprite(sheet, ogreMunchkinThangType, prefix)
|
||||
webGLSprite.x = 200
|
||||
webGLSprite.y = 200
|
||||
|
||||
afterEach ->
|
||||
ogreMunchkinThangType.revert()
|
||||
|
||||
it 'has the same interface as for when the ThangType uses the container renderStrategy', ->
|
||||
webGLSprite.gotoAndPlay('move_fore')
|
||||
webGLSprite.gotoAndStop('attack')
|
Loading…
Reference in a new issue