始める
中級者向けチュートリアル

3D オーディオの追加

*このコンテンツは、ベータ版のAI(人工知能)を使用して翻訳されており、エラーが含まれている可能性があります。このページを英語で表示するには、 こちら をクリックしてください。

3D オーディオ は、3D 空間の特定の位置から発生する方向性のある音で、オーディオエミッターとリスナーの間の距離と方向に応じて音量が増減します。これにより、リスナーやエミッターが環境内を移動する際、プレイヤーは異なる方向と音量レベルからオーディオを動的に聞くことができます。

Gingerbread House - Start .rbxl ファイルを出発点として使用し、Gingerbread House - Complete Audio を参照として、このチュートリアルでは、ループする3Dオーディオとワンショット3Dオーディオを経験に追加する方法を示します。具体的には以下の内容についてのガイダンスが含まれます:

  • プレイヤーがサーバーに接続した瞬間に再生されるループ環境音。
  • プレイヤーのゲームプレイにとって重要な状況イベントについて知らせるためのオーディオのトリガー。
  • プレイヤーが3Dオブジェクトとインタラクトしたときに聴覚的フィードバックを提供するためのオーディオのアクティベーション。
  • キャラクターの音声サンプルを再生し、プレイヤーを環境内の注目ポイントに導く。

プロセスのどの時点で行き詰まった場合でも、あなたの進捗を比較するために Gingerbread House - Complete Audio を参照することができます。

オーディオオブジェクト

方向性のあるオーディオを作成するには、このチュートリアルで使用するオーディオオブジェクトを理解することが重要です。3Dオーディオ用には主に6種類のオーディオオブジェクトがあります:

  • AudioPlayer オブジェクトは オーディオファイル をロードして再生します。
  • AudioEmitter オブジェクトは 3D 環境にオーディオを発信する 仮想スピーカー です。
  • AudioListener オブジェクトは 3D 環境からオーディオを受信する 仮想マイク です。
  • AudioDeviceOutput オブジェクトは、スピーカーやヘッドフォンなどの現実世界の 物理ハードウェアデバイス です。
  • AudioDeviceInput オブジェクトは現実世界に存在する 物理マイク です。
  • Wires は、オーディオストリームを1つのオブジェクトから別のオブジェクトに運びます。

これらすべてのオーディオオブジェクトは、実世界の対応物のように音を発生させるために連携して動作します。次の例を使って、プレイヤーがノートパソコンで体験をプレイする際にヘッドセットを装着しているときに、どのように機能するかを見てみましょう:

  • AudioPlayer は、雨のトラック用に 1516791621 オーディオアセットIDを体験にロードします。
  • AudioEmitter は、3D環境に雨のトラックオーディオのストリームを発信します。
  • Wire は、AudioPlayer から AudioEmitter へのストリームを運び、ストリームが3Dスピーカーから出力されるようにします。
  • キャラクターの子である AudioListener オブジェクトは、3D 環境内でその音を聞き、それをヘッドセットに返します。
  • AudioDeviceOutput オブジェクトは、AudioListener からプレイヤーの物理スピーカー、あるいはこの場合、ヘッドフォンへサウンドを運びます。
  • AudioDeviceInput オブジェクトは、実世界からの音をキャプチャし、ボイスチャットのために体験にフィードバックします。
体験内のオブジェクト表現
現実世界のオブジェクト表現

次のセクションでは、これらのオブジェクトを利用してループとワンショットの3Dオーディオを再生する方法を詳細に紹介します。これからの技術を使ってこれらのオブジェクトを確認していくことで、体験からプレイヤーへ音をキャプチャし供給する方法をより正確に予測できるようになります。

ループオーディオ

ループする3Dオーディオ、またはプレイヤーがサーバーに接続した瞬間に途切れることなく繰り返される方向性のあるオーディオは、3D空間の雰囲気を向上させるための一般的なサウンドデザイン技法です。この手法により、環境音源を一貫性のあるものに保つことができます。たとえば、テレビの静止音や滝の轟音などです。これらの音が突然消えると、環境は非現実的に感じられます。

