mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 15:48:11 -05:00
Built most of the WebGLSprite.
This commit is contained in:
parent
c96f5d7bcf
commit
a633f6f82f
4 changed files with 221 additions and 2 deletions
|
@ -77,7 +77,7 @@ module.exports = class SpriteBuilder
|
||||||
buildMovieClipAnimations: (localAnimations) ->
|
buildMovieClipAnimations: (localAnimations) ->
|
||||||
map = {}
|
map = {}
|
||||||
for localAnimation in localAnimations
|
for localAnimation in localAnimations
|
||||||
animation = @buildMovieClip(localAnimation.gn, localAnimation.a)
|
animation = @buildMovieClip(localAnimation.gn, localAnimation.a...)
|
||||||
animation.setTransform(localAnimation.t...)
|
animation.setTransform(localAnimation.t...)
|
||||||
map[localAnimation.bn] = animation
|
map[localAnimation.bn] = animation
|
||||||
map
|
map
|
||||||
|
|
|
@ -11,7 +11,6 @@ module.exports = class WebGLLayer extends createjs.SpriteContainer
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super(arguments...)
|
super(arguments...)
|
||||||
@spriteSheetBuilder = new createjs.SpriteSheetBuilder()
|
|
||||||
@actionRenderState = {}
|
@actionRenderState = {}
|
||||||
@toRenderBundles = []
|
@toRenderBundles = []
|
||||||
@initialize(arguments...)
|
@initialize(arguments...)
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
SpriteBuilder = require 'lib/sprites/SpriteBuilder'
|
||||||
|
|
||||||
|
module.exports = class WebGLSprite extends createjs.SpriteContainer
|
||||||
|
constructor: (@spriteSheet, @thangType, @spriteSheetPrefix) ->
|
||||||
|
@initialize(@spriteSheet)
|
||||||
|
|
||||||
|
gotoAndPlay: (actionName) -> @goto(actionName, false)
|
||||||
|
gotoAndStop: (actionName) -> @goto(actionName, true)
|
||||||
|
|
||||||
|
goto: (actionName, @paused=true) ->
|
||||||
|
@currentAnimation = actionName
|
||||||
|
action = @thangType.getActions()[actionName]
|
||||||
|
if action.animation
|
||||||
|
@baseMovieClip = @buildMovieClip(action.animation)
|
||||||
|
@mirrorMovieClip(@baseMovieClip, @)
|
||||||
|
@framerate = (action.framerate ? 20) * (action.speed ? 1)
|
||||||
|
@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
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
mirrorMovieClip: (movieClip, spriteContainer) ->
|
||||||
|
movieClips = []
|
||||||
|
spriteContainer.children = movieClip.children
|
||||||
|
for child, index in spriteContainer.children
|
||||||
|
if child instanceof createjs.MovieClip
|
||||||
|
movieClips.push(child)
|
||||||
|
childMovieClip = child
|
||||||
|
childSpriteContainer = new createjs.SpriteContainer(@spriteSheet)
|
||||||
|
spriteContainer.children[index] = childSpriteContainer
|
||||||
|
movieClips = movieClips.concat(@mirrorMovieClip(childMovieClip, childSpriteContainer))
|
||||||
|
return movieClips
|
||||||
|
|
||||||
|
buildMovieClip: (animationName, mode, startPosition, loops) ->
|
||||||
|
raw = @thangType.get('raw')
|
||||||
|
animData = raw.animations[animationName]
|
||||||
|
movieClip = new createjs.MovieClip()
|
||||||
|
|
||||||
|
locals = {}
|
||||||
|
_.extend locals, @buildMovieClipContainers(animData.containers)
|
||||||
|
_.extend locals, @buildMovieClipAnimations(animData.animations)
|
||||||
|
|
||||||
|
anim = new createjs.MovieClip()
|
||||||
|
anim.initialize(mode ? createjs.MovieClip.INDEPENDENT, startPosition ? 0, loops ? true)
|
||||||
|
|
||||||
|
for tweenData in animData.tweens
|
||||||
|
stopped = false
|
||||||
|
tween = createjs.Tween
|
||||||
|
for func in tweenData
|
||||||
|
args = $.extend(true, [], (func.a))
|
||||||
|
args = @dereferenceArgs(args, locals)
|
||||||
|
if args is false
|
||||||
|
console.log 'could not dereference args', args
|
||||||
|
stopped = true
|
||||||
|
break
|
||||||
|
tween = tween[func.n](args...)
|
||||||
|
continue if stopped
|
||||||
|
anim.timeline.addTween(tween)
|
||||||
|
|
||||||
|
anim.nominalBounds = new createjs.Rectangle(animData.bounds...)
|
||||||
|
if animData.frameBounds
|
||||||
|
anim.frameBounds = (new createjs.Rectangle(bounds...) for bounds in animData.frameBounds)
|
||||||
|
return anim
|
||||||
|
|
||||||
|
buildMovieClipContainers: (localContainers) ->
|
||||||
|
map = {}
|
||||||
|
for localContainer in localContainers
|
||||||
|
container = new createjs.Sprite(@spriteSheet)
|
||||||
|
container.gotoAndStop(@spriteSheetPrefix + localContainer.gn)
|
||||||
|
container.setTransform(localContainer.t...)
|
||||||
|
container._off = localContainer.o if localContainer.o?
|
||||||
|
container.alpha = localContainer.al if localContainer.al?
|
||||||
|
map[localContainer.bn] = container
|
||||||
|
return map
|
||||||
|
|
||||||
|
buildMovieClipAnimations: (localAnimations) ->
|
||||||
|
map = {}
|
||||||
|
for localAnimation in localAnimations
|
||||||
|
animation = @buildMovieClip(localAnimation.gn, localAnimation.a...)
|
||||||
|
animation.setTransform(localAnimation.t...)
|
||||||
|
map[localAnimation.bn] = animation
|
||||||
|
return map
|
||||||
|
|
||||||
|
dereferenceArgs: (args, locals) ->
|
||||||
|
for key, val of args
|
||||||
|
if locals[val]
|
||||||
|
args[key] = locals[val]
|
||||||
|
else if val is null
|
||||||
|
args[key] = {}
|
||||||
|
else if _.isString(val) and val.indexOf('createjs.') is 0
|
||||||
|
args[key] = eval(val) # TODO: Security risk
|
||||||
|
else if _.isObject(val) or _.isArray(val)
|
||||||
|
res = @dereferenceArgs(val, locals)
|
||||||
|
return res if res is false
|
||||||
|
else if _.isString(val)
|
||||||
|
return false
|
||||||
|
return args
|
||||||
|
|
||||||
|
tick: (delta) ->
|
||||||
|
return unless @framerate and not @paused
|
||||||
|
newFrame = @currentFrame + @framerate * delta / 1000
|
||||||
|
|
||||||
|
if newFrame > @animLength
|
||||||
|
if @goesTo
|
||||||
|
@gotoAndPlay(@goesTo)
|
||||||
|
return
|
||||||
|
else if not @loop
|
||||||
|
@paused = false
|
||||||
|
newFrame = @animLength - 1
|
||||||
|
@dispatchEvent('animationend')
|
||||||
|
else
|
||||||
|
newFrame = newFrame % @animLength
|
||||||
|
|
||||||
|
if @frames
|
||||||
|
prevFrame = Math.floor(newFrame)
|
||||||
|
nextFrame = Math.ceil(newFrame)
|
||||||
|
if prevFrame is nextFrame
|
||||||
|
@baseMovieClip.gotoAndStop(@frames[newFrame])
|
||||||
|
else if nextFrame is @frames.length
|
||||||
|
@baseMovieClip.gotoAndStop(@frames[prevFrame])
|
||||||
|
else
|
||||||
|
# interpolate between frames
|
||||||
|
pct = newFrame % 1
|
||||||
|
newFrameIndex = @frames[prevFrame] + (pct * (@frames[nextFrame] - @frames[prevFrame]))
|
||||||
|
@baseMovieClip.gotoAndStop(newFrameIndex)
|
||||||
|
else
|
||||||
|
@baseMovieClip.gotoAndStop(newFrame)
|
||||||
|
|
||||||
|
@currentFrame = newFrame
|
||||||
|
|
||||||
|
getBounds: ->
|
||||||
|
@baseMovieClip.getBounds()
|
79
test/app/lib/surface/WebGLSprite.spec.coffee
Normal file
79
test/app/lib/surface/WebGLSprite.spec.coffee
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
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')
|
||||||
|
|
||||||
|
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
|
||||||
|
webGLSprite.tick(arguments[0].delta)
|
||||||
|
stage.update()
|
||||||
|
ticks += 1
|
||||||
|
}
|
||||||
|
createjs.Ticker.addEventListener "tick", listener
|
||||||
|
|
||||||
|
beforeEach ->
|
||||||
|
layer = new WebGLLayer()
|
||||||
|
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)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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('move_fore')
|
||||||
|
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)
|
Loading…
Reference in a new issue