|
|
|
2018/12/1(Sat) 15:32:03|NO.85911
とりあえずここまで作ったのですが、
ブロックの配列データをどう取り出してどう動かせばいいかわからないです。
とりあえずテトリスのアルゴリズムのサイトは一通り見たつもりなんですがいまいちわかりませんでした。
#define WINDX 500
#define WINDY 600
randomize //乱数をかぶらず出すモジュール
#module
#deffunc rndnum array a
max=length(a)
repeat max
b=rnd(cnt+1)
a(cnt)=a(b)
a(b)=cnt
loop
return
#global
*sysinit //システム設定
screen 0,WINDX,WINDY; //ウィンドウ
buffer 1,WINDX,WINDY; //キャッシュ
*selo
mmload "sound/start.wav",0,0;
mmload "sound/BGM.wav",1,1;
mmload "sound/move.wav",2,0;
*imglo //画像読み込み
buffer 100,25,25;
gsel 100;
picload "img/n.png",1;
buffer 101,25,25;
gsel 101;
picload "img/i.png",1;
buffer 102,25,25;
gsel 102;
picload "img/t.png",1;
buffer 103,25,25;
gsel 103;
picload "img/o.png",1;
buffer 104,25,25;
gsel 104;
picload "img/j.png",1;
buffer 105,25,25;
gsel 105;
picload "img/l.png",1;
buffer 106,25,25;
gsel 106;
picload "img/z.png",1;
buffer 107,25,25;
gsel 107;
picload "img/s.png",1;
buffer 108,25,25;
gsel 108;
picload "img/x.png",1;
gsel 0; //画像リセット
*init //設定
ransu=0; //乱数
Grav=1; //G
patuX=0; //パーツ座標
patuY=0;
kidou=0; //ゲーム開始
Gcou=0; //Gカウンター移動
Gcouto=0;
Gcouflm=0;
SPcou=0; //ゲームカウンター
SPcouto=0;
SPcouflm=0;
dim NXhai,7; //next用配列
NXnow=7;
moti=0; //ブロック持ってる判定
nowmoti=0; //今持ってるブロック
nowlote=0; //今何コマ目
Lk=0; //キー入力
Rk=0;
Dk=0;
Uk=0;
Lr=0;
Rr=0;
nisin=""; //二進数表示
//X軸→,Y軸↑
dim feld1p,12,21;
Yin=0; //壁つけ
while(Yin!=21)
/* { */
feld1p(0,Yin)=8;
feld1p(11,Yin)=8;
Yin=Yin+1;
/* } */wend;
Xin=0; //底付け
while(Xin!=12)
/* { */
feld1p(Xin,20)=8;
Xin=Xin+1;
/* } */wend;
//ブロック用
//x,y,ページ数
//i
dim ibl,4,4,4;
ibl(0,0,0)=0,0,0,0;
ibl(0,1,0)=1,1,1,1;
ibl(0,2,0)=0,0,0,0;
ibl(0,3,0)=0,0,0,0;
ibl(0,0,1)=0,0,1,0;
ibl(0,1,1)=0,0,1,0;
ibl(0,2,1)=0,0,1,0;
ibl(0,3,1)=0,0,1,0;
ibl(0,0,2)=0,0,0,0;
ibl(0,1,2)=0,0,0,0;
ibl(0,2,2)=1,1,1,1;
ibl(0,3,2)=0,0,0,0;
ibl(0,0,3)=0,1,0,0;
ibl(0,1,3)=0,1,0,0;
ibl(0,2,3)=0,1,0,0;
ibl(0,3,3)=0,1,0,0;
//t
dim tbl,4,4,4;
tbl(0,0,0)=0,0,1,0;
tbl(0,1,0)=0,1,1,1;
tbl(0,2,0)=0,0,0,0;
tbl(0,3,0)=0,0,0,0;
tbl(0,0,1)=0,0,1,0;
tbl(0,1,1)=0,0,1,1;
tbl(0,2,1)=0,0,1,0;
tbl(0,3,1)=0,0,0,0;
tbl(0,0,2)=0,0,0,0;
tbl(0,1,2)=0,1,1,1;
tbl(0,2,2)=0,0,1,0;
tbl(0,3,2)=0,0,0,0;
tbl(0,0,3)=0,0,1,0;
tbl(0,1,3)=0,1,1,0;
tbl(0,2,3)=0,0,1,0;
tbl(0,3,3)=0,0,0,0;
//o
dim obl,4,4,4;
obl(0,0,0)=0,0,0,0;
obl(0,1,0)=0,1,1,0;
obl(0,2,0)=0,1,1,0;
obl(0,3,0)=0,0,0,0;
obl(0,0,1)=0,0,0,0;
obl(0,1,1)=0,1,1,0;
obl(0,2,1)=0,1,1,0;
obl(0,3,1)=0,0,0,0;
obl(0,0,2)=0,0,0,0;
obl(0,1,2)=0,1,1,0;
obl(0,2,2)=0,1,1,0;
obl(0,3,2)=0,0,0,0;
obl(0,0,3)=0,0,0,0;
obl(0,1,3)=0,1,1,0;
obl(0,2,3)=0,1,1,0;
obl(0,3,3)=0,0,0,0;
//j
dim jbl,4,4,4;
jbl(0,0,0)=0,1,0,0;
jbl(0,1,0)=0,1,1,1;
jbl(0,2,0)=0,0,0,0;
jbl(0,3,0)=0,0,0,0;
jbl(0,0,1)=0,0,1,1;
jbl(0,1,1)=0,0,1,0;
jbl(0,2,1)=0,0,1,0;
jbl(0,3,1)=0,0,0,0;
jbl(0,0,2)=0,0,0,0;
jbl(0,1,2)=0,1,1,1;
jbl(0,2,2)=0,0,0,1;
jbl(0,3,2)=0,0,0,0;
jbl(0,0,3)=0,0,1,0;
jbl(0,1,3)=0,0,1,0;
jbl(0,2,3)=0,1,1,0;
jbl(0,3,3)=0,0,0,0;
//l
dim lbl,4,4,4;
lbl(0,0,0)=0,0,0,1;
lbl(0,1,0)=0,1,1,1;
lbl(0,2,0)=0,0,0,0;
lbl(0,3,0)=0,0,0,0;
lbl(0,0,1)=0,0,1,0;
lbl(0,1,1)=0,0,1,0;
lbl(0,2,1)=0,0,1,1;
lbl(0,3,1)=0,0,0,0;
lbl(0,0,2)=0,0,0,0;
lbl(0,1,2)=0,1,1,1;
lbl(0,2,2)=0,1,0,0;
lbl(0,3,2)=0,0,0,0;
lbl(0,0,3)=0,1,1,0;
lbl(0,1,3)=0,0,1,0;
lbl(0,2,3)=0,0,1,0;
lbl(0,3,3)=0,0,0,0;
//z
dim zbl,4,4,4;
zbl(0,0,0)=0,1,1,0;
zbl(0,1,0)=0,0,1,1;
zbl(0,2,0)=0,0,0,0;
zbl(0,3,0)=0,0,0,0;
zbl(0,0,1)=0,0,0,1;
zbl(0,1,1)=0,0,1,1;
zbl(0,2,1)=0,0,1,0;
zbl(0,3,1)=0,0,0,0;
zbl(0,0,2)=0,0,0,0;
zbl(0,1,2)=0,1,1,0;
zbl(0,2,2)=0,0,1,1;
zbl(0,3,2)=0,0,0,0;
zbl(0,0,3)=0,0,1,0;
zbl(0,1,3)=0,1,1,0;
zbl(0,2,3)=0,1,0,0;
zbl(0,3,3)=0,0,0,0;
//s
dim sbl,4,4,4;
sbl(0,0,0)=0,0,1,1;
sbl(0,1,0)=0,1,1,0;
sbl(0,2,0)=0,0,0,0;
sbl(0,3,0)=0,0,0,0;
sbl(0,0,1)=0,0,1,0;
sbl(0,1,1)=0,0,1,1;
sbl(0,2,1)=0,0,0,1;
sbl(0,3,1)=0,0,0,0;
sbl(0,0,2)=0,0,0,0;
sbl(0,1,2)=0,0,1,1;
sbl(0,2,2)=0,1,1,0;
sbl(0,3,2)=0,0,0,0;
sbl(0,0,3)=0,1,0,0;
sbl(0,1,3)=0,1,1,0;
sbl(0,2,3)=0,0,1,0;
sbl(0,3,3)=0,0,0,0;
*main //メイン
gosub *keyload;
gosub *syokai;
gosub *rupu;
gosub *SPloop;
gosub *Glist;
await 17-(Counter\3==0);//画面更新系命令
gosub *relo;
goto *main; //メインに戻す
*rupu
if kidou==1{
patuY=patuY+1;
if(moti==0){ //持ってないときネク要求
gosub *nextGET;
moti=1;
}
}
return;
*SPloop
if(SPcou==1){ //ループカウント
if(SPcouto==SPcouflm){
SPcou=0;
SPcouflm=0;
}else{
SPcouflm=SPcouflm+1;
}
}
return;
if(SPcou==0){ //ループカウントの欲張りセット
}
SPcou=1; //カウント欲張りセット
SPcouto=1;
gosub *SPloop;
*nextGET //ブロック呼び
if(NXnow==7){
NXnow=0;
randomize;
rndnum NXhai;
}
nowmoti=NXhai(NXnow);
NXnow=NXnow+1;
nowmoti=nowmoti+1;
return
*Glist //G関連呼び
if(kidou==0){
gosub *Gup;
gosub *Gdn;
gosub *Gloop;
}
return;
*sutato
kidou=1;
mmplay 1;
mmplay 0;
return;
*Gloop
if(Gcou==1){ //ループカウント
if(Gcouto==Gcouflm){
Gcou=0;
Gcouflm=0;
}else{
Gcouflm=Gcouflm+1;
}
}
return;
*Gup
if(Gcou==0){
if(Rk==1){
if(Grv<20){
mmplay 2;
Grv=Grv+1;
Gcouto=5; //G移動速度
Gcou=1;
}
}
}
return;
*Gdn
if(Gcou==0){
if(Lk==1){
if(Grv>1){
mmplay 2;
Grv=Grv-1;
Gcouto=5; //G移動速度
Gcou=1;
}
}
}
return;
*syokai
if kidou==1{
return;
}else{
if Lr==1{
gosub *sutato;
}else:if Rr==1{
gosub *sutato;
}else:if Lk==1{
gosub *Gdn;
}
}
return;
*keyload
getkey Lk,37;
getkey Rk,39;
getkey Dk,40;
getkey Uk,38;
getkey Lr,90;
getkey Rr,88;
return;
*relo //画像リロード
//X軸→,Y軸↑
//0 無:1 I:2 T:3 O:4 J:5 L:6 Z:7 S:8 壁
redraw 0; //更新停止
gsel 1; //キャッッシュに書き込み
color 255,255,255:boxf; //画面けし
color 0,0,0; //色リセット
pos 300,0; //文字出し
mes ""+Lk+""+Rk+""+Dk+""+Uk+""+Lr+""+Rr+""+patuY+"jyou";
mes ""+Grv+"G";
mes nowmoti
Yre=0;
Xre=0;
while(Yre!=21)
/* { */
Xre=0;
while(Xre!=12);
/* { */
pos (Xre*25),(Yre*25);
if(feld1p(Xre,Yre)==0){
gcopy 100, 0, 0, 32, 32
}else:if(feld1p(Xre,Yre)==1){
gcopy 101, 0, 0, 32, 32
}else:if(feld1p(Xre,Yre)==2){
gcopy 102, 0, 0, 32, 32
}else:if(feld1p(Xre,Yre)==3){
gcopy 103, 0, 0, 32, 32
}else:if(feld1p(Xre,Yre)==4){
gcopy 104, 0, 0, 32, 32
}else:if(feld1p(Xre,Yre)==5){
gcopy 105, 0, 0, 32, 32
}else:if(feld1p(Xre,Yre)==6){
gcopy 106, 0, 0, 32, 32
}else:if(feld1p(Xre,Yre)==7){
gcopy 107, 0, 0, 32, 32
}else:if(feld1p(Xre,Yre)==8){
gcopy 108, 0, 0, 32, 32
};
Xre==Xre+1;
/* } */wend ;
Yre=Yre+1;
/* } */wend ;
gsel 0; //画面へ変更
gcopy 1,0,0,WINDX,WINDY; //キャッシュから画面へコピー
redraw 1; //画面更新
return;
| |
|
2018/12/2(Sun) 15:19:08|NO.85919
ソース見ましたがテトリスがどうなってるのがわからなかったです
テトリスのみで参考はないですか?
|
|
2018/12/2(Sun) 22:07:09|NO.85927
Dripです。
たこさん、こんにちは。
ご提示くださったスクリプトは回答者にとって画像ファイルがどういうものかわからないので、
たこさんがどのようにテトリスを実装しようとしているのかちょっと判り辛いですね。
またテトリスの動かし方とのことですが、どういった処理ができずに困っているのかわからないので、
こちらの予想で回答せざるを得ないのですが…ご提示されたスクリプトには消滅処理がないようですが
判定と消滅だけでしたら以下のようなサンプルが参考になりませんか?
//基本的なテトリスの判定処理のサンプル
xsize=10 //マップXサイズ
ysize=20 //マップYサイズ
*go //初期化
cls:objsize 100,30:objmode 2
dim fld,xsize,ysize //フィールド配列X,Y。1ならブロックがある
repeat 400:fld(rnd(xsize),rnd(ysize))=1:loop //適当にブロックを置く
gosub *draw //マップ再描画
pos 10,ysize*10+5:button "判定",*hantei //判定ボタン生成
stop
*hantei //消す列の判定だけする
repeat ysize:y=cnt:kazu=0 //縦方向に判定していく。kazu=その列の横に何個ブロックがあったか?
repeat xsize:x=cnt //横方向にブロックを数える
if fld(x,y):kazu++ //ブロックがあればkazu+1
loop
if kazu=xsize:color 255:line 0,y*10,xsize*10,y*10+10 //ブロック数が横幅と一致した。消滅する列に斜線を引く
loop
pos 10,ysize*10+40:button "消去",*del //判定+消去を行うボタンを生成
stop
*del //判定+消去を同時に行う
repeat ysize:y=cnt:kazu=0 //縦方向に判定していく。kazu=その列の横に何個ブロックがあったか?
repeat xsize:x=cnt //横方向にブロックを数える
if fld(x,y):kazu++ //ブロックがあればkazu+1
loop
if kazu=xsize:{ //横方向にブロックが満たされていたので消滅処理開始
repeat y:t=y-cnt //消えた列から順に上の列をコピーする
repeat xsize //ブロックを上の列から1つずつコピーする
fld(cnt,t)=fld(cnt,t-1)
loop
loop
repeat xsize //一番上の列は必ずクリアされる
fld(cnt,0)=0
loop
}
loop
gosub *draw //マップ再描画
pos 10,ysize*10+80:button "再配置",*go
stop
*draw //マップを描画する
repeat xsize:x=cnt:repeat ysize:y=cnt //フィールド描画
if fld(x,y):color:else:color 255,255,255 //ブロックの色分け
boxf x*10,y*10,x*10+10,y*10+10 //ブロック描画
loop:loop
return
実はテトリスも考え方を工夫すれば100行程度で基本的な動作を作ることができます。
以下はそのサンプルです。上記のサンプルの考え方もこの中に組み込まれていますよ。
いきなり全てを理解できないかもしれませんが、部分的に参考にしてみたり、
色々工夫しながら頑張ってみてください。
// シンプルテトリス ★ 操作方法 : 十字キーで移動、上キーで瞬間落下、スペースキーやCtrlキーなどで回転します。
//------------------------------------------------------------------------------------------------------------
#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
| |
|
2018/12/3(Mon) 16:01:15|NO.85928
サンプルありがとうございます。
こういう作り方があるんだなーとは思いました。
このソースでは中心から考える形になっているんですが、
僕が質問したかったのは配列で定義したブロックをどうフィールド用の配列と比較していいかという部分です。
僕が見たテトリスのアルゴリズムのサイトでは
1 配列でブロックを定義する。
2 それを回転する枚数分用意する。
3 フィールド用の配列も用意する。
4 回転する場合は次のコマに移る。
5 そのブロックの配列がフィールド上のブロックと被ると回転しない。
6 ブロックの配列をフィールドの配列にコピー
となってたんですが、
5と6で使う「配列同士の比較」「配列から配列へコピー」をどうしていいかがわからないです。
後画像ファイルは全部25×25の色違いのブロック用画像です。
Nってファイルは何もない空間用のマス目でXっていうファイルは外側の壁用のマス目です。
完全に余談ですがこれはテトリスを作るというより、
テトリス武闘外伝っていうゲームのRENSAモードが再現したくて作り始めました。
|
|
2018/12/3(Mon) 20:49:51|NO.85934
たこさん、こんにちは。
ご説明有難うございます。
それでは今回は「二次元数値型配列」の「配列同士の比較」と「配列から配列へのコピー」
のみに着眼した説明となります。今回はマップ配列と自分の操作するブロック配列に、
たこさんが主に利用されている「二次元数値型配列」のみを使用した形で説明します。
以下のサンプルではテトリスの「ブロック配置」に関する処理のみをまとめています。
消滅判定や回転処理などは一切ありません。左右・下キーによる移動のみ可能です。
横の移動に失敗した場合は移動を中止するだけ、
(この処理では ご質問の[5]、配列同士の比較(*hitChk)をしています)
下の移動に失敗した場合は自分のブロック配列をマップ配列に書き込んでいます。
(この処理では ご質問の[6]、配列から配列へのコピー(*mapWrite)もしています)
サンプル中、これらの要点に対して★マークを振っています。そこは特に注目して観察してください。
もしこれでも理解が難しい場合は、テトリスの開発に入る前にHSPの変数の扱い方の基本や、
配列変数に関する基本的な考え方をまず勉強されることをお勧めいたします。
慣れないうちは難しいかもしれませんが、がんばってみてください。
// map(x,y) 二次元数値配列。地形情報を記録していて 1 ならブロックがある
// myBlock(x,y) 二次元数値配列。4x4マスのブロック形状を記録していて 1 ならブロックがある
//この2つの配列を比較して当たり判定をしているのは *hitChk です ■ご質問の [5]配列同士の比較です■
//myBlock の配列情報を map に書き込んでいるのは *mapWrite です ■ご質問の [6]配列から配列へのコピーです■
size=20 //ブロックのサイズ
sx=10 //マップサイズX
sy=20 //マップサイズY
dim map,sx,sy //マップを整数配列で管理する。1ならブロック有り
screen 0,sx*size,sy*size //画面初期化
gosub *newBlock //新しいブロックを要求
*main //メインループ
stick ky,15 //キーの状態を取得
if ky=1:px=px-1:gosub *hitChk:if ans=0:px=px+1 //★左に移動して障害物にぶつかったら位置を戻す
if ky=4:px=px+1:gosub *hitChk:if ans=0:px=px-1 //★右に移動して障害物にぶつかったら位置を戻す
if ky=8 | timer\20=0:{ //下キーか20フレームごとに落下する
py=py+1:gosub *hitChk //★下に移動させてヒットチェックをする
if ans=0:py=py-1:gosub *mapWrite //★障害物にぶつかったら位置を戻して、マップに書き込む
}
timer++ //フレーム数カウント
redraw 0 //描画更新OFF
gosub *mapDraw //マップを描画
gosub *myBlockDraw //自分のブロックを描画
redraw 1 //画面更新
await 50 //ウェイト
goto *main //ループ
*newBlock //新しいブロックを作成する処理
dim myBlock,4,4 //自分のブロックの配列を初期化
id=rnd(4) //ブロックの種類を確定。今回はとりあえず4種類
if id=0:myBlock(1,0)=1:myBlock(1,1)=1:myBlock(1,2)=1:myBlock(1,3)=1 //縦棒
if id=1:myBlock(0,0)=1:myBlock(1,0)=1:myBlock(1,1)=1:myBlock(2,1)=1 //階段
if id=2:myBlock(0,0)=1:myBlock(1,0)=1:myBlock(0,1)=1:myBlock(1,1)=1 //正方形
if id=3:myBlock(0,0)=1:myBlock(1,0)=1:myBlock(2,0)=1:myBlock(1,1)=1 //T字
px=sx/2-2:py=0 //自分のブロックの座標を初期化。px,pyはmyBlockの左上の座標を示す
return
*mapDraw //マップを描画する処理
repeat sx:x=cnt //横方向ループ
repeat sy:y=cnt //縦方向ループ
if map(x,y)!0:color 32,32,32:else:color 240,240,240 //地形と空間で色分け
boxf x*size+1,y*size+1,x*size+size-2,y*size+size-2 //マップを描画
loop
loop
return
*myBlockDraw //自分のブロックを描画する処理
color 255,0,0 //自分のブロックの色
repeat 4:x=cnt //横方向ループ
repeat 4:y=cnt //縦方向ループ
if myBlock(x,y)!0:{ //自分のブロック配列にブロックがあれば描画する
boxf (px+x)*size+1,(py+y)*size+1,(px+x)*size+size-2,(py+y)*size+size-2 //描画
}
loop
loop
return
//★ご質問の [5]配列同士の比較です■
*hitChk //マップ配列と自分のブロックとの当たり判定
ans=1 //移動可能フラグ
repeat 4:x=cnt //横方向ループ
repeat 4:y=cnt //縦方向ループ
if myBlock(x,y)=0:continue //自分のブロック配列にブロックがなければ判定しない
if px+x<0 | px+x>=sx | py+y>=sy:ans=0:break //画面外にはみ出ていたら移動不可能。ans=0
if map(px+x,py+y)!0:ans=0:break //マップ配列上のブロックにぶつかったら移動不可能。ans=0
loop
if ans=0:break //もう移動不能と判定されたので処理はここでおわり。
loop
return
//★ご質問の [6]配列から配列へのコピーです■
//コピーというか代入です。myBlockの空白まで「コピー」してしまうとmapの地形を破壊してしまうので、
//テトリスでは「ブロックのある場所だけ」をコピー(1を代入)する処理となります。
*mapWrite //マップに自分のブロックを書き込む処理
repeat 4:x=cnt //横方向ループ
repeat 4:y=cnt //縦方向ループ
if myBlock(x,y)!0:map(px+x,py+y)=1 //自分のブロックをマップに書き込む
loop
loop
gosub *newBlock //新しいブロックを要求
return
| |
|