この概念を示すために、次の3Dオーディオが2つの大きな滝の音が未ループのオーディオトラックが完了するとすぐに停止する様子を確認してください。水の音は最初はプレイヤーを屋外の環境に没入させますが、突然の音が変化すると、滝が実世界であるかのように行動するのが不自然で衝撃的になります。

この技術を使用して流れるチョコレートの滝でのサンプルは、プレイヤーのオーディオエミッターからの距離に応じて音量を調整します。プレイヤーが20スタッド未満の距離にいると、エミッターは全音量で音を発信します。プレイヤーがさらに離れると、音がエミッターから20スタッド離れるごとに徐々に音量が減少します。これは、実世界の音がソースから遠ざかるほど音量が下がることを模倣しています。

サンプルの Gingerbread House - Complete Audio プレースファイルでループする3Dオーディオを再現する方法は次の通りです:

  1. プレイヤーキャラクターに接続されているデフォルトリスナーを有効にします。

    1. Explorer ウィンドウで SoundService を選択します。
    2. Properties ウィンドウで DefaultListenerLocationCharacter に設定します。体験を実行すると、エンジンは自動的に以下のことを行います:
      • 各プレイヤーキャラクターの Humanoid.RootPart の下に AudioListener を作成して、体験内のサウンドソースの位置とスケールに応じて、実際のスピーカーからの音がどのように移動するかを感知できるようにします。
      • SoundService の下に AudioDeviceOutput を作成します。
  2. Explorer ウィンドウで WorkspaceWaterfallAudioObjectに移動し、次を行います:

    1. AudioPlayer オブジェクトを挿入して、滝の音源を作成します。
    2. AudioEmitter オブジェクトを挿入して WaterfallAudioObject から位置ストリームを発信します。
    3. オーディオプレイヤーからオーディオエミッターにストリームを運ぶために Wire オブジェクトを挿入します。
  3. AudioPlayer を選択し、Properties ウィンドウで、

    1. AssetIDrbxassetid://1516791621 に設定して、雨のオーディオトラックを再生します。
    2. オーディオが途切れることなく再生されるように Looping を有効にします。
  4. AudioEmitter を選択し、Properties ウィンドウで DistanceAttenuation{0: 1}, {20: 0.8}, {40: 0.4}, {80: 0} に設定して、音が20スタッドごとに音量が徐々に減少するようにします。

  5. Wire を選択し、Properties ウィンドウで、

    1. SourceInstance を新しい AudioPlayer に設定して、この特定のオーディオプレイヤーからオーディオを運ぶためにワイヤが必要であることを指定します。
    2. TargetInstance を新しい AudioEmitter に設定して、この特定のオーディオエミッターにオーディオを運ぶためにワイヤが必要であることを指定します。
  6. Explorer ウィンドウに戻り、WaterfallAudioObjectScript を挿入し、名前を LoopWaterfallMusic に変更して、RunContext プロパティを Client に設定し、次のコードをスクリプトに貼り付けます:


    local audioPlayer = script.Parent
    audioPlayer:Play()

    スクリプトは、スクリプトの親である AudioPlayer を表す変数を宣言することから始まります。スクリプトは、プレイヤーが体験に参加している瞬間から体験を退出するまで、オーディオソースを再生するように設定します。

  7. 体験をプレイテストして、アバターが滝の近くにいるときにループするチョコレート雨の音を聞きます。キャラクターの頭を回して別の方向を見ると、音が3D空間内のエミッターの位置に応じて実際のスピーカーで動的に変化します。

ワンショットオーディオ

ワンショット3Dオーディオ、または特定の時間と位置で一度再生され、プレイヤーが再度トリガーしない限り何度も発生する方向性のあるオーディオは、プレイヤーに自分の行動、環境、および周囲のキャラクターについてのコンテキストを提供します。この種の聴覚フィードバックをあなたの体験の中で使用することは非常に重要です。これにより、プレイヤーは敵から避けたり、有用なアイテムを拾ったりするなどの戦略的な決定を下すことができます。

