Working on PlayLevelModal and ChooseHeroView.

This commit is contained in:
Nick Winter 2014-09-19 22:15:58 -07:00
parent 81a5b73f93
commit e3b75a69ea
17 changed files with 383 additions and 41 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

View file

@ -136,6 +136,10 @@
achievements: "Achievements"
account: "Account"
settings: "Settings"
next: "Next"
previous: "Previous"
play: "Play"
choose_inventory: "Equip Items"
items:
armor: "Armor"
@ -465,10 +469,16 @@
multiplayer_caption: "Play with friends!"
inventory:
temp: "Temp"
choose_inventory: "Equip Items"
choose_hero:
temp: "Temp"
choose_hero: "Choose Your Hero"
programming_language: "Programming Language"
programming_language_description: "Which programming language do you want to use?"
status: "Status"
weapons: "Weapons"
health: "Health"
speed: "Speed"
save_load:
granularity_saved_games: "Saved"
@ -979,6 +989,7 @@
user_remarks: "User Remarks"
versions: "Versions"
items: "Items"
heroes: "Heroes"
wizard: "Wizard"
achievement: "Achievement"
clas: "CLAs"

View file

@ -7,6 +7,16 @@ buildQueue = []
module.exports = class ThangType extends CocoModel
@className: 'ThangType'
@schema: require 'schemas/models/thang_type'
@heroes:
captain: '529ec584c423d4e83b000014'
knight: '529ffbf1cf1818f2be000001'
librarian: '52fbf74b7e01835453bd8d8e'
equestrian: '52e95b4222efc8e70900175d'
'potion-master': '52e9adf7427172ae56002172'
thoktar: '52a00542cf1818f2be000006'
'robot-walker': '5301696ad82649ec2c0c9b0d'
'michael-heasell': '53e126a4e06b897606d38bef'
'ian-elliott': '53e12be0d042f23505c3023b'
urlRoot: '/db/thang.type'
building: {}

View file

@ -38,3 +38,7 @@ module.exports =
'supermodel:load-progress-changed': c.object {required: ['progress']},
progress: {type: 'number', minimum: 0, maximum: 1}
'options:hero-changed': c.object {required: ['hero']},
hero: {type: 'object'}
locked: {type: 'boolean'}

View file

@ -237,6 +237,7 @@ table.table
.header-font
font-family: $headings-font-family
letter-spacing: 2px
body[lang='ru'], body[lang|='zh'], body[lang='pl'], body[lang='tr'], body[lang='cs'], body[lang='el'], body[lang='ro'], body[lang='vi'], body[lang='th'], body[lang='ko'], body[lang='sk'], body[lang='sl'], body[lang='bg'], body[lang='he'], body[lang='lt'], body[lang='sr'], body[lang='uk'], body[lang='hi'], body[lang='ur'], body[lang='hu']
h1, h2, h3, h4, h5, h6

View file

@ -1,3 +1,89 @@
@import "app/styles/mixins"
@import "app/styles/bootstrap/variables"
$maxHeroPortraitSize: 100px
$minHeroPortraitSize: 50px
$heroCanvasHeight: 330px
#choose-hero-view
h3
text-decoration: underline
#hero-carousel
margin: 0 auto 20px auto
.carousel-indicator-container
height: $maxHeroPortraitSize
text-align: center
width: 100%
margin-bottom: 10px
margin-top: 10px
position: relative
z-index: 1
.carousel-indicators
position: static
height: $maxHeroPortraitSize
width: 100%
margin-left: 0
background-repeat: no-repeat
.hero-indicator
width: $maxHeroPortraitSize
height: $maxHeroPortraitSize
margin: 0px 3px
background-size: contain
@include transition(0.5s ease)
border: 2px solid black
border-radius: 2px
position: relative
&.active
border-color: gold
&.locked
@include opacity(0.6)
.hero-item
&.locked
@include opacity(0.6)
canvas, .hero-stats
width: 45%
height: $heroCanvasHeight
float: left
canvas
margin-left: 5%
.hero-stats
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.6)
font-size: 24px
.carousel-control.left
border-top-left-radius: 10px
border-bottom-left-radius: 10px
.carousel-control.right
border-top-right-radius: 10px
border-bottom-right-radius: 10px
.carousel-control
height: 75%
top: 25%
width: 10%
.select-group
display: block
min-height: 20px
margin-top: 10px
margin-bottom: 10px
padding-left: 20px
vertical-align: middle
label
margin-right: 20px
margin-bottom: 0
select
font-size: 18px

