SyntaxHighlighter

2012年2月22日水曜日

スパゲティ爆発

コードが複雑になりすぎて頭が爆発した。
設計を見直そう。

仕様を決めずに拡張性の高いコードを書こう、と思ったのだけど、無謀だった。とりあえず動くものはできたが、いざ機能を追加しようとしても、コードがあちこちに散在しすぎてて修正箇所の把握が困難。作業効率が悪すぎて一向に前に進まない。

…というわけで、早めに正しい設計に戻そう。コードの重複に死を。適当にconstされてないポインタ戻すのは最早誰が中身を弄っているのか分からないし最悪だ。かといってGetSetにまみれた糞クラスも作ってはいけない。

今回の件から我々が得るべき教訓は、仕様が確定しないうちに製造を始めても決して完成しないということだ。



My Hack and Slash Gameにおける仕様と設計

【おおざっぱな仕様】
--あらゆる手段で敵を倒すのが目的である
--武器、スキル、キャラクタは外部から数値が変更されることがある
【少し細かい仕様】
--CharacterにはPlayer,Friend,Enemy,Bullet,AoE,Wall等がある
--SkillにはActiveSklillとPassiveSkillがある
----前者は実際にSkillをInvokeするTrigger
----WeaponはSkill発動の条件にはなるが、それ自体にInvokeの概念は無い
----後者は内部的にはほとんどWeaponと同じだが、Itemではない
--WeaponはSkillの性能を変更させる
----普通のARPGにおけるItemはWeaponとして処理する
--Skill,WeaponはCharacterが所有する
----それらは変更のされない参照を無制限にされる
--CharacterがSkillを使い、CharacterとSkillとWeaponに基づいてCharacterを生成する
--Characterの数値が変更されるEventは以下の条件で発生する
----Character同士の衝突
------衝突開始、接触中、接触終了により処理が分岐する
----時間経過
------SkillやWeaponの時間経過によるCharacterへの影響
------Character自身のTimeEventによる変化
----Userによる操作
------専らPlayerのみである。SkillのInvokeと移動を行う
----AIによる操作
------Player以外はCharacter自身で保有するAIがSkillのInvokeと移動を行う
----Skillによる衝突に拠らないCharacterへの干渉
------Friendの操作など
------SkillのPowerCost等はInvoke時ではなくここに処理がStackされ実行される
----CharacterがDeathってるならそのFrameの終わりにInstanceが消滅する
----その他
------未定┗(^o^ )┓三
--衝突、Characterの挙動はBox2Dが全部面倒見てくれます


【恒例の進行具合SS】


敵の体力ゲージ作ったらAoE放つともりもり減ってんぎもぢぃいいいい。

【確認されている不具合】
敵が200体ぐらいいると超重い。
プレイヤー発見した状態で毎F敵同士密着しながら接近してくると50体でも重い。

あと、Box2D側の不具合(?)かどうかは分からないけど、b2_staticBody上になんらかのb2_dynamicBodyをめり込んだ状態で生成してしまうと、以降全てのb2_dynamicBodyがisBullet=true状態でもめりこみまくりーの状態になる。ただし、普通はこの不正な場所への生成自体がなされないんだけど、一度に沢山生成するとたまに失敗するっぽい。

2012年2月20日月曜日

簡単なUIができた


今回はBox2DではなくほとんどDxLibを触っていた。

左右の赤(Health)と青(Power)の円アイコンの増減は、残量に応じてマスクを移動させた後、中身を埋めた円を描画することで実装。

それより小さな円アイコンは
a. 割り当てたスキルの画像
b. スキルの再使用時間
c. 利用回数制限があるスキルはその残り利用回数
…を表示

ウィンドウの大きさを可変にしたいので、画像の大きさも可変にする必要がある。ただ、b.(円グラフ)を表現するためにDxLib::DrawCircleGaugeっていう便利な関数を使いたかったが、これの引数のグラフィックハンドルは既に適切な大きさになっている必要がある。画像を拡大縮小して描画する関数にDxLib::DrawExtendGraphがあるが、DxLib::ExtendGraphCircleGauge関数なるものは存在しないので、DxLib::MakeScreenを使ってサイズを拡大/縮小したアイコン用のグラフィックハンドルを作ってから、DxLib::DrawCircleGaugeで描画している。

DrawCircleGaugeは三角形の組み合わせを描画することで実現している模様。
ちなみにそのままではこの関数で矩形を描画することはできない。

