Redhuのゲーム開発Fragments

UnityやUEでゲームを作る際に学んだことを、これからなにか作りたい人に向けて。あるいは復習する自分に向けて記す。

自作ゲームリメイク中-エフェクト、サウンド編-(Unity制作)

前回>自作ゲームリメイク中-当たり判定・弾丸編-(Unity制作) - Redhuのゲーム開発Fragments


今回はエフェクトとサウンドについて書きたいと思います。
新たにブースター使用時、ブースター炎のエフェクトを発生させるようにしました。オーバーブースト時には追加でOB炎も同じく発生させています。

f:id:redhu:20150817115045p:plain

それらの処理を行うスクリプトを、ブースターボーンの箇所に、オーディオソースと一緒にセットしています。
通常ブーストで発生させる炎エフェクト、OBエフェクト、ブーストをふかしている時のSE、ブーストが起動するときのSE、OBが起動するときのSEですね。

エフェクト処理

Player Booster CtrlスクリプトはFPSInputControllerとPlayerMoveStatsを見て・・・つまり入力と機体の状況を見張っています。
移動してる時に、機体のブーストがONになっていて、このスクリプトでブースト状態判定がONになっていない(つまりブーストが起動した時)にブーストエフェクトを、同じようにOBエフェクトをInstantiateして即親子付けしてくっつけています。

さて、これでブーストを起動した時にエフェクトが生まれるようになりました。
しかしパーティクルの発生をLoopにしているので、ブースト使用を止めてもエフェクトは勝手に消えてくれません。またブーストを起動したら前は消えることなく新しいエフェクトが生まれてしまいます。

そこで、パーティクルオブジェクトひとつひとつにParticleDestroyスクリプトをセットして、エフェクトを消したいときに
BroadcastMessage("BoostParticleStop", SendMessageOptions.DontRequireReceiver);
などでParticleDestroy内のBoostParticleStop関数を起動し、MyParticleSystem.Stop();を使ってパーティクルの生成を止めます。
ブロードキャストメッセージは自身とその子への通知なので、さっきエフェクトオブジェクトを生成した後親子付けしたのが効きます。

アップデート関数で
if(!MyParticleSystem.IsAlive()){
Destroy(gameObject);
}
を使い、パーティクルが無くなったらそのオブジェクトを消すようにしているので、仕事の終わったパーティクルオブジェクトは次々消えていきます。

自分はこれに加えて、パーティクルオブジェクトを子に持つ親オブジェクトを用意しているので親オブジェクトに
if (this.transform.childCount <= 0) {
Destroy (gameObject);
}
をするスクリプトを設定して、子が居なくなったら消えるように仕込んでいます。
パーティクルオブジェクトはデフォで90度回転していたりするので、0,0,0の空オブジェクトに入れていると何かと楽なのです(プレハブ化した後子がひとつしか見えなくなるのが不便だけど)

サウンド

サウンドでは特にややこしいことしていません。
ただし、Unity5から(?)前まではAudioClipが2Dサウンドか3Dサウンドかの情報を持っていたのに対して、AudioSourceが2D/3Dの情報を持つようになりました。しかも2Dか3Dかの二択じゃなくて、スライダーで調節して「3D的に減衰するけどどこにいても最低限は聞こえる」とかみたいな半2Dサウンドみたいなものもできます。
このせいで旧作をUnity5に持ってきた時、ひとつのAudioSourceから機体の音とシステム音と出してたのが、システム音が不自然に3D的に聞こえたり・・・



そうそう、新たな仕組みとして AudioMixerというものがありました。
f:id:redhu:20150817121600p:plain

AudioSourceの音量設定グループ分けみたいなものができます。「このオーディオソースはSEグループの音量調整率を受ける」とか

f:id:redhu:20150817121819p:plain

ちゃんと分けておくと、後々オプション設定つくった時にマスターボリュームやBGMやSE、ボイスの個別音量調整とか楽にできそうな感じがあるのでしっかり設定しとこうと思います。

自作ゲームリメイク中-当たり判定・弾丸編-(Unity制作)

 

前回>自作ゲームリメイク中-ステータスとuGUIの連携編-(Unity制作) - Redhuのゲーム開発Fragments

 

前回からだいぶ時間が開いてしまいましが、動画のほうで進捗をあげてみました。

まずぱっと見で分かる変化。APの数値表示とENの残り%を表示するようにして、ゲージはそれぞれ1/4円表示にしました。開いてる下の円形部分は後々、左右武器のリロードタイム表示に使ったりなんかしようかと。

 

攻撃力を持つ弾丸、及びそれを飛ばしてくるオブジェクトをテストめいて配置しました。自機には当たり判定を実装。受けた弾丸の攻撃力と部位の防御力でダメージを算出する仕組みを入れました。

 

