[C++] 1.5 연습 문제 풀이
카테고리: C++ games
태그: Cpp Graphics OpenGL Programming
인프런에 있는 홍정모 교수님의 홍정모의 게임 만들기 연습 문제 패키지 강의를 듣고 정리한 필기입니다.😀
🌜 공부에 사용된 홍정모 교수님의 코드들 보러가기
🌜 [홍정모의 게임 만들기 연습 문제 패키지] 강의 들으러 가기!
1.5 연습문제
연습 문제는 스스로 풀이했습니다. 😀
해당 챕터 보러가기 🖐 1.5 FMOD를 이용한 소리 재생
연습 문제 출처 : 홍정모 교수님 블로그
🙋 Q1. 무한 반복 사운드를 pause & resume 해보세요.
#include "fmod.hpp"
#include <iostream>
#include <conio.h>
using namespace std;
int main()
{
cout << "FMOD cpp conext example" << endl;
FMOD::System *system(nullptr);
FMOD::Sound *sound(nullptr);
FMOD::Channel *channel(nullptr);
FMOD_RESULT result;
unsigned int version;
void *extradriverdata(nullptr);
result = FMOD::System_Create(&system);
if (result != FMOD_OK) return -1;
result = system->getVersion(&version);
if (result != FMOD_OK) return -1;
else printf("FMOD version %08x\n", version);
result = system->init(32, FMOD_INIT_NORMAL, extradriverdata);
if (result != FMOD_OK) return -1;
result = system->createSound("Rhapsody in Blue.mp3", FMOD_LOOP_NORMAL, 0, &sound);
if (result != FMOD_OK) return -1;
result = system->playSound(sound, 0, false, &channel);
if (result != FMOD_OK) return -1;
while (true)
{
result = system->update();
if (result != FMOD_OK) return -1;
cout << "Press 0 to pause, 1 to resume, and x to exit" << endl;
int i = getch();
if (i == '0')
channel->setPaused(true);
else if (i == '1')
channel->setPaused(false);
else if (i == 'x')
break;
}
system->release();
}
🙋 Q2. 배경 음악 튼 상태에서 스페이스바 키를 누를 때마다 다른 wav파일 재생하기
- 아래 코드! 스페이스바의 아스키코드는 32
else if (i == 32) // 스페이스바의 아스키코드는 32. 스페이스 바를 입력받으면 효과음 객체를 재생시킨다. { result = system->playSound(singing, 0, false, &channel); if (result != FMOD_OK) return -1; }
#include "fmod.hpp"
#include <iostream>
#include <conio.h>
using namespace std;
int main()
{
cout << "FMOD cpp conext example" << endl;
FMOD::System *system(nullptr);
FMOD::Sound *background(nullptr); // 배경 음악 이렇게 사운드 포인터 2개
FMOD::Sound *singing(nullptr); // 효과음 (짧은 wav파일)
FMOD::Channel *channel(nullptr);
FMOD_RESULT result;
unsigned int version;
void *extradriverdata(nullptr);
result = FMOD::System_Create(&system); // 시스템 객체 만들어 주고
if (result != FMOD_OK) return -1;
result = system->getVersion(&version);
if (result != FMOD_OK) return -1;
else printf("FMOD version %08x\n", version);
result = system->init(32, FMOD_INIT_NORMAL, extradriverdata); // 시스템 객체 초기화 해주고
if (result != FMOD_OK) return -1;
result = system->createSound("Rhapsody in Blue.mp3", FMOD_LOOP_NORMAL, 0, &background); // 배경음악 객체 생성 -> LOOP_NORMAL 무한으로 재생시킬거라
if (result != FMOD_OK) return -1;
result = system->createSound("singing.wav", FMOD_LOOP_OFF, 0, &singing); // 효과음 객체 생성 -> LOOP_OFF 스페이스바 누를 때만 재생시킬거라
if (result != FMOD_OK) return -1;
result = system->playSound(background, 0, false, &channel); // 무한루프에 들어가기 전에 배경음악 재생 ! while문이 끝나 프로그램 종료시까지 게~속 재생하게 된다. 미리 재생을 시작.
if (result != FMOD_OK) return -1;
while (true)
{
result = system->update();
if (result != FMOD_OK) return -1;
cout << "Press 0 to pause, 1 to resume, and x to exit" << endl;
int i = getch(); // i is ASCII code
if (i == '0')
channel->setPaused(true);
else if (i == 32) // 스페이스바의 아스키코드는 32. 스페이스 바를 입력받으면 효과음 객체를 재생시킨다.
{
result = system->playSound(singing, 0, false, &channel);
if (result != FMOD_OK) return -1;
}
else if (i == '1')
channel->setPaused(false);
else if (i == 'x')
break;
}
system->release();
}
🙋 Q3. 탱크 포탄 발사 사운드와 이동 소리 넣기
1.3 연습문제 풀이 - Q1. 포탄 여러개 쏘는 탱크 구현하기 에서 구현했던 코드를 활용하여 탱크가 이동할 때, 포탄을 쏠 때 소리를 재생하도록 하였다.
Class Sound 설명
- 포인터 설명
FMOD::System *system = nullptr; FMOD::Sound *tankSound = nullptr; // 탱크 움직일 때의 사운드 객체 포인터 FMOD::Sound *fireSound = nullptr; // 발사할 때의 사운드 객체 포인터 FMOD::Channel *tankChannel = nullptr; // 탱크 사운드를 컨트롤할 채널 포인터 FMOD::Channel *fireChannel = nullptr; // 발사 사운드를 컨트롤할 채널 포인터
- 채널을 탱크채널 발사채널 2개로 따로 둔 이유
- 방향키 아무것도 안누를땐 탱크 사운드가 꺼져야 하지만 발사 사운드는 그대로 유지되야함.
- 즉 통제되는 시기가 서로 다르기 때문에 따로 컨트롤 하기 위해 2개를 둠.
int systemInit()
: 시스템 객체 생성하고 초기화하는 함수int createTankSound()
: 탱크 사운드 객체 생성하는 함수- 무한루프 X
- FMOD_LOOP_OFF
int createFireSound()
: 포탄 사운드 객체 생성하는 함수- 무한루프 X
- FMOD_LOOP_OFF
int playTankSound()
: 탱크 사운드 재생시키는 함수int fireTankSound()
: 발사 사운드 재생시키는 함수
📜TankExample.h
#include "fmod.hpp"
#include "Game2D.h"
#include <vector>
#include <iostream>
#include <conio.h>
using namespace std;
namespace jm
{
class MyTank
{
public:
vec2 center = vec2(0.0f, 0.0f);
//vec2 direction = vec2(1.0f, 0.0f, 0.0f);
void draw()
{
beginTransformation();
{
translate(center);
drawFilledBox(Colors::green, 0.25f, 0.1f); // body
translate(-0.02f, 0.1f);
drawFilledBox(Colors::blue, 0.15f, 0.09f); // turret
translate(0.15f, 0.0f);
drawFilledBox(Colors::red, 0.15f, 0.03f); // barrel
}
endTransformation();
}
};
class MyBullet
{
public:
vec2 center = vec2(0.0f, 0.0f);
vec2 velocity = vec2(0.0f, 0.0f);
void draw()
{
beginTransformation();
translate(center);
drawFilledRegularConvexPolygon(Colors::yellow, 0.02f, 8);
drawWiredRegularConvexPolygon(Colors::gray, 0.02f, 8);
endTransformation();
}
void update(const float& dt)
{
center += velocity * dt;
}
};
// ==================== class Sound ===========================================//
class Sound
{
public:
FMOD::System *system = nullptr;
FMOD::Sound *tankSound = nullptr;
FMOD::Sound *fireSound = nullptr;
FMOD::Channel *tankChannel = nullptr;
FMOD::Channel *fireChannel = nullptr;
FMOD_RESULT result;
unsigned int version;
void *extradriverdata = nullptr;
int systemInit()
{
result = FMOD::System_Create(&system); // 시스템 객체 만들어 주고
if (result != FMOD_OK) return -1;
result = system->getVersion(&version);
if (result != FMOD_OK) return -1;
else printf("FMOD version %08x\n", version);
result = system->init(32, FMOD_INIT_NORMAL, extradriverdata); // 시스템 객체 초기화 해주고
if (result != FMOD_OK) return -1;
}
int createTankSound()
{
result = system->createSound("drive.wav", FMOD_LOOP_OFF, 0, &tankSound); // .mp3 files work!
if (result != FMOD_OK) return 0;
}
int createFireSound()
{
result = system->createSound("shot.wav", FMOD_LOOP_OFF, 0, &fireSound); // .mp3 files work!
if (result != FMOD_OK) return 0;
}
int playTankSound()
{
result = system->playSound(tankSound, 0, false, &tankChannel);
if (result != FMOD_OK) return 0;
}
int playFireSound()
{
result = system->playSound(fireSound, 0, false, &fireChannel);
if (result != FMOD_OK) return 0;
}
};
// ======================================================================================
class TankExample : public Game2D
{
public:
MyTank tank;
vector<MyBullet *> bullets;
Sound sound;
bool playing = false;
//TODO: allow multiple bullets
//TODO: delete bullets when they go out of the screen
public:
TankExample()
: Game2D("This is my digital canvas!", 1024, 768, false, 2)
{}
void update() override
{
if (sound.tankSound == nullptr && sound.tankSound == nullptr) // 각 사운드 객체는 한번만 만들도록
{
sound.systemInit(); // 시스템 먼저 생성하기. 아주 중요 !
sound.createTankSound();
sound.createFireSound();
}
if (isKeyPressed(GLFW_KEY_LEFT))
{
tank.center.x -= 0.5f * getTimeStep();
sound.result = sound.tankChannel->isPlaying(&playing); // 탱크 이동 소리 이미 재생중이면 새로 처음부터 재생 안하도록
if (!playing)
sound.playTankSound();
}
if (isKeyPressed(GLFW_KEY_RIGHT))
{
tank.center.x += 0.5f * getTimeStep();
sound.result = sound.tankChannel->isPlaying(&playing);
if (!playing)
sound.playTankSound();
}
if (isKeyPressed(GLFW_KEY_UP))
{
tank.center.y += 0.5f * getTimeStep();
sound.result = sound.tankChannel->isPlaying(&playing);
if (!playing)
sound.playTankSound();
}
if (isKeyPressed(GLFW_KEY_DOWN))
{
tank.center.y -= 0.5f * getTimeStep();
sound.result = sound.tankChannel->isPlaying(&playing);
if (!playing)
sound.playTankSound();
}
if (!isKeyPressed(GLFW_KEY_LEFT) && !isKeyPressed(GLFW_KEY_RIGHT) && !isKeyPressed(GLFW_KEY_UP) && !isKeyPressed(GLFW_KEY_DOWN))
{
sound.tankChannel->stop(); // 각 방향키를 안누르고 있을땐 tank 소리 정지
}
if (isKeyPressedAndReleased(GLFW_KEY_SPACE))
{
bullets.push_back(new MyBullet);
bullets.back()->center = tank.center; //
bullets.back()->center.x += 0.2f;
bullets.back()->center.y += 0.1f;
bullets.back()->velocity = vec2(2.0f, 0.0f);
sound.playFireSound(); // 스페이스바 누르면 발사소리 재생되도록! tank와 다르게 쏠때마다 소리 새로 재생되도 자연스러움
}
if (!bullets.empty())
{
for (int i = 0; i < bullets.size(); i++)
{
bullets.at(i)->update(getTimeStep());
bullets.at(i)->draw();
}
}
tank.draw();
if (!bullets.empty())
{
for (int i = 0; i < bullets.size(); i++)
{
if (bullets[i]->center.x > 1.5f)
{
delete bullets[i];
bullets.erase(bullets.begin() + i);
}
}
}
}
};
}
📜main.cpp
#include "Game2D.h"
#include "TankExample.h"
int main(void)
{
jm::TankExample().init("Tank example", 1280, 960, false, 2).run();
return 0;
}
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기