次のセクションでは、プレイヤーにタイムリーで方向性のあるフィードバックが必要な一般的なゲームプレイシナリオについての実装詳細を提供します。これには、状況ゲームプレイイベント、オブジェクトの相互作用、および非プレイ可能キャラクターのダイアログが含まれます。

イベントフィードバック

プレイヤーが新しいゲームプレイエリアをアンロックしたり敵の攻撃を促したりするなど、環境内で重要な状況イベントを引き起こす際には、3D空間のどこに焦点を合わせる必要があるのかを理解することが不可欠です。即座に聴覚フィードバックがなければ、プレイヤーはゲームプレイに重要な情報を見逃してしまい、次にどこに行けばよいのかわからずにフラストレーションを感じるかもしれません。

これがなぜ重要かを示すために、各プレイヤーのブラスターから再生される Laser Tag テンプレートのワンショット3Dオーディオを確認してみましょう:

  • プレイヤーがブラスターから発射するたびに深いポップ音が鳴ります。
  • プレイヤーが新しい弾薬でブラスターをリロードするたびにカチッという音とロボットのビープ音が鳴ります。

これらの音はすべて、近くのプレイヤーに発射音がどこから来ているかを知らせ、彼らが楽しみに加わるべきか、潜在的な危険を避けるべきかに関する情報を提供します。

このサンプルは、プレイヤーが体験内でメインの目的を達成したことに対して報酬を得たことを知らせるための状況認識を提供するために、この技術を使用しています。全ての3つのガムドロップを集めると、ジンジャーブレッドハウスのドアが開いて、内部のプレゼントにアクセスできるようになります。

プレイヤーがガムドロップを集める必要がある特定の順番がないため、プレイヤーが最も最後に集めたガムドロップに関係なく、ドアが開くことを認識できることが重要です。位置音はこれを可能にし、プレイヤーがあなたの成功を意識し、次にどこに行く必要があるかを理解できるようにします。

