- 어떤 클래스의 객체가 프로그램 전체에서 단 하나만 만들어지도록 하는 것.
- 오직 한개의 인스턴스만을 갖도록 보장.
- 그래픽스 엔진이나 사운드 엔진에 종종 사용 된다.
싱글톤을 사용하는 이유
1. 객체 생성 없이 사용될 수 있게 한다.
사운드 엔진은 여러가지 많은 클래스, 객체에서 많이 사용된다. 사운드 기능을 쓰는 객체마다 계속 사운드 엔진 객체를 생성해내고 매개변수로 넘기고 하는 것 너무 낭비.
2. 사운드 엔진 객체를 딱 하나를 여러곳에서 공유 할 수 있게 한다.
사운드 엔진은 객체가 여러개일 필요가 없다. 단 하나면 된다. 사운드 엔진의 기능들만 가져다 쓰면 된다.
사운드 엔진의 map 에 저장되어있는 사운드들 굳이 다 객체로 찍어낼 필요 없이 기존에 만들어진 사운드 엔진 객체를 공유하는게 더 효율적이다.
싱글톤 구성법
- 사운드 엔진 클래스에서 자기 자신(사운드 엔진 객체)을 static 변수에 넣어두면 된다.
- 사운드 엔진 객체는 딱 1개만 생성될 수 있게 여러 장치(예를들면 class의 private)를 통하여 제어한다
- 생성자를 private로 두어 객체로 찍어내는 것을 막는다
- static 변수에 사운드 엔진 객체를 넣어줄 때 변수 값이 null일때만 넣는다
static 멤버 변수 특징
- static 멤버 변수의 값을 모든 인스턴스들이 공유할 수 있다.
- 인스턴스 생성 없이도 클래스 이름으로 접근하여 사용할 수 있다.
- 딱 한번만 생성된다.
- 초기화는 반드시 클래스 밖에서 해준다.
- 초기화는 보통 cpp 파일에서 따로 초기화 1회 해주는 함수를 만들어서 해준다.
- 공유되는 변수이기 때문에 객체 생성시마다 변수가 중복 선언 되는것을 방지 하기 위해
싱글톤을 사용하지 않고 사운드 엔진을 객체로 생성하여 사용한 경우 문제점
- 사운드엔진 객체를 생성해주는 것은 컴퓨터 사운드 카드에게 너무 부담 되는 일이다.
- 예를 들어 총알은 계속해서, 많이 생성되기 때문에 그때마다 게속 사운드엔진 객체가 또 생기고 또 생기고 하게된다.
전체 코드
강사님이 사운드 엔진에 대한 이해를 돕기 위해 만드신 것으로 실무엔 비효율적인 코드임
#pragma once
#include "fmod.hpp"
#include <iostream>
#include <map>
#include <string>
namespace jm
{
//Note: This example implementation of sound engine is inefficient.
class SoundEngine
{
private:
FMOD::System *system = nullptr;
//FMOD::Channel *channel = nullptr;
std::map<std::string, FMOD::Sound*> sound_map;
std::map<FMOD::Sound*, FMOD::Channel*> channel_map;// not efficient
FMOD_RESULT result;
unsigned int version;
void *extradriverdata = nullptr;
public:
SoundEngine()
{
using namespace std;
result = FMOD::System_Create(&system);
if (result != FMOD_OK) {
cout << "FMOD::System_Create() fail" << endl;
exit(-1);
}
result = system->getVersion(&version);
if (result != FMOD_OK) {
cout << "getVersion() fail" << endl;
exit(-1);
}
else printf("FMOD version %08x\n", version);
result = system->init(32, FMOD_INIT_NORMAL, extradriverdata);
if (result != FMOD_OK) {
cout << "system->init() fail" << endl;
exit(-1);
}
}
public:
~SoundEngine()
{
system->release();
}
void createSound(const std::string & filename, const std::string & sound_name, const bool & use_loop)
{
sound_map[sound_name] = nullptr;
auto & sound_ptr = sound_map[sound_name];
const int loop_flag = use_loop ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF;
result = system->createSound(filename.c_str(), loop_flag, 0, &sound_ptr);
if (result != FMOD_OK) {
std::cout << "system->createSound() fail" << std::endl;
exit(-1);
}
}
void playSound(const std::string & sound_name)
{
if (sound_map.count(sound_name) <= 0) {
std::cout << sound_name << " isn't initialized." << std::endl;
exit(-1);
}
const auto & sound_ptr = sound_map[sound_name];
auto & channel_ptr = channel_map[sound_ptr];
bool is_playing = false;
result = channel_ptr->isPlaying(&is_playing);
if (is_playing) return; // don't play if this is already playing
result = system->playSound(sound_ptr, 0, false, &channel_ptr);
if (result != FMOD_OK) {
std::cout << "system->playSound() fail" << std::endl;
exit(-1);
}
}
void stopSound(const std::string & sound_name)
{
if (sound_map.count(sound_name) <= 0) {
std::cout << sound_name << " isn't initialized." << std::endl;
exit(-1);
}
const auto & sound_ptr = sound_map[sound_name];
auto & channel_ptr = channel_map[sound_ptr];
bool is_playing = false;
result = channel_ptr->isPlaying(&is_playing);
if (is_playing == false) return; // don't stop playing if this is not playing
result = channel_ptr->stop();
if (result != FMOD_OK) {
std::cout << "system->playSound() fail" << std::endl;
exit(-1);
}
}
};
}
'공부 일지 > C++' 카테고리의 다른 글
[C++] 3.2 공 두 개를 충돌시켜보자 (0) | 2023.12.12 |
---|---|
[C++] 3.1 공 튕기기 시뮬레이션 (0) | 2023.10.03 |
[C++] 2.5 명령 패턴 command pattern (0) | 2023.09.20 |
[C++] 2.4 공장 패턴 factory pattern (0) | 2023.09.16 |
[C++] 2.3 다형성(std::vector, auto, new&delete, 스마트포인터) (0) | 2023.09.16 |
- 어떤 클래스의 객체가 프로그램 전체에서 단 하나만 만들어지도록 하는 것.
- 오직 한개의 인스턴스만을 갖도록 보장.
- 그래픽스 엔진이나 사운드 엔진에 종종 사용 된다.
싱글톤을 사용하는 이유
1. 객체 생성 없이 사용될 수 있게 한다.
사운드 엔진은 여러가지 많은 클래스, 객체에서 많이 사용된다. 사운드 기능을 쓰는 객체마다 계속 사운드 엔진 객체를 생성해내고 매개변수로 넘기고 하는 것 너무 낭비.
2. 사운드 엔진 객체를 딱 하나를 여러곳에서 공유 할 수 있게 한다.
사운드 엔진은 객체가 여러개일 필요가 없다. 단 하나면 된다. 사운드 엔진의 기능들만 가져다 쓰면 된다.
사운드 엔진의 map 에 저장되어있는 사운드들 굳이 다 객체로 찍어낼 필요 없이 기존에 만들어진 사운드 엔진 객체를 공유하는게 더 효율적이다.
싱글톤 구성법
- 사운드 엔진 클래스에서 자기 자신(사운드 엔진 객체)을 static 변수에 넣어두면 된다.
- 사운드 엔진 객체는 딱 1개만 생성될 수 있게 여러 장치(예를들면 class의 private)를 통하여 제어한다
- 생성자를 private로 두어 객체로 찍어내는 것을 막는다
- static 변수에 사운드 엔진 객체를 넣어줄 때 변수 값이 null일때만 넣는다
static 멤버 변수 특징
- static 멤버 변수의 값을 모든 인스턴스들이 공유할 수 있다.
- 인스턴스 생성 없이도 클래스 이름으로 접근하여 사용할 수 있다.
- 딱 한번만 생성된다.
- 초기화는 반드시 클래스 밖에서 해준다.
- 초기화는 보통 cpp 파일에서 따로 초기화 1회 해주는 함수를 만들어서 해준다.
- 공유되는 변수이기 때문에 객체 생성시마다 변수가 중복 선언 되는것을 방지 하기 위해
싱글톤을 사용하지 않고 사운드 엔진을 객체로 생성하여 사용한 경우 문제점
- 사운드엔진 객체를 생성해주는 것은 컴퓨터 사운드 카드에게 너무 부담 되는 일이다.
- 예를 들어 총알은 계속해서, 많이 생성되기 때문에 그때마다 게속 사운드엔진 객체가 또 생기고 또 생기고 하게된다.
전체 코드
강사님이 사운드 엔진에 대한 이해를 돕기 위해 만드신 것으로 실무엔 비효율적인 코드임
#pragma once
#include "fmod.hpp"
#include <iostream>
#include <map>
#include <string>
namespace jm
{
//Note: This example implementation of sound engine is inefficient.
class SoundEngine
{
private:
FMOD::System *system = nullptr;
//FMOD::Channel *channel = nullptr;
std::map<std::string, FMOD::Sound*> sound_map;
std::map<FMOD::Sound*, FMOD::Channel*> channel_map;// not efficient
FMOD_RESULT result;
unsigned int version;
void *extradriverdata = nullptr;
public:
SoundEngine()
{
using namespace std;
result = FMOD::System_Create(&system);
if (result != FMOD_OK) {
cout << "FMOD::System_Create() fail" << endl;
exit(-1);
}
result = system->getVersion(&version);
if (result != FMOD_OK) {
cout << "getVersion() fail" << endl;
exit(-1);
}
else printf("FMOD version %08x\n", version);
result = system->init(32, FMOD_INIT_NORMAL, extradriverdata);
if (result != FMOD_OK) {
cout << "system->init() fail" << endl;
exit(-1);
}
}
public:
~SoundEngine()
{
system->release();
}
void createSound(const std::string & filename, const std::string & sound_name, const bool & use_loop)
{
sound_map[sound_name] = nullptr;
auto & sound_ptr = sound_map[sound_name];
const int loop_flag = use_loop ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF;
result = system->createSound(filename.c_str(), loop_flag, 0, &sound_ptr);
if (result != FMOD_OK) {
std::cout << "system->createSound() fail" << std::endl;
exit(-1);
}
}
void playSound(const std::string & sound_name)
{
if (sound_map.count(sound_name) <= 0) {
std::cout << sound_name << " isn't initialized." << std::endl;
exit(-1);
}
const auto & sound_ptr = sound_map[sound_name];
auto & channel_ptr = channel_map[sound_ptr];
bool is_playing = false;
result = channel_ptr->isPlaying(&is_playing);
if (is_playing) return; // don't play if this is already playing
result = system->playSound(sound_ptr, 0, false, &channel_ptr);
if (result != FMOD_OK) {
std::cout << "system->playSound() fail" << std::endl;
exit(-1);
}
}
void stopSound(const std::string & sound_name)
{
if (sound_map.count(sound_name) <= 0) {
std::cout << sound_name << " isn't initialized." << std::endl;
exit(-1);
}
const auto & sound_ptr = sound_map[sound_name];
auto & channel_ptr = channel_map[sound_ptr];
bool is_playing = false;
result = channel_ptr->isPlaying(&is_playing);
if (is_playing == false) return; // don't stop playing if this is not playing
result = channel_ptr->stop();
if (result != FMOD_OK) {
std::cout << "system->playSound() fail" << std::endl;
exit(-1);
}
}
};
}
'공부 일지 > C++' 카테고리의 다른 글
[C++] 3.2 공 두 개를 충돌시켜보자 (0) | 2023.12.12 |
---|---|
[C++] 3.1 공 튕기기 시뮬레이션 (0) | 2023.10.03 |
[C++] 2.5 명령 패턴 command pattern (0) | 2023.09.20 |
[C++] 2.4 공장 패턴 factory pattern (0) | 2023.09.16 |
[C++] 2.3 다형성(std::vector, auto, new&delete, 스마트포인터) (0) | 2023.09.16 |