| 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> |
|---|