EaselJS の SpriteSheetBuilder クラスを触ってみる

目次

EaselJS の SpriteSheetBuilder クラスを使ってみる

このデモでは createjs-2015.05.21.min.js を利用しています。

EaselJS には SpriteSheetBuilder というクラスがあります。

今回はこの SpriteSheetBuilder というクラスの使い方とこれを使って何ができるのかを見ながら解説をしていきます。

SpriteSheetBuilder Class

SpriteSheet クラスのインスタンスを生成できるクラス

SpriteBuilder クラスを利用すると、DisplayObject クラスを継承しているオブジェクトを使って SpriteSheet クラスのインスタンスを作成することができます。

DisplayObject は位置や変形情報、など表示関する共通のプロパティが定義されているようなクラスなので、Stage に addStage で追加できるようなクラス(Container,Bitmap,Shape,Textなど)がそれに属しています。

言葉だけだとイメージがつきにくいと思うので、実際にやってみようと思います。

DEMO

See the Pen 1c9e02fe1e3fb64e084bb681a02100d4 by turusuke (@turusuke) on CodePen.

この DEMO でやっていることを元に解説をしていきます。

事前準備

まず、このDEMO では SpriteSheetBuilder の機能を検証するために以下のインスタンスを用意しました。

インスタンスの作成

SpriteSheetBuilder クラスを利用するためにインスタンスを作成します。

var builder = new createjs.SpriteSheetBuilder();

フレームの登録

次に addFrame メソッドでフレームを追加していきます。 addFrame の引数にはフレームとして利用したい DisplayObject をとります。

builder.addFrame(circle);

アニメーションの登録

フレームの登録が終わったら次は addAnimation を使ってアニメーションを登録します。

addAnimation

builder.addAnimation("anim", [0, 1, 2, 3, 4, 5], null);

ここで addAnimation に渡している引数の詳細は以下のようになっています。

引数の値 内容
"anim" アニメーション名。ここで登録した名前でアニメーションを呼び出す。
[0,1,2,3] "anim" でアニメーションさせるフレームを配列で渡す。ここで登録した順番で再生される。
null アニメーションの再生終了後の次のアニメーション名(addAnimation の第一引数で指定した名前)を指定します。デフォルトでは同じアニメーションが繰り返されるようになっているのですが、1度だけ再生したい場合は null を指定しておきます

上記の例だと、AddFrame で登録したフレーム 0,1,2,3,4,5 番目を 0,1,2,3,4,5 の順番で再生する "anim" というアニメーションを builder に登録しています。

同じフレームを利用して別なアニメーションを登録することもできるので、途中までは同じで微妙に違いのあるアニメーションを登録したりなんてことにつかうこともできます。

ビルドして SpriteSheet クラスのインスタンスを作成

フレームの登録、アニメーションの登録が終わったら build 関数を使ってビルドします。 返り値に SpriteSheet クラスインスタンスが返ってくるので、これを変数に代入しておきます。

spriteSheet = builder.build()

Sprite クラスに SpriteSheet のインスタンスを渡す

後は Sprite に SpriteSheet のインスタンスを渡して、Sprite のインスタンスを作成後、任意のタイミングで登録したアニメーションを再生させるができます。

