Working on SegmentedSprite mouse events, hit tests and scaling.

This commit is contained in:
Scott Erickson 2014-09-23 11:37:05 -07:00
parent 39b6b9ef84
commit 5de5d5658e
2 changed files with 95 additions and 7 deletions

View file

@ -25,12 +25,16 @@ module.exports = class SegmentedSprite extends createjs.SpriteContainer
action = @thangType.getActions()[actionName]
randomStart = actionName.startsWith('move')
# because the resulting segmented image is set to the size of the movie clip, you can use
# the raw registration data without scaling it.
reg = action.positions?.registration or @thangType.get('positions')?.registration or {x:0, y:0}
@regX = -reg.x
@regY = -reg.y
if action.animation
@framerate = (action.framerate ? 20) * (action.speed ? 1)
@regX = -reg.x
@regY = -reg.y
@baseScaleY = @baseScaleX = action.scale ? @thangType.get('scale') ? 1
@childMovieClips = []
@baseMovieClip = @buildMovieClip(action.animation)
@children = @baseMovieClip.children
@ -42,11 +46,10 @@ module.exports = class SegmentedSprite extends createjs.SpriteContainer
@loop = action.loops isnt false
@goesTo = action.goesTo
@notifyActionNeedsRender(action) if @actionNotSupported
@updateBaseMovieClip()
else if action.container
scale = @resolutionFactor * (action.scale ? @thangType.get('scale') ? 1)
@regX = -reg.x
@regY = -reg.y
@childMovieClips = []
containerName = @spriteSheetPrefix + action.container
sprite = new createjs.Sprite(@spriteSheet)
@ -63,6 +66,10 @@ module.exports = class SegmentedSprite extends createjs.SpriteContainer
@children = [sprite]
return
updateBaseMovieClip: ->
return unless @baseMovieClip
@baseMovieClip[prop] = @[prop] for prop in ['x', 'y', 'regX', 'regY']
notifyActionNeedsRender: (action) ->
@sprite?.trigger('action-needs-render', @sprite, action)
@ -107,7 +114,9 @@ module.exports = class SegmentedSprite extends createjs.SpriteContainer
outerContainer = new createjs.SpriteContainer(@spriteSheet)
innerContainer = new createjs.Sprite(@spriteSheet)
innerContainer.gotoAndStop(@spriteSheetPrefix + localContainer.gn)
if innerContainer.currentFrame is 0
@listenToEventsFor(innerContainer)
if innerContainer.currentFrame is 0 or @usePlaceholders
innerContainer.gotoAndStop(0)
@actionNotSupported = true
bounds = @thangType.get('raw').containers[localContainer.gn].b
innerContainer.x = bounds[0]
@ -123,6 +132,12 @@ module.exports = class SegmentedSprite extends createjs.SpriteContainer
map[localContainer.bn] = outerContainer
return map
listenToEventsFor: (displayObject) ->
for event in ['mousedown', 'click', 'dblclick', 'pressmove', 'pressup']
displayObject.on event, @onMouseEvent, @
onMouseEvent: (e) -> @dispatchEvent(e)
buildMovieClipAnimations: (localAnimations) ->
map = {}
for localAnimation in localAnimations

View file

