JavaScriptでスロットゲームを作る

 

スロットゲームの概要

先回ラムネマシーンを作りましたが、IoT化されていませんでした。そこで今回ラムネマシーンをIoT仕様にする準備として、JavaScriptを使ってスロットゲームを作ってみます。
(IoTという言葉の意味はあまり深く考えず、本ホームページ管理者のフィーリング的なものとご了解お願いします。)

今回作成するスロットゲームは次の図の様なものです。左の図が、ページを開いた状態で中央と右側はスロットゲームを行って、“7”が横,もしくは斜めに3つ揃った  “当たり”  の状態を示しています。  今回は、“7”  以外のキャラクターが揃っても  “当たり”  とはしていません。

スロットゲームの概要 ※リンク有

ゲームのやり方は、ページを開いた状態、もしくはゲームが完了している状態(リールが動いていない)で「スタート」ボタンを押すと各縦の列毎にリールが動きます。各列ごとに「停止」ボタンがあり、列毎にリールを停止できます。全リールが停止すると上部に  “当たり!”  、 “外れ!”  の判定結果を出力します。
ラムネマシーンのIoT化との関係は、“当たり!”になった時に、インターネット経由で判定結果をESPr DEVELOPERに知らせ、ラムネを搬出する様にするということです。
今回はブラウザー上で動くスロットゲームのプログラムについて概要を説明します。

プログラム概要

スロットゲームのプログラムについて概略説明します。下記の図は、今回のスロットゲームの画面配置を表しています。表示部(背景色:黄色)には、要素のID属性を書いています。入力部(背景色:灰色)には、ボタンの値(名称)を書いています。JavaScriptのプログラム内で表示部の内容を変更させる時は、このID属性を指定します。これらの表示部,入力部の定義は行番101~135のテーブル要素の中でそれぞれ定義しています。

msg_box
pic11 pic12 pic13
pic21 pic22 pic23
pic31 pic32 pic33
停止 停止 停止
スタート

行番132の「スタート」ボタンは、行番27~46の関数 “start( )” を呼び出します。行番28~32中の  “rotat_f]”  は、左(pic11,21,31)、中央(pic12,22,32)、右(pic13,23,33) をそれぞれ異なる回転リールとして、回転/停止状態を表す変数です。いずれかのリールが回転している場合はスタート処理は実行出来ません。行番38~43では左のリールから順に最初に表示するキャラクター(行番39)、キャラクター変化間隔の基本時間(行番40)を乱数を使って求め、回転用のプログラム(start_prg(  ))を開始します。この時、引数として、0~2を渡しますが、0:左リール,1:中央リール,2:右リールを意味します。また、同時に回転/停止状態を表す “rotat_f[ ]”  を“ON”(回転中) にしています。
行番49~63の回転用のプログラム(start_prg(  ))では、行番50~54で回転リールに表示するキャラクターを求め、行番56~58で表示部に設定します。行番14で対象キャラクターファイル名、行番15で表示部要素のID属性を配列変数に予め格納していますので、受け取った引数  “r_no”  から、対象リールの下段・中段・上段に表示するキャラクター番号と表示箇所を求めることが出来ます。行番60では、キャラクター番号に1加算し、次回表示処理時に表示キャラクターが1枠移動する様にしています。
行番62では、“setTimeout” という遅延処理を使って、設定した遅延時間後に再び同じ引数( “r_no”  )を渡し自身の関数を実行する様にしています。遅延時間として、行番40で計算した変化間隔の基本時間に乱数を使った値を加算していますが、リールが同じ速度で回転しない様にしたいと考えたためです。
最後に「停止」ボタン(行番120,123,126)  から呼び出す各リールの停止(行番66~89)についてです。
行番62で遅延処理時に “time_id[r_no] ” に格納される処理IDを行番67でクリアします。この処理により繰り返し処理を中断します。この時、行番68で回転/停止状態を表す“rotat_f[ ]”  を“OFF”(停止) にしています。各リールの“rotat_f[ ]”が全て “ON”(回転中)以外になった時、行番72~88が実行されます。ここでは行番72~77で、“当たり”の判定を行い、行番81~86で判定に応じ表示を行います。   rotat_f[3]”は、一連のゲームの実施/完了を表し、行番87で“OFF”にすることで、次回ゲームスタートが可能になります。