Sprite のインスタンスから SpriteSheet で登録したアニメーションを再生させるためのメソッドはいくつかありますが、今回は gotoAndStop() 関数(EaselJS v0.8.1 API Documentation : EaselJS#)を使っています。

引数には先ほど設定したアニメーション名を指定しています。

sprite = new createjs.Sprite(spriteSheet)
stage.addChild sprite
sprite.gotoAndStop("anim")

Stage に Sprite のインスタンスを追加し、 gotoAndStop を実行することで addAnimation で指定した順序でフレームが切り替わってアニメーションするオブジェクトを追加することができました。

SpriteBuilder をパーティクルアニメーションに活用してみる

SpriteteBuilder を使えばパーツとして利用するだけでなく、アニメーションのパフォーマンスを向上させるために利用することもできます。

canvas = document.getElementById("canvas")
context = canvas.getContext("2d")

canvas.width = window.innerWidth
canvas.height = window.innerHeight
# stage = new createjs.Stage(canvas)
stage = new createjs.SpriteStage(canvas)
stage.autoClear = false

ctx = canvas.getContext("2d")
ctx.fillStyle = "rgba(0, 0, 0, 0)"

ctx.fillRect 0,0,canvas.width,canvas.height
createjs.Ticker.setFPS(60)
stage.update()

GRAVITY = 2
K = 0.9
SPEED = 12

ToRadian = (degree) ->
  degree * Math.PI / 180.0

class Fireworks
  constructor: (@sx = 100,@sy = 100,@particles = 70) ->
    @sky = new createjs.Container()
    @sky.setBounds(@sx - 175,@sy - 175, 350, 350)
    
    @sprite = new createjs.SpriteSheetBuilder()
    @r = 0
    @h = Math.random() * 360 | 0
    @s = 100
    @l = 50
    @size = 3
    
    @index

    for i in [0...@particles]
      speed = Math.random() * 12 + 2
      circle = new createjs.Shape()
      circle.graphics.f("hsla(#{@h}, #{@s}%, #{@l}%, 1)").dc(0, 0, @size)
      circle.snapToPixel = true
      circle.compositeOperation = "lighter"
      rad = ToRadian(Math.random() * 360 | 0)

      circle.set({
        x: @sx
        y: @sy
        vx: Math.cos(rad) * speed
        vy: Math.sin(rad) * speed
      })
      
      @sky.addChild circle
      
  setUp: (target) =>
    ++@h
    
    for p in [0...target.getNumChildren()]
      circle = target.getChildAt(p)

      circle.vx = circle.vx * K
      circle.vy = circle.vy * K

      circle.x += circle.vx
      circle.y += circle.vy + GRAVITY

      @l = Math.random() * 100
      @size = @size - 0.001
      if @size > 0
        circle.graphics.c().f("hsla(#{@h}, 100%, #{@l}%, 1)").dc(0, 0, @size)
        
    return

  buildParticle: =>

    if @sky.alpha > 0.1
      @sky.alpha -= K / 50
      @skyBounds = @sky.getBounds()
      @sprite.addFrame @sky,@skyBounds,1,@setUp
      @buildParticle()
      
    else
      @sprite.addAnimation "anim",[0...70],false
      @sprite.addEventListener("complete", (e) =>
        @buildSpriteSheet = e.currentTarget.spriteSheet
        @sky = null
      )
      
      @sprite.buildAsync()
    return

  
class Anim
  constructor: (buildSpriteSheet,x,y) ->
    @buildSpriteSheet = buildSpriteSheet
    @x = x
    @y = y
    @explode(@x, @y)
  explode: (x,y) =>
    @anim = new createjs.Sprite(@buildSpriteSheet, "anim")
    @anim.compositeOperation = "lighter"
    @anim.set(
      x: x
      y: y
      regX: 300 / 2
      regY: 300 / 2
    )
    @anim.addEventListener("animationend", =>
      stage.removeChild(@anim)
    )
    stage.addChild @anim

    return

fireworks = new Fireworks()
fireworks.buildParticle()

stage.on("fire", ->
  h = canvas.height
  h = 0
  repeat = null
  repeat = setInterval(->
    if h > canvas.height
      h = 0
    for w in [0...40]
      new Anim(fireworks.buildSpriteSheet, Math.random() * canvas.width, h)
    h += 50
  ,100)
,null,true)

handleTick = ->
  if fireworks.buildSpriteSheet?
    stage.dispatchEvent "fire"
  ctx.fillStyle = "rgba(0, 0, 0, 0.1)"
  ctx.fillRect 0,0,canvas.width,canvas.height
  stage.update()

createjs.Ticker.addEventListener("tick", handleTick)

See the Pen YXOMWj by turusuke (@turusuke) on CodePen.