문제가 발생했을 때 소리를 재생하는 좋은 방법은 무엇입니까? 이 소리는 어때?


10

그래서 저는 수업 시간이 얼마나 모 놀리 식인지 생각하고있었습니다. 예를 들어, Character클래스의 Jump메서드에서 사운드 효과 객체에 대한 참조를 가지고 재생할 수 있습니다. 그 자체로는 괜찮지 만 물리, 애니메이션, 충돌 등을 고려할 때 Jump 메서드가 커지고 Character클래스는 여러 가지 요소에 많은 의존성을 갖습니다. 그래도 괜찮을 수도 있습니다. 그러나 캐릭터가 점프 할 때 더 이상 소리를 재생하지 않으려면 어떻게해야합니까? 이제 코드의 혼란에서 특정 코드 줄을 찾아서 Jump주석 처리해야합니다.

그래서 .. 나는 생각하고 있었다.

대신 어떤 종류의 AudioSystem클래스가 있었고 다른 클래스에 관심이있는 임의의 이벤트를 구독하면됩니다. 예를 들어 클래스에는 메소드 의 클래스 내에서 발생 Character하는 Jumped이벤트 (정적도 가정합니다)가 있을 수 있습니다 Character. 그런 다음 Character클래스는 캐릭터가 점프 할 때 재생되는 작은 사운드 효과에 대해 전혀 알지 못합니다. 이것은 AudioSystem정적 이벤트를 사용하여 게임에서 발생하는 특정 이벤트와 사운드 효과를 연결하기 위해 프로그래머가 후퇴 할 수있는 거대한 클래스 일 것입니다. 너무 큰 가지고 있다면, 그것은 같은 서브 클래스에서 분리 될 수있는 EffectsAudioSystem, BackgroundAudioSystem, AmbientAudioSystem, 등등.

그런 다음 게임 옵션에서 이러한 종류의 사운드를 활성화 또는 비활성화하는 확인란이있을 수 있으며 간단하고 단일 부울 플래그를 사용하여 해당 시스템 하나만 비활성화하면됩니다. 시스템에 대한이 개념은 물리, 애니메이션 등과 같은 것들로 확장 될 수 있으며, 이러한 정교한 시스템과 분리 된 시스템을 통해 플레이어의 행동으로 인한 대부분의 게임 반응이 연결될 수 있습니다.

좋아, 내 질문은 약간 모호 할 수 있지만, 이런 종류의 소리는 어떻게 들립니까? 나는 이런 종류의 시스템에 대한 많은 이야기를 들어 본 적이 없다. 이것은 지금까지 어떤 코딩도하지 않고 지금 머릿속에 있습니다. 아마도 "이론에는 좋지만 실제로는 아닙니다"종류의 거래 중 하나 일 것입니다. 이런 종류의 시스템이 더 큰 게임에서 작동합니까? 아니면 결국 원래 시스템보다 더 많은 스파게티 엉망이 될까요?


5
건전한 아이디어처럼 들리 네요 :) (더 진지한 참고 : 느슨하게 연결된 서브 시스템 / 클래스 간의 통신을 위해 메시지를 사용하는 것이 일반적으로 좋은 아이디어입니다)
bummzack

1
이것이 완료된 방법입니다. 아직 렌더링하지 않은 경우 렌더링을 별도의 클래스에 배치해야합니다 (캐릭터 클래스에 draw () 함수가 없어야 함).
dreta

답변:


2

메시지는 디버그 및 유지 관리하기 어려운 지옥입니다. 이론적으로는 잘 들리지만 실제로 일단 복제되면 많은 중복 데이터가 전송되어 혼란스러워집니다. 점프 사운드 효과는 끝에 더 많은 데이터가 필요합니다. 예를 들어 위치, 속도, 캐릭터가있는 재료, 이름을 말하면 목록이 끝납니다.

따라서이 데이터를 수집하여 데이터가 복사 된 매우 구체적인 이벤트 / 메시지를 통해 AudioManager로 보내거나 메시지의 문자에 대한 참조를 보내서 AudioManager가 데이터에 액세스 할 수 있습니다. 방법은 지저분 해지고 이제 오디오 관리자는 재료 등을위한 소리를 선택해야합니다.

결국 특정 이벤트 (이 메시지에 대해서만 매우 특정한 클래스)는 해당 클래스를 다시 깊이 결합시킵니다. 그리 많지 않고 결국에는 데이터를 보내기위한 목적으로 만 사용되며 이미 존재하며 오래된 것일 수 있으며 중복 된 데이터의 다른 모든 문제로 고통받을 매우 구체적인 이벤트 / 클래스의 지저분한 큰 목록을 갖게됩니다 .