@ -2,17 +2,20 @@ LayerAdapter = require 'lib/surface/LayerAdapter'
SegmentedSprite = require 'lib/surface/SegmentedSprite'
CocoSprite = require 'lib/surface/CocoSprite'
ThangType = require 'models/ThangType'
SpriteBuilder = require 'lib/sprites/SpriteBuilder'
ogreMunchkinThangType = new ThangType(require 'test/app/fixtures/ogre-munchkin-m.thang.type')
ogreFangriderThangType = new ThangType(require 'test/app/fixtures/ogre-fangrider.thang.type')
describe 'SegmentedSprite', ->
segmentedSprite = null
stage = null
showMe = ->
canvas = $('<canvas width="600" height="400"></canvas>').css('position', 'absolute').css('index', 1000).css('background', 'white')
$('body').append(canvas)
stage = new createjs.SpriteStage(canvas[0])
stage = new createjs.Stage(canvas[0]) # this is not a SpriteStage because some tests require adding MovieClips
stage.addChild(segmentedSprite)
window.stage = stage
ticks = 0
listener = {
@ -36,6 +39,7 @@ describe 'SegmentedSprite', ->
# couple extra actions for doing some tests
actions.littledance = {animation:'enemy_small_move_side',framerate:1, frames:'0,6,2,6,2,8,0'}
actions.onestep = {animation:'enemy_small_move_side', loops: false}
actions.head = {container:'head'}
colorConfig = {team: {hue: 0, saturation: 1, lightness: 0.5}}
sprite = new CocoSprite(ogreMunchkinThangType, {colorConfig: colorConfig})
@ -43,7 +47,7 @@ describe 'SegmentedSprite', ->
sheet = layer.renderNewSpriteSheet()
prefix = layer.renderGroupingKey(ogreMunchkinThangType, null, colorConfig) + '.'
window.segmentedSprite = segmentedSprite = new SegmentedSprite(sheet, ogreMunchkinThangType, prefix)
segmentedSprite.x = 200
segmentedSprite.x = 100
segmentedSprite.y = 200
afterEach ->
@ -80,6 +84,75 @@ describe 'SegmentedSprite', ->
segmentedSprite.tick(1000)
expect(fired).toBe(true)
it 'scales rendered animations like a MovieClip', ->
# build a movie clip, put it on top of the segmented sprite and make sure
# they both 'hit' at the same time.
segmentedSprite.gotoAndStop('idle')
builder = new SpriteBuilder(ogreMunchkinThangType)
movieClip = builder.buildMovieClip('enemy_small_move_side')
movieClip.x = 100
movieClip.y = 200
movieClip.regX = 285
movieClip.regY = 300
movieClip.stop()
showMe()
stage.addChild(movieClip)
stage.update()
t = new Date()
tests = hits = 0
for x in _.range(50, 160, 20)
for y in _.range(50, 220, 20)
tests += 1
objects = stage.getObjectsUnderPoint(x, y)
if objects.length
hasSprite = _.any objects, (o) -> o instanceof createjs.Sprite
hasShape = _.any objects, (o) -> o instanceof createjs.Shape
hits+= 1 if hasSprite and hasShape
else
hits += 1
expect(hits / tests).toBeGreaterThan(0.98) # not perfect, but pretty close.
expect(segmentedSprite.baseScaleX).toBe(0.3)
expect(segmentedSprite.baseScaleY).toBe(0.3)
$('canvas').remove()
it 'scales placeholder animations like a MovieClip', ->
segmentedSprite.usePlaceholders = true
segmentedSprite.gotoAndStop('idle')
builder = new SpriteBuilder(ogreMunchkinThangType)
movieClip = builder.buildMovieClip('enemy_small_move_side')
movieClip.x = 100
movieClip.y = 200
movieClip.regX = 285
movieClip.regY = 300
movieClip.stop()
showMe()
stage.addChild(movieClip)
stage.update()
t = new Date()
tests = hits = 0
for x in _.range(50, 160, 20)
for y in _.range(50, 220, 20)
tests += 1
objects = stage.getObjectsUnderPoint(x, y)
if objects.length
hasSprite = _.any objects, (o) -> o instanceof createjs.Sprite
hasShape = _.any objects, (o) -> o instanceof createjs.Shape
hits+= 1 if hasSprite and hasShape
else
hits += 1
expect(hits / tests).toBeGreaterThan(0.96) # not as perfect, but still, close!
$('canvas').remove()
it 'propagates events from the segments through the segmented sprite', ->
fired = {}
segmentedSprite.on('click', -> fired.didIt = true)
segmentedSprite.gotoAndStop('idle')
segmentedSprite.children[0].children[0].dispatchEvent('click')
expect(fired.didIt).toBe(true)
describe 'with Ogre Fangrider ThangType', ->
beforeEach ->
layer = new LayerAdapter({webGL:true})