View file

@ -1,4 +1,12 @@
#play-level-modal
h3
color: black
.modal-dialog
margin: 30px auto 0 auto
padding: 0
width: 726px
.background-wrapper
height: 100%
.modal-body
width: 726px - 20px
height: 550px

View file

@ -13,7 +13,7 @@ $levelDotShadowWidth: 0.8 * $levelDotWidth
$levelDotShadowHeight: 0.8 * $levelDotHeight
$levelClickRadius: 40px
$gameControlSize: 80px
$gameControlMargin: 40px
$gameControlMargin: 30px
+keyframes(levelStartedPulse)
from
@ -179,3 +179,6 @@ $gameControlMargin: 40px
background-position-x: -3 * $gameControlSize
&.settings
background-position-x: -4 * $gameControlSize
.tooltip
font-size: 24px

View file

@ -1,18 +1,52 @@
h3(data-i18n="play_level.reload_title") Reload All Code?
p(data-i18n="play_level.reload_really") Are you sure you want to reload this level back to the beginning?
#hero-carousel.carousel.slide(data-interval=0)
.carousel-indicator-container
ol.carousel-indicators
for hero, index in heroes
- var info = heroInfo[hero.get('slug')]
li(data-hero-id=hero.get('original'), title=hero.get('name'), data-slide-to=index, data-target="#hero-carousel", class="hero-indicator" + (info.status == "Locked" ? " locked" : ""))
p
a(href='#', data-dismiss="modal", aria-hidden="true", data-i18n="play_level.reload_confirm").btn.btn-primary#restart-level-confirm-button Reload All
.carousel-inner
for hero in heroes
- var info = heroInfo[hero.get('slug')]
div(class="item hero-item" + (info.status == "Locked" ? " locked" : ""), data-hero-id=hero.get('original'))
canvas.hero-canvas
.hero-stats
h2= info.fullName
p
span(data-i18n="choose_hero.status") Status
span.spr :
| #{info.status}
p
span(data-i18n="choose_hero.weapons") Weapons
span.spr :
| #{info.weapons}
p
span(data-i18n="choose_hero.health") Health
span.spr :
| #{info.health}
p
span(data-i18n="choose_hero.speed") Speed
span.spr :
| #{info.speed}
a.carousel-control.left(role="button", data-slide="prev", href="#hero-carousel")
span.glyphicon.glyphicon-chevron-left
a.carousel-control.right(role="button", data-slide="next", href="#hero-carousel")
span.glyphicon.glyphicon-chevron-right
.form
.form-group.select-group
label.control-label(for="option-code-language", data-i18n="choose_hero.programming_language") Programming Language
select#option-code-language(name="code-language")
for option in languages
option(value=option.id, selected=(me.get('aceConfig', true).language === option.id))= option.name
span.help-block(data-i18n="choose_hero.programming_language_description") Which programming language do you want to use?
if level
.form-group.select-group
label.control-label(for="#restart-level-confirm-button", data-i18n="play_level.reload_title") Reload All Code?
button(data-dismiss="modal", data-i18n="play_level.reload_confirm").btn.btn-sm.btn-danger#restart-level-confirm-button Reload All
span.help-block(data-i18n="play_level.reload_really") Are you sure you want to reload this level back to the beginning?
if showDevBits
img(src="/images/pages/game-menu/choose-hero-stub.png")
div(data-i18n="choose_hero.temp") Temp
h3 Interactions
ul
li Click a language button. Click save as default language if you want to carry it over to following levels.
li Click a hero. Right here its just a simple list on the left with a picture of the hero on the right. Might instead have a carousel on the left and stats on the right. Basically this needs more thought because its starting to look like the inventory screen, but this is more for later. Might also have the wizard coloring used here for heroes.
li Click equip and it puts in basically the inventory screen view to choose which items to start the level with.
li Click begin. A new LevelSession is created. LevelLoader is given the new/updated LevelSession, new data is loaded, world reruns.

