|
 |
|
2014/2/22(Sat) 20:21:06|NO.60199
いまマリオやロックマンのようなゲームを作成しています。
そこでブロック崩しのサンプルをいじって作り変えていたところ
衝突判定で躓いてしましました。
どのようにすればよろしいのでしょうか?
また、マップをマップチップのようにしてスクロールして進んでいくように
していく予定です。
自分なりに考えて見たのですが、配列が足りなくなってしまうのではないかと心配しております。
現在表示されているマップチップとスクロールして新たに右に出現するブロックをどのように
処理すればいいか悩んでいます。
;
; ブロック崩し(3)
;
x1=0.0:y1=0.0 ; 画面左上の座標
x2=480.0:y2=480.0 ; 画面右下の座標
clrflag=0 ; クリアフラグ
blsize=16.0 ; ボールのサイズ
blspd=5.0 ; ボールのスピード
blx=240.0:bly=300.0 ; ボールの座標
bpx=4.0:bpy=4.0 ; XY方向のボール座標加算値
bk=0 ; ブロックを崩すフラグ(1=崩す)
mblsize=-blsize;ボール一点座標?
blhalf=blsize/2
wpx=10.0:wpy=10.0 ; ブロック1個あたりのサイズ
wx=0:wy=y2-100.0 ; ブロックの表示開始位置(左上)
blnum_x=x2/wpx
blnum_y=100.0/wpy
wsx=blnum_x:wsy=blnum_y ; ブロックの配置数(X,Y)
dim wall,wsx,wsy ; ブロックを表示するフラグ
; 0=表示、1=表示しない
screen 0,x2,y2
title "ブロック崩し"
cls 4
*main
redraw 0
gradf 0,0,x2,y2,1,0,128 ; 画面クリア
; ボール : X方向の移動
stick key,15
if key&1 :blx=blx-4.0
if key&4 :blx=blx+4.0
if blx<=x1 : blx=x1 : bpx=-bpx
if blx>=(x2-blsize) : blx=x2-blsize : bpx=-bpx
//ueキーでジャンプ
getkey key,38//ueキー
if key=1 and ジャンプ中=0{
ジャンプ中=1
キャラvy=-8.0
}
//ジャンプ中、落下中、共通する点は、地面に付いていない事。
if ジャンプ中=1{
キャラvy+=0.45//重力加速度、まあテキトーに
bly+=キャラvy
}
//着地
if tyaku=1{
ジャンプ中=0:キャラvy=0.0:tyaku=0}
; ブロックの処理
colx=wpx+bsize;ブロックの大きさ + ボールのサイズ
coly=wpy+bsize
left=0
repeat wsy//ブロックy座標
cy=cnt
y=cnt*wpy+wy//ブロックをある大きさごとに区切る?
hsvcolor cnt*10,255,255
repeat wsx//ブロックx座標
cx=cnt
x=cnt*wpx+wx//ブロックの一辺長さ+開始点 ブロックをある大きさに区切る?
if wall(cx,cy)=0 {//ブロック2次配列
; ブロックを表示
boxf x,y,x+wpx-2.0,y+wpy-2.0
i=x-blx:j=y-bly//ボール座標 - ブロック始点座標
//ボールとブロックのあたり判定
//ボールとブロック差ががボールサイズより小さい アンド
//ボールとブロック差が ボールサイズとブロックサイズが大きい
if (i<=blsize)&(j<=blsize) {
tyaku=1
bly=y-13
}
}
if wall(cx,cy)=0 & cx>30{
wall(cx,cy)=1
tyaku=0//ブロックが無いときは着地処理をしない
}
if wall(cx,cy)=1{
// i=x-blx:j=y-bly//ボール座標 - ブロック始点座標
//ボールとブロックのあたり判定
//ボールとブロック差ががボールサイズより小さい アンド
//ボールとブロック差が ボールサイズとブロックサイズが大きい
if (i<=blsize)&(j<=blsize) {
// ジャンプ中=1
tyaku=0
}
}
loop
loop
; ボールを表示
pos blx,bly:color 255,255,255
font msgothic,blsize
mes "●"
redraw 1
await 16
goto *main
*gameover
objsize 180,32
pos 150,330:button "終わり",*owari
stop
*owari
end

