先日、自分の口癖が「ちなみに」であることに気づいたエディター若栁です。
エディターが学ぶ初めてのプログラミングの第5回。第4回に続き、今回もスロットゲームを改修していきます。
今回着手するのは、画像の切り替わり処理の部分。今はsetTimeout()を使って、以下のように書いています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//スロットを動かす箇所のみ抜粋 var timerID; var picture1 = null; var picture2 = null; var picture3 = null; function start_slot() { picture1 = Math.floor(Math.random() * 3 + 1); picture2 = Math.floor(Math.random() * 3 + 1); picture3 = Math.floor(Math.random() * 3 + 1); document.getElementById('slot1').src = "img/" + picture1 + ".png"; document.getElementById('slot2').src = "img/" + picture2 + ".png"; document.getElementById('slot3').src = "img/" + picture3 + ".png"; timerID = setTimeout(start_slot, 80); } |
上で使っているsetTimeout()以外にも、JavaScriptには処理のタイミングを決めるメソッドがあります。
- setTimeout:指定した時間が経過したら、関数を呼び出して1回だけ実行する
- setInterval:指定した時間の間隔で、関数を呼び出して繰り返し実行する←今回はこちらを使ってみます。
setIntervalは、設定した秒数の間隔で、関数を呼び出して実行させます。
設定をオフにするまで、5分おきとか8分おきに鳴り続ける目覚ましアラームのイメージです。
読みは、せっといんたーばる。フォントによって、大文字のIと小文字のlが区別しにくい時もありますのでお気をつけ下さい。
よし、じゃあsetTimeoutをsetIntervalへ置き換えてみよう!と書いたコードがこちらです。
(注意)以下のコードは間違った例なので実行しないでください(注意)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//スロット画像を回す部分のみ抜粋 var timerID = null; var picture1 = null; var picture2 = null; var picture3 = null; function start_slot(){ timerID = setInterval(start_slot, 80); picture1 = Math.floor(Math.random() * 3 + 1); picture2 = Math.floor(Math.random() * 3 + 1); picture3 = Math.floor(Math.random() * 3 + 1); document.getElementById('slot1').src = "img/" + picture1 + ".png"; document.getElementById('slot2').src = "img/" + picture2 + ".png"; document.getElementById('slot3').src = "img/" + picture3 + ".png"; } |
動きました、最初の数秒だけ。
その後は動作が重くなり、画像は切り替わらない上、画面を閉じるのにも数秒かかる始末。7行目と8行目をよく見ると、
1 2 |
function start_slot(){ timerID = setInterval(start_slot, 80); |
start_slot()の中で、さらに0.08秒ごとにstart_slot()を呼び出しているため、処理が重複しています。その結果、何度も同じ処理が走っていました。
以下で、ランダムな画像を表示させるための関数slotting()を新たに作り、start_slot()の外に出しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function slotting() { picture1 = Math.floor(Math.random() * 3 + 1); picture2 = Math.floor(Math.random() * 3 + 1); picture3 = Math.floor(Math.random() * 3 + 1); document.getElementById('slot1').src = "img/" + picture1 + ".png"; document.getElementById('slot2').src = "img/" + picture2 + ".png"; document.getElementById('slot3').src = "img/" + picture3 + ".png"; } function start_slot() { timerID = setInterval(slotting, 80); } |
これで、処理が重くなることなく順調に動きました。次は画像切り替えを止める処理へ移ります。
setIntervalは、「もうやめていいよ」という指示が飛ぶまで、指定の間隔で関数を実行し続けます。
この「もうやめていいよ」にあたるのが、clearIntervalです。設定した間隔をclearして、処理を止めます。
setTimeoutはclearTimeoutと、setIntervalはclearIntervalとセット、と覚えるとよさそうです。
今回は先に、完成形のコードを載せます。
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 |
var timerID = null; var picture1 = null; var picture2 = null; var picture3 = null; function slotting() { picture1 = Math.floor(Math.random() * 3 + 1); picture2 = Math.floor(Math.random() * 3 + 1); picture3 = Math.floor(Math.random() * 3 + 1); document.getElementById('slot1').src = "img/" + picture1 + ".png"; document.getElementById('slot2').src = "img/" + picture2 + ".png"; document.getElementById('slot3').src = "img/" + picture3 + ".png"; } function start_slot() { if (timerID === null) { timerID = setInterval(slotting, 80); } } function stop_slot() { if (timerID !== null) { clearInterval(timerID); timerID = null; if (picture1 === picture2 && picture2 === picture3) { window.open("ooatari.html"); } } } |
start_slot()もstop_slot()も、数行増えていますが追って説明します。まずは24行目のclearIntervalから。
1 |
clearInterval(timerID); |
「setInterval(slotting, 80) で動いているんだから、clearInterval(slotting)じゃだめなの?」と思った方。
だめなんです・・・setIntervalで始めた処理を止めるには、setIntervalの戻り値をclearIntervalに入れる、のが正解。
本ブログの第2回ではこの点に触れなかったのですが、setTimeoutも同じです。
戻り値とは
プログラムが処理された後に、戻ってくる値のこと。
返り値とも言うようですが英語だとreturnなので、どっちでも良さそう。このブログでは戻り値、で統一します。
今回は変数timerIDで戻り値を受け取って、スロット動作の制御にも使っています。
以下、コメントアウトして、どういう処理をしているかを補足します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
var timerID = null; //timerIDという変数を使います!と宣言 //途中省略 function start_slot() { if (timerID === null) { //もしスロットが動いていなかったら timerID = setInterval(slotting, 80);//0.08秒間隔でslotting()を処理して、戻り値をtimerIDに入れる } } function stop_slot() { if (timerID !== null) { clearInterval(timerID); timerID = null; // 以下省略 } } |
timerIDに入っている値が、nullかそれ以外かで、スロットが止まっているか動いているか、も判断できるようになりました。
結果、もともとあった以下の不具合も解消されました。
- あたりが出た画面でストップボタンを押すと、あたり判定が出てしまう。
- スタートボタンを押した数だけ、絵柄の切り替わりが早くなる。
これで最初に作ったスロットよりも、完成度が高くなりました。やった!!
今回はsetIntervalとclearIntervalを扱ってみました。