サンプル Gingerbread House - Complete Audio プレースファイルでワンショットイベントフィードバック3Dオーディオを再現する方法は次の通りです:

  1. Explorer ウィンドウで WorkspaceDoor に移動し、次を行います:

    1. 音源を作成するために AudioPlayer オブジェクトを挿入します。
    2. Door から位置ストリームを発信するために AudioEmitter オブジェクトを挿入します。
    3. オーディオプレイヤーからオーディオエミッターにストリームを運ぶために Wire オブジェクトを挿入します。
  2. AudioPlayer を選択し、Properties ウィンドウで AssetIDrbxassetid://5930776613 に設定して、スライディングメタルゲートオーディオトラックを再生します。

  3. Wire を選択し、Properties ウィンドウで、

    1. SourceInstance をあなたの新しい AudioPlayer に設定してこの特定のオーディオプレイヤーからオーディオを運ぶことを指定します。
    2. TargetInstance をあなたの新しい AudioEmitter に設定してこの特定のオーディオエミッターにオーディオを運ぶことを指定します。
  4. 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.Gumdrops
    local gumdrops = gumdropsFolder:GetChildren()
    local GUMDROP_KEY_NAME = PlayerData.GUMDROP_KEY_NAME
    local GUMDROP_AMOUNT_TO_ADD = 1
    local function updatePlayerGumdrops(player, updateFunction)
    -- ガムドロップテーブルを更新
    local newGumdropAmount = PlayerData.updateValue(player, GUMDROP_KEY_NAME, updateFunction)
    -- ガムドロップリーダーボードを更新
    Leaderboard.setStat(player, GUMDROP_KEY_NAME, newGumdropAmount)
    -- プレイヤーが3つのガムドロップを集めたかチェック
    if newGumdropAmount >= 3 then
    -- プレイヤーが3つのガムドロップを集めたときにドアイベントオーディオを再生
    local audioPlayer = Workspace.Door.AudioPlayer
    audioPlayer:Play()
    -- ドアを下にアニメーションさせる
    local doorPart = Workspace.Door
    local tweenInfo = TweenInfo.new(2, Enum.EasingStyle.Linear)
    local tween = TweenService:Create(doorPart, tweenInfo, {Position = doorPart.Position + Vector3.new(0, -15, 0)})
    tween:Play()
    end
    end
    -- イベントハンドラの定義
    local function onGumdropTouched(otherPart, gumdrop)
    if gumdrop:GetAttribute("Enabled") then
    local character = otherPart.Parent
    local player = Players:GetPlayerFromCharacter(character)
    if player then
    -- プレイヤーがガムドロップに触れた
    local audioPlayer = gumdrop.AudioPlayer
    audioPlayer:Play()
    gumdrop.Transparency = 1
    gumdrop:SetAttribute("Enabled", false)
    updatePlayerGumdrops(player, function(oldGumdropAmount)
    oldGumdropAmount = oldGumdropAmount or 0
    return oldGumdropAmount + GUMDROP_AMOUNT_TO_ADD
    end)
    print("プレイヤーがガムドロップを収集しました")
    end
    end
    end
    -- イベントリスナーを設定
    for _, gumdrop in gumdrops do
    gumdrop:SetAttribute("Enabled", true)
    gumdrop.Touched:Connect(function(otherPart)
    onGumdropTouched(otherPart, gumdrop)
    end)
    end

    このスクリプトは、WorkspacePlayersServerStorage、および TweenService サービスを初期化し、それらの子と機能を参照できるようにしています。次に、LeaderboardPlayerData モジュールを ServerStorage から要求します。これらのモジュールは、プレイヤーが環境において収集したガムボールの量を追跡するための画面の右上隅にガムドロップリーダーボードを作成し更新する責任があります。

    スクリプトの updatePlayerGumdrops 関数は、イベントフィードバックのための3Dオーディオをトリガーする仕事の大部分を行い、次の2つの引数を取ります:

    • player - ガムドロップを収集したプレイヤー。
    • updateFunction - プレイヤーの収集したガムドロップ量を更新するコールバック関数。

    プレイヤーがガムドロップと衝突する際、スクリプトは以下のことを行います:

    • PlayerData.updateValue 関数を呼び出し、プレイヤーの新しいガムドロップ収集量の値を取得します。
    • Leaderboard.setStat 関数を呼び出してこの新しい量でリーダーボードを更新します。
    • その量が 3 以上かをチェックします。

    この値が 3 以上であれば、スクリプトは以下を行います:

    • オーディオエミッターからオーディオプレイヤーの3Dオーディオトラックを再生します。
    • ドアを現在の位置から直線的に 15 スタッド下に移動させます。

    スクリプトの残りは、収集フィードバックのためにオブジェクトに衝突したものがプレイヤーであるかどうかを検出する役割を担っています。スクリプトのこの部分に関する詳細については、Add 2D audio - Gameplay feedback を参照してください。

  5. 体験をプレイテストして、環境内のガムドロップをすべて集めた後にスライドゲートの音を聞きます。カメラを回すと、音は3D空間内のエミッターの位置に応じて実際のスピーカーで動的に変化します。

オブジェクトの相互作用

プレイヤーがスイッチを入れたり武器を拾ったりするなど、環境内の3Dオブジェクトに相互作用する際には、フィードバックを提供することが重要です。これにより、プレイヤーがオブジェクトとの相互作用の方法を直感的に理解できるようになります。視覚的および聴覚的なフィードバックがペアになって、プレイヤーのアクションと環境の反応の間の因果関係を強化します。

この概念を拡張するために、キャベツを栽培するためのユーザーフローのために Plant サンプルからの次のワンショット3Dオーディオを確認しましょう:

  • プレイヤーが種を植えるときに優しいカチッという音が再生されます。
  • プレイヤーが成長中の植物に水をやるときに濡れた水音が再生されます。
  • プレイヤーが完全に成長した植物を収集するときにカチッという音が再生されます。
  • プレイヤーがキャベツをワゴンに置くときに柔らかい衝撃音が再生されます。

