かつてパソコン雑誌で「暇つぶし」という名前のフリーソフトが紹介されていました。次々とあらわれる「暇」という文字をクリックして潰していくというもので、これをやっていると「俺って暇だなあ」という気持ちになるとのこと。
以前 本当に鳩でも分かるC#講座で動く暇つぶしを作りました。今回はJavaScriptで同じようなものをつくります。
HTMLとCSS部分
HTML部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>JavaScriptでつくる動く暇つぶし</title> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="./style.css" type="text/css" media="all"> <style> </style> </head> <body> <div id = "container"> <div id = "hit-count"></div> <div id = "miss-count"></div> </div> <script type='text/javascript' src='./app.js'></script> </body> </html> |
style.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#container { border: 1px solid #333; width: 320px; height: 480px; background-color: #000; position: relative; overflow: hidden; } #hit-count { position: absolute; top: 450px; left: 120px; color: #fff; } #miss-count { position: absolute; top: 450px; left: 220px; color: #fff; } |
JavaScript部分
タイマーで更新処理をおこない、更新時に暇という文字を追加して移動させます。
グローバル変数
最初にグローバル変数を示します。
app.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
let updateCount = 0; // 更新回数 let $container = document.getElementById('container'); let maxX = $container.clientWidth; // 「暇」文字が取り得るX座標とY座標の最大値 let maxY = $container.clientHeight; let colors = ['#f00', '#0f0', '#00f','#ff0', '#f0f', '#0ff']; // 文字の色 let $hitCount = document.getElementById('hit-count'); // 成功回数と失敗回数を表示させるdiv要素 let $missCount = document.getElementById('miss-count'); let hit = 0; // 成功回数と失敗回数 let miss = 0; let himas = []; // 暇オブジェクトを格納する配列 |
Himaクラスの定義
暇という文字を表示・移動させるHimaクラスを定義します。
コンストラクタに渡す引数は出現位置のXY座標と消滅位置のXY座標です。出現した文字は消滅座標にむけて移動します。出現位置のXY座標と消滅位置のXY座標は、乱数を生成して決定します。また移動速度と文字の色も乱数を生成して設定します。
Math.random()とすることで0以上1未満の乱数を生成することができます。Math.random() * 3.5とすれば0以上3.5未満の乱数を生成することができます。またMath.floor( Math.random() * 6)とすれば0から5までの整数の乱数を生成することができます。
表示したい座標に表示できるように文字は絶対配置にします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
class Hima { constructor(startX, startY, endX, endY){ let colorIndex = Math.floor( Math.random() * colors.length); let speed = 2 + Math.random() * 3; // 乱数を生成して移動速度を設定する this.X = startX; this.Y = startY; let elm = document.createElement('span'); elm.style.color = colors[colorIndex]; elm.style.position = 'absolute'; // 絶対配置 elm.style.left = this.X + 'px'; elm.style.top = this.Y + 'px'; elm.innerText = '暇'; elm.style.font = '32px MS ゴシック'; $container.append(elm); this.Element = elm; this.IsDead = false; // 移動する角度を求める let angle = Math.atan2(endY - startY, endX - startX); // 移動する角度が決定するとXY方向にどれだけ移動すればよいかも決定する this.VX = Math.cos(angle) * speed; this.VY = Math.sin(angle) * speed; // 文字をクリックしたらhitをインクリメントして文字を取り除く // このままでは文字をクリックすると$containerでもクリックイベントが発生するので伝搬を止める // 文字が消滅してもオブジェクト自体は配列内に残るのでIsDeadフラグを立ててあとで取り除けるようにする elm.onclick = (ev) => { hit++; elm.remove(); this.IsDead = true; ev.stopPropagation(); // 伝搬を止める } } Move(){ // 移動先のXY座標をもとめてセットする this.X += this.VX; this.Y += this.VY; this.Element.style.left = this.X + 'px'; this.Element.style.top = this.Y + 'px'; // 外に移動したら文字を消滅させる if(this.X < 0 || this.X > maxX || this.Y < 0 || this.Y > maxY){ this.Element.remove(); this.IsDead = true; } } } |
文字ではない部分をクリックしたときの処理を示します。
1 2 3 |
// 文字ではない部分をクリックしたらミスとする // 変数missをインクリメントする $container.onclick = () => miss++; |
更新処理を示します。更新回数の下2桁が00,25, 50, 75のときは新しく文字を生成し、配列に格納します。生成される位置は外枠の上辺、下辺、左辺、右辺のいずれかの上で対辺にむけて移動します。
配列に格納されているオブジェクトのMove関数を呼び出して移動の処理をおこないます。そのあとIsDeadフラグが立っているオブジェクトを配列から除外します。最後にヒット数とミス数を画面下部に表示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
setInterval(() => { updateCount++; if(updateCount % 100 == 0) himas.push(new Hima(0, Math.random() * maxY,maxX, Math.random() * maxY)); if(updateCount % 100 == 25) himas.push(new Hima(maxX, Math.random() * maxY, 0, Math.random() * maxY)); if(updateCount % 100 == 50) himas.push(new Hima(Math.random() * maxX, 0, Math.random() * maxX, maxY)); if(updateCount % 100 == 75) himas.push(new Hima(Math.random() * maxX, maxY, Math.random() * maxX, 0)); for(let i=0; i < himas.length; i++) himas[i].Move(); himas = himas.filter(_=> !_.IsDead); // IsDeadフラグが立っていないものだけを集める $hitCount.innerHTML = `HIT ${hit}`; $missCount.innerHTML = `MISS ${miss}`; }, 33); |
このゲームの欠陥は効果音がないことと、始まりと終わりがなく延々と続いてしまうことです。次回はcanvasを使って同じようなものをつくります。