何かが起こったときに音を鳴らす良い方法は?この音はどうですか?


10

だから私は自分のクラスがどれだけモノリシックになるかを考えていました。たとえば、CharacterクラスのJumpメソッドでは、サウンドエフェクトオブジェクトへの参照があり、それを再生できます。それ自体は問題ありませんが、物理学、アニメーション、衝突などを考慮に入れると、Jumpメソッドは巨大になり、Characterクラスには多くの異なるものへの多くの依存関係があります。それでも、これで問題ない可能性があります。ただし、キャラクターがジャンプしたときにサウンドを再生したくない場合はどうすればよいでしょうか。さて、コードのごちゃごちゃした混乱の中から特定のコード行を見つけてJump、コメントアウトするか、何でもしなければなりません。

それで..と思っていました。

代わりに、ある種のAudioSystemクラスがあり、他のクラスに関心のあるランダムなイベントをサブスクライブした場合はどうなるでしょうか。たとえば、クラスにはメソッド内のクラス内で発生CharacterするJumpedイベント(静的だと思います)があるかもしれませんCharacter。次に、Characterクラスは、キャラクターがジャンプしたときに再生される小さな音響効果について何も知りません。これAudioSystemは、静的イベントを使用してゲーム内で発生する特定のイベントでサウンドエフェクトをフックするためにプログラマが後退できる巨大なクラスです。その後、それはのようなサブクラスにして分離することができ大きすぎるなった場合はEffectsAudioSystemBackgroundAudioSystemAmbientAudioSystem、エトセトラ。

次に、ゲームのオプションで、これらの種類のサウンドを有効または無効にするチェックボックスを設定できます。実行する必要があるのは、単純な単一のブールフラグでその1つのシステムを無効にすることだけです。このシステムの考え方は、物理学、アニメーションなどにも拡張でき、プレーヤーのアクションから生じるゲームの応答のほとんどが、これらの精巧で分離されたシステムを通じて接続されます。

さて、私の質問は少しあいまいかもしれませんが、この種のことはどのように聞こえますか?このようなシステムについては、これまであまり話を聞いたことがありません。これは、今のところコーディングがまったく行われていないので、頭の中で問題になっているので、おそらく「理論的には良いが実際にはない」種類の取引の1つでしょう。この種のシステムは、より大きなゲームで機能するのでしょうか、それとも最終的に故障して、元のシステムよりもさらにスパゲッティの混乱になるのでしょうか?


5
健全なアイデアのように聞こえます:)(より深刻な注意:疎結合サブシステム/クラス間の通信にメッセージを使用することは、一般に設計的には良いアイデアです)
bummzack

1
これがどのように行われるかです。まだレンダリングしていない場合は、レンダリングを別のクラスにも配置する必要があります(Characterクラスにdraw()関数を含めないでください)。
dreta

回答:


2

メッセージはデバッグして維持するのが大変です。理論上は良さそうに聞こえますが、実際に実行すると、大量の重複データが送信されて混乱します。ジャンプ音の効果には、最後に多くのデータが必要になります。たとえば、位置、速度、キャラクターがいるマテリアル、名前を付けると、リストは最後に長くなります。

したがって、このデータを収集して、データがコピーされた非常に具体的なイベント/メッセージを介してAudioManagerに送信するか、メッセージ内の文字への参照を送信して、AudioManagerがデータにアクセスできるようにする必要があります。方法が乱雑になり、オーディオマネージャはマテリアルアンダーグラウンドなどのサウンドを選択する必要があります。

したがって、最後に、特定のイベント(このメッセージのみの非常に特定のクラス)がこれらのクラスを非常に深く結合します。あまり勝てず、最後には、データを送信する目的のみで機能する非常に具体的なイベント/クラスの乱雑な大きなリストが表示されます。これは、すでに存在し、古くなっており、重複データの他のすべての問題の影響を受ける可能性があります。 。

したがって、維持する必要のない不要なクラスの膨大なリストが存在し、キャラクターとAudioManagerの間に深い結合が導入されますが、ソースコード全体に分散している点が異なります。CharacterクラスとAudioManagerクラスだけではありません。

それでもコードを分離するのは良い考えですが、メッセージは実際には深い結合のもう1つの方法にすぎません。一部のコードは結合する必要があるだけであり、最も直接的な方法を使用して結合し、過度に設計しないでください。


