mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 07:38:20 -05:00
Added keyboard shortcuts to move, resize, minor-rotate, and toggle collision for Thangs in the level editor. Fixed some issues with stretchy Thangs and collision shapes not updating. Fixed #1699. Fixed #57. Colored collision overlays according to collision categories.
This commit is contained in:
parent
a52bf08792
commit
e4c6d07a4a
5 changed files with 88 additions and 29 deletions
|
@ -287,21 +287,21 @@ module.exports = Lank = class Lank extends CocoClass
|
|||
# Let the pending flags know we're here (but not this call stack, they need to delete themselves, and we may be iterating sprites).
|
||||
_.defer => Backbone.Mediator.publish 'surface:flag-appeared', sprite: @
|
||||
|
||||
updateScale: ->
|
||||
updateScale: (force) ->
|
||||
return unless @sprite
|
||||
if @thangType.get('matchWorldDimensions') and @thang
|
||||
if @thang.width isnt @lastThangWidth or @thang.height isnt @lastThangHeight
|
||||
if @thangType.get('matchWorldDimensions') and @thang and @options.camera
|
||||
if force or @thang.width isnt @lastThangWidth or @thang.height isnt @lastThangHeight or @thang.rotation isnt @lastThangRotation
|
||||
bounds = @sprite.getBounds()
|
||||
return unless bounds
|
||||
@sprite.scaleX = @thang.width * Camera.PPM / bounds.width
|
||||
@sprite.scaleY = @thang.height * Camera.PPM * @options.camera.y2x / bounds.height
|
||||
@sprite.regX = bounds.width / 2
|
||||
@sprite.regY = bounds.height / 2
|
||||
@sprite.scaleX = @thang.width * Camera.PPM / bounds.width * (@options.camera.y2x + (1 - @options.camera.y2x) * Math.abs Math.cos @thang.rotation)
|
||||
@sprite.scaleY = @thang.height * Camera.PPM / bounds.height * (@options.camera.y2x + (1 - @options.camera.y2x) * Math.abs Math.sin @thang.rotation)
|
||||
@sprite.regX = bounds.width * 3 / 4 # Why not / 2? I don't know.
|
||||
@sprite.regY = bounds.height * 3 / 4 # Why not / 2? I don't know.
|
||||
|
||||
unless @thang.spriteName is 'Beam'
|
||||
@sprite.scaleX *= @thangType.get('scale') ? 1
|
||||
@sprite.scaleY *= @thangType.get('scale') ? 1
|
||||
[@lastThangWidth, @lastThangHeight] = [@thang.width, @thang.height]
|
||||
[@lastThangWidth, @lastThangHeight, @lastThangRotation] = [@thang.width, @thang.height, @thang.rotation]
|
||||
return
|
||||
|
||||
scaleX = scaleY = 1
|
||||
|
|
|
@ -500,6 +500,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
|||
lank.setSprite(sprite)
|
||||
lank.update(true)
|
||||
@container.addChild(sprite)
|
||||
lank.updateScale true if lank.thangType.get 'matchWorldDimensions' # Otherwise it's at the wrong scale for some reason.
|
||||
|
||||
renderGroupingKey: (thangType, grouping, colorConfig) ->
|
||||
key = thangType.get('slug')
|
||||
|
|
|
@ -216,11 +216,19 @@ module.exports = class Mark extends CocoClass
|
|||
|
||||
buildDebug: ->
|
||||
shapeName = if @lank.thang.shape in ['ellipsoid', 'disc'] then 'ellipse' else 'rect'
|
||||
key = "#{shapeName}-debug"
|
||||
key = "#{shapeName}-debug-#{@lank.thang.collisionCategory}"
|
||||
DEBUG_SIZE = 10
|
||||
unless key in @layer.spriteSheet.getAnimations()
|
||||
shape = new createjs.Shape()
|
||||
shape.graphics.beginFill 'rgba(171,205,239,0.5)'
|
||||
debugColor = {
|
||||
none: 'rgba(224,255,239,0.25)'
|
||||
ground: 'rgba(239,171,205,0.5)'
|
||||
air: 'rgba(131,205,255,0.5)'
|
||||
ground_and_air: 'rgba(2391,140,239,0.5)'
|
||||
obstacles: 'rgba(88,88,88,0.5)'
|
||||
dead: 'rgba(89,171,100,0.25)'
|
||||
}[@lank.thang.collisionCategory] or 'rgba(171,205,239,0.5)'
|
||||
shape.graphics.beginFill debugColor
|
||||
bounds = [-DEBUG_SIZE / 2, -DEBUG_SIZE / 2, DEBUG_SIZE, DEBUG_SIZE]
|
||||
if shapeName is 'ellipse'
|
||||
shape.graphics.drawEllipse bounds...
|
||||
|
@ -232,9 +240,11 @@ module.exports = class Mark extends CocoClass
|
|||
@sprite = new createjs.Sprite(@layer.spriteSheet)
|
||||
@sprite.gotoAndStop(key)
|
||||
PX = 3
|
||||
[w, h] = [Math.max(PX, @lank.thang.width * Camera.PPM), Math.max(PX, @lank.thang.height * Camera.PPM) * @camera.y2x] # TODO: doesn't work with rotation
|
||||
w = Math.max(PX, @lank.thang.width * Camera.PPM) * (@camera.y2x + (1 - @camera.y2x) * Math.abs Math.cos @lank.thang.rotation)
|
||||
h = Math.max(PX, @lank.thang.height * Camera.PPM) * (@camera.y2x + (1 - @camera.y2x) * Math.abs Math.sin @lank.thang.rotation)
|
||||
@sprite.scaleX = w / (@layer.resolutionFactor * DEBUG_SIZE)
|
||||
@sprite.scaleY = h / (@layer.resolutionFactor * DEBUG_SIZE)
|
||||
@sprite.rotation = -@lank.thang.rotation * 180 / Math.PI
|
||||
|
||||
buildSprite: ->
|
||||
if _.isString @thangType
|
||||
|
|
|
@ -57,14 +57,23 @@ module.exports = class ThangsTabView extends CocoView
|
|||
shortcuts:
|
||||
'esc': 'selectAddThang'
|
||||
'delete, del, backspace': 'deleteSelectedExtantThang'
|
||||
'left': -> @moveAddThangSelection -1
|
||||
'right': -> @moveAddThangSelection 1
|
||||
'ctrl+z, ⌘+z': 'undo'
|
||||
'ctrl+shift+z, ⌘+shift+z': 'redo'
|
||||
'alt+left': -> @rotateSelectedThangBy(Math.PI)
|
||||
'alt+right': -> @rotateSelectedThangBy(0)
|
||||
'alt+up': -> @rotateSelectedThangBy(-Math.PI/2)
|
||||
'alt+down': -> @rotateSelectedThangBy(Math.PI/2)
|
||||
'alt+c': 'toggleSelectedThangCollision'
|
||||
'left': -> @moveSelectedThangBy -1, 0
|
||||
'right': -> @moveSelectedThangBy 1, 0
|
||||
'up': -> @moveSelectedThangBy 0, 1
|
||||
'down': -> @moveSelectedThangBy 0, -1
|
||||
'alt+left': -> @rotateSelectedThangTo Math.PI unless key.shift
|
||||
'alt+right': -> @rotateSelectedThangTo 0 unless key.shift
|
||||
'alt+up': -> @rotateSelectedThangTo -Math.PI / 2
|
||||
'alt+down': -> @rotateSelectedThangTo Math.PI / 2
|
||||
'alt+shift+left': -> @rotateSelectedThangBy Math.PI / 16
|
||||
'alt+shift+right': -> @rotateSelectedThangBy -Math.PI / 16
|
||||
'shift+left': -> @resizeSelectedThangBy -1, 0
|
||||
'shift+right': -> @resizeSelectedThangBy 1, 0
|
||||
'shift+up': -> @resizeSelectedThangBy 0, 1
|
||||
'shift+down': -> @resizeSelectedThangBy 0, -1
|
||||
|
||||
constructor: (options) ->
|
||||
super options
|
||||
|
@ -516,7 +525,7 @@ module.exports = class ThangsTabView extends CocoView
|
|||
prefix += segment
|
||||
if not @thangsTreema.get(prefix) then @thangsTreema.set(prefix, {})
|
||||
|
||||
onThangsChanged: =>
|
||||
onThangsChanged: (skipSerialization) =>
|
||||
return if @hush
|
||||
|
||||
# keep the thangs in the same order as before, roughly
|
||||
|
@ -527,6 +536,7 @@ module.exports = class ThangsTabView extends CocoView
|
|||
|
||||
@level.set 'thangs', thangs
|
||||
return if @editThangView
|
||||
return if skipSerialization
|
||||
serializedLevel = @level.serialize @supermodel, null, null, true
|
||||
try
|
||||
@world.loadFromLevel serializedLevel, false
|
||||
|
@ -634,18 +644,56 @@ module.exports = class ThangsTabView extends CocoView
|
|||
onClickRotationButton: (e) ->
|
||||
$('#contextmenu').hide()
|
||||
rotation = parseFloat($(e.target).closest('button').data('rotation'))
|
||||
@rotateSelectedThangBy rotation * Math.PI
|
||||
@rotateSelectedThangTo rotation * Math.PI
|
||||
|
||||
modifySelectedThangComponentConfig: (thang, componentOriginal, modificationFunction) ->
|
||||
return unless thang
|
||||
@hush = true
|
||||
thangData = @getThangByID thang.id
|
||||
thangData = $.extend true, {}, thangData
|
||||
unless component = _.find thangData.components, {original: componentOriginal}
|
||||
component = original: componentOriginal, config: {}
|
||||
thangData.components.push component
|
||||
modificationFunction component
|
||||
@thangsTreema.set @pathForThang(thangData), thangData
|
||||
@hush = false
|
||||
@onThangsChanged true
|
||||
thang.stateChanged = true
|
||||
lank = @surface.lankBoss.lanks[thang.id]
|
||||
lank.update true
|
||||
lank.marks.debug?.destroy()
|
||||
lank.marks.debug = null
|
||||
lank.setDebug true
|
||||
|
||||
rotateSelectedThangTo: (radians) ->
|
||||
@modifySelectedThangComponentConfig @selectedExtantThang, LevelComponent.PhysicalID, (component) =>
|
||||
component.config.rotation = radians
|
||||
@selectedExtantThang.rotation = component.config.rotation
|
||||
|
||||
rotateSelectedThangBy: (radians) ->
|
||||
return unless @selectedExtantThang
|
||||
@hush = true
|
||||
thangData = @getThangByID(@selectedExtantThang.id)
|
||||
thangData = $.extend(true, {}, thangData)
|
||||
component = _.find thangData.components, {original: LevelComponent.PhysicalID}
|
||||
component.config.rotation = radians
|
||||
@thangsTreema.set(@pathForThang(thangData), thangData)
|
||||
@hush = false
|
||||
@onThangsChanged()
|
||||
@modifySelectedThangComponentConfig @selectedExtantThang, LevelComponent.PhysicalID, (component) =>
|
||||
component.config.rotation = ((component.config.rotation ? 0) + radians) % (2 * Math.PI)
|
||||
@selectedExtantThang.rotation = component.config.rotation
|
||||
|
||||
moveSelectedThangBy: (xDir, yDir) ->
|
||||
@modifySelectedThangComponentConfig @selectedExtantThang, LevelComponent.PhysicalID, (component) =>
|
||||
component.config.pos.x += 0.5 * xDir
|
||||
component.config.pos.y += 0.5 * yDir
|
||||
@selectedExtantThang.pos.x = component.config.pos.x
|
||||
@selectedExtantThang.pos.y = component.config.pos.y
|
||||
|
||||
resizeSelectedThangBy: (xDir, yDir) ->
|
||||
@modifySelectedThangComponentConfig @selectedExtantThang, LevelComponent.PhysicalID, (component) =>
|
||||
component.config.width = (component.config.width ? 4) + 0.5 * xDir
|
||||
component.config.height = (component.config.height ? 4) + 0.5 * yDir
|
||||
@selectedExtantThang.width = component.config.width
|
||||
@selectedExtantThang.height = component.config.height
|
||||
|
||||
toggleSelectedThangCollision: ->
|
||||
@modifySelectedThangComponentConfig @selectedExtantThang, LevelComponent.CollidesID, (component) =>
|
||||
component.config ?= {}
|
||||
component.config.collisionCategory = if component.config.collisionCategory is 'none' then 'ground' else 'none'
|
||||
@selectedExtantThang.collisionCategory = component.config.collisionCategory
|
||||
|
||||
toggleThangsContainer: (e) ->
|
||||
$('#all-thangs').toggleClass('hide')
|
||||
|
|
|
@ -63,7 +63,7 @@ setupExpressMiddleware = (app) ->
|
|||
else
|
||||
express.logger.format('dev', developmentLogging)
|
||||
app.use(express.logger('dev'))
|
||||
app.use(express.static(path.join(__dirname, 'public'), maxAge: 30 * 60 * 1000))
|
||||
app.use(express.static(path.join(__dirname, 'public'), maxAge: 0)) # CloudFlare overrides maxAge, and we don't want local development caching.
|
||||
app.use(useragent.express())
|
||||
|
||||
app.use(express.favicon())
|
||||
|
|
Loading…
Reference in a new issue