作ってから思ったのだけど、銃本体をスキル扱いにしてしまっているので、今の仕様だと左手にマシンガン、右手にショットガン、残りスキルスロットにも重火器スキルを設定すると、スキルスロットの数だけ武器が同時発射可能になってしまう。
色々バランスが崩壊することが予想されるので、”装備している武器を使う”スキルとして実装する必要がありそう。さらに、スキルの再使用時間以外にの追加のパラメータとしてスキル使用後の硬直(他のスキルも使用できない)時間を設定する必要もあるか。

次回更新までに、スキルの種類増やしつつその辺を補強しようと思います。

2012年2月17日金曜日

UI作成中

HUDと言うのだろうか、よくわからない。
Hellgateの配置をそのまま参考にしている。

これを前提に設計されていなかった事による作業量の意外な多さと、マスク関係の難しさと、体調の悪さによりほとんど進んでいない。

とりあえずHealthとPowerの数字抜き版のみを表示。少し透過させるのが好み。

Hellgateのそれに加えて、残弾数表示と、再使用時間の表示をLoL風にする予定。ゲージを時計回りに増減させて表示するのって、三角形を組み合わせてマスキングしていく方法でいいのだろうか。負荷高そうなんだけどw

2012年2月14日火曜日

敵の動きの追加

最も単純なAIを実装した。

【アルゴリズム】
a.敵プレイヤー間の距離が一定の範囲内である
b.敵プレイヤー間に射線が存在する(間に壁が無い)
・条件aかつbを満たした時、敵はプレイヤーに向かって移動する

敵をすり抜けられないので、敵の移動速度が速いとあっさり囲まれる
条件aの実装は割と簡単。b2Distance関数に両者の座標を入れるだけ。
条件bの調査にはb2WorldクラスからRayCast関数を呼べばいいのだけど、その引数のb2RayCastCallbackクラスがちょっとやっかい。

いつか書いたb2QueryCallbackクラスと同様にb2RayCastCallbackクラスはインターフェイスなので、自前でMyRayCastCallbackクラスを書く必要がある。



この純粋仮想関数は、b2WorldのRayCastから呼ばれると始点から終点にかけてb2Fixtureを発見する度に呼ばれる。つまりループに組み込まれるのである。ループを終わらせたい場合は0.0fを戻し、走査を続けたい場合は0.0fより大きい正の数(普通は1.0f)を戻せばいい。条件bのようなことをしたい場合は、RayCast関数の始点終点を敵とプレイヤーに設定し、ReportFixture関数の引数に壁オブジェクトが含まれることがあるかどうか調べればいい。
大体そんな感じで実装した。

ただ、奇妙な問題が発生した。上の画像のものは両者間の距離が最短5.0m~最長50.0mの範囲にあるときに接近する、と設定したのだけど、実際はかなり密着している。これは外側の敵が内側の敵を押し込んでいるためである。

ただの赤丸でしかない敵だけど、動きを加えたらなんだか可愛く思えてきた今日この頃。

AoEの実装

範囲攻撃を1つ実装した。
大した内容ではないのにやたら大変だった。

クリック後、その地点を中心に攻撃範囲が描画される。
しばらくすると攻撃判定が発生する。しばらくすると自動で消える。


【範囲攻撃】
クリック後、任意の時間経過後、クリック地点から任意の範囲に任意の期間攻撃判定を与え続けるもの。
【追加で必要になったもの】
①ゲーム内時間の管理
②時間をトリガーにして発動する処理
③接触している限り攻撃判定を出し続ける処理

①に関しては既に雛形があったのでそのままクラス化した。
②は既存の処理と整合性をとるのが面倒だった。色々書き直した。
③はb2ContactListenerは接触開始と、接触終了しか教えてくれないので、その間の処理を自分で書く必要がある。Bulletは連続hitしてほしくないが、AoEは連続hitするものもあるので場合分けが必要。
更に言うと、物理接触は無いけど攻撃判定はあるっていうのが面倒だった。

結局全パターンあるということか。

別の話。
Orc Must Dieが今までプレイした何かに似ていると思ったらテクモの影牢シリーズの蒼魔灯だった。あのゲーム、今思えばかなりの良作だった。攻撃面(罠)の種類や強化手段が多いので、敵をどう倒そうかとゆっくり考えてる時間が楽しめた。ただ、血と断末魔の表現が苦手だったので1週しかしなかったな。

2012年2月12日日曜日

散弾銃っぽいの実装した


前回b2Filter設定したので一度に沢山の弾が出せるようになった。上画像は16発に拡散したもの。
そのままだと、近距離で密集した敵を蹴散らすには物足りなかったので、貫通オプションと反射オプションを実装。近距離では弾が貫通する、みたいに設定するといい感じ。反射は自殺してるようにしか見えないので微妙(笑)

