Move sync pvp status UI to control bar

Replaces level name UI for hero-ladder levels.
This commit is contained in:
Matt Lott 2014-11-18 09:01:04 -08:00
parent 547ba692e1
commit 05cc9c2f46
8 changed files with 123 additions and 129 deletions

View file

@ -207,6 +207,8 @@
failing: "Failing"
action_timeline: "Action Timeline"
click_to_select: "Click on a unit to select it."
control_bar_multiplayer: "Multiplayer"
control_bar_join_game: "Join Game"
reload: "Reload"
reload_title: "Reload All Code?"
reload_really: "Are you sure you want to reload this level back to the beginning?"

View file

@ -112,6 +112,36 @@
color: white
font-size: 18px
.multiplayer-area-container
position: relative
width: 100%
height: 50px
pointer-events: none
.multiplayer-area
min-width: 200px
max-width: 293px
height: 60px
margin: 0 auto
padding: 8px
border-image: url(/images/level/control_bar_level_name_background.png) 30 fill round
border-width: 0 15px 15px 15px
text-align: center
position: absolute
left: 50%
cursor: pointer
pointer-events: all
@include translate(-50%, 0)
.multiplayer-label
font-size: 12px
color: $control-yellow-highlight
margin-bottom: -5px
.multiplayer-status
color: white
font-size: 18px
.buttons-area
position: absolute
right: 35px
@ -167,6 +197,12 @@ html.no-borderimage
background: transparent url(/images/level/control_bar_level_name_background.png)
background-size: contain
background-repeat: no-repeat
#control-bar-view .multiplayer-area
border: 0
background: transparent url(/images/level/control_bar_level_name_background.png)
background-size: contain
background-repeat: no-repeat
body:not(.ipad)
@media only screen and (max-width: 1300px)

View file

@ -1,16 +0,0 @@
@import "app/styles/mixins"
@import "app/styles/bootstrap/variables"
// TODO: Replace this devart with nice shinies
#multiplayer-status-view
position: absolute
.player-count
color: white
.players-available
color: lightblue
.players-unavailable
color: fuchsia
.game-status
color: lightgreen

View file

@ -9,10 +9,19 @@
.glyphicon.glyphicon-play
span(data-i18n="nav.play").home-text Levels
.level-name-area-container
.level-name-area
.level-label(data-i18n="play_level.level")
.level-name= worldName
if isMultiplayerLevel
.multiplayer-area-container
.multiplayer-area
.multiplayer-label(data-i18n="play_level.control_bar_multiplayer")
if multiplayerStatus
.multiplayer-status= multiplayerStatus
else
.multiplayer-status(data-i18n="play_level.control_bar_join_game")
else
.level-name-area-container
.level-name-area
.level-label(data-i18n="play_level.level")
.level-name= worldName
.buttons-area

View file

@ -1,12 +0,0 @@
//- TODO: Replace this devart with nice shinies
div
button#multiplayer-button Multiplayer
//- span.spr
//- span.player-count #{playerCount} total players
span.spr
span.players-available #{playersAvailable} available
span.spr
span.players-unavailable #{playersUnavailable} playing
span.spr
span.game-status #{status}

View file

