From 7dbfd25ef3281975a7e9c457e6accddca4baf4bb Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Sun, 22 Nov 2015 22:33:15 -0800 Subject: [PATCH] Add basic support for displaying multiblock steps --- Gruntfile.coffee | 1 - src/coffee/controllers/base_controller.coffee | 40 ++--- .../controllers/item_page_controller.coffee | 47 ++++-- .../controllers/multiblock_controller.coffee | 156 ++++++++++++++++++ .../multiblock_viewer_controller.coffee | 68 ++++++++ src/coffee/models/multiblock.coffee | 4 + src/jade/templates/item_page.jade | 5 + src/jade/templates/multiblock.jade | 8 + src/jade/templates/multiblock_viewer.jade | 12 ++ src/scss/templates/index.scss | 2 + src/scss/templates/multiblock.scss | 15 ++ src/scss/templates/multiblock_viewer.scss | 26 +++ 12 files changed, 342 insertions(+), 42 deletions(-) create mode 100644 src/coffee/controllers/multiblock_controller.coffee create mode 100644 src/coffee/controllers/multiblock_viewer_controller.coffee create mode 100644 src/jade/templates/multiblock.jade create mode 100644 src/jade/templates/multiblock_viewer.jade create mode 100644 src/scss/templates/multiblock.scss create mode 100644 src/scss/templates/multiblock_viewer.scss diff --git a/Gruntfile.coffee b/Gruntfile.coffee index 4be0962df..dba9fd47e 100644 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -76,7 +76,6 @@ module.exports = (grunt)-> node: true processName: (f)-> f = f.replace './src/jade/templates/', '' - f = f.replace '_view', '' f = f.replace '.jade', '' f = f.replace /\//g, '_' return f diff --git a/src/coffee/controllers/base_controller.coffee b/src/coffee/controllers/base_controller.coffee index 01c892594..28cc90200 100644 --- a/src/coffee/controllers/base_controller.coffee +++ b/src/coffee/controllers/base_controller.coffee @@ -107,30 +107,24 @@ module.exports = class BaseController extends backbone.View # Property Methods ############################################################################# - getModel: -> - return @_model - - setModel: (newModel)-> - return if @model is newModel - - newModel = @onWillChangeModel @_model, newModel - @_model = newModel - @tryRefresh() - - isRendered: -> - return @_rendered - - getUser: -> - return @_user - - setUser: (user)-> - @_user = user - @tryRefresh() - Object.defineProperties @prototype, - model: {get:@prototype.getModel, set:@prototype.setModel} - rendered: {get:@prototype.isRendered } - user: {get:@prototype.getUser, set:@prototype.setUser} + model: + get: -> @_model + set: (newModel)-> + return if @model is newModel + + newModel = @onWillChangeModel @_model, newModel + @_model = newModel + @tryRefresh() + + rendered: + get: -> @_rendered + + user: + get: -> @_user + set: (newUser)-> + @_user = newUser + @tryRefresh() # Backbone.View Overrides ###################################################################### diff --git a/src/coffee/controllers/item_page_controller.coffee b/src/coffee/controllers/item_page_controller.coffee index 685e40368..6b33d6222 100644 --- a/src/coffee/controllers/item_page_controller.coffee +++ b/src/coffee/controllers/item_page_controller.coffee @@ -5,24 +5,25 @@ Copyright (c) 2015 by Redwood Labs All rights reserved. ### -AdsenseController = require './adsense_controller' -EditableFile = require '../models/editable_file' -FullRecipeController = require './full_recipe_controller' -ImageLoader = require './image_loader' -Item = require '../models/item' -ItemGroupController = require './item_group_controller' -ItemPage = require '../models/item_page' -ItemSlug = require '../models/item_slug' -MarkdownSectionController = require './markdown_section_controller' -PageController = require './page_controller' -VideoController = require './video_controller' -_ = require 'underscore' -w = require 'when' -{Duration} = require '../constants' -{Event} = require '../constants' -{GitHub} = require '../constants' -{Text} = require '../constants' -{Url} = require '../constants' +_ = require 'underscore' +AdsenseController = require './adsense_controller' +{Duration} = require '../constants' +EditableFile = require '../models/editable_file' +{Event} = require '../constants' +FullRecipeController = require './full_recipe_controller' +{GitHub} = require '../constants' +ImageLoader = require './image_loader' +Item = require '../models/item' +ItemGroupController = require './item_group_controller' +ItemPage = require '../models/item_page' +ItemSlug = require '../models/item_slug' +MarkdownSectionController = require './markdown_section_controller' +MultiblockViewerController = require './multiblock_viewer_controller' +PageController = require './page_controller' +{Text} = require '../constants' +{Url} = require '../constants' +VideoController = require './video_controller' +w = require 'when' ######################################################################################################################## @@ -77,6 +78,7 @@ module.exports = class ItemPageController extends PageController @adsenseController = @addChild AdsenseController, '.view__adsense', model:'sidebar_skyscraper' options = imageLoader:@imageLoader, modPack:@modPack, show:false + @_multiblockController = @addChild MultiblockViewerController, '.view__multiblock_viewer', options @_similarItemsController = @addChild ItemGroupController, '.view__item_group.similar', options @_usedAsToolToMakeController = @addChild ItemGroupController, '.view__item_group.usedAsToolToMake', options @_usedToMakeController = @addChild ItemGroupController, '.view__item_group.usedToMake', options @@ -91,6 +93,7 @@ module.exports = class ItemPageController extends PageController @$byline = @$('.byline') @$bylineLink = @$('.byline a') @$descriptionSection = @$('.description') + @$multiblockSection = @$('.multiblock.section') @$name = @$('h1.name') @$officialPageLink = @$('a.officialPage') @$recipeContainer = @$('.recipes .panel') @@ -127,6 +130,7 @@ module.exports = class ItemPageController extends PageController @_refreshByline() @_refreshDescription() + @_refreshMultiblock() @_refreshRecipes() @_refreshSimilarItems() @_refreshUsedAsToolToMake() @@ -217,6 +221,13 @@ module.exports = class ItemPageController extends PageController @_descriptionController.model = @model.item.description @_descriptionController.resetToDefaultState() + _refreshMultiblock: -> + if @model.item?.multiblock? + @_multiblockController.model = @model.item.multiblock + @show @$multiblockSection + else + @hide @$multiblockSection + _refreshRecipes: -> @_recipeControllers ?= [] index = 0 diff --git a/src/coffee/controllers/multiblock_controller.coffee b/src/coffee/controllers/multiblock_controller.coffee new file mode 100644 index 000000000..03701e88d --- /dev/null +++ b/src/coffee/controllers/multiblock_controller.coffee @@ -0,0 +1,156 @@ +### +Crafting Guide - multiblock_controller.coffee + +Copyright (c) 2014-2015 by Redwood Labs +All rights reserved. +### + +$ = require 'jquery' +_ = require '../underscore_mixins' +BaseController = require './base_controller' + +######################################################################################################################## + +module.exports = class MultiblockController extends BaseController + + @::IMAGE_SIZE = 48 # px + + @::X_LAYER_H_SHIFT = -24 # px + @::Z_LAYER_H_SHIFT = +24 # px + + @::X_LAYER_V_SHIFT = -12 # px + @::Y_LAYER_V_SHIFT = -30 # px + @::Z_LAYER_V_SHIFT = -12 # px + + @::MAX_DROP_DELAY = 250 # ms + + constructor: (options={})-> + if not options.imageLoader? then throw new Error 'options.imageLoader is required' + if not options.modPack? then throw new Error 'options.modPack is required' + options.templateName = 'multiblock' + super options + + @_currentLayer = 0 + @_blockCache = null + @_imageLoader = options.imageLoader + @_modPack = options.modPack + + # Public Methods ############################################################################### + + goBackLayer: -> + @_currentLayer = Math.max 0, @_currentLayer - 1 + @_refreshAllBlocks() + + goNextLayer: -> + @_currentLayer = Math.min @model.height - 1, @_currentLayer + 1 + @_refreshAllBlocks() + + hasBackLayer: -> + return false unless @model? + return @_currentLayer > 0 + + hasNextLayer: -> + return false unless @model? + return @_currentLayer < @model.height - 1 + + # BaseController Overrides ##################################################################### + + onDidRender: -> + # do nothing + + refresh: -> + @$el.css 'min-height':@_computeMinHeight(), 'min-width':@_computeMinWidth() + + @_refreshBlockCache() + @_refreshAllBlocks() + + # Private Methods ############################################################################## + + _computePosition: (x, y, z, options={})-> + if not @model? then return left:0, top:-@IMAGE_SIZE, 'z-index':0, opacity:0.0 + + options.hideUpperLayers ?= false + pxWidth = @$el.width() + pxHeight = @$el.height() + + left = ((pxWidth - @IMAGE_SIZE) / 2) + (x * @X_LAYER_H_SHIFT) + (z * @Z_LAYER_H_SHIFT) + + if options.hideUpperLayers and y > @_currentLayer + top = 0 + opacity = 0.0 + else + top = (pxHeight - @IMAGE_SIZE) + (x * @X_LAYER_V_SHIFT) + (z * @Z_LAYER_V_SHIFT) + (y * @Y_LAYER_V_SHIFT) + opacity = 1.0 + + zindex = (@model.width - x) + (@model.depth - z) + ((@model.width * @model.depth) * y) + + return left:left, top:top, 'z-index':zindex, opacity:opacity + + _computeMinHeight: -> + return 0 unless @model? + + minHeight = Math.max(Math.abs(@model.width * @X_LAYER_V_SHIFT), Math.abs(@model.depth * @Z_LAYER_V_SHIFT)) + minHeight += Math.abs(@model.height * @Y_LAYER_V_SHIFT) + minHeight += 2 * @IMAGE_SIZE + return minHeight + + _computeMinWidth: -> + return 0 unless @model? + + leftPosition = @_computePosition @model.width, 0, 0 + rightPosition = @_computePosition 0, 0, @model.depth + return rightPosition.left - leftPosition.left + + _randomDropDelay: -> + return Math.random() * @MAX_DROP_DELAY + + _refreshBlockCache: -> + @_blockCache = null + return unless @model? + + @_blockCache = width:@model.width, height:@model.height, depth:@model.depth + for x in [0...@model.width] + @_blockCache[x] ?= {} + for y in [0...@model.height] + @_blockCache[x][y] ?= {} + for z in [0...@model.depth] + @_blockCache[x][y][z] ?= null + + for el in @$('.block') + $el = $(el) + @_blockCache[$el.data('x')][$el.data('y')][$el.data('z')] = $el + + _refreshBlock: (x, y, z)-> + return unless @model? + + stack = @model.getStackAt x, y, z + $block = @_blockCache[x][y][z] + position = @_computePosition x, y, z, hideUpperLayers:true + move = false + + if stack? + itemDisplay = @_modPack.findItemDisplay stack.itemSlug + + if not $block? + $block = $("#{itemDisplay.itemName}") + $block.css position, top:-@IMAGE_SIZE, opacity:0.0 + @_imageLoader.load itemDisplay.iconUrl, $block + @_blockCache[x][y][z] = $block + @$el.append $block + move = true + else + $block.attr 'src', itemDisplay.iconUrl + move = true + else if $block? + $block.attr 'src', '' + move = true + + if move then _.delay (-> $block.css position), @_randomDropDelay() + + _refreshAllBlocks: -> + return unless @model? + + for x in [0...@model.width] + for y in [0...@model.height] + for z in [0...@model.depth] + @_refreshBlock(x, y, z) diff --git a/src/coffee/controllers/multiblock_viewer_controller.coffee b/src/coffee/controllers/multiblock_viewer_controller.coffee new file mode 100644 index 000000000..ca18a7914 --- /dev/null +++ b/src/coffee/controllers/multiblock_viewer_controller.coffee @@ -0,0 +1,68 @@ +### +Crafting Guide - multiblock_viewer_controller.coffee + +Copyright (c) 2014-2015 by Redwood Labs +All rights reserved. +### + +_ = require '../underscore_mixins' +BaseController = require './base_controller' +MultiblockController = require './multiblock_controller' + +######################################################################################################################## + +module.exports = class MultiblockViewerController extends BaseController + + constructor: (options={})-> + if not options.imageLoader? then throw new Error 'options.imageLoader is required' + if not options.modPack? then throw new Error 'options.modPack is required' + options.templateName = 'multiblock_viewer' + super options + + @_imageLoader = options.imageLoader + @_modPack = options.modPack + + # Event Methods ################################################################################ + + onBackClicked: -> + return if @backButton.hasClass 'disabled' + @multiblockController.goBackLayer() + @refresh() + + onNextClicked: -> + return if @nextButton.hasClass 'disabled' + @multiblockController.goNextLayer() + @refresh() + + # BaseController Overrides ##################################################################### + + onDidRender: -> + @multiblockController = @addChild MultiblockController, '.view__multiblock', + imageLoader: @_imageLoader + modPack: @_modPack + + @backButton = @$('.button.back') + @nextButton = @$('.button.next') + super + + refresh: -> + @multiblockController.model = @model + + if @multiblockController.hasBackLayer() + @backButton.removeClass 'disabled' + else + @backButton.addClass 'disabled' + + if @multiblockController.hasNextLayer() + @nextButton.removeClass 'disabled' + else + @nextButton.addClass 'disabled' + + super + + # Backbone.View Overrides ###################################################################### + + events: -> + _.extend super, + 'click .button.back': 'onBackClicked' + 'click .button.next': 'onNextClicked' diff --git a/src/coffee/models/multiblock.coffee b/src/coffee/models/multiblock.coffee index 0923c9ae1..29f973de5 100644 --- a/src/coffee/models/multiblock.coffee +++ b/src/coffee/models/multiblock.coffee @@ -5,6 +5,7 @@ Copyright (c) 2014-2015 by Redwood Labs All rights reserved. ### +_ = require '../underscore_mixins' BaseModel = require './base_model' SimpleInventory = require './simple_inventory' @@ -36,6 +37,9 @@ module.exports = class Multiblock extends BaseModel height: get: -> @_height + inventory: + get: -> @_inventory + width: get: -> @_width diff --git a/src/jade/templates/item_page.jade b/src/jade/templates/item_page.jade index e1c86fcd4..034be0812 100644 --- a/src/jade/templates/item_page.jade +++ b/src/jade/templates/item_page.jade @@ -22,6 +22,11 @@ h2 Recipes .panel + .multiblock.section.hideable.hidden + h2 Multiblock Construction + .panel + .view__multiblock_viewer + .description.section h2 Description .panel.markdown diff --git a/src/jade/templates/multiblock.jade b/src/jade/templates/multiblock.jade new file mode 100644 index 000000000..38a476b8b --- /dev/null +++ b/src/jade/templates/multiblock.jade @@ -0,0 +1,8 @@ +//- +//- Crafting Guide - multiblock.jade +//- +//- Copyright (c) 2015 by Redwood Labs +//- All rights reserved. +//- + +.view__multiblock diff --git a/src/jade/templates/multiblock_viewer.jade b/src/jade/templates/multiblock_viewer.jade new file mode 100644 index 000000000..307b25405 --- /dev/null +++ b/src/jade/templates/multiblock_viewer.jade @@ -0,0 +1,12 @@ +//- +//- Crafting Guide - multiblock_viewer.jade +//- +//- Copyright (c) 2015 by Redwood Labs +//- All rights reserved. +//- + +.view__multiblock_viewer + .view__multiblock + .buttons + .button.back: p back + .button.next: p next diff --git a/src/scss/templates/index.scss b/src/scss/templates/index.scss index 78079a150..a17bde05f 100644 --- a/src/scss/templates/index.scss +++ b/src/scss/templates/index.scss @@ -23,6 +23,8 @@ All rights reserved. @import 'markdown_image'; @import 'markdown_image_list'; @import 'markdown_section'; +@import 'multiblock'; +@import 'multiblock_viewer'; @import 'minimal_recipe'; @import 'mod'; @import 'mod_pack'; diff --git a/src/scss/templates/multiblock.scss b/src/scss/templates/multiblock.scss new file mode 100644 index 000000000..65ec555ab --- /dev/null +++ b/src/scss/templates/multiblock.scss @@ -0,0 +1,15 @@ +/* +Crafting Guide - mod.scss + +Copyright (C) 2015 by Redwood Labs +All rights reserved. +*/ + +.view__multiblock { + position: relative; + + .block { + position: absolute; + transition: all $animate-slow cubic-bezier(0.615, -0.090, 0.010, 1.090); + } +} diff --git a/src/scss/templates/multiblock_viewer.scss b/src/scss/templates/multiblock_viewer.scss new file mode 100644 index 000000000..5c8c2f957 --- /dev/null +++ b/src/scss/templates/multiblock_viewer.scss @@ -0,0 +1,26 @@ +/* +Crafting Guide - mod.scss + +Copyright (C) 2015 by Redwood Labs +All rights reserved. +*/ + +.view__multiblock_viewer { + display: flex; + flex-direction: column; + + .view__multiblock_viewer { + flex: 0 1 100%; + } + + .buttons { + display: flex; + flex: 0 0 auto; + margin: 1em 25% 0 25%; + + .button { + flex: 50%; + margin: 1em; + } + } +}