mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 09:35:39 -05:00
Refactored CocoSprite -> Lank, lank.imageObject -> lank.sprite, SpriteBoss -> LankBoss, spriteLayers -> layerAdapters, sprite -> lank in general. Also got the ThangTypeEditView working again.
This commit is contained in:
parent
64a8322ec0
commit
f081d9ed4b
22 changed files with 833 additions and 803 deletions
|
@ -53,11 +53,11 @@ module.exports = class LevelBus extends Bus
|
|||
super()
|
||||
|
||||
onSelfWizardCreated: (e) ->
|
||||
@selfWizardSprite = e.sprite
|
||||
@selfWizardLank = e.sprite
|
||||
|
||||
onSelfWizardTargetChanged: (e) ->
|
||||
@wizardRef?.child('targetPos').set(@selfWizardSprite?.targetPos or null)
|
||||
@wizardRef?.child('targetSprite').set(@selfWizardSprite?.targetSprite?.thang.id or null)
|
||||
@wizardRef?.child('targetPos').set(@selfWizardLank?.targetPos or null)
|
||||
@wizardRef?.child('targetSprite').set(@selfWizardLank?.targetSprite?.thang.id or null)
|
||||
|
||||
onMeSynced: =>
|
||||
super()
|
||||
|
@ -66,8 +66,8 @@ module.exports = class LevelBus extends Bus
|
|||
join: ->
|
||||
super()
|
||||
@wizardRef = @myConnection.child('wizard')
|
||||
@wizardRef?.child('targetPos').set(@selfWizardSprite?.targetPos or null)
|
||||
@wizardRef?.child('targetSprite').set(@selfWizardSprite?.targetSprite?.thang.id or null)
|
||||
@wizardRef?.child('targetPos').set(@selfWizardLank?.targetPos or null)
|
||||
@wizardRef?.child('targetSprite').set(@selfWizardLank?.targetSprite?.thang.id or null)
|
||||
@wizardRef?.child('wizardColor1').set(me.get('wizardColor1') or 0.0)
|
||||
|
||||
disconnect: ->
|
||||
|
|
|
@ -66,7 +66,7 @@ module.exports = class Dimmer extends CocoClass
|
|||
@dimMask.graphics.clear()
|
||||
for thangID, sprite of @sprites
|
||||
continue unless (thangID in @highlightedThangIDs) or sprite.isTalking?() or sprite.thang?.id is 'My Wizard'
|
||||
sup = x: sprite.imageObject.x, y: sprite.imageObject.y
|
||||
sup = x: sprite.sprite.x, y: sprite.sprite.y
|
||||
cap = @camera.surfaceToCanvas sup
|
||||
r = 50 * @camera.zoom # TODO: find better way to get the radius based on the sprite's size
|
||||
@dimMask.graphics.beginRadialGradientFill(['rgba(0,0,0,1)', 'rgba(0,0,0,0)'], [0.5, 1], cap.x, cap.y, 0, cap.x, cap.y, r).drawCircle(cap.x, cap.y, r)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
IndieSprite = require 'lib/surface/IndieSprite'
|
||||
IndieLank = require 'lib/surface/IndieLank'
|
||||
{me} = require 'lib/auth'
|
||||
|
||||
module.exports = class FlagSprite extends IndieSprite
|
||||
module.exports = class FlagLank extends IndieLank
|
||||
subscriptions:
|
||||
'surface:mouse-moved': 'onMouseMoved'
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
Thang = require 'lib/world/thang'
|
||||
CocoSprite = require 'lib/surface/CocoSprite'
|
||||
Lank = require 'lib/surface/Lank'
|
||||
|
||||
module.exports = IndieSprite = class IndieSprite extends CocoSprite
|
||||
module.exports = IndieLank = class IndieLank extends Lank
|
||||
notOfThisWorld: true
|
||||
subscriptions:
|
||||
'script:note-group-started': 'onNoteGroupStarted'
|
|
@ -49,11 +49,11 @@ module.exports = class Label extends CocoClass
|
|||
update: ->
|
||||
return unless @text
|
||||
offset = @sprite.getOffset? (if @style in ['dialogue', 'say'] then 'mouth' else 'aboveHead')
|
||||
offset ?= x: 0, y: 0 # temp (if not CocoSprite)
|
||||
offset ?= x: 0, y: 0 # temp (if not Lank)
|
||||
rotation = @sprite.getRotation()
|
||||
offset.x *= -1 if rotation >= 135 or rotation <= -135
|
||||
@label.x = @background.x = @sprite.imageObject.x + offset.x
|
||||
@label.y = @background.y = @sprite.imageObject.y + offset.y
|
||||
@label.x = @background.x = @sprite.sprite.x + offset.x
|
||||
@label.y = @background.y = @sprite.sprite.y + offset.y
|
||||
null
|
||||
|
||||
show: ->
|
||||
|
@ -122,7 +122,7 @@ module.exports = class Label extends CocoClass
|
|||
pointerWidth += radius # Convenience value including pointer width and border radius
|
||||
|
||||
# Figure out the position of the pointer for the bubble
|
||||
sup = x: @sprite.imageObject.x, y: @sprite.imageObject.y # a little more accurate to aim for mouth--how?
|
||||
sup = x: @sprite.sprite.x, y: @sprite.sprite.y # a little more accurate to aim for mouth--how?
|
||||
cap = @camera.surfaceToCanvas sup
|
||||
hPos = if cap.x / @camera.canvasWidth > 0.53 then 'right' else 'left'
|
||||
vPos = if cap.y / @camera.canvasHeight > 0.53 then 'bottom' else 'top'
|
||||
|
|
|
@ -13,10 +13,10 @@ healthColors =
|
|||
neutral: [64, 212, 128]
|
||||
|
||||
# Sprite: EaselJS-based view/controller for Thang model
|
||||
module.exports = CocoSprite = class CocoSprite extends CocoClass
|
||||
module.exports = Lank = class Lank extends CocoClass
|
||||
thangType: null # ThangType instance
|
||||
|
||||
imageObject: null
|
||||
sprite: null
|
||||
|
||||
healthBar: null
|
||||
marks: null
|
||||
|
@ -62,12 +62,12 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
@options = _.extend($.extend(true, {}, @options), options)
|
||||
@setThang @options.thang
|
||||
if @thang?
|
||||
options = @thang?.getSpriteOptions?()
|
||||
options = @thang?.getLankOptions?()
|
||||
@options.colorConfig = options.colorConfig if options and options.colorConfig
|
||||
console.error @toString(), 'has no ThangType!' unless @thangType
|
||||
|
||||
# this is a stub, use @setImageObject to swap it out for something else later
|
||||
@imageObject = new createjs.Container
|
||||
# this is a stub, use @setSprite to swap it out for something else later
|
||||
@sprite = new createjs.Container
|
||||
|
||||
@actionQueue = []
|
||||
@marks = {}
|
||||
|
@ -78,7 +78,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
@stillLoading = true
|
||||
if @thangType.isFullyLoaded() then @onThangTypeLoaded() else @listenToOnce(@thangType, 'sync', @onThangTypeLoaded)
|
||||
|
||||
toString: -> "<CocoSprite: #{@thang?.id}>"
|
||||
toString: -> "<Lank: #{@thang?.id}>"
|
||||
|
||||
onThangTypeLoaded: ->
|
||||
@stillLoading = false
|
||||
|
@ -97,22 +97,22 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
@scaleFactorY = @thang.scaleFactor if @thang?.scaleFactor?
|
||||
@updateAction() unless @currentAction
|
||||
|
||||
setImageObject: (newImageObject) ->
|
||||
if @imageObject
|
||||
@imageObject.destroy?()
|
||||
if parent = @imageObject.parent
|
||||
parent.removeChild @imageObject
|
||||
parent.addChild newImageObject
|
||||
setSprite: (newSprite) ->
|
||||
if @sprite
|
||||
@sprite.destroy?()
|
||||
if parent = @sprite.parent
|
||||
parent.removeChild @sprite
|
||||
parent.addChild newSprite
|
||||
|
||||
# get the cocosprite to update things
|
||||
# get the lank to update things
|
||||
for prop in ['lastPos', 'currentRootAction']
|
||||
delete @[prop]
|
||||
|
||||
@imageObject = newImageObject
|
||||
@sprite = newSprite
|
||||
@configureMouse()
|
||||
@imageObject.on 'animationend', @playNextAction
|
||||
@sprite.on 'animationend', @playNextAction
|
||||
@playAction(@currentAction) if @currentAction and not @stillLoading
|
||||
@trigger 'new-image-object', @imageObject
|
||||
@trigger 'new-sprite', @sprite
|
||||
|
||||
##################################################
|
||||
# QUEUEING AND PLAYING ACTIONS
|
||||
|
@ -141,9 +141,9 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
return @hide() unless action.animation or action.container or action.relatedActions
|
||||
@show()
|
||||
return @updateActionDirection() unless action.animation or action.container
|
||||
return if @imageObject.placeholder
|
||||
return if @sprite.placeholder
|
||||
m = if action.container then 'gotoAndStop' else 'gotoAndPlay'
|
||||
@imageObject[m]?(action.name)
|
||||
@sprite[m]?(action.name)
|
||||
@updateScale()
|
||||
@updateRotation()
|
||||
|
||||
|
@ -156,12 +156,12 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
@updateAlpha()
|
||||
|
||||
stop: ->
|
||||
@imageObject?.stop?()
|
||||
@sprite?.stop?()
|
||||
mark.stop() for name, mark of @marks
|
||||
@stopped = true
|
||||
|
||||
play: ->
|
||||
@imageObject?.play?()
|
||||
@sprite?.play?()
|
||||
mark.play() for name, mark of @marks
|
||||
@stopped = false
|
||||
|
||||
|
@ -238,7 +238,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
shadowColor = {humans: '#F00', ogres: '#00F', neutral: '#0F0', common: '#0F0'}[@thang.team] ? '#000'
|
||||
label.shadow = new createjs.Shadow shadowColor, 1, 1, 3
|
||||
offset = @getOffset 'aboveHead'
|
||||
[label.x, label.y] = [@imageObject.x + offset.x - label.getMeasuredWidth() / 2, @imageObject.y + offset.y]
|
||||
[label.x, label.y] = [@sprite.x + offset.x - label.getMeasuredWidth() / 2, @sprite.y + offset.y]
|
||||
@options.textLayer.addChild label
|
||||
window.labels ?= []
|
||||
window.labels.push label
|
||||
|
@ -270,7 +270,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
[p0, p1] = [@lastPos, @thang.pos]
|
||||
return if p0 and p0.x is p1.x and p0.y is p1.y and p0.z is p1.z and not @options.camera.tweeningZoomTo and not @thang.bobHeight
|
||||
sup = @options.camera.worldToSurface wop
|
||||
[@imageObject.x, @imageObject.y] = [sup.x, sup.y]
|
||||
[@sprite.x, @sprite.y] = [sup.x, sup.y]
|
||||
@lastPos = p1.copy?() or _.clone(p1) unless whileLoading
|
||||
@hasMoved = true
|
||||
if @thangType.get('name') is 'Flag' and not @notOfThisWorld
|
||||
|
@ -278,19 +278,19 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
_.defer => Backbone.Mediator.publish 'surface:flag-appeared', sprite: @
|
||||
|
||||
updateScale: ->
|
||||
return unless @imageObject
|
||||
return unless @sprite
|
||||
if @thangType.get('matchWorldDimensions') and @thang
|
||||
if @thang.width isnt @lastThangWidth or @thang.height isnt @lastThangHeight
|
||||
bounds = @imageObject.getBounds()
|
||||
bounds = @sprite.getBounds()
|
||||
return unless bounds
|
||||
@imageObject.scaleX = @thang.width * Camera.PPM / bounds.width
|
||||
@imageObject.scaleY = @thang.height * Camera.PPM * @options.camera.y2x / bounds.height
|
||||
@imageObject.regX = bounds.width / 2
|
||||
@imageObject.regY = bounds.height / 2
|
||||
@sprite.scaleX = @thang.width * Camera.PPM / bounds.width
|
||||
@sprite.scaleY = @thang.height * Camera.PPM * @options.camera.y2x / bounds.height
|
||||
@sprite.regX = bounds.width / 2
|
||||
@sprite.regY = bounds.height / 2
|
||||
|
||||
unless @thang.spriteName is 'Beam'
|
||||
@imageObject.scaleX *= @thangType.get('scale') ? 1
|
||||
@imageObject.scaleY *= @thangType.get('scale') ? 1
|
||||
@sprite.scaleX *= @thangType.get('scale') ? 1
|
||||
@sprite.scaleY *= @thangType.get('scale') ? 1
|
||||
[@lastThangWidth, @lastThangHeight] = [@thang.width, @thang.height]
|
||||
return
|
||||
|
||||
|
@ -311,8 +311,8 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
scaleX = 0.5 + 0.5 * (90 - angle) / 90
|
||||
|
||||
# console.error 'No thang for', @ unless @thang
|
||||
@imageObject.scaleX = @imageObject.baseScaleX * @scaleFactorX * scaleX
|
||||
@imageObject.scaleY = @imageObject.baseScaleY * @scaleFactorY * scaleY
|
||||
@sprite.scaleX = @sprite.baseScaleX * @scaleFactorX * scaleX
|
||||
@sprite.scaleY = @sprite.baseScaleY * @scaleFactorY * scaleY
|
||||
|
||||
newScaleFactorX = @thang?.scaleFactorX ? @thang?.scaleFactor ? 1
|
||||
newScaleFactorY = @thang?.scaleFactorY ? @thang?.scaleFactor ? 1
|
||||
|
@ -323,16 +323,16 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
createjs.Tween.get(@).to({scaleFactorX: @targetScaleFactorX, scaleFactorY: @targetScaleFactorY}, 2000, createjs.Ease.elasticOut)
|
||||
|
||||
updateAlpha: ->
|
||||
@imageObject.alpha = if @hiding then 0 else 1
|
||||
@sprite.alpha = if @hiding then 0 else 1
|
||||
return unless @thang?.alpha?
|
||||
return if @imageObject.alpha is @thang.alpha
|
||||
@imageObject.alpha = @thang.alpha
|
||||
return if @sprite.alpha is @thang.alpha
|
||||
@sprite.alpha = @thang.alpha
|
||||
if @options.showInvisible
|
||||
@imageObject.alpha = Math.max 0.5, @imageObject.alpha
|
||||
@sprite.alpha = Math.max 0.5, @sprite.alpha
|
||||
mark.updateAlpha @thang.alpha for name, mark of @marks
|
||||
@healthBar?.alpha = @thang.alpha
|
||||
|
||||
updateRotation: (imageObject) ->
|
||||
updateRotation: (sprite) ->
|
||||
rotationType = @thangType.get('rotationType')
|
||||
return if rotationType is 'fixed'
|
||||
rotation = @getRotation()
|
||||
|
@ -347,9 +347,9 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
xFactor = Math.cos heading
|
||||
zFactor = vz / Math.sqrt(vz * vz + vx * vx)
|
||||
rotation -= xFactor * zFactor * 45
|
||||
imageObject ?= @imageObject
|
||||
return imageObject.rotation = rotation if rotationType is 'free' or not rotationType
|
||||
@updateIsometricRotation(rotation, imageObject)
|
||||
sprite ?= @sprite
|
||||
return sprite.rotation = rotation if rotationType is 'free' or not rotationType
|
||||
@updateIsometricRotation(rotation, sprite)
|
||||
|
||||
getRotation: ->
|
||||
thang = if @possessed then @shadow else @thang
|
||||
|
@ -359,11 +359,11 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
rotation -= 360 if rotation > 180
|
||||
rotation
|
||||
|
||||
updateIsometricRotation: (rotation, imageObject) ->
|
||||
updateIsometricRotation: (rotation, sprite) ->
|
||||
return unless @currentAction
|
||||
return if _.string.endsWith(@currentAction.name, 'back')
|
||||
return if _.string.endsWith(@currentAction.name, 'fore')
|
||||
imageObject.scaleX *= -1 if Math.abs(rotation) >= 90
|
||||
sprite.scaleX *= -1 if Math.abs(rotation) >= 90
|
||||
|
||||
##################################################
|
||||
updateAction: ->
|
||||
|
@ -455,18 +455,18 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
@setNameLabel(if @thang.health <= 0 then '' else @thang.id)
|
||||
|
||||
configureMouse: ->
|
||||
@imageObject.cursor = 'pointer' if @thang?.isSelectable
|
||||
@imageObject.mouseEnabled = @imageObject.mouseChildren = false unless @thang?.isSelectable or @thang?.isLand
|
||||
if @imageObject.mouseEnabled
|
||||
@imageObject.on 'mousedown', @onMouseEvent, @, false, 'sprite:mouse-down'
|
||||
@imageObject.on 'click', @onMouseEvent, @, false, 'sprite:clicked'
|
||||
@imageObject.on 'dblclick', @onMouseEvent, @, false, 'sprite:double-clicked'
|
||||
@imageObject.on 'pressmove', @onMouseEvent, @, false, 'sprite:dragged'
|
||||
@imageObject.on 'pressup', @onMouseEvent, @, false, 'sprite:mouse-up'
|
||||
@sprite.cursor = 'pointer' if @thang?.isSelectable
|
||||
@sprite.mouseEnabled = @sprite.mouseChildren = false unless @thang?.isSelectable or @thang?.isLand
|
||||
if @sprite.mouseEnabled
|
||||
@sprite.on 'mousedown', @onMouseEvent, @, false, 'sprite:mouse-down'
|
||||
@sprite.on 'click', @onMouseEvent, @, false, 'sprite:clicked'
|
||||
@sprite.on 'dblclick', @onMouseEvent, @, false, 'sprite:double-clicked'
|
||||
@sprite.on 'pressmove', @onMouseEvent, @, false, 'sprite:dragged'
|
||||
@sprite.on 'pressup', @onMouseEvent, @, false, 'sprite:mouse-up'
|
||||
|
||||
onMouseEvent: (e, ourEventName) ->
|
||||
return if @letterboxOn or not @imageObject
|
||||
p = @imageObject
|
||||
return if @letterboxOn or not @sprite
|
||||
p = @sprite
|
||||
p = p.parent while p.parent
|
||||
newEvent = sprite: @, thang: @thang, originalEvent: e, canvas: p.canvas
|
||||
@trigger ourEventName, newEvent
|
||||
|
@ -505,7 +505,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
pos = x: pos.x, y: pos.y
|
||||
if not @isRaster
|
||||
scale = @getActionProp 'scale', null, 1
|
||||
scale *= @imageObject.parent.resolutionFactor if prop is 'registration'
|
||||
scale *= @sprite.parent.resolutionFactor if prop is 'registration'
|
||||
pos.x *= scale
|
||||
pos.y *= scale
|
||||
if @thang and prop isnt 'registration'
|
||||
|
@ -613,7 +613,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
@labels[name]
|
||||
|
||||
addMark: (name, layer, thangType=null) ->
|
||||
@marks[name] ?= new Mark name: name, sprite: @, camera: @options.camera, layer: layer ? @options.groundLayer, thangType: thangType
|
||||
@marks[name] ?= new Mark name: name, lank: @, camera: @options.camera, layer: layer ? @options.groundLayer, thangType: thangType
|
||||
@marks[name]
|
||||
|
||||
notifySpeechUpdated: (e) ->
|
||||
|
@ -720,7 +720,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
z = @shadow.pos.z
|
||||
@shadow.pos = pos
|
||||
@shadow.pos.z = z
|
||||
@imageObject.gotoAndPlay?(endAnimation)
|
||||
@sprite.gotoAndPlay?(endAnimation)
|
||||
return
|
||||
|
||||
@shadow.action = 'move'
|
||||
|
@ -736,7 +736,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
|
||||
endFunc = =>
|
||||
@lastTween = null
|
||||
@imageObject.gotoAndPlay(endAnimation) unless @stillLoading
|
||||
@sprite.gotoAndPlay(endAnimation) unless @stillLoading
|
||||
@shadow.action = 'idle'
|
||||
@update true
|
||||
@possessed = false
|
||||
|
@ -762,13 +762,13 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
return unless @healthBar
|
||||
bounds = @healthBar.getBounds()
|
||||
offset = @getOffset 'aboveHead'
|
||||
@healthBar.x = @imageObject.x - (-offset.x + bounds.width / 2 / @options.floatingLayer.resolutionFactor)
|
||||
@healthBar.y = @imageObject.y - (-offset.y + bounds.height / 2 / @options.floatingLayer.resolutionFactor)
|
||||
@healthBar.x = @sprite.x - (-offset.x + bounds.width / 2 / @options.floatingLayer.resolutionFactor)
|
||||
@healthBar.y = @sprite.y - (-offset.y + bounds.height / 2 / @options.floatingLayer.resolutionFactor)
|
||||
|
||||
destroy: ->
|
||||
mark.destroy() for name, mark of @marks
|
||||
label.destroy() for name, label of @labels
|
||||
p.removeChild @healthBar if p = @healthBar?.parent
|
||||
@imageObject?.off 'animationend', @playNextAction
|
||||
@sprite?.off 'animationend', @playNextAction
|
||||
clearInterval @effectInterval if @effectInterval
|
||||
super()
|
391
app/lib/surface/LankBoss.coffee
Normal file
391
app/lib/surface/LankBoss.coffee
Normal file
|
@ -0,0 +1,391 @@
|
|||
CocoClass = require 'lib/CocoClass'
|
||||
{me} = require 'lib/auth'
|
||||
LayerAdapter = require './LayerAdapter'
|
||||
IndieLank = require 'lib/surface/IndieLank'
|
||||
WizardLank = require 'lib/surface/WizardLank'
|
||||
FlagLank = require 'lib/surface/FlagLank'
|
||||
Lank = require 'lib/surface/Lank'
|
||||
Mark = require './Mark'
|
||||
Grid = require 'lib/world/Grid'
|
||||
|
||||
module.exports = class LankBoss extends CocoClass
|
||||
subscriptions:
|
||||
'bus:player-joined': 'onPlayerJoined'
|
||||
'bus:player-left': 'onPlayerLeft'
|
||||
'level:set-debug': 'onSetDebug'
|
||||
'sprite:highlight-sprites': 'onHighlightSprites'
|
||||
'surface:stage-mouse-down': 'onStageMouseDown'
|
||||
'level:select-sprite': 'onSelectSprite'
|
||||
'level:suppress-selection-sounds': 'onSuppressSelectionSounds'
|
||||
'level:lock-select': 'onSetLockSelect'
|
||||
'level:restarted': 'onLevelRestarted'
|
||||
'god:new-world-created': 'onNewWorld'
|
||||
'god:streaming-world-updated': 'onNewWorld'
|
||||
'camera:dragged': 'onCameraDragged'
|
||||
'sprite:loaded': -> @update(true)
|
||||
'level:flag-color-selected': 'onFlagColorSelected'
|
||||
'level:flag-updated': 'onFlagUpdated'
|
||||
'surface:flag-appeared': 'onFlagAppeared'
|
||||
'surface:remove-selected-flag': 'onRemoveSelectedFlag'
|
||||
|
||||
constructor: (@options) ->
|
||||
super()
|
||||
@dragged = 0
|
||||
@options ?= {}
|
||||
@camera = @options.camera
|
||||
@webGLStage = @options.webGLStage
|
||||
@surfaceTextLayer = @options.surfaceTextLayer
|
||||
@world = options.world
|
||||
@options.thangTypes ?= []
|
||||
@lanks = {}
|
||||
@lankArray = [] # Mirror @lanks, but faster for when we just need to iterate
|
||||
@selfWizardLank = null
|
||||
@createLayers()
|
||||
@pendingFlags = []
|
||||
|
||||
destroy: ->
|
||||
@removeLank lank for thangID, lank of @lanks
|
||||
@targetMark?.destroy()
|
||||
@selectionMark?.destroy()
|
||||
super()
|
||||
|
||||
toString: -> "<LankBoss: #{@lankArray.length} lanks>"
|
||||
|
||||
thangTypeFor: (type) ->
|
||||
_.find @options.thangTypes, (m) -> m.get('original') is type or m.get('name') is type
|
||||
|
||||
createLayers: ->
|
||||
@layerAdapters = {}
|
||||
for [name, priority] in [
|
||||
['Land', -40]
|
||||
['Ground', -30]
|
||||
['Obstacle', -20]
|
||||
['Path', -10]
|
||||
['Default', 0]
|
||||
['Floating', 10]
|
||||
]
|
||||
@layerAdapters[name] = new LayerAdapter name: name, webGL: true, layerPriority: priority, transform: LayerAdapter.TRANSFORM_SURFACE, camera: @camera
|
||||
@webGLStage.addChild (lankLayer.container for lankLayer in _.values(@layerAdapters))...
|
||||
|
||||
layerForChild: (child, lank) ->
|
||||
unless child.layerPriority?
|
||||
if thang = lank?.thang
|
||||
child.layerPriority = thang.layerPriority
|
||||
child.layerPriority ?= 0 if thang.isSelectable
|
||||
child.layerPriority ?= -40 if thang.isLand
|
||||
child.layerPriority ?= 0
|
||||
return @layerAdapters['Default'] unless child.layerPriority
|
||||
layer = _.findLast @layerAdapters, (layer, name) ->
|
||||
layer.layerPriority <= child.layerPriority
|
||||
layer ?= @layerAdapters['Land'] if child.layerPriority < -40
|
||||
layer ? @layerAdapters['Default']
|
||||
|
||||
addLank: (lank, id=null, layer=null) ->
|
||||
id ?= lank.thang.id
|
||||
console.error 'Lank collision! Already have:', id if @lanks[id]
|
||||
@lanks[id] = lank
|
||||
@lankArray.push lank
|
||||
layer ?= @layerAdapters['Obstacle'] if lank.thang?.spriteName.search(/(dungeon|indoor).wall/i) isnt -1
|
||||
layer ?= @layerForChild lank.sprite, lank
|
||||
layer.addLank lank
|
||||
layer.updateLayerOrder()
|
||||
lank
|
||||
|
||||
createMarks: ->
|
||||
@targetMark = new Mark name: 'target', camera: @camera, layer: @layerAdapters['Ground'], thangType: 'target'
|
||||
@selectionMark = new Mark name: 'selection', camera: @camera, layer: @layerAdapters['Ground'], thangType: 'selection'
|
||||
|
||||
createLankOptions: (options) ->
|
||||
_.extend options, camera: @camera, resolutionFactor: SPRITE_RESOLUTION_FACTOR, groundLayer: @layerAdapters['Ground'], textLayer: @surfaceTextLayer, floatingLayer: @layerAdapters['Floating'], showInvisible: @options.showInvisible
|
||||
|
||||
createIndieLanks: (indieLanks, withWizards) ->
|
||||
unless @indieLanks
|
||||
@indieLanks = []
|
||||
@indieLanks = (@createIndieLank indieLank for indieLank in indieLanks) if indieLanks
|
||||
if withWizards and not @selfWizardLank
|
||||
@selfWizardLank = @createWizardLank thangID: 'My Wizard', isSelf: true, lanks: @lanks
|
||||
|
||||
createIndieLank: (indieLank) ->
|
||||
unless thangType = @thangTypeFor indieLank.thangType
|
||||
console.warn "Need to convert #{indieLank.id}'s ThangType #{indieLank.thangType} to a ThangType reference. Until then, #{indieLank.id} won't show up."
|
||||
return
|
||||
lank = new IndieLank thangType, @createLankOptions {thangID: indieLank.id, pos: indieLank.pos, lanks: @lanks, team: indieLank.team, teamColors: @world.getTeamColors()}
|
||||
@addLank lank, lank.thang.id
|
||||
|
||||
createOpponentWizard: (opponent) ->
|
||||
# TODO: colorize name and cloud by team, colorize wizard by user's color config, level-specific wizard spawn points
|
||||
lank = @createWizardLank thangID: opponent.id, name: opponent.name, codeLanguage: opponent.codeLanguage
|
||||
if not opponent.levelSlug or opponent.levelSlug is 'brawlwood'
|
||||
lank.targetPos = if opponent.team is 'ogres' then {x: 52, y: 52} else {x: 28, y: 28}
|
||||
else if opponent.levelSlug in ['dungeon-arena', 'sky-span']
|
||||
lank.targetPos = if opponent.team is 'ogres' then {x: 72, y: 39} else {x: 9, y: 39}
|
||||
else if opponent.levelSlug is 'criss-cross'
|
||||
lank.targetPos = if opponent.team is 'ogres' then {x: 50, y: 12} else {x: 0, y: 40}
|
||||
else
|
||||
lank.targetPos = if opponent.team is 'ogres' then {x: 52, y: 28} else {x: 20, y: 28}
|
||||
|
||||
createWizardLank: (options) ->
|
||||
lank = new WizardLank @thangTypeFor('Wizard'), @createLankOptions(options)
|
||||
@addLank lank, lank.thang.id, @layerAdapters['Floating']
|
||||
|
||||
onPlayerJoined: (e) ->
|
||||
# Create another WizardLank, unless this player is just me
|
||||
pid = e.player.id
|
||||
return if pid is me.id
|
||||
wiz = @createWizardLank thangID: pid, lanks: @lanks
|
||||
wiz.animateIn()
|
||||
state = e.player.wizard or {}
|
||||
wiz.setInitialState(state.targetPos, @lanks[state.targetLank])
|
||||
|
||||
onPlayerLeft: (e) ->
|
||||
pid = e.player.id
|
||||
@lanks[pid]?.animateOut => @removeLank @lanks[pid]
|
||||
|
||||
onSetDebug: (e) ->
|
||||
return if e.debug is @debug
|
||||
@debug = e.debug
|
||||
lank.setDebug @debug for lank in @lankArray
|
||||
|
||||
onHighlightSprites: (e) ->
|
||||
highlightedIDs = e.thangIDs or []
|
||||
for thangID, lank of @lanks
|
||||
lank.setHighlight? thangID in highlightedIDs, e.delay
|
||||
|
||||
addThangToLanks: (thang, layer=null) ->
|
||||
return console.warn 'Tried to add Thang to the surface it already has:', thang.id if @lanks[thang.id]
|
||||
thangType = _.find @options.thangTypes, (m) ->
|
||||
return false unless m.get('actions') or m.get('raster')
|
||||
return m.get('name') is thang.spriteName
|
||||
thangType ?= _.find @options.thangTypes, (m) -> return m.get('name') is thang.spriteName
|
||||
return console.error "Couldn't find ThangType for", thang unless thangType
|
||||
|
||||
options = @createLankOptions thang: thang
|
||||
options.resolutionFactor = if thangType.get('kind') is 'Floor' then 2 else SPRITE_RESOLUTION_FACTOR
|
||||
lank = new Lank thangType, options
|
||||
@listenTo lank, 'sprite:mouse-up', @onLankMouseUp
|
||||
@addLank lank, null, layer
|
||||
lank.setDebug @debug
|
||||
lank
|
||||
|
||||
removeLank: (lank) ->
|
||||
lank.layer.removeLank(lank)
|
||||
thang = lank.thang
|
||||
delete @lanks[lank.thang.id]
|
||||
@lankArray.splice @lankArray.indexOf(lank), 1
|
||||
@stopListening lank
|
||||
lank.destroy()
|
||||
lank.thang = thang # Keep around so that we know which thang the destroyed thang was for
|
||||
|
||||
updateSounds: ->
|
||||
lank.playSounds() for lank in @lankArray # hmm; doesn't work for lanks which we didn't add yet in adjustLankExistence
|
||||
|
||||
update: (frameChanged) ->
|
||||
@adjustLankExistence() if frameChanged
|
||||
lank.update frameChanged for lank in @lankArray
|
||||
@updateSelection()
|
||||
@layerAdapters['Default'].updateLayerOrder()
|
||||
@cacheObstacles()
|
||||
|
||||
adjustLankExistence: ->
|
||||
# Add anything new, remove anything old, update everything current
|
||||
updatedObstacles = []
|
||||
itemsJustEquipped = []
|
||||
for thang in @world.thangs when thang.exists and thang.pos
|
||||
itemsJustEquipped = itemsJustEquipped.concat @equipNewItems thang
|
||||
if lank = @lanks[thang.id]
|
||||
lank.setThang thang # make sure Lank has latest Thang
|
||||
else
|
||||
lank = @addThangToLanks(thang)
|
||||
Backbone.Mediator.publish 'surface:new-thang-added', thang: thang, sprite: lank
|
||||
updatedObstacles.push lank if lank.sprite.parent is @layerAdapters['Obstacle']
|
||||
lank.playSounds()
|
||||
item.modifyStats() for item in itemsJustEquipped
|
||||
for thangID, lank of @lanks
|
||||
missing = not (lank.notOfThisWorld or @world.thangMap[thangID]?.exists)
|
||||
isObstacle = lank.sprite.parent is @layerAdapters['Obstacle']
|
||||
updatedObstacles.push lank if isObstacle and (missing or lank.hasMoved)
|
||||
lank.hasMoved = false
|
||||
@removeLank lank if missing
|
||||
@cacheObstacles updatedObstacles if updatedObstacles.length and @cachedObstacles
|
||||
|
||||
# mainly for handling selecting thangs from session when the thang is not always in existence
|
||||
if @willSelectThang and @lanks[@willSelectThang[0]]
|
||||
@selectThang @willSelectThang...
|
||||
|
||||
equipNewItems: (thang) ->
|
||||
itemsJustEquipped = []
|
||||
if thang.equip and not thang.equipped
|
||||
thang.equip() # Pretty hacky, but needed since initialize may not be called if we're not running Systems.
|
||||
itemsJustEquipped.push thang
|
||||
if thang.inventoryIDs
|
||||
# Even hackier: these items were only created/equipped during simulation, so we reequip here.
|
||||
for slot, itemID of thang.inventoryIDs
|
||||
item = @world.getThangByID itemID
|
||||
unless item.equipped
|
||||
console.log thang.id, 'equipping', item, 'in', thang.slot, 'Surface-side, but it cannot equip?' unless item.equip
|
||||
item.equip()
|
||||
itemsJustEquipped.push item
|
||||
return itemsJustEquipped
|
||||
|
||||
cacheObstacles: (updatedObstacles=null) ->
|
||||
return if @cachedObstacles and not updatedObstacles
|
||||
wallLanks = (lank for lank in @lankArray when lank.thangType?.get('name').search(/(dungeon|indoor).wall/i) isnt -1)
|
||||
return if _.any (s.stillLoading for s in wallLanks)
|
||||
walls = (lank.thang for lank in wallLanks)
|
||||
@world.calculateBounds()
|
||||
wallGrid = new Grid walls, @world.size()...
|
||||
if updatedObstacles
|
||||
possiblyUpdatedWallLanks = (lank for lank in wallLanks when _.find updatedObstacles, (w2) -> lank is w2 or (Math.abs(lank.thang.pos.x - w2.thang.pos.x) + Math.abs(lank.thang.pos.y - w2.thang.pos.y)) <= 16)
|
||||
else
|
||||
possiblyUpdatedWallLanks = wallLanks
|
||||
#console.log 'updating up to', possiblyUpdatedWallLanks.length, 'of', wallLanks.length, 'wall lanks from updatedObstacles', updatedObstacles
|
||||
for wallLank in possiblyUpdatedWallLanks
|
||||
wallLank.updateActionDirection wallGrid
|
||||
wallLank.lockAction()
|
||||
wallLank.updateScale()
|
||||
wallLank.updatePosition()
|
||||
#console.log @wallGrid.toString()
|
||||
@cachedObstacles = true
|
||||
|
||||
lankFor: (thangID) -> @lanks[thangID]
|
||||
|
||||
onNewWorld: (e) ->
|
||||
@world = @options.world = e.world
|
||||
|
||||
play: ->
|
||||
lank.play() for lank in @lankArray
|
||||
@selectionMark?.play()
|
||||
@targetMark?.play()
|
||||
|
||||
stop: ->
|
||||
lank.stop() for lank in @lankArray
|
||||
@selectionMark?.stop()
|
||||
@targetMark?.stop()
|
||||
|
||||
# Selection
|
||||
|
||||
onSuppressSelectionSounds: (e) -> @suppressSelectionSounds = e.suppress
|
||||
onSetLockSelect: (e) -> @selectLocked = e.lock
|
||||
onLevelRestarted: (e) ->
|
||||
@selectLocked = false
|
||||
@selectLank e, null
|
||||
|
||||
onSelectSprite: (e) ->
|
||||
@selectThang e.thangID, e.spellName
|
||||
|
||||
onCameraDragged: ->
|
||||
@dragged += 1
|
||||
|
||||
onLankMouseUp: (e) ->
|
||||
return if key.shift #and @options.choosing
|
||||
return @dragged = 0 if @dragged > 3
|
||||
@dragged = 0
|
||||
lank = if e.sprite?.thang?.isSelectable then e.sprite else null
|
||||
return if @flagCursorLank and lank?.thangType.get('name') is 'Flag'
|
||||
@selectLank e, lank
|
||||
|
||||
onStageMouseDown: (e) ->
|
||||
return if key.shift #and @options.choosing
|
||||
@selectLank e if e.onBackground
|
||||
|
||||
selectThang: (thangID, spellName=null, treemaThangSelected = null) ->
|
||||
return @willSelectThang = [thangID, spellName] unless @lanks[thangID]
|
||||
@selectLank null, @lanks[thangID], spellName, treemaThangSelected
|
||||
|
||||
selectLank: (e, lank=null, spellName=null, treemaThangSelected = null) ->
|
||||
return if e and (@disabled or @selectLocked) # Ignore clicks for selection/panning/wizard movement while disabled or select is locked
|
||||
worldPos = lank?.thang?.pos
|
||||
worldPos ?= @camera.screenToWorld {x: e.originalEvent.rawX, y: e.originalEvent.rawY} if e?.originalEvent
|
||||
if worldPos and (@options.navigateToSelection or not lank or treemaThangSelected) and e?.originalEvent?.nativeEvent?.which isnt 3
|
||||
@camera.zoomTo(lank?.sprite or @camera.worldToSurface(worldPos), @camera.zoom, 1000, true)
|
||||
lank = null if @options.choosing # Don't select lanks while choosing
|
||||
if lank isnt @selectedLank
|
||||
@selectedLank?.selected = false
|
||||
lank?.selected = true
|
||||
@selectedLank = lank
|
||||
alive = lank and not (lank.thang.health < 0)
|
||||
|
||||
Backbone.Mediator.publish 'surface:sprite-selected',
|
||||
thang: if lank then lank.thang else null
|
||||
sprite: lank
|
||||
spellName: spellName ? e?.spellName
|
||||
originalEvent: e
|
||||
worldPos: worldPos
|
||||
|
||||
@willSelectThang = null if lank # Now that we've done a real selection, don't reselect some other Thang later.
|
||||
|
||||
if alive and not @suppressSelectionSounds
|
||||
instance = lank.playSound 'selected'
|
||||
if instance?.playState is 'playSucceeded'
|
||||
Backbone.Mediator.publish 'sprite:thang-began-talking', thang: lank?.thang
|
||||
instance.addEventListener 'complete', ->
|
||||
Backbone.Mediator.publish 'sprite:thang-finished-talking', thang: lank?.thang
|
||||
|
||||
onFlagColorSelected: (e) ->
|
||||
@removeLank @flagCursorLank if @flagCursorLank
|
||||
@flagCursorLank = null
|
||||
for flagLank in @lankArray when flagLank.thangType.get('name') is 'Flag'
|
||||
flagLank.sprite.cursor = if e.color then 'crosshair' else 'pointer'
|
||||
return unless e.color
|
||||
@flagCursorLank = new FlagLank @thangTypeFor('Flag'), @createLankOptions(thangID: 'Flag Cursor', color: e.color, team: me.team, isCursor: true, pos: e.pos)
|
||||
@addLank @flagCursorLank, @flagCursorLank.thang.id, @layerAdapters['Floating']
|
||||
|
||||
onFlagUpdated: (e) ->
|
||||
return unless e.active
|
||||
pendingFlag = new FlagLank @thangTypeFor('Flag'), @createLankOptions(thangID: 'Pending Flag ' + Math.random(), color: e.color, team: e.team, isCursor: false, pos: e.pos)
|
||||
@addLank pendingFlag, pendingFlag.thang.id, @layerAdapters['Floating']
|
||||
@pendingFlags.push pendingFlag
|
||||
|
||||
onFlagAppeared: (e) ->
|
||||
# Remove the pending flag that matches this one's color/team/position, and any color/team matches placed earlier.
|
||||
t1 = e.sprite.thang
|
||||
pending = (@pendingFlags ? []).slice()
|
||||
foundExactMatch = false
|
||||
for i in [pending.length - 1 .. 0] by -1
|
||||
pendingFlag = pending[i]
|
||||
t2 = pendingFlag.thang
|
||||
matchedType = t1.color is t2.color and t1.team is t2.team
|
||||
matched = matchedType and (foundExactMatch or Math.abs(t1.pos.x - t2.pos.x) < 0.00001 and Math.abs(t1.pos.y - t2.pos.y) < 0.00001)
|
||||
if matched
|
||||
foundExactMatch = true
|
||||
@pendingFlags.splice(i, 1)
|
||||
@removeLank pendingFlag
|
||||
e.sprite.sprite.cursor = if @flagCursorLank then 'crosshair' else 'pointer'
|
||||
null
|
||||
|
||||
onRemoveSelectedFlag: (e) ->
|
||||
# Remove the selected lank if it's a flag, or any flag of the given color if a color is given.
|
||||
flagLank = _.find [@selectedLank].concat(@lankArray), (lank) ->
|
||||
lank and lank.thangType.get('name') is 'Flag' and lank.thang.team is me.team and (lank.thang.color is e.color or not e.color) and not lank.notOfThisWorld
|
||||
return unless flagLank
|
||||
Backbone.Mediator.publish 'surface:remove-flag', color: flagLank.thang.color
|
||||
|
||||
# Marks
|
||||
|
||||
updateSelection: ->
|
||||
if @selectedLank?.thang and (not @selectedLank.thang.exists or not @world.getThangByID @selectedLank.thang.id)
|
||||
thangID = @selectedLank.thang.id
|
||||
@selectedLank = null # Don't actually trigger deselection, but remove the selected lank.
|
||||
@selectionMark?.toggle false
|
||||
@willSelectThang = [thangID, null]
|
||||
@updateTarget()
|
||||
return unless @selectionMark
|
||||
@selectedLank = null if @selectedLank and (@selectedLank.destroyed or not @selectedLank.thang)
|
||||
# The selection mark should be on the ground layer, unless we're not a normal lank (like a wall), in which case we'll place it higher so we can see it.
|
||||
if @selectedLank and @selectedLank.sprite.parent isnt @layerAdapters.Default.container
|
||||
@selectionMark.setLayer @layerAdapters.Default
|
||||
else if @selectedLank
|
||||
@selectionMark.setLayer @layerAdapters.Ground
|
||||
@selectionMark.toggle @selectedLank?
|
||||
@selectionMark.setLank @selectedLank
|
||||
@selectionMark.update()
|
||||
|
||||
updateTarget: ->
|
||||
return unless @targetMark
|
||||
thang = @selectedLank?.thang
|
||||
target = thang?.target
|
||||
targetPos = thang?.targetPos
|
||||
targetPos = null if targetPos?.isZero?() # Null targetPos get serialized as (0, 0, 0)
|
||||
@targetMark.setLank if target then @lanks[target.id] else null
|
||||
@targetMark.toggle @targetMark.lank or targetPos
|
||||
@targetMark.update if targetPos then @camera.worldToSurface targetPos else null
|
|
@ -44,7 +44,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
|||
resolutionFactor: SPRITE_RESOLUTION_FACTOR
|
||||
defaultActions: ['idle', 'die', 'move', 'move', 'attack']
|
||||
numThingsLoading: 0
|
||||
cocoSprites: null
|
||||
lanks: null
|
||||
spriteSheet: null
|
||||
container: null
|
||||
customGraphics: null
|
||||
|
@ -70,7 +70,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
|||
@container = new createjs.SpriteContainer(@spriteSheet)
|
||||
@actionRenderState = {}
|
||||
@toRenderBundles = []
|
||||
@cocoSprites = []
|
||||
@lanks = []
|
||||
@initializing = false
|
||||
|
||||
else
|
||||
|
@ -91,13 +91,13 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
|||
# TODO: remove this z stuff
|
||||
az = a.z or 1000
|
||||
bz = b.z or 1000
|
||||
if aSprite = a.sprite
|
||||
if aThang = aSprite.thang
|
||||
if aLank = a.lank
|
||||
if aThang = aLank.thang
|
||||
aPos = aThang.pos
|
||||
if aThang.health < 0
|
||||
--az
|
||||
if bSprite = b.sprite
|
||||
if bThang = bSprite.thang
|
||||
if bLank = b.lank
|
||||
if bThang = bLank.thang
|
||||
bPos = bThang.pos
|
||||
if bThang.health < 0
|
||||
--bz
|
||||
|
@ -142,27 +142,27 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
|||
|
||||
#- Adding, removing children for WebGL layers.
|
||||
|
||||
addCocoSprite: (cocoSprite) ->
|
||||
addLank: (lank) ->
|
||||
# TODO: Move this into the production DB rather than setting it dynamically.
|
||||
if cocoSprite.thangType?.get('name') is 'Highlight'
|
||||
cocoSprite.thangType.set('spriteType', 'segmented')
|
||||
cocoSprite.options.resolutionFactor = @resolutionFactor
|
||||
if cocoSprite.layer
|
||||
console.warn 'CocoSprite being re-added to a layer?'
|
||||
if lank.thangType?.get('name') is 'Highlight'
|
||||
lank.thangType.set('spriteType', 'segmented')
|
||||
lank.options.resolutionFactor = @resolutionFactor
|
||||
if lank.layer
|
||||
console.warn 'Lank being re-added to a layer?'
|
||||
|
||||
cocoSprite.layer = @
|
||||
@listenTo(cocoSprite, 'action-needs-render', @onActionNeedsRender)
|
||||
@cocoSprites.push cocoSprite
|
||||
@loadThangType(cocoSprite.thangType)
|
||||
@addDefaultActionsToRender(cocoSprite)
|
||||
@setImageObjectToCocoSprite(cocoSprite)
|
||||
lank.layer = @
|
||||
@listenTo(lank, 'action-needs-render', @onActionNeedsRender)
|
||||
@lanks.push lank
|
||||
@loadThangType(lank.thangType)
|
||||
@addDefaultActionsToRender(lank)
|
||||
@setSpriteToLank(lank)
|
||||
@updateLayerOrder()
|
||||
cocoSprite.addHealthBar()
|
||||
lank.addHealthBar()
|
||||
|
||||
removeCocoSprite: (cocoSprite) ->
|
||||
@stopListening(cocoSprite)
|
||||
@container.removeChild cocoSprite.imageObject
|
||||
@cocoSprites = _.without @cocoSprites, cocoSprite
|
||||
removeLank: (lank) ->
|
||||
@stopListening(lank)
|
||||
@container.removeChild lank.sprite
|
||||
@lanks = _.without @lanks, lank
|
||||
|
||||
#- Loading network resources dynamically
|
||||
|
||||
|
@ -180,24 +180,24 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
|||
somethingLoaded: (thangType) ->
|
||||
@numThingsLoading--
|
||||
@loadThangType(thangType) # might need to load the raster image object
|
||||
for cocoSprite in @cocoSprites
|
||||
if cocoSprite.thangType is thangType
|
||||
@addDefaultActionsToRender(cocoSprite)
|
||||
for lank in @lanks
|
||||
if lank.thangType is thangType
|
||||
@addDefaultActionsToRender(lank)
|
||||
@renderNewSpriteSheet()
|
||||
|
||||
#- Adding to the list of things we need to render
|
||||
|
||||
onActionNeedsRender: (cocoSprite, action) ->
|
||||
@upsertActionToRender(cocoSprite.thangType, action.name, cocoSprite.options.colorConfig)
|
||||
onActionNeedsRender: (lank, action) ->
|
||||
@upsertActionToRender(lank.thangType, action.name, lank.options.colorConfig)
|
||||
|
||||
addDefaultActionsToRender: (cocoSprite) ->
|
||||
addDefaultActionsToRender: (lank) ->
|
||||
needToRender = false
|
||||
if cocoSprite.thangType.get('raster')
|
||||
@upsertActionToRender(cocoSprite.thangType)
|
||||
if lank.thangType.get('raster')
|
||||
@upsertActionToRender(lank.thangType)
|
||||
else
|
||||
for action in _.values(cocoSprite.thangType.getActions())
|
||||
for action in _.values(lank.thangType.getActions())
|
||||
continue unless _.any @defaultActions, (prefix) -> action.name.startsWith(prefix)
|
||||
@upsertActionToRender(cocoSprite.thangType, action.name, cocoSprite.options.colorConfig)
|
||||
@upsertActionToRender(lank.thangType, action.name, lank.options.colorConfig)
|
||||
|
||||
upsertActionToRender: (thangType, actionName, colorConfig) ->
|
||||
groupKey = @renderGroupingKey(thangType, actionName, colorConfig)
|
||||
|
@ -279,10 +279,10 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
|||
@spriteSheet.resolutionFactor = @resolutionFactor
|
||||
oldLayer = @container
|
||||
@container = new createjs.SpriteContainer(@spriteSheet)
|
||||
for cocoSprite in @cocoSprites
|
||||
console.log 'zombie sprite found on layer', @name if cocoSprite.destroyed
|
||||
continue if cocoSprite.destroyed
|
||||
@setImageObjectToCocoSprite(cocoSprite)
|
||||
for lank in @lanks
|
||||
console.log 'zombie sprite found on layer', @name if lank.destroyed
|
||||
continue if lank.destroyed
|
||||
@setSpriteToLank(lank)
|
||||
for prop in ['scaleX', 'scaleY', 'regX', 'regY']
|
||||
@container[prop] = oldLayer[prop]
|
||||
if parent = oldLayer.parent
|
||||
|
@ -291,11 +291,19 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
|||
parent.addChildAt(@container, index)
|
||||
@camera?.updateZoom(true)
|
||||
@updateLayerOrder()
|
||||
for cocoSprite in @cocoSprites
|
||||
cocoSprite.options.resolutionFactor = @resolutionFactor
|
||||
cocoSprite.updateScale()
|
||||
cocoSprite.updateRotation()
|
||||
for lank in @lanks
|
||||
lank.options.resolutionFactor = @resolutionFactor
|
||||
lank.updateScale()
|
||||
lank.updateRotation()
|
||||
@trigger 'new-spritesheet'
|
||||
|
||||
resetSpriteSheet: ->
|
||||
@removeLank(lank) for lank in @lanks.slice(0)
|
||||
@toRenderBundles = []
|
||||
@actionRenderState = {}
|
||||
@initializing = true
|
||||
@spriteSheet = @_renderNewSpriteSheet(false) # builds an empty spritesheet
|
||||
@initializing = false
|
||||
|
||||
#- Placeholder
|
||||
|
||||
|
@ -326,6 +334,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
|||
#- Rendering containers for segmented thang types
|
||||
|
||||
renderSegmentedThangType: (thangType, colorConfig, actionNames, spriteSheetBuilder) ->
|
||||
console.log 'rendering segmented thang type'
|
||||
containersToRender = {}
|
||||
for actionName in actionNames
|
||||
action = _.find(thangType.getActions(), {name: actionName})
|
||||
|
@ -356,6 +365,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
|||
#- Rendering sprite sheets for singular thang types
|
||||
|
||||
renderSingularThangType: (thangType, colorConfig, actionNames, spriteSheetBuilder) ->
|
||||
console.log 'rendering singular thang type'
|
||||
actionObjects = _.values(thangType.getActions())
|
||||
animationActions = []
|
||||
for a in actionObjects
|
||||
|
@ -441,10 +451,10 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
|||
frame = spriteSheetBuilder.addFrame(bm, null, scale)
|
||||
spriteSheetBuilder.addAnimation(@renderGroupingKey(thangType), [frame], false)
|
||||
|
||||
#- Distributing new Segmented/Singular/RasterSprites to CocoSprites
|
||||
#- Distributing new Segmented/Singular/RasterSprites to Lanks
|
||||
|
||||
setImageObjectToCocoSprite: (cocoSprite) ->
|
||||
if not cocoSprite.thangType.isFullyLoaded()
|
||||
setSpriteToLank: (lank) ->
|
||||
if not lank.thangType.isFullyLoaded()
|
||||
# just give a placeholder
|
||||
sprite = new createjs.Sprite(@spriteSheet)
|
||||
sprite.gotoAndStop(0)
|
||||
|
@ -453,26 +463,26 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
|||
sprite.regY = @resolutionFactor * SPRITE_PLACEHOLDER_WIDTH
|
||||
sprite.baseScaleX = sprite.baseScaleY = sprite.scaleX = sprite.scaleY = 10 / (@resolutionFactor * SPRITE_PLACEHOLDER_WIDTH)
|
||||
|
||||
else if cocoSprite.thangType.get('raster')
|
||||
else if lank.thangType.get('raster')
|
||||
sprite = new createjs.Sprite(@spriteSheet)
|
||||
scale = cocoSprite.thangType.get('scale') or 1
|
||||
reg = cocoSprite.getOffset 'registration'
|
||||
scale = lank.thangType.get('scale') or 1
|
||||
reg = lank.getOffset 'registration'
|
||||
sprite.regX = -reg.x * scale
|
||||
sprite.regY = -reg.y * scale
|
||||
sprite.gotoAndStop(@renderGroupingKey(cocoSprite.thangType))
|
||||
sprite.gotoAndStop(@renderGroupingKey(lank.thangType))
|
||||
sprite.baseScaleX = sprite.baseScaleY = 1
|
||||
|
||||
else
|
||||
SpriteClass = if (cocoSprite.thangType.get('spriteType') or @defaultSpriteType) is 'segmented' then SegmentedSprite else SingularSprite
|
||||
prefix = @renderGroupingKey(cocoSprite.thangType, null, cocoSprite.options.colorConfig) + '.'
|
||||
sprite = new SpriteClass(@spriteSheet, cocoSprite.thangType, prefix, @resolutionFactor)
|
||||
SpriteClass = if (lank.thangType.get('spriteType') or @defaultSpriteType) is 'segmented' then SegmentedSprite else SingularSprite
|
||||
prefix = @renderGroupingKey(lank.thangType, null, lank.options.colorConfig) + '.'
|
||||
sprite = new SpriteClass(@spriteSheet, lank.thangType, prefix, @resolutionFactor)
|
||||
|
||||
sprite.sprite = cocoSprite
|
||||
sprite.lank = lank
|
||||
sprite.camera = @camera
|
||||
sprite.layerPriority = cocoSprite.thang?.layerPriority ? cocoSprite.thangType.get 'layerPriority'
|
||||
sprite.name = cocoSprite.thang?.spriteName or cocoSprite.thangType.get 'name'
|
||||
cocoSprite.setImageObject(sprite)
|
||||
cocoSprite.update(true)
|
||||
sprite.layerPriority = lank.thang?.layerPriority ? lank.thangType.get 'layerPriority'
|
||||
sprite.name = lank.thang?.spriteName or lank.thangType.get 'name'
|
||||
lank.setSprite(sprite)
|
||||
lank.update(true)
|
||||
@container.addChild(sprite)
|
||||
|
||||
renderGroupingKey: (thangType, grouping, colorConfig) ->
|
||||
|
|
|
@ -11,7 +11,7 @@ module.exports = class Mark extends CocoClass
|
|||
super()
|
||||
options ?= {}
|
||||
@name = options.name
|
||||
@sprite = options.sprite
|
||||
@lank = options.lank
|
||||
@camera = options.camera
|
||||
@layer = options.layer
|
||||
@thangType = options.thangType
|
||||
|
@ -22,46 +22,46 @@ module.exports = class Mark extends CocoClass
|
|||
@build()
|
||||
|
||||
destroy: ->
|
||||
createjs.Tween.removeTweens @mark if @mark
|
||||
@mark?.parent?.removeChild @mark
|
||||
if @markSprite
|
||||
@layer.removeCocoSprite(@markSprite)
|
||||
@markSprite.destroy()
|
||||
@sprite = null
|
||||
createjs.Tween.removeTweens @sprite if @sprite
|
||||
@sprite?.parent?.removeChild @sprite
|
||||
if @markLank
|
||||
@layer.removeLank(@markLank)
|
||||
@markLank.destroy()
|
||||
@lank = null
|
||||
super()
|
||||
|
||||
toString: -> "<Mark #{@name}: Sprite #{@sprite?.thang?.id ? 'None'}>"
|
||||
toString: -> "<Mark #{@name}: Sprite #{@lank?.thang?.id ? 'None'}>"
|
||||
|
||||
onLayerMadeSpriteSheet: ->
|
||||
return unless @mark
|
||||
return @update() if @markSprite
|
||||
return unless @sprite
|
||||
return @update() if @markLank
|
||||
# need to update the mark display object manually...
|
||||
@mark = null
|
||||
@sprite = null
|
||||
@build()
|
||||
@layer.addChild @mark
|
||||
@layer.addChild @sprite
|
||||
@layer.updateLayerOrder()
|
||||
|
||||
toggle: (to) ->
|
||||
to = !!to
|
||||
return @ if to is @on
|
||||
return @toggleTo = to unless @mark
|
||||
return @toggleTo = to unless @sprite
|
||||
@on = to
|
||||
delete @toggleTo
|
||||
if @on
|
||||
if @markSprite
|
||||
@layer.addCocoSprite(@markSprite)
|
||||
if @markLank
|
||||
@layer.addLank(@markLank)
|
||||
else
|
||||
@layer.addChild @mark
|
||||
@layer.addChild @sprite
|
||||
@layer.updateLayerOrder()
|
||||
else
|
||||
if @markSprite
|
||||
@layer.removeCocoSprite(@markSprite)
|
||||
if @markLank
|
||||
@layer.removeLank(@markLank)
|
||||
else
|
||||
@layer.removeChild @mark
|
||||
@layer.removeChild @sprite
|
||||
if @highlightTween
|
||||
@highlightDelay = @highlightTween = null
|
||||
createjs.Tween.removeTweens @mark
|
||||
@mark.visible = true
|
||||
createjs.Tween.removeTweens @sprite
|
||||
@sprite.visible = true
|
||||
@
|
||||
|
||||
setLayer: (layer) ->
|
||||
|
@ -71,34 +71,34 @@ module.exports = class Mark extends CocoClass
|
|||
@layer = layer
|
||||
@toggle true if wasOn
|
||||
|
||||
setSprite: (sprite) ->
|
||||
return if sprite is @sprite
|
||||
@sprite = sprite
|
||||
setLank: (lank) ->
|
||||
return if lank is @lank
|
||||
@lank = lank
|
||||
@build()
|
||||
@
|
||||
|
||||
build: ->
|
||||
unless @mark
|
||||
unless @sprite
|
||||
if @name is 'bounds' then @buildBounds()
|
||||
else if @name is 'shadow' then @buildShadow()
|
||||
else if @name is 'debug' then @buildDebug()
|
||||
else if @name.match(/.+(Range|Distance|Radius)$/) then @buildRadius(@name)
|
||||
else if @thangType then @buildSprite()
|
||||
else console.error 'Don\'t know how to build mark for', @name
|
||||
@mark?.mouseEnabled = false
|
||||
@sprite?.mouseEnabled = false
|
||||
@
|
||||
|
||||
buildBounds: ->
|
||||
@mark = new createjs.Container()
|
||||
@mark.mouseChildren = false
|
||||
style = @sprite.thang.drawsBoundsStyle
|
||||
@drawsBoundsIndex = @sprite.thang.drawsBoundsIndex
|
||||
return if style is 'corner-text' and @sprite.thang.world.age is 0
|
||||
@sprite = new createjs.Container()
|
||||
@sprite.mouseChildren = false
|
||||
style = @lank.thang.drawsBoundsStyle
|
||||
@drawsBoundsIndex = @lank.thang.drawsBoundsIndex
|
||||
return if style is 'corner-text' and @lank.thang.world.age is 0
|
||||
|
||||
# Confusingly make some semi-random colors that'll be consistent based on the drawsBoundsIndex
|
||||
colors = (128 + Math.floor(('0.'+Math.sin(3 * @drawsBoundsIndex + i).toString().substr(6)) * 128) for i in [1 ... 4])
|
||||
color = "rgba(#{colors[0]}, #{colors[1]}, #{colors[2]}, 0.5)"
|
||||
[w, h] = [@sprite.thang.width * Camera.PPM, @sprite.thang.height * Camera.PPM * @camera.y2x]
|
||||
[w, h] = [@lank.thang.width * Camera.PPM, @lank.thang.height * Camera.PPM * @camera.y2x]
|
||||
|
||||
if style in ['border-text', 'corner-text']
|
||||
@drawsBoundsBorderShape = shape = new createjs.Shape()
|
||||
|
@ -108,37 +108,37 @@ module.exports = class Mark extends CocoClass
|
|||
shape.graphics.beginFill color.replace('0.5', '0.25')
|
||||
else
|
||||
shape.graphics.beginFill color
|
||||
if @sprite.thang.shape in ['ellipsoid', 'disc']
|
||||
if @lank.thang.shape in ['ellipsoid', 'disc']
|
||||
shape.drawEllipse 0, 0, w, h
|
||||
else
|
||||
shape.graphics.drawRect -w / 2, -h / 2, w, h
|
||||
shape.graphics.endStroke()
|
||||
shape.graphics.endFill()
|
||||
@mark.addChild shape
|
||||
@sprite.addChild shape
|
||||
|
||||
if style is 'border-text'
|
||||
text = new createjs.Text '' + @drawsBoundsIndex, '20px Arial', color.replace('0.5', '1')
|
||||
text.regX = text.getMeasuredWidth() / 2
|
||||
text.regY = text.getMeasuredHeight() / 2
|
||||
text.shadow = new createjs.Shadow('#000000', 1, 1, 0)
|
||||
@mark.addChild text
|
||||
@sprite.addChild text
|
||||
else if style is 'corner-text'
|
||||
return if @sprite.thang.world.age is 0
|
||||
return if @lank.thang.world.age is 0
|
||||
letter = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[@drawsBoundsIndex % 26]
|
||||
text = new createjs.Text letter, '14px Arial', '#333333' # color.replace('0.5', '1')
|
||||
text.x = -w / 2 + 2
|
||||
text.y = -h / 2 + 2
|
||||
@mark.addChild text
|
||||
@sprite.addChild text
|
||||
else
|
||||
console.warn @sprite.thang.id, 'didn\'t know how to draw bounds style:', style
|
||||
console.warn @lank.thang.id, 'didn\'t know how to draw bounds style:', style
|
||||
|
||||
if w > 0 and h > 0 and style is 'border-text'
|
||||
@mark.cache -w / 2, -h / 2, w, h, 2
|
||||
@lastWidth = @sprite.thang.width
|
||||
@lastHeight = @sprite.thang.height
|
||||
@sprite.cache -w / 2, -h / 2, w, h, 2
|
||||
@lastWidth = @lank.thang.width
|
||||
@lastHeight = @lank.thang.height
|
||||
|
||||
buildShadow: ->
|
||||
shapeName = if @sprite.thang.shape in ['ellipsoid', 'disc'] then 'ellipse' else 'rect'
|
||||
shapeName = if @lank.thang.shape in ['ellipsoid', 'disc'] then 'ellipse' else 'rect'
|
||||
key = "#{shapeName}-shadow"
|
||||
SHADOW_SIZE = 10
|
||||
unless key in @layer.spriteSheet.getAnimations()
|
||||
|
@ -151,21 +151,21 @@ module.exports = class Mark extends CocoClass
|
|||
shape.graphics.drawRect bounds...
|
||||
shape.graphics.endFill()
|
||||
@layer.addCustomGraphic(key, shape, bounds)
|
||||
alpha = @sprite.thang?.alpha ? 1
|
||||
width = (@sprite.thang?.width ? 0) + 0.5
|
||||
height = (@sprite.thang?.height ? 0) + 0.5
|
||||
alpha = @lank.thang?.alpha ? 1
|
||||
width = (@lank.thang?.width ? 0) + 0.5
|
||||
height = (@lank.thang?.height ? 0) + 0.5
|
||||
longest = Math.max width, height
|
||||
actualLongest = @sprite.thangType.get('shadow') ? longest
|
||||
actualLongest = @lank.thangType.get('shadow') ? longest
|
||||
width = width * actualLongest / longest
|
||||
height = height * actualLongest / longest
|
||||
width *= Camera.PPM
|
||||
height *= Camera.PPM * @camera.y2x # TODO: doesn't work with rotation
|
||||
@mark = new createjs.Sprite(@layer.spriteSheet)
|
||||
@mark.gotoAndStop(key)
|
||||
@mark.mouseEnabled = false
|
||||
@mark.alpha = alpha
|
||||
@baseScaleX = @mark.scaleX = width / (@layer.resolutionFactor * SHADOW_SIZE)
|
||||
@baseScaleY = @mark.scaleY = height / (@layer.resolutionFactor * SHADOW_SIZE)
|
||||
@sprite = new createjs.Sprite(@layer.spriteSheet)
|
||||
@sprite.gotoAndStop(key)
|
||||
@sprite.mouseEnabled = false
|
||||
@sprite.alpha = alpha
|
||||
@baseScaleX = @sprite.scaleX = width / (@layer.resolutionFactor * SHADOW_SIZE)
|
||||
@baseScaleY = @sprite.scaleY = height / (@layer.resolutionFactor * SHADOW_SIZE)
|
||||
|
||||
buildRadius: (range) ->
|
||||
alpha = 0.15
|
||||
|
@ -183,36 +183,36 @@ module.exports = class Mark extends CocoClass
|
|||
]
|
||||
|
||||
# Find the index of this range, to find the next-smallest radius
|
||||
rangeNames = @sprite.ranges.map((range, index) ->
|
||||
rangeNames = @lank.ranges.map((range, index) ->
|
||||
range['name']
|
||||
)
|
||||
i = rangeNames.indexOf(range)
|
||||
|
||||
@mark = new createjs.Shape()
|
||||
@sprite = new createjs.Shape()
|
||||
|
||||
fillColor = colors[range] ? extraColors[i]
|
||||
@mark.graphics.beginFill fillColor
|
||||
@sprite.graphics.beginFill fillColor
|
||||
|
||||
# Draw the outer circle
|
||||
@mark.graphics.drawCircle 0, 0, @sprite.thang[range] * Camera.PPM
|
||||
@sprite.graphics.drawCircle 0, 0, @lank.thang[range] * Camera.PPM
|
||||
|
||||
# Cut out the hollow part if necessary
|
||||
if i+1 < @sprite.ranges.length
|
||||
@mark.graphics.arc 0, 0, @sprite.ranges[i+1]['radius'], Math.PI*2, 0, true
|
||||
if i+1 < @lank.ranges.length
|
||||
@sprite.graphics.arc 0, 0, @lank.ranges[i+1]['radius'], Math.PI*2, 0, true
|
||||
|
||||
@mark.graphics.endFill()
|
||||
@sprite.graphics.endFill()
|
||||
|
||||
strokeColor = fillColor.replace '' + alpha, '0.75'
|
||||
@mark.graphics.setStrokeStyle 2
|
||||
@mark.graphics.beginStroke strokeColor
|
||||
@mark.graphics.arc 0, 0, @sprite.thang[range] * Camera.PPM, Math.PI*2, 0, true
|
||||
@mark.graphics.endStroke()
|
||||
@sprite.graphics.setStrokeStyle 2
|
||||
@sprite.graphics.beginStroke strokeColor
|
||||
@sprite.graphics.arc 0, 0, @lank.thang[range] * Camera.PPM, Math.PI*2, 0, true
|
||||
@sprite.graphics.endStroke()
|
||||
|
||||
# Add perspective
|
||||
@mark.scaleY *= @camera.y2x
|
||||
@sprite.scaleY *= @camera.y2x
|
||||
|
||||
buildDebug: ->
|
||||
shapeName = if @sprite.thang.shape in ['ellipsoid', 'disc'] then 'ellipse' else 'rect'
|
||||
shapeName = if @lank.thang.shape in ['ellipsoid', 'disc'] then 'ellipse' else 'rect'
|
||||
key = "#{shapeName}-debug"
|
||||
DEBUG_SIZE = 10
|
||||
unless key in @layer.spriteSheet.getAnimations()
|
||||
|
@ -226,12 +226,12 @@ module.exports = class Mark extends CocoClass
|
|||
shape.graphics.endFill()
|
||||
@layer.addCustomGraphic(key, shape, bounds)
|
||||
|
||||
@mark = new createjs.Sprite(@layer.spriteSheet)
|
||||
@mark.gotoAndStop(key)
|
||||
@sprite = new createjs.Sprite(@layer.spriteSheet)
|
||||
@sprite.gotoAndStop(key)
|
||||
PX = 3
|
||||
[w, h] = [Math.max(PX, @sprite.thang.width * Camera.PPM), Math.max(PX, @sprite.thang.height * Camera.PPM) * @camera.y2x] # TODO: doesn't work with rotation
|
||||
@mark.scaleX = w / (@layer.resolutionFactor * DEBUG_SIZE)
|
||||
@mark.scaleY = h / (@layer.resolutionFactor * DEBUG_SIZE)
|
||||
[w, h] = [Math.max(PX, @lank.thang.width * Camera.PPM), Math.max(PX, @lank.thang.height * Camera.PPM) * @camera.y2x] # TODO: doesn't work with rotation
|
||||
@sprite.scaleX = w / (@layer.resolutionFactor * DEBUG_SIZE)
|
||||
@sprite.scaleY = h / (@layer.resolutionFactor * DEBUG_SIZE)
|
||||
|
||||
buildSprite: ->
|
||||
if _.isString @thangType
|
||||
|
@ -240,13 +240,13 @@ module.exports = class Mark extends CocoClass
|
|||
@thangType = thangType
|
||||
|
||||
return @listenToOnce(@thangType, 'sync', @onLoadedThangType) if not @thangType.loaded
|
||||
CocoSprite = require './CocoSprite'
|
||||
Lank = require './Lank'
|
||||
# don't bother with making these render async for now, but maybe later for fun and more complexity of code
|
||||
markSprite = new CocoSprite @thangType
|
||||
markSprite.queueAction 'idle'
|
||||
@mark = markSprite.imageObject
|
||||
@markSprite = markSprite
|
||||
@listenTo @markSprite, 'new-image-object', (@mark) ->
|
||||
markLank = new Lank @thangType
|
||||
markLank.queueAction 'idle'
|
||||
@sprite = markLank.sprite
|
||||
@markLank = markLank
|
||||
@listenTo @markLank, 'new-sprite', (@sprite) ->
|
||||
|
||||
loadThangType: ->
|
||||
name = @thangType
|
||||
|
@ -262,83 +262,83 @@ module.exports = class Mark extends CocoClass
|
|||
Backbone.Mediator.publish 'sprite:loaded', {sprite: @}
|
||||
|
||||
update: (pos=null) ->
|
||||
return false unless @on and @mark
|
||||
return false if @sprite? and not @sprite.thangType.isFullyLoaded()
|
||||
@mark.visible = not @hidden
|
||||
return false unless @on and @sprite
|
||||
return false if @lank? and not @lank.thangType.isFullyLoaded()
|
||||
@sprite.visible = not @hidden
|
||||
@updatePosition pos
|
||||
@updateRotation()
|
||||
@updateScale()
|
||||
if @name is 'highlight' and @highlightDelay and not @highlightTween
|
||||
@mark.visible = false
|
||||
@highlightTween = createjs.Tween.get(@mark).to({}, @highlightDelay).call =>
|
||||
@mark.visible = true
|
||||
@sprite.visible = false
|
||||
@highlightTween = createjs.Tween.get(@sprite).to({}, @highlightDelay).call =>
|
||||
@sprite.visible = true
|
||||
@highlightDelay = @highlightTween = null
|
||||
@updateAlpha @alpha if @name in ['shadow', 'bounds']
|
||||
true
|
||||
|
||||
updatePosition: (pos) ->
|
||||
if @sprite?.thang and @name in ['shadow', 'debug', 'target', 'selection', 'repair']
|
||||
pos = @camera.worldToSurface x: @sprite.thang.pos.x, y: @sprite.thang.pos.y
|
||||
if @lank?.thang and @name in ['shadow', 'debug', 'target', 'selection', 'repair']
|
||||
pos = @camera.worldToSurface x: @lank.thang.pos.x, y: @lank.thang.pos.y
|
||||
else
|
||||
pos ?= @sprite?.imageObject
|
||||
pos ?= @lank?.sprite
|
||||
return unless pos
|
||||
@mark.x = pos.x
|
||||
@mark.y = pos.y
|
||||
@sprite.x = pos.x
|
||||
@sprite.y = pos.y
|
||||
if @statusEffect or @name is 'highlight'
|
||||
offset = @sprite.getOffset 'aboveHead'
|
||||
@mark.x += offset.x
|
||||
@mark.y += offset.y
|
||||
@mark.y -= 3 if @statusEffect
|
||||
offset = @lank.getOffset 'aboveHead'
|
||||
@sprite.x += offset.x
|
||||
@sprite.y += offset.y
|
||||
@sprite.y -= 3 if @statusEffect
|
||||
|
||||
updateAlpha: (@alpha) ->
|
||||
return if not @mark or @name is 'debug'
|
||||
return if not @sprite or @name is 'debug'
|
||||
if @name is 'shadow'
|
||||
worldZ = @sprite.thang.pos.z - @sprite.thang.depth / 2 + @sprite.getBobOffset()
|
||||
@mark.alpha = @alpha * 0.451 / Math.sqrt(worldZ / 2 + 1)
|
||||
worldZ = @lank.thang.pos.z - @lank.thang.depth / 2 + @lank.getBobOffset()
|
||||
@sprite.alpha = @alpha * 0.451 / Math.sqrt(worldZ / 2 + 1)
|
||||
else if @name is 'bounds'
|
||||
@drawsBoundsBorderShape?.alpha = Math.floor @sprite.thang.alpha # Stop drawing bounds as soon as alpha is reduced at all
|
||||
@drawsBoundsBorderShape?.alpha = Math.floor @lank.thang.alpha # Stop drawing bounds as soon as alpha is reduced at all
|
||||
else
|
||||
@mark.alpha = @alpha
|
||||
@sprite.alpha = @alpha
|
||||
|
||||
updateRotation: ->
|
||||
if @name is 'debug' or (@name is 'shadow' and @sprite.thang?.shape in ['rectangle', 'box'])
|
||||
@mark.rotation = -@sprite.thang.rotation * 180 / Math.PI
|
||||
if @name is 'debug' or (@name is 'shadow' and @lank.thang?.shape in ['rectangle', 'box'])
|
||||
@sprite.rotation = -@lank.thang.rotation * 180 / Math.PI
|
||||
|
||||
updateScale: ->
|
||||
if @name is 'bounds' and ((@sprite.thang.width isnt @lastWidth or @sprite.thang.height isnt @lastHeight) or (@sprite.thang.drawsBoundsIndex isnt @drawsBoundsIndex))
|
||||
oldMark = @mark
|
||||
if @name is 'bounds' and ((@lank.thang.width isnt @lastWidth or @lank.thang.height isnt @lastHeight) or (@lank.thang.drawsBoundsIndex isnt @drawsBoundsIndex))
|
||||
oldMark = @sprite
|
||||
@buildBounds()
|
||||
oldMark.parent.addChild @mark
|
||||
oldMark.parent.swapChildren oldMark, @mark
|
||||
oldMark.parent.addChild @sprite
|
||||
oldMark.parent.swapChildren oldMark, @sprite
|
||||
oldMark.parent.removeChild oldMark
|
||||
|
||||
if @markSprite?
|
||||
@markSprite.scaleFactor = 1.2
|
||||
@markSprite.updateScale()
|
||||
if @markLank?
|
||||
@markLank.scaleFactor = 1.2
|
||||
@markLank.updateScale()
|
||||
|
||||
if @name is 'shadow' and thang = @sprite.thang
|
||||
@mark.scaleX = @baseScaleX * (thang.scaleFactor ? thang.scaleFactorX ? 1)
|
||||
@mark.scaleY = @baseScaleY * (thang.scaleFactor ? thang.scaleFactorY ? 1)
|
||||
if @name is 'shadow' and thang = @lank.thang
|
||||
@sprite.scaleX = @baseScaleX * (thang.scaleFactor ? thang.scaleFactorX ? 1)
|
||||
@sprite.scaleY = @baseScaleY * (thang.scaleFactor ? thang.scaleFactorY ? 1)
|
||||
|
||||
return unless @name in ['selection', 'target', 'repair', 'highlight']
|
||||
|
||||
# scale these marks to 10m (100px). Adjust based on sprite size.
|
||||
# scale these marks to 10m (100px). Adjust based on lank size.
|
||||
factor = 0.3 # default size: 3m width, most commonly for target when pointing to a location
|
||||
|
||||
if @sprite?.imageObject
|
||||
width = @sprite.imageObject.getBounds()?.width or 0
|
||||
width /= @sprite.options.resolutionFactor
|
||||
if @lank?.sprite
|
||||
width = @lank.sprite.getBounds()?.width or 0
|
||||
width /= @lank.options.resolutionFactor
|
||||
# all targets should be set to have a width of 100px, and then be scaled accordingly
|
||||
factor = width / 100 # normalize
|
||||
factor *= 1.1 # add margin
|
||||
factor = Math.max(factor, 0.3) # lower bound
|
||||
@mark.scaleX *= factor
|
||||
@mark.scaleY *= factor
|
||||
@sprite.scaleX *= factor
|
||||
@sprite.scaleY *= factor
|
||||
|
||||
if @name in ['selection', 'target', 'repair']
|
||||
@mark.scaleY *= @camera.y2x # code applies perspective
|
||||
@sprite.scaleY *= @camera.y2x # code applies perspective
|
||||
|
||||
stop: -> @markSprite?.stop()
|
||||
play: -> @markSprite?.play()
|
||||
stop: -> @markLank?.stop()
|
||||
play: -> @markLank?.play()
|
||||
hide: -> @hidden = true
|
||||
show: -> @hidden = false
|
||||
|
|
|
@ -1,391 +0,0 @@
|
|||
CocoClass = require 'lib/CocoClass'
|
||||
{me} = require 'lib/auth'
|
||||
LayerAdapter = require './LayerAdapter'
|
||||
IndieSprite = require 'lib/surface/IndieSprite'
|
||||
WizardSprite = require 'lib/surface/WizardSprite'
|
||||
FlagSprite = require 'lib/surface/FlagSprite'
|
||||
CocoSprite = require 'lib/surface/CocoSprite'
|
||||
Mark = require './Mark'
|
||||
Grid = require 'lib/world/Grid'
|
||||
|
||||
module.exports = class SpriteBoss extends CocoClass
|
||||
subscriptions:
|
||||
'bus:player-joined': 'onPlayerJoined'
|
||||
'bus:player-left': 'onPlayerLeft'
|
||||
'level:set-debug': 'onSetDebug'
|
||||
'sprite:highlight-sprites': 'onHighlightSprites'
|
||||
'surface:stage-mouse-down': 'onStageMouseDown'
|
||||
'level:select-sprite': 'onSelectSprite'
|
||||
'level:suppress-selection-sounds': 'onSuppressSelectionSounds'
|
||||
'level:lock-select': 'onSetLockSelect'
|
||||
'level:restarted': 'onLevelRestarted'
|
||||
'god:new-world-created': 'onNewWorld'
|
||||
'god:streaming-world-updated': 'onNewWorld'
|
||||
'camera:dragged': 'onCameraDragged'
|
||||
'sprite:loaded': -> @update(true)
|
||||
'level:flag-color-selected': 'onFlagColorSelected'
|
||||
'level:flag-updated': 'onFlagUpdated'
|
||||
'surface:flag-appeared': 'onFlagAppeared'
|
||||
'surface:remove-selected-flag': 'onRemoveSelectedFlag'
|
||||
|
||||
constructor: (@options) ->
|
||||
super()
|
||||
@dragged = 0
|
||||
@options ?= {}
|
||||
@camera = @options.camera
|
||||
@webGLStage = @options.webGLStage
|
||||
@surfaceTextLayer = @options.surfaceTextLayer
|
||||
@world = options.world
|
||||
@options.thangTypes ?= []
|
||||
@sprites = {}
|
||||
@spriteArray = [] # Mirror @sprites, but faster for when we just need to iterate
|
||||
@selfWizardSprite = null
|
||||
@createLayers()
|
||||
@pendingFlags = []
|
||||
|
||||
destroy: ->
|
||||
@removeSprite sprite for thangID, sprite of @sprites
|
||||
@targetMark?.destroy()
|
||||
@selectionMark?.destroy()
|
||||
super()
|
||||
|
||||
toString: -> "<SpriteBoss: #{@spriteArray.length} sprites>"
|
||||
|
||||
thangTypeFor: (type) ->
|
||||
_.find @options.thangTypes, (m) -> m.get('original') is type or m.get('name') is type
|
||||
|
||||
createLayers: ->
|
||||
@spriteLayers = {}
|
||||
for [name, priority] in [
|
||||
['Land', -40]
|
||||
['Ground', -30]
|
||||
['Obstacle', -20]
|
||||
['Path', -10]
|
||||
['Default', 0]
|
||||
['Floating', 10]
|
||||
]
|
||||
@spriteLayers[name] = new LayerAdapter name: name, webGL: true, layerPriority: priority, transform: LayerAdapter.TRANSFORM_SURFACE, camera: @camera
|
||||
@webGLStage.addChild (spriteLayer.container for spriteLayer in _.values(@spriteLayers))...
|
||||
|
||||
layerForChild: (child, sprite) ->
|
||||
unless child.layerPriority?
|
||||
if thang = sprite?.thang
|
||||
child.layerPriority = thang.layerPriority
|
||||
child.layerPriority ?= 0 if thang.isSelectable
|
||||
child.layerPriority ?= -40 if thang.isLand
|
||||
child.layerPriority ?= 0
|
||||
return @spriteLayers['Default'] unless child.layerPriority
|
||||
layer = _.findLast @spriteLayers, (layer, name) ->
|
||||
layer.layerPriority <= child.layerPriority
|
||||
layer ?= @spriteLayers['Land'] if child.layerPriority < -40
|
||||
layer ? @spriteLayers['Default']
|
||||
|
||||
addSprite: (sprite, id=null, layer=null) ->
|
||||
id ?= sprite.thang.id
|
||||
console.error 'Sprite collision! Already have:', id if @sprites[id]
|
||||
@sprites[id] = sprite
|
||||
@spriteArray.push sprite
|
||||
layer ?= @spriteLayers['Obstacle'] if sprite.thang?.spriteName.search(/(dungeon|indoor).wall/i) isnt -1
|
||||
layer ?= @layerForChild sprite.imageObject, sprite
|
||||
layer.addCocoSprite sprite
|
||||
layer.updateLayerOrder()
|
||||
sprite
|
||||
|
||||
createMarks: ->
|
||||
@targetMark = new Mark name: 'target', camera: @camera, layer: @spriteLayers['Ground'], thangType: 'target'
|
||||
@selectionMark = new Mark name: 'selection', camera: @camera, layer: @spriteLayers['Ground'], thangType: 'selection'
|
||||
|
||||
createSpriteOptions: (options) ->
|
||||
_.extend options, camera: @camera, resolutionFactor: SPRITE_RESOLUTION_FACTOR, groundLayer: @spriteLayers['Ground'], textLayer: @surfaceTextLayer, floatingLayer: @spriteLayers['Floating'], showInvisible: @options.showInvisible
|
||||
|
||||
createIndieSprites: (indieSprites, withWizards) ->
|
||||
unless @indieSprites
|
||||
@indieSprites = []
|
||||
@indieSprites = (@createIndieSprite indieSprite for indieSprite in indieSprites) if indieSprites
|
||||
if withWizards and not @selfWizardSprite
|
||||
@selfWizardSprite = @createWizardSprite thangID: 'My Wizard', isSelf: true, sprites: @sprites
|
||||
|
||||
createIndieSprite: (indieSprite) ->
|
||||
unless thangType = @thangTypeFor indieSprite.thangType
|
||||
console.warn "Need to convert #{indieSprite.id}'s ThangType #{indieSprite.thangType} to a ThangType reference. Until then, #{indieSprite.id} won't show up."
|
||||
return
|
||||
sprite = new IndieSprite thangType, @createSpriteOptions {thangID: indieSprite.id, pos: indieSprite.pos, sprites: @sprites, team: indieSprite.team, teamColors: @world.getTeamColors()}
|
||||
@addSprite sprite, sprite.thang.id
|
||||
|
||||
createOpponentWizard: (opponent) ->
|
||||
# TODO: colorize name and cloud by team, colorize wizard by user's color config, level-specific wizard spawn points
|
||||
sprite = @createWizardSprite thangID: opponent.id, name: opponent.name, codeLanguage: opponent.codeLanguage
|
||||
if not opponent.levelSlug or opponent.levelSlug is 'brawlwood'
|
||||
sprite.targetPos = if opponent.team is 'ogres' then {x: 52, y: 52} else {x: 28, y: 28}
|
||||
else if opponent.levelSlug in ['dungeon-arena', 'sky-span']
|
||||
sprite.targetPos = if opponent.team is 'ogres' then {x: 72, y: 39} else {x: 9, y: 39}
|
||||
else if opponent.levelSlug is 'criss-cross'
|
||||
sprite.targetPos = if opponent.team is 'ogres' then {x: 50, y: 12} else {x: 0, y: 40}
|
||||
else
|
||||
sprite.targetPos = if opponent.team is 'ogres' then {x: 52, y: 28} else {x: 20, y: 28}
|
||||
|
||||
createWizardSprite: (options) ->
|
||||
sprite = new WizardSprite @thangTypeFor('Wizard'), @createSpriteOptions(options)
|
||||
@addSprite sprite, sprite.thang.id, @spriteLayers['Floating']
|
||||
|
||||
onPlayerJoined: (e) ->
|
||||
# Create another WizardSprite, unless this player is just me
|
||||
pid = e.player.id
|
||||
return if pid is me.id
|
||||
wiz = @createWizardSprite thangID: pid, sprites: @sprites
|
||||
wiz.animateIn()
|
||||
state = e.player.wizard or {}
|
||||
wiz.setInitialState(state.targetPos, @sprites[state.targetSprite])
|
||||
|
||||
onPlayerLeft: (e) ->
|
||||
pid = e.player.id
|
||||
@sprites[pid]?.animateOut => @removeSprite @sprites[pid]
|
||||
|
||||
onSetDebug: (e) ->
|
||||
return if e.debug is @debug
|
||||
@debug = e.debug
|
||||
sprite.setDebug @debug for sprite in @spriteArray
|
||||
|
||||
onHighlightSprites: (e) ->
|
||||
highlightedIDs = e.thangIDs or []
|
||||
for thangID, sprite of @sprites
|
||||
sprite.setHighlight? thangID in highlightedIDs, e.delay
|
||||
|
||||
addThangToSprites: (thang, layer=null) ->
|
||||
return console.warn 'Tried to add Thang to the surface it already has:', thang.id if @sprites[thang.id]
|
||||
thangType = _.find @options.thangTypes, (m) ->
|
||||
return false unless m.get('actions') or m.get('raster')
|
||||
return m.get('name') is thang.spriteName
|
||||
thangType ?= _.find @options.thangTypes, (m) -> return m.get('name') is thang.spriteName
|
||||
return console.error "Couldn't find ThangType for", thang unless thangType
|
||||
|
||||
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
|
||||
|
||||
removeSprite: (sprite) ->
|
||||
sprite.layer.removeCocoSprite(sprite)
|
||||
thang = sprite.thang
|
||||
delete @sprites[sprite.thang.id]
|
||||
@spriteArray.splice @spriteArray.indexOf(sprite), 1
|
||||
@stopListening sprite
|
||||
sprite.destroy()
|
||||
sprite.thang = thang # Keep around so that we know which thang the destroyed thang was for
|
||||
|
||||
updateSounds: ->
|
||||
sprite.playSounds() for sprite in @spriteArray # hmm; doesn't work for sprites which we didn't add yet in adjustSpriteExistence
|
||||
|
||||
update: (frameChanged) ->
|
||||
@adjustSpriteExistence() if frameChanged
|
||||
sprite.update frameChanged for sprite in @spriteArray
|
||||
@updateSelection()
|
||||
@spriteLayers['Default'].updateLayerOrder()
|
||||
@cacheObstacles()
|
||||
|
||||
adjustSpriteExistence: ->
|
||||
# Add anything new, remove anything old, update everything current
|
||||
updatedObstacles = []
|
||||
itemsJustEquipped = []
|
||||
for thang in @world.thangs when thang.exists and thang.pos
|
||||
itemsJustEquipped = itemsJustEquipped.concat @equipNewItems thang
|
||||
if sprite = @sprites[thang.id]
|
||||
sprite.setThang thang # make sure Sprite has latest Thang
|
||||
else
|
||||
sprite = @addThangToSprites(thang)
|
||||
Backbone.Mediator.publish 'surface:new-thang-added', thang: thang, sprite: sprite
|
||||
updatedObstacles.push sprite if sprite.imageObject.parent is @spriteLayers['Obstacle']
|
||||
sprite.playSounds()
|
||||
item.modifyStats() for item in itemsJustEquipped
|
||||
for thangID, sprite of @sprites
|
||||
missing = not (sprite.notOfThisWorld or @world.thangMap[thangID]?.exists)
|
||||
isObstacle = sprite.imageObject.parent is @spriteLayers['Obstacle']
|
||||
updatedObstacles.push sprite if isObstacle and (missing or sprite.hasMoved)
|
||||
sprite.hasMoved = false
|
||||
@removeSprite sprite if missing
|
||||
@cacheObstacles updatedObstacles if updatedObstacles.length and @cachedObstacles
|
||||
|
||||
# mainly for handling selecting thangs from session when the thang is not always in existence
|
||||
if @willSelectThang and @sprites[@willSelectThang[0]]
|
||||
@selectThang @willSelectThang...
|
||||
|
||||
equipNewItems: (thang) ->
|
||||
itemsJustEquipped = []
|
||||
if thang.equip and not thang.equipped
|
||||
thang.equip() # Pretty hacky, but needed since initialize may not be called if we're not running Systems.
|
||||
itemsJustEquipped.push thang
|
||||
if thang.inventoryIDs
|
||||
# Even hackier: these items were only created/equipped during simulation, so we reequip here.
|
||||
for slot, itemID of thang.inventoryIDs
|
||||
item = @world.getThangByID itemID
|
||||
unless item.equipped
|
||||
console.log thang.id, 'equipping', item, 'in', thang.slot, 'Surface-side, but it cannot equip?' unless item.equip
|
||||
item.equip()
|
||||
itemsJustEquipped.push item
|
||||
return itemsJustEquipped
|
||||
|
||||
cacheObstacles: (updatedObstacles=null) ->
|
||||
return if @cachedObstacles and not updatedObstacles
|
||||
wallSprites = (sprite for sprite in @spriteArray when sprite.thangType?.get('name').search(/(dungeon|indoor).wall/i) isnt -1)
|
||||
return if _.any (s.stillLoading for s in wallSprites)
|
||||
walls = (sprite.thang for sprite in wallSprites)
|
||||
@world.calculateBounds()
|
||||
wallGrid = new Grid walls, @world.size()...
|
||||
if updatedObstacles
|
||||
possiblyUpdatedWallSprites = (sprite for sprite in wallSprites when _.find updatedObstacles, (w2) -> sprite is w2 or (Math.abs(sprite.thang.pos.x - w2.thang.pos.x) + Math.abs(sprite.thang.pos.y - w2.thang.pos.y)) <= 16)
|
||||
else
|
||||
possiblyUpdatedWallSprites = wallSprites
|
||||
#console.log 'updating up to', possiblyUpdatedWallSprites.length, 'of', wallSprites.length, 'wall sprites from updatedObstacles', updatedObstacles
|
||||
for wallSprite in possiblyUpdatedWallSprites
|
||||
wallSprite.updateActionDirection wallGrid
|
||||
wallSprite.lockAction()
|
||||
wallSprite.updateScale()
|
||||
wallSprite.updatePosition()
|
||||
#console.log @wallGrid.toString()
|
||||
@cachedObstacles = true
|
||||
|
||||
spriteFor: (thangID) -> @sprites[thangID]
|
||||
|
||||
onNewWorld: (e) ->
|
||||
@world = @options.world = e.world
|
||||
|
||||
play: ->
|
||||
sprite.play() for sprite in @spriteArray
|
||||
@selectionMark?.play()
|
||||
@targetMark?.play()
|
||||
|
||||
stop: ->
|
||||
sprite.stop() for sprite in @spriteArray
|
||||
@selectionMark?.stop()
|
||||
@targetMark?.stop()
|
||||
|
||||
# Selection
|
||||
|
||||
onSuppressSelectionSounds: (e) -> @suppressSelectionSounds = e.suppress
|
||||
onSetLockSelect: (e) -> @selectLocked = e.lock
|
||||
onLevelRestarted: (e) ->
|
||||
@selectLocked = false
|
||||
@selectSprite e, null
|
||||
|
||||
onSelectSprite: (e) ->
|
||||
@selectThang e.thangID, e.spellName
|
||||
|
||||
onCameraDragged: ->
|
||||
@dragged += 1
|
||||
|
||||
onSpriteMouseUp: (e) ->
|
||||
return if key.shift #and @options.choosing
|
||||
return @dragged = 0 if @dragged > 3
|
||||
@dragged = 0
|
||||
sprite = if e.sprite?.thang?.isSelectable then e.sprite else null
|
||||
return if @flagCursorSprite and sprite?.thangType.get('name') is 'Flag'
|
||||
@selectSprite e, sprite
|
||||
|
||||
onStageMouseDown: (e) ->
|
||||
return if key.shift #and @options.choosing
|
||||
@selectSprite e if e.onBackground
|
||||
|
||||
selectThang: (thangID, spellName=null, treemaThangSelected = null) ->
|
||||
return @willSelectThang = [thangID, spellName] unless @sprites[thangID]
|
||||
@selectSprite null, @sprites[thangID], spellName, treemaThangSelected
|
||||
|
||||
selectSprite: (e, sprite=null, spellName=null, treemaThangSelected = null) ->
|
||||
return if e and (@disabled or @selectLocked) # Ignore clicks for selection/panning/wizard movement while disabled or select is locked
|
||||
worldPos = sprite?.thang?.pos
|
||||
worldPos ?= @camera.screenToWorld {x: e.originalEvent.rawX, y: e.originalEvent.rawY} if e?.originalEvent
|
||||
if worldPos and (@options.navigateToSelection or not sprite or treemaThangSelected) and e?.originalEvent?.nativeEvent?.which isnt 3
|
||||
@camera.zoomTo(sprite?.imageObject or @camera.worldToSurface(worldPos), @camera.zoom, 1000, true)
|
||||
sprite = null if @options.choosing # Don't select sprites while choosing
|
||||
if sprite isnt @selectedSprite
|
||||
@selectedSprite?.selected = false
|
||||
sprite?.selected = true
|
||||
@selectedSprite = sprite
|
||||
alive = sprite and not (sprite.thang.health < 0)
|
||||
|
||||
Backbone.Mediator.publish 'surface:sprite-selected',
|
||||
thang: if sprite then sprite.thang else null
|
||||
sprite: sprite
|
||||
spellName: spellName ? e?.spellName
|
||||
originalEvent: e
|
||||
worldPos: worldPos
|
||||
|
||||
@willSelectThang = null if sprite # Now that we've done a real selection, don't reselect some other Thang later.
|
||||
|
||||
if alive and not @suppressSelectionSounds
|
||||
instance = sprite.playSound 'selected'
|
||||
if instance?.playState is 'playSucceeded'
|
||||
Backbone.Mediator.publish 'sprite:thang-began-talking', thang: sprite?.thang
|
||||
instance.addEventListener 'complete', ->
|
||||
Backbone.Mediator.publish 'sprite:thang-finished-talking', thang: sprite?.thang
|
||||
|
||||
onFlagColorSelected: (e) ->
|
||||
@removeSprite @flagCursorSprite if @flagCursorSprite
|
||||
@flagCursorSprite = null
|
||||
for flagSprite in @spriteArray when flagSprite.thangType.get('name') is 'Flag'
|
||||
flagSprite.imageObject.cursor = if e.color then 'crosshair' else 'pointer'
|
||||
return unless e.color
|
||||
@flagCursorSprite = new FlagSprite @thangTypeFor('Flag'), @createSpriteOptions(thangID: 'Flag Cursor', color: e.color, team: me.team, isCursor: true, pos: e.pos)
|
||||
@addSprite @flagCursorSprite, @flagCursorSprite.thang.id, @spriteLayers['Floating']
|
||||
|
||||
onFlagUpdated: (e) ->
|
||||
return unless e.active
|
||||
pendingFlag = new FlagSprite @thangTypeFor('Flag'), @createSpriteOptions(thangID: 'Pending Flag ' + Math.random(), color: e.color, team: e.team, isCursor: false, pos: e.pos)
|
||||
@addSprite pendingFlag, pendingFlag.thang.id, @spriteLayers['Floating']
|
||||
@pendingFlags.push pendingFlag
|
||||
|
||||
onFlagAppeared: (e) ->
|
||||
# Remove the pending flag that matches this one's color/team/position, and any color/team matches placed earlier.
|
||||
t1 = e.sprite.thang
|
||||
pending = (@pendingFlags ? []).slice()
|
||||
foundExactMatch = false
|
||||
for i in [pending.length - 1 .. 0] by -1
|
||||
pendingFlag = pending[i]
|
||||
t2 = pendingFlag.thang
|
||||
matchedType = t1.color is t2.color and t1.team is t2.team
|
||||
matched = matchedType and (foundExactMatch or Math.abs(t1.pos.x - t2.pos.x) < 0.00001 and Math.abs(t1.pos.y - t2.pos.y) < 0.00001)
|
||||
if matched
|
||||
foundExactMatch = true
|
||||
@pendingFlags.splice(i, 1)
|
||||
@removeSprite pendingFlag
|
||||
e.sprite.imageObject.cursor = if @flagCursorSprite then 'crosshair' else 'pointer'
|
||||
null
|
||||
|
||||
onRemoveSelectedFlag: (e) ->
|
||||
# Remove the selected sprite if it's a flag, or any flag of the given color if a color is given.
|
||||
flagSprite = _.find [@selectedSprite].concat(@spriteArray), (sprite) ->
|
||||
sprite and sprite.thangType.get('name') is 'Flag' and sprite.thang.team is me.team and (sprite.thang.color is e.color or not e.color) and not sprite.notOfThisWorld
|
||||
return unless flagSprite
|
||||
Backbone.Mediator.publish 'surface:remove-flag', color: flagSprite.thang.color
|
||||
|
||||
# Marks
|
||||
|
||||
updateSelection: ->
|
||||
if @selectedSprite?.thang and (not @selectedSprite.thang.exists or not @world.getThangByID @selectedSprite.thang.id)
|
||||
thangID = @selectedSprite.thang.id
|
||||
@selectedSprite = null # Don't actually trigger deselection, but remove the selected sprite.
|
||||
@selectionMark?.toggle false
|
||||
@willSelectThang = [thangID, null]
|
||||
@updateTarget()
|
||||
return unless @selectionMark
|
||||
@selectedSprite = null if @selectedSprite and (@selectedSprite.destroyed or not @selectedSprite.thang)
|
||||
# The selection mark should be on the ground layer, unless we're not a normal sprite (like a wall), in which case we'll place it higher so we can see it.
|
||||
if @selectedSprite and @selectedSprite.imageObject.parent isnt @spriteLayers.Default.container
|
||||
@selectionMark.setLayer @spriteLayers.Default
|
||||
else if @selectedSprite
|
||||
@selectionMark.setLayer @spriteLayers.Ground
|
||||
@selectionMark.toggle @selectedSprite?
|
||||
@selectionMark.setSprite @selectedSprite
|
||||
@selectionMark.update()
|
||||
|
||||
updateTarget: ->
|
||||
return unless @targetMark
|
||||
thang = @selectedSprite?.thang
|
||||
target = thang?.target
|
||||
targetPos = thang?.targetPos
|
||||
targetPos = null if targetPos?.isZero?() # Null targetPos get serialized as (0, 0, 0)
|
||||
@targetMark.setSprite if target then @sprites[target.id] else null
|
||||
@targetMark.toggle @targetMark.sprite or targetPos
|
||||
@targetMark.update if targetPos then @camera.worldToSurface targetPos else null
|
|
@ -14,7 +14,7 @@ WaitingScreen = require './WaitingScreen'
|
|||
DebugDisplay = require './DebugDisplay'
|
||||
CoordinateDisplay = require './CoordinateDisplay'
|
||||
CoordinateGrid = require './CoordinateGrid'
|
||||
SpriteBoss = require './SpriteBoss'
|
||||
LankBoss = require './LankBoss'
|
||||
PointChooser = require './PointChooser'
|
||||
RegionChooser = require './RegionChooser'
|
||||
MusicPlayer = require './MusicPlayer'
|
||||
|
@ -30,7 +30,7 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
screenLayer: null
|
||||
gridLayer: null
|
||||
|
||||
spriteBoss: null
|
||||
lankBoss: null
|
||||
|
||||
debugDisplay: null
|
||||
currentFrame: 0
|
||||
|
@ -111,7 +111,7 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
canvasHeight = parseInt @normalCanvas.attr('height'), 10
|
||||
@screenLayer.addChild new Letterbox canvasWidth: canvasWidth, canvasHeight: canvasHeight
|
||||
|
||||
@spriteBoss = new SpriteBoss camera: @camera, webGLStage: @webGLStage, surfaceTextLayer: @surfaceTextLayer, world: @world, thangTypes: @options.thangTypes, choosing: @options.choosing, navigateToSelection: @options.navigateToSelection, showInvisible: @options.showInvisible
|
||||
@lankBoss = new LankBoss camera: @camera, webGLStage: @webGLStage, surfaceTextLayer: @surfaceTextLayer, world: @world, thangTypes: @options.thangTypes, choosing: @options.choosing, navigateToSelection: @options.navigateToSelection, showInvisible: @options.showInvisible
|
||||
@countdownScreen = new CountdownScreen camera: @camera, layer: @screenLayer
|
||||
@playbackOverScreen = new PlaybackOverScreen camera: @camera, layer: @screenLayer
|
||||
@waitingScreen = new WaitingScreen camera: @camera, layer: @screenLayer
|
||||
|
@ -146,7 +146,7 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
|
||||
setWorld: (@world) ->
|
||||
@worldLoaded = true
|
||||
@spriteBoss.world = @world
|
||||
@lankBoss.world = @world
|
||||
@restoreWorldState() unless @options.choosing
|
||||
@showLevel()
|
||||
@updateState true if @loaded
|
||||
|
@ -156,15 +156,15 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
return if @destroyed
|
||||
return if @loaded
|
||||
@loaded = true
|
||||
@spriteBoss.createMarks()
|
||||
@spriteBoss.createIndieSprites @world.indieSprites, @options.wizards
|
||||
@lankBoss.createMarks()
|
||||
@lankBoss.createIndieLanks @world.indieSprites, @options.wizards
|
||||
@updateState true
|
||||
@drawCurrentFrame()
|
||||
createjs.Ticker.addEventListener 'tick', @tick
|
||||
Backbone.Mediator.publish 'level:started', {}
|
||||
|
||||
createOpponentWizard: (opponent) ->
|
||||
@spriteBoss.createOpponentWizard opponent
|
||||
@lankBoss.createOpponentWizard opponent
|
||||
|
||||
|
||||
|
||||
|
@ -224,15 +224,15 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
ratio = current % 1
|
||||
@world.frames[next].restorePartialState ratio if next > 1
|
||||
frame.clearEvents() if parseInt(@currentFrame) is parseInt(@lastFrame)
|
||||
@spriteBoss.updateSounds() if parseInt(@currentFrame) isnt parseInt(@lastFrame)
|
||||
@lankBoss.updateSounds() if parseInt(@currentFrame) isnt parseInt(@lastFrame)
|
||||
|
||||
updateState: (frameChanged) ->
|
||||
# world state must have been restored in @restoreWorldState
|
||||
if @playing and @heroSprite and not @mouseIsDown and @camera.newTarget isnt @heroSprite.imageObject and @camera.target isnt @heroSprite.imageObject
|
||||
@camera.zoomTo @heroSprite.imageObject, @camera.zoom, 750
|
||||
if @playing and @heroSprite and not @mouseIsDown and @camera.newTarget isnt @heroSprite.sprite and @camera.target isnt @heroSprite.sprite
|
||||
@camera.zoomTo @heroSprite.sprite, @camera.zoom, 750
|
||||
@camera.updateZoom()
|
||||
@spriteBoss.update frameChanged
|
||||
@dimmer?.setSprites @spriteBoss.sprites
|
||||
@lankBoss.update frameChanged
|
||||
@dimmer?.setSprites @lankBoss.sprites
|
||||
|
||||
drawCurrentFrame: (e) ->
|
||||
++@totalFramesDrawn
|
||||
|
@ -288,12 +288,12 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
frame = @world.getFrame(@getCurrentFrame())
|
||||
frame.restoreState()
|
||||
volume = Math.max(0.05, Math.min(1, 1 / @scrubbingPlaybackSpeed))
|
||||
sprite.playSounds false, volume for sprite in @spriteBoss.spriteArray
|
||||
sprite.playSounds false, volume for sprite in @lankBoss.spriteArray
|
||||
tempFrame += if rising then 1 else -1
|
||||
@currentFrame = actualCurrentFrame
|
||||
|
||||
@restoreWorldState()
|
||||
@spriteBoss.update true
|
||||
@lankBoss.update true
|
||||
@onFrameChanged()
|
||||
|
||||
getCurrentFrame: ->
|
||||
|
@ -310,11 +310,11 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
@surfacePauseTimeout = @surfaceZoomPauseTimeout = null
|
||||
if paused
|
||||
@surfacePauseTimeout = _.delay performToggle, 2000
|
||||
@spriteBoss.stop()
|
||||
@lankBoss.stop()
|
||||
@playbackOverScreen.show()
|
||||
else
|
||||
performToggle()
|
||||
@spriteBoss.play()
|
||||
@lankBoss.play()
|
||||
@playbackOverScreen.hide()
|
||||
|
||||
|
||||
|
@ -327,7 +327,7 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
return if @currentFrame is @lastFrame and not force
|
||||
progress = @getProgress()
|
||||
Backbone.Mediator.publish('surface:frame-changed',
|
||||
selectedThang: @spriteBoss.selectedSprite?.thang
|
||||
selectedThang: @lankBoss.selectedSprite?.thang
|
||||
progress: progress
|
||||
frame: @currentFrame
|
||||
world: @world
|
||||
|
@ -365,7 +365,7 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
|
||||
onSetCamera: (e) ->
|
||||
if e.thangID
|
||||
return unless target = @spriteBoss.spriteFor(e.thangID)?.imageObject
|
||||
return unless target = @lankBoss.spriteFor(e.thangID)?.sprite
|
||||
else if e.pos
|
||||
target = @camera.worldToSurface e.pos
|
||||
else
|
||||
|
@ -383,7 +383,7 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
return if e.controls and not ('surface' in e.controls)
|
||||
@setDisabled true
|
||||
@dimmer ?= new Dimmer camera: @camera, layer: @screenLayer
|
||||
@dimmer.setSprites @spriteBoss.sprites
|
||||
@dimmer.setSprites @lankBoss.sprites
|
||||
|
||||
onEnableControls: (e) ->
|
||||
return if e.controls and not ('surface' in e.controls)
|
||||
|
@ -393,7 +393,7 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
@setDisabled e.on
|
||||
|
||||
setDisabled: (@disabled) ->
|
||||
@spriteBoss.disabled = @disabled
|
||||
@lankBoss.disabled = @disabled
|
||||
|
||||
onSetPlaying: (e) ->
|
||||
@playing = (e ? {}).playing ? true
|
||||
|
@ -433,7 +433,7 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
|
||||
onStreamingWorldUpdated: (event) ->
|
||||
@casting = false
|
||||
@spriteBoss.play()
|
||||
@lankBoss.play()
|
||||
|
||||
# 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.
|
||||
|
@ -535,7 +535,7 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
|
||||
#- Camera focus on hero
|
||||
focusOnHero: ->
|
||||
@heroSprite = @spriteBoss.spriteFor 'Hero Placeholder'
|
||||
@heroSprite = @lankBoss.spriteFor 'Hero Placeholder'
|
||||
|
||||
|
||||
#- Real-time playback
|
||||
|
@ -547,18 +547,18 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
return if @realTime
|
||||
@realTime = true
|
||||
@onResize()
|
||||
@spriteBoss.selfWizardSprite?.toggle false
|
||||
@lankBoss.selfWizardLank?.toggle false
|
||||
@playing = false # Will start when countdown is done.
|
||||
if @heroSprite
|
||||
@previousCameraZoom = @camera.zoom
|
||||
@camera.zoomTo @heroSprite.imageObject, 4, 3000
|
||||
@camera.zoomTo @heroSprite.sprite, 4, 3000
|
||||
|
||||
onRealTimePlaybackEnded: (e) ->
|
||||
return unless @realTime
|
||||
@realTime = false
|
||||
@onResize()
|
||||
_.delay @onResize, resizeDelay + 100 # Do it again just to be double sure that we don't stay zoomed in due to timing problems.
|
||||
@spriteBoss.selfWizardSprite?.toggle true
|
||||
@lankBoss.selfWizardLank?.toggle true
|
||||
@normalCanvas.add(@webGLCanvas).removeClass 'flag-color-selected'
|
||||
if @previousCameraZoom
|
||||
@camera.zoomTo @camera.newTarget or @camera.target, @previousCameraZoom, 3000
|
||||
|
@ -569,22 +569,22 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
|
||||
|
||||
|
||||
#- Paths - TODO: move to SpriteBoss? but only update on frame drawing instead of on every frame update?
|
||||
#- Paths - TODO: move to LankBoss? but only update on frame drawing instead of on every frame update?
|
||||
|
||||
updatePaths: ->
|
||||
return # TODO: Get paths working again with WebGL
|
||||
return unless @options.paths
|
||||
return if @casting
|
||||
@hidePaths()
|
||||
selectedThang = @spriteBoss.selectedSprite?.thang
|
||||
selectedThang = @lankBoss.selectedSprite?.thang
|
||||
return if @world.showPaths is 'never'
|
||||
return if @world.showPaths is 'paused' and @playing
|
||||
return if @world.showPaths is 'selected' and not selectedThang
|
||||
@trailmaster ?= new path.Trailmaster @camera
|
||||
selectedOnly = @playing and @world.showPaths is 'selected'
|
||||
@paths = @trailmaster.generatePaths @world, @getCurrentFrame(), selectedThang, @spriteBoss.sprites, selectedOnly
|
||||
@paths = @trailmaster.generatePaths @world, @getCurrentFrame(), selectedThang, @lankBoss.sprites, selectedOnly
|
||||
@paths.name = 'paths'
|
||||
@spriteBoss.spriteLayers['Path'].addChild @paths
|
||||
@lankBoss.layerAdapters['Path'].addChild @paths
|
||||
|
||||
hidePaths: ->
|
||||
return if not @paths
|
||||
|
@ -681,7 +681,7 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
createjs.Ticker.removeEventListener('tick', @tick)
|
||||
createjs.Sound.stop()
|
||||
layer.destroy() for layer in @normalLayers
|
||||
@spriteBoss.destroy()
|
||||
@lankBoss.destroy()
|
||||
@chooser?.destroy()
|
||||
@dimmer?.destroy()
|
||||
@countdownScreen?.destroy()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
IndieSprite = require 'lib/surface/IndieSprite'
|
||||
IndieLank = require 'lib/surface/IndieLank'
|
||||
{me} = require 'lib/auth'
|
||||
|
||||
module.exports = class WizardSprite extends IndieSprite
|
||||
module.exports = class WizardLank extends IndieLank
|
||||
# Wizard targets are constantly changing, so a simple tween doesn't work.
|
||||
# Instead, the wizard stores its origin point and the (possibly) moving target.
|
||||
# Then it figures out its current position based on tween percentage and
|
||||
|
@ -9,7 +9,7 @@ module.exports = class WizardSprite extends IndieSprite
|
|||
tweenPercentage: 1.0
|
||||
originPos: null
|
||||
targetPos: null
|
||||
targetSprite: null
|
||||
targetLank: null
|
||||
reachedTarget: true
|
||||
spriteXOffset: 4 # meters from target sprite
|
||||
spriteYOffset: 0 # meters from target sprite
|
||||
|
@ -17,8 +17,8 @@ module.exports = class WizardSprite extends IndieSprite
|
|||
subscriptions:
|
||||
'bus:player-states-changed': 'onPlayerStatesChanged'
|
||||
'auth:me-synced': 'onMeSynced'
|
||||
'surface:sprite-selected': 'onSpriteSelected'
|
||||
'sprite:echo-all-wizard-sprites': 'onEchoAllWizardSprites'
|
||||
'surface:sprite-selected': 'onLankSelected'
|
||||
'sprite:echo-all-wizard-sprites': 'onEchoAllWizardLanks'
|
||||
|
||||
shortcuts:
|
||||
'up': 'onMoveKey'
|
||||
|
@ -57,7 +57,7 @@ module.exports = class WizardSprite extends IndieSprite
|
|||
super name
|
||||
|
||||
toggle: (to) ->
|
||||
@imageObject?.visible = to
|
||||
@sprite?.visible = to
|
||||
label[if to then 'show' else 'hide']() for name, label of @labels
|
||||
mark.mark?.visible = to for name, mark of @marks
|
||||
|
||||
|
@ -65,37 +65,37 @@ module.exports = class WizardSprite extends IndieSprite
|
|||
for playerID, state of e.states
|
||||
continue unless playerID is @thang.id
|
||||
@setEditing state.wizard?.editing
|
||||
continue if playerID is me.id # ignore changes for self wizard sprite
|
||||
continue if playerID is me.id # ignore changes for self wizard lank
|
||||
@setNameLabel state.name
|
||||
continue unless state.wizard?
|
||||
if targetID = state.wizard.targetSprite
|
||||
return console.warn 'Wizard Sprite couldn\'t find target sprite', targetID unless targetID of @options.sprites
|
||||
@setTarget @options.sprites[targetID]
|
||||
if targetID = state.wizard.targetLank
|
||||
return console.warn 'Wizard Lank couldn\'t find target lank', targetID unless targetID of @options.lanks
|
||||
@setTarget @options.lanks[targetID]
|
||||
else
|
||||
@setTarget state.wizard.targetPos
|
||||
|
||||
onMeSynced: (e) ->
|
||||
return unless @isSelf
|
||||
@setNameLabel me.displayName() if @imageObject.visible # not if we hid the wiz
|
||||
@setNameLabel me.displayName() if @sprite.visible # not if we hid the wiz
|
||||
newColorConfig = me.get('wizard')?.colorConfig or {}
|
||||
shouldUpdate = not _.isEqual(newColorConfig, @options.colorConfig)
|
||||
@options.colorConfig = $.extend(true, {}, newColorConfig)
|
||||
if shouldUpdate
|
||||
@setUpSprite()
|
||||
@setUpLank()
|
||||
@playAction(@currentAction) if @currentAction
|
||||
|
||||
onSpriteSelected: (e) ->
|
||||
onLankSelected: (e) ->
|
||||
return unless @isSelf
|
||||
@setTarget e.sprite or e.worldPos
|
||||
|
||||
animateIn: ->
|
||||
@imageObject.scaleX = @imageObject.scaleY = @imageObject.alpha = 0
|
||||
createjs.Tween.get(@imageObject)
|
||||
@sprite.scaleX = @sprite.scaleY = @sprite.alpha = 0
|
||||
createjs.Tween.get(@sprite)
|
||||
.to({scaleX: 1, scaleY: 1, alpha: 1}, 1000, createjs.Ease.getPowInOut(2.2))
|
||||
@labels.name?.show()
|
||||
|
||||
animateOut: (callback) ->
|
||||
tween = createjs.Tween.get(@imageObject)
|
||||
tween = createjs.Tween.get(@sprite)
|
||||
.to({scaleX: 0, scaleY: 0, alpha: 0}, 1000, createjs.Ease.getPowInOut(2.2))
|
||||
tween.call(callback) if callback
|
||||
@labels.name?.hide()
|
||||
|
@ -107,11 +107,11 @@ module.exports = class WizardSprite extends IndieSprite
|
|||
else
|
||||
@thang.action = 'idle' if @thang.action is 'cast'
|
||||
|
||||
setInitialState: (targetPos, @targetSprite) ->
|
||||
@targetPos = @getPosFromTarget(@targetSprite or targetPos)
|
||||
setInitialState: (targetPos, @targetLank) ->
|
||||
@targetPos = @getPosFromTarget(@targetLank or targetPos)
|
||||
@endMoveTween()
|
||||
|
||||
onEchoAllWizardSprites: (e) -> e.payload.push @
|
||||
onEchoAllWizardLanks: (e) -> e.payload.push @
|
||||
defaultPos: -> x: 35, y: 24, z: @thang.depth / 2 + @thang.bobHeight
|
||||
move: (pos, duration) -> @setTarget(pos, duration)
|
||||
|
||||
|
@ -121,12 +121,12 @@ module.exports = class WizardSprite extends IndieSprite
|
|||
return if @targetPos and @targetPos.x is targetPos.x and @targetPos.y is targetPos.y
|
||||
|
||||
# ignore selecting sprites you can't control
|
||||
isSprite = newTarget?.thang?
|
||||
return if isSprite and not newTarget.thang.isProgrammable
|
||||
return if isSprite and newTarget is @targetSprite
|
||||
isLank = newTarget?.thang?
|
||||
return if isLank and not newTarget.thang.isProgrammable
|
||||
return if isLank and newTarget is @targetLank
|
||||
|
||||
@shoveOtherWizards(true) if @targetSprite
|
||||
@targetSprite = if isSprite then newTarget else null
|
||||
@shoveOtherWizards(true) if @targetLank
|
||||
@targetLank = if isLank then newTarget else null
|
||||
@targetPos = @boundWizard targetPos
|
||||
@beginMoveTween(duration, isLinear)
|
||||
@shoveOtherWizards()
|
||||
|
@ -175,10 +175,10 @@ module.exports = class WizardSprite extends IndieSprite
|
|||
@update true
|
||||
|
||||
shoveOtherWizards: (removeMe) ->
|
||||
return unless @targetSprite
|
||||
return unless @targetLank
|
||||
allWizards = []
|
||||
Backbone.Mediator.publish 'sprite:echo-all-wizard-sprites', payload: allWizards
|
||||
allOfUs = (wizard for wizard in allWizards when wizard.targetSprite is @targetSprite)
|
||||
allOfUs = (wizard for wizard in allWizards when wizard.targetLank is @targetLank)
|
||||
allOfUs = (wizard for wizard in allOfUs when wizard isnt @) if removeMe
|
||||
|
||||
# diagonal lineup pattern
|
||||
|
@ -210,18 +210,18 @@ module.exports = class WizardSprite extends IndieSprite
|
|||
@thang.pos = @getCurrentPosition()
|
||||
@faceTarget()
|
||||
sup = @options.camera.worldToSurface x: @thang.pos.x, y: @thang.pos.y, z: @thang.pos.z - @thang.depth / 2
|
||||
@imageObject.x = sup.x
|
||||
@imageObject.y = sup.y
|
||||
@sprite.x = sup.x
|
||||
@sprite.y = sup.y
|
||||
|
||||
getCurrentPosition: ->
|
||||
"""
|
||||
Takes into account whether the wizard is in transit or not, and the bobbing up and down.
|
||||
Eventually will also adjust based on where other wizards are.
|
||||
"""
|
||||
@targetPos = @targetSprite.thang.pos if @targetSprite?.thang
|
||||
@targetPos = @targetLank.thang.pos if @targetLank?.thang
|
||||
pos = _.clone(@targetPos)
|
||||
pos.z = @defaultPos().z + @getBobOffset()
|
||||
@adjustPositionToSideOfTarget(pos) if @targetSprite # be off to the side depending on placement in world
|
||||
@adjustPositionToSideOfTarget(pos) if @targetLank # be off to the side depending on placement in world
|
||||
return pos if @reachedTarget # stick like glue
|
||||
|
||||
# if here, then the wizard is in transit. Calculate the diff!
|
||||
|
@ -248,11 +248,11 @@ module.exports = class WizardSprite extends IndieSprite
|
|||
targetPos.y += @spriteYOffset
|
||||
|
||||
faceTarget: ->
|
||||
if @targetSprite?.thang
|
||||
@pointToward(@targetSprite.thang.pos)
|
||||
if @targetLank?.thang
|
||||
@pointToward(@targetLank.thang.pos)
|
||||
|
||||
updateMarks: ->
|
||||
super() if @imageObject.visible # not if we hid the wiz
|
||||
super() if @sprite.visible # not if we hid the wiz
|
||||
|
||||
onMoveKey: (e) ->
|
||||
return unless @isSelf
|
|
@ -144,7 +144,7 @@ module.exports.Trailmaster = class Trailmaster
|
|||
sprites = []
|
||||
sprite = @sprites[thang.id]
|
||||
return sprites unless sprite?.actions
|
||||
lastPos = @camera.surfaceToWorld x: sprite.imageObject.x, y: sprite.imageObject.y
|
||||
lastPos = @camera.surfaceToWorld x: sprite.sprite.x, y: sprite.sprite.y
|
||||
minDistance = Math.pow(CLONE_INTERVAL * Camera.MPP, 2)
|
||||
actions = @world.actionsForThang(thang.id)
|
||||
lastAction = null
|
||||
|
@ -159,7 +159,7 @@ module.exports.Trailmaster = class Trailmaster
|
|||
diff += Math.pow(lastPos.y - thang.pos.y, 2)
|
||||
continue if diff < minDistance and action.name is lastAction
|
||||
|
||||
clone = sprite.imageObject.clone()
|
||||
clone = sprite.sprite.clone()
|
||||
clonePos = @camera.worldToSurface thang.pos
|
||||
clone.x = clonePos.x
|
||||
clone.y = clonePos.y
|
||||
|
|
|
@ -166,7 +166,7 @@ module.exports = class Thang
|
|||
serializeForAether: ->
|
||||
{CN: @constructor.className, id: @id}
|
||||
|
||||
getSpriteOptions: ->
|
||||
getLankOptions: ->
|
||||
colorConfigs = @teamColors or @world?.getTeamColors() or {}
|
||||
options = {colorConfig: {}}
|
||||
if @team and teamColor = colorConfigs[@team]
|
||||
|
|
|
@ -66,7 +66,7 @@ class CocoModel extends Backbone.Model
|
|||
inFlux = @loading or not @loaded
|
||||
@markToRevert() unless inFlux or @_revertAttributes or @project or options?.fromMerge
|
||||
res = super attributes, options
|
||||
@saveBackup() if @saveBackups and (not inFlux) and @hasLocalChanges()
|
||||
@saveBackup() if @saveBackups and (not inFlux)
|
||||
res
|
||||
|
||||
buildAttributesWithDefaults: ->
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
RootView = require 'views/kinds/RootView'
|
||||
template = require 'templates/home'
|
||||
WizardSprite = require 'lib/surface/WizardSprite'
|
||||
WizardLank = require 'lib/surface/WizardLank'
|
||||
ThangType = require 'models/ThangType'
|
||||
Simulator = require 'lib/simulator/Simulator'
|
||||
{me} = require '/lib/auth'
|
||||
|
|
|
@ -359,9 +359,9 @@ module.exports = class ThangsTabView extends CocoView
|
|||
@addThangType = type
|
||||
if @addThangType
|
||||
thang = @createAddThang()
|
||||
@addThangSprite = @surface.spriteBoss.addThangToSprites thang, @surface.spriteBoss.spriteLayers['Floating']
|
||||
@addThangSprite = @surface.spriteBoss.addThangToSprites thang, @surface.spriteBoss.layerAdapters['Floating']
|
||||
@addThangSprite.notOfThisWorld = true
|
||||
@addThangSprite.imageObject.alpha = 0.75
|
||||
@addThangSprite.sprite.alpha = 0.75
|
||||
@addThangSprite.playSound? 'selected'
|
||||
pos ?= x: Math.round(@world.width / 2), y: Math.round(@world.height / 2)
|
||||
@adjustThangPos @addThangSprite, thang, pos
|
||||
|
@ -420,11 +420,11 @@ module.exports = class ThangsTabView extends CocoView
|
|||
|
||||
onSurfaceMouseOver: (e) ->
|
||||
return unless @addThangSprite
|
||||
@addThangSprite.imageObject.visible = true
|
||||
@addThangSprite.sprite.visible = true
|
||||
|
||||
onSurfaceMouseOut: (e) ->
|
||||
return unless @addThangSprite
|
||||
@addThangSprite.imageObject.visible = false
|
||||
@addThangSprite.sprite.visible = false
|
||||
|
||||
calculateMovement: (pctX, pctY, widthHeightRatio) ->
|
||||
MOVE_TOP_MARGIN = 1.0 - MOVE_MARGIN
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
ThangType = require 'models/ThangType'
|
||||
SpriteParser = require 'lib/sprites/SpriteParser'
|
||||
SpriteBuilder = require 'lib/sprites/SpriteBuilder'
|
||||
CocoSprite = require 'lib/surface/CocoSprite'
|
||||
Lank = require 'lib/surface/Lank'
|
||||
LayerAdapter = require 'lib/surface/LayerAdapter'
|
||||
Camera = require 'lib/surface/Camera'
|
||||
DocumentFiles = require 'collections/DocumentFiles'
|
||||
|
||||
|
@ -58,7 +59,7 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
@listenToOnce @thangType, 'sync', ->
|
||||
@files = @supermodel.loadCollection(new DocumentFiles(@thangType), 'files').model
|
||||
@updateFileSize()
|
||||
@refreshAnimation = _.debounce @refreshAnimation, 500
|
||||
# @refreshAnimation = _.debounce @refreshAnimation, 500
|
||||
|
||||
showLoading: ($el) ->
|
||||
$el ?= @$el.find('.outer-content')
|
||||
|
@ -74,7 +75,8 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
context
|
||||
|
||||
getAnimationNames: ->
|
||||
raw = _.keys(@thangType.get('raw', true).animations)
|
||||
raw = _.keys((@thangType.get('raw') or {}).animations)
|
||||
return [] unless raw
|
||||
raw = ("raw:#{name}" for name in raw)
|
||||
main = _.keys(@thangType.get('actions') or {})
|
||||
main.concat(raw)
|
||||
|
@ -119,6 +121,8 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
initStage: ->
|
||||
canvas = @$el.find('#canvas')
|
||||
@stage = new createjs.Stage(canvas[0])
|
||||
@layerAdapter = new LayerAdapter({name:'Default', webGL: true})
|
||||
@stage.addChild(@layerAdapter.container)
|
||||
@camera?.destroy()
|
||||
@camera = new Camera canvas
|
||||
|
||||
|
@ -128,7 +132,7 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
@groundDot = @makeDot('red')
|
||||
@stage.addChild(@groundDot, @torsoDot, @mouthDot, @aboveHeadDot)
|
||||
@updateGrid()
|
||||
@refreshAnimation()
|
||||
_.defer @refreshAnimation
|
||||
|
||||
createjs.Ticker.setFPS(30)
|
||||
createjs.Ticker.addEventListener('tick', @stage)
|
||||
|
@ -139,11 +143,11 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
|
||||
updateDots: ->
|
||||
@stage.removeChild(@torsoDot, @mouthDot, @aboveHeadDot, @groundDot)
|
||||
return unless @currentSprite
|
||||
return unless @currentLank
|
||||
return unless @showDots
|
||||
torso = @currentSprite.getOffset 'torso'
|
||||
mouth = @currentSprite.getOffset 'mouth'
|
||||
aboveHead = @currentSprite.getOffset 'aboveHead'
|
||||
torso = @currentLank.getOffset 'torso'
|
||||
mouth = @currentLank.getOffset 'mouth'
|
||||
aboveHead = @currentLank.getOffset 'aboveHead'
|
||||
@torsoDot.x = CENTER.x + torso.x * @scale
|
||||
@torsoDot.y = CENTER.y + torso.y * @scale
|
||||
@mouthDot.x = CENTER.x + mouth.x * @scale
|
||||
|
@ -153,7 +157,7 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
@stage.addChild(@groundDot, @torsoDot, @mouthDot, @aboveHeadDot)
|
||||
|
||||
endAnimation: ->
|
||||
@currentSprite?.queueAction('idle')
|
||||
@currentLank?.queueAction('idle')
|
||||
|
||||
updateGrid: ->
|
||||
grid = new createjs.Container()
|
||||
|
@ -223,23 +227,24 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
|
||||
# animation select
|
||||
|
||||
refreshAnimation: ->
|
||||
refreshAnimation: =>
|
||||
return @showRasterImage() if @thangType.get('raster')
|
||||
options = @getSpriteOptions()
|
||||
@thangType.resetSpriteSheetCache()
|
||||
spriteSheet = @thangType.buildSpriteSheet(options)
|
||||
$('#spritesheets').empty()
|
||||
return unless spriteSheet
|
||||
for image in spriteSheet._images
|
||||
$('#spritesheets').append(image)
|
||||
options = @getLankOptions()
|
||||
console.log 'refresh animation....'
|
||||
# @thangType.resetSpriteSheetCache()
|
||||
# spriteSheet = @thangType.buildSpriteSheet(options)
|
||||
# $('#spritesheets').empty()
|
||||
# return unless spriteSheet
|
||||
# for image in spriteSheet._images
|
||||
# $('#spritesheets').append(image)
|
||||
@showAnimation()
|
||||
@updatePortrait()
|
||||
|
||||
showRasterImage: ->
|
||||
sprite = new CocoSprite(@thangType, @getSpriteOptions())
|
||||
@currentSprite?.destroy()
|
||||
@currentSprite = sprite
|
||||
@showImageObject(sprite.imageObject)
|
||||
sprite = new Lank(@thangType, @getLankOptions())
|
||||
@currentLank?.destroy()
|
||||
@currentLank = sprite
|
||||
@showSprite(sprite.sprite)
|
||||
@updateScale()
|
||||
|
||||
showAnimation: (animationName) ->
|
||||
|
@ -249,7 +254,7 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
animationName = animationName[4...]
|
||||
@showMovieClip(animationName)
|
||||
else
|
||||
@showSprite(animationName)
|
||||
@showAction(animationName)
|
||||
@updateRotation()
|
||||
@updateScale() # must happen after update rotation, because updateRotation calls the sprite update() method.
|
||||
|
||||
|
@ -261,36 +266,51 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
if reg
|
||||
movieClip.regX = -reg.x
|
||||
movieClip.regY = -reg.y
|
||||
@showImageObject(movieClip)
|
||||
@showSprite(movieClip)
|
||||
|
||||
getSpriteOptions: -> {resolutionFactor: @resolution, thang: @mockThang}
|
||||
getLankOptions: -> {resolutionFactor: @resolution, thang: @mockThang}
|
||||
|
||||
showSprite: (actionName) ->
|
||||
options = @getSpriteOptions()
|
||||
sprite = new CocoSprite(@thangType, options)
|
||||
sprite.queueAction(actionName)
|
||||
@currentSprite?.destroy()
|
||||
@currentSprite = sprite
|
||||
@showImageObject(sprite.imageObject)
|
||||
showAction: (actionName) ->
|
||||
options = @getLankOptions()
|
||||
lank = new Lank(@thangType, options)
|
||||
@showLank(lank)
|
||||
lank.queueAction(actionName)
|
||||
|
||||
updatePortrait: ->
|
||||
options = @getSpriteOptions()
|
||||
options = @getLankOptions()
|
||||
portrait = @thangType.getPortraitImage(options)
|
||||
return unless portrait
|
||||
portrait?.attr('id', 'portrait').addClass('img-thumbnail')
|
||||
portrait.addClass 'img-thumbnail'
|
||||
$('#portrait').replaceWith(portrait)
|
||||
|
||||
showImageObject: (imageObject) ->
|
||||
|
||||
showLank: (lank) ->
|
||||
@clearDisplayObject()
|
||||
imageObject.x = CENTER.x
|
||||
imageObject.y = CENTER.y
|
||||
@stage.addChildAt(imageObject, 1)
|
||||
@currentObject = imageObject
|
||||
@clearLank()
|
||||
@layerAdapter.resetSpriteSheet()
|
||||
@layerAdapter.addLank(lank)
|
||||
@currentLank = lank
|
||||
lank.sprite.x = CENTER.x
|
||||
lank.sprite.y = CENTER.y
|
||||
lank.on 'new-sprite', ->
|
||||
lank.sprite.x = CENTER.x
|
||||
lank.sprite.y = CENTER.y
|
||||
|
||||
showSprite: (sprite) ->
|
||||
@clearDisplayObject()
|
||||
@clearLank()
|
||||
sprite.x = CENTER.x
|
||||
sprite.y = CENTER.y
|
||||
@stage.addChildAt(sprite, 1)
|
||||
@currentObject = sprite
|
||||
@updateDots()
|
||||
|
||||
clearDisplayObject: ->
|
||||
@stage.removeChild(@currentObject) if @currentObject?
|
||||
|
||||
clearLank: ->
|
||||
@layerAdapter.removeLank(@currentLank) if @currentLank
|
||||
@currentLank?.destroy()
|
||||
|
||||
# sliders
|
||||
|
||||
|
@ -303,9 +323,9 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
updateRotation: =>
|
||||
value = parseInt(180 * (@rotationSlider.slider('value') - 50) / 50)
|
||||
@$el.find('.rotation-label').text " #{value}° "
|
||||
if @currentSprite
|
||||
@currentSprite.rotation = value
|
||||
@currentSprite.update(true)
|
||||
if @currentLank
|
||||
@currentLank.rotation = value
|
||||
@currentLank.update(true)
|
||||
|
||||
updateScale: =>
|
||||
resValue = (@resolutionSlider.slider('value') + 1) / 10
|
||||
|
@ -313,9 +333,9 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
fixed = scaleValue.toFixed(1)
|
||||
@scale = scaleValue
|
||||
@$el.find('.scale-label').text " #{fixed}x "
|
||||
if @currentSprite
|
||||
@currentSprite.scaleFactorX = @currentSprite.scaleFactorY = scaleValue
|
||||
@currentSprite.updateScale()
|
||||
if @currentLank
|
||||
@currentLank.scaleFactorX = @currentLank.scaleFactorY = scaleValue
|
||||
@currentLank.updateScale()
|
||||
else if @currentObject?
|
||||
@currentObject.scaleX = @currentObject.scaleY = scaleValue / resValue
|
||||
@updateGrid()
|
||||
|
@ -332,7 +352,7 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
value = parseInt((@healthSlider.slider('value')) / 10)
|
||||
@$el.find('.health-label').text " #{value}hp "
|
||||
@mockThang.health = value
|
||||
@currentSprite?.update()
|
||||
@currentLank?.update()
|
||||
|
||||
# save
|
||||
|
||||
|
@ -352,7 +372,7 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
url = "/editor/thang/#{newThangType.get('slug') or newThangType.id}"
|
||||
portraitSource = null
|
||||
if @thangType.get('raster')
|
||||
image = @currentSprite.imageObject.image
|
||||
image = @currentLank.sprite.image
|
||||
portraitSource = imageToPortrait image
|
||||
# bit of a hacky way to get that portrait
|
||||
success = =>
|
||||
|
@ -422,11 +442,11 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
bounds = obj.frameBounds[0]
|
||||
obj.regX = bounds.x + bounds.width / 2
|
||||
obj.regY = bounds.y + bounds.height / 2
|
||||
@showImageObject(obj) if obj
|
||||
@showSprite(obj) if obj
|
||||
obj.y = 200 if obj # truly center the container
|
||||
@showingSelectedNode = true
|
||||
@currentSprite?.destroy()
|
||||
@currentSprite = null
|
||||
@currentLank?.destroy()
|
||||
@currentLank = null
|
||||
@updateScale()
|
||||
@grid.alpha = 0.0
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
ModalView = require 'views/kinds/ModalView'
|
||||
template = require 'templates/modal/wizard_settings'
|
||||
WizardSprite = require 'lib/surface/WizardSprite'
|
||||
WizardLank = require 'lib/surface/WizardLank'
|
||||
ThangType = require 'models/ThangType'
|
||||
{me} = require 'lib/auth'
|
||||
forms = require 'lib/forms'
|
||||
|
|
|
@ -118,7 +118,7 @@ module.exports = class LevelHUDView extends CocoView
|
|||
@listeningToCreateAvatar = true
|
||||
return
|
||||
@listeningToCreateAvatar = false
|
||||
options = thang.getSpriteOptions() or {}
|
||||
options = thang.getLankOptions() or {}
|
||||
options.async = false
|
||||
options.colorConfig = colorConfig if colorConfig
|
||||
wrapper = @$el.find '.thang-canvas-wrapper'
|
||||
|
|
|
@ -36,7 +36,7 @@ module.exports = class ThangAvatarView extends CocoView
|
|||
getRenderData: (context={}) ->
|
||||
context = super context
|
||||
context.thang = @thang
|
||||
options = @thang?.getSpriteOptions() or {}
|
||||
options = @thang?.getLankOptions() or {}
|
||||
options.async = true
|
||||
context.avatarURL = @thangType.getPortraitSource(options) unless @thangType.loading
|
||||
context.includeName = @includeName
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
SpriteBoss = require 'lib/surface/SpriteBoss'
|
||||
LankBoss = require 'lib/surface/LankBoss'
|
||||
Camera = require 'lib/surface/Camera'
|
||||
World = require 'lib/world/world'
|
||||
ThangType = require 'models/ThangType'
|
||||
|
@ -8,8 +8,8 @@ munchkinData = require 'test/app/fixtures/ogre-munchkin-m.thang.type'
|
|||
fangriderData = require 'test/app/fixtures/ogre-fangrider.thang.type'
|
||||
curseData = require 'test/app/fixtures/curse.thang.type'
|
||||
|
||||
describe 'SpriteBoss', ->
|
||||
spriteBoss = null
|
||||
describe 'LankBoss', ->
|
||||
lankBoss = null
|
||||
canvas = null
|
||||
stage = null
|
||||
midRenderExpectations = [] # bit of a hack to move tests which happen mid-initialization into a separate test
|
||||
|
@ -18,7 +18,7 @@ describe 'SpriteBoss', ->
|
|||
# check the resulting data for the whole thing, without changing anything.
|
||||
|
||||
init = (done) ->
|
||||
return done() if spriteBoss
|
||||
return done() if lankBoss
|
||||
t = new Date()
|
||||
canvas = $('<canvas width="800" height="600"></canvas>')
|
||||
camera = new Camera(canvas)
|
||||
|
@ -45,7 +45,7 @@ describe 'SpriteBoss', ->
|
|||
|
||||
thangTypes = [fangrider, segmentedMunchkin, singularMunchkin, segmentedTree, singularTree]
|
||||
|
||||
# Build the Stage and SpriteBoss.
|
||||
# Build the Stage and LankBoss.
|
||||
window.stage = stage = new createjs.SpriteStage(canvas[0])
|
||||
options = {
|
||||
camera: camera
|
||||
|
@ -55,9 +55,9 @@ describe 'SpriteBoss', ->
|
|||
thangTypes: thangTypes
|
||||
}
|
||||
|
||||
window.spriteBoss = spriteBoss = new SpriteBoss(options)
|
||||
window.lankBoss = lankBoss = new LankBoss(options)
|
||||
|
||||
defaultLayer = spriteBoss.spriteLayers.Default
|
||||
defaultLayer = lankBoss.layerAdapters.Default
|
||||
defaultLayer.buildAsync = false # cause faster
|
||||
|
||||
# Sort of an implicit test. By default, all the default actions are always rendered,
|
||||
|
@ -66,14 +66,14 @@ describe 'SpriteBoss', ->
|
|||
defaultLayer.defaultActions = ['idle']
|
||||
|
||||
# Render the simple world with just trees
|
||||
spriteBoss.update(true)
|
||||
lankBoss.update(true)
|
||||
|
||||
# Test that the unrendered, static sprites aren't showing anything
|
||||
midRenderExpectations.push([spriteBoss.sprites['Segmented Tree'].imageObject.children.length,1,'static segmented action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Segmented Tree'].imageObject.children[0].currentFrame,0,'static segmented action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Segmented Tree'].imageObject.children[0].paused,true,'static segmented action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Singular Tree'].imageObject.currentFrame,0,'static singular action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Singular Tree'].imageObject.paused,true,'static singular action'])
|
||||
midRenderExpectations.push([lankBoss.lanks['Segmented Tree'].imageObject.children.length,1,'static segmented action'])
|
||||
midRenderExpectations.push([lankBoss.lanks['Segmented Tree'].imageObject.children[0].currentFrame,0,'static segmented action'])
|
||||
midRenderExpectations.push([lankBoss.lanks['Segmented Tree'].imageObject.children[0].paused,true,'static segmented action'])
|
||||
midRenderExpectations.push([lankBoss.lanks['Singular Tree'].imageObject.currentFrame,0,'static singular action'])
|
||||
midRenderExpectations.push([lankBoss.lanks['Singular Tree'].imageObject.paused,true,'static singular action'])
|
||||
|
||||
defaultLayer.once 'new-spritesheet', ->
|
||||
|
||||
|
@ -101,15 +101,15 @@ describe 'SpriteBoss', ->
|
|||
|
||||
_.find(world.thangs, {id: 'Disappearing Tree'}).exists = false
|
||||
world.thangMap[thang.id] = thang for thang in world.thangs
|
||||
spriteBoss.update(true)
|
||||
lankBoss.update(true)
|
||||
jasmine.Ajax.requests.sendResponses({'/db/thang.type/curse': curseData})
|
||||
|
||||
# Test that the unrendered, animated sprites aren't showing anything
|
||||
midRenderExpectations.push([spriteBoss.sprites['Segmented Ogre'].imageObject.children.length,10,'animated segmented action'])
|
||||
for child in spriteBoss.sprites['Segmented Ogre'].imageObject.children
|
||||
midRenderExpectations.push([lankBoss.lanks['Segmented Ogre'].imageObject.children.length,10,'animated segmented action'])
|
||||
for child in lankBoss.lanks['Segmented Ogre'].imageObject.children
|
||||
midRenderExpectations.push([child.children[0].currentFrame, 0, 'animated segmented action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Singular Ogre'].imageObject.currentFrame,0,'animated singular action'])
|
||||
midRenderExpectations.push([spriteBoss.sprites['Singular Ogre'].imageObject.paused,true,'animated singular action'])
|
||||
midRenderExpectations.push([lankBoss.lanks['Singular Ogre'].imageObject.currentFrame,0,'animated singular action'])
|
||||
midRenderExpectations.push([lankBoss.lanks['Singular Ogre'].imageObject.paused,true,'animated singular action'])
|
||||
|
||||
defaultLayer.once 'new-spritesheet', ->
|
||||
# showMe() # Uncomment to display this world when you run any of these tests.
|
||||
|
@ -127,7 +127,7 @@ describe 'SpriteBoss', ->
|
|||
return if ticks >= 100
|
||||
ticks += 1
|
||||
if ticks % 20 is 0
|
||||
spriteBoss.update(true)
|
||||
lankBoss.update(true)
|
||||
stage.update()
|
||||
}
|
||||
createjs.Ticker.addEventListener "tick", listener
|
||||
|
@ -140,43 +140,43 @@ describe 'SpriteBoss', ->
|
|||
expect(expectation[0]).toBe(expectation[1])
|
||||
|
||||
it 'rotates and animates sprites according to thang rotation', ->
|
||||
expect(spriteBoss.sprites['Ogre N'].imageObject.currentAnimation).toBe('move_fore')
|
||||
expect(spriteBoss.sprites['Ogre E'].imageObject.currentAnimation).toBe('move_side')
|
||||
expect(spriteBoss.sprites['Ogre W'].imageObject.currentAnimation).toBe('move_side')
|
||||
expect(spriteBoss.sprites['Ogre S'].imageObject.currentAnimation).toBe('move_back')
|
||||
expect(lankBoss.lanks['Ogre N'].imageObject.currentAnimation).toBe('move_fore')
|
||||
expect(lankBoss.lanks['Ogre E'].imageObject.currentAnimation).toBe('move_side')
|
||||
expect(lankBoss.lanks['Ogre W'].imageObject.currentAnimation).toBe('move_side')
|
||||
expect(lankBoss.lanks['Ogre S'].imageObject.currentAnimation).toBe('move_back')
|
||||
|
||||
expect(spriteBoss.sprites['Ogre E'].imageObject.scaleX).toBeLessThan(0)
|
||||
expect(spriteBoss.sprites['Ogre W'].imageObject.scaleX).toBeGreaterThan(0)
|
||||
expect(lankBoss.lanks['Ogre E'].imageObject.scaleX).toBeLessThan(0)
|
||||
expect(lankBoss.lanks['Ogre W'].imageObject.scaleX).toBeGreaterThan(0)
|
||||
|
||||
it 'positions sprites according to thang pos', ->
|
||||
expect(spriteBoss.sprites['Ogre N'].imageObject.x).toBe(0)
|
||||
expect(spriteBoss.sprites['Ogre N'].imageObject.y).toBeCloseTo(-60)
|
||||
expect(spriteBoss.sprites['Ogre E'].imageObject.x).toBeCloseTo(80)
|
||||
expect(spriteBoss.sprites['Ogre E'].imageObject.y).toBe(0)
|
||||
expect(spriteBoss.sprites['Ogre W'].imageObject.x).toBe(-80)
|
||||
expect(spriteBoss.sprites['Ogre W'].imageObject.y).toBeCloseTo(0)
|
||||
expect(spriteBoss.sprites['Ogre S'].imageObject.x).toBe(0)
|
||||
expect(spriteBoss.sprites['Ogre S'].imageObject.y).toBeCloseTo(60)
|
||||
expect(lankBoss.lanks['Ogre N'].imageObject.x).toBe(0)
|
||||
expect(lankBoss.lanks['Ogre N'].imageObject.y).toBeCloseTo(-60)
|
||||
expect(lankBoss.lanks['Ogre E'].imageObject.x).toBeCloseTo(80)
|
||||
expect(lankBoss.lanks['Ogre E'].imageObject.y).toBe(0)
|
||||
expect(lankBoss.lanks['Ogre W'].imageObject.x).toBe(-80)
|
||||
expect(lankBoss.lanks['Ogre W'].imageObject.y).toBeCloseTo(0)
|
||||
expect(lankBoss.lanks['Ogre S'].imageObject.x).toBe(0)
|
||||
expect(lankBoss.lanks['Ogre S'].imageObject.y).toBeCloseTo(60)
|
||||
|
||||
it 'scales sprites according to thang scaleFactorX and scaleFactorY', ->
|
||||
expect(spriteBoss.sprites['Ogre N'].imageObject.scaleX).toBe(spriteBoss.sprites['Ogre N'].imageObject.baseScaleX * 1.5)
|
||||
expect(spriteBoss.sprites['Ogre W'].imageObject.scaleY).toBe(spriteBoss.sprites['Ogre N'].imageObject.baseScaleY * 1.5)
|
||||
expect(lankBoss.lanks['Ogre N'].imageObject.scaleX).toBe(lankBoss.lanks['Ogre N'].imageObject.baseScaleX * 1.5)
|
||||
expect(lankBoss.lanks['Ogre W'].imageObject.scaleY).toBe(lankBoss.lanks['Ogre N'].imageObject.baseScaleY * 1.5)
|
||||
|
||||
it 'sets alpha based on thang alpha', ->
|
||||
expect(spriteBoss.sprites['Ogre E'].imageObject.alpha).toBe(0.5)
|
||||
expect(lankBoss.lanks['Ogre E'].imageObject.alpha).toBe(0.5)
|
||||
|
||||
it 'orders sprites in the layer based on thang pos.y\'s', ->
|
||||
container = spriteBoss.spriteLayers.Default.container
|
||||
container = lankBoss.layerAdapters.Default.container
|
||||
l = container.children
|
||||
i1 = container.getChildIndex(_.find(container.children, (c) -> c.sprite.thang.id is 'Dying Ogre 1'))
|
||||
i2 = container.getChildIndex(_.find(container.children, (c) -> c.sprite.thang.id is 'Dying Ogre 2'))
|
||||
i3 = container.getChildIndex(_.find(container.children, (c) -> c.sprite.thang.id is 'Dying Ogre 3'))
|
||||
i4 = container.getChildIndex(_.find(container.children, (c) -> c.sprite.thang.id is 'Dying Ogre 4'))
|
||||
i1 = container.getChildIndex(_.find(container.children, (c) -> c.lank.thang.id is 'Dying Ogre 1'))
|
||||
i2 = container.getChildIndex(_.find(container.children, (c) -> c.lank.thang.id is 'Dying Ogre 2'))
|
||||
i3 = container.getChildIndex(_.find(container.children, (c) -> c.lank.thang.id is 'Dying Ogre 3'))
|
||||
i4 = container.getChildIndex(_.find(container.children, (c) -> c.lank.thang.id is 'Dying Ogre 4'))
|
||||
expect(i1).toBeGreaterThan(i2)
|
||||
expect(i2).toBeGreaterThan(i3)
|
||||
expect(i3).toBeGreaterThan(i4)
|
||||
|
||||
it 'only contains children Sprites and SpriteContainers whose spritesheet matches the Layer', ->
|
||||
defaultLayerContainer = spriteBoss.spriteLayers.Default.container
|
||||
defaultLayerContainer = lankBoss.layerAdapters.Default.container
|
||||
for c in defaultLayerContainer.children
|
||||
expect(c.spriteSheet).toBe(defaultLayerContainer.spriteSheet)
|
Loading…
Reference in a new issue