2Dオーディオは特定の位置から発せられない無方向性の音であり、3D空間におけるリスナーの位置や方向に関係なく一定の音を保ちます。これは、プレイヤーが環境内でリスナーを動かしても、どこを向いているかにかかわらず、常に2Dオーディオが聞こえることを意味します。
ジンジャーブレッドハウス - スタート .rbxl ファイルを出発点として、ジンジャーブレッドハウス - 完全なオーディオを参照として使用することで、このチュートリアルでは、ループする2Dオーディオとワンショットの2Dオーディオを体験に追加する方法を示します。以下のガイダンスが含まれています:
- プレイヤーがサーバーに接続するとすぐに再生されるループするバックグラウンドミュージック。
- プレイヤーのゲームプレイの目的に応じて即時のフィードバックを提供するためのオーディオトリガー。
- 様々なユーザーインターフェイスの相互作用を示すために異なる音を発動させること。
プロセスの途中で行き詰まった場合は、ジンジャーブレッドハウス - 完全なオーディオを参照として使用して、自分の進捗を比較できます。
2Dオーディオオブジェクト
無方向性オーディオを作成するには、このチュートリアル全体で作業するオーディオオブジェクトを理解することが重要です。2Dオーディオに対する主なオーディオオブジェクトは3種類あります:
- AudioPlayerオブジェクトはオーディオファイルをロードして再生します。
- AudioDeviceOutputオブジェクトは、スピーカーやヘッドフォンなど、現実世界の物理的ハードウェアデバイスです。
- Wiresは、オーディオストリームをあるオブジェクトから別のオブジェクトへと運びます。
これらのすべてのオーディオオブジェクトは、ファイル再生から各プレイヤーのハードウェアへの音を運ぶために協力して機能します。ここで、ラップトップを使用して体験をプレイしているプレイヤーがヘッドセットを着用している例を見てみましょう:
- AudioPlayerは通貨購入音のために127645268874265オーディオアセットIDを体験にロードします。
- AudioDeviceOutputオブジェクトは、プレイヤーの物理的スピーカー、またはこの場合彼らのヘッドフォンに音を運びます。
以下のセクションでは、これらのオブジェクトについて深く掘り下げながら、ループする2Dオーディオとワンショットの2Dオーディオを再生する方法を学ぶにつれて、これらのオブジェクトへの言及が含まれています。これらのオブジェクトを今後のテクニックで確認しながら、体験からプレイヤーへサウンドをキャプチャしてフィードする方法をより正確に予測できます。
ループオーディオ
ループする2Dオーディオ、つまりプレイヤーがサーバーに接続するとすぐにシームレスに繰り返される無方向性オーディオは、プレイヤーが行っていることや3D空間内でどこにいるかに関わらず、調和のとれた聴覚の背景を提供するための一般的なサウンドデザイン技術です。さらに、ループする2Dオーディオは、体験が完全に静寂になることは決してないことを保証します。それはプレイヤーを混乱させ、目標からそれる原因になる可能性があります。
この概念を示すために、以下の2Dオーディオがどのように危険な宇宙ステーションサンプルの質を大幅に向上させるかを確認してください。バックグラウンドミュージックがない場合、宇宙ステーションは空虚で生気がありません。しかし、宇宙ステーションにバックグラウンドミュージックが含まれると、宇宙ステーションは不気味で危険な印象を与え、全体的に不気味な雰囲気を高めます。
ループオーディオは、プレイヤーが自分の体験に参加した瞬間にどのように感じてほしいかを作り上げるために特に役立ちます。たとえば、サンプルは冬のワンダーランドでの楽しい冒険を提供することを目指しているため、環境に入った瞬間から彼らの気分にポジティブな影響を与えるために、元気なオーディオトラックを使用しています。この技術がどれほど影響力があるかを理解するために、ループオーディオをメタルトラックに置き換えた場合、プレイヤーの体験がどのように変わるかを考えてみてください。
サンプルジンジャーブレッドハウス - 完全なオーディオプレースファイルでループする2Dオーディオを再現するには:
プレイヤーキャラクターに接続されているデフォルトリスナーを有効にします。
- Explorerウィンドウで、SoundServiceを選択します。
- Propertiesウィンドウで、DefaultListenerLocationをCharacterに設定します。体験を実行すると、エンジンが自動的にSoundServiceの下にAudioDeviceOutputを作成します。
ExplorerウィンドウでSoundServiceに移動し、次に:
- AudioPlayerオブジェクトを挿入してオーディオソースを作成します。
- AudioDeviceOutputオブジェクトを挿入して体験全体で再生されるスピーカーを作成します。
- Wireオブジェクトを挿入して音声プレーヤーからスピーカーにストリームを運びます。

