Audio3D
Uwagi na ten temat Wskazówki
Ten przykład jest oparty na programach opublikowanych w następujących witrynach. Zmieniam trochę kod, aby ułatwić zrozumienie i wyjaśnienie go po japońsku. Zasadniczo używamy oryginalnego kodu takim, jaki jest, więc jeśli faktycznie zaadaptujesz go w swoim programie gry, popraw go w odpowiednim czasie i użyj go.
- Strona referencyjna
Ponadto jest to wyjaśnione przy założeniu, że masz podstawową wiedzę na temat MonoGame i XNA. Zobacz MonoGame Tips i XNA Tips dla rumianych.
W szczególności, ponieważ matematyka, wektory, funkcje trygonometryczne, macierze itp. są niezbędne, więc proszę wiedzieć, czym one są do pewnego stopnia.
środowisko
- podest
-
- System Windows 10
- Kod może być używany na innych platformach obsługujących MonoGame
- Visual Studio
-
- Program Visual Studio 2019
- Platforma .NET Core
-
- 3.1
- MonoGame
-
- 3.8
Informacje o próbkach
Na podstawie położenia kamery można usłyszeć połączenie z pozycji psa i pozycji kota. Kot krąży i okrąża pochodzenie, a gracz może kontrolować pozycję kamery za pomocą. Upewnij się, że sposób, w jaki słyszysz dźwięk, zmienia się z każdą zmianą położenia kamery lub pozycji kota. Myślę, że łatwo zrozumieć używanie słuchawek. Jestem niepotwierdzony na kanale 5.1.
Jak obsługiwać
What's Do | Keyboard | Gamepad (XInput) | Mouse | Touch |
---|---|---|---|---|
Aparat do przodu i do tyłu | ↑↓ | Lewy drążek (górny i dolny) | - | - |
Zmiana orientacji kamery | ←→ | Lewy drążek (lewy i prawy) | - | - |
Koniec gry | Esc | Wstecz | - | - |
Co przygotować
- Plik audio pisku psa
- Trzy pliki audio piszczące koty
- Plik obrazu psa
- Plik obrazu kota
- Plik obrazu podłoża
Oryginalna próbka na oficjalnej stronie wykorzystuje wstępnie skompilowaną zawartość plików .xnb . Jeśli chcesz zachować próbki na oficjalnej stronie, nie używaj mgcbs, dodaj je bezpośrednio do rozwiązania Visual Studio i skopiuj je w czasie kompilacji.
Nie wiem, dlaczego oryginalna próbka przyjmuje tę metodę, ale myślę, że to prawdopodobnie dlatego, że migrujemy starsze wersje projektu. Oczywiście możesz użyć mgcb do wygenerowania tego samego pliku. Projekty, które można pobrać na tej stronie, zostały zmodyfikowane do wersji MGCB.
program
Pobierz program dla całego kodu.
Ten przykład został zaprojektowany, aby kod wyglądał nieco bardziej ogólnie, a jednocześnie sprawiał, że odtwarzanie dźwięku wyglądało dobrze w czasie wykonywania. Używanie tylko Audio3D byłoby znacznie mniejszym kodem, ale jest opisane w oryginalnym przykładzie. Zachowam mniej ważne części.
Projekt składa się z następujących plików kodu:
- Audio3DGame
- AudioManager
- Kot
- Pies
- IAudioEmitter
- Program
- QuadDrawer
- SpriteEntity
QuadDrawer klasa
Ta klasa jest klasą pomocniczą do rysowania prostokątnych wielokątów. Prostokątne wielokąty są często używane głównie do wyświetlania sprite'ów 3D (billboardów). Ta wskazówka jest używana do billboardów dla kotów i psów, a także do prostokątnych wyświetlaczy ziemi.
Ta klasa nie ma nic wspólnego z Audio3D.
pole
readonly GraphicsDevice _graphicsDevice;
readonly AlphaTestEffect _effect;
readonly VertexPositionTexture[] _vertices;
Minimum informacji wymaganych do rysowania wielokątów. Rysuj wielokąty z danych wierzchołków bez przygotowywania danych modelu.
konstruktor
<summary>
新しい四辺形の描画ワーカーを作成します。
</summary>
public QuadDrawer(GraphicsDevice device)
{
_graphicsDevice = device;
_effect = new AlphaTestEffect(device);
_effect.AlphaFunction = CompareFunction.Greater;
_effect.ReferenceAlpha = 128;
// 4つの頂点の配列を事前に割り当てます。
_vertices = new VertexPositionTexture[4];
_vertices[0].Position = new Vector3(1, 1, 0);
_vertices[1].Position = new Vector3(-1, 1, 0);
_vertices[2].Position = new Vector3(1, -1, 0);
_vertices[3].Position = new Vector3(-1, -1, 0);
}
Ponieważ ta klasa jest uniwersalnie użyteczna, otrzymujesz GraphicsDevice
instancję utworzoną w procesie inicjowania klasy gry.
Tutaj ustawiamy efekt niezbędny do narysowania sprite'a i położenie 4 wierzchołków wymaganych dla prostokątnego wielokąta. Rozmiar powinien być skalowany podczas rysowania, więc wynosi od -1 do 1.
Metoda DrawQuad
<summary>
3Dワールドの一部として四角形を描画します。
</summary>
public void DrawQuad(Texture2D texture, float textureRepeats, Matrix world, Matrix view, Matrix projection)
{
// 指定されたテクスチャとカメラマトリックスを使用するようにエフェクトを設定します。
_effect.Texture = texture;
_effect.World = world;
_effect.View = view;
_effect.Projection = projection;
// 指定された数のテクスチャの繰り返しを使用するように頂点配列を更新します。
_vertices[0].TextureCoordinate = new Vector2(0, 0);
_vertices[1].TextureCoordinate = new Vector2(textureRepeats, 0);
_vertices[2].TextureCoordinate = new Vector2(0, textureRepeats);
_vertices[3].TextureCoordinate = new Vector2(textureRepeats, textureRepeats);
// 矩形を描画します。
_effect.CurrentTechnique.Passes[0].Apply();
_graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _vertices, 0, 2);
}
Ustawia przekazywaną teksturę na prostokąt i rysuje ją. Ponieważ jest to podstawowy proces, nie ma nic do odnotowania.
Jeśli istnieje jeden punkt, w textureRepeats
argumencie można określić wywołaną zmienną, dzięki czemu można zmienić współrzędne tekstury.
Jeśli vertexPositionTexture.TextureCoordinate jest ustawiona poza zakresem od 0 do 1, tekstura jest domyślnie rysowana wielokrotnie.
Za jego pomocą można wyrazić, że płytki można układać wielokrotnie.
W rzeczywistości wzory w kratkę na ziemi wydają się mieć wiele prostych czarno-białych obrazów ustawionych w linii.
Interfejs IAudioEmitter
<summary>
3D サウンドを再生するエンティティの位置と速度を検索するために AudioManager が使用するインターフェイス。
</summary>
public interface IAudioEmitter
{
Vector3 Position { get; }
Vector3 Forward { get; }
Vector3 Up { get; }
Vector3 Velocity { get; }
}
Zdefiniowany jako jednostka emitująca dźwięk. Ponieważ jednostki, które emitują dźwięk tym razem, to psy i koty, są one dziedziczone w swoich klasach. Emiter potrzebuje następujących informacji:
Wykorzystanie nieruchomości | |
---|---|
Pozycja | Pozycja jednostki |
Naprzód | Kierunek, w którym skierowana jest encja (wektor) |
W górę | Up podmiotu. Kierunek, w którym głowa istnieje w osobie |
Prędkość | Prędkość, z jaką porusza się jednostka. Służy do obliczania wartości dopplerowskich. |
SpriteEntity, klasa
Klasa do reprezentowania sprite'ów 3D (billboardów). Jest również emiterem i dziedziczy IAudioEmitter
.
Psy i koty dziedziczą tę klasę.
własność
<summary>エンティティの3D位置を取得または設定します。</summary>
public Vector3 Position { get; set; }
<summary>エンティティが向いている方向を取得または設定します。</summary>
public Vector3 Forward { get; set; }
<summary>このエンティティの上方向を取得または設定します。</summary>
public Vector3 Up { get; set; }
<summary>このエンティティの移動速度を取得または設定します。</summary>
public Vector3 Velocity { get; protected set; }
<summary>このエンティティの表示に使用されるテクスチャを取得または設定します。</summary>
public Texture2D Texture { get; set; }
Ma informacje o lokalizacji jednostki itp. Zasadniczo mam informacje jako emiter. Jest to również jednostka rysunkowa, więc ma również obraz (Teksturę) do wyświetlenia.
Metoda aktualizacji
<summary>
エンティティの位置を更新し、サウンドを再生できるようにします。
</summary>
public abstract void Update(GameTime gameTime, AudioManager audioManager);
Opisuje pozycję encji i proces odtwarzania dźwięku, ale implementuje go w klasie pochodnej.
Metoda rysowania
<summary>
エンティティをビルボードスプライトとして描画します。
</summary>
public void Draw(QuadDrawer quadDrawer, Vector3 cameraPosition, Matrix view, Matrix projection)
{
Matrix world = Matrix.CreateTranslation(0, 1, 0) *
Matrix.CreateScale(800) *
Matrix.CreateConstrainedBillboard(Position, cameraPosition, Up, null, null);
quadDrawer.DrawQuad(Texture, 1, world, view, projection);
}
Psy i koty mają różne obrazy i pozycje, ale drugi mechanizm rysowania jest dokładnie taki sam, więc opisuję je tutaj.
Każda transformacja i tekstura są przekazywane do QuadDrawer w celu wyświetlenia prostokątnego wielokąta. Ponieważ transformacja współrzędnych jest podstawową wiedzą, wyjaśnienia nie są uwzględnione.
Matrix.CreateConstrainedBillboard
Użyj informacji o metodzie i kamerze, aby łatwo reprezentować billboardy, więc efektywnie je wykorzystaj.
Klasa psa
Jest to klasa, która rysuje i śpiewa psy. SpriteEntity
Dziedziczenie klasy.
Pies pozostaje w ustalonej pozycji w przestrzeni 3D.
pole
<summary>サウンドを開始または停止するまでの時間。</summary>
TimeSpan _timeDelay = TimeSpan.Zero;
<summary>現在再生中のサウンド(ある場合)。</summary>
SoundEffectInstance _activeSound = null;
_timeDelay
jest używany w odstępach czasu do odtwarzania płaczu.
SoundEffectInstance _activeSound
jest instancją do odtwarzania dźwięku.
SoundEffectInstance
Jak często widzisz w klasie odtwarzania dźwięku, możesz użyć tego tak, jak w dźwięku 3D.
Nawiasem _activeSound
mówiąc, później otrzymuję tylko referencję z klasy AudioManager, więc nie odrzucę jej po stronie klasy Dot.
Metoda aktualizacji
<summary>
犬の位置を更新し、音を鳴らします。
</summary>
public override void Update(GameTime gameTime, AudioManager audioManager)
{
// エンティティを固定位置に設定します。
Position = new Vector3(0, 0, -4000);
Forward = Vector3.Forward;
Up = Vector3.Up;
Velocity = Vector3.Zero;
// 時間遅延がなくなった場合は、ループ音を開始または停止します。 これは通常は永久に続きますが、6秒の遅延後に停止し、さらに4秒後に再起動します。
_timeDelay -= gameTime.ElapsedGameTime;
if (_timeDelay < TimeSpan.Zero)
{
if (_activeSound == null)
{
// 現在再生中のサウンドがない場合は、トリガーします。
_activeSound = audioManager.Play3DSound("DogSound", true, this);
_timeDelay += TimeSpan.FromSeconds(6);
}
else
{
// それ以外の場合は、現在のサウンドを停止します。
_activeSound.Stop(false);
_activeSound = null;
_timeDelay += TimeSpan.FromSeconds(4);
}
}
}
W tej próbce pies pozostaje w tej samej pozycji przez długi czas, więc pierwsze cztery parametry są określone przez decydujące uderzenie. Rysowanie odbywa się w klasie podstawowej.
_timeDelay jest następnie używany jako pozostały czas na zatrzymanie się, grając płacz.
AudioManager
zostanie odtworzonyPlay3DSound
w przestrzeni 3D poprzez przekazanie nazwy krzyku, informacji o pętli i własnych informacji jako emitera do .
Klasa Pies została zaprojektowana tak, aby zapętlić krzyk, więc nie musisz się zbytnio zastanawiać, ponieważ jest to tylko dostosowanie, takie jak gra lub zatrzymanie rozgałęzienia.
Klasa Cat
Jest to klasa, która rysuje kota i śpiewa. SpriteEntity
Dziedziczenie klasy.
Kot porusza się po pochodzeniu.
pole
<summary>次の音を鳴らすまでの時間。</summary>
TimeSpan _timeDelay = TimeSpan.Zero;
<summary>サウンドバリエーションから選択するための乱数ジェネレータ。</summary>
static readonly Random _random = new Random();
_timeDelay
jest używany w taki sam sposób, jak klasa Pies, z resztą czasu przed następnym piskiem.
Istnieją trzy rodzaje wywołań kotów, które są losowo wybierane i odtwarzane, ale nie mają nic wspólnego z Audio3D, ponieważ są elementem bonusowym.
Metoda aktualizacji
<summary>
猫の位置を更新し、音を鳴らします。
</summary>
public override void Update(GameTime gameTime, AudioManager audioManager)
{
// 猫を大きな円で動かします。
double time = gameTime.TotalGameTime.TotalSeconds;
float dx = (float)-Math.Cos(time);
float dz = (float)-Math.Sin(time);
Vector3 newPosition = new Vector3(dx, 0, dz) * 6000;
// エンティティの位置と速度を更新します。
Velocity = newPosition - Position;
Position = newPosition;
if (Velocity == Vector3.Zero)
{
Forward = Vector3.Forward;
}
else
{
Forward = Vector3.Normalize(Velocity);
}
Up = Vector3.Up;
// 時間遅延がなくなった場合は、別の単発音をトリガーします。
_timeDelay -= gameTime.ElapsedGameTime;
if (_timeDelay < TimeSpan.Zero)
{
// 異なる3つのサウンドバリエーション(CatSound0、CatSound1、CatSound2)からランダムに選択します。
string soundName = "CatSound" + _random.Next(3);
audioManager.Play3DSound(soundName, false, this);
_timeDelay += TimeSpan.FromSeconds(1.25f);
}
}
Ponieważ kot obraca się wokół początku ruchem okrężnym, przetwarza go tak, że porusza trajektorią okręgu za pomocą funkcji trygonometrycznej. W rezultacie pozycja, przód i prędkość zmieniały się jeden po drugim. Dlatego po uruchomieniu programu widać, że płacz kota krąży wokół, nawet jeśli nie poruszasz kamerą.
_timeDelay
Poniższy kod to proces, w którym płacz kota jest losowo przydzielany i odtwarzany w regularnych odstępach czasu.
audioManager.Play3DSound
Przekazuję się metodzie, która jest emiterem.
Widać, że pozycja odtwarzania dźwięku zmienia się jeden po drugim.
Klasa AudioManager
To w końcu esencja Audio3D. Dźwięk 3D składa się ze słuchacza i emitera. Emiter definiuje już psy i koty, więc klasa AudioManager definiuje detektory. Zwykle istnieje wiele emiterów, podczas gdy jest tylko jeden słuchacz.
Ta klasa dziedziczy,Game
rejestruje GameComponent
i używa składnika w klasie.
ActiveSound klasa
<summary>
アクティブな3Dサウンドを追跡し、アタッチされているエミッターオブジェクトを記憶するための内部ヘルパークラス。
</summary>
private class ActiveSound
{
public SoundEffectInstance Instance;
public IAudioEmitter Emitter;
}
Jest zdefiniowany na dole kodu, ale jest to klasa do zachowania stanu, który jest odtwarzany. Zawiera informacje o odtwarzanej instancji dźwiękowej i odtwarzanym emiterze.
pole
// このマネージャーにロードされるすべてのサウンドエフェクトのリスト。
static string[] _soundNames =
{
"CatSound0",
"CatSound1",
"CatSound2",
"DogSound",
};
<summary>音を聞くリスナーの情報です。これは通常カメラに一致するように設定されます。</summary>
public AudioListener Listener { get; } = new AudioListener();
<summary>AudioEmitter は、3Dサウンドを生成しているエンティティを表します。</summary>
readonly AudioEmitter _emitter = new AudioEmitter();
<summary>再生可能なすべての効果音を保存します。</summary>
readonly Dictionary<string, SoundEffect> _soundEffects = new Dictionary<string, SoundEffect>();
<summary>現在再生中のすべての3Dサウンドを追跡します。また、再生が終わったインスタンスの破棄にも使用します。</summary>
readonly List<ActiveSound> _activeSounds = new List<ActiveSound>();
_soundNames
definiuje nazwę pliku audio (nazwę zasobu) do załadowania. Ponieważ jest to przykładowy program, zdefiniowano, aby najpierw załadować plik audio zbiorczo.
Zaimportowane dane _soundEffects
dźwiękowe są przechowywane w formacie .
AudioListener Listener
to definicja słuchacza. Informacje o odbiorniku są definiowane, public
ponieważ są ustawiane z klasy Game.
AudioEmitter _emitter
to definicja emitera podczas stosowania 3D do odtwarzania dźwięku.
W tym przykładzie podczas odtwarzania dźwięku wartość każdego obiektu emitera jest ustawiona na _emitter
, więc jest to forma, która współdzieli jeden jako instancję.
Oczywiście możesz mieć dla każdego AudioEmitter
obiektu.
_activeSounds
zawiera informacje o dźwięku, który odtwarzasz w klasie, którą zdefiniowałeś ActiveSound
wcześniej.
Ponieważ informacje o emiterze zmieniają się przez cały czas, są używane do aktualizowania informacji o lokalizacji itp. oraz do odrzucania instancji dźwiękowych, które zakończyły odtwarzanie.
konstruktor
public AudioManager(Game game) : base(game) { }
GameComponent
Ponieważ dziedziczy klasę, Game
otrzymuje instancję i przekazuje ją do klasy bazowej.
Metoda inicjowania
<summary>
オーディオマネージャを初期化します。
</summary>
public override void Initialize()
{
// ゲームの世界のスケールと一致するように、3Dオーディオのスケールを設定します。
// DistanceScale は、離れるにつれて音量が変化する音の量を制御します。
// DopplerScale は、サウンドを通過するときにピッチが変化するサウンドの量を制御します。
SoundEffect.DistanceScale = 2000;
SoundEffect.DopplerScale = 0.1f;
// すべての効果音をロードします。
foreach (string soundName in _soundNames)
{
_soundEffects.Add(soundName, Game.Content.Load<SoundEffect>(soundName));
}
base.Initialize();
}
GameComponent
Ponieważ dziedziczy klasę, jest automatycznie wywoływana podczas inicjowania.
SoundEffect.DistanceScale
i SoundEffect.DopplerScale
są parametrami dedykowanymi dźwiękowi static
3D.
SoundEffect.DistanceScale
, aby usłyszeć dźwięk nawet w oddali.
SoundEffect.DopplerScale
to wpływ efektu Dopplera. Im wyższa liczba, tym większy efekt Dopplera.
_soundNames
Zapisz nazwę zasobu zdefiniowaną w pętli, aby załadować _soundEffects
.
Metoda utylizowania
<summary>
効果音データをアンロードします。
GameComponent として登録すればゲーム終了時に自動的に呼ばれます。
</summary>
protected override void Dispose(bool disposing)
{
try
{
if (disposing)
{
foreach (SoundEffect soundEffect in _soundEffects.Values)
{
soundEffect.Dispose();
}
_soundEffects.Clear();
}
}
finally
{
base.Dispose(disposing);
}
}
GameComponent
Jest automatycznie wywoływany na końcu gry, ponieważ dziedziczy klasę.
Niszczenie wszystkich zaimportowanych zasobów dźwiękowych.
Metoda aktualizacji
<summary>
3Dオーディオシステムの状態を更新します。
</summary>
public override void Update(GameTime gameTime)
{
// 現在再生中のすべての3Dサウンドをループします。
int index = 0;
while (index < _activeSounds.Count)
{
ActiveSound activeSound = _activeSounds[index];
if (activeSound.Instance.State == SoundState.Stopped)
{
// 音の再生が終了した場合は廃棄してください。
activeSound.Instance.Dispose();
// アクティブリストから削除します。
_activeSounds.RemoveAt(index);
}
else
{
// サウンドがまだ再生されている場合は、3D設定を更新します。
Apply3D(activeSound);
index++;
}
}
base.Update(gameTime);
}
GameComponent
Ponieważ dziedziczy klasę, jest automatycznie wywoływana w procesie aktualizacji.
Sprawdź aktualnie odtwarzany dźwięk i, jeśli Apply3D
jest odtwarzany, wywołaj metodę, aby zaktualizować lokalizację dźwięku, aby pasowała do emitera.
Jeśli odtwarzanie jakiegokolwiek dźwięku zostało zakończone, instancja zostanie odrzucona.
Metoda Play3DSound —
<summary>
新しい3Dサウンドを設定し再生します。
</summary>
public SoundEffectInstance Play3DSound(string soundName, bool isLooped, IAudioEmitter emitter)
{
ActiveSound activeSound = new ActiveSound();
// インスタンスを生成し、インスタンス、エミッターを設定します。
activeSound.Instance = _soundEffects[soundName].CreateInstance();
activeSound.Instance.IsLooped = isLooped;
activeSound.Emitter = emitter;
// 3D 位置を設定します。
Apply3D(activeSound);
activeSound.Instance.Play();
// このサウンドがアクティブであることを保存します。
_activeSounds.Add(activeSound);
return activeSound.Instance;
}
Proces odtwarzania dźwięku 3D z zewnątrz. Ma nazwę dźwięku do odtworzenia, czy zapętlać, i emiter informacji.
Jeśli chcesz odtworzyć dźwięk, utwórz nowe wystąpienie dźwięku z zasobu dźwiękowego przechowywanego w _soundEffects.
SoundEffectInstance
może również mieć pętlę lub nie, więc ustaw informacje o pętli.
Ponieważ tworzę jako ActiveSound
stan odtwarzania, ustawiam informacje o emiterze, które są obiektem odtwarzającym dźwięk.
Jeśli chcesz zastosować informacje o lokalizacji 3D do dźwięku, otrzymasz Emitter
potrzebną wartość.
Apply3D
Metoda jest opisana poniżej, ale jest to proces nakładania informacji 3D z emitera do dźwięku.
Podstawowym procesem dźwięku 3D jest rozpoczęcie odtwarzania z ustawionymi informacjami SoundEffectInstance.Play
3D.
Reszta polega na okresowym aktualizowaniu informacji 3D, aż dźwięk zostanie ukończony.
Metoda Apply3D
<summary>
3Dサウンドの位置と速度の設定を更新します。
</summary>
private void Apply3D(ActiveSound activeSound)
{
_emitter.Position = activeSound.Emitter.Position;
_emitter.Forward = activeSound.Emitter.Forward;
_emitter.Up = activeSound.Emitter.Up;
_emitter.Velocity = activeSound.Emitter.Velocity;
activeSound.Instance.Apply3D(Listener, _emitter);
}
Proces stosowania efektu 3D do określonej instancji dźwiękowej przy użyciu detektorów i emiterów.
Za każdym razem ustawiamy wartość na _emitter wspólnego wystąpienia.
SoundEffectInstance.Apply3D
Jeśli już AudioEmitter
go masz, po prostu przekaż słuchacza i emiter do metody.
Audio3DGame Klasa
Na koniec przyjrzyjmy się, o co chodzi w klasie Game.
pole
readonly GraphicsDeviceManager _graphics;
readonly AudioManager _audioManager;
readonly SpriteEntity _cat;
readonly SpriteEntity _dog;
<summary>地面の描画に使用するテクスチャーです。</summary>
Texture2D _checkerTexture;
QuadDrawer _quadDrawer;
Vector3 _cameraPosition = new Vector3(0, 512, 0);
Vector3 _cameraForward = Vector3.Forward;
Vector3 _cameraUp = Vector3.Up;
Vector3 _cameraVelocity = Vector3.Zero;
KeyboardState _currentKeyboardState;
GamePadState _currentGamePadState;
AudioManager
Rejestruje się GameComponents
w programie , ale ma go jako pole, ponieważ uzyskuje do niego dostęp indywidualnie.
Inne definiują psy, elementy kotów, tekstury do rysowania podłoża, quaddrawer, informacje o kamerze i informacje wejściowe.
konstruktor
public Audio3DGame()
{
Content.RootDirectory = "Content";
_graphics = new GraphicsDeviceManager(this);
_audioManager = new AudioManager(this);
// AudioManager を Components に追加して自動的に Update メソッドが呼ばれるようにします。
Components.Add(_audioManager);
_cat = new Cat();
_dog = new Dog();
}
AudioManager
Wygeneruj i GameComponents
zarejestruj się za pomocą programu .
Wygenerowałeś także klasy Kota i Psa.
Metoda LoadContent —
<summary>
グラフィックコンテンツをロードします。
</summary>
protected override void LoadContent()
{
_cat.Texture = Content.Load<Texture2D>("CatTexture");
_dog.Texture = Content.Load<Texture2D>("DogTexture");
_checkerTexture = Content.Load<Texture2D>("checker");
// 四角形ポリゴンを描画するためのクラス
_quadDrawer = new QuadDrawer(_graphics.GraphicsDevice);
}
Załaduj tekstury potrzebne dla każdego rysunku.
QuadDrawer
jest GraphicsDevice
generowany tutaj, ponieważ wymaga .
Metoda aktualizacji
<summary>
ゲームがロジックを実行できるようにします。
</summary>
protected override void Update(GameTime gameTime)
{
HandleInput();
UpdateCamera();
// 新しいカメラの位置について AudioManager に伝えます。
_audioManager.Listener.Position = _cameraPosition;
_audioManager.Listener.Forward = _cameraForward;
_audioManager.Listener.Up = _cameraUp;
_audioManager.Listener.Velocity = _cameraVelocity;
// ゲームエンティティに動き回って音を鳴らすように伝えます。
_cat.Update(gameTime, _audioManager);
_dog.Update(gameTime, _audioManager);
base.Update(gameTime);
}
HandleInput
Metody i UpdateCamera
metody to proces pobierania danych wejściowych urządzenia i obsługi kamery, który zostanie omówiony później.
Ponieważ pozycja kamery i pozycja słuchacza są prawie zawsze takie same, słuchacz jest ustawiany na tę samą wartość po procesie aktualizacji kamery.
_cat
Wywołaj metody i _dog
Update, aby odpowiednio przesuwać i piszczeć.
Metoda rysowania
<summary>
ゲームが描画する必要があるときに呼び出されます。
</summary>
protected override void Draw(GameTime gameTime)
{
var device = _graphics.GraphicsDevice;
device.Clear(Color.CornflowerBlue);
device.BlendState = BlendState.AlphaBlend;
// カメラ行列を計算します。
var view = Matrix.CreateLookAt(_cameraPosition, _cameraPosition + _cameraForward, _cameraUp);
var projection = Matrix.CreatePerspectiveFieldOfView(1, device.Viewport.AspectRatio, 1, 100000);
// チェッカーグラウンドポリゴンを描画します。
var groundTransform = Matrix.CreateScale(20000) * Matrix.CreateRotationX(MathHelper.PiOver2);
_quadDrawer.DrawQuad(_checkerTexture, 32, groundTransform, view, projection);
// ゲームエンティティを描画します。
_cat.Draw(_quadDrawer, _cameraPosition, view, projection);
_dog.Draw(_quadDrawer, _cameraPosition, view, projection);
base.Draw(gameTime);
}
Generuje przekształcenia widoku i projekcji na podstawie informacji z kamery.
W przypadku podłoża prostokąt narysowany w QuadDrawer jest wyświetlany pionowo, więc jest obracany w poziomie i umiarkowanie powiększony.
_quadDrawer.DrawQuad
Drugi argument metody określa liczbę powtórzeń tekstury, co określa, że arkusze 32x32 pojawiają się obok siebie.
_cat i _dog są umieszczane wewnętrznie, więc informacje o lokalizacji kamery są przekazywane i rysowane.
Metoda HandleInput —
<summary>
ゲームを終了するための入力を処理します。
</summary>
void HandleInput()
{
_currentKeyboardState = Keyboard.GetState();
_currentGamePadState = GamePad.GetState(PlayerIndex.One);
// 終了を確認します。
if (_currentKeyboardState.IsKeyDown(Keys.Escape) ||
_currentGamePadState.Buttons.Back == ButtonState.Pressed)
{
Exit();
}
}
Informacje na klawiaturze i gamepadzie są pozyskiwane, a koniec gry jest określany.
Metoda UpdateCamera —
<summary>
カメラを動かすための入力を処理します。
</summary>
void UpdateCamera()
{
const float turnSpeed = 0.05f;
const float accelerationSpeed = 4;
const float frictionAmount = 0.98f;
// 左または右に曲がります。
float turn = -_currentGamePadState.ThumbSticks.Left.X * turnSpeed;
if (_currentKeyboardState.IsKeyDown(Keys.Left)) turn += turnSpeed;
if (_currentKeyboardState.IsKeyDown(Keys.Right)) turn -= turnSpeed;
_cameraForward = Vector3.TransformNormal(_cameraForward, Matrix.CreateRotationY(turn));
// 前方または後方に加速します。
float accel = _currentGamePadState.ThumbSticks.Left.Y * accelerationSpeed;
if (_currentKeyboardState.IsKeyDown(Keys.Up)) accel += accelerationSpeed;
if (_currentKeyboardState.IsKeyDown(Keys.Down)) accel -= accelerationSpeed;
_cameraVelocity += _cameraForward * accel;
// 現在の位置に速度を追加します。
_cameraPosition += _cameraVelocity;
// 摩擦力を加えます。
_cameraVelocity *= frictionAmount;
}
Kamera jest sterowana ruchem.
Zawiera również obliczenia takie jak przyspieszenie i tarcie, ale myślę, że prawdopodobnie bierze pod uwagę efekt Dopplera na dźwięk 3D. Ponieważ nie robię nic specjalnego z samymi obliczeniami, nie będę o tym dyskutował.
Streszczenie
Omówiłem to obszernie, ale zwykle wystarczy odnieść się do klasy AudioManager
, aby dowiedzieć się, jak odtwarzać dźwięk 3D.
W rzeczywistości większość trudności jest wykonywana przez ramy, ponieważ to, co SoundEffectInstance
robimy, to ustawianie informacji 3D w .
Jeśli samplowałeś tylko części dźwięku 3D, skończysz pisząc trochę pracy w klasie Game.
Piszę jednak Porady w oparciu o oryginalną historię, więc minęło dużo więcej czasu.