From ae640327393e65741ebe5abe9f61ecfb4d3f420d Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Fri, 16 May 2014 15:33:49 -0700 Subject: [PATCH 1/5] Refactored the Camera to only listen to events that use the same canvas. Fixed the level editor map selection modals. --- app/lib/surface/Camera.coffee | 13 ++++++++++--- app/lib/surface/CocoSprite.coffee | 6 +++++- app/lib/surface/PointChooser.coffee | 2 +- app/lib/surface/RegionChooser.coffee | 4 ++-- app/lib/surface/SpriteBoss.coffee | 2 +- app/lib/surface/Surface.coffee | 4 +++- app/views/editor/thang/edit.coffee | 4 +--- 7 files changed, 23 insertions(+), 12 deletions(-) diff --git a/app/lib/surface/Camera.coffee b/app/lib/surface/Camera.coffee index f76be81b4..891a1c4aa 100644 --- a/app/lib/surface/Camera.coffee +++ b/app/lib/surface/Camera.coffee @@ -25,6 +25,8 @@ module.exports = class Camera extends CocoClass # what the camera is pointed at right now target: DEFAULT_TARGET zoom: DEFAULT_ZOOM + canvasScaleFactorX: 1 + canvasScaleFactorY: 1 # properties for tracking going between targets oldZoom: null @@ -40,14 +42,16 @@ module.exports = class Camera extends CocoClass subscriptions: 'camera-zoom-in': 'onZoomIn' 'camera-zoom-out': 'onZoomOut' - 'surface:mouse-scrolled': 'onMouseScrolled' + 'camera-zoom-to': 'onZoomTo' 'level:restarted': 'onLevelRestarted' + 'surface:mouse-scrolled': 'onMouseScrolled' 'sprite:mouse-down': 'onMouseDown' 'sprite:dragged': 'onMouseDragged' - 'camera-zoom-to': 'onZoomTo' - constructor: (@canvasWidth, @canvasHeight, angle=Math.asin(0.75), hFOV=d2r(30)) -> + constructor: (@canvas, angle=Math.asin(0.75), hFOV=d2r(30)) -> super() + @canvasWidth = parseInt(@canvas.attr('width'), 10) + @canvasHeight = parseInt(@canvas.attr('height'), 10) @offset = {x: 0, y: 0} @calculateViewingAngle angle @calculateFieldOfView hFOV @@ -151,6 +155,7 @@ module.exports = class Camera extends CocoClass onZoomIn: (e) -> @zoomTo @target, @zoom * 1.15, 300 onZoomOut: (e) -> @zoomTo @target, @zoom / 1.15, 300 onMouseScrolled: (e) -> + return unless e.canvas is @canvas ratio = 1 + 0.05 * Math.sqrt(Math.abs(e.deltaY)) ratio = 1 / ratio if e.deltaY > 0 newZoom = @zoom * ratio @@ -169,10 +174,12 @@ module.exports = class Camera extends CocoClass @zoomTo target, newZoom, 0 onMouseDown: (e) -> + return unless e.canvas is @canvas return if @dragDisabled @lastPos = {x: e.originalEvent.rawX, y: e.originalEvent.rawY} onMouseDragged: (e) -> + return unless e.canvas is @canvas return if @dragDisabled target = @boundTarget(@target, @zoom) newPos = diff --git a/app/lib/surface/CocoSprite.coffee b/app/lib/surface/CocoSprite.coffee index a6cdcc741..9bfaaab64 100644 --- a/app/lib/surface/CocoSprite.coffee +++ b/app/lib/surface/CocoSprite.coffee @@ -465,7 +465,11 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass onMouseEvent: (e, ourEventName) -> return if @letterboxOn - Backbone.Mediator.publish ourEventName, sprite: @, thang: @thang, originalEvent: e + p = @imageObject + p = p.parent while p.parent + newEvent = sprite: @, thang: @thang, originalEvent: e, canvas:p + @trigger ourEventName, newEvent + Backbone.Mediator.publish ourEventName, newEvent addHealthBar: -> return unless @thang?.health? and "health" in (@thang?.hudProperties ? []) diff --git a/app/lib/surface/PointChooser.coffee b/app/lib/surface/PointChooser.coffee index c55b1a134..2c8e598e5 100644 --- a/app/lib/surface/PointChooser.coffee +++ b/app/lib/surface/PointChooser.coffee @@ -26,7 +26,7 @@ module.exports = class PointChooser extends CocoClass onMouseDown: (e) => console.log "got stagemousedown", e, key.shift return unless key.shift - @setPoint @options.camera.canvasToWorld {x: e.stageX, y: e.stageY} + @setPoint @options.camera.screenToWorld {x: e.stageX, y: e.stageY} Backbone.Mediator.publish 'choose-point', point: @point updateShape: -> diff --git a/app/lib/surface/RegionChooser.coffee b/app/lib/surface/RegionChooser.coffee index 7d28131d4..3b15ec4f7 100644 --- a/app/lib/surface/RegionChooser.coffee +++ b/app/lib/surface/RegionChooser.coffee @@ -16,12 +16,12 @@ module.exports = class RegionChooser extends CocoClass onMouseDown: (e) => return unless key.shift - @firstPoint = @options.camera.canvasToWorld {x: e.stageX, y: e.stageY} + @firstPoint = @options.camera.screenToWorld {x: e.stageX, y: e.stageY} @options.camera.dragDisabled = true onMouseMove: (e) => return unless @firstPoint - @secondPoint = @options.camera.canvasToWorld {x: e.stageX, y: e.stageY} + @secondPoint = @options.camera.screenToWorld {x: e.stageX, y: e.stageY} @restrictRegion() if @options.restrictRatio @updateShape() diff --git a/app/lib/surface/SpriteBoss.coffee b/app/lib/surface/SpriteBoss.coffee index b23c37d03..d755979d1 100644 --- a/app/lib/surface/SpriteBoss.coffee +++ b/app/lib/surface/SpriteBoss.coffee @@ -13,7 +13,6 @@ module.exports = class SpriteBoss extends CocoClass 'bus:player-left': 'onPlayerLeft' # 'level-set-debug': 'onSetDebug' 'level-highlight-sprites': 'onHighlightSprites' - 'sprite:mouse-up': 'onSpriteMouseUp' 'surface:stage-mouse-down': 'onStageMouseDown' 'level-select-sprite': 'onSelectSprite' 'level-suppress-selection-sounds': 'onSuppressSelectionSounds' @@ -152,6 +151,7 @@ module.exports = class SpriteBoss extends CocoClass options = @createSpriteOptions thang: thang options.resolutionFactor = if thangType.get('kind') is 'Floor' then 2 else SPRITE_RESOLUTION_FACTOR sprite = new CocoSprite thangType, options + @listenTo sprite, 'sprite:mouse-up', @onSpriteMouseUp @addSprite sprite, null, layer sprite.setDebug @debug sprite diff --git a/app/lib/surface/Surface.coffee b/app/lib/surface/Surface.coffee index 108224cee..7beb03cf4 100644 --- a/app/lib/surface/Surface.coffee +++ b/app/lib/surface/Surface.coffee @@ -400,7 +400,7 @@ module.exports = Surface = class Surface extends CocoClass canvasWidth = parseInt @canvas.attr('width'), 10 canvasHeight = parseInt @canvas.attr('height'), 10 @camera?.destroy() - @camera = new Camera canvasWidth, canvasHeight + @camera = new Camera @canvas AudioPlayer.camera = @camera @layers.push @surfaceLayer = new Layer name: "Surface", layerPriority: 0, transform: Layer.TRANSFORM_SURFACE, camera: @camera @layers.push @surfaceTextLayer = new Layer name: "Surface Text", layerPriority: 1, transform: Layer.TRANSFORM_SURFACE_TEXT, camera: @camera @@ -425,6 +425,7 @@ module.exports = Surface = class Surface extends CocoClass oldHeight = parseInt @canvas.attr('height'), 10 newWidth = @canvas.width() newHeight = @canvas.height() + return unless newWidth > 0 and newHeight > 0 #if InstallTrigger? # Firefox rendering performance goes down as canvas size goes up # newWidth = Math.min 924, newWidth # newHeight = Math.min 589, newHeight @@ -544,6 +545,7 @@ module.exports = Surface = class Surface extends CocoClass deltaX: e.deltaX deltaY: e.deltaY screenPos: @mouseScreenPos + canvas: @canvas Backbone.Mediator.publish 'surface:mouse-scrolled', event unless @disabled hookUpChooseControls: -> diff --git a/app/views/editor/thang/edit.coffee b/app/views/editor/thang/edit.coffee index 42ee1adaf..7baa18de6 100644 --- a/app/views/editor/thang/edit.coffee +++ b/app/views/editor/thang/edit.coffee @@ -100,10 +100,8 @@ module.exports = class ThangTypeEditView extends View initStage: -> canvas = @$el.find('#canvas') @stage = new createjs.Stage(canvas[0]) - canvasWidth = parseInt(canvas.attr('width'), 10) - canvasHeight = parseInt(canvas.attr('height'), 10) @camera?.destroy() - @camera = new Camera canvasWidth, canvasHeight + @camera = new Camera canvas @torsoDot = @makeDot('blue') @mouthDot = @makeDot('yellow') From 891471b80ac8eb639a3eff24ee4f172bc448528d Mon Sep 17 00:00:00 2001 From: Michael Schmatz Date: Fri, 16 May 2014 16:04:08 -0700 Subject: [PATCH 2/5] Add time to hover debugger --- .../play/level/tome/spell_debug_view.coffee | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/app/views/play/level/tome/spell_debug_view.coffee b/app/views/play/level/tome/spell_debug_view.coffee index 761e3e480..aa419c750 100644 --- a/app/views/play/level/tome/spell_debug_view.coffee +++ b/app/views/play/level/tome/spell_debug_view.coffee @@ -34,9 +34,23 @@ module.exports = class DebugView extends View @cache = {} @lastFrameRequested = -1 @workerIsSimulating = false + + + pad2: (num) -> + if not num? or num is 0 then "00" else ((if num < 10 then "0" else "") + num) + + calculateCurrentTimeString: => + time = @currentFrame / @frameRate + console.log "Current frame is",@currentFrame + console.log "Current framerate is",@frameRate + mins = Math.floor(time / 60) + secs = (time - mins * 60).toFixed(1) + "#{mins}:#{@pad2 secs}" + setTooltipKeyAndValue: (key, value) => - @$el.find("code").text "#{key}: #{value}" + message = "Time: #{@calculateCurrentTimeString()}\n#{key}: #{value}" + @$el.find("code").text message @$el.show().css(@pos) setTooltipText: (text) => @@ -128,9 +142,11 @@ module.exports = class DebugView extends View onNewWorld: (e) -> @thang = @options.thang = e.world.thangMap[@thang.id] if @thang + @frameRate = e.world.frameRate onFrameChanged: (data) -> @currentFrame = data.frame + @frameRate = data.world.frameRate update: -> if @variableChain From f64e50f85b0806310616425bef253e9a43a40b90 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Fri, 16 May 2014 16:52:55 -0700 Subject: [PATCH 3/5] Recording flow only for frame of interest. --- .../javascripts/workers/worker_world.js | 8 ++--- app/lib/surface/Mark.coffee | 1 + app/lib/world/world.coffee | 6 ++++ .../play/level/tome/spell_debug_view.coffee | 32 +++++++++---------- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/app/assets/javascripts/workers/worker_world.js b/app/assets/javascripts/workers/worker_world.js index c47d296c3..f5d91cf18 100644 --- a/app/assets/javascripts/workers/worker_world.js +++ b/app/assets/javascripts/workers/worker_world.js @@ -238,13 +238,13 @@ self.retrieveValueFromFrame = function retrieveValueFromFrame(args) { self.enableFlowOnThangSpell = function (thangID, spellID, userCodeMap) { try { - if (userCodeMap[thangID][spellID].originalOptions.includeFlow === true && - userCodeMap[thangID][spellID].originalOptions.noSerializationInFlow === true) + var options = userCodeMap[thangID][spellID].originalOptions; + if (options.includeFlow === true && options.noSerializationInFlow === true) return; else { - userCodeMap[thangID][spellID].originalOptions.includeFlow = true; - userCodeMap[thangID][spellID].originalOptions.noSerializationInFlow = true; + options.includeFlow = true; + options.noSerializationInFlow = true; var temporaryAether = Aether.deserialize(userCodeMap[thangID][spellID]); temporaryAether.transpile(temporaryAether.raw); userCodeMap[thangID][spellID] = temporaryAether.serialize(); diff --git a/app/lib/surface/Mark.coffee b/app/lib/surface/Mark.coffee index abf2b7fed..de27d01dd 100644 --- a/app/lib/surface/Mark.coffee +++ b/app/lib/surface/Mark.coffee @@ -20,6 +20,7 @@ module.exports = class Mark extends CocoClass @build() destroy: -> + createjs.Tween.removeTweens @mark @mark?.parent?.removeChild @mark @markSprite?.destroy() @sprite = null diff --git a/app/lib/world/world.coffee b/app/lib/world/world.coffee index 4dae55cb0..acdc62048 100644 --- a/app/lib/world/world.coffee +++ b/app/lib/world/world.coffee @@ -85,6 +85,12 @@ module.exports = class World frameToLoadUntil = @totalFrames i = @frames.length while i < frameToLoadUntil + if @debugging + for thang in @thangs when thang.isProgrammable + userCode = @userCodeMap[thang.id] ? {} + for methodName, aether of userCode + framesToLoadFlowBefore = if methodName is 'plan' then 200 else 1 # Adjust if plan() is taking even longer + aether._shouldSkipFlow = i < loadUntilFrame - framesToLoadFlowBefore try @getFrame(i) ++i # increment this after we have succeeded in getting the frame, otherwise we'll have to do that frame again diff --git a/app/views/play/level/tome/spell_debug_view.coffee b/app/views/play/level/tome/spell_debug_view.coffee index aa419c750..a8a03cbd7 100644 --- a/app/views/play/level/tome/spell_debug_view.coffee +++ b/app/views/play/level/tome/spell_debug_view.coffee @@ -34,40 +34,38 @@ module.exports = class DebugView extends View @cache = {} @lastFrameRequested = -1 @workerIsSimulating = false - + pad2: (num) -> if not num? or num is 0 then "00" else ((if num < 10 then "0" else "") + num) - + calculateCurrentTimeString: => time = @currentFrame / @frameRate - console.log "Current frame is",@currentFrame - console.log "Current framerate is",@frameRate mins = Math.floor(time / 60) secs = (time - mins * 60).toFixed(1) "#{mins}:#{@pad2 secs}" - - + + setTooltipKeyAndValue: (key, value) => message = "Time: #{@calculateCurrentTimeString()}\n#{key}: #{value}" @$el.find("code").text message @$el.show().css(@pos) - + setTooltipText: (text) => #perhaps changing styling here in the future @$el.find("code").text text @$el.show().css(@pos) - + onTomeCast: -> @invalidateCache() - + invalidateCache: -> @cache = {} - + retrieveValueFromCache: (thangID,spellID,variableChain,frame) -> joinedVariableChain = variableChain.join() value = @cache[frame]?[thangID]?[spellID]?[joinedVariableChain] return value ? undefined - + updateCache: (thangID, spellID, variableChain, frame, value) -> currentObject = @cache keys = [frame,thangID,spellID,variableChain.join()] @@ -77,8 +75,8 @@ module.exports = class DebugView extends View currentObject[key] = {} currentObject = currentObject[key] currentObject[keys[keys.length - 1]] = value - - + + changeCurrentThangAndSpell: (thangAndSpellObject) -> @thang = thangAndSpellObject.thang @spell = thangAndSpellObject.spell @@ -143,11 +141,11 @@ module.exports = class DebugView extends View onNewWorld: (e) -> @thang = @options.thang = e.world.thangMap[@thang.id] if @thang @frameRate = e.world.frameRate - + onFrameChanged: (data) -> @currentFrame = data.frame @frameRate = data.world.frameRate - + update: -> if @variableChain if @variableChain.length is 2 and @variableChain[0] is "this" @@ -173,7 +171,7 @@ module.exports = class DebugView extends View else @notifyPropertyHovered() @updateMarker() - + stringifyValue: (value, depth) -> return value if not value or _.isString value if _.isFunction value @@ -214,7 +212,7 @@ module.exports = class DebugView extends View @hoveredProperty = if @variableChain?.length is 2 then owner: @variableChain[0], property: @variableChain[1] else {} unless _.isEqual oldHoveredProperty, @hoveredProperty Backbone.Mediator.publish 'tome:spell-debug-property-hovered', @hoveredProperty - + updateMarker: -> if @marker @ace.getSession().removeMarker @marker From a36a7792ec9824197d36485a6f537022021f870c Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Fri, 16 May 2014 17:18:56 -0700 Subject: [PATCH 4/5] Fixed problem with IndieSprites not loading, breaking scripts. --- app/lib/surface/SpriteBoss.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/surface/SpriteBoss.coffee b/app/lib/surface/SpriteBoss.coffee index d755979d1..617232af7 100644 --- a/app/lib/surface/SpriteBoss.coffee +++ b/app/lib/surface/SpriteBoss.coffee @@ -46,7 +46,7 @@ module.exports = class SpriteBoss extends CocoClass toString: -> "" thangTypeFor: (type) -> - _.find @options.thangTypes, (m) -> m.get('actions') and m.get('original') is type or m.get('name') is type + _.find @options.thangTypes, (m) -> m.get('original') is type or m.get('name') is type createLayers: -> @spriteLayers = {} From 418c2f1a2c5d39000366a2d17828b0291913af8a Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Fri, 16 May 2014 17:38:33 -0700 Subject: [PATCH 5/5] Preserve original scripts; don't overwrite with nothing if new world finishes before script initialization. --- app/lib/scripts/GoalsScriptModule.coffee | 6 +----- app/views/play/level/control_bar_view.coffee | 6 +++--- app/views/play/level_view.coffee | 10 ++++++---- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/app/lib/scripts/GoalsScriptModule.coffee b/app/lib/scripts/GoalsScriptModule.coffee index b55673117..0e6737b92 100644 --- a/app/lib/scripts/GoalsScriptModule.coffee +++ b/app/lib/scripts/GoalsScriptModule.coffee @@ -12,7 +12,7 @@ module.exports = class GoalsScriptModule extends ScriptModule endNotes: -> return [] - + skipNotes: -> return @startNotes() @@ -21,7 +21,6 @@ module.exports = class GoalsScriptModule extends ScriptModule channel: 'level-add-goals' event: goals: @noteGroup.goals.add - worldName: @view.world.name return note removeNote: -> @@ -29,7 +28,4 @@ module.exports = class GoalsScriptModule extends ScriptModule channel: 'level-remove-goals' event: goals: @noteGroup.goals.remove - worldName: @view.world.name return note - - \ No newline at end of file diff --git a/app/views/play/level/control_bar_view.coffee b/app/views/play/level/control_bar_view.coffee index f2502ba6f..9c1076edb 100644 --- a/app/views/play/level/control_bar_view.coffee +++ b/app/views/play/level/control_bar_view.coffee @@ -14,15 +14,15 @@ module.exports = class ControlBarView extends View events: 'click #multiplayer-button': -> - window.tracker?.trackEvent 'Clicked Multiplayer', level: @worldName, label: @worldName + window.tracker?.trackEvent 'Clicked Multiplayer', level: @level.get('name'), label: @level.get('name') @showMultiplayerModal() 'click #docs-button': -> - window.tracker?.trackEvent 'Clicked Docs', level: @worldName, label: @worldName + window.tracker?.trackEvent 'Clicked Docs', level: @level.get('name'), label: @level.get('name') @showGuideModal() 'click #restart-button': -> - window.tracker?.trackEvent 'Clicked Restart', level: @worldName, label: @worldName + window.tracker?.trackEvent 'Clicked Restart', level: @level.get('name'), label: @level.get('name') @showRestartModal() 'click #next-game-button': -> diff --git a/app/views/play/level_view.coffee b/app/views/play/level_view.coffee index 8d45ddd10..9cfb0da61 100644 --- a/app/views/play/level_view.coffee +++ b/app/views/play/level_view.coffee @@ -198,7 +198,7 @@ module.exports = class PlayLevelView extends View for spellTeam, spells of @session.get('teamSpells') ? @otherSession?.get('teamSpells') ? {} continue if spellTeam is myTeam or not myTeam opponentSpells = opponentSpells.concat spells - if (not @session.get('teamSpells')) and @otherSession?.get('teamSpells') + if (not @session.get('teamSpells')) and @otherSession?.get('teamSpells') @session.set('teamSpells',@otherSession.get('teamSpells')) opponentCode = @otherSession?.get('transpiledCode') or {} myCode = @session.get('code') or {} @@ -295,7 +295,7 @@ module.exports = class PlayLevelView extends View @victorySeen = true victoryTime = (new Date()) - @loadEndTime if victoryTime > 10 * 1000 # Don't track it if we're reloading an already-beaten level - application.tracker?.trackEvent 'Saw Victory', level: @world.name, label: @world.name + application.tracker?.trackEvent 'Saw Victory', level: @level.get('name'), label: @level.get('name') application.tracker?.trackTiming victoryTime, 'Level Victory Time', @levelID, @levelID, 100 showVictory: -> @@ -309,12 +309,12 @@ module.exports = class PlayLevelView extends View @tome.reloadAllCode() Backbone.Mediator.publish 'level:restarted' $('#level-done-button', @$el).hide() - application.tracker?.trackEvent 'Confirmed Restart', level: @world.name, label: @world.name + application.tracker?.trackEvent 'Confirmed Restart', level: @level.get('name'), label: @level.get('name') onInfiniteLoop: (e) -> return unless e.firstWorld @openModalView new InfiniteLoopModal() - application.tracker?.trackEvent 'Saw Initial Infinite Loop', level: @world.name, label: @world.name + application.tracker?.trackEvent 'Saw Initial Infinite Loop', level: @level.get('name'), label: @level.get('name') onPlayNextLevel: -> nextLevelID = @getNextLevelID() @@ -485,7 +485,9 @@ module.exports = class PlayLevelView extends View onNewWorld: (e) -> return if @headless + scripts = @world.scripts # Since these worlds don't have scripts, preserve them. @world = e.world + @world.scripts = scripts thangTypes = @supermodel.getModels(ThangType) for [spriteName, message] in @world.thangDialogueSounds() continue unless thangType = _.find thangTypes, (m) -> m.get('name') is spriteName