Initial integration of SpriteBoss with the WebGLLayer and all else.

This commit is contained in:
Scott Erickson 2014-09-17 15:47:25 -07:00
parent 1ef3d150a8
commit 7387248ffd
9 changed files with 310 additions and 125 deletions

View file

@ -92,7 +92,6 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
else
@actions = @thangType.getActions()
@createMarks()
@queueAction 'idle'
@updateBaseScale()
@scaleFactorX = @thang.scaleFactorX if @thang?.scaleFactorX?
@ -102,11 +101,16 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
setImageObject: (newImageObject) ->
if @imageObject
@imageObject.removeAllEventListeners()
@imageObject.destroy?()
if parent = @imageObject.parent
parent.removeChild @imageObject
parent.addChild newImageObject
parent.updateLayerOrder()
# get the cocosprite to update things
for prop in ['lastPos', 'currentRootAction']
delete @[prop]
@imageObject = newImageObject
@configureMouse()
@imageObject.on 'animationend', @playNextAction
@ -536,6 +540,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
pos
createMarks: ->
return # TODO: get marks working again
return unless @options.camera
if @thang
allProps = []

View file

@ -16,25 +16,26 @@
** Grid lines--somewhere--we will figure it out, do not really need it at first
###
layerClassProperties = {
TRANSFORM_CHILD: 'child' # Layer transform is managed by its parents
TRANSFORM_SURFACE: 'surface' # Layer moves/scales/zooms with the Surface of the World
TRANSFORM_SURFACE_TEXT: 'surface_text' # Layer moves with the Surface but is size-independent
TRANSFORM_SCREEN: 'screen' # Layer stays fixed to the screen (different from child?)
}
module.exports = class Layer extends createjs.Container
@TRANSFORM_CHILD = 'child' # Layer transform is managed by its parents
@TRANSFORM_SURFACE = 'surface' # Layer moves/scales/zooms with the Surface of the World
@TRANSFORM_SURFACE_TEXT = 'surface_text' # Layer moves with the Surface but is size-independent
@TRANSFORM_SCREEN = 'screen' # Layer stays fixed to the screen (different from child?)
layerProperties = {
subscriptions:
'camera:zoom-updated': 'onZoomUpdated'
constructor: (options) ->
super()
@initialize()
initializeLayer: (options) ->
options ?= {}
@name = options.name ? 'Unnamed'
@layerPriority = options.layerPriority ? 0
@transformStyle = options.transform ? Layer.TRANSFORM_CHILD
@transformStyle = options.transform ? layerClassProperties.TRANSFORM_CHILD
@camera = options.camera
console.error @toString(), 'needs a camera.' unless @camera
console.debug @toString(), 'needs a camera.' unless @camera
@updateLayerOrder = _.bind(@updateLayerOrder, @)
@updateLayerOrder = _.throttle @updateLayerOrder, 1000 / 30 # Don't call multiple times in one frame; 30 FPS is probably good enough
Backbone.Mediator.subscribe(channel, @[func], @) for channel, func of @subscriptions
@ -42,27 +43,12 @@ module.exports = class Layer extends createjs.Container
child.destroy?() for child in @children
Backbone.Mediator.unsubscribe(channel, @[func], @) for channel, func of @subscriptions
delete @updateLayerOrder
toString: -> "<Layer #{@layerPriority}: #{@name}>"
addChild: (children...) ->
super children...
if @transformStyle is Layer.TRANSFORM_SURFACE_TEXT
for child in children
child.scaleX /= @scaleX
child.scaleY /= @scaleY
removeChild: (children...) ->
super children...
if @transformStyle is Layer.TRANSFORM_SURFACE_TEXT
for child in children
child.scaleX *= @scaleX
child.scaleY *= @scaleY
updateLayerOrder: =>
#console.log @, @toString(), 'sorting children', _.clone @children if @name is 'Default'
updateLayerOrder: ->
@sortChildren @layerOrderComparator
layerOrderComparator: (a, b) ->
# Optimize
alp = a.layerPriority or 0
@ -85,21 +71,65 @@ module.exports = class Layer extends createjs.Container
return 0 unless aPos and bPos
return (bPos.y - aPos.y) or (bPos.x - aPos.x)
return az - bz
onZoomUpdated: (e) ->
return unless e.camera is @camera
if @transformStyle in [Layer.TRANSFORM_SURFACE, Layer.TRANSFORM_SURFACE_TEXT]
# TODO: move this to the new SpriteStage, because it's what needs to be transformed.
# This is a bit of a hack to get it to work for the time being.
if @parent and @transformStyle is layerClassProperties.TRANSFORM_CHILD
@parent.scaleX = @parent.scaleY = e.zoom
@parent.regX = e.surfaceViewport.x
@parent.regY = e.surfaceViewport.y
if @transformStyle in [layerClassProperties.TRANSFORM_SURFACE, layerClassProperties.TRANSFORM_SURFACE_TEXT]
change = @scaleX / e.zoom
@scaleX = @scaleY = e.zoom
@regX = e.surfaceViewport.x
@regY = e.surfaceViewport.y
if @transformStyle is Layer.TRANSFORM_SURFACE_TEXT
if @transformStyle is layerClassProperties.TRANSFORM_SURFACE_TEXT
for child in @children
child.scaleX *= change
child.scaleY *= change
}
class ContainerLayer extends createjs.Container
constructor: (options) ->
super()
@initialize()
@initializeLayer(options)
addChild: (children...) ->
super children...
if @transformStyle is ContainerLayer.TRANSFORM_SURFACE_TEXT
for child in children
child.scaleX /= @scaleX
child.scaleY /= @scaleY
removeChild: (children...) ->
super children...
if @transformStyle is ContainerLayer.TRANSFORM_SURFACE_TEXT
for child in children
child.scaleX *= @scaleX
child.scaleY *= @scaleY
cache: ->
return unless @children.length
bounds = @getBounds()
return unless bounds
super bounds.x, bounds.y, bounds.width, bounds.height, 2
class SpriteContainerLayer extends createjs.SpriteContainer
constructor: (spriteSheet, options) ->
super(spriteSheet)
@initialize(spriteSheet)
@initializeLayer(options)
_.extend(ContainerLayer.prototype, layerProperties)
_.extend(SpriteContainerLayer.prototype, layerProperties)
_.extend(ContainerLayer, layerClassProperties)
_.extend(SpriteContainerLayer, layerClassProperties)
module.exports.ContainerLayer = ContainerLayer
module.exports.SpriteContainerLayer = SpriteContainerLayer

