3-2 (3) ソースコード


解説ページに戻る

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//キャンバスの準備
14var winW = window.innerWidth;
15var winH = window.innerHeight;
16var CWIDTH  = 360;
17var CHEIGHT = 360;
18if( winW < winH )
19 winH = winW;
20else
21 winW = winH;
22var SCALE = winW / CWIDTH;
23
24var canvas = [];
25var cnt = [];
26for( 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
37var click = 0;
38canvas[1].onclick = function(event) { click = 1; }
39
40function toInt( val ) {//整数を返す関数
41 return parseInt(val);
42}
43
44function rnd( max ) {//乱数を返す関数
45 return toInt( Math.random()*max );
46}
47
48function colRGB( red, gre, blu ) {//色を返す
49 return ( "rgb(" + red + "," +  gre + "," + blu + ")" );
50}
51
52function setAlp( cn, per ) {//透明度
53 cnt[cn].globalAlpha = per/100;
54}
55
56function clrCanvas( cn ) {//キャンバスをクリアする
57 cnt[cn].clearRect( 0, 0, CWIDTH, CHEIGHT );
58}
59
60function 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
66function fRect( cn, x, y, w, h, col ) {//矩形
67 cnt[cn].fillStyle = col;
68 cnt[cn].fillRect( x, y, w, h );
69}
70
71function 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//キー入力
81var key = 0;
82window.onkeydown = function(event) { key = event.keyCode; }
83window.onkeyup = function(event) { key = 0; }
84
85//加速度センサー
86var acX = 0, acY = 0, acZ = 0;
87window.addEventListener( "devicemotion", deviceMotion );
88function 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//迷路
101var MAZE_W = 15;
102var MAZE_H = 15;
103var 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
109function 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
131var XP = [  0, 1, 0, -1 ];
132var YP = [ -1,  0, 1, 0 ];
133function 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
144function 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 を返す
165function mazeU( x, y ) {
166 if( y == 0 ) return true;
167 if( maze[y-1][x] != 0 ) return false;
168 return true;
169}
170
171function 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
177function mazeL( x, y ) {
178 if( x == 0 ) return true;
179 if( maze[y][x-1] != 0 ) return false;
180 return true;
181}
182
183function 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//ボール
190var goalX, goalY;
191var BALL_ST = [ 0, 1, 2, 3, 4, 6, 8, 12, 24 ];
192var BALL_COL = [ "#F00", "#EB0", "#0C0" ];
193var BALL_MAX = 3;
194var ballX = [];
195var ballY = [];
196var ballA = [];
197var ballD = [];
198var ballS = [];
199var ballT = [];
200
201function 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
212function 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
218function 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
253var idx = 0;
254var tmr = 0;
255var gtime = 0;
256var hisc = 0;
257
258window.onload = acGame();
259
260function 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>

傾きの値から、ボールの移動方向と速度を決める処理( moveBall()関数 )について
220forループでBALL_MAX(今回はボール3個)分の処理する。
222~232ボールが停止している時、X方向、Y方向、傾きの大きいほうの入力を優先し、その値からボールの向きと速度を決める
233速度は1~最大8の8段階
234~242移動方向に壁が無いなら、ボールの速度と何フレームで移動するかの変数をセットする
244~249ボールを移動する処理


解説ページに戻る
お気軽にお問い合わせ下さい →