他にもエフェクトやサウンドとか色々やってますが、今回はこの、弾丸と当たり判定中心の記事です。

 

被弾側の当たり判定

f:id:redhu:20150816162611p:plainf:id:redhu:20150816162615p:plain

BoxColliderを、ボーンオブジェクトにつけて大雑把に当たり判定が取れるように形作ります。

当たり判定をつけたボーンオブジェクトのTagとLayerをそれぞれ、Parts,Unitと新しくつくって付けます。弾丸が当たる対象を決めるための判定に使います。

f:id:redhu:20150816164206p:plainf:id:redhu:20150816164724p:plain

 

実際に防御力とダメージを処理するのは根本のオブジェクトのParts_ArmorStatsです。弾丸から渡された威力を受け取り、自身の防御力でダメージを算出し、親であるPlayerオブジェクトのAP現在値を減少させます。

APを管理するのはUnitAPスクリプトとして独立させました。

子のParts_ArmorStatsと合わせて雑魚敵とかにも流用できるかなーって。

 

今回作っているゲームでは、攻撃力・防御力ともに「貫通」「衝撃」「熱量」の三属性を常に持ちます。受けたそれぞれの攻撃値をそれぞれの防御値で減衰した合計がダメージとなります。

 

 弾丸の当たり判定

結論からいうと、Collider(isTriggerで)を使うもののOnTriggerEnterとかは使わないちょっと特殊な判定をやってます。

理由としましては、通常のその方法だと弾速が速くなった場合に(Collision DetectionをContinuousにしようとも)物体を貫通してしまう自体が頻発したためです。

ついでに複数のパーツが隣接する場所に弾丸が当たった場合、1発の弾丸に複数部位が反応して多重ダメージを受けてしまうこともありました。

貫通防止したくてCollisionのサイズを大きくすると多重ヒットが発生する・・・

 

その解決策として

DontGoThroughThings - Unify Community Wiki

このスクリプトをお借りして少々改良を加えたものを使っています。

要するにrigidbodyの移動分Rayを飛ばして、高速時の物体貫通を防止するスクリプトといえばいいんでしょうか。これを弾丸オブジェクトにつけています。

コンポーネントとしてオブジェクトにつけると、Rayが感知するオブジェクトのLayer設定が項目が見えるので感知対象にさっきつくったUnitレイヤーを設定してあげます。

独自改造として、同じ弾丸オブジェクト内の弾丸スクリプト(BulletScript)を取得しておいて、Rayの当たり判定時に

BulletScript.TriggerEnter(hitInfo.Collider);

として、弾丸が何かに当たった時の処理を起動しています。

 

弾丸スクリプト

 長いですが

gistf848e237849bafd0cc42

publicなところは要するに

  • 自動消滅時エフェクト、ヒット時エフェクト
  • 貫通、衝撃、熱量攻撃力
  • 姿勢影響力を設定(防御側で未使用の項目)
  • 弾丸の速度
  • 弾道のバラけ度
  • 攻撃力が100%発揮される有効射程
  • 有効射程以上飛んだ時の威力減衰度
  • 弾丸のTrailエフェクト

ッて感じです(Listをpublicにする必要はあったのだろうか

 

弾丸が生成された瞬間、バラけ角度分だけランダムに向きを変え、弾速分の力をrigidbodyに加えてふっ飛ばしてます。有効射程を超えるまで重力の影響は受けず真っ直ぐ飛んできます。

発射音、着弾音はそれぞれ、発射するオブジェクト、ヒット時エフェクトが発生させるので弾丸では扱いません。

ヒット時エフェクトは、着弾判定が行われた場所ではなく、着弾対象となったオブジェクトの部位で発生させています(発生を判定場所にすると、貫通補正の判定時に貫通していた先でエフェクトが発生して違和感あるため)

 

あとは大体中のコメントに書いてあることをしているだけ。

ちょっとした工夫で、弾丸のTrailエフェクトを弾丸オブジェクトの子として持っておいて弾丸が消える直前に切り離しています。そうしないとTrailのエフェクトが着弾時に一気に消えるので、なんとなく違和感が出ます。

 

弾丸の攻撃力を伝えるためにSendMessageUpwardsを使っているのは、着弾箇所はあくまでパーツの部位になるからです。防御力・ダメージ処理を持つスクリプトはその根本のパーツになるためUpwardsで登って行ってもらってます。

(多分、親であるPlayerまでメッセージ行ってるけど対象関数持ってないからダイジョーブダイジョーブ)

 

 

弾丸と当たり判定はこんなかんじで実装しました。

色々説明不足かと思いますので何かあれば気軽にお聞きください。

 

次回>自作ゲームリメイク中-エフェクト、サウンド編-(Unity制作) - Redhuのゲーム開発Fragments

うに部屋さんに置かせて頂いているリメイク対象の旧作

unityroom.com