짧은 설명
- 프레임 워크 클래스 : 메인 루프를 담당하는 클래스다.
- 리소스 매니저
- 인풋 매니저
- 씬 매니저 : 프레임 워크 밑에서 씬들을 관리하는 클래스
- 싱글톤으로 어디서든 접근할 수 있게 한다.
- 씬 : 특정 게임 오브젝트들을 관리한다.
- 업데이트, 드로우, 게임오브젝트 추가 ‘ 제거
- 게임 씬
- 타이틀 씬
- 개발용 테스트 씬 등…
- 매니저들은 싱글톤으로 만드는게 좋다.
- 싱글톤은 상속할때 자식 클래스를 템플릿으로 넘겨야한다.
- 릴리즈는 역순으로 해야한다.
- reset과 init을 나눈 이유 : 사용 용도를 구분하기 위해서다.
씬 매니저
- 컨테이너 생성은 벡터, 리스트, 언오더드 맵 중에서 골라야한다.
- 씬은 몇개 없다. -> 벡터(일반 배열), 언 오더드 맵 중에서 고르면 좋다.
- 씬마다 ID(씬 아이디)주기 때문에 배열의 인덱스를 씬 아이디와 키로 맞춰야한다.
- Scene* : Scene으로 하면 자식 클래스의 사이즈가 다 다르기 때문에 포인터를 붙인것이다.
- 주소값으로 받게되면 뭘 받아도 똑같은 주소의 메모리크기이기 때문이다.
- 씬은 하나만 열려있어야하고, 씬을 열려면 열려있는 씬을 닫아야한다.
std::vector<Scene*> scenes; //씬을 동적할당해서 저장한다.
- 지연해서 추가 및 삭제해야하는것이 있다.
- 이유 : 업데이트때 씬이 바뀌는 경우 업데이트 중간에 벗어나야하는 경우가 생기기 때문이다. -> 이때 중간에 벗어나기 위해 지연이 필요하다.
SceneIds nextScene = SceneIds::None; //지연을 위한 씬 아이디
- 열릴 씬의 Enter 함수를 호출해야한다. -> 이걸 지연해서 실행해야한다.
nextScene = id; //다음 열 씬 아이디 저장
void SceneMgr::Update(float dt)
{
//다음 열 씬이 none이 아니라면 열어야하는 씬이라는 것이다.
if (nextScene != SceneIds::None)
{
scenes[(int)currentScene]->Exit(); //열려있는 씬 닫기
currentScene = nextScene; //현재 씬을 다음 씬으로 저장
nextScene = SceneIds::None; //다음 씬은 없으니 초기화 -> 이거 안하면 계속 바뀌는게 무한반복이 되기 때문이다.
scenes[(int)currentScene]->Enter(); //다음 씬 열기
}
scenes[(int)currentScene]->Update(dt);
}
게임 오브젝트 배치
- Init : 계속 배치
- Enter / Exit : 생성 및 제거
프레임워크 클래스
- 프레임 워크 객체 생성 - 메인에서
- 생성만 하면 동작하게 된다.
- 그 밑에 속한 매니저가 알아서 동작하게 된다.
int main()
{
FRAMEWORK.Init(1280, 720, "SFML");
FRAMEWORK.Do();
FRAMEWORK.Release();
return 0;
}
//윈도우 생성 / t뒤에 창모드니 전체화면이니 하는것을 지정할 수 있다.
window.create(sf::VideoMode(w, h), t);
//시간 갱신
sf::Time dt = clock.restart();
realDeltaTime = dt.asSeconds(); //실제 시간
deltaTime *= timeScale;
time += deltaTime; //시간은 누적해야한다.
realTime = realDeltaTime; //배율 누적 안된 실제 누적 시간
- Do() : 미리 사용할 함수를 미리 호출하는 것이다.
while (window.isOpen())
{
~~~
sf::Event event;
while (window.pollEvent(event)) { ~~~ }
~~~
}
백그라운드 오브젝트
- 속도와 방향은 수업이니 약식으로 public으로 설정하지만 나중에 개인 프로젝트에서 고쳐야한다.
- 구름같이 배치해야할 오브젝트 이미지를 넣고 움직임을 주는 역할을 한다.
auto pos = GetPosition();
pos += direction * speed * dt;
- 스프라이트 게임 오브젝트 ; 움직이지 않는 이미지의 텍스쳐와 위치, 회전, 크기 등을 설정하여 출력한다.
- 배경화면
- 임시 동적할당을 매개변수로 직접 넘겨서 생성해도 괜찮다.
- 백그라운드 이미지 : 속도, 방향을 받아 움직이는 그림을 출력한다.
- 구름, 벌 : 움직여야한다.
- 화면 밖으로 나갈수가 있으니 ‘경계검사’가 필요하다.
if (pos.x < -400.f || pos.x > bounds.width + 200.f) //윈도우 경계검사
{
if (Utils::RandomValue() < 0.5f)
{
SetSide(Sides::Right);
}
else
{
SetSide(Sides::Left);
}
}
void BackgroundElement::Reset()
{
SpriteGameObject::Reset();
SetOrigin(Origins::MC); //피벗 : 중앙
SetSide(Sides::Right);
SetPosition({ 500.f, 0.f });
}
실수 난수 출력
float f = (float)rand() / RAND_MAX;
return min + f * (max - min);
- max - min : 전체 구간 길이
- f * (max - min) : 랜덤으로 얼마나 갈지 정한다.
- f = 0.5 → 절반만큼 이동 → 3.0(전체 구간 길이) * 0.5 : 1.5 → 전체 구간의 반
- min + ~~ : 시작 위치에서 시작
- (2.0, 5.0) → 2.0 + 1.5 = 3.5가 출력된다.
트리
- 가지들을 멤버로 가지고 있어야한다.
- 기둥 그릴 스프라이트
- 가지들 스프라이트
std::vector<sf::Sprite> branches;
SetPosition({ windowBounds.width * 0.5f, 0.f });;
void Tree::SetPosition(const sf::Vector2f& pos)
{
tree.setPosition(pos);
for (int i = 0; i < branches.size(); i++)
{
branches[i].setPosition(pos.x, i * 150.f);
}
}
for (int i = branchesSide.size() - 1; i > 0; i--)
{
branchesSide[i] = branchesSide[i - 1];
}
branchesSide[0] = (Sides)Utils::RandomRange(0, 3);
for (int i = 0; i < branchesSide.size(); i++)
{
switch (branchesSide[i])
{
case Sides::Left:
branches[i].setScale(-1.f, 1.f);
break;
case Sides::Right:
branches[i].setScale(1.f, 1.f);
break;
}
}
- 외부에서 마지막 가지 방향을 가져올 수 있게 설정
- 로테이션, 스케일은 설정하지 않는다.