これらの音はすべて、プレイヤーの proximity prompt 主要インタラクションにおいて、3D空間内のオブジェクトが形を変えることを強調しています。視覚に障害のあるプレイヤーにとって、色の変化やアニメーションが自分自身だけでは解読しにくい場合、これらの複数の感覚フィードバック形式を提供することで、3Dオブジェクトの相互作用ができるだけ多くのプレイヤーにとってアクセス可能で直感的であるように保ちます。

オブジェクトの相互作用に、複数の感覚フィードバックを使った異なる例を示すために、サンプルはプレイヤーがジンジャーブレッドハウス内の3Dペパーミントボタンを踏んだときに視覚的および聴覚的フィードバックの両方を提供します。プレイヤーがボタンと相互作用していないときは、典型的なペパーミントキャンディのように見えますが、ボタンを踏むと、サンプルは:

  • お祝いのジングルオーディオトラックを再生します。
  • ボタンの側面を緑色にトーンします。
  • ボタンを地面に押し込みます。

ここから、このインタラクションをアイテムのロック解除や特別な能力のトリガーなど、さまざまなユニークなゲームプレイアクションに接続できます。

デフォルトビュー
押された状態

サンプル Gingerbread House - Complete Audio プレースファイルでワンショットオブジェクトインタラクション3Dオーディオを再現する方法は次の通りです:

  1. Explorer ウィンドウで Workspace3DAudioButton に移動し、次を行います:

    1. ボタンの音源を作成するために AudioPlayer オブジェクトを挿入します。
    2. 3DAudioButton から位置ストリームを発信するために AudioEmitter オブジェクトを挿入します。
    3. オーディオプレイヤーからオーディオエミッターにストリームを運ぶために Wire オブジェクトを挿入します。
  2. AudioPlayer を選択し、Properties ウィンドウで AssetIDrbxassetid://1846248593 に設定して、お祝いの音楽トラックを再生します。

  3. Wire を選択し、Properties ウィンドウで、

    1. SourceInstance をあなたの新しい AudioPlayer に設定して、この特定のオーディオプレイヤーからオーディオを運ぶことを指定します。
    2. TargetInstance をあなたの新しい AudioEmitter に設定して、この特定のオーディオエミッターにオーディオを運ぶことを指定します。
  4. Explorer ウィンドウに戻り、3DAudioButtonScript を挿入し、名前を PlayAudioWhenPressed に変更して、次のコードをスクリプトに貼り付けます:


    local TweenService = game:GetService("TweenService")
    local buttonModel = script.Parent.Parent
    local buttonPart = buttonModel.ButtonPart
    local buttonPressedAudioPlayer = buttonModel.ButtonPressedAudioPlayer
    local tweenInfo = TweenInfo.new(.2, Enum.EasingStyle.Exponential)
    local buttonTweenByIsPressed = {
    -- 押されている
    [true] = TweenService:Create(buttonPart, tweenInfo, {
    Size = buttonPart.Size / Vector3.new(2, 1, 1),
    Color = Color3.fromRGB(75, 151, 75),
    }),
    -- デフォルト
    [false] = TweenService:Create(buttonPart, tweenInfo, {
    Size = buttonPart.Size,
    Color = Color3.fromRGB(196, 40, 28),
    }),
    }
    local function onIsPlayingChanged()
    local isPlaying = buttonPressedAudioPlayer.IsPlaying
    local tween = buttonTweenByIsPressed[isPlaying]
    tween:Play()
    end
    onIsPlayingChanged()
    buttonPressedAudioPlayer:GetPropertyChangedSignal("IsPlaying"):Connect(onIsPlayingChanged)
    buttonPressedAudioPlayer.Ended:Connect(onIsPlayingChanged)
    buttonPart.Touched:Connect(function(_hit)
    buttonPressedAudioPlayer:Play()
    end)

    スクリプトは、次のものを取得することから始まります:

    • 地面から出ているボタンのパーツにアニメーションを付加するための TweenService
    • スクリプトの親である 3DAudioButton モデル。
    • 地面から出ているボタンのパーツ。
    • お祝いのサウンドトラックが入ったオーディオプレイヤー。

    次に、スクリプトは以下を定義します:

    • ボタンのアニメーションが指数関数的なアニメーションスタイルで再生されることを指定する TweenInfo オブジェクト。
    • ボタンが押されているか、押されていないかの状態を表す2つのツイーン。
      • true 押下状態はボタンをわずかに下に押し込み、パーツの側面に緑色のトーンを付けます。
      • false アンプレッサー状態はボタンを元の位置に戻し、以前のトーンを取り除きます。

    スクリプトの残りはオブジェクト相互作用フィードバックの大部分が実行される場所であり、onIsPlayingChanged 関数とイベントリスナーがどのように連携するかをレビューしましょう:

    1. buttonPart.Touched はプレイヤーがボタンに触れたことをリスンし、その後、関連オーディオプレイヤーからオーディオを再生するために Play() 関数を呼び出します。このプロセスにより、AudioPlayer.IsPlaying プロパティが false から true に切り替わります。
    2. buttonPressedAudioPlayer:GetPropertyChangedSignal("IsPlaying") はオーディオプレイヤーの IsPlaying プロパティが変更されることをリスンし、onIsPlayingChanged 関数を呼び出します。
    3. onIsPlayingChanged 関数はこの情報を使用して、3D空間内における視覚的な外観の切り替えをトリガーします。
    4. プレイヤーがボタンに急速に飛び乗った場合にオーディオを偶発的に再起動しないようにするために、buttonPressedAudioPlayer.Ended はオーディオプレイヤーが再生を終了するのをリスンし、onIsPlayingChanged 関数を再度呼び出します。

    onIsPlayingChanged イベントは、プロパティが false から true に変更されたときのみ発火することに注意してください。これは、サーバーからクライアントへのプロパティの複製のタイミングに関する複雑さを考慮した意図された動作です。このため、この例では、両方のケースをカバーするために Ended イベントが提供され、リスンされています。

  5. 体験をプレイテストして、ジンジャーブレッドハウスにある3Dボタンに触れるとお祝いの音が聞こえるのを確認してください。ボタンから離れると、音の音量が減少します。

