|
NaGu-Ru開発もいよいよ大詰め(ほんとか?)に入ってきました。
しかし、「敵がアホ」、具体的には単発攻撃しかしないので、
妙によわっちいし面白くもないということで、連続攻撃をさせることにしました。
いわゆる「こんぼ」ってやつですかね。
(実は、今までのNaGu-Ruで「敵が強い」というのは
「攻撃間隔が短い」とかそんな単純なことだったりする.....) 「コンボ」の考え方は非常に簡単です。 攻撃の一つ一つをつなげていったものがコンボなんですから。 つまり、攻撃ひとつをしおえたら、次の攻撃を行う。 たった。これだけなんですよね。 たいてい、攻撃が終わる、というのはアニメーションが終わる、ってことなので アニメーションが終わったときに、つづけて攻撃するようにしていけばいいだけです。 さて、プログラムを組むことになりますが、 コンボの長さが固定ではおもしろくないし、制限が出てきますね。 そういうわけで、長短さまざまなコンボを実現するために、TListを使うことにしました。 これに好きな数だけコンボデータ配列をぶち込んでやるわけです。 で、敵キャラクタはアニメーション終了時にそのコンボデータを読み取ったものから順番に消していき、 コンボデータがなくなったらコンボ終了、というわけです。 ちょっとした擬似的なコードを書いてみます。 var ComoboDataList:TList;
//コンボデータをセットする
procedure SetCombo(data:array of TComboData);
var i:Integer;
comboData:PComboData;
begin
//引数dataの全データをリストに追加する
for i:= Low(dat) to High(data) do begin
New(comboData); //メモリを確保
comboData^:=data[i]; //データをゲット
ComboDataList.Add(comboData); //データをリストに追加
end;
end;
//アニメーション終了時に呼び出される関数
procedure OnAnimationLoop;
var comboData:PComboData;
newdata:PComboData;
begin
if comboDataList.Count = 0 then Exit; //コンボデータがなくなったら何もしない
comboData:=ComboDataList[0]; //先頭のコンボデータをゲット
ComboDataList.Delete(0); //んでリストから削除
Dispose(combData); //メモリ開放
if comboDataList.Count = 0 then Exit; //コンボデータがなくなったら何もしない
newData:=ComboDataList[0]; //次のコンボデータをゲット
end;
こんな感じになると思います。
ポインタとか、メモリの確保とかが絡んでいるのでわかりにくいかも
しれませんが、やっていることは非常に単純です。アルゴリズムさえわかっていれば
それなりに読めると思います。それと、上記の「SetCombo」手続きで使われている、 「配列を関数に渡し、それをすべて読み込む方法」はこれ以外の場でも 多く流用できると思いますので、参考にしていただければ幸いです。 さて、実際に僕が作っているゲームでうまくいくかどうかを試してみたところ、 うまくいきました。そこで、調子に乗ってコンボデータを作っていろんなコンボを試していたら、 ある問題に遭遇しました。 どんな問題かというと、途中に攻撃以外のものをはさめないということです。 たとえば、NaGu-Ruの基本的なコンボとして、パンチX2、キックキックで敵を浮かして そこでジャンプして叩き落す、というのがあるんですが、このジャンプが問題なんです。 現在はアニメーション終了時に次のアニメーションをセットする、方法でコンボを実現していますが、 この方法だと、ジャンプは着地するまでアニメーションが続くために、着地後に 技を繰り出す、という変なものになってしまいます。つまり、ちょっとこったことをしようとすると アニメーション終了時に次のアニメーションをセットする方法では都合が悪いんです。 というか、悪かったんですよ。
というわけで、これを以下のように修正しました。 ちょっと文章で書くとわけわかんないので、コードを書いてみます。
//コンボの状態を管理する
procedure TEnemy.CheckComboState;
begin
//コンボデータがなければだめ
if ComboList.Count = 0 then Exit;
//攻撃中なら次の動作に移らない
if Attacking then Exit;
//プレーヤーに攻撃が当たるかをチェックする
if (NextIsAttacking)AND(not TryDstCheck) then begin
//ミスカウントが0のときに、ミスった時間をとっておく
if FMissCnt = 0 then FMissTime:=FrameTM;
Inc(FMissCnt);
Exit;
end;
//次のコンボデータを読み込む
ComboList.DelData(0);
if ComboList.Count = 0 then Exit;
//ミスったときから1秒以上ならコンボ失敗なのでコンボデータをクリアする
if (FMissCnt > 0)AND(FrameTM - FMissTime > 1000) then begin
ComboList.ClearAll;
end else begin
//それ以外ならコンボを続ける
doAction(ComboList.Data[0]);
FMissCnt:=0;
end;
end;
スパゲッティであるNaGu-Ruのコードの中でかなりきれいなほうです。
多分読めると思います...(たぶんね)。上の条件に加えて「コンボミス」を判定して
よりそれっぽくしてます。これで、敵が普通にコンボをかましてくれるようになりました(^^;)
もうこれで、思考ルーチンがへぼいなんていわせないぜ!!(<まだへぼいやん)
さぁ、みんなもれっつれっとこんぼ!!
|
※敵がアホ 安いゲームにありがちな「強い=反応速度が速い」という方程式の元 ゲームが作られていたためにおこった現象。格闘ゲームでこれをやると、 かなり面白くないものになる。幸いNaGu-Ruは複数の敵と戦うので、 ある程度ごまかしが効いていたのだ。
※アニメーション
※擬似的なコード
※ポインタ
※アルゴリズム
※TList
※High,Low関数
※リスト
※うまくいくかどうか
※都合が悪い
※コンボデータ
※ジャンプ
※フラグ
※FrameTM
※NextIsAttacking
※クリア
※スパゲッティ
※思考ルーチン
|