Big performance improvements for scrubbing between frames; look out for bugs.

This commit is contained in:
Nick Winter 2014-02-28 11:27:32 -08:00
parent e20e9d68cf
commit 3cee341887

View file

@ -100,7 +100,7 @@ module.exports = Surface = class Surface extends CocoClass
@stage.removeAllEventListeners()
@stage.enableDOMEvents false
@stage.enableMouseOver 0
@playScrubbedSounds = null
@onFramesScrubbed = null
@onMouseMove = null
@onMouseDown = null
@tick = null
@ -202,32 +202,33 @@ module.exports = Surface = class Surface extends CocoClass
.get(@)
.to({currentFrame:@scrubbingTo}, scrubDuration, createjs.Ease.sineInOut)
.call(onTweenEnd)
t.addEventListener('change', @playScrubbedSounds)
t.addEventListener('change', @onFramesScrubbed)
else
@currentFrame = @scrubbingTo
@playScrubbedSounds()
@onFramesScrubbed() # For performance, don't play these for instant transitions.
onTweenEnd()
@updateState true
@onFrameChanged()
playScrubbedSounds: (e) =>
# gotta play all the sounds, even when scrubbing!
rising = @currentFrame > @lastFrame
actualCurrentFrame = @currentFrame
tempFrame = if rising then Math.ceil(@lastFrame) else Math.floor(@lastFrame)
while true # temporary fix to stop cacophony
break if rising and tempFrame > actualCurrentFrame
break if (not rising) and tempFrame < actualCurrentFrame
@currentFrame = tempFrame
frame = @world.getFrame(@getCurrentFrame())
frame.restoreState()
for thangID, sprite of @spriteBoss.sprites
sprite.playSounds false, Math.max(0.05, Math.min(1, 1 / @scrubbingPlaybackSpeed))
tempFrame += if rising then 1 else -1
@currentFrame = actualCurrentFrame
onFramesScrubbed: (e) =>
if e
# Gotta play all the sounds when scrubbing (but not when doing an immediate transition).
rising = @currentFrame > @lastFrame
actualCurrentFrame = @currentFrame
tempFrame = if rising then Math.ceil(@lastFrame) else Math.floor(@lastFrame)
while true # temporary fix to stop cacophony
break if rising and tempFrame > actualCurrentFrame
break if (not rising) and tempFrame < actualCurrentFrame
@currentFrame = tempFrame
frame = @world.getFrame(@getCurrentFrame())
frame.restoreState()
for thangID, sprite of @spriteBoss.sprites
sprite.playSounds false, Math.max(0.05, Math.min(1, 1 / @scrubbingPlaybackSpeed))
tempFrame += if rising then 1 else -1
@currentFrame = actualCurrentFrame
# TODO: are these needed, or perhaps do they duplicate things?
@restoreWorldState()
@spriteBoss.update true
@onFrameChanged()
@ -325,7 +326,7 @@ module.exports = Surface = class Surface extends CocoClass
onNewWorld: (event) ->
return unless event.world.name is @world.name
@casting = false
# This has a tendency to break scripts that are waiting for playback to change when the level is loaded
# so only run it after the first world is created.
Backbone.Mediator.publish 'level-set-playing', { playing: @wasPlayingWhenCastingBegan } unless event.firstWorld
@ -493,14 +494,23 @@ module.exports = Surface = class Surface extends CocoClass
tick: (e) =>
# seems to be a bug where only one object can register with the Ticker...
oldFrame = @currentFrame
oldWorldFrame = Math.floor oldFrame
while true
Dropper.tick()
@trailmaster.tick() if @trailmaster
# Skip some frame updates unless we're playing and not at end (or we haven't drawn much yet)
frameAdvanced = (@playing and @currentFrame < @world.totalFrames) or @totalFramesDrawn < 2
@currentFrame += @world.frameRate / @frameRate if frameAdvanced
@updateSpriteSounds() if frameAdvanced
newWorldFrame = Math.floor @currentFrame
worldFrameAdvanced = newWorldFrame isnt oldWorldFrame
if worldFrameAdvanced
# Only restore world state when it will correspond to an integer WorldFrame, not interpolated frame.
@restoreWorldState()
oldWorldFrame = newWorldFrame
break unless Dropper.drop()
if frameAdvanced and not worldFrameAdvanced
# We didn't end the above loop on an integer frame, so do the world state update.
@restoreWorldState()
# these are skipped for dropped frames
@updateState @currentFrame isnt oldFrame
@ -513,7 +523,7 @@ module.exports = Surface = class Surface extends CocoClass
Backbone.Mediator.publish('surface:mouse-' + (if mib then "over" else "out"), {})
@mouseInBounds = mib
updateSpriteSounds: ->
restoreWorldState: ->
@world.getFrame(@getCurrentFrame()).restoreState()
current = Math.max(0, Math.min(@currentFrame, @world.totalFrames - 1))
if current - Math.floor(current) > 0.01
@ -523,7 +533,7 @@ module.exports = Surface = class Surface extends CocoClass
@spriteBoss.updateSounds()
updateState: (frameChanged) ->
# world state must have been restored in @updateSpriteSounds
# world state must have been restored in @restoreWorldState
@camera.updateZoom()
@spriteBoss.update frameChanged unless @casting
@dimmer?.setSprites @spriteBoss.sprites