HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2020
0308
きょうテトリスのゲームオーバーについて5解決


きょう

リンク

2020/3/8(Sun) 21:24:22|NO.89657

https://hsp.tv/play/pforum.php?mode=pastwch&num=85911
ここに載っている文章を使ってゲームオーバーの処理をしたいのですが分かりません。どなたか教えていただけますでしょうか。
#define size 32 //ブロックサイズ
#define sx 10 //マップサイズX
#define sy 20 //マップサイズY

//ブロックの形状を定義。中心位置からブロックの生える位置X,Yを定義していく
bls( 0)= 0,-1, 0,-2, 0,1 //縦棒(1マス上、2マス上、1マス下に生えてる …という具合。)
bls( 6)= 0,-1, 1,-1, 1,0 //正方形(上に1つ、右上に1つ、右に1つ生えている これで正方形!)
bls(12)= -1,0, 0,-1, 1,-1 //右階段
bls(18)= 1,0, 0,-1, -1,-1 //左階段   ↑のルールで全ての形状は中心から
bls(24)= 0,1, 1,1, 0,-1 //エル字     3つブロックを生やしています
bls(30)= 0,1, -1,1, 0,-1 //逆エル字    全部定義していきましょう…
bls(36)= -1,0, 1,0, 0,1 //T字

//%1の配列変数(*getBlockで取得される)のブロックをカレントポジションに描画するマクロを定義
//上のbls配列と同じようなルールで変数%1の配列にブロックの形状が4つ分記録されているものとする。(配列6,7は中心座標なので常に0)
//例えばT字型ならblock=-1,0, 1,0, 0,1, 0,0 //1マス左、1マス右、1マス下、中心 の4箇所にブロックがある。
//この変数を%1に指定することで、blockDrawマクロはその形状をカレントポジションに描画する。
#define blockDraw(%1) repeat 4: grect ginfo_cx+%1(cnt*2)*size+size/2, ginfo_cy+%1(cnt*2+1)*size-size/2: loop

screen 0,size*sx,size*sy //スクリーン初期化
sdim map,sx,sy //マップの状態を書き込む変数(横方向sxがインデックス、縦方向syが配列 として初期化)
gosub *release //新しいブロックを要求

*main //メインループ
//★通常の移動処理
stick ky,13 //キーの状態を取得
if ky=1 | ky=4:ren++:else:ren=0 //横キーの連続入力判定。↓の左右移動の判定に使う。
if ky=1 & (ren=1 | ren>8):prm=px-size,py:gosub *hitChk:if ans:px=prm //左移動チェック。移動できればX座標を移動先に設定。
if ky=4 & (ren=1 | ren>8):prm=px+size,py:gosub *hitChk:if ans:px=prm //右移動チェック。移動できればX座標を移動先に設定。
if ky=8:prm=px,py+size:gosub *hitChk:if ans:py=prm(1):else:gosub *mapWrite //高速落下。移動できればY座標を移動先に設定し、着地したらマップにブロックを書き込む。
if ky>=16:{ //十字キー以外のキーが押されたらブロック回転
myRot=(myRot+1)\4:gosub *getBlock //回転した状態のブロックをblockの配列に取得
prm=px,py:gosub *hitChk:if ans=0:myRot=(myRot+3)\4:gosub *getBlock //回転できなければブロックを回転前の状態に戻す
}
prm=px,py+1:gosub *hitChk:if ans:py=prm(1):else:gosub *mapWrite //自然落下。移動できればY座標を移動先に設定し、着地したらマップに操作中のブロックを書き込む。

//★落下予測位置の取得と瞬間落下の処理
repeat sy-py/size+1,py/size //現在位置からの下に向けてチェックするループ処理
prm=px,cnt*size:gosub *hitChk:if ans=0:yosoku=prm,prm(1)-1:break //障害物にぶつかったらその1ドット上が落下予測位置。
loop
if ky=2:if yosoku>-1:px=yosoku:py=yosoku(1):gosub *mapWrite //瞬間落下

