버그 해결을 위한 모든 질문을 던져
0 votes
108 views

안녕하세요. 클라이언트 프로그래머를 목표로 공부하고 있는 학생입니다.

 

현재 WINAPI만 사용해서 슈퍼마리오 모작을 만들고 있고, FMOD를 사용해서 오디오를 프로그래밍 하고 있습니다.

 

프로그램 내 씬은 Title, InGame, GameOver 이렇게 3가지이고, 

 

Title씬이나 GameOver씬에서는 잘 작동하는데, 인게임에서 문제가 발생했습니다..

 

게임을 진행하다보면 갑자기 게임진행시 발생하는 모든 사운드가 안나왔다가, Title로 돌아가면

 

무슨 막혔던게 한번에 풀리듯이 그 동안 안나왔던 사운드들이 한꺼번에 나옵니다.

 

그러면 또 다시 잘되다가, 다시 같은 문제가 발생해버네요..

 

분명 어디선가 병목이 발생해서 그런 것 같은데 감이 잘 안옵니다..

 

구글, stack overflow, gamedev 다 검색해봐도 안보여서 너무 답답해서 질문올립니다 ㅠㅠ

 

아래가 제가 구현한 CSoundManager.h이고, 

#pragma once


#include "..\..\..\stdafx.h"
#include "..\..\Singleton.hpp"


class CSoundManager : public Singleton<CSoundManager>
{
	DECLARE_SINGLETON(CSoundManager)

public:
	enum SoundType {
		SOUND_BGM = 0, SOUND_SFX_PLAYER, SOUND_SFX_ENEMY, SOUND_SFX_PICKUP, 
		SOUND_SFX_ATTACK, SOUND_SFX_BLOCK
	};


private:
	struct SOUND {
		SOUND(FMOD::Sound* pSound, SoundType type, int iIndex = -1)
			:m_pSound(pSound), m_SoundType(type), m_iChannelIndex(iIndex)
		{
		}
		~SOUND()
		{
			m_pSound->release();
		}
		FMOD::Sound*	m_pSound;
		SoundType		m_SoundType;
		int				m_iChannelIndex;
	};
	typedef std::shared_ptr<SOUND> SoundPtr;
	typedef std::weak_ptr<SOUND>   WeakSoundPtr;


public:
	bool Init();
	void Update();
	

public:
	void SetChannelVolume(float fVolume, SoundType type);


public:
	bool LoadSound(const char* strPath, const TSTRING& strSoundName, SoundType type, FMOD_MODE mode);
	bool ReleaseSound(const TSTRING& strSoundName);


public:
	void SoundPlay(const TSTRING& strSoundName);
	void ChangeBGM(const TSTRING& strSoundName);
	void GroupSoundPause(bool bPause);
	void GroupSoundPause(bool bPause, SoundType type);
	void StopChannel(SoundType type);



private:
	WeakSoundPtr FindSound(const TSTRING& strSoundName);


private:
	bool LoadEnemySFX();
	bool LoadPlayerSFX();
	bool LoadPickupSFX();
	bool LoadAttackSFX();
	bool LoadBlockSFX();
	bool LoadBGM();


private:
	FMOD::System*						m_pFMODSystem;
	FMOD::Sound*						m_pBGM;
	FMOD::ChannelGroup*					m_pMasterChannelGroup;
	std::vector<FMOD::Channel*>			m_ChannelList;

private:
	typedef std::unordered_map<TSTRING, SoundPtr> SoundList;
	SoundList							m_SoundTable;
	

};

 

아래가 구현부입니다.(사운드파일 불러오는 부분은 굳이 넣을 필요가 없을 듯 하여 뺐습니다.)

#include "..\..\..\stdafx.h"
#include "..\..\..\Include\Core\Sound\CSoundManager.h"
#include <fmod_errors.h>


CSoundManager::CSoundManager()
{
}

CSoundManager::~CSoundManager()
{
	m_SoundTable.clear();
	m_pMasterChannelGroup->release();
	m_pFMODSystem->release();
	m_pFMODSystem->close();
}