1
うまく設計されたメッセージングシステムは、「密結合のもう1つの方法」であるか。メッセージの送信は、オブジェクトが通信することがない絶対的な最小のカップリングです。あなたがそれを設計した方法は問題を引き起こすかもしれませんが、システムが音、場所、タイプのみを取り込む場合、それは彼のすべての問題を解決し、あなたが提案する問題のどれも生じないかもしれません。オーディオシステムは、必要なサウンドを計算してはならず、すべての設定を抽象化し、できれば拡散の問題を抽象化する必要があります。)en.wikipedia.org/wiki/Coupling_(computer_programming
ClassicThunder

1
@ClassicThunder要点は、実際にはこのアプローチはあまりうまく拡張できないことです。単純なアプリケーションに適していますが、必要なのは一般的なPlaySoundEventだけです。しかし、問題はAudioManagerが特別なOnJump()イベントをリッスンすることです。そのため、キャラクターはオーディオワークを取り除くことができます。ただし、これは単純なPlaySoundEventには当てはまりません。これは、キャラクターがサウンドを選択してそれをAudioManagerに送信する必要があるため、OnJumpEventを導入してオーディオ作業を取り除く本来のポイントが無効になるためです。
Maik Semder

1
ただし、OnJumpEventを使用する場合は、キャラクターへの参照をイベントに追加するか、すべての重要なデータをキャラクターからイベントにコピーするかを選択できます。もちろん、あなたは正しいです。後者は深い結合を導入しませんが、他のすべての新しいイベントと同様に、データ複製の問題と、維持する必要がある新しいデータ受け渡しオブジェクトの影響を受けます。
Maik Semder

1
-1原因:メッセージを非常に特殊化(OnJump)することはおそらく悪い考えですが、これは、名前をとるPlaySoundイベントを作成するのに役立つ情報ではなく、長い「これは悪い考えではありません」です。効果音とそれが発生した3D位置および/または音量の
ジェームズ

@James氏、入力ありがとう。PlaySoundイベントを使用するつもりはありませんでした。つまり、イベントはGUIデータベースアプリケーションの優れた抽象概念ですが、複雑なゲームには実用的ではないということです。
Maik Semder

2

メッセージパッシングシステムがエンジニアリングを超えているとは思いません。実際、研磨段階での作業を劇的に簡単にすることができます。あなたはそれを正しくやっています!

あなたが説明したのは、去年私がGlobal Game Jamゲームのために一緒に投げたものです。私はSFXの作成と編集を担当し、自分と他の作曲家がゲームに書き込んだ音楽を、やりがいのない方法で統合しました。

オーディオの観点から見たこのアプローチの優れている点は、サウンドを使って多くの興味深いことを実行できることです。ゲームの効果音が単なるサウンドファイル、音量、およびパンであると考えている場合、それは間違っています。

私たちのゲームでは、あなたは惑星に走る宇宙船を飛んでポイントを獲得する恐竜でした。私たちはFlashで作業していたので、データ駆動型インフラストラクチャは必要ありませんでした。AudioManagerは、ゲームイベントに応答して発生するサウンドを制御することを唯一の目的とする一連の静的メソッドで構成されるクラスでした。

もしそれをC ++で書くとしたら、サウンドが持つ可能性のあるすべての振る舞いを抽象化するのにもう少し時間がかかっただろう。アクションが発生したことをシステムに通知するメッセージの要件は、それほど複雑ではありません。メッセージの種類、影響を受けるオブジェクトまたは影響を受けるオブジェクト、ある種のゲーム状態コンテキストへのアクセスなどが必要になるだけです。プロトコルは、ゲームのニーズの増大に応じて増大する可能性があります。当然のことながら、これらすべてをコードで実装する場合(お粗末なGGJコードのように)、モノリシッククラスの問題が悪化します。しかし、それはデータ駆動型システムを作ることによって簡単に軽減されます。

とにかく、ゲームのオーディオシステムがさまざまなメッセージにどのように反応したかを次に示します。

  • プレイヤーが惑星と衝突する:これは十分基本的な惑星爆発音を引き起こします。次に、実行中のコンボカウンターを照会します。もしそれが十分に高ければ、それは恐竜が勝利の轟音を鳴らしてから0.5秒ほど後に再生されるように効果音を予定するでしょう。また、バックグラウンドでランダムな惑星の人口値が計算されました(600から3000のようなものです-なぜその範囲が選択されたかはわかりませんが、それは放棄されたゲームプレイメカニックであり、オーディオを面白くするために使用するためにまだ横たわっていました)、そして、私はそれを使用して、悲鳴の遠くの音の音量をスケーリングしました(惑星の市民が早すぎる運命に出会う)。

  • プレイヤーは加速のためにスペースバーを押し続けます:これを受け取ると、小さな「わーい」スラスターサウンドが再生されましたが、同時に、低ループのエンジンの轟音が1.5秒を超えて増加しました。パーティクルシステムはこれを使用してエミッタIIRCを発射しました

  • プレーヤーがスペースバーを離して減速する:プレーヤーがスペースバーを離したので、オーディオシステムは、エンジンループを元に戻す必要があることに気付きました。もっと時間があったら、その上に別の音を重ねてみたいと思います。

  • プレイヤーが邪悪な宇宙鉱山と衝突する:宇宙鉱山は悪いので、爆発と組み合わされた金属製の衝撃音(1つの音に焼き付けられるだけ)だけでなく、ランダムに選択された恐竜の不快な音も再生されます。プレイヤーの健康状態が低下するにつれて、より「泣く」ような音を選択する可能性が高くなります。

すでに楽しいゲームは、サウンドトラックがアクティブでダイナミックなときに、上で説明したような単純なビヘイビアーが少しでもある場合でも、プレイする楽しみになります。はい、正しいデータが渡されることを確認するために解決するいくつかのロジスティクスがあります。でもねえ、BFD。ゲームコードのより大きな範囲で記述する必要がある最も複雑なものからはほど遠いでしょう。

実際、FMODとWwiseはこのように機能します。中央のメッセージディスパッチャーはありませんが、中央システムに効果的にイベントをポストし、オーサリングツールのオーディオインプリメンターによって事前に設計されたサウンドエフェクトを再生することで反応します。あなたのゲームにライブDJを与えるようなものだと考えてください。彼は座って何が起こっているのかを観察し、サウンドクリップを適切なタイミングでトリガーして物事を面白く保ち、それらをミキシングして既存のオーディオ環境にうまく適合させます。

[編集]また、このC#にタグを付けたようです。これはXNAですか、それともXACTを使用していますか?XNAを使用している場合は、XACTを使用する必要があります。


1
これは小さなプロジェクトでうまくいくかもしれませんし、楽しいかもしれません。ただし、大きなクラスでは、維持する必要のある膨大な数のメッセージクラスが作成されますが、単純な関数呼び出しでも同じ効果が得られます。そのため、イベントシステムが適切に拡張されず、プロジェクトが大きくなると管理が難しくなります。
Maik Semder

1
ところで、私のスタジオではFMODを使用しています。メッセージ/イベントシステムはなく、イベントをFMODに送信せず、C関数またはC ++メソッドを呼び出して何かを再生します。彼らは単に彼らの音を「イベント」と呼んでいます、それはそれをイベントシステムにしません、それは彼らが音の代わりに彼らが使う言葉です。
Maik Semder

いいえ、なぜですか。イベントを使用してパラメーターを渡す代わりに、関数を直接呼び出すだけです。イベントは、最後に関数を呼び出すものであり、直接渡すのではなく、イベントオブジェクトでパラメーターを渡すだけです。唯一の違いは、イベントシステムによって導入された新しい間接化ですが、最終的には単純な関数呼び出しであり、不必要に過度に複雑になっています。
Maik Semder

@MaikSemderどうやってメソッド呼び出しが自分の絡み合ったわいせつなウェブにならないのですか?また、イベントシステムと、WwiseおよびFMODで使用される「イベント」の違いを書き留めておきました。私が考えているのは、複雑なオーディオロジックはゲームオブジェクトクラスに属さないということです。また、インターフェースがイベントのディスパッチに似ているようにサウンドロジックを抽象化すると、リッチなオーディオロジックを簡単に作成できます。私は本当に少しの間で機能的な違いを参照EventManager->dispatch("Sound:PlayerJump")してをsoundSystem->playFMODEvent("/MyGame/Player/Jump")
michael.bartnett

2
コーディングが簡単になるというメリットがあるかもしれませんが、無料ではありません。パフォーマンス、メンテナンス、およびデバッグのコストが高くなります。私の要点は、大きなプロジェクトにとってメリットは価値がないということです。あなたはイベントなしよりもはるかに多くのオブジェクトを扱っており、その代償を払わなければなりません。メッセージシステムの使用を検討する唯一の場所は、スレッド間の通信がスレッド間のロックを防ぐためです。
Maik Semder 2012

0

私はMaik Semderに同意します。メッセージパッシングシステムは、(とにかく今のところ)過剰に設計されている可能性があるということです。

私が理解しているところによると、あなたのクラスは現在、ここの「モノリシッククラス」に見られるように、ビョルンの「モノリシッククラス」のように見えます

その記事を読むことをお勧めします。今のところ、完全なコンポーネントシステムはやり過ぎですが、「残りの部分を分割する」に目を通すと、動作を抽象化して最終的にはより複雑な方法に移行できるはずです。解決。それはあなたにとにかく始めるのに良い基盤を与えるでしょう。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.