忍者ブログ
Admin*Write*Comment
35歳からのC言語ゲームプログラミング
[1]  [2]  [3]  [4]  [5]  [6]  [7]  [8]  [9]  [10]  [11
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

ミサイルの向きを実装しました。
今回使った方法をザックリとですが説明します。

ミサイルの元の方向と自機方向のベクトルと合成して出来た新しい方向のベクトルは、その大きさで割って正規化(大きさ1のベクトルにすること)します。
ベクトルの大きさは三平方の定理で求められます。
(ベクトルのX成分の二乗とY成分の二乗を足した数の平方根(ルート) )

で、大きさ1のベクトルと言う事は、ありうる全ての方向にグルッと回すと半径1の円になります。
ベクトルの作用点を原点とした座標上で考えるとそれはつまり、ベクトルのX成分はcosの値を、Y成分はsinの値をとると言う事です。
今回はこのcos=X成分の値を使いました。
X成分は、 1 ~ -1 の範囲の数になります。
ベクトルとX軸の作る角度が0度のとき1となり、90度で0、180度で-1となります。
180度から360度までは逆に-1から0を通って1へと推移してゆきます。

で、使うグラフィックパターンは8方向なので、円を8分割します。
そうすると、それぞれの方向のグラフィックパターンがどの範囲の角度に入るのか決まります。
その基点となる角度のcosの値をゲームの初期化部分であらかじめ計算させて変数に入れておきます。

cbc27142.jpg








こんな感じ。
Y軸は画面座標にあわせて下がプラス方向になっています。








正規化したベクトルのX成分の値とこの変数の値を比較すると角度の範囲が2つ見つかります。
Yがプラス側(0~180度)とマイナス側(180~360度)の2つです。
あとはY成分が0より大きいかどうかを判断すればベクトルの向きが特定できます。
例えば、X成分の値がcos(22度)を入れた変数より小さくて、cos(68度)を入れた変数より大きく、かつY成分が0より小さければベクトルは右上方向のグラフィックを表示する範囲の角度にあると特定できます。

使うのはたった4つの角度のcos値ですし、三角関数の処理の負荷が大きいことを考えると、ゲームが始まる前にあらかじめ4つのcos値を計算して変数に入れておいた方がより高速なアルゴリズムになります。

f96f5dd5.JPG









しっかり向きを変えながら自機を追ってきます。







今回のアルゴリズムで最大の発見は、あらかじめ三角関数を計算して変数に入れておくという部分かと思います。
もっと早く思いついていれば他の敵のアルゴリズムももっと高速に作れたと思います。
作り直すつもりはありませんが(笑)
っていうか、それほど厳密な値が必要なければ360度を例えば10度ずつ36等分した時のsin、cosを先に配列変数に入れておいて、プログラム上0~360度を0~36度として使用すれば、三角関数使い放題でアルゴリズムを書いても普通の変数のやり取り(計算や比較)と同じ負荷ですみますね。
これならそうとう遅いCPUでも楽々動くでしょう。
PCエンジンとか昔の8bitゲーム機でR-TYPEなんかのシューティングゲームがちゃんと動いていた秘密の一つを見付けた気分です。
PR

致命的な問題を発見しました。
敵機の座標を表す変数の宣言はint型を使っていたんですが、そこにベクトルの実数を足し引きしていたので、座標に対するベクトルの影響がうまく出ていないケースがありました。
いままでも敵の動きが時々何か変だなとは感じていたんですが、誘導ミサイルが思ったように動かない事で原因が特定できました。
敵の座標変数もfloat型で宣言するように修正済みです。
コレを画面描画の際はintに変換して使う形になります。
ベクトルで動くゲームを作る時に初心者が落ちやすい穴なんじゃないかと。
まだ全ての変換部分を直しているわけじゃないのでコンパイルの時に変数型に関する警告が出まくりますが(笑)、とりあえず動く形にはなりました。

93f60c89.JPG









8方向分のミサイルを描きましたよ。








誘導に関してはうまく動くようになりましたが、微調整はなかなか難しいですな。
自機方向のベクトルをそのまま合成すると、自機との距離によって相当誘導性能が変る(遠いほど誘導性能が上がる)ので、自機方向のベクトルを正規化したうえで、大きさを調整しています。
よって、平方根の計算を2回行うアルゴリズムに変更されましたが、速度的にはまったく問題なさそうです。

da1696e1.JPG









誘導性能の調整具合によっては自機の周りを衛星のように回ったり・・・(笑)






現状ではミサイルは常に右向きなので、次はミサイルの角度によって向きをつける部分を実装してみようと思います。

えーとですね、別の方法も考えてみましょう。

まず、X軸正方向を0度として現在のミサイルのベクトルの角度Aと、自機へ向かうベクトルの角度Bを求めます。
角度C = 角度A - 角度B を計算します。
角度Cが正か負か、また角度Cの絶対値が180より小さいかどうかを基準にミサイルの方向修正する角度が正負どちらの方向か得ます。
画面座標上だと正が時計回り、負が反時計回りと鳴ります。
修正角度を角度D(ただし絶対値C<DならD=Cとする)とすると、
正方向なら、A  = A + D
不法項なら、A = A - D
と、ミサイルの方向を修正します。
Dの値の大小で追尾性能が変ります。

この方法だと前の記事の方法のようにミサイルと自機の位置関係や向きによって追尾角度が変る事がありません。
ミサイルの後ろ側に自機がいたとしても同じペースで方向修正してきます。
数値上では一番理想的なアルゴリズムだと思います。

じゃあ、こっちでやりゃあ良いじゃんとなりそうでなりません。
問題は処理の重さです。
実装してみなければ実際に影響があるかどうかわかりませんが、この方法は一発のミサイルにつき1フレームに複数回ずつasin、acosの処理を必要とします。
複数のミサイルが飛びかう様を想像すると、いかにもやばそうです。

要はそれっぽく見えた上で誘導弾としての機能をちゃんと実現していれば、それが三角関数を駆使した理想的で高度な処理だろうと、単純なベクトルの合成による処理であろうと、遊ぶ人からしたらゲームが面白ければどうでも良いわけで。
無駄に高度で重い処理を多用するのは、ゲームプログラミングの方法論としては必ずしも正解ではないと思うんです。
速度無視で物理シミュレーションをするとかなら話は別ですが。

で、そんなことを考えた上で実装の方向を決めました。

弾道補正のは現在ベクトルと自機方向ベクトルの合成を使います。
で、グラフィック表示に必要なミサイルの向き(角度)のみasin、acosを使用して取得します。
いや、待てよ、三角関数使わないで出来ないか?

まず合成ベクトルを正規化(大きさ1にする)すれば、X成分の値がcosθってことになるでしょ。
で、あらかじめグラフィックの向きごとの角度の範囲を決めて移行点となる角度のcosの値をゲーム初期化部分で変数に入れておく。
変数の値とX成分の値を比較して向きを判断するんだけど、この情報だけだと0~180度と180~360度の範囲に2つ該当する角度が出てしまう。
そこで、Y成分の正負を判定しよう。
よし!これで現在の角度が厳密ではないけども8方向のどこかは確定できる!
うまくいけば、一発のミサイルにつき1フレーム当たり1回平方根の計算をするだけで実装できるかもしれない。

というわけで、実装方法決定案。
①ミサイルの方向補正は自機方向ベクトルとの合成で行う
②合成ベクトルを正規化(ここで平方根を1回使う)し向きを判定、グラフィックに反映する
③正規化したベクトルにミサイルの速度をかけて、それを新しいミサイルのベクトルとする

これで、うまく動かないようならもうちょっと高度なアルゴリズムを考えてみます(笑)。

じゃあ、ミサイルのドット絵でも描くか!
いろんな方法が考えられて面白いですね。
どんな方向に向かっていようと、次のフレームでいきなり自機を向いて飛んでくるなら簡単ですが、それじゃあミサイルらしい動きにはなりません。
徐々に自分の方向に軌道を修正してくる感じが必要です。
また、その修正度合いで追尾性能を調整してゲームのバランスをとらなければなりませんね。

今考えているのは、ミサイルの現在の移動ベクトルに自機方向へ向かうベクトルを合成する方法です。
合成する自機方向へのベクトルの大きさを変える事で追尾性能を調整できると考えています。
合成ベクトルの単位ベクトルを求めてミサイルの速度をかけてやれば新しいミサイルのベクトルを作れます。
問題は真後ろに自機がいる場合ですが、動的にゲームが進行している中では、互い位置関係は常に変わってくるので、それほどおかしな動きはしないんじゃないかと思っています。
これは実装してテストしてみないとわかりませんね。

あとの問題はミサイルのグラフィックを8方向で変えるための角度の情報をどうやって得るかということです。
ミサイルのベクトルのXY成分の正負と大きさの比較で得られるかなぁと、漠然と考えています。
誘導ミサイルを撃ってくるロボットの動きのアルゴリズムが出来ました。
画面中ほどの高さで右へ飛行し、着地します。
出現時からのフレーム数でベクトルの値を変えてゆき、着地の時のみ地面との当たり判定で状態移行させています。
プログラムはこんな感じ。
834d2c82.PNG

















数式で動かすタイプに比べると単純なアルゴリズムです。
しかし、状態を移行するタイミングを調整するために、トリガーになるフレーム数を変えながらテストを重ねる必要があるため、プログラムが単純なわりに思ったように動かすためには時間がかかります。

9ae1460e.JPG











飛んで、飛んで、飛んで・・・





88e2c4f7.JPG












スタッと、着地します。




さて、次は一定時間間隔で誘導ミサイルを発射するようにしてみましょう。


ぜんぜん関係ないんですが、メインのシステム部分にも少し改良を加えました。
まず、スクロール部分で背景の画像のX座標を毎フレーム-1する処理をしていたんですが、ゲームがスタートしてからのフレーム数を使う形にしました。
背景のX座標 = -ゲームフレーム
となります。
それにあわせて、メインループに入る前の初期化やファイルの読み込みなんかをやっている部分に、現在のゲームフレームの値から最初に出現する事になる敵がスケジュールファイルの中の何番目の敵かを検索するプログラムを加えました。

なぜこんな改造をしたかというと、ゲーム制作が後半部分に入ってきてテストプレイに時間がかかるようになったからです。
チェックしたいお目当ての部分にたどり着くまで、数値を僅かに変えた結果を見たいだけなのに最初からプレイするのはあまりにめんどくさいです。
今回の改造によって、ゲームフレームを入れる変数の初期化部分に任意のフレーム数を書いておけば、途中からゲームをスタートできるようになりました。
いやあ、もっと早く実装しとけば良かった・・・。
テストプレイがメチャメチャ楽になりました(笑)
また、この実装は後々、自機がやられた時の再スタート処理にも役立つでしょう。

あと、アニメーション関数も少し書き換えました。
関数に渡したパラメーターによってキャラの左右反転を可能にするため、DrawRotaGraph関数を使っていましたが、この関数を使うと(もともと画像を拡大縮小・回転表示する関数のため)表示位置を指定する座標は画像の中心点となります。
全てのキャラが一定の画像サイズなら問題ないんですが、画像サイズの異なるキャラがいる場合、中心点を求めるために座標に足す数値が変ってくるため、やっかいです。
じっさい今回のロボットを実装する時もこの関数のせいで思った位置に調整するのに苦労させられました。
今回のゲームでは拡大や回転の必要はなく、ただ左右反転は使いたかっただけなので、DrawTurnGraph関数を使う形にしました。
呼び出し側から渡されたフラグがFALSEなら普通にDrawGraph関数で、TRUEならDrawTurnGraph関数で表示を行うように条件分岐させます。
これで、ここまでに既に書いてしまっているアニメーション関数の呼び出しは一切変更する必要無く、画像サイズを気にせずにすむようになりました。

あと、もうひとつ改良したいところがあるんだよなあ・・・。
固定FPSでゲームを進行しているのに、時間の関係する処理ごとにGetNowCount関数を使うのはナンセンスなんです。
フレーム数をタイマーとして使う方が処理も軽いし合理的です。
GetNouCount関数は1フレームの時間を管理する部分にだけ使えばよいので、1フレーム1回使えば済む話じゃないかと。
なんで最初に気付かなかったのか・・・(悲)。
まあ、今時点で処理が重くて困っているわけでもないんで、このまま行くかも知れません。
  • ABOUT
やってやれないことはないっ!たぶん・・・
  • カレンダー
04 2024/05 06
S M T W T F S
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
  • 最新コメント
[11/09 CALL MY NAME]
[11/09 erin]
[08/18 うずランド]
[07/11 うずランド]
[06/23 うずランド]
  • プロフィール
HN:
Call my name
年齢:
49
性別:
男性
誕生日:
1974/05/22
職業:
スロ屋店員
趣味:
いろいろ
自己紹介:
やる気だけはあるつもりです。
はい。
  • バーコード
  • ブログ内検索
  • カウンター
  • アクセス解析
Copyright © 35歳からのC言語ゲームプログラミング All Rights Reserved.*Powered by NinjaBlog
Graphics By R-C free web graphics*material by 工房たま素材館*Template by Kaie
忍者ブログ [PR]