개발/C, C++

C언어로 게임만들기 - 5. 첫번째 게임_1)Player 만들기

huiyu 2017. 3. 19. 15:44

이제 프레임워크는 완성됐고, 이 프레임워크를 갖고 게임을 만들면 됩니다.
첫번째 게임은 C언어 게임만들기 강좌에서 나오는 5장-슛골임 게임 만들기입니다.

(전체적인 내용은 위링크의 강좌의 내용이지만 순서나 코드는 제 나름대로 작성하였습니다.)


게임은 간단합니다.
좌우로 움직이는 골대에 플레이어를 좌우로 움직여 제한시간 내에 공을 가능한 많이 넣는 것입니다.


우선 좌우로 움직이는 플레이어 캐릭터를 만든다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
char PLAYER_STR[] = "└─●─┘";
typedef struct Position
{
    int x, y;
}Position;
 
typedef struct
{
    Position position;
    char *strPlayer;// = "└─●─┘";//주인공 캐릭터
    int nLength; //주인공 캐릭터 전체 길이
}Player;
 
Player g_Player;
cs

Player를 조작할 Player 구조를 만듭니다.
Player는 x,y 좌표값, 그려질 텍스트값, 텍스트 길이를 갖고 있습니다.


이 값을  Init()함수에서 초기화  해줍니다.

1
2
3
4
5
6
7
8
9
10
11
void Init()
{
    InitFPSData(&fpsData);
    g_Player.position.y = 22;
    g_Player.position.x = 0;
 
    g_Player.nLength = strlen(PLAYER_STR);
 
    g_Player.strPlayer = (char*)malloc(sizeof(char)*g_Player.nLength);
    strcpy(g_Player.strPlayer, PLAYER_STR);
}
cs