AudioPlayerを選択し、次にPropertiesウィンドウで、
- AssetIDをrbxassetid://1841461968に設定して元気なオーディオトラックを再生します。
- Loopingを有効にしてオーディオがシームレスに繰り返されるようにします。
- Volumeを0.2に設定して、他のオーディオソースをまだ聞くことができる低い音量でオーディオを再生します。
Wireを選択し、次にPropertiesウィンドウで、
- SourceInstanceを新しいAudioPlayerに設定して、この特定のオーディオプレーヤーから音声を運ぶように指定します。
- TargetInstanceを新しいAudioDeviceOutputに設定して、この特定のスピーカーに音声を運ぶように指定します。
Explorerウィンドウに戻り、AudioPlayerにScriptを挿入し、名前をLoopBackgroundMusicに変更し、RunContextプロパティをClientに設定し、次のコードをスクリプトに貼り付けます:
local audioPlayer = script.ParentaudioPlayer:Play()コードの説明このスクリプトは、スクリプトの親AudioPlayerを表す変数を宣言することから始まります。スクリプトは、プレイヤーが体験に参加した瞬間から退出する瞬間まで、オーディオソースを再生するように設定します。
体験をプレイテストしてループするバックグラウンドミュージックを聞きます。
ワンショットオーディオ
ワンショット2Dオーディオ、または特定の時間と位置で一度再生される無方向性オーディオは、プレイヤーが見逃したくない重要なコンテキストを提供します。この種の聴覚フィードバックをあなたの体験に使用することは重要です。なぜなら、それはボス戦の開始や大きな量の健康を失った時など、重要なゲームプレイ機能やプレイヤーの行動に対する即時の明確な反応を提供するからです。
次のセクションでは、プレイヤーがタイムリーで無方向性のフィードバックを必要とする一般的なゲームプレイシナリオ、つまりゲームプレイのフィードバック、UIエレメントのインタラクション、チュートリアルのためのボイスオーバーのナレーションについての実装の詳細を提供します。
ゲームプレイフィードバック
プレイヤーがあなたの体験を進むにつれて、スコア、健康、レベルの進捗状況など、ゲームプレイに影響を与えるものの状態について即時の聴覚フィードバックを受けることが重要です。この種のオーディオはプレイヤーの目的に直接関連しているため、これらの音は明瞭で聞き取りやすく、有用で正確な情報を伝える必要があります。
この概念を示すために、プレイヤーがジャンプしてコインを収集する際に再生される、プラットフォーマーテンプレートからの以下のワンショット2Dオーディオを確認しましょう:
- プレイヤーがデバイスでジャンプキーを押すとすぐにエアリーなウィッシュ音が鳴ります。
- プレイヤーのキャラクターがコインに触れるとすぐに高音の「ディング」とコインがジャストリングする音が鳴ります。
これらの音は3D空間内で即座に認識可能であり、視覚的な手がかりのみを頼りにすることなく、プレイヤーが自分の行動の成功を理解するのに役立ちます。
複数の音を同時に再生する場合、プレイヤーが聞く必要がある特定の音が他の音よりも重要になることがあります。この場合、コイン収集音はジャンプ音よりも価値のあるゲームプレイ情報を伝えています。そのため、体験はそれを少し高い音量で再生します。ただし、優れたミックスを達成するための基準やルールはありませんので、あなたの体験のサウンドが最も重要だと感じるものを反映するように調整してください。
たとえば、サンプルには体験のさまざまなオーディオトリガーが含まれていますが、すべてが体験の主な目的である:ジンジャーブレッドハウスを開くためのガムドロップを収集することの理解には同じ重要度ではありません。プレイヤーが何をすべきかを認識できるようにするために、サンプルはプレイヤーがガムドロップを集めるたびに聴覚フィードバックの振幅を3倍にします。
サンプルジンジャーブレッドハウス - 完全なオーディオプレースファイルでワンショットステートフィードバックオーディオを再現するには:
Explorerウィンドウで、Workspace ⟩ Gumdrops ⟩ Gumdropに移動し、次に:
- AudioPlayerオブジェクトを挿入してオーディオソースを作成します。
- AudioDeviceOutputオブジェクトを挿入して体験全体で再生されるスピーカーを作成します。
- Wireオブジェクトを挿入して音声プレーヤーからスピーカーにストリームを運びます。

