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


HSPTV!掲示板


未解決 解決 停止 削除要請

2023
1015
nennneko5787テトリスのスーパーローテーションシステムの実装3解決


nennneko5787

リンク

2023/10/15(Sun) 18:28:14|NO.100252

うまくいかないのです。

#module #deffunc SimDel array v1, int ind repeat length(v1)-ind-1,ind v1(cnt) = v1(cnt+1) loop v1(length(v1)-1) = -1 return #global // シンプルテトリス ★ 操作方法 : 十字キーで移動、上キーで瞬間落下、スペースキーやCtrlキーなどで回転します。 //------------------------------------------------------------------------------------------------------------ #define size 32 //ブロックサイズ #define sx 10 //マップサイズX #define sy 20 //マップサイズY //ブロックの形状を定義。中心位置からブロックの生える位置X,Yを定義していく bls( 0)= -1,0, -2,0, 1,0 //縦棒(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)= 1,0, -1,0, -1,-1 //エル字     3つブロックを生やしています bls(30)= 1,0, -1,0, 1,-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*3,size*sy //スクリーン初期化 sdim map,sx,sy //マップの状態を書き込む変数(横方向sxがインデックス、縦方向syが配列 として初期化) dim minos,7 dim nextmino,5 minos = 0,1,2,3,4,5,6 holdingmino = -1 ishold = 0 randomize repeat 5 _m = 0 repeat length(minos) if minos(cnt) == -1{ break }else{ _m += 1 } loop if _m == 0{ minos = 0,1,2,3,4,5,6 repeat length(minos) if minos(cnt) == -1{ break }else{ _m += 1 } loop } px=sx/2*size: py=size: myID=rnd(_m) //プレイヤーの初期座標と新しいブロックIDを設定 repeat length(nextmino)-1 nextmino(cnt) = nextmino(cnt+1) loop nextmino(5) = minos(myID) SimDel minos,myID myID = nextmino(cnt) loop 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:else{ if rakkatimer<=0{ gosub *mapWrite //高速落下。移動できればY座標を移動先に設定し、着地したらマップに操作中のブロックを書き込む。 }else{ rakkatimer -= 2 } } if ky&2048:{ //ブロック回転 _oldmyRot = myRot myRot=(myRot+1)\4:gosub *getBlock //回転した状態のブロックをblockの配列に取得 prm=px,py:gosub *hitChk:if ans=0{ //回転できなければスーパーローテーションシステム発動!! gosub *superrotationsystem prm=px,py:gosub *hitChk:if ans=0{ myRot=(myRot+3)\4:gosub *getBlock } } } if ky&4096:{ //ブロック回転 _oldmyRot = myRot myRot=(myRot+3)\4:gosub *getBlock //回転した状態のブロックをblockの配列に取得 prm=px,py:gosub *hitChk:if ans=0{ //回転できなければスーパーローテーションシステム発動!! gosub *superrotationsystem prm=px,py:gosub *hitChk:if ans=0{ myRot=(myRot+1)\4:gosub *getBlock } } } if ky&8192:{ //ホールド if ishold == 0{ ishold = 1 if holdingmino == -1{ holdingmino = myID gosub *release }else{ _old = holdingmino holdingmino = myID myID = _old gosub *getBlock } } } prm=px,py+1:gosub *hitChk:if ans:py=prm(1):else{ if rakkatimer<=0{ gosub *mapWrite //自然落下。移動できればY座標を移動先に設定し、着地したらマップに操作中のブロックを書き込む。 }else{ rakkatimer -= 1 } } //★落下予測位置の取得と瞬間落下の処理 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 (1000/60) //画面更新とウェイト 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 //★新しいブロックをリリースする処理 _m = 0 repeat length(minos) if minos(cnt) == -1{ break }else{ _m += 1 } loop if _m == 0{ minos = 0,1,2,3,4,5,6 repeat length(minos) if minos(cnt) == -1{ break }else{ _m += 1 } loop } px=sx/2*size: py=size: myID=rnd(_m) //プレイヤーの初期座標と新しいブロックIDを設定 repeat length(nextmino)-1 nextmino(cnt) = nextmino(cnt+1) loop nextmino(5) = minos(myID) SimDel minos,myID myID = nextmino(cnt) title str(nextmino(0))+","+str(nextmino(1))+","+str(nextmino(2))+","+str(nextmino(3))+","+str(nextmino(4)) myRot = 0 gosub *getBlock //自分のブロック配列をblockに取得 yosoku=-1,0 //落下予測位置X,Y(-1だと予測位置不明を意味する) rakkatimer = 120 ishold = 0 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 *superrotationsystem if (myRot == 1){ px += 32*1 gosub *getBlock prm=px,py:gosub *hitChk:if ans=0{ py -= 32*1 gosub *getBlock prm=px,py:gosub *hitChk:if ans=0{ px -= 32*1 py += 32*3 gosub *getBlock prm=px,py:gosub *hitChk:if ans=0{ px -= 32*1 gosub *getBlock } } } return } if (myRot == 3){ px += 32*1 gosub *getBlock prm=px,py:gosub *hitChk:if ans=0{ py += 32*1 gosub *getBlock prm=px,py:gosub *hitChk:if ans=0{ px += 32*1 py += 32*3 gosub *getBlock prm=px,py:gosub *hitChk:if ans=0{ px += 32*1 gosub *getBlock } } } return } if (myRot == 2){ px -= 32*1 gosub *getBlock prm=px,py:gosub *hitChk:if ans=0{ py += 32*1 gosub *getBlock prm=px,py:gosub *hitChk:if ans=0{ px += 32*1 py -= 32*3 gosub *getBlock prm=px,py:gosub *hitChk:if ans=0{ px -= 32*1 gosub *getBlock } } } return } if (myRot == 0){ px -= 32*2 gosub *getBlock prm=px,py:gosub *hitChk:if ans=0{ py += 32*1 gosub *getBlock prm=px,py:gosub *hitChk:if ans=0{ px += 32*2 py -= 32*3 gosub *getBlock prm=px,py:gosub *hitChk:if ans=0{ px -= 32*1 gosub *getBlock } } } return } return