反射は単純な接触カウントと、前回当たったオブジェクトかどうかの判定のみで実現している。
貫通は上に加えて、接触対象が敵の場合、弾側は物理衝突の影響を受けない、とした。
普通にゲーム作ったら反射の方が複雑そうなのに、物理エンジンの上だと貫通の方が特殊だという事例。

b2ContactLisner使っている限りは連続Hitしないので、現状「前回当たったオブジェクト かどうかの判定」はいらないのだけど、弾に当たった敵が弾より速い速度でふっ飛んだりするとアウトなので、とりあえず付けた。便利そうなので親クラスに持たせてもいいかもしれない。


以下、その他の話題。

Googleのスタイルガイドが大変参考になります。C++は色々ハマりやすい言語らしいので、迷ったときはここの規約に従っておけ!ってなるのがすごく楽。親→子とするのにdynamic_castを使いそうになったけど、設計に問題がある可能性があると言ってくれているので省みるきっかけになりました。

あと、ETERNAL CITY 2とがOrc Must Dieが気になってる。目指したいノリとして結構近いのでどっちかプレイしてみようかな。商業の壁に心折れてしまうかもしれないけどw

2012年2月10日金曜日

進捗まとめ動画


進んでいるような後退しているような(笑)
密着かつ同時破壊はくっそ重いという、処理落ち動画。

多分、破壊表現はリアルタイムで処理すると低スペックPCはフリーズするかも。
雰囲気とノリで付けただけなのですぐ剥がす。
GPUが演算してくれるグラフィックにしよう。


今後の方針

・プレイヤーのアクションを増やす
弾幕バリエーションだったり、AoEだったり、何か攻撃的なスキルだったり

・敵を動かす
処理の限界を知る上では先にやったほうがいいかもしれない

・リソースは自作しない
グラフィックと音楽のセンスが致命的に無いので、それらは借りるか買う。
つまり、しばらく画面に劇的な変化は無いだろう。

・エフェクト知識を充実させる
ゲームの気持ち良さはエフェクトと音と操作性が8割占めると思う。
自作はしないだろうけど、利用できるくらいまでは知っておこう。

・C++の知識
細かいことで悩む回数が減ってきたので作業スピードを意識してみる。

2012年2月8日水曜日

ゲームのデータをどう扱うか

ゲームのデータを全部実行ファイルに入れるのではなく、必要なときだけ読み込んで使いたい。
あわよくば書き出しもしたい。
どうするか。

予想されるデータ群。

 ・ステージの情報   : 地形、敵の沸き
 ・キャラクターの情報 : プレイヤー、敵、弾、壁
 ・道具の情報     : アイテム、武器、スキル
 ・描画の情報     : (どこに紐付けるんだろう…)
 ・セーブファイル   : ユーザーの進行状況、環境設定情報


後でどうとでもなるようにする、と連呼してきたので、資源が充実しているXMLを使ってみようと思う。
html分かればすぐ使える…よね?

名前をつけておけばいつでも引っ張り出せるのは楽しそうだ。まだ良く分からないけど。

2012年2月7日火曜日

セミコロンがないだけで3時間も悩んだ

T/O

…で済む話だけどあまりにf***************kなので後世に語り継ごう。


Visual C++ 2010でのお話。
コンパイルするとこんなエラーが出た
error C2236: 予期しない'class' 'b2Body'です。';' が入力されていることを確認してください。
エラーにしたがって";"セミコロンの欠如を全力で探すべき。素直に。
間違ってるのは前方宣言とかテンプレート引数じゃないよ!!
…と、当時の自分に伝えたい。

具体的にはエラーが出たファイル自体じゃなくて、インクルードしたヘッダで宣言されたクラスのセミコロンが抜けてたりした。


でも、おかげで前方宣言の知識が強化されてファイル間の依存関係が若干減った。
そんなことより早く完成させるべきなのだが…。

2012年2月2日木曜日

色んな物体を自由に生成できるクラスを製作中

まだDxLibで描画できたよー、ってだけのレベルです。

テストコード(スパゲティ関数郡)書いて、テスト。
後で読めるようにクラス化して、テスト。
機能追加するために構成変えて、テスト。
あとで変更しやすいように書き直して、テスト。

確実に進んではいるのだけど、わりとまったり速度です。

今は色んな物体を自由に生成できるクラスを製作中。
Factory Classって言うのだろうか。

早く動かしたいなー。