View file

@ -1,6 +1,6 @@
CocoClass = require 'lib/CocoClass'
{me} = require 'lib/auth'
Layer = require './Layer'
Layer = require './WebGLLayer'
IndieSprite = require 'lib/surface/IndieSprite'
WizardSprite = require 'lib/surface/WizardSprite'
FlagSprite = require 'lib/surface/FlagSprite'
@ -66,7 +66,7 @@ module.exports = class SpriteBoss extends CocoClass
['Floating', 10]
]
@spriteLayers[name] = new Layer name: name, layerPriority: priority, transform: Layer.TRANSFORM_CHILD, camera: @camera
@surfaceLayer.addChild _.values(@spriteLayers)...
@surfaceLayer.addChild (spriteLayer.spriteContainer for spriteLayer in _.values(@spriteLayers))...
layerForChild: (child, sprite) ->
unless child.layerPriority?
@ -77,7 +77,7 @@ module.exports = class SpriteBoss extends CocoClass
child.layerPriority ?= 0
return @spriteLayers['Default'] unless child.layerPriority
layer = _.findLast @spriteLayers, (layer, name) ->
layer.layerPriority <= child.layerPriority
layer.spriteContainer.layerPriority <= child.layerPriority
layer ?= @spriteLayers['Land'] if child.layerPriority < -40
layer ? @spriteLayers['Default']
@ -86,19 +86,19 @@ module.exports = class SpriteBoss extends CocoClass
console.error 'Sprite collision! Already have:', id if @sprites[id]
@sprites[id] = sprite
@spriteArray.push sprite
sprite.imageObject.layerPriority ?= sprite.thang?.layerPriority
layer ?= @spriteLayers['Obstacle'] if sprite.thang?.spriteName.search(/(dungeon|indoor).wall/i) isnt -1
layer ?= @layerForChild sprite.imageObject, sprite
layer.addChild sprite.imageObject
layer.updateLayerOrder()
layer.addCocoSprite sprite
layer.spriteContainer.updateLayerOrder()
sprite
createMarks: ->
return # TODO: get these marks working again
@targetMark = new Mark name: 'target', camera: @camera, layer: @spriteLayers['Ground'], thangType: 'target'
@selectionMark = new Mark name: 'selection', camera: @camera, layer: @spriteLayers['Ground'], thangType: 'selection'
createSpriteOptions: (options) ->
_.extend options, camera: @camera, resolutionFactor: 4, groundLayer: @spriteLayers['Ground'], textLayer: @surfaceTextLayer, floatingLayer: @spriteLayers['Floating'], spriteSheetCache: @spriteSheetCache, showInvisible: @options.showInvisible
_.extend options, camera: @camera, resolutionFactor: SPRITE_RESOLUTION_FACTOR, groundLayer: @spriteLayers['Ground'], textLayer: @surfaceTextLayer, floatingLayer: @spriteLayers['Floating'], spriteSheetCache: @spriteSheetCache, showInvisible: @options.showInvisible
createIndieSprites: (indieSprites, withWizards) ->
unless @indieSprites
@ -185,7 +185,7 @@ module.exports = class SpriteBoss extends CocoClass
@adjustSpriteExistence() if frameChanged
sprite.update frameChanged for sprite in @spriteArray
@updateSelection()
@spriteLayers['Default'].updateLayerOrder()
@spriteLayers['Default'].spriteContainer.updateLayerOrder()
@cache()
adjustSpriteExistence: ->
@ -230,24 +230,7 @@ module.exports = class SpriteBoss extends CocoClass
return itemsJustEquipped
cache: (update=false) ->
return if @cached and not update
wallSprites = (sprite for sprite in @spriteArray when sprite.thangType?.get('name').search(/(dungeon|indoor).wall/i) isnt -1)
return if _.any (s.stillLoading for s in wallSprites)
walls = (sprite.thang for sprite in wallSprites)
@world.calculateBounds()
wallGrid = new Grid walls, @world.size()...
for wallSprite in wallSprites
wallSprite.updateActionDirection wallGrid
wallSprite.updateScale()
wallSprite.updatePosition()
#console.log @wallGrid.toString()
@spriteLayers['Obstacle'].uncache() if @spriteLayers['Obstacle'].cacheID # might have changed sizes
@spriteLayers['Obstacle'].cache()
# test performance of doing land layer, too, to see if it's faster
# @spriteLayers['Land'].uncache() if @spriteLayers['Land'].cacheID # might have changed sizes
# @spriteLayers['Land'].cache()
# I don't notice much difference - Scott
@cached = true
# TODO: remove caching
spriteFor: (thangID) -> @sprites[thangID]