@ -3,8 +3,10 @@ template = require 'templates/play/level/control_bar'
{me} = require 'lib/auth'
GameMenuModal = require 'views/game-menu/GameMenuModal'
RealTimeModel = require 'models/RealTimeModel'
RealTimeCollection = require 'collections/RealTimeCollection'
LevelSetupManager = require 'lib/LevelSetupManager'
GameMenuModal = require 'views/game-menu/GameMenuModal'
module.exports = class ControlBarView extends CocoView
id: 'control-bar-view'
@ -20,13 +22,17 @@ module.exports = class ControlBarView extends CocoView
'click #game-menu-button': 'showGameMenuModal'
'click': -> Backbone.Mediator.publish 'tome:focus-editor', {}
'click .home a': 'onClickHome'
'click .multiplayer-area': 'onClickMultiplayer'
constructor: (options) ->
@worldName = options.worldName
@session = options.session
@level = options.level
@levelID = @level.get('slug')
@spectateGame = options.spectateGame ? false
super options
if @isMultiplayerLevel = @level.get('type') in ['hero-ladder']
@multiplayerStatusManager = new MultiplayerStatusManager @levelID, @onMultiplayerStateChanged
setBus: (@bus) ->
@ -40,11 +46,15 @@ module.exports = class ControlBarView extends CocoView
text += " (#{numPlayers})" if numPlayers > 1
$('#multiplayer-button', @$el).text(text)
onMultiplayerStateChanged: => @render?()
getRenderData: (c={}) ->
super c
c.worldName = @worldName
c.multiplayerEnabled = @session.get('multiplayer')
c.ladderGame = @level.get('type') in ['ladder', 'hero-ladder']
if c.isMultiplayerLevel = @isMultiplayerLevel
c.multiplayerStatus = @multiplayerStatusManager?.status
c.spectateGame = @spectateGame
@homeViewArgs = [{supermodel: @supermodel}]
if @level.get('type', true) in ['ladder', 'ladder-tutorial', 'hero-ladder']
@ -71,7 +81,7 @@ module.exports = class ControlBarView extends CocoView
@openModalView gameMenuModal
@listenToOnce gameMenuModal, 'change-hero', ->
@setupManager?.destroy()
@setupManager = new LevelSetupManager({supermodel: @supermodel, levelID: @level.get('slug'), parent: @, session: @session})
@setupManager = new LevelSetupManager({supermodel: @supermodel, levelID: @levelID, parent: @, session: @session})
@setupManager.open()
onClickHome: (e) ->
@ -79,6 +89,9 @@ module.exports = class ControlBarView extends CocoView
e.stopImmediatePropagation()
Backbone.Mediator.publish 'router:navigate', route: @homeLink, viewClass: @homeViewClass, viewArgs: @homeViewArgs
onClickMultiplayer: (e) ->
@openModalView new GameMenuModal showTab: 'multiplayer', level: @level, session: @session, supermodel: @supermodel
onDisableControls: (e) -> @toggleControls e, false
onEnableControls: (e) -> @toggleControls e, true
toggleControls: (e, enabled) ->
@ -94,4 +107,62 @@ module.exports = class ControlBarView extends CocoView
destroy: ->
@setupManager?.destroy()
@multiplayerStatusManager?.destroy()
super()
# MultiplayerStatusManager ######################################################
#
# Manages the multiplayer status, and calls @statusChangedCallback when it changes.
#
# It monitors these:
# Real-time multiplayer players
# Internal multiplayer status
#
# Real-time state variables:
# @playersCollection - Real-time multiplayer players
#
# TODO: Not currently using player counts. Should remove if we keep simple design.
#
class MultiplayerStatusManager
constructor: (@levelID, @statusChangedCallback) ->
@status = ''
# @players = {}
# @playersCollection = new RealTimeCollection('multiplayer_players/' + @levelID)
# @playersCollection.on 'add', @onPlayerAdded
# @playersCollection.each (player) => @onPlayerAdded player
Backbone.Mediator.subscribe 'real-time-multiplayer:player-status', @onMultiplayerPlayerStatus
destroy: ->
Backbone.Mediator.unsubscribe 'real-time-multiplayer:player-status', @onMultiplayerPlayerStatus
# @playersCollection?.off 'add', @onPlayerAdded
# player.off 'change', @onPlayerChanged for id, player of @players
onMultiplayerPlayerStatus: (e) =>
@status = e.status
@statusChangedCallback()
# onPlayerAdded: (player) =>
# unless player.id is me.id
# @players[player.id] = new RealTimeModel('multiplayer_players/' + @levelID + '/' + player.id)
# @players[player.id].on 'change', @onPlayerChanged
# @countPlayers player
#
# onPlayerChanged: (player) =>
# @countPlayers player
#
# countPlayers: (changedPlayer) =>
# # TODO: save this stale hearbeat threshold setting somewhere
# staleHeartbeat = new Date()
# staleHeartbeat.setMinutes staleHeartbeat.getMinutes() - 3
# @playerCount = 0
# @playersCollectionAvailable = 0
# @playersCollectionUnavailable = 0
# @playersCollection.each (player) =>
# # Assume changedPlayer is fresher than entry in @playersCollection collection
# player = changedPlayer if changedPlayer? and player.id is changedPlayer.id
# unless staleHeartbeat >= new Date(player.get('heartbeat'))
# @playerCount++
# @playersCollectionAvailable++ if player.get('state') is 'available'
# @playersCollectionUnavailable++ if player.get('state') is 'unavailable'
# @statusChangedCallback()

View file