この記事に返信する


名無し

リンク

2023/10/15(Sun) 19:46:53|NO.100254

回転が出来ない原因は
>>if ky&2048:{
>>if ky&4096:{
キー入力判定しているこの二つの値が間違ってるからですね。
スペースキーとCTRLキーなら16と64になるはずなので。現状の2048と4096はZとXです。
なのでZとXキー入力で回転は出来ました。

(バッファオーバーフローが起きたりブロックが消えたりするので他に問題は起きてそうですが)



名無し

リンク

2023/10/15(Sun) 20:33:37|NO.100256

軽くではあるけど折角調べたのでメモ
・バッファオーバーフローは150行目で発生する
→変数txがマイナス値になるのが原因
 →ブロックが画面外に行った上で更に回転させると変数prm(か変数px)がどんどん変化してく
 →左回転だと数値は増える。右回転は減る。
 →右回転を繰り返し、マイナス値になるまで減らすとオーバーフローになる
 →そもそもブロックが画面外に退場するのが問題

という事で、十字キーの左右の様に画面端の判定を回転時にも入れれば解決しそう。
後、直線4マスの棒ブロックに限って、ブロックが右端や左端になくても、
最下段で回転しただけで消え去るので、床部分に対しての対応も入れる必要ありっぽい。
というか、回転時のブロックの座標計算が間違ってる可能性もある。
(どこがその部分の処理なのかちょっと判断付かず分からないけど)



nennneko5787

リンク

2023/10/16(Mon) 16:14:16|NO.100267

自己解決いたしました。
これでDT砲組めますね
https://i.imgur.com/D5qWWDv.mp4



記事削除

記事NO.パスワード
(質問が解決したスレッドは他の利用者に活用してもらうため、削除しないようお願いします)

NO.100252への返信

マスコット

好きなマスコットを選んでください。

名前

e-mail
HOME
  1. 初めて利用する方は、HSP3掲示板の使い方をお読みください。
  2. 不要部分の多い長いスクリプトの投稿は ご遠慮ください。
  3. 書き込みは自動改行されません。適度に改行を入れてください。
  4. スクリプトは小文字の<pre>〜</pre>で囲むと見やすく表示できます。

削除用パスワード

解決したら質問者本人がここをチェックしてください。

エラー発生時、再送信すると二重送信になることがあります。
回答が得られたら、お礼書き込み時に[解決]チェックしてください。
SPAM防止のためURLから始まる文章は投稿できません。
SPAM防止のため英文字のみの本文を投稿することはできません。

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