따라서 유지 관리해야 할 불필요한 클래스 목록이 많이 있습니다.이 클래스는 캐릭터와 AudioManager 사이에 깊은 연결을 제공합니다. 단, 소스 코드 전체에 흩어져 있습니다. Character 클래스와 AudioManager 클래스에서만 가능합니다.

코드를 분리하는 것이 좋습니다. 그러나 메시지는 실제로 또 다른 심층 결합 방법입니다. 일부 코드는 결합되어 있어야하며, 가장 직접적인 방법으로 코드를 결합하고 과도하게 엔지니어링해서는 안됩니다.


1
잘 설계된 메시징 시스템은 어떻게 또 다른 방식의 딥 커플 링입니까? 메시지를 보내는 것은 객체가 통신하지 않는 절대 최소 결합입니다. 설계 한 방식에 따라 문제가 발생할 수 있지만 시스템에서 소리, 위치 및 유형 만 입력하면 모든 문제가 해결되고 발생할 수있는 문제는 발생하지 않습니다. 오디오 시스템은 어떤 사운드가 필요한지 계산해서는 안되며 모든 설정을 추상화하고 확산 문제를 제거해야합니다. en.wikipedia.org/wiki/Coupling_(computer_programming)
ClassicThunder

1
@ClassicThunder 요점은 실제로이 접근법은 잘 확장되지 않습니다. 간단한 응용 프로그램에 적합하며 일반적인 PlaySoundEvent 만 있으면됩니다. 그러나 문제는 특수한 OnJump () 이벤트를 듣는 AudioManager에 관한 것이므로 캐릭터가 오디오 작업을 제거 할 수 있습니다. 그러나 캐릭터가 사운드를 선택하여 AudioManager로 보내야하므로 오디오 작업을 없애기 위해 OnJumpEvent를 도입하는 원래 지점이 무효화되므로 간단한 PlaySoundEvent의 경우에는 해당되지 않습니다.
Maik Semder

1
그러나 OnJumpEvent를 사용하는 경우 문자에 대한 참조를 이벤트에 추가하거나 문자에서 이벤트로 모든 중요한 데이터를 복사하도록 선택할 수 있습니다. 물론, 후자는 깊은 커플 링을 도입하지는 않지만 데이터 복제 문제와 다른 모든 새로운 이벤트와 같이 유지 관리 해야하는 새로운 데이터 전달 객체로 고통받을 것입니다.
Maik Semder

1
-1 이유는 내가 전문화 된 메시지 (OnJump)를 갖는 것은 나쁜 생각 일 것입니다. 이것은 사람이 이름을 취하는 PlaySound 이벤트를 만들 수 있도록 유용한 정보 대신 '아니오 나쁜 생각입니다'입니다. 음향 효과, 그리고 발생한 3D 위치 및 / 또는 볼륨.
제임스

@James 입력에 감사드립니다. PlaySound 이벤트를 사용한다는 의미는 아닙니다. 이벤트는 GUI 데이터베이스 응용 프로그램에 대한 훌륭한 추상화이지만 복잡한 게임에는 실용적이지 않습니다.
Maik Semder

2

나는 메시지 전달 시스템이 전혀 엔지니어링이 아니라고 생각합니다. 실제로 연마 단계에서 작업을 훨씬 쉽게 수행 할 수 있습니다. 당신은 제대로하고 있어요!

당신이 묘사 한 것은 작년에 우리의 글로벌 게임 잼 게임을 위해 함께 던진 것입니다. 나는 SFX를 만들고 편집하고 자신과 다른 작곡가가 빨지 않은 방식으로 게임에 쓴 음악을 통합하는 일을 담당했습니다.

오디오 관점에서이 접근 방식의 장점은 사운드로 훨씬 더 흥미로운 것들을 할 수 있다는 것입니다. 게임에서 사운드 효과가 단순히 사운드 파일, 볼륨 및 패닝이라고 생각하면 잘못한 것입니다.

우리 게임의 경우 당신은 행성을 뛰어 넘는 우주선을 타고 공룡으로 점수를 얻었습니다. 우리는 Flash에서 일하고 있었기 때문에 데이터 기반 인프라가 필요하지 않았습니다. AudioManager는 게임 이벤트에 대한 응답으로 어떤 사운드가 발생했는지를 제어하는 ​​유일한 정적 메소드로 구성된 클래스입니다.

C ++로 작성한다면, 소리가 가질 수있는 모든 가능한 동작을 추상화하는 데 약간의 시간이 더 걸렸을 것입니다. 시스템에 조치가 발생했음을 알리는 메시지의 요구 사항은 그리 복잡하지 않습니다. 메시지 유형, 원본 객체 또는 영향을받는 객체, 일종의 게임 상태 컨텍스트에 대한 액세스 등이 필요합니다. 게임의 요구가 커짐에 따라 프로토콜이 커질 수 있습니다. 당연히 코드로 구현할 때 (우리의 거친 GGJ 코드와 같이)이 모든 것을 수행하면 모 놀리 식 클래스 문제가 악화됩니다. 그러나 이는 데이터 중심 시스템을 만들어 쉽게 완화 할 수 있습니다.