キャラクターダイアログ

非プレイ可能キャラクター (NPC) からの方向性のあるオーディオを提供することは、プレイヤーを環境内の注目ポイントに導いたり、他のキャラクターとの相互作用に深みを与えたりするのに役立ちます。実際、物語主導の体験において、多くのデザイナーはキャラクターダイアログを戦略的に使用して、プレイヤーに自分のキャラクター、味方や敵のキャラクター、または世界自体について間接的に教えることがあります。

この技術の一般的な例は以下の通りです:

  • ダイアログスタイル で体験のトーンを設定します。
  • バンター でキャラクター間の関係をプレイヤーに教えます。
  • 敵の会話 でプレイヤーに対する動機や自分の位置を告白します。
  • プレイヤーキャラクターが思ったことを声に出して話す ことで、プレイヤーに次に何をすべきか(自分を回復する、別の場所に移動する、アイテムを見つけるなど)を優しく導きます。
  • 味方キャラクターがプレイヤーキャラクターに話しかけ、体験内の世界の詳細(歴史、文化、社会問題)を明らかにします。

実際にどのように見えるかを示すために、以下のワンショット3Dオーディオを確認しましょう。Beyond the Dark ショーケースで、プレイヤーが宇宙ステーションのメインロビーエリアにいるときに定期的に再生されます。

宇宙ステーションをキャラクターとして使用するこのダイアログクリップは、プレイヤーに全体の設定に関する重要なコンテキストやストーリーを提供します。例えば、この一文からプレイヤーは次のことを学びます:

  • 彼らは外宇宙にいて、特に Kerr-Newman Deep Space Relay 14 という名前の宇宙ステーションにいる。
  • 彼らの環境は未来的かつ迎合的である。
  • 彼らは訪問者であり、間もなく立ち去る可能性が高い。

これらの詳細は、プレイヤーをその環境に没入させ、彼らの任務に対する緊急感を加えます。しかし、プレイヤーが彼らの主な任務が何であるかを知らない場合、キャラクターダイアログを使用して、プレイヤーにあなたが彼らに体験内でやってほしいことを知らせることもできます。