bool CSoundManager::Init()
{
	//FMOD System변수 초기화
	auto result = FMOD::System_Create(&m_pFMODSystem);
	if (result != FMOD_OK)
	{
		printf("[ERROR] (%d) %s\n", result, FMOD_ErrorString(result));
		return false;
	}

	result = m_pFMODSystem->init(100, FMOD_INIT_NORMAL, NULL);
	if (result != FMOD_OK)
	{
		printf("[ERROR] (%d) %s\n", result, FMOD_ErrorString(result));
		return false;
	}

	//FMOD MasterGroup Channel 초기화
	result = m_pFMODSystem->getMasterChannelGroup(&m_pMasterChannelGroup);
	if (result != FMOD_OK)
	{
		printf("[ERROR] (%d) %s\n", result, FMOD_ErrorString(result));
		return false;
	}

	//ChannelList 초기화
	m_ChannelList.assign(6, nullptr);

	//Load Sound
	if (!LoadEnemySFX())
	{
		printf("[ERROR] LoadEnemySFX Error.\n");
		return false;
	}

	if (!LoadPlayerSFX())
	{
		printf("[ERROR] LoadPlayerSFX Error.\n");
		return false;
	}

	if (!LoadPickupSFX())
	{
		printf("[ERROR] LoadPickupSFX Error.\n");
		return false;
	}

	if (!LoadAttackSFX())
	{
		printf("[ERROR] LoadAttackSFX Error.\n");
		return false;
	}

	if (!LoadBlockSFX())
	{
		printf("[ERROR] LoadBlockSFX Error.\n");
		return false;
	}

	if (!LoadBGM())
	{
		printf("[ERROR] LoadBGM Error.\n");
		return false;
	}

	return true;
}

void CSoundManager::Update()
{
	m_pFMODSystem->update();
}

void CSoundManager::SetChannelVolume(float fVolume, SoundType type)
{
	m_ChannelList[type]->setVolume(fVolume);
}

bool CSoundManager::LoadSound(const char* strPath, const TSTRING& strSoundName, 
	CSoundManager::SoundType type, FMOD_MODE mode)
{
	FMOD::Sound* pSound;
	auto result = m_pFMODSystem->createSound(strPath, mode, 0, &pSound);
	if (result != FMOD_OK)
	{
		printf("[ERROR] (%d) %s\n", result, FMOD_ErrorString(result));
		return false;
	}
	
	return m_SoundTable.emplace(strSoundName, std::make_shared<SOUND>(pSound, type)).second;
}

bool CSoundManager::ReleaseSound(const TSTRING & strSoundName)
{
	auto it = m_SoundTable.find(strSoundName);
	if (it != m_SoundTable.end())
	{
		it->second->m_pSound->release();
		m_SoundTable.erase(it);
		return true;
	}

	printf("[ERROR] Sound not exist on SoundTable.\n");

	return false;
}

void CSoundManager::SoundPlay(const TSTRING & strSoundName)
{
	auto pSound = FindSound(strSoundName);
	if (!pSound.expired())
	{
		//PlaySound
		auto result = m_pFMODSystem->playSound(pSound.lock()->m_pSound, nullptr, false, &m_ChannelList[pSound.lock()->m_SoundType]);
		if (result != FMOD_OK)
		{
			printf("[ERROR] (%d) %s\n", result, FMOD_ErrorString(result));
			return;
		}

		//Get channel index
		result = m_ChannelList[pSound.lock()->m_SoundType]->getIndex(&(pSound.lock()->m_iChannelIndex));
		if (result != FMOD_OK)
		{
			printf("[ERROR] (%d) %s\n", result, FMOD_ErrorString(result));
			return;
		}
		printf("Channel : %d\n", pSound.lock()->m_iChannelIndex);
	}
	
}

void CSoundManager::ChangeBGM(const TSTRING & strSoundName)
{
	StopChannel(SOUND_BGM);
	SoundPlay(strSoundName);
}

void CSoundManager::GroupSoundPause(bool bPause)
{
	m_pMasterChannelGroup->setPaused(bPause);
}

void CSoundManager::GroupSoundPause(bool bPause, SoundType type)
{
	//m_ChannelGroupList[type]->setPaused(bPause);
}

void CSoundManager::StopChannel(SoundType type)
{
	bool bPlaying;
	m_ChannelList[type]->isPlaying(&bPlaying);

	if (bPlaying)
	{
		puts("StopChannel");
		m_ChannelList[type]->stop();
	}
}

CSoundManager::WeakSoundPtr CSoundManager::FindSound(const TSTRING & strSoundName)
{
	auto it = m_SoundTable.find(strSoundName);
	if (it == m_SoundTable.end())
	{
		return WeakSoundPtr();
	}

	return it->second;
}

 