@ -1,93 +0,0 @@
CocoView = require 'views/kinds/CocoView'
template = require 'templates/play/level/multiplayer-status'
{me} = require 'lib/auth'
RealTimeModel = require 'models/RealTimeModel'
RealTimeCollection = require 'collections/RealTimeCollection'
GameMenuModal = require 'views/game-menu/GameMenuModal'
# Real-time Multiplayer ######################################################
#
# This view displays the real-time multiplayer status for the current level.
#
# It performs these actions:
# Multiplayer button into game-menu multiplayer section
# Display number of players waiting for an opponent in this level
# Display number of players current playing a pvp game in this level
# Status for user's current real-time multiplayer session
#
# It monitors these:
# Real-time multiplayer players
# Internal multiplayer status
#
# Real-time state variables:
# @playersCollection - Real-time multiplayer players
module.exports = class MultiplayerStatusView extends CocoView
id: 'multiplayer-status-view'
template: template
subscriptions:
'real-time-multiplayer:player-status': 'onRealTimeMultiplayerPlayerStatus'
events:
'click #multiplayer-button': 'onClickMultiplayerButton'
constructor: (options) ->
super(options)
@session = options.session
@level = options.level
@levelID = options.levelID
@status = ''
@players = {}
@playersCollection = new RealTimeCollection('multiplayer_players/' + @levelID)
@playersCollection.on 'add', @onPlayerAdded
@playersCollection.each (player) => @onPlayerAdded player
destroy: ->
@playersCollection?.off 'add', @onPlayerAdded
player.off 'change', @onPlayerChanged for id, player of @players
super()
getRenderData: ->
c = super()
c.playerCount = @playerCount
c.playersAvailable = @playersCollectionAvailable
c.playersUnavailable = @playersCollectionUnavailable
c.status = @status
c
onRealTimeMultiplayerPlayerStatus: (e) ->
@status = e.status
@render?()
onClickMultiplayerButton: (e) ->
@openModalView new GameMenuModal showTab: 'multiplayer', level: @level, session: @session, supermodel: @supermodel
onPlayerAdded: (player) =>
# console.log 'MultiplayerStatusView onPlayerAdded', player
unless player.id is me.id
@players[player.id] = new RealTimeModel('multiplayer_players/' + @levelID + '/' + player.id)
@players[player.id].on 'change', @onPlayerChanged
@countPlayers player
onPlayerChanged: (player) =>
# console.log 'MultiplayerStatusView onPlayerChanged', player
@countPlayers player
countPlayers: (changedPlayer) =>
# TODO: save this stale hearbeat threshold setting somewhere
staleHeartbeat = new Date()
staleHeartbeat.setMinutes staleHeartbeat.getMinutes() - 3
@playerCount = 0
@playersCollectionAvailable = 0
@playersCollectionUnavailable = 0
@playersCollection.each (player) =>
# Assume changedPlayer is fresher than entry in @playersCollection collection
player = changedPlayer if changedPlayer? and player.id is changedPlayer.id
unless staleHeartbeat >= new Date(player.get('heartbeat'))
@playerCount++
@playersCollectionAvailable++ if player.get('state') is 'available'
@playersCollectionUnavailable++ if player.get('state') is 'unavailable'
# console.log 'MultiplayerStatusView countPlayers', @playerCount, @playersCollectionAvailable, @playersCollectionUnavailable
@render()

View file

@ -36,7 +36,6 @@ GoldView = require './LevelGoldView'
VictoryModal = require './modal/VictoryModal'
HeroVictoryModal = require './modal/HeroVictoryModal'
InfiniteLoopModal = require './modal/InfiniteLoopModal'
MultiplayerStatusView = require './MultiplayerStatusView'
LevelSetupManager = require 'lib/LevelSetupManager'
PROFILE_ME = false
@ -255,8 +254,6 @@ module.exports = class PlayLevelView extends RootView
@insertSubView new HUDView {level: @level}
@insertSubView new LevelDialogueView {level: @level}
@insertSubView new ChatView levelID: @levelID, sessionID: @session.id, session: @session
if @level.get('type') in ['hero-ladder']
@insertSubView new MultiplayerStatusView levelID: @levelID, session: @session, level: @level
@insertSubView new ProblemAlertView {}
worldName = utils.i18n @level.attributes, 'name'
@controlBar = @insertSubView new ControlBarView {worldName: worldName, session: @session, level: @level, supermodel: @supermodel}