Monaca Docs
検索…
ブロック崩しゲーム
pixi.js を使用したサンプルゲームです。 pixi.js は、非常に高速な、HTML5 の 2D レンダリング エンジンです。WebGL を基盤としています [ WebGL 未対応のブラウザーでは、Canvas にフォールバック ( fallback / 切り替え ) します ]。Pixi の詳細は、 こちら をご確認ください。このゲームでは、ボールが画面下に落ちないように、パドルを操作しながら、煉瓦状に積まれたブロックを崩していきます。すべてのブロックを崩し終えたところで、ゲームクリアとなります。

デモ

テスト環境
  • Android 11.0
  • iOS 14.3

ファイル構成

ファイル
説明
index.html
スタート画面のページ ( ホーム画面のページ )
js/main.js
アプリ内でさまざまな処理を行う JavaScript ファイル
css/style.css
アプリに適用する共通スタイルシート
img/*.png
このテンプレートで使用する、すべてのイメージファイル
res/VT323-Regular.ttf
TrueType のフォン

必要な JS/CSS コンポーネント

  • Pixi

ソースコードの解説

js/main.js

main.js は、アプリ内のさまざまな処理を定義している JavaScript ファイルです。
BB オブジェクトのコードを次に記します。こちらが、アプリで使用する、メインのオブジェクトとなります。プロパティには、スクリーンサイズ用 ( screenSize )、パドル用 ( paddle )、ボール用 ( balls )、ブロック用 ( blocks )、スコア用 ( score ) などがあります。メソッドには、マップの作成用 ( setMap() )、ボールの配置用 ( addBall() )、パドルの配置用 ( addPaddle() )、ゲームのリセット用 ( reset() )、スコアの計算用 ( addScore() )、ゲームの終了用 ( endGame() ) などがあります。
1
...
2
var BB = {
3
stage: new PIXI.Stage(0x000000),
4
renderer: null,
5
screenSize: null,
6
paddle: null,
7
balls: [],
8
blocks: [],
9
score: 0,
10
scoreLabel: null,
11
accelLabel: null,
12
isMouseDown: false,
13
14
// Create blocks map
15
setMap: function() {
16
var blockMap = [
17
[null, null, null, null, null, 'blue', null, null, null, null],
18
[null, null, null, null, 'red', 'red', 'blue', null, null, null],
19
[null, null, null, 'red', 'red', null, null, 'blue', null, null],
20
[null, null, 'red', 'red', null, null, null, null, 'blue', null],
21
[null, 'red', 'red', null, null, 'gold', null, null, 'silver', 'silver'],
22
[null, null, 'red', 'red', null, null, null, 'silver', 'silver', null],
23
[null, null, null, 'red', 'red', null, 'silver', 'silver', null, null],
24
[null, null, null, null, 'silver', 'silver', 'silver', null, null, null],
25
[null, null, null, null, null, 'silver', null, null, null, null]
26
];
27
28
for(j = 0; j < blockMap.length; j++) {
29
for(i = 0; i < blockMap[j].length; i++) {
30
if(blockMap[j][i] !== null) {
31
var block = BB.addBlock(10 + (30 * i), 80 + (12 * j), blockMap[j][i]);
32
}
33
}
34
}
35
},
36
37
/**
38
* @param {int} x
39
* @param {int} y
40
* @param {String} color red,blue,silver,gold
41
* @return {Object} block
42
**/
43
addBlock: function(x, y, color) {
44
switch (color) {
45
case "red":
46
case "blue":
47
var point = SETTINGS_POINT;
48
break;
49
case "silver":
50
var point = SETTINGS_POINT_SILVER;
51
break;
52
case "gold":
53
var point = SETTINGS_POINT_GOLD;
54
break;
55
default:
56
var point = SETTINGS_POINT;
57
color = "red";
58
break;
59
}
60
61
var texture = PIXI.Texture.fromImage(imgPath["block_" + color], false);
62
var block = new PIXI.Sprite(texture);
63
64
block.anchor.x = 0.5;
65
block.anchor.y = 0.5;
66
67
block.position.x = x;
68
block.position.y = y;
69
70
block.width = 30;
71
block.height = 12;
72
73
block.point = point;
74
75
BB.stage.addChild(block);
76
BB.blocks.push(block);
77
78
return block;
79
},
80
81
// Create a ball and add it to PIXI.Stage
82
addBall: function() {
83
var texture = PIXI.Texture.fromImage(imgPath["ball"], false);
84
var ball = new PIXI.Sprite(texture);
85
86
ball.anchor.x = 0.5;
87
ball.anchor.y = 0.5;
88
89
ball.position.x = parseInt(BB.renderer.width * 0.5);
90
ball.position.y = 200;
91
92
ball.width = 10;
93
ball.height = 10;
94
95
ball.delta = {
96
'x' : Math.random() - 0.5,
97
'y' : -0.4
98
};
99
100
BB.stage.addChild(ball);
101
BB.balls.push(ball);
102
},
103
104
// Create a paddle and add it to PIXI.Stage
105
addPaddle: function() {
106
var texture = PIXI.Texture.fromImage(imgPath["paddle"], false);
107
BB.paddle = new PIXI.Sprite(texture);
108
109
BB.paddle.anchor.x = 0.5;
110
BB.paddle.anchor.y = 0.5;
111
112
BB.paddle.position.x = parseInt(BB.renderer.width * 0.5);
113
BB.paddle.position.y = BB.renderer.height - 60;
114
115
BB.paddle.width = 60;
116
BB.paddle.height = 10;
117
118
BB.paddle.accel = 0;
119
BB.paddle.delta = {
120
'x' : Math.random() - 0.5,
121
'y' : -3.8
122
};
123
124
BB.stage.addChild(BB.paddle);
125
},
126
127
/**
128
* Add points to current score
129
* @param {int} val points to add
130
*/
131
addScore: function(val) {
132
BB.score += parseInt(val);
133
BB.scoreLabel.setText(BB.score);
134
},
135
136
/**
137
* Set score
138
* @param {int} val new score
139
*/
140
setScore: function(val) {
141
BB.score = val;
142
BB.scoreLabel.setText(BB.score);
143
},
144
145
/**
146
* callback for Core Cordova Plugins Acceleration Watch
147
* @param {Object} a a.x, a.y, a.z
148
*/
149
updateAcceleration: function(a) {
150
var accelText = "", ac = a.x.toFixed(2);
151
152
if(a.x > 0) accelText = '+' + String(ac);
153
else accelText = String(ac);
154
155
// Use parameter x to move paddle
156
if (BB.paddle !== null) {
157
if (BB.paddle.accel / ac > 2.0) {
158
159
} else if (BB.paddle.accel / ac > 0) {
160
BB.paddle.accel += ac * SETTINGS_PADDLE_ACCEL;
161
} else {
162
BB.paddle.accel = ac * SETTINGS_PADDLE_ACCEL;
163
}
164
}
165
166
BB.accelLabel.setText(accelText);
167
},
168
169
// Reset current game and start new one
170
reset: function() {
171
//Reset (remove all children in the stage if exists)
172
for (var i = BB.stage.children.length - 1; i >= 0; i--) {
173
BB.stage.removeChildAt(i);
174
}
175
176
BB.balls = [];
177
BB.blocks = [];
178
BB.setMap();
179
for (var i = 0; i < SETTINGS_BALL_NUM; i++) {
180
BB.addBall();
181
}
182
BB.addPaddle();
183
184
var resetLabel = new PIXI.Text("RESET", {font: "24px/1.2 vt", fill: "red"});
185
resetLabel.position.x = 18;
186
resetLabel.position.y = BB.renderer.height - 52;
187
BB.stage.addChild(resetLabel);
188
resetLabel.buttonMode = true;
189
resetLabel.interactive = true;
190
resetLabel.click = resetLabel.tap = function(data) {
191
BB.reset();
192
};
193
setTimeout(function() {
194
resetLabel.setText("RESET"); //for Android
195
}, 1000, resetLabel);
196
197
var label = new PIXI.Text("SCORE:", {font: "24px/1.2 vt", fill: "red"});
198
label.position.x = 20;
199
label.position.y = 20;
200
BB.stage.addChild(label);
201
setTimeout(function() {
202
label.setText("SCORE:"); //for Android
203
}, 1000, label);
204
205
BB.scoreLabel = new PIXI.Text("0", {font: "24px/1.2 vt", fill: "white"});
206
BB.scoreLabel.position.x = 90;
207
BB.scoreLabel.position.y = 20;
208
BB.stage.addChild(BB.scoreLabel);
209
BB.setScore(0);
210
211
/*
212
var label = new PIXI.Text("ACCEL:", {font: "24px/1.2 vt", fill: "red"});
213
label.position.x = 160;
214
label.position.y = 20;
215
BB.stage.addChild(label);
216
label.setText("ACCEL:"); //for Android
217
218
BB.accelLabel = new PIXI.Text("0", {font: "24px/1.2 vt", fill: "white"});
219
BB.accelLabel.position.x = 230;
220
BB.accelLabel.position.y = 20;
221
BB.stage.addChild(BB.accelLabel);
222
*/
223
224
BB.gameState = GAMESTATE_PLAY;
225
},
226
227
/**
228
* Check whether the ball hits the object
229
* @param {PIXI.Sprite} ball
230
* @param {PIXI.Sprite} obj target object
231
*/
232
isBallHit: function(ball, obj) {
233
return (ball.position.x > (obj.position.x - (obj.width * 0.5))) &&
234
(ball.position.x < (obj.position.x + (obj.width * 0.5))) &&
235
(ball.position.y > (obj.position.y - (obj.height * 0.5))) &&
236
(ball.position.y < (obj.position.y + (obj.height * 0.5)));
237
},
238
239
// Game Over
240
endGame: function() {
241
BB.gameState = GAMESTATE_STOP;
242
vibrate();
243
},
244
245
// Game Clear
246
clearGame: function() {
247
if(typeof navigator.notification !== 'undefined') navigator.notification.alert("Cleared!", function(){}, "Congraturations");
248
else alert("Cleared!");
249
250
BB.gameState = GAMESTATE_STOP;
251
}
252
}
253
...
Copied!
このページの読み込みが開始されると、 init() が呼び出されます。Cordova 側の準備が完了したとき、または、端末の種類を検知できなかったとき、いずれの場合でも、init() が呼び出されます。
1
...
2
window.onload = function() {
3
if(getUa() === false) init();
4
else document.addEventListener("deviceready", init, false);
5
}
6
...
Copied!
init() 関数のコードを次に記します。この関数では、使用されている端末の種類に応じた、BB オブジェクトのレンダリングを行います。次に、パドルに対して、リスナーを設定します。そして、各イベントに応じて、パドルの位置を決めます。
1
...
2
function init() {
3
// Accelerometer
4
/*
5
if (typeof navigator.accelerometer !== 'undefined' && !accelerationWatch) {
6
accelerationWatch = navigator.accelerometer.watchAcceleration(
7
BB.updateAcceleration,
8
function(ex) {
9
alert("accel fail (" + ex.name + ": " + ex.message + ")");
10
},
11
{frequency: SETTINGS_ACCELEROMETER_RELOAD_FREQ}
12
);
13
}
14
*/
15
BB.screenSize = setBound();
16
17
BB.renderer = (getUa() === "Android") ? new PIXI.CanvasRenderer(BB.screenSize.width, BB.screenSize.height) : new PIXI.autoDetectRenderer(BB.screenSize.width, BB.screenSize.height),
18
BB.renderer.transparent = false;
19
document.body.appendChild(BB.renderer.view);
20
21
setScale(BB.screenSize);
22
23
BB.reset();
24
25
// Event listeners to control the paddle
26
window.addEventListener("touchmove", function(e) {
27
BB.paddle.position.x = e.touches[0].clientX / BB.screenSize.zoom;
28
});
29
30
window.addEventListener("mousedown", function(e) {
31
BB.isMouseDown = true;
32
});
33
34
window.addEventListener("mouseup", function(e) {
35
BB.isMouseDown = false;
36
});
37
38
window.addEventListener("mousemove", function(e) {
39
if(BB.isMouseDown) BB.paddle.position.x = e.clientX;
40
});
41
42
window.addEventListener("keydown", function(e) {
43
switch (e.which) {
44
case 37:
45
BB.paddle.position.x -= 4;
46
BB.paddle.accel += (SETTINGS_PADDLE_ACCEL * 0.1);
47
break;
48
case 39:
49
BB.paddle.position.x += 4;
50
BB.paddle.accel -= (SETTINGS_PADDLE_ACCEL * 0.1);
51
break;
52
case 38:
53
BB.paddle.position.y -= 1;
54
break;
55
}
56
});
57
58
requestAnimFrame(animate);
59
}
60
...
Copied!
getUa() 関数を使用して、端末の種類を検知します。検知できない場合には、 false を返します。
1
...
2
function getUa() {
3
if ((navigator.userAgent.indexOf('iPhone') > 0 && navigator.userAgent.indexOf('iPad') == -1) || navigator.userAgent.indexOf('iPod') > 0 ) {
4
return 'iPhone';
5
} else if(navigator.userAgent.indexOf('iPad') > 0) {
6
return 'iPad';
7
} else if(navigator.userAgent.indexOf('Android') > 0) {
8
return 'Android';
9
} else return false;
10
}
11
...
Copied!
最終更新 5mo ago