main함수와 SnakeGame클래스

jh Seo·2023년 7월 21일
0

모든 ncurses의 함수를 사용하려면 당연하지만

#include<ncurses.h>

를 해줘야한다.

main함수

#include"../Include/SnakeGame.h"

int main(){
  SnakeGame* sG= new SnakeGame();
  sG->StartGame();
}

간단하다.
SnakeGame클래스를 하나 생성 후 StartGame()함수를 호출하도록 구현하였다.

SnakeGame.h

#ifndef _SnakeGame_H
#define _SnakeGame_H

#include "Snake.h"
#include "IDraw.h"
#include "Board.h"
#include "ItemManager.h"
#include "CollisionManager.h"
#include "Gate.h"
#include<vector>
using namespace std;
class SnakeGame{
public:
    SnakeGame();
    SnakeGame(pair<int,int> startPoint);
    ~SnakeGame();
    void Display();
    void StartGame();
private:
    int gameDelay;
    Snake* player;
    Board* entireBoard;
    Gate* gate;
    ItemManager* itemManager;
    CollisionManager& colMgr=CollisionManager::GetInstance();
    vector<IDraw*> drawableObjects;
};

#endif

사용되는 클래스로는
Snake, 플레이어 뱀 클래스
[Snake객체 구현]

Board, 전체 보드 클래스
[Board 및 Wall객체 구현]

Gate, 포탈 클래스
[Gate 객체 구현]

ItemManager, 아이템 관리하는 매니저 클래스
[ItemManager객체 구현]
[Item객체 구현]

CollisionManager 충돌 관리하는 매니저 클래스
[CollisionManager객체 구현]
등이 있다.

화면에 그려지는 모든 오브젝트들은 IDraw 인터페이스를 상속받는다.
해당 인터페이스를 상속받는 오브젝트들의 벡터를 따로 생성했다.

SnakeGame.cpp

#include<unistd.h>
#include<ncurses.h>
#include "../Include/SnakeGame.h"
#include "../Include/Input.h"
#include"../Include/CollisionManager.h"
using namespace std;

SnakeGame::SnakeGame(){
    gameDelay=1;
    player= new Snake();
    entireBoard=new Board(drawableObjects,false);
    itemManager=new ItemManager(drawableObjects);
    //게이트는 벽에 세워지면 벽을 지워야하므로 벽보다 늦게 생성자 실행되어야함.
    gate= new Gate(drawableObjects,make_pair(2,0),make_pair(3,20));
    drawableObjects.push_back(static_cast<IDraw*>( player));
}
SnakeGame::SnakeGame(pair<int,int> startPoint){
    gameDelay=1;
    player= new Snake(startPoint);
    entireBoard=new Board(drawableObjects,false);
    itemManager=new ItemManager(drawableObjects);
    //게이트는 벽에 세워지면 벽을 지워야하므로 벽보다 늦게 생성자 실행되어야함.
    gate= new Gate(drawableObjects,make_pair(2,0),make_pair(3,20));

    drawableObjects.push_back(static_cast<IDraw*>( player));
}

SnakeGame::~SnakeGame(){
    delete player;
    delete entireBoard;
    delete itemManager;
    drawableObjects.clear();
    vector<IDraw*>().swap(drawableObjects);
}

void SnakeGame::Display(){
       for(auto it = drawableObjects.cbegin() ; it!= drawableObjects.cend(); ++it){
        (*it)->Draw();
    }
    refresh();
}

void SnakeGame::StartGame(){
    initscr();
    noecho();               //hide input on screen
    curs_set(false);        //hide cursor

    keypad(stdscr,TRUE);    
    nodelay(stdscr,TRUE);   //getchar non-blocking mode로 실행
    while(1){
        //죽었다면 끝냄
        if(player->IsDead()) break;
        //아이템 매니저에서 아이템 생성
        itemManager->CheckIfUnusedItemExist();
        player->Move(getInput());
        colMgr.CheckIfCollide(player);
        clear();
        Display();
        sleep(gameDelay);
    }
    endwin();
}
  • 생성자로는 두 가지를 만들었는데, 플레이어 시작위치만 변경하기 위해 만들어줬다.

  • 소멸자에선 할당받은 객체들을 해제시킨다.
    사실 벡터의 clear 함수가 capacity는 그대로고 size만 0으로 줄인다는 걸 알고있어서 검색해봤다.
    저렇게 빈 벡터와 swap함수를 통해 교체하면 사라진다는데 나중에 확인 해봐야겠다.

  • main함수에서는 SnakeGame의 StartGame을 호출한다.
    noecho함수를 통해 입력값을 스크린에서 빼주고,
    curs_set(false)를 통해 커서를 숨긴다.

또한 nodelay함수를 호출해야 input.h의 getchar()함수가
non-blocking모드로 실행된다. [input.h 구현]

그 다음 반복문의 순서는
1. 매 반복문마다 플레이어가 죽었는지 체크한다.
2. 아이템매니저에서 사용안한 아이템이 있는지 체크 후 아이템 관련 처리
3. 그 후 플레이어를 움직인다.
4. 충돌처리매니저에서 플레이어가 이동한 좌표를 넣어서 충돌체가 있는지 판단하고 처리한다.
5. 화면을 다 지우고 Display()를 호출한다.
6. Display()함수는 IDraw* 인터페이스를 상속받는 모든 객체들의
Draw()함수를 호출한다.

생각

할당받은 객체들을 소멸자에서 다 해제시켜주는데 나중에 smart포인터를 통해 업데이트를 하고싶다.

Display에서 iterator을 사용하는게 좀 어려웠다.
drawableobject의 원소들이 포인터 형이라서
(*it)가 가리키는 값은 포인터다.
따라서 (*it)-> Draw() 이런식으로 Draw함수를 호출해야한다.

profile
코딩 창고!

1개의 댓글

comment-user-thumbnail
2023년 7월 21일

게시글의 내용이 상당히 복잡한 프로그래밍 코드에 대한 것이군요. 게임의 구현에 대한 세부사항을 잘 설명하셨습니다. 오브젝트들의 상호작용과 각 클래스의 역할에 대한 설명이 인상적이었습니다. 특히, 코드의 세부사항을 이해하는 데 도움이 되었습니다. 또한, 다음 단계로 스마트 포인터를 사용하려는 의지도 보여주셨네요. 좋은 글 감사합니다. 계속해서 좋은 내용 공유 부탁드립니다!

답글 달기