구원좀 해주십쇼..ㅠㅠ

 

※ 추가

BGM을 변경할 때는 

CSoundManager::GetInstance()->ChangeBGM(TEXT("BGMOverworld"));

이런 식으로 ChangeBGM() 메소드를 Scene전환하면서 한번씩 호출해주고,

 

기타 효과음을 Play할 때는

void CPlayer::SetPlayerState(PlayerState state)
{
	auto pRender = GetComponent<AnimationRender>().lock();
	auto pCollider = GetComponent<ColliderBox>().lock();
	switch (state)
	{
	case PS_SMALL:
		if (m_PlayerState != PS_SMALL)
		{
			pRender->ChangeAnimationTable(TEXT("MarioSmall"));
			pCollider->SetHeight(m_iSmallStateHeight);
			m_pSoundManager->SoundPlay(TEXT("SFXPipe"));
		}
		break;
	case PS_BIG:
		if (m_PlayerState == PS_SMALL)
		{
			pCollider->SetHeight(m_iEntityHeight*0.8);
		}

		if (m_PlayerState != PS_BIG)
		{
			pRender->ChangeAnimationTable(TEXT("MarioBig"));
		}
		break;
	case PS_FLOWER:
		if (m_PlayerState == PS_SMALL)
		{
			pCollider->SetHeight(m_iEntityHeight*0.8);
		}

		if (m_PlayerState != PS_FLOWER)
		{
			pRender->ChangeAnimationTable(TEXT("MarioFlower"));
			m_pSoundManager->SoundPlay(TEXT("SFXPowerUp"));
		}
		break;
	}
	
	m_PlayerState = state;


}

이런식으로 SoundPlay()메소드만 사용하여 호출해주었습니다.

 

※추가2

사운드 호출 시 채널의 인덱스를 계속 출력해 보았을 때, 

채널 100개기준 99번부터 계속 내려가다가 

채널인덱스가 35번이 될 때 부터 상기 적어놓은 현상이 발생하더군요..

asked (3 point)
수정됨 , 108 views
클래스가 잘 동작ㅎ하는 상태에서 안되는 경우가 발생시 보통 클래스만 구현 문제가 있을수도있지만 사용하는 부분이 잘 못 된 경우가 많습니다 또는 구현 부분 잘못이 사용 부분도 참고해야 알수있는 경우나요
 

그런 이유로 구현 클래스만 놓으신다고 그 상황을 제대로 파악하기 힘들어서 추측성 답변 외로는 정확한 분석에 따른 답변을 드리기 힘들거 같네요
더구나 아예 안 나오거나 하는게 아닌 한꺼번에 나중에 나온다는것에서도 사용측면에서 잘못된게 있을거 같네요
답변 감사합니다 !

일단 말씀해주신대로 어떤 식으로 해당 클래스를 사용하였는지 추가해놨습니다.
원인을 찾았습니다...

해당 Scene들을 관리하는 SceneManager 클래스에서 SoundManager를 매틱마다 Update해주는걸로 생각하고 있었는데, 알고보니 그 부분이 빠져있더군요..

이제 잘됩니다 ㅜㅜㅜ

Title씬에서 안나왔던 Sound들이 한꺼번에 재생됬던 것도 Title씬에서만 SoundManager를 Update해줘서 그런거였네요..

결국 이틀동안 삽질했지만, 해결되서 기분좋네요!
ㅋ 역시 사용이 문제죠 보통 이런 케이스

뭐 아시겠지만 그래도 혹시나 해서 팁을 드리면
이런 형태로 진행 중 뭔가 안되는 경우에는 큰 흐름적으로 로그 찍어서 출력하는것도 좋지만
파트로 좀 나누어서 그 파트별로 시작 부분에 브래이크 포인트 찍어서 파트별로 일일이 따라가면서 한줄씩 실행 해보면서 호출이나 대입 같은게 제대로 이루어지는지 따라가면서 보는게 일찍 버그 찾는 경우가 많더라구요

질문에 대한 답변을 하려면 로그인 또는 가입해야합니다.

버그 해결을 위해 도움을 구하고, 도움을 주세요. 우리는 그렇게 발전합니다.

throw bug 는 프로그래밍에 대한 전분야를 다룹니다. 질문,논의거리,팁,정보공유 모든 것이 가능합니다. 프로그래밍과 관련이 없는 내용은 환영받지 못합니다.

96 질문
186 answers
194 댓글
211 users