01 | <!DOCTYPE html>
|
---|
02 | <html lang="ja">
|
---|
03 | <head>
|
---|
04 | <meta charset="utf-8">
|
---|
05 | <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0 user-scalable=no">
|
---|
06 | <title>JavaScriptのテストプログラム</title>
|
---|
07 | </head>
|
---|
08 | <body style="background-color:#000;">
|
---|
09 | <canvas style="position:absolute; top:0; bottom:0; left:0; right:0; margin:auto; z-index:0;" id="bg0"></canvas>
|
---|
10 | <canvas style="position:absolute; top:0; bottom:0; left:0; right:0; margin:auto; z-index:1;" id="bg1"></canvas>
|
---|
11 |
|
---|
12 | <script>
|
---|
13 | //キャンバスの準備
|
---|
14 | var winW = window.innerWidth;
|
---|
15 | var winH = window.innerHeight;
|
---|
16 | var CWIDTH = 360;
|
---|
17 | var CHEIGHT = 360;
|
---|
18 | if( winW < winH )
|
---|
19 | winH = winW;
|
---|
20 | else
|
---|
21 | winW = winH;
|
---|
22 | var SCALE = winW / CWIDTH;
|
---|
23 |
|
---|
24 | var canvas = [];
|
---|
25 | var cnt = [];
|
---|
26 | for( var i = 0; i < 2; i ++ ) {
|
---|
27 | canvas[i] = document.getElementById("bg"+i);
|
---|
28 | cnt[i] = canvas[i].getContext("2d");
|
---|
29 | canvas[i].width = winW;
|
---|
30 | canvas[i].height = winH;
|
---|
31 | cnt[i].scale( SCALE, SCALE );
|
---|
32 | cnt[i].textAlign = "center";
|
---|
33 | cnt[i].textBaseline = "middle";
|
---|
34 | cnt[i].lineCap = "round";
|
---|
35 | }
|
---|
36 |
|
---|
37 | var click = 0;
|
---|
38 | canvas[1].onclick = function(event) { click = 1; }
|
---|
39 |
|
---|
40 | function toInt( val ) {//整数を返す関数
|
---|
41 | return parseInt(val);
|
---|
42 | }
|
---|
43 |
|
---|
44 | function rnd( max ) {//乱数を返す関数
|
---|
45 | return toInt( Math.random()*max );
|
---|
46 | }
|
---|
47 |
|
---|
48 | function colRGB( red, gre, blu ) {//色を返す
|
---|
49 | return ( "rgb(" + red + "," + gre + "," + blu + ")" );
|
---|
50 | }
|
---|
51 |
|
---|
52 | function setAlp( cn, per ) {//透明度
|
---|
53 | cnt[cn].globalAlpha = per/100;
|
---|
54 | }
|
---|
55 |
|
---|
56 | function clrCanvas( cn ) {//キャンバスをクリアする
|
---|
57 | cnt[cn].clearRect( 0, 0, CWIDTH, CHEIGHT );
|
---|
58 | }
|
---|
59 |
|
---|
60 | function fText( cn, str, x, y, siz, col ) {//文字表示
|
---|
61 | cnt[cn].font = siz + "px monospace";
|
---|
62 | cnt[cn].fillStyle = col;
|
---|
63 | cnt[cn].fillText( str, x, y );
|
---|
64 | }
|
---|
65 |
|
---|
66 | function fRect( cn, x, y, w, h, col ) {//矩形
|
---|
67 | cnt[cn].fillStyle = col;
|
---|
68 | cnt[cn].fillRect( x, y, w, h );
|
---|
69 | }
|
---|
70 |
|
---|
71 | function fLine( cn, x1, y1, x2, y2, col, wid ) {//線
|
---|
72 | cnt[cn].strokeStyle = col;
|
---|
73 | cnt[cn].lineWidth = wid;
|
---|
74 | cnt[cn].beginPath();
|
---|
75 | cnt[cn].moveTo( x1, y1 );
|
---|
76 | cnt[cn].lineTo( x2, y2 );
|
---|
77 | cnt[cn].stroke();
|
---|
78 | }
|
---|
79 |
|
---|
80 | //キー入力
|
---|
81 | var key = 0;
|
---|
82 | window.onkeydown = function(event) { key = event.keyCode; }
|
---|
83 | window.onkeyup = function(event) { key = 0; }
|
---|
84 |
|
---|
85 | //加速度センサー
|
---|
86 | var acX = 0, acY = 0, acZ = 0;
|
---|
87 | window.addEventListener( "devicemotion", deviceMotion );
|
---|
88 | function deviceMotion( event ) {
|
---|
89 | var aIG = event.accelerationIncludingGravity;
|
---|
90 | acX = toInt( aIG.x );
|
---|
91 | acY = toInt( aIG.y );
|
---|
92 | acZ = toInt( aIG.z );
|
---|
93 | if( (navigator.userAgent).indexOf("Android") > 0 ) {//Android と iOS で正負が逆になる
|
---|
94 | acX = -acX;
|
---|
95 | acY = -acY;
|
---|
96 | acZ = -acZ;
|
---|
97 | }
|
---|
98 | }
|
---|
99 |
|
---|
100 | //迷路
|
---|
101 | var MAZE_W = 15;
|
---|
102 | var MAZE_H = 15;
|
---|
103 | var maze = new Array();
|
---|
104 | for( var y = 0; y < MAZE_H; y ++ ) {
|
---|
105 | maze[y] = new Array();
|
---|
106 | for( var x = 0; x < MAZE_W; x ++ ) maze[y][x] = 0;
|
---|
107 | }
|
---|
108 |
|
---|
109 | function initMaze() {//迷路の初期化
|
---|
110 | var x, y;
|
---|
111 |
|
---|
112 | //周りの壁
|
---|
113 | for( x = 0; x < MAZE_W; x ++ ) {
|
---|
114 | maze[0][x] = 1;//上の横一列
|
---|
115 | maze[MAZE_H-1][x] = 1;//下の横一列
|
---|
116 | }
|
---|
117 | for( y = 1; y < MAZE_H-1; y ++ ) {
|
---|
118 | maze[y][0] = 1;//左の縦一列
|
---|
119 | maze[y][MAZE_W-1] = 1;//右の縦一列
|
---|
120 | }
|
---|
121 |
|
---|
122 | for( y = 1; y < MAZE_H-1; y ++ ) {
|
---|
123 | for( x = 1; x < MAZE_W-1; x ++ ) maze[y][x] = 0;//中を何も無い状態に
|
---|
124 | }
|
---|
125 |
|
---|
126 | for( y = 2; y < MAZE_H-2; y += 2 ) {
|
---|
127 | for( x = 2; x < MAZE_W-2; x += 2 ) maze[y][x] = 2;//1マス置きの柱
|
---|
128 | }
|
---|
129 | }
|
---|
130 |
|
---|
131 | var XP = [ 0, 1, 0, -1 ];
|
---|
132 | var YP = [ -1, 0, 1, 0 ];
|
---|
133 | function makeMaze() {//迷路を作る
|
---|
134 | var d, x, y;
|
---|
135 | for( y = 2; y < MAZE_H-2; y += 2 ) {
|
---|
136 | for( x = 2; x < MAZE_W-2; x += 2 ) {
|
---|
137 | d = rnd(4);
|
---|
138 | if( x > 2 ) d = rnd(3);//二列目の柱からは左には壁を作らない
|
---|
139 | maze[ y+YP[d] ][ x+XP[d] ] = 2;//柱を倒す
|
---|
140 | }
|
---|
141 | }
|
---|
142 | }
|
---|
143 |
|
---|
144 | function drawMaze() {//迷路を描く
|
---|
145 | var x, y, X, Y;
|
---|
146 | clrCanvas(0);
|
---|
147 | for( y = 0; y < MAZE_H; y ++ ) {
|
---|
148 | for( x = 0; x < MAZE_W; x ++ ) {
|
---|
149 | if( maze[y][x] != 0 ) {
|
---|
150 | X = x*24;
|
---|
151 | Y = y*24;
|
---|
152 | fRect( 0, X, Y, 24, 24, "#008" );
|
---|
153 | if( mazeU(x,y) ) fLine( 0, X+4, Y+4, X+20, Y+4, colRGB( x*16, (15-y)*16, 192 ), 6 );
|
---|
154 | if( mazeD(x,y) ) fLine( 0, X+4, Y+20, X+20, Y+20, colRGB( x*16, (15-y)*16, 192 ), 6 );
|
---|
155 | if( mazeL(x,y) ) fLine( 0, X+4, Y+4, X+4, Y+20, colRGB( x*16, (15-y)*16, 192 ), 6 );
|
---|
156 | if( mazeR(x,y) ) fLine( 0, X+20, Y+4, X+20, Y+20, colRGB( x*16, (15-y)*16, 192 ), 6 );
|
---|
157 | }
|
---|
158 | }
|
---|
159 | }
|
---|
160 | }
|
---|
161 |
|
---|
162 | //迷路データ[y][x]の上下左右が通路か調べる
|
---|
163 | //通路なら true を返す
|
---|
164 | //迷路の外側も 迷路を描くために true を返す
|
---|
165 | function mazeU( x, y ) {
|
---|
166 | if( y == 0 ) return true;
|
---|
167 | if( maze[y-1][x] != 0 ) return false;
|
---|
168 | return true;
|
---|
169 | }
|
---|
170 |
|
---|
171 | function mazeD( x, y ) {
|
---|
172 | if( y == MAZE_H-1 ) return true;
|
---|
173 | if( maze[y+1][x] != 0 ) return false;
|
---|
174 | return true;
|
---|
175 | }
|
---|
176 |
|
---|
177 | function mazeL( x, y ) {
|
---|
178 | if( x == 0 ) return true;
|
---|
179 | if( maze[y][x-1] != 0 ) return false;
|
---|
180 | return true;
|
---|
181 | }
|
---|
182 |
|
---|
183 | function mazeR( x, y ) {
|
---|
184 | if( x == MAZE_W-1 ) return true;
|
---|
185 | if( maze[y][x+1] != 0 ) return false;
|
---|
186 | return true;
|
---|
187 | }
|
---|
188 |
|
---|
189 | //ボール
|
---|
190 | var goalX, goalY;
|
---|
191 | var BALL_ST = [ 0, 1, 2, 3, 4, 6, 8, 12, 24 ];
|
---|
192 | var BALL_COL = [ "#F00", "#EB0", "#0C0" ];
|
---|
193 | var BALL_MAX = 3;
|
---|
194 | var ballX = [];
|
---|
195 | var ballY = [];
|
---|
196 | var ballA = [];
|
---|
197 | var ballD = [];
|
---|
198 | var ballS = [];
|
---|
199 | var ballT = [];
|
---|
200 |
|
---|
201 | function drawBall() {
|
---|
202 | var a, i;
|
---|
203 | for( i = 0; i < BALL_MAX; i ++ ) {
|
---|
204 | setAlp(1,50);
|
---|
205 | for( a = 0; a < 360; a += 24 ) {
|
---|
206 | fLine( 1, ballX[i], ballY[i], ballX[i]+12*Math.cos(Math.PI*(a+i*8+tmr)/180), ballY[i]+12*Math.sin(Math.PI*(a+i*8+tmr)/180), BALL_COL[i], 5 );
|
---|
207 | }
|
---|
208 | }
|
---|
209 | setAlp(1,100);
|
---|
210 | }
|
---|
211 |
|
---|
212 | function initBall() {//ボールの中心座標をセットする
|
---|
213 | ballX[0] = 36; ballY[0] = 36; ballA[0] = 0;
|
---|
214 | ballX[1] = 324; ballY[1] = 36; ballA[1] = 0;
|
---|
215 | ballX[2] = 36; ballY[2] = 324; ballA[2] = 0;
|
---|
216 | }
|
---|
217 |
|
---|
218 | function moveBall() {
|
---|
219 | var i, x, y;
|
---|
220 | for( i = 0; i < BALL_MAX; i ++ ) {
|
---|
221 |
|
---|
222 | if( ballA[i] == 0 ) {//停止中→移動の向きと速度を決める
|
---|
223 | ballS[i] = 0;
|
---|
224 | //X方向の傾き、Y方向の傾き、傾きの大きいほうの入力を優先
|
---|
225 | if( Math.abs(acX) > Math.abs(acY) ) {
|
---|
226 | if( acX < 0 ) { ballD[i] = 3; ballS[i] = -acX; }
|
---|
227 | if( acX > 0 ) { ballD[i] = 1; ballS[i] = acX; }
|
---|
228 | }
|
---|
229 | else {
|
---|
230 | if( acY < 0 ) { ballD[i] = 2; ballS[i] = -acY; }
|
---|
231 | if( acY > 0 ) { ballD[i] = 0; ballS[i] = acY; }
|
---|
232 | }
|
---|
233 | if( ballS[i] > 8 ) ballS[i] = 8;
|
---|
234 | if( ballS[i] > 0 ) {
|
---|
235 | x = ballX[i] + 24*XP[ballD[i]];
|
---|
236 | y = ballY[i] + 24*YP[ballD[i]];
|
---|
237 | if( maze[toInt(y/24)][toInt(x/24)] == 0 ) {
|
---|
238 | ballA[i] = 1;
|
---|
239 | ballS[i] = BALL_ST[ballS[i]];//移動速度(何ドットずつ動かすか)
|
---|
240 | ballT[i] = 24 / ballS[i];//何フレームで1マス(24ドット)動かすか
|
---|
241 | }
|
---|
242 | }
|
---|
243 | }
|
---|
244 | if( ballA[i] == 1 ) {//移動中
|
---|
245 | ballX[i] = ballX[i] + XP[ballD[i]] * ballS[i];
|
---|
246 | ballY[i] = ballY[i] + YP[ballD[i]] * ballS[i];
|
---|
247 | ballT[i] --;
|
---|
248 | if( ballT[i] == 0 ) ballA[i] = 0;
|
---|
249 | }
|
---|
250 | }
|
---|
251 | }
|
---|
252 |
|
---|
253 | var idx = 0;
|
---|
254 | var tmr = 0;
|
---|
255 | var gtime = 0;
|
---|
256 | var hisc = 0;
|
---|
257 |
|
---|
258 | window.onload = acGame();
|
---|
259 |
|
---|
260 | function acGame() {
|
---|
261 | var s, t, x, y;
|
---|
262 | tmr ++;
|
---|
263 |
|
---|
264 | switch( idx ) {
|
---|
265 |
|
---|
266 | case 0:
|
---|
267 | initMaze(); makeMaze(); drawMaze();
|
---|
268 | initBall();
|
---|
269 | goalX = 13; goalY = 13; click = 0; idx = 1;
|
---|
270 | break;
|
---|
271 |
|
---|
272 | case 1:
|
---|
273 | clrCanvas(1);
|
---|
274 | drawBall();
|
---|
275 | s = 24;
|
---|
276 | t = tmr%30; if( t <= 4 ) s = s + 6 - (t-2)*(t-2);
|
---|
277 | fText( 1, "画面をタップしてスタート!", 180, 120, s, "#CF8" );
|
---|
278 | fText( 1, "端末を傾けて3つのボールを", 180, 160, 24, "#FFF" );
|
---|
279 | fText( 1, "転がしゴールを目指しましょう", 180, 200, 24, "#FFF" );
|
---|
280 | if( Math.abs(acX) >= 2 || Math.abs(acY) >= 2 ) fText( 1, "端末を水平に持って下さい", 180, 240, 24, "#FF0" );
|
---|
281 | if( hisc > 0 ) fText( 1, "最短ゴール時間 " + toInt(hisc/2)/10, 180, 348, 20, "#FFF" );
|
---|
282 | if( click == 1 ) { gtime = 0; idx = 2; tmr = 0; }
|
---|
283 | break;
|
---|
284 |
|
---|
285 | case 2:
|
---|
286 | moveBall();
|
---|
287 | clrCanvas(1);
|
---|
288 | gtime ++;
|
---|
289 | fText( 1, "経過時間 " + toInt(gtime/2)/10, 180, 348, 20, "#FFF" );
|
---|
290 | for( s = 0; s <= 4; s ++ ) {//ゴールの表示
|
---|
291 | t = 32*((tmr+4-s)%8);
|
---|
292 | fRect( 1, goalX*24+2*s, goalY*24+2*s, 24-4*s, 24-4*s, colRGB(t,t,t) );
|
---|
293 | }
|
---|
294 | drawBall();
|
---|
295 | if( window.innerWidth > window.innerHeight ) fText( 1, "縦に持ってプレイしましょう", 180, 12, 20, "#F00" );
|
---|
296 | x = goalX*24+12;//ゴールの画面上の座標
|
---|
297 | y = goalY*24+12;
|
---|
298 | if( ballX[0] == x && ballY[0] == y && ballX[1] == x && ballY[1] == y && ballX[2] == x && ballY[2] == y ) {
|
---|
299 | if( hisc == 0 || gtime < hisc ) hisc = gtime;//最短タイムか?
|
---|
300 | idx = 3;
|
---|
301 | tmr = 0;
|
---|
302 | }
|
---|
303 | break;
|
---|
304 |
|
---|
305 | case 3:
|
---|
306 | clrCanvas(1);
|
---|
307 | fText( 1, "経過時間 " + toInt(gtime/2)/10, 180, 348, 20, "#FFF" );
|
---|
308 | fText( 1, "Goal!", 180, 180, 64+(tmr%8), "#CF8" );
|
---|
309 | if( tmr > 80 ) idx = 0;
|
---|
310 | break;
|
---|
311 |
|
---|
312 | }
|
---|
313 |
|
---|
314 | setTimeout( acGame, 50 );
|
---|
315 | }
|
---|
316 | </script>
|
---|
317 | </body>
|
---|
318 | </html> |
---|