●移動アルゴリズム 加速度を上下させて移動量を算出 直接座標を上下させる事はない プレイヤー機とボス機は必ず向き合うものとする ○ボス機x軸方向移動 プレイヤー機と適当な距離を保とうとする プレイヤー機に一定以上近づかれたら逆方向へ移動 (ボス機y軸方向移動との組み合わせで回り込む動作となる) ○ボス機y軸方向移動 プレイヤー機に合わせる プレイヤー機に一定以上近づかれたら適当な距離を保とうとする ※ボス機はプレイヤー機のレーザーソードを警戒しています ○プレイヤー機x軸方向移動 & プレイヤー機y軸方向移動 プレイヤーが操作しないと減速していく ●ウィンドウ外へ移動した場合 強制力(大きな逆加速度)が発生して内部へ戻される 直接座標を修正する事はない(強制力さえなければどこまでも行ける) ※インチキ物理公式 △y=1/2*a*△t*△t (△:デルタ) 本来の公式( y=1/2*a*t*t )は絶対移動量を表しているが、 その為には経過時間が必要となる。 一定速度に落ち着いたり、減速させられる為には空気抵抗も必要となる。 どちらもかなりいや〜な予感がする。 インチキ公式でいじれる値は加速度 a だけなので、 プログラムではこの値を上下させている。 どこがインチキかって? 例えば一定速度に落ち着いているのに加速度が0じゃなかったりね。 ○ボス機攻撃方法 ・通常弾 プレイヤー機の通常弾と同じ 狙い撃ち(y軸方向誤差有り) ・誘導弾 100回(1回/0.05秒)方向修正可能 その倍の時間で自動消滅 〜必殺技 予備動作(収束)が必要〜 ・麻痺レーザー 触れると一定時間操作不能 撃ちっ放し ・全方位弾 通常弾を全方位に発射 狙い撃ちじゃない ・極太レーザー 一定時間極太レーザーを照射し続ける ボス機は移動可能 ・子機レーザー 子機を射出してレーザー攻撃させる その際ボス機は通常弾で攻撃 子機は無敵 ○プレイヤー機攻撃(&その他)方法 ・通常弾 前方まっすぐにしか撃てません ・レーザーソード レーザーソードを振り下ろす 振り上げた方向で最後まで振り下ろす ・自己修復 耐久力が徐々に回復していく 自己修復中は操作不能 ・ダッシュ 一時的に加速度アップ ●ダメージ算出方法 エネルギー密度(範囲内にどれだけ判定点があるのか)の概念を導入 大きくてもスカスカなエネルギーは威力が小さい 疑似面判定(面は点の集合である)で行う 純粋な面判定は無理かも? 弾は当たると消える レーザーは貫通し当たっても消えない 当たり続けるとダメージを受け続ける 本当なら全ての判定点のダメージは1にするつもりだったが、 いろいろと不都合が出てきた為に調整を入れてみた。 エネルギー密度の概念に従って判定点を減らしていくと処理は軽くなって良いのだが、 減らしすぎるとダメージにムラが発生し不自然になるので注意。 ●WM_TIMERメッセージが来たときの処理順序 当たり判定 弾移動 弾発射 収束 発射処理も含まれるのでボス機が移動する前に実行する必要がある ボス機移動 プレイヤー機移動 新しい向きを取得 全ての処理において認識している向きは同じ ※以下のようにすると人間が見ている状態と一致しません 弾移動→当たり判定 弾は(人間の目には)当たる前に消えてしまいます 弾発射→弾移動 撃った直後に移動し、人間の目に映るのは移動後の座標です 機体移動→弾発射 人間が見ている場所(次に撃ってくると思われる場所)とは違う場所(移動先)から発射してきます 基本的には普通に考えた場合と逆に配置していく事になる。 ○勝敗&終了判定 耐久力ゼロで勝敗決定 勝敗決定後も一定時間継続動作(変数が自動的に元の値に戻るのを待っている) 但し新しい状態には移行できない 勝利機は移動のみ可能 敗北機は徐々に下降 継続動作中に両者共耐久力ゼロになった場合は引き分け 一定時間後終了 ○チューニング項目 耐久力(ライフポイント) 50〜150 機体移動スピード(上限加速度) 8000〜12000 自己修復速度 1ライフ/6〜14(*0.05)秒 連射性能 1発/3〜7(*0.05)秒 ○性能比較 プレイヤー機 vs ボス機 耐久力 50〜150 vs 1500 加速度 1000〜2000 vs 500〜1000 上限速度 8000〜12000 vs 5000〜10000 ★重要な注意 以下のようにするとCreatePen関数は何故か失敗します。 更に不思議な事に、一度失敗すると以降の同関数(別の行であっても)は皆失敗し続けます。 CreateSolidBrush関数も同様です。 hPen=CreatePen(PS_SOLID,1,RGB(255,0,0)); SelectObject(hdc,hPen); 描画処理 hPen=CreatePen(PS_SOLID,1,RGB(255,0,0)); SelectObject(hdc,hPen); 描画処理 DeleteObject(hPen); 同じような時間に発生しているような気がしますが、 原因は特定できていません。 GetStockObject関数は問題ありません。 以下のように模範的な書き方をすれば問題ありません。 hPen=CreatePen(PS_SOLID,1,RGB(255,0,0)); hOldPen=(HPEN)SelectObject(hdc,hPen); 描画処理 SelectObject(hdc,hOldPen); DeleteObject(hPen); hPen=CreatePen(PS_SOLID,1,RGB(0,255,0)); hOldPen=(HPEN)SelectObject(hdc,hPen); 描画処理 SelectObject(hdc,hOldPen); DeleteObject(hPen); ★重要な注意 其の弐 以下のようにすると他の処理に悪影響を及ぼします。 自分自体は正常でした。 *mahiray_x[mahiray_max]=x_mahiray(mahiray_x,mahiray_n,mahiray_xb,houkou_temp); *mahiray_y[mahiray_max]=y_mahiray(mahiray_y,mahiray_n,mahiray_yb); 以下のようにすれば問題ありません。 mahiray_x[mahiray_max][mahiray_max2]=x_mahiray(mahiray_x,mahiray_n,mahiray_xb,houkou_temp); mahiray_y[mahiray_max][mahiray_max2]=y_mahiray(mahiray_y,mahiray_n,mahiray_yb); ☆開発秘話 全方位弾・・・はじめの頃は通常弾を流用していたがダメージを変えられない事に気付き、 同じような変数を別途用意した。ある意味無駄。 ちらつき・・・方法は二つある。マシンの処理限界に依存させる。乱数を使う。 基本的には前者の方がより自然だが、位置関係で後者を採用しなければならない場合も。 今回の子機レーザーがそう。 ちなみに、プレイヤー機レーザーソードは唯一ちらつかないレーザーである。 背景画像・・・実は3枚ある。再戦する毎に変更。 ☆本作品が示した未来への可能性 膨大な計算を行っているにもかかわらず、非常にライトな本作。 軽くするコツは・・・画像の読み込み(作成)は一度だけにする(WM_CREATE等で)。 色数は256色まで。減色しても殆ど分かりません。しかも効果的。 無駄に緻密な計算(当たり判定等)は簡略化・・・と言ったところ。 実は画像処理自体は気にならない程度の重さでしかない。 重たいのは読み込み(作成)だけなので、ここを工夫する事が重要となってくる。 つまり、画像バリバリのゲームも十分可能であるという事を示している。 ☆アイディア 思い付き 当たると怯む:当たった直後に一時的な無敵状態が必要 より自然な敵移動アルゴリズム:自律的(プレイヤー機無視)周期運動が必要 バグ防止にも役立つ ☆プログラミング方針 基本的にグローバル変数は使わない。 関数内部で渡された値をいじらない。必要な結果はreturnで返させる。 基本的に構造体は使わない。 可能な限りヘッダーファイルにまとめて、メインの方をすっきりとさせる。 ☆構造体について思ふ事 関数に大量の変数を簡単に渡せる。 関数で複数の値を返す事ができる(特に重要)。 配列の多重化を防止できる。 変数同士の関係がわかりやすくなる。 上手くまとめないと、無駄な変数を大量に関数に渡してしまう。 ☆次回への方針 構造体&クラスを積極的に利用する事により、更に大規模なプログラミングに備える。 更に汎用的なヘッダーファイルを作成する。 ・・・今回のプログラム量:約1200行