View file

@ -5,7 +5,7 @@ AudioPlayer = require 'lib/AudioPlayer'
{me} = require 'lib/auth'
Camera = require './Camera'
CameraBorder = require './CameraBorder'
Layer = require './Layer'
Layer = require('./Layer').ContainerLayer
Letterbox = require './Letterbox'
Dimmer = require './Dimmer'
CountdownScreen = require './CountdownScreen'

View file

@ -1,8 +1,9 @@
SpriteBuilder = require 'lib/sprites/SpriteBuilder'
CocoClass = require 'lib/CocoClass'
WebGLSprite = require './WebGLSprite'
{SpriteContainerLayer} = require 'lib/surface/Layer'
module.exports = class WebGLLayer extends CocoClass # createjs.SpriteContainer
module.exports = class WebGLLayer extends CocoClass
_.extend(WebGLLayer.prototype, Backbone.Events)
@ -19,13 +20,15 @@ module.exports = class WebGLLayer extends CocoClass # createjs.SpriteContainer
spriteSheet: null
spriteContainer: null
constructor: ->
super(arguments...)
constructor: (@layerOptions) ->
super()
@initializing = true
@spriteSheet = @_renderNewSpriteSheet(false) # builds an empty spritesheet
@spriteContainer = new createjs.SpriteContainer(@spriteSheet)
@spriteContainer = new SpriteContainerLayer(@spriteSheet, @layerOptions)
@actionRenderState = {}
@toRenderBundles = []
@cocoSprites = []
@initializing = false
setDefaultActions: (@defaultActions) ->
@ -63,6 +66,7 @@ module.exports = class WebGLLayer extends CocoClass # createjs.SpriteContainer
@renderNewSpriteSheet()
addDefaultActionsToRender: (cocoSprite) ->
needToRender = false
if cocoSprite.thangType.get('raster')
@upsertActionToRender(cocoSprite.thangType)
else
@ -72,11 +76,12 @@ module.exports = class WebGLLayer extends CocoClass # createjs.SpriteContainer
upsertActionToRender: (thangType, actionName, colorConfig) ->
groupKey = @renderGroupingKey(thangType, actionName, colorConfig)
return if @actionRenderState[groupKey] isnt undefined
return false if @actionRenderState[groupKey] isnt undefined
@actionRenderState[groupKey] = 'need-to-render'
@toRenderBundles.push({thangType: thangType, actionName: actionName, colorConfig: colorConfig})
return if @willRender or not @buildAutomatically
return true if @willRender or not @buildAutomatically
@willRender = _.defer => @renderNewSpriteSheet()
return true
renderNewSpriteSheet: ->
@willRender = false
@ -109,11 +114,27 @@ module.exports = class WebGLLayer extends CocoClass # createjs.SpriteContainer
builder.buildAsync()
builder.on 'complete', @onBuildSpriteSheetComplete, @, true, builder
else
builder.build()
sheet = builder.build()
@onBuildSpriteSheetComplete(null, builder)
return sheet
onBuildSpriteSheetComplete: (e, builder) ->
console.log 'done?', builder.spriteSheet
return if @initializing
@spriteSheet = builder.spriteSheet
oldLayer = @spriteContainer
@spriteContainer = new SpriteContainerLayer(@spriteSheet, @layerOptions)
for cocoSprite in @cocoSprites
@setImageObjectToCocoSprite(cocoSprite)
for prop in ['scaleX', 'scaleY', 'regX', 'regY']
@spriteContainer[prop] = oldLayer[prop]
if parent = oldLayer.parent
index = parent.getChildIndex(oldLayer)
parent.removeChildAt(index)
parent.addChildAt(@spriteContainer, index)
@layerOptions.camera.updateZoom(true)
@spriteContainer.updateLayerOrder()
@trigger 'new-spritesheet'
renderContainers: (thangType, colorConfig, actionNames, spriteSheetBuilder) ->
containersToRender = {}
for actionName in actionNames
@ -223,4 +244,6 @@ module.exports = class WebGLLayer extends CocoClass # createjs.SpriteContainer
sprite.layerPriority = cocoSprite.thang?.layerPriority ? cocoSprite.thangType.get 'layerPriority'
sprite.name = cocoSprite.thang?.spriteName or cocoSprite.thangType.get 'name'
cocoSprite.addHealthBar()
cocoSprite.setImageObject(sprite)
cocoSprite.setImageObject(sprite)
cocoSprite.update(true)
@spriteContainer.addChild(sprite)