//★描画処理
redraw 0:color:boxf //画面更新OFF、背景クリア
gmode 0,size-2,size-2 //描画するブロックのサイズを設定
repeat sx:tx=cnt:repeat sy:ty=cnt //地形をmapの配列を参照して描画
if peek(map(ty),tx):hsvcolor (peek(map(ty),tx)-1)*191/7,160,255:else:color 24,24,24 //ブロックがあればブロックの色設定。無ければグレーに設定。
grect tx*size+size/2,ty*size+size/2 //地形ブロック描画
loop:loop
hsvcolor myID*191/7,100,255:pos px,py:blockDraw block //現在操作中のブロック描画
if yosoku>-1:gmode 5,size-2,size-2,64:pos yosoku,yosoku(1)+1:blockDraw block //予測座標がわかっていればそこに薄くブロック描画
redraw 1:await 30 //画面更新とウェイト
goto *main

*mapWrite //★マップ(map配列)に現在操作中のブロック(block配列)を書き込む処理
tx=px/size:ty=py/size //書き込むX,Y座標をtx,tyに代入。
repeat 4 //4つのブロックをループで書き込む。
if ty+block(cnt*2+1)<0:continue //もしY座標がフィールドからはみ出ていたら描画しない
poke map(ty+block(cnt*2+1)),tx+block(cnt*2),myID+1 //mapの配列に地形を書き込み!
loop
repeat sy:ty=cnt:tmp=0 //★ブロックの消滅チェックをする。ty=現在調査中の横列。tmp=その横列のブロックの数
repeat sx //現在調査中の横列をX方向にループでブロックが存在するかチェック
if peek(map(ty),cnt):tmp++ //ブロックが存在したらtmp+1
loop
if tmp=sx:{ //もしその横列のブロック数はフィールドのXサイズと一致した場合、その列は消滅
repeat ty //消滅した列まで1つ上の列から地形情報をコピーする
memcpy map(ty-cnt),map(ty-cnt-1),sx,0,0 //地形情報を上の列からコピー
loop
memset map(0),0,sx //最上段はクリアする
}
loop
gosub *release //新しいブロックがリリースする
return

*hitChk //★prm,prm(1)のX,Y座標にblockの配列に記録されているブロックが存在できるかチェックし、存在できればans=1にする処理
ans=1 //移動可能フラグ
repeat 4 //ブロック4つ分判定
tx=block(cnt*2)+prm/size:ty=block(cnt*2+1)+prm(1)/size //チェックするブロックの座標をtx,tyに代入
if tx<0 | tx>=sx | ty>=sy:ans=0:break //場外・移動不可能。ans=0
if ty>=0:if peek(map(ty),tx):ans=0:break //ブロックに重なる・移動不可能。ans=0
loop
return

*release //★新しいブロックをリリースする処理
px=sx/2*size: py=size: myID=rnd(7) //プレイヤーの初期座標と新しいブロックIDを設定
gosub *getBlock //自分のブロック配列をblockに取得
yosoku=-1,0 //落下予測位置X,Y(-1だと予測位置不明を意味する)
return

*getBlock //★myIDの形状のブロックをmyRot回回転させた場合の形状をblockの配列に代入する処理(block配列の仕様はblockDrawマクロの説明文を参照!)
repeat 3 //ブロック形状を記録したbln配列は各形状ごとに3ブロック分のブロック位置を記録してある
if myRot=1: block(cnt*2)= -bls(myID*6+cnt*2+1), bls(myID*6+cnt*2): continue //右に90度回転してる
if myRot=2: block(cnt*2)= -bls(myID*6+cnt*2), -bls(myID*6+cnt*2+1): continue //180度回転している
if myRot=3: block(cnt*2)= bls(myID*6+cnt*2+1), -bls(myID*6+cnt*2): continue //左に90度回転している
block(cnt*2)= bls(myID*6+cnt*2), bls(myID*6+cnt*2+1) //回転していない
loop
block(6)=0,0 //中心には必ずブロックがある
return



この記事に返信する


あらや

リンク

2020/3/9(Mon) 18:26:48|NO.89673

