html5 Canvasでシューティングゲーム
http://www.geocities.jp/psipage/html5/html5_canvas_shot.html
書いてみた。
boxの上半分にターゲットが現れ、下半分をクリックで弾を発射。
パラメータの値をいじると面白いかも。
context.shadowBlurについて
contextに影(ぼかし)を入れるためにshadowBlurを適用したら処理が重くなった。対応してるブラウザも少ない。
shadowBlur プロパティ - Canvasリファレンス - HTML5.JP
気になったこと
マウスの座標はキャンバスからの相対位置ではなく絶対位置。なのでCanvas領域の上にバナー広告などが入ることを想定すると、相対位置で考えると思い通りに動かない(ことがあるかも)。とりあえずCanvas領域の位置は絶対配置で指定した。
<canvas id="canvassample" width="640" height="320" style="position: absolute; top:80px;"></canvas>
position: absolute;したら、それ以降の要素すべて絶対配置にする必要あり?よくわかんない。
ソース
<!DOCTYPE html> <html> <head> <meta charset=utf-8 /> <title>Example3(Shooting): HTML5 canvas</title> <!--[if IE]> <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> </head> <body> <canvas id="canvassample" width="640" height="320" style="position: absolute; top:80px;" onmousedown="mouseClicked()" onmousemove="mouseMove(event.clientX, event.clientY)" onmouseup="mouseUp()"></canvas> <script type="text/javascript"> window.onload = function() { setInterval('draw()',10); }; var w_size = 640; var h_size = 320; var y = 20; var oval_size = 10; ; var mouse_X = 0; var mouse_Y = 0; function draw() { /* canvas要素のノードオブジェクト */ var canvas = document.getElementById('canvassample'); /* canvas要素の存在チェックとCanvas未対応ブラウザの対処 */ if ( ! canvas || ! canvas.getContext ) { document.getElementById('ms').innerHTML = "This browser is not supported." return false; } /* 2Dコンテキスト */ var ctx = canvas.getContext('2d'); ctx.clearRect(0,0,w_size,h_size); ctx.strokeStyle = "black"; // 枠 ctx.strokeRect(0,0,w_size,h_size); // 敵との境界 ctx.moveTo(0, (h_size / 2)+50); ctx.lineTo(w_size, (h_size / 2)+50); ctx.stroke(); enemy(ctx); ctx.clearRect(1, (h_size / 2)+50+1,w_size-2, (h_size / 2)-52); bullet(ctx); ctx.beginPath(); //ctx.arc(mouse_X, mouse_Y, oval_size, 0, Math.PI*2, false); ctx.stroke(); ctx.closePath(); }; // 弾描画 var bullet_array = []; var end = 0; function bullet(ctx) { ctx.beginPath(); ctx.strokeStyle = "#a0410d"; ctx.lineCap = "round"; ctx.lineWidth = 1; for(var i=end;i<bullet_array.length;i++) { ctx.moveTo(bullet_array[i][0], bullet_array[i][1] - 10); ctx.lineTo(bullet_array[i][0], bullet_array[i][1]); ctx.stroke(); if (bullet_array[i][1] >= -10) { bullet_array[i][1] -= 4; } else { end += 1; } } }; // 敵描画&当たり判定 var enemy_array = []; var enemy_size = 30; var enemy_wait_time = 0; var hit_count = 0; var enemy_leave = 0; var enemy_color = []; var enemy_size_array = []; var hit = 0; var purupuru1 = 3; var _hit = 0; var enemy_born_interval = 100; var enemy_num = 10; function enemy(ctx) { if (enemy_wait_time == 0) { // create enemy var tmp = []; tmp[0] = Math.floor(Math.random() * w_size); tmp[1] = Math.floor(Math.random() * (h_size / 2)); enemy_array[enemy_array.length] = tmp; setColor(enemy_color.length); enemy_size_array[enemy_size_array.length] = 20 +Math.floor(Math.random() * enemy_size); } var enemy_count = 0; for (var i=enemy_leave;i<enemy_array.length;i++) { if (!(enemy_size_array[i] <= 0)) { for (var ii=end;ii<bullet_array.length;ii++) { if (enemy_array[i][0] - enemy_size_array[i] <= bullet_array[ii][0] && bullet_array[ii][0] <= enemy_array[i][0] + enemy_size_array[i] && enemy_array[i][1] - enemy_size_array[i] <= bullet_array[ii][1] && bullet_array[ii][1] <= enemy_array[i][1] + enemy_size_array[i]) { enemy_size_array[i] -= 1; hit += 1; document.getElementById('debug').innerHTML = "Hit!: " + hit; if (hit > 1500) { document.getElementById('debug').innerHTML += " ★★★"; } else if(hit > 1000) { document.getElementById('debug').innerHTML += " ★★☆"; } else if(hit > 500) { document.getElementById('debug').innerHTML += " ★☆☆"; } ctx.fillStyle = "orange"; //enemy_array[i][0] = -1; //enemy_array[i][1] = -1; } } } if (!(enemy_size_array <= 0)) { if ((Math.random() * 2) < 1) { enemy_array[i][0] -= (Math.random() * purupuru1); } else { enemy_array[i][0] += (Math.random() * purupuru1); } if ((Math.random() * 2) < 1) { enemy_array[i][1] -= (Math.random() * purupuru1); } else { enemy_array[i][1] += (Math.random() * purupuru1); } // 敵描画 ctx.beginPath(); ctx.fillStyle = enemy_color[i]; ctx.arc(enemy_array[i][0], enemy_array[i][1], enemy_size_array[i], 0, Math.PI*2, false); ctx.fill(); ctx.closePath(); enemy_count += 1; } } enemy_wait_time += 1; if (enemy_wait_time < enemy_born_interval) { return; } else { if (enemy_count > enemy_num) { enemy_leave += 1; } enemy_wait_time = 0; } }; // 弾の移動 var bullect_count = 0; var bullect_u = 1; function shot() { var tmp = []; tmp[0] = mouse_X -7; tmp[1] = mouse_Y -67; bullet_array[bullect_count] = tmp; bullect_count += bullect_u; }; function setColor(index) { var color = Math.floor(Math.random() * 0xFFFFFF).toString(16); //#RRGGBBを取得 for(count = color.length; count < 6; count++){ color = "0" + color; //上位に0を補完する } enemy_color[index] = "#" + color; }; function setColors() { for (var i=enemy_leave;i<enemy_array.length;i++) { setColor(i); } }; function mouseClicked() { if (mouse_Y >= (h_size / 2) + 50 + 87) { shot(); } }; function mouseUp() { trigger = 0; }; function mouseMove(x,y) { mouse_X = x; mouse_Y = y; document.getElementById('debug2').innerHTML = "MousePos: x="+mouse_X + " y="+mouse_Y; }; function change() { enemy_num = parseInt(document.getElementById('enemy_num').value); enemy_size = parseInt(document.getElementById('enemy_size').value); enemy_born_interval = parseInt(document.getElementById('enemy_born_interval').value); purupuru1 = parseInt(document.getElementById('purupuru1').value); }; </script> <div style="position: absolute;top:400px;">.</div> <div id="debug" style="position: absolute;top:420px;">Hit!: 0</div> <div id="debug2" style="position: absolute;top:440px;"> </div> <p style="position: absolute;top:460px;"> <form style="position: absolute; top:460px;"> 目標の最大数:<input type="text" id="enemy_num" value="10" onchange="change()"></input> 目標の大きさ:<input type="text" id="enemy_size" value="30" onchange="change()"></input> 目標が表示される間隔:<input type="text" id="enemy_born_interval" value="100" onchange="change()"></input> プルプル係数:<input type="text" id="purupuru1" value="3" onchange="change()"></input> </form> </p> <p style="position: absolute;top:500px;"><a href="http://d.hatena.ne.jp/juntk/20100425/1272201655">HTML5 Canvasでシューティングっぽいもの</a></p> </body> </html>