60 FPS and support for independent world/surface frame rates.

This commit is contained in:
Nick Winter 2014-02-17 11:53:52 -08:00
parent 1b0f15b5f3
commit af510c7cc7
6 changed files with 46 additions and 15 deletions

View file

@ -210,8 +210,11 @@ class Angel
@purgatoryTimer = null
if @worker
worker = @worker
_.defer -> worker.terminate()
@worker.removeEventListener 'message', @onWorkerMessage
onWorkerMessage = @onWorkerMessage
_.delay ->
worker.terminate()
worker.removeEventListener 'message', onWorkerMessage
, 1000
@worker = null
@

View file

@ -98,7 +98,7 @@ module.exports = class LevelLoader extends CocoClass
onSupermodelError: ->
msg = $.i18n.t('play_level.level_load_error',
defaultValue: "Level could not be loaded.")
@$el.html('<div class="alert">' + msg + '</div>')
$('body').append('<div class="alert">' + msg + '</div>')
onSupermodelLoadedOne: (e) ->
@update()

View file

@ -140,8 +140,8 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
@show()
return @updateActionDirection() unless action.animation or action.container
m = if action.container then "gotoAndStop" else "gotoAndPlay"
@imageObject[m] action.name
@imageObject.framerate = action.framerate or 20
@imageObject[m] action.name
reg = @getOffset 'registration'
@imageObject.regX = -reg.x
@imageObject.regY = -reg.y

View file

@ -36,6 +36,7 @@ module.exports = Surface = class Surface extends CocoClass
worldLoaded: false
scrubbing: false
debug: false
frameRate: 60
defaults:
wizards: true
@ -190,7 +191,7 @@ module.exports = Surface = class Surface extends CocoClass
createjs.Tween.removeTweens(@)
@currentFrame = @scrubbingTo
@scrubbingTo = parseInt(progress * @world.totalFrames)
@scrubbingTo = Math.floor(progress * @world.totalFrames)
@scrubbingPlaybackSpeed = Math.sqrt(Math.abs(@scrubbingTo - @currentFrame) * @world.dt / (scrubDuration or 0.5))
if scrubDuration
t = createjs.Tween
@ -227,7 +228,7 @@ module.exports = Surface = class Surface extends CocoClass
@onFrameChanged()
getCurrentFrame: ->
return Math.max(0, Math.min(parseInt(@currentFrame), @world.totalFrames - 1))
return Math.max(0, Math.min(Math.floor(@currentFrame), @world.totalFrames - 1))
getProgress: -> @currentFrame / @world.totalFrames
@ -344,8 +345,7 @@ module.exports = Surface = class Surface extends CocoClass
@stage.addEventListener 'stagemousedown', @onMouseDown
@canvas.on 'mousewheel', @onMouseWheel
@hookUpChooseControls() if @options.choosing
console.log "Setting fps", @world.frameRate unless @world.frameRate is 30
createjs.Ticker.setFPS @world.frameRate
createjs.Ticker.setFPS @frameRate
showLevel: ->
return if @dead
@ -467,16 +467,16 @@ module.exports = Surface = class Surface extends CocoClass
@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 if frameAdvanced
@currentFrame += @world.frameRate / @frameRate if frameAdvanced
@updateSpriteSounds() if frameAdvanced
break unless Dropper.drop()
# these are skipped for dropped frames
@updateState @currentFrame isnt oldFrame
@drawCurrentFrame()
@drawCurrentFrame e
@onFrameChanged()
@updatePaths() if (@totalFramesDrawn % 2) is 0 or createjs.Ticker.getMeasuredFPS() > createjs.Ticker.getFPS() - 5
Backbone.Mediator.publish('surface:ticked', {dt: @world.dt})
@updatePaths() if (@totalFramesDrawn % 4) is 0 or createjs.Ticker.getMeasuredFPS() > createjs.Ticker.getFPS() - 5
Backbone.Mediator.publish('surface:ticked', {dt: 1 / @frameRate})
mib = @stage.mouseInBounds
if @mouseInBounds isnt mib
Backbone.Mediator.publish('surface:mouse-' + (if mib then "over" else "out"), {})
@ -484,6 +484,11 @@ module.exports = Surface = class Surface extends CocoClass
updateSpriteSounds: ->
@world.getFrame(@getCurrentFrame()).restoreState()
current = Math.max(0, Math.min(@currentFrame, @world.totalFrames - 1))
if current - Math.floor(current) > 0.01
next = Math.ceil current
ratio = current % 1
@world.frames[next].restorePartialState ratio if next > 1
@spriteBoss.updateSounds()
updateState: (frameChanged) ->
@ -492,9 +497,9 @@ module.exports = Surface = class Surface extends CocoClass
@spriteBoss.update frameChanged
@dimmer?.setSprites @spriteBoss.sprites
drawCurrentFrame: ->
drawCurrentFrame: (e) ->
++@totalFramesDrawn
@stage.update()
@stage.update e
# paths - TODO: move to SpriteBoss? but only update on frame drawing instead of on every frame update?

View file

@ -67,7 +67,7 @@ module.exports = class ThangState
restore: ->
# Restore trackedProperties' values to @thang, retrieving them from @trackedPropertyValues if needed. Optimize it.
return @ if @thang._state is @
return @ if @thang._state is @ and not @thang.partialState
unless @hasRestored # Restoring in a deserialized World for first time
props = []
for prop, propIndex in @trackedPropertyKeys
@ -81,6 +81,26 @@ module.exports = class ThangState
else # Restoring later times
for prop, propIndex in @trackedPropertyKeys
@thang[prop] = @props[propIndex]
@thang.partialState = false
@
restorePartial: (ratio) ->
inverse = 1 - ratio
for prop, propIndex in @trackedPropertyKeys when prop is "pos" or prop is "rotation"
if @hasRestored
value = @props[propIndex]
else
type = @trackedPropertyTypes[propIndex]
storage = @trackedPropertyValues[propIndex]
value = @getStoredProp propIndex, type, storage
if prop is "pos"
@thang.pos = @thang.pos.copy()
@thang.pos.x = inverse * @thang.pos.x + ratio * value.x
@thang.pos.y = inverse * @thang.pos.y + ratio * value.y
@thang.pos.z = inverse * @thang.pos.z + ratio * value.z
else if prop is "rotation"
@thang.rotation = inverse * @thang.rotation + ratio * value
@thang.partialState = true
@
serialize: (frameIndex, trackedPropertyIndices, trackedPropertyTypes, trackedPropertyValues, specialValuesToKeys, specialKeysToValues) ->

View file

@ -25,6 +25,9 @@ module.exports = class WorldFrame
#console.log "Frame", @time, "restoring state for", thang.id, "and saying it don't exist"
thang.exists = false
restorePartialState: (ratio) ->
thangState.restorePartial ratio for thangID, thangState of @thangStateMap
restoreStateForThang: (thang) ->
thangState = @thangStateMap[thang.id]
if not thangState