View file

@ -1,11 +1,16 @@
extends /templates/modal/modal_base
block modal-header-content
h3(data-i18n="play.todotodotodo") Play the Level Man: #{levelName} at #{levelPath}/#{levelID}
h1#choose-hero-header(data-i18n="choose_hero.choose_hero") Choose Your Hero
h1#choose-inventory-header.secret(data-i18n="inventory.choose_inventory") Equip Items
block modal-body-content
p TODO: show dat hero selection view
#choose-hero-view
#inventory-view
block modal-footer-content
button#choose-inventory-button.btn.btn-lg.btn-success(data-i18n="play.next") Next
button#choose-hero-button.btn.btn-lg.btn-primary.secret.pull-left(data-i18n="play.previous") Previous
button#play-level-button.btn.btn-lg.btn-success.secret(data-i18n="play.play") Play

View file

@ -29,7 +29,7 @@
span(data-i18n="play.hours_played") hours played
.campaign-label(style="color: #{campaign.color}")= campaign.name
.game-controls
.game-controls.header-font
if me.isAdmin()
button.btn.items(data-toggle='coco-modal', data-target='play/modal/PlayItemsModal', data-i18n="[title]play.items")
button.btn.heroes(data-toggle='coco-modal', data-target='play/modal/PlayHeroesModal', data-i18n="[title]play.heroes")

View file

