前回の投稿から、少しでもゲームっぽくする為には何が必要なのか考えた結果、ブロックではなくスプライト画像を使ってみる事にしました。引き続きphina.jsのお世話になりつつスプライト画像の適用をしてみました。
しかし、絵心のない私には自分でイラストを作るだけで数日を要してしまうので、無料配布してくださっているサイト「ぴぽや倉庫」様からお借りしました。
前回のプログラムで表示していたブロックを、お借りした画像に置き換えアニメーションも付け加えたものがこちら
前回からの変更点
ASSETSの追加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
const ASSETS = { image: { balloon: "balloon.png" }, spritesheet: { balloon_ss: { frame: { // フレーム情報 width: 32, // 1フレームの画像サイズ(横) height: 32, // 1フレームの画像サイズ(縦) cols: 6, // フレーム数(横) rows: 12 // フレーム数(縦) }, animations: { move: { // アニメーション名 frames: [0, 1, 2], // フレーム番号範囲 next: "move", // 次のアニメーション frequency: 6 // アニメーション間隔 }, explosion: { // アニメーション名 frames: [3, 4, 5], // フレーム番号範囲 next: "", // 次のアニメーション frequency: 3 // アニメーション間隔 } } } } }; |
Shapeで作っていたブロックを、Spriteに変更
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
// スプライトクラス phina.define(`Balloon`, { superClass: "Sprite", init: function(shotGroup) { this.superInit("balloon", BALLOON_SIZE, BALLOON_SIZE); this.x = Math.randint(25, SCREEN_WIDTH - this.width / 2); this.y = Math.randint(25, SCREEN_HEIGHT - this.width / 2); this.shotGroup = shotGroup; this.speed = movespeed; this.angle = Math.randint(0, 359).toRadian(); this.vx = this.speed * Math.cos(this.angle); this.vy = this.speed * Math.sin(this.angle); this.anim = FrameAnimation("balloon_ss").attachTo(this); this.anim.fit = false; this.anim.gotoAndPlay("move"); this.life = 1; this.scaleX = 1.2; this.scaleY = 1.2; this.setInteractive(true); }, update: function(app) { // 画面端での反射処理 X if (this.right + this.vx > SCREEN_WIDTH || this.left + this.vx < 0) { this.vx *= -1; } // 画面端での反射処理 Y if (this.bottom + this.vy > SCREEN_HEIGHT || this.top + this.vy < 0) { this.vy *= -1; } this.x += this.vx; this.y += this.vy; // anim終了したら削除 if (this.anim.finished) { this.remove(); } }, onpointstart: function () { if(this.life > 0) { this.hit(); } }, hit: function() { this.life--; if (this.life <= 0) { this.vx = 0; this.vy = 0; this.anim.gotoAndPlay("explosion"); // this.tweener.wait(200) // .call(function () { // this.remove() // }, this); for (i = 0; i < quantity; i++) { bullet = Scrap(this.x, this.y).addChildTo(this.shotGroup); } } } }); |
その他、破裂から消滅までの猶予の追加をしました。せっかく素材に破裂アニメーションまで用意されているのに使わないのはもったいないですから。
前回までは当たり判定が反応したと同時に、ブロックの消滅と破片の生成を行っていたのですが、破裂アニメーションを付けた事でスプライト消滅までに少し猶予をもたせる必要が生じました。猶予をもたせるのは簡単ですが、同時にいくつか問題も生じました。
- 破裂→スプライト消滅→破片生成
- 破片生成までに時間が空いてしまい不自然に…。
- 破裂&破片生成→スプライト消滅
- 消滅前に自身の破片で当たり判定が反応。無尽蔵に破片が生成される結果に…。
私が解決方法として選んだのは、スプライトにHPをつける方法。スプライトのHPが1以上の時に当たり判定が作動するように、当たり判定の部分にちょこっとだけ手を加えました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// ゲームメイン phina.define("MainScene", { superClass: "DisplayScene", init: function() { ... }, update: function(app) { ... }, collisionGroups: function(scrap, balloon) { // 当たり判定 scrap.children.some(function(scrap) { balloon.children.some(function(balloon) { if (Collision.testRectRect(scrap, balloon)) { if (balloon.life > 0) { scrap.hit(); balloon.hit(); } } }); }); } }); |
あとちょっとしたこだわりで、破裂が始まったらスプライトの移動を停止させたりとか、ちょこちょこ調整しました。
今後はこのプログラム?をきちんとしたゲームの形にしたいと思っています。が、ここからどうすればいいのか…
参考にしたサイト
大変お世話になりました。この場を借りてお礼申し上げます。

旧 phina.js Tips集 - Qiita
コンテンツは以下のzennのbookに移行しました。今後はzennの方を更新する予定です。…

phina.js room - ほろほろりドットコム
ゲームライブラリ『phina.js』について今までに書いた記事一覧や、ほろほろりがphina.jsを使って作った作品を紹介しているページです。記事の方は、ただ図形を描画させるだけの基本的なものから、入力関連、少し突っ込んでゲーム作成について、他のライブラリと連携に関しての記事等、色々置いています。

vistan - ニコニコ
vistanさんのユーザーページです。以前はプログラム動画を上げていたが2018年ごろからVRばっかりやってる男Youtube
特にお世話になっているのが @alkn203 様。本当に感謝しています。
コメント