다음 초기화한 Player 변수를 화면에 그려줍니다. 그려주는 건 Render()함수 내부에  작성해줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
void Render()
{
    ScreenClear();
    DrawFPS(&fpsData);
 
    char string[100= { 0, };
 
    ScreenPrint(g_Player.position.x, g_Player.position.y, g_Player.strPlayer);
 
    sprintf(string"주인공 이동좌표 : %d, %d", g_Player.position.x, g_Player.position.y);
    ScreenPrint(03string);
    ScreenFlipping();
}
cs


실행시켜보면 간단하게 현재 x, y좌표와 함께  player 의  모습이 화면에 나타납니다.


이제 j키로 왼쪽으로  이동,  l키로  오른쪽으로 이동하게 처리하면  됩니다.

키처리하는 부분은 입력받은  key값에  따라 처리하는 keyProcess()함수 내부에서 처리하면 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
void KeyProcess(int key)
{
    int remain;
    switch (key)
    {
    case 'j':
        g_Player.position.x--;
        break;
    case'l':
        g_Player.position.x++;
        break;
    }
}
cs

다시  실행시킨  후  j,l키를 입력해보면 좌우로 움직이는 것을 확인할 수 있습니다.


*이동 시 화면에 잔상이 남을  경우,  WaitRender()함수에서 시간을 조정해서 fps를 높여보세요.
  또는 ScreenClear()함수의 Clear범위를 늘려주세요.


현재 출력되고 있는 Player는 왼쪽 팔을 기준으로 0,0으로 설정되어져 그려지고 있다.


팔 길이가 다른 캐릭터의 경우 동시에 출력할 경우 팔 길이에 따라 머리는 다른 곳에 위치하게 된다.
(경계에 대한 처리도 다르고 볼 컨트롤 하는 위치 좌표 역시 다르게 된다)
그렇기 때문에 머리좌표를 기준으로 출력하는 중심좌표가 필요하다.

미리 만들어 둔 Player 구조체에 center Position을 추가한 후 Init에서 초기화해준다.

1
2
3
4
5
6
7
typedef struct
{
    Position position;
    Position center;// 중심 좌표
    char *strPlayer;// = "└─●─┘";//주인공 캐릭터
    int nLength; //주인공 캐릭터 전체 길이
}Player;
cs


Init()

1
2
    g_Player.center.x = 4;
    g_Player.center.y = 0;
cs

*중심좌표가 4인 이유는 PLAYER_STR[] = "└─●─┘" 를 strlen()으로 사이즈를 출려해보면 10인 것을 볼 수 있다. 즉, 한 글자당 2컬럼씩의 사이즈를 갖고 있어서 왼쪽 팔 2개 다음에 위치한 머리의 좌표는 4를 갖는다.


Render()

1
2
int printX = g_Player.position.x - g_Player.center.x;
ScreenPrint(printX, g_Player.position.y, g_Player.strPlayer);
cs

Player를 출력했던 Render()함수에서 center.x만큼 뺀 후 출력하게 되면 중심좌표(머리)를 기준으로 출력하게 된다.

*(4,0)에 위치할 때 실제 출력은 4를 뺀(0,0)에서 출력하므로 머리를 기준좌표로 출력하게 되는 것이다.


클리핑(Clipping) 적용

클리핑이란? 오려낸다는 뜻으로 게임 이미지에서 필요한 부분만을 출력하고 보이지 않는 부분은 출력하지 않는 기법을  말합니다.
이 게임에선 양쪽 경계 끝으로 갔을 때는 경계를 넘어간 만큼 팔은 잘라내고 출력하게 구현하겠습니다.

아래 그림과 같이요.

 


Render()함수 내부에서 경계를 넘어갔을 경우, 처리해주면 됩니다.
우선 아래와 같이 조건문을  나눕니다.

1
2
3
4
5
6
7
8
9
10
11
    int printX = g_Player.position.x - g_Player.center.x;
    if (printX < 0)
    {
    }
    else if (g_Player.position.x + g_Player.center.x +1 > 40)
    {
    }
    else
    {
        ScreenPrint(printX, g_Player.position.y, g_Player.strPlayer);
    }
cs


첫번째 if문  printX<0보다 작을 경우는 왼쪽  팔이 경계를 넘어갔을 경우

두번째 else  if문의 경우,
g_Player.position.x(머리좌표)+g_player.center.x(이름이 헷갈리지만 오른쪽팔을 계산) +1(맨끝 Null을 계산) 하여
40(오른쪽 경계선)을 넘는지 체크합니다.

각 경계를 넘억가지 않은 경우 else에서 처리됩니다.


이제 각각 처리되는 경우는 아래와 같이 하면 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int printX = g_Player.position.x - g_Player.center.x;
if (printX < 0)
{
    ScreenPrint(0, g_Player.position.y,  &g_Player.strPlayer[printX*-1]);
}
else if (g_Player.position.x + g_Player.center.x + 1 > 40)
{
    strncat(string, g_Player.strPlayer, g_Player.nLength - ((g_Player.position.x + g_Player.center.x +1)-40));
    ScreenPrint(printX, g_Player.position.y, string);
}
else
{
    ScreenPrint(printX, g_Player.position.y, g_Player.strPlayer);
}
cs

1. 왼쪽 경계를 넘을 경우
ScreenPrint(0, g_Player.position.y, &g_Player.strPlayer[printX*-1]);
-> 왼쪽을 넘은 경우 -(음수)값에 출력할 수 없으므로 무조건 0에 출력한다. -> g_Player.strPlayer[printX*-1], printX값은 왼편으로 넘어갈때마다 -2,-4... 값으로 줄게 되는데 -1을 곱하여 주인공 string값의 인덱스로 사용한다. : -2(2): ─●─┘, -4(4):●─┘, -6(6):─┘ (각 글자의 칼럼 값은 2이므로..)

2. 오른쪽 경계를 넘을 경우
strncat(string, g_Player.strPlayer, g_Player.nLength - ((g_Player.position.x + g_Player.center.x +1)-40));     ScreenPrint(printX, g_Player.position.y, string);
-> strncat : 지정된 길이만큼 두개의 문자열을 합친다. -> string배열에 오른쪽으로 넘어간 팔의 길이를 제외하고 합친 뒤 출력.
 이상태로 실행해보면 좌우 경계를 넘었을  때 문작가 깨진 것을 확인할 수 있다.
이는 각 글자의 칼럼은 2이기 때문에 경계를 넘어선 경우엔 2씩 이동해주어야한다. 아래와 같이 경계를 넘어선 경우 2씩 이동되게 해주자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void KeyProcess(int key)
{
    int remain;
    switch (key)
    {
    case 'j':
        g_Player.position.x--;
        if (g_Player.position.x- g_Player.center.x < 0 || g_Player.position.x + (g_Player.center.x*2+ 1 >40)
        {
            g_Player.position.x--;
        }
        break;
    case'l':
        g_Player.position.x++;
        if (g_Player.position.x+(g_Player.center.x*2)+1 >40||g_Player.position.x - g_Player.center.x < 0)
        {
            g_Player.position.x++;
        }
        break;
    }
}
cs

실행시켜 보면 Player 객체를 좌우로 움직여볼 수 있습니다.




728x90
반응형