@ -2,6 +2,8 @@ CocoView = require 'views/kinds/CocoView'
template = require 'templates/game-menu/choose-hero-view'
{me} = require 'lib/auth'
ThangType = require 'models/ThangType'
CocoCollection = require 'collections/CocoCollection'
SpriteBuilder = require 'lib/sprites/SpriteBuilder'
module.exports = class ChooseHeroView extends CocoView
id: 'choose-hero-view'
@ -10,11 +12,157 @@ module.exports = class ChooseHeroView extends CocoView
events:
'click #restart-level-confirm-button': -> Backbone.Mediator.publish 'level:restart', {}
'slide.bs.carousel #hero-carousel': 'onHeroChanged'
shortcuts:
'left': -> @$el.find('#hero-carousel').carousel('prev')
'right': -> @$el.find('#hero-carousel').carousel('next')
constructor: (options) ->
super options
@heroes = new CocoCollection([], {model: ThangType})
@equipment = options.equipment or @options.session?.get('heroConfig')?.inventory or {}
@heroes.url = '/db/thang.type?view=heroes&project=original,name,slug,soundTriggers'
@supermodel.loadCollection(@heroes, 'heroes')
@stages = {}
destroy: ->
for heroIndex, stage of @stages
createjs.Ticker.removeEventListener "tick", stage
stage.removeAllChildren()
super()
getRenderData: (context={}) ->
context = super(context)
context.showDevBits = @options.showDevBits
context.heroes = @heroes.models
context.level = @options.level
context.languages = [
{id: 'python', name: 'Python'}
{id: 'javascript', name: 'JavaScript'}
{id: 'coffeescript', name: 'CoffeeScript'}
{id: 'clojure', name: 'Clojure (Experimental)'}
{id: 'lua', name: 'Lua (Experimental)'}
{id: 'io', name: 'Io (Experimental)'}
]
context.heroInfo = temporaryHeroInfo
context
afterRender: ->
super()
return unless @supermodel.finished()
@$el.find('.hero-item:first-child, .hero-indicator:first-child').addClass('active')
heroes = @heroes.models
@$el.find('.hero-indicator').each ->
heroID = $(@).data('hero-id')
hero = _.find heroes, (hero) -> hero.get('original') is heroID
$(@).css('background-image', "url(#{hero.getPortraitURL()})").tooltip()
@canvasWidth = 313 # @$el.find('canvas').width() # unreliable, whatever
@canvasHeight = @$el.find('canvas').height()
@onHeroChanged direction: null, relatedTarget: @$el.find('.hero-item')[0]
onHeroChanged: (e) ->
direction = e.direction # 'left' or 'right'
heroItem = $(e.relatedTarget)
hero = _.find @heroes.models, (hero) -> hero.get('original') is heroItem.data('hero-id')
heroIndex = heroItem.index()
@$el.find('.hero-indicator').each ->
distance = Math.min 3, Math.abs $(@).index() - heroIndex
size = 100 - (50 / 3) * distance
$(@).css width: size, height: size, top: -(100 - size) / 2
heroInfo = temporaryHeroInfo[hero.get('slug')]
hero = @loadHero hero, heroIndex
Backbone.Mediator.publish 'options:hero-changed', hero: hero, locked: heroInfo.status is 'Locked'
loadHero: (hero, heroIndex) ->
createjs.Ticker.removeEventListener 'tick', stage for stage in _.values @stages
if stage = @stages[heroIndex]
createjs.Ticker.addEventListener 'tick', stage
return hero
fullHero = new ThangType()
fullHero.setURL "/db/thang.type/#{hero.get('original')}/version"
fullHero = (@supermodel.loadModel fullHero, 'thang').model
onLoaded = =>
return unless canvas = $(".hero-item[data-hero-id='#{fullHero.get('original')}'] canvas")
canvas.prop width: @canvasWidth, height: @canvasHeight
builder = new SpriteBuilder(fullHero)
movieClip = builder.buildMovieClip(fullHero.get('actions').attack?.animation ? fullHero.get('actions').idle.animation)
movieClip.scaleX = movieClip.scaleY = canvas.prop('height') / 170 # Tallest hero so far is 160px tall at normal resolution
movieClip.regX = -fullHero.get('positions').registration.x
movieClip.regY = -fullHero.get('positions').registration.y
movieClip.x = canvas.prop('width') * 0.5
movieClip.y = canvas.prop('height') * 0.85 # This is where the feet go.
stage = new createjs.Stage(canvas[0])
stage.addChild movieClip
stage.update()
createjs.Ticker.addEventListener 'tick', stage
movieClip.gotoAndPlay 0
@stages[heroIndex] = stage
if fullHero.loaded
_.defer onLoaded
else
@listenToOnce fullHero, 'sync', onLoaded
fullHero
temporaryHeroInfo =
captain:
fullName: 'Captain Anya Weston'
weapons: 'Razor Discs'
status: 'Available'
health: '35'
speed: '4 m/s'
knight:
fullName: 'Tharin Thunderfist'
weapons: 'Swords'
status: 'Available'
health: '35'
speed: '4 m/s'
thoktar:
fullName: 'Thoktar the Devourer'
weapons: 'Magic'
status: 'Locked'
health: '???'
speed: '???'
equestrian:
fullName: 'Rider Reynaldo'
weapons: 'Axes'
status: 'Locked'
health: '???'
speed: '???'
'potion-master':
fullName: 'Master Snake'
weapons: 'Magic'
status: 'Locked'
health: '???'
speed: '???'
librarian:
fullName: 'Hushbaum'
weapons: 'Magic'
status: 'Locked'
health: '???'
speed: '???'
'robot-walker':
fullName: '???'
weapons: '???'
status: 'Locked'
health: '???'
speed: '???'
'michael-heasell':
fullName: '???'
weapons: '???'
status: 'Locked'
health: '???'
speed: '???'
'ian-elliott':
fullName: '???'
weapons: '???'
status: 'Locked'
health: '???'
speed: '???'

View file

@ -25,7 +25,7 @@ module.exports = class InventoryView extends CocoView
super(arguments...)
@items = new CocoCollection([], {model: ThangType})
@equipment = options.equipment or @options.session?.get('heroConfig')?.inventory or {}
@items.url = '/db/thang.type?view=items&project=name,description,components,original,rasterIcon'
@items.url = '/db/thang.type?view=items&project=name,components,original,rasterIcon'
@supermodel.loadCollection(@items, 'items')
onLoaded: ->

View file