어쨌든 게임 오디오 시스템이 다양한 메시지에 반응 한 방식은 다음과 같습니다.

  • 플레이어가 행성과 충돌합니다 : 이것은 기본적으로 행성 폭발음을 유발합니다. 그런 다음 실행중인 콤보 카운터를 쿼리 한 직후. 그것이 충분히 높았다면, 공룡이 승리의 포효를하는 0.5 초 정도 후에 음향 효과가 재생되도록 스케줄 할 것입니다. 또한 백그라운드에서 임의의 행성 인구 값이 계산되었습니다 (600 ~ 3000과 같은 것-그 범위가 선택된 이유를 모르겠습니다. 버려진 게임 플레이 메커니즘이었고 오디오를 재미있게 만드는 데 사용할 수있는 거짓말) 그래서 나는 그것을 사용하여 비명 소리가 먼 소리의 음량을 조절했습니다 (비행기 시민들이시기 적절하게 운명을 맞이했습니다).

  • 플레이어는 가속을위한 스페이스 바를 보유합니다 : 이 소리를 받으면 약간의 "후스"스러 스터 사운드가 재생되었지만 동시에 저 루프 엔진의 포효가 1.5 초 이상 증가했습니다. 파티클 시스템은 또한 이미 터 IIRC를 발사하기 위해 이것을 사용했습니다.

  • 플레이어는 감속 을 위해 스페이스 바를 놓을 수 있습니다 . 이제 플레이어는 스페이스 바를 놓았으므로 오디오 시스템은 엔진 루프를 다시 내려야한다는 것을 알고있었습니다. 더 많은 시간이 있었다면 나는 그 위에 다른 소리를 겹치게하고 싶었을 것입니다.

  • 플레이어는 악한 우주 광산과 충돌합니다 : 우주 광산은 나쁘기 때문에 폭발과 결합 된 금속 충격음 (단 하나의 소리로 구운 것)뿐만 아니라 무작위로 선택된 공룡 불쾌한 소리도 재생됩니다. 플레이어의 체력이 낮아질수록 소리와 같이 더 많은 "울음 소리"를 선택할 가능성이 높습니다.

이미 재미있는 게임은 위에서 설명한 것처럼 약간의 간단한 동작만으로도 사운드 트랙이 활성화되고 역동적 일 때 재생하는 즐거움이됩니다. 예, 올바른 데이터가 전달되도록하는 몇 가지 물류가 있습니다. 그러나 BFD. 더 큰 범위의 게임 코드에서 작성해야하는 가장 복잡한 것은 아닙니다.

실제로 FMOD와 Wwise는 이와 같이 작동합니다. 중앙 메시지 디스패처가 없지만 이벤트를 중앙 시스템에 효과적으로 게시하고 제작 도구의 오디오 구현자가 사전에 디자인 한 사운드 효과를 재생하여 반응합니다. 게임에 라이브 DJ를 제공하는 것처럼 생각하십시오. 그는 일어나고있는 일을보고 지켜보고, 적절한 시간에 사운드 클립을 트리거하여 흥미를 유지하고 기존 오디오 환경에 잘 맞도록 믹싱합니다.

[편집] 또한이 C #에 태그를 추가 한 것을 확인했습니다. 이 XNA입니까, 그렇다면 XACT를 사용하고 있습니까? XNA를 사용하는 경우 XACT를 사용해야합니다.


1
이것은 작은 프로젝트에서 작동 할 수도 있고 재미있을 수도 있습니다. 그러나 큰 함수에서는 유지해야 할 수많은 메시지 클래스가 생겨나지 만 간단한 함수 호출은 같은 영향을 미칩니다. 그렇기 때문에 이벤트 시스템이 제대로 확장되지 않아 프로젝트가 커질수록 관리하기가 어려워집니다.
Maik Semder

1
Btw 우리는 내 스튜디오에서 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

0

메시지 전달 시스템이 과도하게 엔지니어링 될 수 있다는 Maik Semder의 의견에 동의합니다.

"A 모 놀리 식 클래스"에서 볼 수 있듯이 내가 이해에서, 클래스는 현재 비욘 "모 놀리 식 클래스"처럼 보이는 여기 .

이 기사를 읽어 보시고 지금은 전체 구성 요소 시스템이 과잉 상태이지만 "나머지 나누기"를 읽으면 행동을 추상화하고 더 복잡한 방법으로 이동할 수있는 좋은 방법이 될 것입니다 해결책. 어쨌든 시작하기에 좋은 기반을 제공합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.