例を示すと、サンプルでは、雪だるまの周りの3D空間のボリューム、または不可視の領域を使用して、プレイヤーに3つのガムドロップを収集させてその家のドアを開けるように案内します。プレイヤーが体験に参加するときに最初に見るものの1つとして、プレイヤーはダイアログをトリガーする可能性が高く、成功するために何をすべきかを知ります。

雪だるまの周りのボリュームが、プレイヤーが3D領域に入るとオーディオを再生するために衝突フィードバックを使用します。

サンプル Gingerbread House - Complete Audio プレースファイルでワンショットキャラクターダイアログ3Dオーディオを再現する方法は次の通りです:

  1. Explorer ウィンドウで WorkspaceDialogueVolume に移動し、次を行います:

    1. ボリュームのオーディオソースを作成するために AudioPlayer オブジェクトを挿入します。
    2. DialogueVolume から位置ストリームを発信するために AudioEmitter オブジェクトを挿入します。
    3. オーディオプレイヤーからオーディオエミッターにストリームを運ぶために Wire オブジェクトを挿入します。
  2. AudioPlayer を選択し、Properties ウィンドウで AssetIDrbxassetid://92917410841704 に設定して、体験の目的に関する指示音声トラックを再生します。

  3. Wire を選択し、Properties ウィンドウで、

    1. SourceInstance をあなたの新しい AudioPlayer に設定して、この特定のオーディオプレイヤーからオーディオを運ぶことを指定します。
    2. TargetInstance をあなたの新しい AudioEmitter に設定して、この特定のオーディオエミッターにオーディオを運ぶことを指定します。
  4. Explorer ウィンドウに戻り、StarterPlayerStarterCharacterScripts に移動して LocalScript を挿入し、名前を PlayAudioWhenInVolume に変更し、次のコードをローカルスクリプトに貼り付けます:


    local Workspace = game:GetService("Workspace")
    local Players = game:GetService("Players")
    local humanoid = script.Parent:WaitForChild("Humanoid")
    local volumeDetector = Workspace.DialogueVolume
    local trigger = humanoid:WaitForChild("Animator")
    local debounce = false
    local localPlayer = Players.LocalPlayer
    volumeDetector.Touched:Connect(function(hit)
    if debounce then
    return
    end
    local hitCharacter = hit:FindFirstAncestorWhichIsA("Model")
    local hitPlayer = Players:GetPlayerFromCharacter(hitCharacter)
    if hitPlayer ~= localPlayer then
    return
    end
    debounce = true
    local audioPlayer = Workspace.DialogueVolume.AudioPlayer
    audioPlayer:Play()
    audioPlayer.Ended:Wait()
    debounce = false
    end)

    このスクリプトは、Workspace と Players サービスを取得して子や機能を参照できるようにします。各プレイヤーキャラクターが体験にロードまたはリスポーンするとき、スクリプトは以下のものを待機します:

    • キャラクターの Humanoid および Animator オブジェクト。
    • ワークスペース内にある DialogueVolume という名前のボリュームオブジェクト。

    何かがボリュームと衝突すると、Touched イベントハンドラ関数は、ボリュームに衝突した BasePart がキャラクターモデルの子孫である場合、それに対応する Model を最初の祖先として取得します。もしそれがそうなら、関数は次の操作を行います:

    • debounce を true に設定します。
    • オーディオを再生し、オーディオが終了するのを待ちます。
    • debounce を再び false に設定します。

    debounce を false から true に設定し、オーディオが再生が終了した後に再び false に戻すことで、プレイヤーがボリュームと衝突し続けるときにオーディオが再度トリガーされるのを防ぐパターンです。 debounce パターンの詳細については、Debounce - Detect collisions を参照してください。

  5. 体験をプレイテストして、雪だるまの周りのボリュームにタッチしたときに指示するキャラクターダイアログが聞こえるのを確認してください。

©2026 Roblox Corporation。Roblox(ロブロックス)、RobloxロゴおよびPowering Imaginationは、米国並びにその他の国における登録商標および非登録商標です。