◆スロットプログラム①(アップロード機能無し)◆

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
	<title>スロットゲーム</title>
	
</head>


<body>
    <script language="JavaScript">

	var slotImg = ['slot1.jpg','slot2.jpg','slot3.jpg','slot4.jpg','slot5.jpg','slot6.jpg'];
	var pic_loc = ['pic11','pic21','pic31','pic12','pic22','pic32','pic13','pic23','pic33'];
	var int_p01 = [ 8 , 5 , 4 ];
	var int_p02 = [ 6 , 9 , 11];

	var time_id = new Array(2);
	var start_p = new Array(2);
	var int_tim = new Array(2);
	var rotat_f = new Array(3);

	var var_par;

	// 全リール回転開始
	function start() {
	    if (rotat_f[0] == "ON" || rotat_f[1] == "ON" || rotat_f[2] == "ON"){
		// リール回転中、スタートボタンを無効にする
		// alert(rotat_f[0] + "," + rotat_f[1] + "," + rotat_f[2] ) ;
		exit() ;
	    }

	    document.getElementById("msg_box").innerHTML = "" ;

    	    var_par = 200 ;

	    for(var i = 0; i < 3; i++ ){
		start_p[i] = Math.floor( Math.random() * 6 );
		int_tim[i] = 80 + int_p01[i] * Math.floor( int_p02[i] * Math.random() );
		start_prg(i);
		rotat_f[i] = "ON" ;
	    }

	    rotat_f[3] = "ON" ;
	}

	// 回転
	function start_prg(r_no) {
    	    if (start_p[r_no] > 5){ start_p[r_no] = 0 ; }
    
    	    var tmp1 = start_p[r_no] ; var tmp2 = start_p[r_no] + 1 ; var tmp3 = start_p[r_no] + 2 ;
    	    if (tmp1==5){ var tmp2 = 0; var tmp3 = 1; }
    	    if (tmp1==4){ var tmp3 = 0; }

    	    document.getElementById(pic_loc[3 * r_no + 0]).src=slotImg[tmp3] ;
    	    document.getElementById(pic_loc[3 * r_no + 1]).src=slotImg[tmp2] ;
    	    document.getElementById(pic_loc[3 * r_no + 2]).src=slotImg[tmp1] ;
 
    	    start_p[r_no] = start_p[r_no] + 1 ;

    	    time_id[r_no] = setTimeout(function(){start_prg(r_no)}, int_tim[r_no] + Math.floor( var_par * Math.random()) );
	}

	// 停止
	function stop_prg(id_no) {
    	    clearTimeout(time_id[id_no]);
	    rotat_f[id_no] = "OFF" ;

	    if (rotat_f[0] != "ON" && rotat_f[1] != "ON" && rotat_f[2] != "ON" && rotat_f[3] == "ON"){
		//全停止
		var jdg_slot = "lost" ;
		if(start_p[0]==1 && start_p[1]==1 && start_p[2]==1){ jdg_slot = "won" ; }
		if(start_p[0]==5 && start_p[1]==5 && start_p[2]==5){ jdg_slot = "won" ; }
		if(start_p[0]==6 && start_p[1]==6 && start_p[2]==6){ jdg_slot = "won" ; }
		if(start_p[0]==1 && start_p[1]==6 && start_p[2]==5){ jdg_slot = "won" ; }
		if(start_p[0]==5 && start_p[1]==6 && start_p[2]==1){ jdg_slot = "won" ; }



		var elem = document.getElementById("msg_box");
		if (jdg_slot == "won" ){
		    elem.innerHTML = "<span style='color:red; font-size:28px; font-weight:bold;'> 当たり!(777)</span>" ;
		}else{
		    elem.innerHTML = "<span style='color:black; font-size:28px; font-weight:bold;'> 外れ! 残念!</span>" ;
		}
		rotat_f[3] = "OFF" ;
	    }
	}

    </script>


    <style>
    	table, tr, td{
    	    border-style:none;
    	    text-align: center;
    	}
    </style>

    <table>
	<tr><td colspan="3" id="msg_box" style="height:45px;"></td></tr>

	<tr><td><img border="0" id="pic11" src="slot1.jpg" width="90" height="60" alt="写真11" ></td>
    	    <td><img border="0" id="pic12" src="slot2.jpg" width="90" height="60" alt="写真12" ></td>
    	    <td><img border="0" id="pic13" src="slot6.jpg" width="90" height="60" alt="写真13" ></td></tr>

	<tr><td><img border="0" id="pic21" src="slot3.jpg" width="90" height="60" alt="写真21" ></td>
    	    <td><img border="0" id="pic22" src="slot1.jpg" width="90" height="60" alt="写真22" ></td>
    	    <td><img border="0" id="pic23" src="slot4.jpg" width="90" height="60" alt="写真23" ></td></tr>

	<tr><td><img border="0" id="pic31" src="slot6.jpg" width="90" height="60" alt="写真31" ></td>
    	    <td><img border="0" id="pic32" src="slot5.jpg" width="90" height="60" alt="写真32" ></td>
    	    <td><img border="0" id="pic33" src="slot1.jpg" width="90" height="60" alt="写真33" ></td></tr>

	<tr><td colspan="3" style="height:30px;"></td></tr>


    	<tr><td align="center">
    	<input type="button" value="停止" onClick="stop_prg(0)" style="width:80px; height:60px; font-size:22px;">
    	</td>
    	<td align="center">
    	<input type="button" value="停止" onClick="stop_prg(1)" style="width:80px; height:60px; font-size:22px;">
    	</td>
    	<td align="center">
    	<input type="button" value="停止" onClick="stop_prg(2)" style="width:80px; height:60px; font-size:22px;">
    	</td></tr>

	<tr><td colspan="3" style="height:15px;"></td></tr><tr><td colspan="3"></td></tr>

	<tr><td colspan="3">
    	<input type="button" value="スタート" onClick="start()" style="width:170px; height:60px; font-size:25px;">
    	</td></tr>

    </table>