AudioPlayerを選択し、次にPropertiesウィンドウで、
- AssetIDをrbxassetid://9113723699に設定して穏やかな噛む音トラックを再生します。
- TimePositionを0.15に設定してオーディオトラックを実際の噛む音により近い位置から開始します。
- Volumeを3に設定して、体験内の他のオーディオソースよりもガムドロップの音がはっきり聞こえるように、高い音量でオーディオを再生します。
Wireを選択し、次にPropertiesウィンドウで、
- SourceInstanceを新しいAudioPlayerに設定して、この特定のオーディオプレーヤーから音声を運ぶように指定します。
- TargetInstanceを新しいAudioDeviceOutputに設定して、この特定のスピーカーに音声を運ぶように指定します。
Gumdropを複製して、3つのガムドロップを持つようにし、環境中に散らばらせます。
Explorerウィンドウに戻り、ServerScriptServiceに移動し、Scriptを挿入し、名前をGumdropServiceに変更し、RunContextプロパティをServerに設定し、次のコードをスクリプトに貼り付けます:
-- サービスの初期化local Workspace = game:GetService("Workspace")local Players = game:GetService("Players")local ServerStorage = game:GetService("ServerStorage")local TweenService = game:GetService("TweenService")-- モジュールlocal Leaderboard = require(ServerStorage.Leaderboard)local PlayerData = require(ServerStorage.PlayerData)-- 変数local gumdropsFolder = Workspace.Gumdropslocal gumdrops = gumdropsFolder:GetChildren()local GUMDROP_KEY_NAME = PlayerData.GUMDROP_KEY_NAMElocal GUMDROP_AMOUNT_TO_ADD = 1local function updatePlayerGumdrops(player, updateFunction)-- ガムドロップテーブルを更新local newGumdropAmount = PlayerData.updateValue(player, GUMDROP_KEY_NAME, updateFunction)-- ガムドロップリーダーボードを更新Leaderboard.setStat(player, GUMDROP_KEY_NAME, newGumdropAmount)-- プレイヤーが三つのガムドロップを収集したかを確認if newGumdropAmount >= 3 then-- プレイヤーが三つのガムドロップを収集した際にドアイベントのオーディオを再生local audioPlayer = Workspace.Door.AudioPlayeraudioPlayer:Play()-- ドアを下に移動させるアニメーションを実行local doorPart = Workspace.Doorlocal tweenInfo = TweenInfo.new(2, Enum.EasingStyle.Linear)local tween = TweenService:Create(doorPart, tweenInfo, {Position = doorPart.Position + Vector3.new(0, -15, 0)})tween:Play()endend-- イベントハンドラの定義local function onGumdropTouched(otherPart, gumdrop)if gumdrop:GetAttribute("Active") thenlocal character = otherPart.Parentlocal player = Players:GetPlayerFromCharacter(character)if player then-- プレイヤーがガムドロップに触れたlocal audioPlayer = gumdrop.AudioPlayeraudioPlayer:Play()gumdrop.Transparency = 1gumdrop:SetAttribute("Active", false)updatePlayerGumdrops(player, function(oldGumdropAmount)oldGumdropAmount = oldGumdropAmount or 0return oldGumdropAmount + GUMDROP_AMOUNT_TO_ADDend)endendend-- イベントリスナーの設定for _, gumdrop in gumdrops dogumdrop:SetAttribute("Active", true)gumdrop.Touched:Connect(function(otherPart)onGumdropTouched(otherPart, gumdrop)end)endコードの説明スクリプトは、Workspace、Players、ServerStorageおよびTweenServiceサービスを初期化し、それらの子供と機能を参照できるようにします。その後、LeaderboardおよびPlayerDataモジュールをServerStorageから要求し、これらのモジュールはプレイヤーが環境で集めたガムボールの数を追跡するリーダーボードを画面の右上に作成および更新する役割を果たします。
スクリプトのupdatePlayerGumdrops関数は、プレイヤーがガムドロップを収集するたびにリーダーボードを更新し、全てのガムドロップを収拾する瞬間を待機し、その際にジンジャーブレッドハウスのドアのための位置オーディオとアニメーションをトリガーする大部分を担当します。このスクリプトのこの部分についての詳細は、3Dオーディオの追加 - イベントフィードバックを参照してください。
スクリプトのonGumdropTouched関数は、ゲームプレイフィードバックのための2Dオーディオをトリガーするための作業が行われる場所であり、二つの引数を取ります:
- otherPart - ガムドロップと衝突するパーツ。
- gumdrop - ガムドロップを表す球体のパーツ。
ガムドロップパーツに何かが衝突すると、スクリプトは最初にガムドロップがアクティブかどうかを確認します。もしアクティブであれば、現在衝突しているオブジェクトがプレイヤーであることを確認します。そうすれば、スクリプトは次のようにします:
- オーディオプレーヤーから2Dオーディオトラックを再生します。
- ガムドロップを透明にします。
- プレイヤーが透明なガムドロップと相互作用できないようにガムドロップを非アクティブにします。
- ガムドロップに触れたプレイヤーのためにリーダーボードを更新します。
最後に、スクリプトは、各ガムドロップに対して関数をTouchedイベントに接続して、プレイヤーがガムドロップに触れたときにonGumdropTouched関数を呼び出すようにイベントリスナーを設定します。
体験をプレイテストしてガムドロップを収集した後に咀嚼音を聞きます。
UIインタラクション
プレイヤーがチェックボックスの上をホバリングしたり、購入ボタンを選択したりするなどのユーザーインターフェイス(UI)要素とインタラクションする際、それに対する即時のフィードバックを提供することが重要です。そうすることで、彼らは直感的にどのようにそれらのUIと相互作用しているのかを理解できます。たとえば、多くのデザイナーは、プレイヤーが設定を有効または無効にする際にUIの視覚的特性を変更して、設定の状態を伝えます。
ただし、色の変化やアニメーションが自力で解読するのが難しい視覚的障害者のプレイヤーにとっては、できるだけ多くのプレイヤーにインターフェースがアクセスしやすく直感的であるようにするために、UIインタラクションのために複数の感覚フィードバックを提供することが有用です。この概念を深掘りするために、UGCホームストアテンプレートの購入ボタンにとって重要な以下のUI状態を考えてみましょう:
- フォーカス中 - プレイヤーがUI要素を選択する準備としてハイライトしています。
- ホバー中 - プレイヤーがカーソルでUI要素の上をホバリングしています。
- 選択済み - プレイヤーが入力を通じてUI要素を選択しました。
これらの3つのインタラクションは、プレイヤーがアバターの衣類やアクセサリをブラウズし、選択し、購入するためのテンプレートの主要なユーザーフローにとって必須であるため、誰もがUIとどのように相互作用するかについて混乱しないようにすることが最も重要です。成功するためにプレイヤーに設定するために、テンプレートは各UIインタラクションのために視覚的および聴覚的なフィードバックの両方を提供します。




