ブロック崩しを作っていて、敵の設定を行っています。敵をバーの位置に合わせて左右に移動し、ブロックに当たると止まるようにしたいのですが、うまくいきません。
判定はif(敵の右側のx座標 <ブロックの左側のx座標)、if(敵の左側のx座標 <ブロックの右側のx座標)のとき移動というようにしています。
ブロックはj=0~9と横並びで真ん中3つを消しています。j<2のとき上記の左の判定、j>6のとき右の判定のようにしています。
また、線分の四角の当たり判定の方法を調べ関数を作り試してみたのですが駄目でした。
下記のサイトにファイルを上げました。パスワードは「YT2012」です。
http://www1.axfc.net/uploader/so/2695694
当たり判定の設定はhit.cppのstage4_hit()です。
正直もとからブロックとの当たり判定どうすればいいかわからないというのがありました。これから敵の種類を増やしていく場合必要になるためどうか教えてください。
ブロックと敵との当たり判定
-
Eeel
Re: ブロックと敵との当たり判定
こんばんは。
という形にしてはどうでしょうか?
現状では
となっていますが、これは
block1[0][0]にぶつからなければ移動
block1[0][1]にぶつからなければ移動
・
・
・
という事です。
左に移動するとblock1[0][2]にぶつかる状態であっても、block1[0][8]にぶつからなければ左に移動する、というような状態が発生し
移動も最大で残っているブロックの個数回行ってしまっています。
if(敵を左に移動させたい){
if(関数:ブロックにぶつかるか(敵.x-2) == ぶつからない){
敵.x -= 2;
}
}
if(敵を右に移動させたい){
if(関数:ブロックにぶつかるか(敵.x+2) == ぶつからない){
敵.x += 2;
}
}現状では
for(全てのブロックについて){
if(このブロックが左側のブロックなら){
if(敵の左端とブロックの右端がぶつからないなら){
敵を右か左に移動;
}
}
if(このブロックが右側のブロックなら){
if(敵の右端とブロックの左端がぶつからないなら){
敵を右か左に移動;
}
}
}block1[0][0]にぶつからなければ移動
block1[0][1]にぶつからなければ移動
・
・
・
という事です。
左に移動するとblock1[0][2]にぶつかる状態であっても、block1[0][8]にぶつからなければ左に移動する、というような状態が発生し
移動も最大で残っているブロックの個数回行ってしまっています。
-
ヨシタケ
Re: ブロックと敵との当たり判定
ブロックと敵との当たり判定をfor文の外(for文の前)に出して
とやってみたのですがブロックをすり抜けてしまいます。
とやってみたのですがブロックをすり抜けてしまいます。
-
Eeel
Re: ブロックと敵との当たり判定
for文の外にする事自体は間違っていませんが、for文の外だと
の i と j の中身はどうなっているのでしょうか?
また、HitRectAndRectは名前から想像すると、ある二つの Rect 同士(つまりこの場合は、敵とある一つのブロック)がぶつかるかどうかだけを返す関数だと思うのですが、
敵がブロックとぶつかっていないかを判断する場合は
敵が、全てのブロックの内一つ以上のブロックとぶつかる → 「ぶつかる(ヨシタケさんの例での TRUE )」を返す
敵が、全てのブロックの内どのブロックともぶつからない → 「ぶつからない」を返す
という風にやる必要があります。
また、HitRectAndRectは名前から想像すると、ある二つの Rect 同士(つまりこの場合は、敵とある一つのブロック)がぶつかるかどうかだけを返す関数だと思うのですが、
敵がブロックとぶつかっていないかを判断する場合は
敵が、全てのブロックの内一つ以上のブロックとぶつかる → 「ぶつかる(ヨシタケさんの例での TRUE )」を返す
敵が、全てのブロックの内どのブロックともぶつからない → 「ぶつからない」を返す
という風にやる必要があります。
-
Eeel
Re: ブロックと敵との当たり判定
すみません、一つずつ解決していこうと思っていたのですが
小出しにするのもどうかと思い直しました。
今私にわかる範囲で問題になりそうな部分があと二ヶ所あります。
一つ目は詳しい説明は必要無いと思いますが、
衝突判定と同時に、ブロックが消えているか残っているかの判定を行っていない事です。
二つ目です。 これを同じ意味の別の表現に直すと となります。
ヨシタケさんの 同じように表現し直すと となります。
これだと、判定時にブロックと重なっていないのなら、一度だけブロックと重なるように動く事ができます。
そして、一度ブロックと重なってしまうと、今度は左右どちらにも動けなくなってしまいます。
小出しにするのもどうかと思い直しました。
今私にわかる範囲で問題になりそうな部分があと二ヶ所あります。
一つ目は詳しい説明は必要無いと思いますが、
衝突判定と同時に、ブロックが消えているか残っているかの判定を行っていない事です。
二つ目です。 これを同じ意味の別の表現に直すと となります。
ヨシタケさんの 同じように表現し直すと となります。
これだと、判定時にブロックと重なっていないのなら、一度だけブロックと重なるように動く事ができます。
そして、一度ブロックと重なってしまうと、今度は左右どちらにも動けなくなってしまいます。
-
ヨシタケ
Re: ブロックと敵との当たり判定
何度もアドバイスありがとうございます。
試しにi,jの値を決めて というようにしてみたらちゃんとそのブロックの位置でとまるようになりました。
なので、i,jに問題があるのだと思いました。
そこで、判定方法を少し変えて的が左に移動できる位置をleft,右に移動できる位置をrightとし、for文の中に
敵移動制御を
というように追加・変更してみました。(移動制御はfor文の後に移動させました。そうしないとエラーが出てしまうため)一応、ブロックのある位置で止まるようになりました。
しかし、縦3つ並んでるブロックのひとつでも消えると普通にすり抜けてしまいます。
試しにi,jの値を決めて というようにしてみたらちゃんとそのブロックの位置でとまるようになりました。
なので、i,jに問題があるのだと思いました。
そこで、判定方法を少し変えて的が左に移動できる位置をleft,右に移動できる位置をrightとし、for文の中に
if(block1[i][2].flag == 0){//左から2番目の位置にブロックがあるかどうか
left = 145;
}else if(block1[i][1].flag == 0){){//左から1番目の位置にブロックがあるかどうか
left = 104;
}else if(block1[i][0].flag == 0){){//左から0番目の位置にブロックがあるかどうか
left = 63;
}
if(block1[i][6].flag == 0){){//左から6番目の位置にブロックがあるかどうか
right = 270;
}else if(block1[i][7].flag == 0){){//左から7番目の位置にブロックがあるかどうか
right = 311;
}else if(block1[i][8].flag == 0){){//左から8番目の位置にブロックがあるかどうか
right = 352;
}
if(ene1.x +2< bar.x - 10){ //右に移動
//if(HitRectAndRect(guardian,block1[6][6].hit) == FALSE)
if(guardian.rb.x < right)
ene1.x += 2;
}
if(ene1.x -2> bar.x + 10){
//if(HitRectAndRect(guardian,block1[6][2].hit) == FALSE)
if(guardian.lt.x >left)
ene1.x -=2;
}
しかし、縦3つ並んでるブロックのひとつでも消えると普通にすり抜けてしまいます。
-
Eeel
Re: ブロックと敵との当たり判定
良いですね。その調子です。ヨシタケ さんが書きました:というようにしてみたらちゃんとそのブロックの位置でとまるようになりました。
なので、i,jに問題があるのだと思いました。
「個々のブロックの衝突判定をまとめたもの」 = 「ブロック全体の衝突判定」
となるわけですが、i,jに問題というのをより厳密に言うとこのまとめる部分に問題がある、となります。
最初は、左側のブロックとの判定が正しくても右側のブロックに当たらなければ左側に動く、という事ができてしまっていました。
次は、一つのブロックとの判定が正しくてもその一つのブロックとしか衝突判定をしない、という動作になってしまっていました。
そして今回は……。
■■
■■■
■■
左側のブロックがこのような形に残っている状況を考えてみてください。
真ん中の列に関しては、2番目のブロックがあるのでになりますが
上と下の列では、2番目のブロックが無く1番目のブロックがあるのでになってしまいます。
どこか一列だけを考えれば正しい衝突判定ですが、他の列とまとめてブロック全体の衝突判定を得ようとすると問題が生じています。
今回は全てのブロックについて判定を行っているのですが、その結果の情報を上書きしてしまっているのが原因です。
解決方法は上書きをしないようにする、以外にもたくさんあるので、色々試してみてください。
ここからは蛇足ですが、
ソースを書くときは、モノやコトごとに処理をまとめると作りやすくなります。
見やすくなるだけでなく、考えやすくもなります。
例えば、「ブロックと敵との衝突判定」という一つコトが一つの塊(関数でなくても、すぐ関数にできるような状態)になっていれば
別のステージで別の敵を作る時や、敵の数が増えた時にも簡単に対応する事ができます。
しかし、「ブロックと(ボールと敵)との衝突判定」というように二つのコトが一つの塊になっていると、
もし敵が増えた場合に、敵との衝突判定だけを敵の数だけ繰り返そうとしても必要以上に複雑な処理になってしまいます。
もちろん、塊の分け方は細かければ細かいほど良い、というわけではありません。
どの程度のバランスが良いのかという感覚は、センスと経験で磨いていくしかないのでしょう。
私もまだまだ勉強中です。
今回のプログラムでは考えなくても構いません、。
次回以降、余裕があったらちょっとだけ気にしてみてください。
-
ヨシタケ
Re: ブロックと敵との当たり判定
できればやりたくなかった方法ですが、全然いい方法が思い浮かばなかったのでやりました。
今回はブロックが3つなのであまり長くなりませんでしたが、多くなるととても長くなりそうです。
一応、実際やってみた限りでは、問題なさそうでしたが心配なので、大丈夫かどうか聞いてみようと思い、まだ「解決!」はつけませんでした。
//左側の移動できる位置
if(block1[i][2].flag == 0){
left = 145;
}
else if(block1[i][1].flag == 0){
if(block1[5][2].flag == 1 && block1[6][2].flag == 1)
left = 104;
}
else if(block1[6][0].flag == 0){
if(block1[5][1].flag == 1 && block1[6][1].flag == 1)
left = 63;
}
//右側の移動できる位置
if(block1[i][6].flag == 0){
right = 270;
}
else if(block1[7][7].flag == 0){
if(block1[5][6].flag == 1 && block1[6][6].flag == 1)
right = 311;
}
else if(block1[i][8].flag == 0 ){
if(block1[5][7].flag == 1 && block1[6][7].flag == 1)
right = 352;
}
一応、実際やってみた限りでは、問題なさそうでしたが心配なので、大丈夫かどうか聞いてみようと思い、まだ「解決!」はつけませんでした。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: ブロックと敵との当たり判定
比較する条件とか添字とかright ,leftに入れる値とかを構造体配列でテーブルにすると処理はテーブル参照でのループでできるようになります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
Eeel
Re: ブロックと敵との当たり判定
この辺りが問題ですね。
このケースに限れば、思い通りの動作をさせるという意味では、あとはおそらく問題無いでしょう。
ブロック数が増えた時も問題ですし、別の場所で設定しているブロックの配置が変わった時も、この部分を書き換える必要があります。
ステージが増えればステージの数だけ当たり判定を行う箇所が増えてしまいます。
もしブロックのサイズ・配置、敵のサイズ・数・移動の仕方(左右だけじゃなく上下にも動いたり)などに影響されない判定が行えるようになると、その後は楽ですよね。
ただ、ここから先どうするかはヨシタケさん次第です。
完成させるというのはモチベーション的にも経験的にも大きなプラスになります。
とりあえず目的の動作をさせられるようになったという事で、完成を目指すのも良いでしょう。
逆にせっかくの機会なので、より良い方法について質問をするのも良いでしょう。
softyaさんは知識も経験も私なんかと比べてずっと素晴らしいものをお持ちですので、
softyaさんに教えてもらうのはとても良い勉強になるだろうと思います。
このケースに限れば、思い通りの動作をさせるという意味では、あとはおそらく問題無いでしょう。
その感覚は良いと思います。ヨシタケ さんが書きました:できればやりたくなかった方法ですが
ブロック数が増えた時も問題ですし、別の場所で設定しているブロックの配置が変わった時も、この部分を書き換える必要があります。
ステージが増えればステージの数だけ当たり判定を行う箇所が増えてしまいます。
もしブロックのサイズ・配置、敵のサイズ・数・移動の仕方(左右だけじゃなく上下にも動いたり)などに影響されない判定が行えるようになると、その後は楽ですよね。
ただ、ここから先どうするかはヨシタケさん次第です。
完成させるというのはモチベーション的にも経験的にも大きなプラスになります。
とりあえず目的の動作をさせられるようになったという事で、完成を目指すのも良いでしょう。
逆にせっかくの機会なので、より良い方法について質問をするのも良いでしょう。
softyaさんは知識も経験も私なんかと比べてずっと素晴らしいものをお持ちですので、
softyaさんに教えてもらうのはとても良い勉強になるだろうと思います。