</body>

</html>

 

HTTP 通信で判定結果をアップロード

判定結果をレンタルサーバーにアップロードし、結果をESPr DEVELOPER 側から監視する様な流れになるかなと思って、過去の投稿を確認してみます。以下の投稿が流用出来そうです。

元のプログラムに行番91~124を追加し、行番82,行番85からそれぞれ判定結果によって、引数の値を変えて追加したHTTP通信の関数を呼び出しています。関数からサーバー上のPHPプログラムを呼び出しています。

◆スロットプログラム②(アップロード機能有り)◆

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
	<title>スロットゲーム</title>
	
</head>


<body>
    <script language="JavaScript">

	var slotImg = ['slot1.jpg','slot2.jpg','slot3.jpg','slot4.jpg','slot5.jpg','slot6.jpg'];
	var pic_loc = ['pic11','pic21','pic31','pic12','pic22','pic32','pic13','pic23','pic33'];
	var int_p01 = [ 8 , 5 , 4 ];
	var int_p02 = [ 6 , 9 , 11];

	var time_id = new Array(2);
	var start_p = new Array(2);
	var int_tim = new Array(2);
	var rotat_f = new Array(3);

	var var_par;

	// 全リール回転開始
	function start() {
	    if (rotat_f[0] == "ON" || rotat_f[1] == "ON" || rotat_f[2] == "ON"){
		// リール回転中、スタートボタンを無効にする
		// alert(rotat_f[0] + "," + rotat_f[1] + "," + rotat_f[2] ) ;
		exit() ;
	    }

	    document.getElementById("msg_box").innerHTML = "" ;

    	    var_par = 200 ;

	    for(var i = 0; i < 3; i++ ){
		start_p[i] = Math.floor( Math.random() * 6 );
		int_tim[i] = 80 + int_p01[i] * Math.floor( int_p02[i] * Math.random() );
		start_prg(i);
		rotat_f[i] = "ON" ;
	    }

	    rotat_f[3] = "ON" ;
	}

	// 回転
	function start_prg(r_no) {
    	    if (start_p[r_no] > 5){ start_p[r_no] = 0 ; }
    
    	    var tmp1 = start_p[r_no] ; var tmp2 = start_p[r_no] + 1 ; var tmp3 = start_p[r_no] + 2 ;
    	    if (tmp1==5){ var tmp2 = 0; var tmp3 = 1; }
    	    if (tmp1==4){ var tmp3 = 0; }

    	    document.getElementById(pic_loc[3 * r_no + 0]).src=slotImg[tmp3] ;
    	    document.getElementById(pic_loc[3 * r_no + 1]).src=slotImg[tmp2] ;
    	    document.getElementById(pic_loc[3 * r_no + 2]).src=slotImg[tmp1] ;
 
    	    start_p[r_no] = start_p[r_no] + 1 ;

    	    time_id[r_no] = setTimeout(function(){start_prg(r_no)}, int_tim[r_no] + Math.floor( var_par * Math.random()) );
	}

	// 停止
	function stop_prg(id_no) {
    	    clearTimeout(time_id[id_no]);
	    rotat_f[id_no] = "OFF" ;

	    if (rotat_f[0] != "ON" && rotat_f[1] != "ON" && rotat_f[2] != "ON" && rotat_f[3] == "ON"){
		//全停止
		var jdg_slot = "lost" ;
		if(start_p[0]==1 && start_p[1]==1 && start_p[2]==1){ jdg_slot = "won" ; }
		if(start_p[0]==5 && start_p[1]==5 && start_p[2]==5){ jdg_slot = "won" ; }
		if(start_p[0]==6 && start_p[1]==6 && start_p[2]==6){ jdg_slot = "won" ; }
		if(start_p[0]==1 && start_p[1]==6 && start_p[2]==5){ jdg_slot = "won" ; }
		if(start_p[0]==5 && start_p[1]==6 && start_p[2]==1){ jdg_slot = "won" ; }

		var elem = document.getElementById("msg_box");
		if (jdg_slot == "won" ){
		    elem.innerHTML = "<span style='color:red; font-size:28px; font-weight:bold;'> 当たり!(777)</span>" ;
		    var rtn = exec_svr_prg("OK");
		}else{
		    elem.innerHTML = "<span style='color:black; font-size:28px; font-weight:bold;'> 外れ! 残念!</span>" ;
		    var rtn = exec_svr_prg("NG");
		}
		rotat_f[3] = "OFF" ;
	    }
	}

	// HTTP通信API設定
	function createXmlHttpRequest(){
    	    var xmlhttp=null;
    	    if(window.ActiveXObject){
        	try { xmlhttp=new ActiveXObject("Msxml2.XMLHTTP"); }
        	catch(e) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
            		   catch (e2){ }
                }
    	    }else if(window.XMLHttpRequest){
        	xmlhttp = new XMLHttpRequest();
    	    }
    	    return xmlhttp;
	}
 
	// サーバー側PHPプログラムを起動し、結果を得る
	function exec_svr_prg(rcv_dat)
	{   
	    var get_dat = rcv_dat ;
            var xmlhttp=createXmlHttpRequest();

            if(xmlhttp!=null){
        	xmlhttp.open("POST", "http_test.php", false);
        	xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        	var data = "data="+get_dat;
        	xmlhttp.send(data);
        	var rtn=xmlhttp.responseText;
		
		return rtn ;

	    }else{
		return "ER" ;
		alert("HTTP通信API設定失敗!");
    	    }
	}

    </script>


    <style>
    	table, tr, td{
    	    border-style:none;
    	    text-align: center;
    	}
    </style>

    <table>
	<tr><td colspan="3" id="msg_box" style="height:45px;"></td></tr>

	<tr><td><img border="0" id="pic11" src="slot1.jpg" width="90" height="60" alt="写真11" ></td>
    	    <td><img border="0" id="pic12" src="slot2.jpg" width="90" height="60" alt="写真12" ></td>
    	    <td><img border="0" id="pic13" src="slot6.jpg" width="90" height="60" alt="写真13" ></td></tr>

	<tr><td><img border="0" id="pic21" src="slot3.jpg" width="90" height="60" alt="写真21" ></td>
    	    <td><img border="0" id="pic22" src="slot1.jpg" width="90" height="60" alt="写真22" ></td>
    	    <td><img border="0" id="pic23" src="slot4.jpg" width="90" height="60" alt="写真23" ></td></tr>

	<tr><td><img border="0" id="pic31" src="slot6.jpg" width="90" height="60" alt="写真31" ></td>
    	    <td><img border="0" id="pic32" src="slot5.jpg" width="90" height="60" alt="写真32" ></td>
    	    <td><img border="0" id="pic33" src="slot1.jpg" width="90" height="60" alt="写真33" ></td></tr>

	<tr><td colspan="3" style="height:30px;"></td></tr>


    	<tr><td align="center">
    	<input type="button" value="停止" onClick="stop_prg(0)" style="width:80px; height:60px; font-size:22px;">
    	</td>
    	<td align="center">
    	<input type="button" value="停止" onClick="stop_prg(1)" style="width:80px; height:60px; font-size:22px;">
    	</td>
    	<td align="center">
    	<input type="button" value="停止" onClick="stop_prg(2)" style="width:80px; height:60px; font-size:22px;">
    	</td></tr>

	<tr><td colspan="3" style="height:15px;"></td></tr><tr><td colspan="3"></td></tr>

	<tr><td colspan="3">
    	<input type="button" value="スタート" onClick="start()" style="width:170px; height:60px; font-size:25px;">
    	</td></tr>

    </table>

