Herlockで作るiOSアプリ(もちろんAndroidも!) – スプライトシート編 –
|この記事はHerlockシリーズの続きです。
スプライトシートを利用して見た目を調整します。
基本的な仕様はHerlockで作るiOSアプリ(もちろんAndroidも!) – タッチイベント編 –と一緒です。
準備
スプライトシートの作成を参考に作成して下さい。
今回準備したスプライトシートはこちらです。
{"frames": [ { "filename": "1", "frame": {"x":0,"y":0,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "2", "frame": {"x":100,"y":0,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "3", "frame": {"x":200,"y":0,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "4", "frame": {"x":300,"y":0,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "5", "frame": {"x":400,"y":0,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "6", "frame": {"x":0,"y":100,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "7", "frame": {"x":100,"y":100,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "8", "frame": {"x":200,"y":100,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "9", "frame": {"x":300,"y":100,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "10", "frame": {"x":400,"y":100,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "drag1", "frame": {"x":0,"y":200,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag2", "frame": {"x":100,"y":200,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":1,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag3", "frame": {"x":200,"y":200,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag4", "frame": {"x":300,"y":200,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag5", "frame": {"x":400,"y":200,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag6", "frame": {"x":0,"y":300,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag7", "frame": {"x":100,"y":300,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag8", "frame": {"x":200,"y":300,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag9", "frame": {"x":300,"y":300,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag10", "frame": {"x":400,"y":300,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} }], "meta": { "app": "Adobe Flash Professional", "version": "13.1.0.226", "image": "spritesheet.png", "format": "RGBA8888", "size": {"w":512,"h":512}, "scale": "1" } };
スプライトシート用のロジックを追加
spritesheet.pngから指定の範囲を切り出して新規にBitmapを作成し、spriteに追加します。
管理用にscene/gamesprite.jsを作成して下さい。
/* ゲームのロジック */ define( ['config'], function ( config ) { //Flashから書き出したJSONを変数に代入します var flashExport = {"frames": [ { "filename": "1", "frame": {"x":0,"y":0,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "2", "frame": {"x":100,"y":0,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "3", "frame": {"x":200,"y":0,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "4", "frame": {"x":300,"y":0,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "5", "frame": {"x":400,"y":0,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "6", "frame": {"x":0,"y":100,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "7", "frame": {"x":100,"y":100,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "8", "frame": {"x":200,"y":100,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "9", "frame": {"x":300,"y":100,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "10", "frame": {"x":400,"y":100,"w":100,"h":100}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":100}, "sourceSize": {"w":100,"h":100} } ,{ "filename": "drag1", "frame": {"x":0,"y":200,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag2", "frame": {"x":100,"y":200,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":1,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag3", "frame": {"x":200,"y":200,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag4", "frame": {"x":300,"y":200,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag5", "frame": {"x":400,"y":200,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag6", "frame": {"x":0,"y":300,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag7", "frame": {"x":100,"y":300,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag8", "frame": {"x":200,"y":300,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag9", "frame": {"x":300,"y":300,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} } ,{ "filename": "drag10", "frame": {"x":400,"y":300,"w":100,"h":100}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":100,"h":101}, "sourceSize": {"w":100,"h":101} }], "meta": { "app": "Adobe Flash Professional", "version": "13.1.0.226", "image": "spritesheet.png", "format": "RGBA8888", "size": {"w":512,"h":512}, "scale": "1" } }; //Flashのjsonを上記フレーム定義に変換 var SpriteSheet = []; for(var i = 0; i < flashExport.frames.length; i++) { var frame = flashExport.frames[i].frame; SpriteSheet[flashExport.frames[i].filename] = (new Rectangle(frame.x, frame.y, frame.w, frame.h)); } var spriteSheetImage = new Image( "assets/images/spritesheet.png" ); spriteSheetImage.onload = function() { // console.log("spriteLoad!"); }; //外部へ公開するAPI return { getSprite : function(name){ name = name.toString(); var sprite; if(SpriteSheet[name]){ sprite = new Sprite(100,100); sprite.addChild( new Bitmap(new BitmapData( spriteSheetImage ), false, false, SpriteSheet[name]) ); sprite.name = name; } return sprite; } } });
ゲームロジックの修正
スプライトを利用するようにゲームロジックを修正します。
ドラッグ可能なspriteを入替えるロジックも追加しておきます。
/* ゲームのロジック */ define( ['config','scene/gamesprite'], function ( config ,spriteSheet) { //生成するオブジェクト数 var maxCount = 5; //外部へ公開するAPI return { //ランダムの数字作成 createNumber : function(){ return parseInt(1+(Math.random()*8)); }, //新しい数字を追加する addNewNumber : function(list){ var range = list.length; list = list.slice(1,range); list[range-1] = this.createNumber(); return list; }, //数字のリストを生成する createNumberList : function(){ var list = []; for(var i=0;i<maxCount;i++){ list[i] = this.createNumber(); } return list; }, //Spriteを準備する createSprite : function(id,number){ var name = (id===0) ? "drag" + number : number; return _stage.addChild( spriteSheet.getSprite(name) ); }, //新しいSpriteを追加する addNewSprite : function(spriteList,numberList){ //最後の行を追加する var range = numberList.length; _stage.removeChild(spriteList[0]); spriteList = spriteList.slice(1,range); spriteList[range-1] = this.createSprite(range,numberList[range-1]); //最初の行をドラッグ可能なspriteへ変換する spriteList[0] = this.createSprite(0,spriteList[0].name); return spriteList; }, //spriteの初期化 initializeSprite : function(list){ var numberSprite = []; for(var i=0;i<list.length;i++){ numberSprite[i] = this.createSprite(i,list[i]); } return numberSprite; }, //並び替え showList : function(list){ var adjust = 0; _.each(list,function(obj){ obj.x = 30 + ( adjust * 120); obj.y = 100; adjust++; }); }, //タッチ移動 touchMove : function(event,numberSprite){ if(100<event.localY){ numberSprite[0].x = event.localX - numberSprite[0].width/2; numberSprite[0].y = event.localY - numberSprite[0].height/2; } }, //タッチ終了 touchEnd : function(event,number,numberSprite){ return { number : this.addNewNumber(number), numberSprite : this.addNewSprite(numberSprite,number) } }, includeObject : function(x,y,obj){ var _x = [obj.x,obj.x+obj.width]; var _y = [obj.y,obj.y+obj.height]; return (_x[0]<=x && x<=_x[1] && _y[0]<=y && y<=_y[1]) ? false : true; } } });
ゲームロコントローラーの修正
主要なロジックをgamelogic.jsに移譲するように修正致しました。
/* 画面遷移の管理 */ define( ['config','scene/gamelogic'], function ( config,logic ) { //画面オブジェクト var _sprite_image_bg, _sprite_button; var _loaded = false; var _waitNumber; //Gameページの追加 var Page = function (path){ //親の呼び出し Scene.call(this,path); //コンテキストの準備 var self = this; //数字配列 this.touched = true; this.number = logic.createNumberList(); this.numberSprite = []; //Topイベント this.goToTop = function(){ //ゲーム画面の描画 Scene.goto("/"); } //タッチ開始 this.touchMove = this.touchBegin = function(event){ //ホームボタンが押されていかチェックする self.touched = logic.includeObject(event.localX,event.localY,_sprite_button); //ホームボタン以外の時 if(self.touched){ logic.touchMove(event,self.numberSprite); } } //タッチ移動終了 this.touchEnd = function(event){ //ホームボタン以外の時 if(self.touched){ var res = logic.touchEnd(event,self.number,self.numberSprite); self.number = res.number; self.numberSprite = res.numberSprite; //再表示 logic.showList(self.numberSprite); } } //tweemjsを進めるためのイベント this.tweenTick = function(){ createjs.Tween.tick(1000/60); } //画面オブジェクトの追加 this.addChildren = function(){ //背景画像の描画 _stage.addChild( _sprite_image_bg ); //ボタンの描画 _stage.addChild( _sprite_button ); _sprite_button.addEventListener( "touchTap",this.goToTop, false ); //ボタンのアニメーション var startY = config.height*(-1); var oldY = _sprite_button.y; _sprite_button.y = startY + oldY; createjs.Tween.get(_sprite_button,{loop:false}).to({y:oldY},1000, createjs.Ease.backin); //背景のアニメーション _sprite_image_bg.y = startY; createjs.Tween.get(_sprite_image_bg,{loop:false}).to({y:0},1000, createjs.Ease.backin).call(function(){ //ステージにゲームオブジェクトを準備 self.numberSprite = logic.initializeSprite(self.number); logic.showList(self.numberSprite); //タッチイベント self.touched = true; _stage.addEventListener("touchBegin",self.touchBegin,false); _stage.addEventListener("touchMove",self.touchMove); _stage.addEventListener("touchEnd",self.touchEnd); }); _stage.addEventListener("enterFrame",this.tweenTick) } }; Page.prototype = new Scene(); //準備処理 var deferred = Deferred(); //読込処理 Page.prototype.onEnter = function () { if(_loaded) return true; //ボタンの準備 var image_button = new Image(config.button + "top.png"); image_button.onload = function() { _sprite_button = new Sprite(170,90); _sprite_button.x = 117; _sprite_button.y = 500; _sprite_button.addChild( new Bitmap( new BitmapData( image_button ) ) ); //背景画像の描画 var image_bg = new Image(config.background.game); image_bg.onload = function(){ //背景画像の準備 _sprite_image_bg = new Bitmap( new BitmapData( image_bg ) ); //onShowの呼び出し deferred.call(); _loaded = true; }; } }; //表示処理 Page.prototype.onShow = function () { //コンテキスト var self = this; if(!_loaded){ deferred.next( function () { //背景画像の描画 self.addChildren(); }); }else{ this.addChildren(); } }; //非表示処理 Page.prototype.onHide = function () { _stage.removeAllEventListeners(); _sprite_button.removeEventListener( "touchTap", this.goToTop ); _stage.removeChild(_sprite_button); _stage.removeChild(_sprite_image_bg); _.each(this.numberSprite,function(obj){ obj = _stage.getChildByName(obj.name); _stage.removeChild(obj); }); }; //シーンの追加 Scene.mapping({ "/game": Page }); });
ロジックの整理も含まれていますが、スプライトシートが簡単に利用できるのが分かると思います。
画像をロードするとコールバックが発生するので、積極的に使いたい機能ですね!