codecombat/app/lib/surface/Dimmer.coffee

73 lines
2.5 KiB
CoffeeScript

CocoClass = require 'core/CocoClass'
module.exports = class Dimmer extends CocoClass
subscriptions:
'level:disable-controls': 'onDisableControls'
'level:enable-controls': 'onEnableControls'
'sprite:highlight-sprites': 'onHighlightSprites'
'sprite:speech-updated': 'onSpriteSpeechUpdated'
'surface:frame-changed': 'onFrameChanged'
'camera:zoom-updated': 'onZoomUpdated'
constructor: (options) ->
super()
options ?= {}
@camera = options.camera
@layer = options.layer
console.error @toString(), 'needs a camera.' unless @camera
console.error @toString(), 'needs a layer.' unless @layer
@build()
@updateDimMask = _.throttle @updateDimMask, 10
@highlightedThangIDs = []
@sprites = {}
toString: -> '<Dimmer>'
build: ->
@dimLayer = new createjs.Container()
@dimLayer.mouseEnabled = @dimLayer.mouseChildren = false
@dimLayer.addChild @dimScreen = new createjs.Shape()
@dimLayer.addChild @dimMask = new createjs.Shape()
@dimScreen.graphics.beginFill('rgba(0,0,0,0.5)').rect 0, 0, @camera.canvasWidth, @camera.canvasHeight
@dimMask.compositeOperation = 'destination-out'
@dimLayer.cache 0, 0, @camera.canvasWidth, @camera.canvasHeight
onDisableControls: (e) ->
return if @on or (e.controls and not ('surface' in e.controls))
@dim()
onEnableControls: (e) ->
return if not @on or (e.controls and not ('surface' in e.controls))
@undim()
onSpriteSpeechUpdated: (e) -> @updateDimMask() if @on
onFrameChanged: (e) -> @updateDimMask() if @on
onZoomUpdated: (e) -> @updateDimMask() if @on
onHighlightSprites: (e) ->
@highlightedThangIDs = e.thangIDs ? []
@updateDimMask() if @on
setSprites: (@sprites) ->
dim: ->
@on = true
@layer.addChild @dimLayer
@layer.updateLayerOrder()
sprite.setDimmed true for thangID, sprite of @sprites
@updateDimMask()
undim: ->
@on = false
@layer.removeChild @dimLayer
sprite.setDimmed false for thangID, sprite of @sprites
updateDimMask: =>
@dimMask.graphics.clear()
for thangID, sprite of @sprites
continue unless (thangID in @highlightedThangIDs) or sprite.isTalking?()
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)
@dimLayer.updateCache 0, 0, @camera.canvasWidth, @camera.canvasHeight