</body>

</html>

サーバー上のPHPプログラムは、下記の様な簡単なものです。ブラウザー側からのデータを受け取って、結果をそのままテキストファイルに上書きするというものです。
自動ではありませんが、サーバー上に“slot_result.txt”というファイルが生成され、判定結果(“OK”/“NG”)が、書き込まれていることが確認出来ました。

<?php

error_reporting(0);
mb_language("ja");
mb_internal_encoding("UTF-8");

$rcv_dat=$_POST["data"];

file_put_contents("slot_result.txt",$rcv_dat);

echo $rcv_dat;

?>

 

まとめ

サーバーに結果をアップロードするところまで出来ましたので、次回はESPr DEVELOPER側から、結果を監視し、“OK”の場合、ラムネを払い出す処理について考えてみたいと思います。
今回の個人的な成果としては、ブラウザー上の画像位置を連続的に変更することが出来たことと思います。いくつか他のサイトも拝見させて頂きましたが、きめ細やかな動きが出来ていて、比較すると見劣りしてしまいますが、落胆することなく継続し、ブラッシュアップしていきたいと思います。

★今回の成果★ ※リンクしています。
◆スロットプログラム①(アップロード機能無し)◆
◆スロットプログラム②(アップロード機能有り)◆

★関連する前の投稿★ ※リンクしています。
◆ESPR DEVELOPER でラムネマシーンを作る◆

※サーバー環境:レンタルサーバー(ロリポップ)
ライトプラン(月々250円~)

「JavaScriptでスロットゲームを作る」への1件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です