CreateJS のクラスを CoffeeScript 上で継承するには
CoffeeScript には簡単にクラスの継承を実現できる機能が備わっていますが、こと CreateJS のクラスを継承する際には従来とは少し異なる手法で実装するがあるので、注意が必要です。
知ってしまえば大したこと無いのですが、ちょっとクセのあるテクニックなのでサンプルを交えてその方法を紹介します。
例) createjs の Bitmap クラスを継承してみる
従来の継承
通常、CoffeeSctript でクラスの継承をするには以下のように記述します。
Animal クラス
class Animal constructor: (@name) -> alive: -> false
Dog クラス
class Parrot extends Animal constructor: -> super("Parrot") dead: -> not @alive()
Animal クラスを継承した Dog クラスです。Dog クラスの constructor メソッド内で super() と実行すると、継承元である Animal クラスの constructor メソッドが実行され、Animal クラスが持つメソッドを Dog クラスのメソッドとして使用できるようになります。
CreateJS のクラスを継承する場合
通常はこの super()メソッドだけで事足りるのですが、CreateJS のクラスを継承する際は super()メソッドではなくinitialize() メソッドを呼び出すことで実現します。
Bitmap クラスを継承した ImageButton クラス
class ImageButton extends createjs.Bitmap constructor: (args)-> @initialize(args.img) @x = args.x @y = args.y @regX = args.img.width / 2 @regY = args.img.height / 2 @scaleX = 1 @scaleY = 1 @addEventListener 'click', args.clickHandler
super() は呼び出しません。ちなみに僕が参考にした下記のエントリでは先にinitializeを呼んでから、super()する
と書かれています。試しに下記のエントリと同じく createjs.Event を継承したサンプルで試してみましたが、initialize() を呼び出しただけで動作しました *1。仕様が変わったんでしょうか?
詳しくは解説しませんが、Bitmap という関数は中で initialize() というメソッドを呼び出す処理のため、これを直接呼び出してあげることで Bitmap インスタンスが生成されるという訳です(たぶん)。
Bitmap.js (※ 一部抜粋)
/** * A Bitmap represents an Image, Canvas, or Video in the display list. A Bitmap can be instantiated using an existing * ( 中略 ) * @class Bitmap * @extends DisplayObject * @constructor * @param {Image | HTMLCanvasElement | HTMLVideoElement | String} imageOrUri The source object or URI to an image to * display. This can be either an Image, Canvas, or Video object, or a string URI to an image file to load and use. * If it is a URI, a new Image object will be constructed and assigned to the .image property. **/ var Bitmap = function(imageOrUri) { this.initialize(imageOrUri); };
全てのコードをご覧になりたい方はこちらからどうぞ。
以上、ちょっとした備忘録でした。最後にサンプルコードとデモを紹介しておきます。
Bitmap クラスを継承したデモ
ImageButton.coffee
class window.ImageButton extends createjs.Bitmap baseScale: 1 sound: null constructor: (args)-> @initialize(args.img) @x = args.x @y = args.y @regX = args.img.width / 2 @regY = args.img.height / 2 @scaleX = 1 @scaleY = 1 @addEventListener 'click', args.clickHandler @baseScale = @scaleX @sound = createjs.Sound.createInstance args.soundInstanceName ring = -> @sound.play() expand: -> expandedScale = @baseScale * 1.2 createjs.Tween.get(@, {override: true}).to({scaleX: expandedScale, scaleY: expandedScale}, 50).to({scaleX: @baseScale, scaleY: @baseScale}, 50); ring.call @
application.coffee
//=require 'ImageButton' stage = null queue = null imageButton = null createMainCanvasStage = -> canvasId = 'main-canvas' s = new createjs.Stage canvasId canvas = s.canvas h = window.innerHeight w = window.innerWidth canvas.height = h canvas.width = w canvas.style.height = "#{h}px" canvas.style.width = "#{w}px" s loadAssets = -> manifest = [ { id: 'thumbnail', src: './assets/images/myLogo_@128.jpg' } { id: 'sound', src: './assets/audio/click.m4a' } ] queue = new createjs.LoadQueue true queue.installPlugin createjs.Sound createjs.Sound.alternateExtensions = ['mp3'] queue.addEventListener 'complete', handleInitialComplete queue.loadManifest manifest, true @ initThumbnail = -> imageButton = new ImageButton img: queue.getResult 'thumbnail' x: stage.canvas.width / 2 y: stage.canvas.height / 2 clickHandler: handleThumbnailClick soundInstanceName: 'sound' stage.addChild imageButton @ handleInitialComplete = => initThumbnail() @ handleThumbnailClick = (event)-> imageButton.expand() initLoad = -> stage = createMainCanvasStage() loadAssets() createjs.Ticker.setFPS 24 createjs.Ticker.addEventListener 'tick', => stage.update() window.addEventListener 'load', (event)-> event.target.removeEventListener event.type, arguments.callee initLoad()
脚注
- super() に渡している引数 type, bubble, cancelable をinitialize() に渡して呼び出しました。 ↩