@ -84,7 +84,9 @@ module.exports = class WorldMapView extends RootView
console.log " x: #{(100 * x).toFixed(2)}\n y: #{(100 * y).toFixed(2)}\n"
onClickLevel: (e) ->
playLevelModal = new PlayLevelModal supermodel: @options.supermodel, levelID: $(e.target).data('level-id'), levelPath: $(e.target).data('level-path'), levelName: $(e.target).data('level-name')
e.preventDefault()
return if $(e.target).attr('disabled')
playLevelModal = new PlayLevelModal supermodel: @supermodel, levelID: $(e.target).data('level-id'), levelPath: $(e.target).data('level-path'), levelName: $(e.target).data('level-name')
@openModalView playLevelModal
onMouseEnterLevel: (e) ->

View file

@ -6,12 +6,15 @@ InventoryView = require 'views/game-menu/InventoryView'
module.exports = class PlayLevelModal extends ModalView
className: 'modal fade play-modal'
template: template
modalWidthPercent: 90
id: 'play-level-modal'
#instant: true
#events:
# 'change input.select': 'onSelectionChanged'
events:
'click #choose-inventory-button': 'onClickChooseInventory'
'click #choose-hero-button': 'onClickChooseHero'
'click #play-level-button': 'onClickPlayLevel'
subscriptions:
'options:hero-changed': 'onHeroChanged'
constructor: (options) ->
super options
@ -28,15 +31,25 @@ module.exports = class PlayLevelModal extends ModalView
super()
return unless @supermodel.finished()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
@addChooseHeroView()
@addInventoryView()
@insertSubView @chooseHeroView = new ChooseHeroView @options
@insertSubView @inventoryView = new InventoryView @options
@inventoryView.$el.addClass 'secret'
onHidden: ->
super()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1
addChooseHeroView: ->
@insertSubView new ChooseHeroView @options
onClickChooseInventory: (e) ->
@chooseHeroView.$el.add('#choose-inventory-button, #choose-hero-header').addClass 'secret'
@inventoryView.$el.add('#choose-hero-button, #play-level-button, #choose-inventory-header').removeClass 'secret'
addInventoryView: ->
@insertSubView new InventoryView @options
onClickChooseHero: (e) ->
@chooseHeroView.$el.add('#choose-inventory-button, #choose-hero-header').removeClass 'secret'
@inventoryView.$el.add('#choose-hero-button, #play-level-button, #choose-inventory-header').addClass 'secret'
onClickPlayLevel: (e) ->
console.log 'should play!'
onHeroChanged: (e) ->
@$el.find('#choose-inventory-button').prop 'disabled', Boolean e.locked
@hero = e.hero

View file

@ -1,6 +1,17 @@
ThangType = require './ThangType'
Handler = require '../../commons/Handler'
heroes =
captain: '529ec584c423d4e83b000014'
knight: '529ffbf1cf1818f2be000001'
librarian: '52fbf74b7e01835453bd8d8e'
equestrian: '52e95b4222efc8e70900175d'
'potion-master': '52e9adf7427172ae56002172'
thoktar: '52a00542cf1818f2be000006'
'robot-walker': '5301696ad82649ec2c0c9b0d'
'michael-heasell': '53e126a4e06b897606d38bef'
'ian-elliott': '53e12be0d042f23505c3023b'
ThangTypeHandler = class ThangTypeHandler extends Handler
modelClass: ThangType
jsonSchema: require '../../../app/schemas/models/thang_type'
@ -28,11 +39,17 @@ ThangTypeHandler = class ThangTypeHandler extends Handler
req.method is 'GET' or req.user?.isAdmin()
get: (req, res) ->
if req.query.view is 'items'
if req.query.view in ['items', 'heroes']
projection = {}
if req.query.project
projection[field] = 1 for field in req.query.project.split(',')
ThangType.find({ 'kind': 'Item', slug: { $exists: true } }, projection).exec (err, documents) =>
query = slug: {$exists: true}
if req.query.view is 'items'
query.kind = 'Item'
else if req.query.view is 'heroes'
query.kind = 'Unit'
query.original = {$in: _.values heroes} # TODO: replace with some sort of ThangType property later
ThangType.find(query, projection).exec (err, documents) =>
return @sendDatabaseError(res, err) if err
documents = (@formatEntity(req, doc) for doc in documents)
@sendSuccess(res, documents)