mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-02-17 08:50:58 -05:00
Set up talking portraits in the hud.
This commit is contained in:
parent
391207d00f
commit
8077c62ceb
8 changed files with 72 additions and 75 deletions
|
@ -129,7 +129,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
reg = @getOffset 'registration'
|
||||
@imageObject.regX = -reg.x
|
||||
@imageObject.regY = -reg.y
|
||||
if @currentRootAction.name is 'move'
|
||||
if @currentRootAction.name is 'move' and action.frames
|
||||
start = Math.floor(Math.random() * action.frames.length)
|
||||
@imageObject.currentAnimationFrame = start
|
||||
|
||||
|
@ -375,6 +375,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
e = _.clone(e)
|
||||
e.sprite = @
|
||||
e.blurb ?= '...'
|
||||
e.thang = @thang
|
||||
Backbone.Mediator.publish 'sprite:speech-updated', e
|
||||
|
||||
isTalking: ->
|
||||
|
@ -427,5 +428,5 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
delay = if withDelay and sound.delay then 1000 * sound.delay / createjs.Ticker.getFPS() else 0
|
||||
name = AudioPlayer.nameForSoundReference sound
|
||||
instance = createjs.Sound.play name, "none", delay, 0, 0, volume
|
||||
#console.log @thang?.id, "played sound", name, "with delay", delay, "volume", volume, "and got sound instance", instance
|
||||
# console.log @thang?.id, "played sound", name, "with delay", delay, "volume", volume, "and got sound instance", instance
|
||||
instance
|
|
@ -233,7 +233,7 @@ module.exports = class SpriteBoss extends CocoClass
|
|||
sprite?.selected = true
|
||||
@selectedSprite = sprite
|
||||
alive = sprite?.thang.health > 0
|
||||
sprite.playSound 'selected' if alive and not @suppressSelectionSounds
|
||||
|
||||
Backbone.Mediator.publish "surface:sprite-selected",
|
||||
thang: if sprite then sprite.thang else null
|
||||
sprite: sprite
|
||||
|
@ -241,6 +241,14 @@ module.exports = class SpriteBoss extends CocoClass
|
|||
originalEvent: e
|
||||
worldPos: worldPos
|
||||
|
||||
if alive and not @suppressSelectionSounds
|
||||
instance = sprite.playSound 'selected'
|
||||
if instance.playState is 'playSucceeded'
|
||||
Backbone.Mediator.publish 'thang-began-talking', thang: sprite?.thang
|
||||
instance.addEventListener 'complete', ->
|
||||
Backbone.Mediator.publish 'thang-finished-talking', thang: sprite?.thang
|
||||
console.log 'select...', instance.playState
|
||||
|
||||
# Marks
|
||||
|
||||
updateSelection: ->
|
||||
|
|
|
@ -179,7 +179,7 @@ module.exports.Trailmaster = class Trailmaster
|
|||
animation = sprite.getActionDirection(animation) ? animation # no idea if this ever works
|
||||
clone.gotoAndStop animation.name
|
||||
# TODO: use action-specific framerate here?
|
||||
clone.currentAnimationFrame = Math.min(@clock % (animation.frames.length * 3), animation.frames.length - 1)
|
||||
# clone.currentAnimationFrame = Math.min(@clock % (animation.frames.length * 3), animation.frames.length - 1)
|
||||
sprites.push(clone)
|
||||
lastPos = x: thang.pos.x, y: thang.pos.y
|
||||
lastAction = action.name
|
||||
|
|
|
@ -155,7 +155,7 @@ module.exports = class ThangType extends CocoModel
|
|||
|
||||
getPortraitStage: (spriteOptionsOrKey, size=100) ->
|
||||
key = spriteOptionsOrKey
|
||||
key = if _.isObject(key) then @spriteSheetKey(key) else key
|
||||
key = if _.isString(key) then key else @spriteSheetKey(@fillOptions(key))
|
||||
spriteSheet = @spriteSheets[key]
|
||||
spriteSheet ?= @buildSpriteSheet({portraitOnly:true})
|
||||
return unless spriteSheet
|
||||
|
@ -170,15 +170,19 @@ module.exports = class ThangType extends CocoModel
|
|||
stage.update()
|
||||
stage.startTalking = ->
|
||||
sprite.gotoAndPlay 'portrait'
|
||||
return if @tick
|
||||
@tick = => @update()
|
||||
createjs.Ticker.addEventListener 'tick', @tick
|
||||
stage.stopTalking = ->
|
||||
sprite.gotoAndStop 'portrait'
|
||||
@update()
|
||||
createjs.Ticker.removeEventListener 'tick', @tick
|
||||
@tick = null
|
||||
stage
|
||||
|
||||
uploadGenericPortrait: (callback) ->
|
||||
src = @getPortraitSource()
|
||||
return unless src
|
||||
return callback?() unless src
|
||||
src = src.replace('data:image/png;base64,', '').replace(/\ /g, '+')
|
||||
body =
|
||||
filename: 'portrait.png'
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
.no-selection-message
|
||||
display: none
|
||||
|
||||
.thang-image-wrapper, .speaker-image-wrapper
|
||||
.thang-canvas-wrapper, .speaker-image-wrapper
|
||||
width: 100px
|
||||
height: 100px
|
||||
border: 1px solid darkred
|
||||
|
@ -71,9 +71,11 @@
|
|||
|
||||
&.team-humans
|
||||
border-color: darkred
|
||||
background-color: rgba(255,100,100,0.5)
|
||||
|
||||
&.team-ogres
|
||||
border-color: darkblue
|
||||
background-color: rgba(100,100,255,0.5)
|
||||
|
||||
.thang-props
|
||||
width: 144px
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
.center
|
||||
|
||||
.thang-image-wrapper.thang-elem
|
||||
img.thang-image
|
||||
.thang-canvas-wrapper.thang-elem
|
||||
canvas.thang-canvas
|
||||
|
||||
.thang-props.thang-elem
|
||||
.thang-name
|
||||
|
@ -17,9 +17,6 @@
|
|||
tbody
|
||||
|
||||
.dialogue-area
|
||||
.speaker-image-wrapper
|
||||
canvas.thang-canvas(width=100, height=100)
|
||||
img.speaker-image
|
||||
p.bubble.dialogue-bubble
|
||||
|
||||
.no-selection-message
|
||||
|
|
|
@ -166,7 +166,7 @@ module.exports = class ThangTypeEditView extends View
|
|||
@file = e.target.files[0]
|
||||
return unless @file
|
||||
return unless @file.type is 'text/javascript'
|
||||
@$el.find('#upload-button').prop('disabled', true)
|
||||
# @$el.find('#upload-button').prop('disabled', true)
|
||||
@reader = new FileReader()
|
||||
@reader.onload = @onFileLoad
|
||||
@reader.readAsText(@file)
|
||||
|
|
|
@ -10,25 +10,25 @@ module.exports = class HUDView extends View
|
|||
template: template
|
||||
dialogueMode: false
|
||||
|
||||
constructor: (options) ->
|
||||
@thangIDMap = {}
|
||||
super options
|
||||
|
||||
subscriptions:
|
||||
'surface:frame-changed': 'onFrameChanged'
|
||||
'level-disable-controls': 'onDisableControls'
|
||||
'level-enable-controls': 'onEnableControls'
|
||||
'surface:sprite-selected': 'onSpriteSelected'
|
||||
'sprite:speech-updated': 'onSpriteDialogue'
|
||||
'level-sprite-clear-dialogue': 'onSpriteClearDialogue'
|
||||
'level-disable-controls': 'onDisableControls'
|
||||
'level-enable-controls': 'onEnableControls'
|
||||
'level:shift-space-pressed': 'onShiftSpacePressed'
|
||||
'god:new-world-created': 'onNewWorldCreated'
|
||||
'surface:ticked': 'onTick'
|
||||
'dialogue-sound-completed': 'onDialogueSoundCompleted'
|
||||
'thang-began-talking': 'onThangBeganTalking'
|
||||
'thang-finished-talking': 'onThangFinishedTalking'
|
||||
|
||||
events:
|
||||
'click': -> Backbone.Mediator.publish 'focus-editor'
|
||||
|
||||
afterRender: =>
|
||||
super()
|
||||
@$el.addClass 'no-selection'
|
||||
|
||||
onFrameChanged: (e) ->
|
||||
@timeProgress = e.progress
|
||||
@update()
|
||||
|
@ -41,100 +41,83 @@ module.exports = class HUDView extends View
|
|||
return if e.controls and not ('hud' in e.controls)
|
||||
@disabled = false
|
||||
|
||||
onNewWorldCreated: (e) ->
|
||||
@thangIDMap = {}
|
||||
for thang in e.world.thangs
|
||||
if @thang?.id is thang.id
|
||||
#console.log('HUD updated thang for', thang.id)
|
||||
@thang = thang
|
||||
@createActions()
|
||||
@thangIDMap[thang.id] = thang.spriteName
|
||||
|
||||
onSpriteSelected: (e) ->
|
||||
# TODO: this allows the surface and HUD selection to get out of sync if we select another unit while in dialogue mode
|
||||
return if @disabled or @dialogueMode
|
||||
@switchToThangElements()
|
||||
@setThang e.thang
|
||||
@setThang e.thang, e.sprite?.thangType
|
||||
|
||||
onSpriteDialogue: (e) ->
|
||||
return unless e.message
|
||||
spriteID = e.sprite.thang.id
|
||||
spriteName = e.sprite.thangType?.get('name') or e.sprite.thang.spriteName
|
||||
@setSpeaker spriteID, spriteName
|
||||
@startAnimation spriteID
|
||||
@setSpeaker e.sprite
|
||||
@stage?.startTalking()
|
||||
@setMessage(e.message, e.mood, e.responses)
|
||||
window.tracker?.trackEvent 'Heard Sprite', {speaker: spriteID, message: e.message, label: e.message}, ['Google Analytics']
|
||||
|
||||
startAnimation: (spriteID) =>
|
||||
@speakerStage.removeAllChildren()
|
||||
|
||||
#spriteData = spriteMap.dataForThang(spriteID)
|
||||
spriteData = null # we deleted SpriteMap, but haven't refactored to use vector animated portraits yet
|
||||
|
||||
canvas = $('canvas', @$el)
|
||||
image = $('.speaker-image', @$el)
|
||||
if spriteData?.sprite_data?.animations.portrait
|
||||
image.hide()
|
||||
canvas.show()
|
||||
else
|
||||
image.show()
|
||||
canvas.hide()
|
||||
return
|
||||
|
||||
onDialogueSoundCompleted: ->
|
||||
return unless @portraitSprite
|
||||
@portraitSprite.gotoAndPlay('portrait_idle')
|
||||
|
||||
onTick: ->
|
||||
@speakerStage.update()
|
||||
@stage?.stopTalking()
|
||||
|
||||
onSpriteClearDialogue: ->
|
||||
@clearSpeaker()
|
||||
|
||||
afterRender: =>
|
||||
super()
|
||||
@$el.addClass 'no-selection'
|
||||
@speakerStage = new createjs.Stage($('canvas', @$el)[0])
|
||||
|
||||
setThang: (thang) ->
|
||||
setThang: (thang, thangType) ->
|
||||
unless @speaker
|
||||
if not thang? and not @thang? then return
|
||||
if thang? and @thang? and thang.id is @thang.id then return
|
||||
|
||||
@thang = thang
|
||||
@thangType = thangType
|
||||
@$el.toggleClass 'no-selection', not @thang?
|
||||
clearTimeout @hintNextSelectionTimeout
|
||||
@$el.find('.no-selection-message').hide()
|
||||
if not @thang
|
||||
@hintNextSelectionTimeout = _.delay((=> @$el.find('.no-selection-message').slideDown('slow')), 10000)
|
||||
return
|
||||
@createAvatar @thang.id, @sprite
|
||||
@createAvatar thangType
|
||||
@createProperties()
|
||||
@createActions()
|
||||
@update()
|
||||
@speaker = null
|
||||
|
||||
setSpeaker: (speaker, speakerType) ->
|
||||
return if speaker is @speaker
|
||||
image = @$el.find '.speaker-image'
|
||||
spriteUtils.createAvatar @thangIDMap[speakerType] or speakerType, image
|
||||
@speaker = speaker
|
||||
setSpeaker: (speakerSprite) ->
|
||||
return if speakerSprite is @speakerSprite
|
||||
@speakerSprite = speakerSprite
|
||||
@speaker = @speakerSprite.thang.id
|
||||
@createAvatar @speakerSprite.thangType
|
||||
@$el.removeClass 'no-selection'
|
||||
@switchToDialogueElements()
|
||||
|
||||
clearSpeaker: ->
|
||||
if not @thang
|
||||
@$el.addClass 'no-selection'
|
||||
#console.log "clearSpeaker and have thang", @thang
|
||||
@setThang @thang
|
||||
@switchToThangElements()
|
||||
@speaker = null
|
||||
@speakerSprite = null
|
||||
@bubble = null
|
||||
@update()
|
||||
|
||||
createAvatar: (id) ->
|
||||
image = @$el.find '.thang-image'
|
||||
spriteUtils.createAvatar @thangIDMap[id] or id, image
|
||||
image.attr('title', id).parent().removeClass('team-ogres').removeClass('team-humans').addClass('team-' + @thang.team)
|
||||
createAvatar: (thangType) ->
|
||||
stage = thangType.getPortraitStage()
|
||||
wrapper = @$el.find '.thang-canvas-wrapper'
|
||||
newCanvas = $(stage.canvas).addClass('thang-canvas')
|
||||
wrapper.empty().append(newCanvas)
|
||||
team = @thang?.team or @speakerSprite?.thang?.team
|
||||
newCanvas.parent().removeClass('team-ogres').removeClass('team-humans').addClass("team-#{team}")
|
||||
stage.update()
|
||||
@stage?.stopTalking()
|
||||
@stage = stage
|
||||
f = => console.log 'new canvas style timeout', newCanvas.attr 'style'
|
||||
setTimeout f, 1000
|
||||
|
||||
onThangBeganTalking: (e) ->
|
||||
return unless @stage and @thang is e.thang
|
||||
@stage?.startTalking()
|
||||
|
||||
onThangFinishedTalking: (e) ->
|
||||
return unless @stage and @thang is e.thang
|
||||
@stage?.stopTalking()
|
||||
|
||||
createProperties: ->
|
||||
props = @$el.find('.thang-props')
|
||||
|
@ -215,6 +198,7 @@ module.exports = class HUDView extends View
|
|||
switchToDialogueElements: ->
|
||||
@dialogueMode = true
|
||||
$('.thang-elem', @$el).addClass('hide')
|
||||
@$el.find('.thang-canvas-wrapper').removeClass('hide')
|
||||
$('.dialogue-area', @$el)
|
||||
.removeClass('hide')
|
||||
.animate({opacity:1.0}, 200)
|
||||
|
@ -231,11 +215,8 @@ module.exports = class HUDView extends View
|
|||
|
||||
update: ->
|
||||
return unless @thang and not @speaker
|
||||
# Update avatar?
|
||||
|
||||
# Update properties
|
||||
@updatePropElement(prop, @thang[prop]) for prop in @thang.hudProperties ? []
|
||||
|
||||
# Update action timeline
|
||||
@updateActions()
|
||||
|
||||
|
@ -339,3 +320,7 @@ module.exports = class HUDView extends View
|
|||
timeline.append bar
|
||||
|
||||
ael
|
||||
|
||||
destroy: ->
|
||||
super()
|
||||
@stage?.stopTalking()
|
Loading…
Reference in a new issue