Little Strange Software

スマホアプリの開発を行う LittleStrangeSoftware のブログです。

【JavaScript】落ち物パズル「泡」【さじさんver】

 どうも!LSSです!!

 落ち物パズルシリーズ、今回は番外編!

 大幅に雰囲気の変わったゲームをお楽しみください^^

 

 

落ち物パズル「泡」

 

 

 

 

ルール

↑こちらに、とても分かりやすく画像で説明されています。

簡単に書くと「色のついた泡の周囲(斜め含む8マス)を透明の泡で囲めばOK!」です^^

  

Designed by id:conasaji

このゲームは、LSSが当ブログにて制作していた落ち物パズルの「消し実装」前に、さじさん(id:conasaji)が改変に挑戦してくださって生まれたものです^^

 

その、作っていただいたものを今度は逆にLSSがパク消し機能を付与したものが、今回の記事となります!

 

 

コード

<style><!--
#gamen{
position:relative;
background-color: gray;
}
#gamen a{
color:black;
text-decoration:underline;
}
#gamen a:hover{
color:khaki;
}
.km{
position:absolute;
border-radius:30px;
text-align:center;
border-width:3px;
border-style:outset;
background-image:radial-gradient(circle at 70% 30%,#ffffffc0,transparent);
transition:0.2s;
}
.c1{background-color:pink;border-color: white;}
.c2{background-color:aqua;border-color: white;}
.btnlr{
display:inline-block;
position:relative;
width:110px;
background-color: lightcyan;
text-align:center;
border-radius:5px;
border:5px outset lightcyan;
background-image:radial-gradient(circle at 70% 30%,#ffffffc0,transparent);
}
.btndp{
display:inline-block;
position:relative;
background-color: orangered;
text-align:center;
border-radius:5px;
border:5px outset orangered;
background-image:radial-gradient(circle at 70% 30%,#ffffffc0,transparent);
}
--></style>
<div id="gamen"> </div>
<p> </p>
<div id="g2"> </div>
<p>
<script>// <![CDATA[
wMax=4;//横マス数
hMax=5;//縦マス数
kms=9;//コマ種類数
sz=60;//1マスあたりのサイズ
sy=9;//落下速度調節用
psf=false;//一時停止管理フラグ
scr=0;//スコア
fws=0;//花の数
masu=[ ];
for(i=0;i<wMax;i++){
 masu[i]=[ ];
 for(j=0;j<hMax;j++){
  masu[i][j]=0;
 }
}
w=wMax*sz;//画面幅
h=hMax*sz;//画面高さ
document.getElementById("gamen").style.width=w+'px';
document.getElementById("gamen").style.height=h+'px';
mx=0;//操作中コマ横位置
my=0;//操作中コマ縦位置
mz=0;//操作中コマ種類
mz_n=0;//NEXTコマ種類
gamen_i();
function tmc(){
if((my<h-sz) && (masu[mx][Math.floor(my/sz)+1]==0)){
my+=sz/sy;
kmv();
}else{
masu[mx][Math.floor(my/sz)]=mz;
clearInterval(tm);
kensa();
tms();
if(my<sz){
clearInterval(tm);
document.getElementById("gamen").style.backgroundColor='gold';
txt='ゲームオーバー<br/>';
txt+='スコア:'+scr+' :'+fws;
g2.innerHTML=txt;
}else{
kminit();
gamen_w();
kmv();
}
}
}

function tms(){
 tm=setInterval("tmc()",200);
}

function rakka(){
 while(masu[mx][Math.floor(my/sz)+1]==0){
  scr++;
  my=Math.floor(my/sz)*sz+sz+sz/3;
 }
}

function gamen_i(){
 txt='<a href="#!" onclick="tms();kminit();gamen_w();return false;">ここをクリックしてスタート!</a>';
 txt+='<br/><br/><br/><a href="#!" onclick="kms=4;tms();kminit();gamen_w();return false;">ハードモード</a>';
 gamen.innerHTML=txt;
}

function gamen_w(){
txt='';
txt='<div style="position:absolute;height:'+sz*0.6+'px;font-size:'+sz/4+'px;top:0px;left:0px;padding:3px 3px;">Score:'+scr+' :'+fws+'</div>';
txt+='<div class="km c'+mz_n+'" style="height:'+sz*0.6+'px;font-size:'+sz/4+'px;top:0px;right:0px;padding:0px 10px;">NEXT '+mz_n+'</div>';
for(i=0;i<wMax;i++){
for(j=0;j<hMax;j++){
if(masu[i][j]>0){
txt+='<div class="km c'+masu[i][j]+'" style="top:'+j*sz+'px;left:'+i*sz+'px;width:'+sz+'px;height:'+sz+'px;">'+masu[i][j]+'</div>';
}
}
}
txt+='<div id="koma" class="km c'+mz+'" style="top:'+my+'px;left:'+mx*sz+'px;width:'+sz+'px;height:'+sz+'px;">'+mz+'</div>';
gamen.innerHTML=txt;
txt2='';
if(psf){
txt2+='<a href="#!" onmousedown="tms();psf=false;gamen_w();">再開</a> ';
}else{
txt2+='<a href="#!" class="btnlr" onmousedown="mx-=(mx>0 && masu[mx-1][Math.ceil(my/sz)]==0?1:0);kmv();" ondoubleclick="return false;">←に移動</a>';//何故かonclickだと反応が鈍い
txt2+='<a href="#!" class="btnlr" onmousedown="mx+=(mx<wMax-1 && masu[mx+1][Math.ceil(my/sz)]==0?1:0);kmv();" ondoubleclick="return false;">→に移動</a>';
txt2+='<a href="#!" class="btndp" onmousedown="rakka();kmv();" ondoubleclick="return false;">落とす</a> ';
txt2+='<br/>';
txt2+='<br/>';
txt2+='<a href="#!" onmousedown="clearInterval(tm);psf=true;gamen_w();">一時停止</a>';
}
g2.innerHTML=txt2;
}

function kmv(){
 document.getElementById('koma').style.top=my+'px';
 document.getElementById('koma').style.left=mx*sz+'px';
}

function kminit(){
 mx=3;
 my=0;
 do{
  mz=mz_n;
  mz_n=Math.floor(1+Math.random()*kms);
 }while(mz==0)
}

function kensa(){
 kscnt=0;//消しカウント
//全マス検査開始
 for(i=1;i<wMax-1;i++){
  for(j=1;j<hMax-1;j++){
   if(masu[i][j]>0 && masu[i][j]<3 && masu[i-1][j-1]>2 && masu[i][j-1]>2 && masu[i+1][j-1]>2 && masu[i-1][j]>2 && masu[i+1][j]>2 && masu[i-1][j+1]>2 && masu[i][j+1]>2 && masu[i+1][j+1]>2){
    kscnt++;
    fws++;
   }
  }
 }
 gamen_w();
 if(kscnt>0){
  scr+=100;
  for(i=0;i<wMax;i++){
   for(j=0;j<hMax;j++){
    masu[i][j]=0;
   }
  }
 }
}
// ]]></script>
</p>

赤文字部分が、さじさんとLSSが書き換えた部分になります。(他にカットした部分もあります)

 

消し判定について解説します

if(
masu[i][j]>0 && masu[i][j]<3
&& masu[i-1][j-1]>2 && masu[i][j-1]>2 && masu[i+1][j-1]>2
&& masu[i-1][j]>2 && masu[i+1][j]>2
&& masu[i-1][j+1]>2 && masu[i][j+1]>2 && masu[i+1][j+1]>2
){

処理部分

 

function kensa()の中のif文をこのように書き換えました。

変数 masu[横座標][縦座標]は、4×5の盤面に「どの泡が置かれているか」を記録している変数です。

 

例えばmasu[0][0]なら盤面の一番左上のマスを、masu[3][4]なら一番右下のマスの状態を表す数値が記録されています。

 

その値が0の時は空きマス、1~9の時は「その数字の泡が置かれている」ものとしています。

 

今回のゲームでは、色付き泡は1と2で、3以上は透明の泡です。

 

変数iとjでループを回しており、
for(i=1;i<wMax-1;i++){  for(j=1;j<hMax-1;j++){の部分)
「masu[i][j]を中心とした場合に、条件が成立しているか?」をこのif文で判定しているんですね。

 

masu[i][j]>0 && masu[i][j]<3

は、「中央が1か2である事」(&&はand条件、日本語でいう「なおかつ」に相当)

 

&& masu[i-1][j-1]>2 && masu[i][j-1]>2 && masu[i+1][j-1]>2

j-1は中心より1マス分上の行で、中心となるiの左隣の座標であるi-1、およびi、およびi+1の全てが「2より大きい(3以上)=透明の泡である事」

 

&& masu[i-1][j]>2 && masu[i+1][j]>2

同様に、「中心の左隣と右隣が透明の泡である事」

 

&& masu[i-1][j+1]>2 && masu[i][j+1]>2 && masu[i+1][j+1]>2

同様に、中心より1マス分下の行の3つ全てが「透明である事」

 

…の全ての条件が成立した時、
「色付きの泡を透明の泡で包んだ」
という事になります^^

 

挙動の変更

LSSが作ったほうの落ち物パズルは、
「条件成立したコマだけを消し、その上にあったものは落下」
という仕組みにしていましたが、今回はゲームの性質上、その仕組みをばっさりカットし、「条件が成立したら全てのマスがリセット」されるようにしました。

 

また、「イージーモード」はこのゲームルールの場合、逆に難易度が上がるので、文言だけ「ハードモード」に変更していますwww

 

 

謝辞

もちろん、遊んで楽しんでいただいただけでも、めちゃくちゃありがたいです^^

それが更にこうして「自分なりの改変」 に挑戦していただけると、コード載せたり解説書いたりした甲斐があります^^

 

さじさん、ありがとうございました!

 

 

余談

さじさんが改変に挑戦された折、「泡が自然落下で着地した時にぽよんってなる」演出が生まれました。

偶然生まれたようですが、「泡」っぽさがより出る素敵な演出でしたので、
「落とす」ボタンを押した時にも、よりオーバーにポヨらせてみましたw

この細かい動きで質感を演出するのもいいですね^^

勉強になります!

 

 

7/14追記

CSS部分にtransition:0.2sを追加しました。(コード表記にも反映)
これにより、泡の動きが滑らかになりました^^

https://little-strange.hatenablog.com/entry/2020/07/13/070000

と同じ変更です。

 

 

ってなとこで、今回はこのへんで!

次回もまた、よろしくお願いします^^