View file

@ -1,13 +1,23 @@
SpriteBuilder = require 'lib/sprites/SpriteBuilder'
module.exports = class WebGLSprite extends createjs.SpriteContainer
childSpriteContainers: null
childMovieClips: null
constructor: (@spriteSheet, @thangType, @spriteSheetPrefix) ->
@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()
@ -22,12 +32,15 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer
goto: (actionName, @paused=true) ->
@currentAnimation = actionName
@baseMovieClip = @framerate = null
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)
reg = action.positions?.registration or @thangType.get('positions')?.registration or {x:0, y:0}
if @singleChildSprite
scale = SPRITE_RESOLUTION_FACTOR * (action.scale ? @thangType.get('scale') ? 1)
@regX = -reg.x * scale
@ -38,35 +51,41 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer
@singleChildSprite.framerate = action.framerate or 20
if randomStart and frames = @spriteSheet.getAnimation(animationName)?.frames
start = Math.floor(Math.random() * frames.length)
@singleChildSprite.currentAnimationFrame = start
@singleChildSprite.currentAnimationFrame = Math.floor(Math.random() * frames.length)
else
@childSpriteContainers = []
@baseMovieClip = @buildMovieClip(action.animation)
@mirrorMovieClip(@baseMovieClip, @)
@frames = action.frames
@currentFrame = 0
if @frames
@frames = (parseInt(f) for f in @frames.split(','))
if @frames and @frames.length is 1
@baseMovieClip.gotoAndStop(@frames[0])
@paused = true
@loop = action.loops isnt false
@goesTo = action.goesTo
@animLength = if @frames then @frames.length else @baseMovieClip.frameBounds.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
if randomStart
@currentFrame = Math.floor(Math.random() * @animLength)
if action.container
if @singleChildSprite
scale = SPRITE_RESOLUTION_FACTOR * (action.scale ? @thangType.get('scale') ? 1)
@regX = -reg.x * scale
@regY = -reg.y * scale
animationName = @spriteSheetPrefix + actionName
@singleChildSprite.gotoAndStop(animationName)
else
@regX = -reg.x
@regY = -reg.y
@childMovieClips = []
containerName = @spriteSheetPrefix + action.container
sprite = new createjs.Sprite(@spriteSheet)
sprite.gotoAndStop(containerName)
@children = [sprite]
return
mirrorMovieClip: (movieClip, spriteContainer) ->
spriteContainer.children = movieClip.children
buildMovieClip: (animationName, mode, startPosition, loops) ->
raw = @thangType.get('raw')
animData = raw.animations[animationName]
@ -77,8 +96,8 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer
_.extend locals, @buildMovieClipAnimations(animData.animations)
toSkip = {}
toSkip[shape.bn] for shape in animData.shapes
toSkip[graphic.bn] for graphic in animData.graphics
toSkip[shape.bn] = true for shape in animData.shapes
toSkip[graphic.bn] = true for graphic in animData.graphics
anim = new createjs.MovieClip()
anim.initialize(mode ? createjs.MovieClip.INDEPENDENT, startPosition ? 0, loops ? true)
@ -89,7 +108,7 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer
for func in tweenData
args = $.extend(true, [], (func.a))
if @dereferenceArgs(args, locals, toSkip) is false
console.log 'could not dereference args', args
console.debug 'Did not dereference args:', args
stopped = true
break
tween = tween[func.n](args...)
@ -118,10 +137,7 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer
animation = @buildMovieClip(localAnimation.gn, localAnimation.a...)
animation.setTransform(localAnimation.t...)
map[localAnimation.bn] = animation
childSpriteContainer = new createjs.SpriteContainer(@spriteSheet)
childSpriteContainer.movieClip = animation
childSpriteContainer.children = animation.children
@childSpriteContainers.push(childSpriteContainer)
@childMovieClips.push(animation)
return map
dereferenceArgs: (args, locals, toSkip) ->
@ -140,8 +156,7 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer
return args
tick: (delta) ->
return unless @framerate and not @paused
return if @singleChildSprite # this gets moved forward automatically
return unless @baseMovieClip and @framerate and not @paused
newFrame = @currentFrame + @framerate * delta / 1000
if newFrame > @animLength
@ -149,7 +164,7 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer
@gotoAndPlay(@goesTo)
return
else if not @loop
@paused = false
@paused = true
newFrame = @animLength - 1
@dispatchEvent('animationend')
else
@ -172,13 +187,14 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer
@currentFrame = newFrame
if @childSpriteContainers
for childSpriteContainer in @childSpriteContainers
movieClip = childSpriteContainer.movieClip
continue unless movieClip.parent
index = movieClip.parent.getChildIndex(movieClip)
movieClip.gotoAndStop(newFrame)
movieClip.parent[index] = childSpriteContainer
# 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()

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,120 @@
SpriteBoss = require 'lib/surface/SpriteBoss'
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')
describe 'SpriteBoss', ->
spriteBoss = null
canvas = null
stage = null
# This suite just creates and renders the stage once, and then has each of the tests
# check the resulting data for the whole thing, without changing anything.
init = (done) ->
return done() if spriteBoss
t = new Date()
canvas = $('<canvas width="800" height="600"></canvas>')
camera = new Camera(canvas)
world = new World()
world.thangs = [
# four cardinal ogres
{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: 2 }
{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: 2 }
{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, scaleFactorY: 3, scaleFactorX: 3 }
{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 }
# ogres overlapping
{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: 'Fangrider 1', spriteName: 'Ogre Fangrider', exists: true, pos: {x:8, y:8}, action: 'move', health: 20, maxHealth: 20, rotation: 0, acts: true }
{id: 'Tree 1', spriteName: 'Tree 1', exists: true, pos: {x:4, 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
thangTypes = [treeThangType, ogreMunchkinThangType, ogreFangriderThangType]
ogreMunchkinThangType.set('renderStrategy', 'container')
ogreFangriderThangType.set('renderStrategy', 'container')
treeThangType.set('renderStrategy', 'container')
window.stage = stage = new createjs.Stage(canvas[0])
options = {
camera: camera
surfaceLayer: stage
surfaceTextLayer: new createjs.Container()
world: world
thangTypes: thangTypes
}
window.spriteBoss = spriteBoss = new SpriteBoss(options)
defaultLayer = spriteBoss.spriteLayers.Default
defaultLayer.buildAsync = false # cause faster
spriteBoss.update(true)
defaultLayer.once 'new-spritesheet', -> done()
# showMe()
beforeEach (done) -> init(done)
showMe = ->
canvas.css('position', 'absolute').css('index', 1000).css('background', 'white')
$('body').append(canvas)
ticks = 0
listener = {
handleEvent: ->
return if ticks >= 100
ticks += 1
console.log 'update'
stage.update()
}
createjs.Ticker.addEventListener "tick", listener
$('body').append($('<div style="position: absolute; top: 295px; left: 395px; height: 10px; width: 10px; background: red;"></div>'))
it 'rotates and animates sprites according to thang rotation', ->
expect(spriteBoss.sprites['Ogre N'].imageObject.currentAnimation).toBe('move_fore')
expect(spriteBoss.sprites['Ogre E'].imageObject.currentAnimation).toBe('move_side')
expect(spriteBoss.sprites['Ogre W'].imageObject.currentAnimation).toBe('move_side')
expect(spriteBoss.sprites['Ogre S'].imageObject.currentAnimation).toBe('move_back')
expect(spriteBoss.sprites['Ogre E'].imageObject.scaleX).toBeLessThan(0)
expect(spriteBoss.sprites['Ogre W'].imageObject.scaleX).toBeGreaterThan(0)
it 'positions sprites according to thang pos', ->
expect(spriteBoss.sprites['Ogre N'].imageObject.x).toBe(0)
expect(spriteBoss.sprites['Ogre N'].imageObject.y).toBeCloseTo(-60)
expect(spriteBoss.sprites['Ogre E'].imageObject.x).toBeCloseTo(80)
expect(spriteBoss.sprites['Ogre E'].imageObject.y).toBe(0)
expect(spriteBoss.sprites['Ogre W'].imageObject.x).toBe(-80)
expect(spriteBoss.sprites['Ogre W'].imageObject.y).toBeCloseTo(0)
expect(spriteBoss.sprites['Ogre S'].imageObject.x).toBe(0)
expect(spriteBoss.sprites['Ogre S'].imageObject.y).toBeCloseTo(60)
it 'scales sprites according to thang scaleFactorX and scaleFactorY', ->
expect(spriteBoss.sprites['Ogre N'].imageObject.scaleX).toBe(spriteBoss.sprites['Ogre N'].baseScaleX * 2)
expect(spriteBoss.sprites['Ogre W'].imageObject.scaleY).toBe(spriteBoss.sprites['Ogre N'].baseScaleY * 2)
it 'sets alpha based on thang alpha', ->
expect(spriteBoss.sprites['Ogre E'].imageObject.alpha).toBe(0.5)
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'))
expect(i1).toBeGreaterThan(i2)
expect(i2).toBeGreaterThan(i3)
expect(i3).toBeGreaterThan(i4)

View file

@ -19,9 +19,9 @@ describe 'WebGLSprite', ->
listener = {
handleEvent: ->
return if ticks >= 100
ticks += 1
webGLSprite.tick(arguments[0].delta)
stage.update()
ticks += 1
}
createjs.Ticker.addEventListener "tick", listener
@ -57,10 +57,6 @@ describe 'WebGLSprite', ->
webGLSprite.gotoAndStop('move_fore')
expect(webGLSprite.paused).toBe(true)
it 'is paused when the action is a single frame', ->
webGLSprite.gotoAndPlay('idle')
expect(webGLSprite.paused).toBe(true)
it 'has a tick function which moves the animation forward', ->
webGLSprite.gotoAndPlay('attack')
webGLSprite.tick(100) # one hundred milliseconds
@ -108,8 +104,21 @@ describe 'WebGLSprite', ->
webGLSprite.tick(100) # one hundred milliseconds
expectedFrame = webGLSprite.framerate*100/1000
expect(webGLSprite.currentFrame).toBe(expectedFrame)
for child in webGLSprite.childSpriteContainers
expect(child.movieClip.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 ->
@ -138,5 +147,4 @@ describe 'WebGLSprite', ->
it 'has the same interface as for when the ThangType uses the container renderStrategy', ->
webGLSprite.gotoAndPlay('move_fore')
webGLSprite.gotoAndStop('attack')
showMe()
webGLSprite.gotoAndStop('attack')