| |
|
2014/2/22(Sat) 20:34:40|NO.60201
補足です。
現在、右側のブロックの無い部分にボールが移動すると
ボールが消えるという状況です。
|
|
2014/2/22(Sat) 23:54:08|NO.60204
複雑な場合分けをしているようですが、"物理的に考え" れば何がカギかが見えてきます。
○キャラの足場があるかどうか
○加速度
○速度
一見複雑に見える現象も、上の3つの条件で粗方片付いてしまいます。
フラグと場合分けの嵐から開放されます。
下は参考。
//「//」ではじまる行は私が勝手に付けたコメントです。
//まことにまことに勝手ながら....、
// ■未初期化だった「ジャンプ中」フラグを「IsBallJumping」で置き換えさせてもらいました。
// ■重力加速度を「α_G」として新たに定義させてもらいました。
// ■「キャラvy」を「vy_Char」で置き換えさせてもらいました。
//各所に見られる半角スペースの省略やamazingな改行規則は、もしかしてHSPTV用のaxサイズ削減のためでしょうか?
//もしそうでしたら、私の勝手な手入れで肥大化させてしまったかもしれませんことを予め謝っておきます。
;
; ブロック崩し(3)
;
x1=0.0:y1=0.0 ; 画面左上の座標
x2=480.0:y2=480.0 ; 画面右下の座標
clrflag=0 ; クリアフラグ
#define α_G 0.45 //重力加速度
blsize=16.0 ; ボールのサイズ
blspd=5.0 ; ボールのスピード
vy_Char = 0.0 //キャラの速度のy成分
blx=240.0:bly=300.0 ; ボールの座標
bpx=4.0:bpy=4.0 ; XY方向のボール座標加算値
bk=0 ; ブロックを崩すフラグ(1=崩す)
mblsize=-blsize;ボール一点座標?
IsBallJumping = 0 //ボールの滞空フラグ(0,1)=(false,true)
blhalf=blsize/2
wpx=10.0:wpy=10.0 ; ブロック1個あたりのサイズ
wx=0:wy=y2-100.0 ; ブロックの表示開始位置(左上)
blnum_x=x2/wpx //ブロックのx方向の個数
blnum_y=100.0/wpy //〃y〃
wsx=blnum_x:wsy=blnum_y ; ブロックの配置数(X,Y)
dim wall,wsx,wsy ; ブロックを表示するフラグ //←「表示/非表示」というより、むしろ「存在する/しない」では?
; 0=表示、1=表示しない ←(※個人的には「(0,1)=(表示しない,する)」の方が本能的にしっくりくる...。(※あんまり気にしないで!))
;< ブロックの存在の設定 >
repeat 20 ;右端20列を穴にする
cnt1 = cnt
repeat wsy
wall(int(wsx)-cnt1-1,cnt) = 1
loop
loop
screen 0,x2,y2
title "ブロック崩し"
cls 4
*main
redraw 0
gradf 0,0,x2,y2,1,0,128 ; 画面クリア
; ボール : X方向の移動
stick key,15 //(=1+2+4+8)
if key&1 :blx=blx-bpx //※「±4.0」固定だったので勝手に「bpx」に置き換えました。意図が違っていたらごめんなさい。
if key&4 :blx=blx+bpx //
if blx<=x1 : blx=x1 : bpx=-bpx //←解脱しようとすると速度ベクトルが-1倍されるのは仕様?...
if blx>=(x2-blsize) : blx=x2-blsize : bpx=-bpx
//ueキーでジャンプ
getkey key,38//ueキー
if key=1 and IsBallJumping=0{
vy_Char=-8.0
bly + vy_Char ;ここで動かしておかないと、後の座標チェックで引っかかって止められる。
}
;//ジャンプ中、落下中、共通する点は、地面に付いていない事。
;if IsBallJumping=1{
;vy_Char+=α_G//重力加速度、まあテキトーに
;bly+=vy_Char
;}
//着地
;if tyaku=1{
; //tyakuは着地フラグ
;IsBallJumping=0 : vy_Char=0.0:tyaku=0}
; ブロックの処理
colx=wpx+bsize;ブロックの大きさ + ボールのサイズ
coly=wpy+bsize
left=0
//< ブロックの描画 & ボールの足場吟味 >
IsBallJumping = 1 ;フラグ初期化
repeat wsy
cy = cnt
y_check = wy + cnt*wpy
hsvcolor cnt*10,255,255
repeat wsx
cx = cnt
x_check = wx + cnt*wpx
if wall(cx,cy) = 0 { ;ブロックが存在するならば
;< 描画 >
boxf x_check,y_check ,x_check+wpx-2.0,y_check+wpy-2.0
;< 足場吟味 >
if (x_check-blhalf <= blx)&(blx <= x_check+wpx-blhalf) & (y_check-blsize <= bly)&(bly <= y_check) { //いまフォーカスしているブロックがボールの足場であるなら、ボールは接地しているとみなせる。y座標についてはすり抜け現象を防ぐための緩衝値が必要。
;if (dx <= blsize)&(dy <= blsize) {
IsBallJumping = 0
bly = y_check-blsize
}
}
loop
loop
//< 力学処理 >
;< 速度処理 >
if IsBallJumping = 0 { ;接地しているならば
vy_Char = 0.0
} else { ;接地していないならば
vy_Char + α_G
}
;< 移動処理 >
bly + vy_Char //毎回速度成分を足しているけれど、速度が0なら座標が変わらないよね...。つまり、物理的に考えれば「速度」がボールの位置を操る鍵ってこと! (※厳密には「初期位置」&「初速」&「力」が鍵だが、運動方程式を使わないこのゲームならそこまで対応する必要はない。)。これさえコントロールすればあとの処理はいかなる場合でも同じ形の手続きで記述してよい。⇒コードすっきり!
;↓不要
;#if 0 //ここから「#endif」までは実行されない (コンパイル時に無視される)
; repeat wsy//ブロックy座標
; cy=cnt
; y=cnt*wpy+wy//ブロックをある大きさごとに区切る? //←Yes. 察するに、”吟味対象のブロックのy成分を決定し”ているんじゃない?
; //↑(※好みは人さまざまだけど、個人的には「wy + cnt*wpy」がお勧め。定数化の度合いが高いものほど前に置くと見やすいと思う。)
; hsvcolor cnt*10,255,255
;
; repeat wsx//ブロックx座標
; cx=cnt
; x=cnt*wpx+wx//ブロックの一辺長さ+開始点 ブロックをある大きさに区切る?
; if wall(cx,cy)=0 {//ブロック2次配列
; ; ブロックを表示
; boxf x,y,x+wpx-2.0,y+wpy-2.0
; i = absf(x-blx) : j = absf(y-bly)//ボール座標 - ブロック始点座標
; //ボールとブロックのあたり判定
; //「ボールとブロック差」が「ボールサイズ」より小さい アンド
; //「ボールとブロック差」が「ボールサイズ」より大きい
;
; //「差」は「|⊿x|」
;
; if (i<=blsize)&(j<=blsize) {
; tyaku=1
; bly=y-13
; }
;
; }
;
; if wall(cx,cy)=0 & cx>30{
; wall(cx,cy)=1
; tyaku=0//ブロックが無いときは着地処理をしない
; }
; if wall(cx,cy)=1{
;// i=x-blx:j=y-bly//ボール座標 - ブロック始点座標
; //ボールとブロックのあたり判定
; //ボールとブロック差ががボールサイズより小さい アンド
; //ボールとブロック差が ボールサイズとブロックサイズが大きい
; if (i<=blsize)&(j<=blsize) {
; // IsBallJumping=1
; tyaku=0
; }
; }
; loop
; loop
;#endif
; ボールを表示
pos blx,bly:color 255,255,255
font msgothic,blsize
mes "●"
redraw 1
await 16
goto *main
*gameover
objsize 180,32
pos 150,330:button "終わり",*owari
stop
*owari
end

| |
|
2014/2/23(Sun) 08:33:31|NO.60209
No.60204の「開放」は正しくは「解放」です。失礼しました。
また、
>また、マップをマップチップのようにしてスクロールして進んでいくようにしていく予定です。
>自分なりに考えて見たのですが、配列が足りなくなってしまうのではないかと心配しております。
>現在表示されているマップチップとスクロールして新たに右に出現するブロックをどのように処理すればいいか悩んでいます。
これに関してですが、
>マップをマップチップのようにしてスクロールして進んでいくようにしていく予定
いいと思います。
>配列が足りなくなってしまうのではないかと心配
足りなくなるということはないと思います。例えば dim wall,100000,100 としても40MBです。
それに、0or1の数値しか保存しないのなら、各ブロックは1バイトで表せば十分なので、HSP標準の配列を使わずに独自のデータに対してpeek ,poke等の命令でアクセスするようにすることで、
マップに必要なメモリの容量を1/4に減らせます。(∵整数配列は1要素4バイト)
>現在表示されているマップチップとスクロールして新たに右に出現するブロックをどのように処理すればいいか
配列をx方向にぶっこ抜きするイメージですかね。
マップ全体を記憶する巨大配列Mと、画面内のマップのみを記憶する配列Dを用意し、スクロールするごとにMからDへ然るべき領域をコピーして、
衝突判定はDで行うのがよいと思います。スクロールしても同じ計算式でちょっと定数項を噛ませてやるだけで処理できますから。
|
|
2014/2/23(Sun) 14:04:56|NO.60223
教えていただき本当に有難うございます!
これであと一歩作りたいゲームに近づけるとおもいます。
すみません、知識があまりなく、半角や改行法則がなにかおかしかったのでしょうか?
イレギュラーな書き方をしていたのでしょうか?教えていただければ幸いです。
壁に当たると逆方向に動く場所はブロック崩しの残骸で、消し忘れです。
あとブロックの表示ですが、0=ない 1=表示する、が私も考えてみればしっくりします。
ONとOFFなイメージですね!
いろいろなところから切り張りして、追加しては
消しての繰り返しでフランケンシュタインのようなプログラムができています・・・
|
|
2014/2/23(Sun) 16:31:00|NO.60229
参考になって良かったです。
>半角や改行法則がなにかおかしかったのでしょうか?
おかしいと決めつけるつもりはありませんが、
例えば、
//着地
if tyaku=1{
IsBallJumping=0 : vy_Char=0.0:tyaku=0}
のところは
//着地
if tyaku=1{
IsBallJumping=0 : vy_Char=0.0 : tyaku=0
}
とした方が見やすいんじゃないかなと思いました。
if文で{}を使う時は、{}の中をTabで1段上げておくと構造が一目で解ります。
特にifを二重、三重にするときに見やすさがぐんと上がるのが実感できます。
演算記号や、複数の命令や関数を1行にまとめて記述する際の「:」については、コロンの両サイドに半角スペースがあった方が見やすいと思います。
(例)
mes "a":x=ginfo_mesx+cnt
↓
mes "a" : x = ginfo_mesx + cnt
何をもって「見やすい(⇒解りやすい)」とするかは人それぞれなので、必ずしも「こうしろ」という書き方はないです。
最終的には自分が「見やすいな」と思う書き方で書くのが自分にとっては一番です。
また、時間が経つに連れて書き方は自然と良くなっていくものです。
...と、なんか偉そうなこと言いましたが、
とにかく、べりーさんの納得のいくゲームができるといいですね。楽しみながらやっていきましょう!
|
|
2014/2/25(Tue) 00:59:47|NO.60270
衝突判定ですが、横からの判定でまた躓きました。お助けください。
ブロックの衝突判定はブロック内部座標に入ったら上に押し出す。(解決済)
①右から当たったらブロック内部座標右半分に進入するので右に押し出す
②左から当たったらブロック内部座標左半分に進入するので左に押し出す
の2点がうまくいきません。右からの時のあたり判定はうまくいくのですが。。。
ソースは以下に
//「//」ではじまる行は私が勝手に付けたコメントです。
//まことにまことに勝手ながら....、
// ■未初期化だった「ジャンプ中」フラグを「IsBallJumping」で置き換えさせてもらいました。
// ■重力加速度を「α_G」として新たに定義させてもらいました。
// ■「キャラvy」を「vy_Char」で置き換えさせてもらいました。
x1=0.0:y1=0.0 ; 画面左上の座標
x2=480.0:y2=480.0 ; 画面右下の座標
clrflag=0 ; クリアフラグ
#define α_G 0.45 //重力加速度
blsize=16.0 ; ボールのサイズ
blspd=5.0 ; ボールのスピード
vy_Char = 0.0 //キャラの速度のy成分
blx=240.0:bly=300.0 ; ボールの座標
bpx=1.0:bpy=1.0 ; XY方向のボール座標加算値
bk=0 ; ブロックを崩すフラグ(1=崩す)
mblsize=-blsize;ボール一点座標?
IsBallJumping = 0 //ボールの滞空フラグ(0,1)=(false,true)
// ●---head---●
// | |
// | |
// | |
// | |
// ●---leg----●
blhalf=blsize/2//ボールの中心?
wpx=10.0:wpy=10.0 ; ブロック1個あたりのサイズ
wx=0 :wy =y2-100.0 ; ブロックの表示開始位置(左上)
blnum_x=x2/wpx //ブロックのx方向の個数
blnum_y=100.0/wpy //〃y〃
wsx=blnum_x:wsy=blnum_y ; ブロックの配置数(X,Y)
dim wall,wsx,wsy ; ブロックを表示するフラグ //←「表示/非表示」というより、むしろ「存在する/しない」では?
; 0=表示、1=表示しない ←(※個人的には「(0,1)=(表示しない,する)」の方が本能的にしっくりくる...。(※あんまり気にしないで!))
;< ブロックの存在の設定 >
repeat 20 ;右端20列を穴にする
cnt1 = cnt
repeat 5
wall(int(wsx)-cnt1-1,cnt) = 1
loop
loop
repeat 20 ;右端20列を穴にする
cnt1 = cnt
repeat 5
wall(cnt1,cnt) = 1
loop
loop
screen 0,x2,y2
title "キャラ移動"
cls 4
*main
redraw 0
gradf 0,0,x2,y2,1,0,128 ; 画面クリア
; ボール : X方向の移動
stick key,15 //(=1+2+4+8)
//左移動
if key&1 :blx=blx-bpx //bpxは進行速度
//右移動
if key&4 :blx=blx+bpx //
//map離脱制御
if blx<=x1 : blx=x1
if blx>=(x2-blsize): blx=x2-blsize
//ueキーでジャンプ
getkey key,38//ueキー
if key=1 and IsBallJumping=0{
vy_Char=-8.0
bly += vy_Char
}
; ブロックの処理
colx=wpx+bsize;ブロックの大きさ + ボールのサイズ
coly=wpy+bsize
//< ブロックの描画 & ボールの足場吟味 >
IsBallJumping = 1 ;フラグ初期化
repeat wsy
cy = cnt
y_check = wy + cnt*wpy
hsvcolor cnt*10,255,255
repeat wsx
cx = cnt
x_check = wx + cnt*wpx
if wall(cx,cy) = 0 { ;ブロックが存在するならば
;< 描画 >
await 0.1
boxf x_check,y_check ,x_check+wpx-2.0,y_check+wpy-2.0
;< 足場吟味 > ブロック開始座標 - ボール中心座標 <ボール座標 & ブロック開始座標+ブロックのサイズ-ボールの中心座標が >ボール座標 ときは・・・当たる
bl_headx = blx+(blsize/2) : bl_heady = bly
bl_legx = blx+(blsize/2) : bl_legy = bly+blsize
//頭がブロックに当たってないか、足がブロックに当たっていないか
//の順番で判定を行う
//頭がブロックに当たっているか判定
if (x_check <= bl_headx) & ( bl_headx <= x_check + wpx ){
if(y_check <= bl_heady) & ( bl_heady <= y_check + wpy ){
IsBallJumping = 1
//判定ボックスの点滅
color 0,0,0:boxf x_check,y_check ,x_check+wpx-2.0,y_check+wpy-2.0
//if x_cheak+wpx/2 <= bl_headx{
//blx=blx + blsize/3:await 1000
//}else
if x_cheak+wpx/2 <= bl_headx{
blx=blx + blsize/3
}
if x_cheak+wpx/2 > bl_headx{
blx=blx - blsize/3
}
}
}
//blx_old=blx
//足がブロックに当たっているか判定
if (x_check<= bl_legx)&(bl_legx <= x_check+wpx){
if(y_check<= bl_legy)&(bl_legy <= y_check+wpy){
//いまフォーカスしているブロックがボールの足場であるなら、
//ボールは接地しているとみなせる。y座標についてはすり抜け現象を防ぐための緩衝値が必要。
IsBallJumping = 0
bly = y_check-blsize
}
}
}
loop
loop
//< 力学処理 >
;< 速度処理 >
if IsBallJumping = 0 { ;接地しているならば
vy_Char = 0.0
} else { ;接地していないならば
vy_Char + α_G
}
;< 移動処理 >
bly + vy_Char
//毎回速度成分を足しているけれど、速度が0なら座標が変わらないよね...。
//つまり、物理的に考えれば「速度」がボールの位置を操る鍵ってこと!
//(※厳密には「初期位置」&「初速」&「力」が鍵だが、運動方程式を使わないこのゲームならそこまで対応する必要はない。)。
//これさえコントロールすればあとの処理はいかなる場合でも同じ形の手続きで記述してよい。
//⇒コードすっきり!
; ボールを表示
pos blx,bly:color 255,255,255
font msgothic,blsize
mes "●"
redraw 1
await 16
goto *main
*gameover
objsize 180,32
pos 150,330:button "終わり",*owari
stop
*owari
end

| |
|
2014/2/26(Wed) 17:16:23|NO.60282
「ボールを動かしたと仮定したときにボールがブロックに侵入するかどうかを調べて、
大丈夫なら実際に動かし、大丈夫ではない場合は移動を行わない」
こんな考え方でどうでしょうか?
下はサンプルです。
調子に乗りすぎていろいろと派手になっていますが、これも参考なれば...。
;加速度はすべて〔px/s^2〕
;速度はすべて〔px/s〕
*BOOT
;< ワールド設定 >
;< 空間 >
;< システム >
;画面の左上の座標
#define posx1_screen 0
#define posy1_screen 0
#define posx2_screen 479
#define posy2_screen 479
#const sizex_screen posx2_screen+1
#const sizey_screen posy2_screen+1
;< 時間 >
;< システム >
#define period_loop 16 ;ループの周期〔ms〕
;< 力場 >
;< 物理 >
#define α_G 1000.0 ;重力加速度
;< ボール設定 >
;< 物理 >
#define diameter_ball 16 ;ボールの直径
#const radius_ball diameter_ball/2 ;ボールの半径
#define v_h_ball_←→ 100.0 ;←→キーによるボールの移動時の速度
#define v_v_ball_Jump 500.0 ;ジャンプ時の鉛直方向の初速
v_ball = 0.0 ,0.0 ;ボールの速度。(x,y)
pos_ball = 240.0+radius_ball ,150.0+radius_ball ;ボールの中心の座標
Condition1_ball = 0 ;ボールの状態。(0,1,2) = (ブロックへの侵入なし&滞空 ,〃侵入なし&接地 ,〃侵入あり)
;< ブロック設定 >
;< 物理 >
#define sizex_block 10 ;ブロックのxサイズ
#define sizey_block 10 ;〃y
;ブロックの表示開始位置(左上)
#define posx_StartBlock posx1_screen
#const posy_StartBlock posy2_screen - 200
#const num_block_x sizex_screen/sizex_block
#const num_block_y 200/sizey_block
dim LandForm_Blocks ,num_block_x,num_block_y ;地形データ。(0,1)=(ブロックなし,あり)
repeat num_block_x
cnt1 = cnt
repeat num_block_y
LandForm_Blocks(cnt1,cnt) = 1
loop
loop
;< 地形の編集 >
;< (左端上20*5)&(右端上20*5)を消す >
repeat 20
cnt1 = cnt
repeat 5 : LandForm_Blocks(cnt1,cnt) = 0 : LandForm_Blocks(num_block_x-1-cnt1,cnt) = 0 : loop
loop
;< 地下道 >
repeat 15
cnt1 = cnt
repeat 5
LandForm_Blocks(cnt+cnt1,cnt1) = 0
LandForm_Blocks(num_block_x-1-cnt-cnt1,cnt1) = 0
loop
loop
repeat 5
cnt1 = cnt
repeat 18
LandForm_Blocks(15+cnt,10+cnt1) = 0
loop
loop
;< ブロック―ボール間設定 >
;< 物理 >
#define e_Block&Ball 0.40 ;ブロック―ボール間の反発係数
;< ゲーム達成度設定 >
flg_GameClear = 0 ;クリアフラグ
;< 画面初期化 >
screen 0 ,sizex_screen,sizey_screen
title "キャラ移動"
#module mod1
;ボールのブロックへの侵入チェック
;[ 書式 ]
;
; val = DoesBallInvadeIntoBlocks(x,y)
;
; x,y : ボールの中心の座標
;戻り値 : (0,1,2) = (侵入なし&滞空 ,侵入なし&接地 ,侵入あり)
#define radius_ball radius_ball@ ;モジュール内からグローバル変数を"指さす"には@付きのフルネームで指定してやる必要がある。
#define pos_ball pos_ball@
#define sizex_block sizex_block@
#define sizey_block sizey_block@
#define posx_StartBlock posx_StartBlock@
#define posy_StartBlock posy_StartBlock@
#define num_block_x num_block_x@
#define num_block_y num_block_y@
#define LandForm_Blocks LandForm_Blocks@
#defcfunc DoesBallInvadeIntoBlocks double x ,double y
RC = 0 ;戻り値初期化。(因みに「RC」は「ReturnCode」の略)
repeat num_block_x
cnt1 = cnt
repeat num_block_y
if LandForm_Blocks(cnt1,cnt) = 1 {
x1 = double(posx_StartBlock + cnt1*sizex_block) : y1 = double(posy_StartBlock + cnt*sizey_block)
if (x1-radius_ball < pos_ball(0))&(pos_ball(0) < x1+sizex_block+radius_ball) { ;x座標がめりこみ条件を満たしているならば
if (y1-radius_ball < pos_ball(1))&(pos_ball(1) < y1+sizey_block+radius_ball) { ;y座標がめり込み条件を満たしているならば
RC = 2 : break ;めりこみ確定。確定したから、ここで検査打ち切り。
} else { ;y座標がめり込み条件を満たさないならば
if pos_ball(1) = y1-radius_ball { ;いま着目しているブロックに対して接地しているならば
RC = 1 ;他のブロックに対してめり込んでいるかもしれないので検査を打ち切らない。
}
}
}
}
loop
if RC = 2 : break
loop
return RC
#global
#module mod2
;場外判定
;[ 書式 ]
;
; val = IsBallOutOfTheField(x,y)
;
; x,y : ボールの中心の座標
;戻り値 : (0,1)=(セーフ,アウト)
#define posx2_screen posx2_screen@
#define posy2_screen posy2_screen@
#define radius_ball radius_ball@
#define pos_ball pos_ball@
#defcfunc IsBallOutOfTheField double x,double y
if (radius_ball < pos_ball(0))&(pos_ball(0) < posx2_screen-radius_ball)&(radius_ball < pos_ball(1))&(pos_ball(1) < posy2_screen-radius_ball) : return 0
return 1
#global
*Main
repeat
;< 計算 >
Condition1_ball = DoesBallInvadeIntoBlocks(pos_ball(0),pos_ball(1))
;< 重力による加速度 >
if Condition1_ball = 0 { ;滞空しているならば
v_ball(1) + α_G*period_loop/1000
}
;< めり込み状態への対応 >
;[方針]
; めり込んでいるときは、めり込んでいるブロックの中から1つを適当に選択(※チェックの順番の都合で最初に検出されるものでよいだろう)し、ボールの速度y成分が0以上ならそのブロックの上に、0以下ならそのブロックの下にボールを瞬間移動させ、速度y成分を0にセットする。
; それでもめり込んでいる場合は自動的に次のループでさらに別の然るべきブロックの然るべき位置に配置し直される。これを繰り返すうちにやがて落ち着く。
if Condition1_ball = 2 { ;めり込んでいるならば
if v_ball(1) >= 0 { ;速度y成分が0以上ならば
;接地させる
pos_ball(1) = y1@mod1 - radius_ball ;めり込んでいるブロックの上に乗せる。※「y1@mod1」はモジュール「mod1」内の「y1」のフルネーム。なんでこれが使えるのかというと、直前で「DoesBallInvadeIntoBlocks」関数の実行に伴い、「y1@mod1」が新鮮な状態だから。
} else { ;速度y成分が負ならば
pos_ball(1) = y1@mod1 + sizey_block + radius_ball
}
if absf(v_ball(1)) > 1000.0/period_loop { ;速さが1px/s以上ならば
v_ball(1)*-e_Block&Ball
} else {
;速さが1px/s未満のときは停止させないと侵入判定で暴れる。
v_ball(1) = 0.0
}
}
;< ユーザーによるボールのコントロール要求への対応 >
;< 水平移動 >
;[方針]
; 仮に速度を変えてみて、めり込んだり場外になるなら速度を0にし、大丈夫なら実際に変える。
stick key,13 ;(=1+4+8)。↑キーはトリガにする。
;(速度を仮設定)
u = 0.0
if key&1 : u -= v_h_ball_←→
if key&4 : u += v_h_ball_←→
a = pos_ball(0) ;x座標をバックアップ
pos_ball(0) + u*period_loop/1000 ;仮移動
Condition1_ball_tmp = DoesBallInvadeIntoBlocks(pos_ball(0),pos_ball(1)) ;侵入チェック
if (Condition1_ball_tmp ! 2)&(IsBallOutOfTheField(pos_ball(0),pos_ball(1)) = 0) { ;大丈夫ならば
;実効
v_ball(0) = u
} else {
;キャンセル
v_ball(0) = 0.0
}
pos_ball(0) = a ;座標を元に戻しておく
;< 鉛直投げ上げ >
if (key&2) = 2 : v_ball(1) = -v_v_ball_Jump ;打ち上げ
;接地中のみジャンプしたいなら↓
;if ((key&2) = 2)&(Condition1_ball = 1) : v_ball(1) = -v_v_ball_Jump
;< 位置更新 >
pos_ball(0) + v_ball(0)*period_loop/1000
pos_ball(1) + v_ball(1)*period_loop/1000
;< 描画 >
redraw 0
gradf 0,0,posx2_screen,posy2_screen,1,0,128 ;背景
;< ブロック >
repeat num_block_x
cnt1 = cnt
repeat num_block_y
if LandForm_Blocks(cnt1,cnt) = 1 {
hsvcolor cnt*10,255,255
x1 = posx_StartBlock +cnt1*sizex_block : y1 = posy_StartBlock +cnt*sizey_block
boxf x1+1,y1+1 ,x1+sizex_block-1,y1+sizey_block-1
}
loop
loop
;< ボール >
color 255,255,255
circle pos_ball(0)-radius_ball ,pos_ball(1)-radius_ball ,pos_ball(0)+radius_ball ,pos_ball(1)+radius_ball
redraw 1
await period_loop
loop
*GameOver
objsize 180,32
pos 150,330 : button "終わり",*Shutdown
stop
*Shutdown
end

| |
|
2014/2/27(Thu) 07:31:49|NO.60294
補足で書き込ませてもらいます。
まず、謝っておかなければならないのは、提示されたスクリプトを利用する形での解決策の提案が
できていなかったことです。ごめんなさい。
侵入判定等を行うに当たって導入すべき部分が多かったため、やむを得ず私のわかりやすい形で書いてしまいました。
本質は前のスクリプトと変わっていません。
べりーさんがHSPに関してどれくらい知っているか私にはまだよくわからないので、一応、初心者~中級者という設定で
提案させてもらっています。
私の提案したスクリプトでは
#define ほにゃらら 数字
#const ほにゃらら 数式
という部分が多くあります。以前提案したスクリプトでの重力加速度のところでもこういうのがありましたので、なんとなくわかっていると思います。
詳しくはHSP付属ヘルプを見てある程度理解してほしい(※#defineのヘルプの終わりの方はまだ分からなくてもいいと思う)のです。
何故#define や #constを使うのか?変数に値を代入しておいて、参照するという方法ではいけないのか?
と思うかもしれません。(初めて見たらたぶん思います。)
いけないわけではないんです。しかし、使うとちょっと処理が速くなるんです。ゲームはループしまくりで、何かと計算量が多いですから、
数ミリ秒の差が積もり積もって大きな差になることもあります。
実は、変数を参照するよりはプログラムに組み込まれた定数を参照するほうが僅かに速いのです。
変わらない値なら、いっそ定数として定義してしまったときが多いです。
最後に、
#module ○○
#deffunc ほにゃらら
~~~~~処理~~~~~
return
#global
という部分が多くありますが、これはサブルーチンの進化版みたいな機能で「モジュール」と呼ばれています。
これも詳しくはHSP付属ヘルプを見てぜひ理解してほしいです。
これを使えば自分で命令や関数を作れます。何回も使う複雑(or面倒)な手続き(侵入判定,場外判定とか)はモジュール化してポンポン呼んでやればよいのです。
|
|
2014/3/1(Sat) 17:55:50|NO.60362
返信遅れすみません、根詰めすぎて体調を崩してしまい、寝込んでしまいました。。。
私のレベルとゲーム作成の難易度があってないのかもしれません。。。
モジュールの使い方は少しずつ使えるようにしていきます。
また分からないことがあったら教えてください。本当にありがとうございました。
|
|
2014/3/1(Sat) 19:02:25|NO.60365
あら、...それは大変でしたね。もう元気になっているといいんですが。
>私のレベルとゲーム作成の難易度があってないのかもしれません。。
落ち込まないことです。誰でも最初はそう思います。
私も、今でも大したことは出来ない者ですが、前はもっと何もできない状態でした。
上達することを信じてやっていけばそれでいいんです。
義務感は大敵です。一番大切なのは楽しむことだと私は思います。
モジュールはちょっといきなり過ぎましたかね?(ごめんなさいね)
これを使わなくても、「サブルーチン」という機能で何とかなります。
まずは「サブルーチン」を学習してみてはいかがでしょうか?
しばらく(私の場合は数年...(笑))するともどかしく感じてきます。その時が「モジュール」デビューのきっかけになるでしょう。
とにかく、自分を追い込み過ぎないように気楽にいきましょう!
|
|