複数の感覚フィードバックの形式を設定する方法の例を挙げると、サンプルではプレイヤーが画面上のペパーミントボタンを押すたびに、視覚的および聴覚的なフィードバックの両方を提供します。プレイヤーがボタンと相互作用していないとき、ボタンは典型的なペパーミントキャンディのように見えますが、ボタンを押すと、サンプルは:
- 楽しいジングルのオーディオトラックを再生します。
- ボタンにティールの色合いを付けます。
- 画面上でボタンをわずかに下に移動させます。
ここから、このインタラクションをメニューを開いたりアイテムを購入したりするなどの有用なゲームプレイアクションに接続できます。


サンプルジンジャーブレッドハウス - 完全なオーディオプレースファイルでワンショットUIインタラクションオーディオを再現するには:
Explorerウィンドウで、StarterGui ⟩ 2DAudioButtonに移動し、次に:
- AudioPlayerオブジェクトを挿入してオーディオソースを作成します。
- AudioDeviceOutputオブジェクトを挿入して体験全体で再生されるスピーカーを作成します。
- Wireオブジェクトを挿入して音声プレーヤーからスピーカーにストリームを運びます。

AudioPlayerを選択し、次にPropertiesウィンドウで、AssetIDをrbxassetid://3422389728に設定してレトロなジングルのオーディオトラックを再生します。
Wireを選択し、次にPropertiesウィンドウで、
- SourceInstanceを新しいAudioPlayerに設定して、この特定のオーディオプレーヤーから音声を運ぶように指定します。
- TargetInstanceを新しいAudioDeviceOutputに設定して、この特定のスピーカーに音声を運ぶように指定します。
Explorerウィンドウに戻り、2DAudioButtonにLocalScriptを挿入し、名前をPlayAudioWhenPressedに変更し、次のコードをスクリプトに貼り付けます:
local TweenService = game:GetService("TweenService")local buttonGui = script.Parentlocal buttonImageButton = buttonGui.ButtonFrame.ButtonImageButtonlocal buttonAudioPlayer = buttonGui.AudioPlayerlocal tweenInfo = TweenInfo.new(.2, Enum.EasingStyle.Exponential)local buttonTweenByIsPressed = {-- 押下[true] = TweenService:Create(buttonImageButton, tweenInfo, {Position = buttonImageButton.Position + UDim2.fromScale(0, .1),ImageColor3 = Color3.fromRGB(117, 255, 255),}),-- デフォルト[false] = TweenService:Create(buttonImageButton, tweenInfo, {Position = buttonImageButton.Position,ImageColor3 = Color3.fromRGB(255, 255, 255),}),}local function onIsPlayingChanged()local isPlaying = buttonAudioPlayer.IsPlayinglocal tween = buttonTweenByIsPressed[isPlaying]tween:Play()endonIsPlayingChanged()buttonAudioPlayer:GetPropertyChangedSignal("IsPlaying"):Connect(onIsPlayingChanged)buttonAudioPlayer.Ended:Connect(onIsPlayingChanged)buttonImageButton.Activated:Connect(function(_hit)buttonAudioPlayer:Play()end)コードの説明スクリプトは、次の項目を取得することから始まります:
- UI要素をアニメートするためのTweenService。
- スクリプトの親である2DAudioButton ScreenGuiオブジェクト。
- ペパーミントキャンディ ImageButton。
- ジングルオーディオトラックを含む関連するオーディオプレーヤー。
スクリプトはさらに、以下を定義します:
- ボタンのアニメーションが指数関数的なアニメーションスタイルで再生されることを指定したTweenInfoオブジェクト。
- ボタンが押下された状態または未押下の状態を表す二つのTween。
- trueの押下状態は、ボタンをわずかに画面の下に移動させ、ティールの色合いで着色します。
- falseの未押下状態は、ボタンを画面上の元の位置に戻し、以前の色合いを取り除きます。
スクリプトの残りの部分は、2D UIインタラクションフィードバックをトリガーするために行われる作業の大部分であるため、onIsPlayingChanged関数とイベントリスナーがUIユーザーフローのためにどのように連携しているかを確認しましょう:
- buttonImageButton.Activatedは、プレイヤーがボタンをクリックするのを待機し、クリックが発生した場合に関連するオーディオプレーヤーから音声を再生するためにPlay()関数を呼び出します。このプロセスにより、AudioPlayer.IsPlayingプロパティがfalseからtrueに切り替わります。
- buttonAudioPlayer:GetPropertyChangedSignal("IsPlaying")は、オーディオプレーヤーのIsPlayingプロパティの変更を待機し、その後onIsPlayingChanged関数を呼び出します。
- onIsPlayingChanged関数はこの情報を用いて、画面上での視覚的表現を変更するTweenをトリガーします。
- プレイヤーがボタンを連続してクリックした場合、オーディオを誤って再スタートさせないために、buttonAudioPlayer.Endedはオーディオプレーヤーが再生を終了したことを待ち、その後再びonIsPlayingChanged関数を呼び出します。
注意が必要なのは、onIsPlayingChangedイベントはfalseからtrueに変化したときのみ発火し、trueからfalseに変化したときには発火しないことです。これは、サーバーからクライアントへのプロパティの複製タイミングによる問題のために意図された動作です。このため、この例では両方のケースをカバーするために、Endedイベントが提供されてリッスンされています。
体験をプレイテストして、画面上のボタンを押すたびにジングルを聞きます。