From 3c9b40e8f43e8ff80ef283fa7999f89e30a5db0f Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Fri, 19 Sep 2014 13:50:14 -0700 Subject: [PATCH] Set up placeholders for when WebGLSprites don't have their raw data built yet. Not finished yet because of scaling, but will come back to it... Got some refactoring to do first. --- app/application.coffee | 1 + app/lib/surface/WebGLLayer.coffee | 24 +++++-- app/lib/surface/WebGLSprite.coffee | 74 ++++++++++++-------- test/app/lib/surface/SpriteBoss.spec.coffee | 10 ++- test/app/lib/surface/WebGLSprite.spec.coffee | 1 + 5 files changed, 74 insertions(+), 36 deletions(-) diff --git a/app/application.coffee b/app/application.coffee index 549d1822c..abe2df04f 100644 --- a/app/application.coffee +++ b/app/application.coffee @@ -11,6 +11,7 @@ marked.setOptions {gfm: true, sanitize: true, smartLists: true, breaks: false} # TODO, add C-style macro constants like this? window.SPRITE_RESOLUTION_FACTOR = 3 +window.SPRITE_PLACEHOLDER_RADIUS = 30 # Prevent Ctrl/Cmd + [ / ], P, S ctrlDefaultPrevented = [219, 221, 80, 83] diff --git a/app/lib/surface/WebGLLayer.coffee b/app/lib/surface/WebGLLayer.coffee index 32f5098e2..97a71611c 100644 --- a/app/lib/surface/WebGLLayer.coffee +++ b/app/lib/surface/WebGLLayer.coffee @@ -3,6 +3,8 @@ CocoClass = require 'lib/CocoClass' WebGLSprite = require './WebGLSprite' {SpriteContainerLayer} = require 'lib/surface/Layer' +NEVER_RENDER_ANYTHING = true # set to true to test placeholders + module.exports = class WebGLLayer extends CocoClass _.extend(WebGLLayer.prototype, Backbone.Events) @@ -109,12 +111,13 @@ module.exports = class WebGLLayer extends CocoClass builder = new createjs.SpriteSheetBuilder() groups = _.groupBy(@toRenderBundles, ((bundle) -> @renderGroupingKey(bundle.thangType, '', bundle.colorConfig)), @) - # Always have an empty frame be the first frame. - # Then if you go to a frame that DNE, it doesn't show up. - emptiness = new createjs.Container() - emptiness.setBounds(0, 0, 1, 1) - builder.addFrame(emptiness) + # The first frame is always the 'loading', ie placeholder, image. + placeholder = @createPlaceholder() + dimension = @resolutionFactor*SPRITE_PLACEHOLDER_RADIUS*2 + placeholder.setBounds(0, 0, dimension, dimension) + builder.addFrame(placeholder) + groups = {} if NEVER_RENDER_ANYTHING for bundleGrouping in _.values(groups) thangType = bundleGrouping[0].thangType colorConfig = bundleGrouping[0].colorConfig @@ -135,6 +138,17 @@ module.exports = class WebGLLayer extends CocoClass sheet = builder.build() @onBuildSpriteSheetComplete(null, builder) return sheet + + createPlaceholder: -> + # TODO: Experiment with this. Perhaps have rectangles if default layer is obstacle or floor, + # and different colors for different layers. + g = new createjs.Graphics() + g.setStrokeStyle(5) + g.beginStroke(createjs.Graphics.getRGB(64,64,64)) + g.beginFill(createjs.Graphics.getRGB(64,64,64,0.7)) + radius = @resolutionFactor*SPRITE_PLACEHOLDER_RADIUS + g.drawCircle(radius, radius, radius) + new createjs.Shape(g) onBuildSpriteSheetComplete: (e, builder) -> return if @initializing diff --git a/app/lib/surface/WebGLSprite.coffee b/app/lib/surface/WebGLSprite.coffee index 6a7cdf318..1c7b354ff 100644 --- a/app/lib/surface/WebGLSprite.coffee +++ b/app/lib/surface/WebGLSprite.coffee @@ -33,6 +33,7 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer goto: (actionName, @paused=true) -> @currentAnimation = actionName @baseMovieClip = @framerate = null + @actionNotSupported = false action = @thangType.getActions()[actionName] randomStart = actionName.startsWith('move') @@ -47,13 +48,21 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer @regY = -reg.y * scale func = if @paused then 'gotoAndStop' else 'gotoAndPlay' animationName = @spriteSheetPrefix + actionName - if not (animationName in @spriteSheet.getAnimations()) - @singleChildSprite.gotoAndStop(0) - @notifyActionNeedsRender(action) - return @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) @@ -62,10 +71,6 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer @regY = -reg.y @childMovieClips = [] @baseMovieClip = @buildMovieClip(action.animation) - if not @baseMovieClip - @children = [] - @notifyActionNeedsRender(action) - return @children = @baseMovieClip.children @frames = action.frames @frames = (parseInt(f) for f in @frames.split(',')) if @frames @@ -74,31 +79,41 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer @baseMovieClip.gotoAndStop(@currentFrame) @loop = action.loops isnt false @goesTo = action.goesTo + @notifyActionNeedsRender(action) if @actionNotSupported if action.container + scale = @resolutionFactor * (action.scale ? @thangType.get('scale') ? 1) + if @singleChildSprite - scale = @resolutionFactor * (action.scale ? @thangType.get('scale') ? 1) @regX = -reg.x * scale @regY = -reg.y * scale animationName = @spriteSheetPrefix + actionName - if not (animationName in @spriteSheet.getAnimations()) - @singleChildSprite.gotoAndStop(0) - @notifyActionNeedsRender(action) - return @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 else @regX = -reg.x @regY = -reg.y @childMovieClips = [] containerName = @spriteSheetPrefix + action.container - if not (containerName in @spriteSheet.getAnimations()) - @children = [] - @notifyActionNeedsRender(action) - return sprite = new createjs.Sprite(@spriteSheet) sprite.gotoAndStop(containerName) - sprite.scaleX = sprite.scaleY = 1 / @resolutionFactor + 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] return @@ -112,10 +127,8 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer movieClip = new createjs.MovieClip() locals = {} - _.extend locals, containers = @buildMovieClipContainers(animData.containers) - return false if not containers - _.extend locals, animations = @buildMovieClipAnimations(animData.animations) - return false if not animations + _.extend locals, @buildMovieClipContainers(animData.containers) + _.extend locals, @buildMovieClipAnimations(animData.animations) toSkip = {} toSkip[shape.bn] = true for shape in animData.shapes @@ -147,10 +160,16 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer for localContainer in localContainers outerContainer = new createjs.SpriteContainer(@spriteSheet) innerContainer = new createjs.Sprite(@spriteSheet) - innerContainer.scaleX = innerContainer.scaleY = 1 / (@resolutionFactor * (@thangType.get('scale') or 1)) - animationName = @spriteSheetPrefix + localContainer.gn - return false if not (animationName in @spriteSheet.getAnimations()) - innerContainer.gotoAndStop(animationName) + innerContainer.gotoAndStop(@spriteSheetPrefix + localContainer.gn) + if innerContainer.currentFrame is 0 + @actionNotSupported = true + bounds = @thangType.get('raw').containers[localContainer.gn].b + innerContainer.x = bounds[0] + innerContainer.y = bounds[1] + innerContainer.scaleX = bounds[2] / (SPRITE_PLACEHOLDER_RADIUS * @resolutionFactor * 2) + innerContainer.scaleY = bounds[3] / (SPRITE_PLACEHOLDER_RADIUS * @resolutionFactor * 2) + else + innerContainer.scaleX = innerContainer.scaleY = 1 / (@resolutionFactor * (@thangType.get('scale') or 1)) outerContainer.addChild(innerContainer) outerContainer.setTransform(localContainer.t...) outerContainer._off = localContainer.o if localContainer.o? @@ -162,7 +181,6 @@ module.exports = class WebGLSprite extends createjs.SpriteContainer map = {} for localAnimation in localAnimations animation = @buildMovieClip(localAnimation.gn, localAnimation.a...) - return false if not animation animation.setTransform(localAnimation.t...) map[localAnimation.bn] = animation @childMovieClips.push(animation) diff --git a/test/app/lib/surface/SpriteBoss.spec.coffee b/test/app/lib/surface/SpriteBoss.spec.coffee index 98663b5c3..82fcb6904 100644 --- a/test/app/lib/surface/SpriteBoss.spec.coffee +++ b/test/app/lib/surface/SpriteBoss.spec.coffee @@ -69,7 +69,9 @@ describe 'SpriteBoss', -> spriteBoss.update(true) # Test that the unrendered, static sprites aren't showing anything - midRenderExpectations.push([spriteBoss.sprites['Tree 1'].imageObject.children.length,0,'static container action']) + 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']) @@ -102,13 +104,15 @@ describe 'SpriteBoss', -> spriteBoss.update(true) # Test that the unrendered, animated sprites aren't showing anything - midRenderExpectations.push([spriteBoss.sprites['NotFROgre'].imageObject.children.length,0,'animated container action']) + 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']) defaultLayer.once 'new-spritesheet', -> + showMe() # Uncomment to display this world when you run any of these tests. done() -# showMe() # Uncomment to display this world when you run any of these tests. beforeEach (done) -> init(done) diff --git a/test/app/lib/surface/WebGLSprite.spec.coffee b/test/app/lib/surface/WebGLSprite.spec.coffee index e239d6067..72b34bc72 100644 --- a/test/app/lib/surface/WebGLSprite.spec.coffee +++ b/test/app/lib/surface/WebGLSprite.spec.coffee @@ -56,6 +56,7 @@ describe 'WebGLSprite', -> 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')