どこでも良いのですが、
新しいブロックをリリースした時に*hitChkで移動可能か調べて
移動不可能な時にはゲームオーバーとすれば良いのではないでしょうか。

一例:

*getBlock //★myIDの形状のブロックをmyRot回回転させた場合の形状をblockの配列に代入する処理(block配列の仕様はblockDrawマクロの説明文を参照!) repeat 3 //ブロック形状を記録したbln配列は各形状ごとに3ブロック分のブロック位置を記録してある if myRot=1: block(cnt*2)= -bls(myID*6+cnt*2+1), bls(myID*6+cnt*2): continue //右に90度回転してる if myRot=2: block(cnt*2)= -bls(myID*6+cnt*2), -bls(myID*6+cnt*2+1): continue //180度回転している if myRot=3: block(cnt*2)= bls(myID*6+cnt*2+1), -bls(myID*6+cnt*2): continue //左に90度回転している block(cnt*2)= bls(myID*6+cnt*2), bls(myID*6+cnt*2+1) //回転していない loop block(6)=0,0 //中心には必ずブロックがある ////////////////////追加////////////////////////// prm=px,py gosub *hitChk:if ans=0:goto *gameover ////////////////////////////////////////////////// return ////////////////////追加////////////////////////// *gameover dialog "ゲームオーバー", 0, "GameOver" stop



きょう

リンク

2020/3/12(Thu) 10:00:58|NO.89689

おー!それ良いですね!一回やってみます。



きょう

リンク

2020/3/12(Thu) 11:02:18|NO.89690

すごい!できました!ありがとうございます!



Drip

リンク

2020/3/12(Thu) 16:38:14|NO.89695

きょうさんこんにちは。Dripです。

あらやさんの方法ですとブロックの回転に失敗した瞬間にゲームオーバーする上に
gosub中に他所へgotoするご法度をおかしています;
試しに壁に密着しながらブロックを回転してみてください。いきなり終わってしまいます。

ゲームオーバー判定する場所を変えたほうが良いですね。注意されてください。



あらや

リンク

2020/3/12(Thu) 18:27:19|NO.89696

すみません、雑な所が色々ありましたね

>gosub中に他所へgotoするご法度をおかしています;
実はこれはわかっていたのですが、ほかの場所に入れると分かりにくくなるかと思い
一番分かりやすい最終行に追加するという形を取らせていただきました。


*main //メインループ //★通常の移動処理 stick ky,13 //キーの状態を取得 if ky=1 | ky=4:ren++:else:ren=0 //横キーの連続入力判定。↓の左右移動の判定に使う。 if ky=1 & (ren=1 | ren>8):prm=px-size,py:gosub *hitChk:if ans:px=prm //左移動チェック。移動できればX座標を移動先に設定。 if ky=4 & (ren=1 | ren>8):prm=px+size,py:gosub *hitChk:if ans:px=prm //右移動チェック。移動できればX座標を移動先に設定。 if ky=8:prm=px,py+size:gosub *hitChk:if ans:py=prm(1):else:gosub *mapWrite //高速落下。移動できればY座標を移動先に設定し、着地したらマップにブロックを書き込む。 if ky>=16:{ //十字キー以外のキーが押されたらブロック回転 myRot=(myRot+1)\4:gosub *getBlock //回転した状態のブロックをblockの配列に取得 prm=px,py:gosub *hitChk:if ans=0:myRot=(myRot+3)\4:gosub *getBlock //回転できなければブロックを回転前の状態に戻す } prm=px,py+1:gosub *hitChk:if ans:py=prm(1):else:gosub *mapWrite //自然落下。移動できればY座標を移動先に設定し、着地したらマップに操作中のブロックを書き込む。 gosub *hitChk:if ans=0:goto *gameover

>gosub *release //新しいブロックがリリースする
これがあるのが『*mapWrite』の中なので
メインループの中で『*mapWrite』系の処理が終わった後に
追加する形の方が不具合が少ないと思います。



ONION software Copyright 1997-2023(c) All rights reserved.