Set up talking portraits in the hud.

This commit is contained in:
Scott Erickson 2014-01-09 11:04:22 -08:00
parent 391207d00f
commit 8077c62ceb
8 changed files with 72 additions and 75 deletions

View file

@ -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

View file

@ -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: ->

View file

@ -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

View file

@ -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'

View file

@ -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

View file

@ -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

View file

@ -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)

View 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()