mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-12-03 12:27:19 -05:00
WebGLLayer now recycles previous sprite sheets, speeding up rendering additional thang types or animations.
This commit is contained in:
parent
cc76458942
commit
a99cdfb957
3 changed files with 78 additions and 8 deletions
|
@ -34,7 +34,6 @@ layerProperties = {
|
|||
@layerPriority = options.layerPriority ? 0
|
||||
@transformStyle = options.transform ? layerClassProperties.TRANSFORM_CHILD
|
||||
@camera = options.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
|
||||
|
|
|
@ -146,6 +146,7 @@ module.exports = class WebGLLayer extends CocoClass
|
|||
return
|
||||
|
||||
@spriteSheet = builder.spriteSheet
|
||||
@spriteSheet.resolutionFactor = @resolutionFactor
|
||||
oldLayer = @spriteContainer
|
||||
@spriteContainer = new SpriteContainerLayer(@spriteSheet, @layerOptions)
|
||||
for cocoSprite in @cocoSprites
|
||||
|
@ -178,8 +179,13 @@ module.exports = class WebGLLayer extends CocoClass
|
|||
spriteBuilder = new SpriteBuilder(thangType, {colorConfig: colorConfig})
|
||||
for containerGlobalName in _.keys(containersToRender)
|
||||
containerKey = @renderGroupingKey(thangType, containerGlobalName, colorConfig)
|
||||
container = spriteBuilder.buildContainerFromStore(containerGlobalName)
|
||||
frame = spriteSheetBuilder.addFrame(container, null, @resolutionFactor * (thangType.get('scale') or 1))
|
||||
if @spriteSheet?.resolutionFactor is @resolutionFactor and containerKey in @spriteSheet.getAnimations()
|
||||
container = new createjs.Sprite(@spriteSheet)
|
||||
container.gotoAndStop(containerKey)
|
||||
frame = spriteSheetBuilder.addFrame(container)
|
||||
else
|
||||
container = spriteBuilder.buildContainerFromStore(containerGlobalName)
|
||||
frame = spriteSheetBuilder.addFrame(container, null, @resolutionFactor * (thangType.get('scale') or 1))
|
||||
spriteSheetBuilder.addAnimation(containerKey, [frame], false)
|
||||
|
||||
getContainersForAnimation: (thangType, animation) ->
|
||||
|
@ -202,6 +208,22 @@ module.exports = class WebGLLayer extends CocoClass
|
|||
for animationName, actions of animationGroups
|
||||
renderAll = _.any actions, (action) -> action.frames is undefined
|
||||
scale = actions[0].scale or thangType.get('scale') or 1
|
||||
|
||||
actionKeys = (@renderGroupingKey(thangType, action.name, colorConfig) for action in actions)
|
||||
if @spriteSheet?.resolutionFactor is @resolutionFactor and _.all(actionKeys, (key) => key in @spriteSheet.getAnimations())
|
||||
framesNeeded = _.uniq(_.flatten((@spriteSheet.getAnimation(key)).frames for key in actionKeys))
|
||||
framesMap = {}
|
||||
for frame in framesNeeded
|
||||
sprite = new createjs.Sprite(@spriteSheet)
|
||||
sprite.gotoAndStop(frame)
|
||||
framesMap[frame] = spriteSheetBuilder.addFrame(sprite)
|
||||
for key, index in actionKeys
|
||||
action = actions[index]
|
||||
frames = (framesMap[f] for f in @spriteSheet.getAnimation(key).frames)
|
||||
next = @nextForAction(action)
|
||||
spriteSheetBuilder.addAnimation(key, frames, next)
|
||||
continue
|
||||
|
||||
mc = spriteBuilder.buildMovieClip(animationName, null, null, null, {'temp':0})
|
||||
|
||||
if renderAll
|
||||
|
@ -223,11 +245,7 @@ module.exports = class WebGLLayer extends CocoClass
|
|||
frames = (framesMap[parseInt(frame)] for frame in action.frames.split(','))
|
||||
else
|
||||
frames = _.values(framesMap).sort()
|
||||
|
||||
next = true
|
||||
next = action.goesTo if action.goesTo
|
||||
next = false if action.loops is false
|
||||
|
||||
next = @nextForAction(action)
|
||||
spriteSheetBuilder.addAnimation(name, frames, next)
|
||||
|
||||
containerActions = []
|
||||
|
@ -245,6 +263,12 @@ module.exports = class WebGLLayer extends CocoClass
|
|||
name = @renderGroupingKey(thangType, action.name, colorConfig)
|
||||
spriteSheetBuilder.addAnimation(name, [frame], false)
|
||||
|
||||
nextForAction: (action) ->
|
||||
next = true
|
||||
next = action.goesTo if action.goesTo
|
||||
next = false if action.loops is false
|
||||
return next
|
||||
|
||||
renderRasterImage: (thangType, spriteSheetBuilder) ->
|
||||
unless thangType.rasterImage
|
||||
console.error("Cannot render the WebGLLayer SpriteSheet until the raster image for <#{thangType.get('name')}> is loaded.")
|
||||
|
|
|
@ -3,6 +3,7 @@ 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')
|
||||
SpriteBuilder = require 'lib/sprites/SpriteBuilder'
|
||||
|
||||
describe 'WebGLLayer', ->
|
||||
layer = null
|
||||
|
@ -118,3 +119,49 @@ describe 'WebGLLayer', ->
|
|||
thangType2.trigger('raster-image-loaded', thangType2)
|
||||
expect(layer.numThingsLoading).toBe(0)
|
||||
expect(layer._renderNewSpriteSheet).toHaveBeenCalled()
|
||||
|
||||
it 'recycles *containers* from previous sprite sheets, rather than building repeatedly from raw vector data', ->
|
||||
treeThangType.set('renderStrategy', 'container')
|
||||
sprite = new CocoSprite(treeThangType)
|
||||
layer.addCocoSprite(sprite)
|
||||
spyOn(SpriteBuilder.prototype, 'buildContainerFromStore').and.callThrough()
|
||||
for i in _.range(2)
|
||||
sheet = layer.renderNewSpriteSheet()
|
||||
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')
|
||||
sprite = new CocoSprite(treeThangType)
|
||||
layer.addCocoSprite(sprite)
|
||||
spyOn(SpriteBuilder.prototype, 'buildContainerFromStore').and.callThrough()
|
||||
for i in _.range(2)
|
||||
layer.resolutionFactor *= 1.1
|
||||
sheet = layer.renderNewSpriteSheet()
|
||||
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')
|
||||
sprite = new CocoSprite(ogreMunchkinThangType)
|
||||
layer.addCocoSprite(sprite)
|
||||
numFrameses = []
|
||||
spyOn(SpriteBuilder.prototype, 'buildMovieClip').and.callThrough()
|
||||
for i in _.range(2)
|
||||
sheet = layer.renderNewSpriteSheet()
|
||||
numFrameses.push(sheet.getNumFrames())
|
||||
|
||||
# this process should not have created any new frames
|
||||
expect(numFrameses[0]).toBe(numFrameses[1])
|
||||
|
||||
# one movie clip made for each raw animation: move (3), attack, die
|
||||
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')
|
||||
sprite = new CocoSprite(ogreMunchkinThangType)
|
||||
layer.addCocoSprite(sprite)
|
||||
spyOn(SpriteBuilder.prototype, 'buildMovieClip').and.callThrough()
|
||||
for i in _.range(2)
|
||||
layer.resolutionFactor *= 1.1
|
||||
sheet = layer.renderNewSpriteSheet()
|
||||
|
||||
expect(SpriteBuilder.prototype.buildMovieClip.calls.count()).toBe(10)
|
Loading…
Reference in a new issue