본문 바로가기
C언어 프로젝트

[C언어] 타자게임 3 - 게임함수 수정

by davidlee_ 2021. 5. 30.
반응형

게임함수의 실행방식을 대거 수정하였다.
프로젝트 요구사항을 꼼꼼히 읽어보았어야 했는데 꼼꼼히 읽지 않은 내 불찰이다.
수정한 게임함수의 변경사항은 다음과 같다.

1. 사용자의 입력값을 받아오는 방식 변경
기존에는 scanf 함수를 사용하여 입력값을 받아왔었다. 요구사항에 따라 _getch 함수를 사용하여 입력값을 받아오도록 하였다.

2. 난이도 조절 방식 변경
원래는 clock 함수를 사용하여 입력하는데 걸리는 시간에 비례하여 점수를 차감하는 방식으로 난이도를 조절하였었다. 현재는 time함수를 사용하여, 타이머처럼 일정한 시간이 지나면 다음 단어로 넘어가게끔 조정하였다.




1. 사용자의 입력값을 받아오는 방식 변경

 

_getch함수는 화면에 입력한 문자가 출력되지 않는다.(입력 버퍼에만 입력값이 저장됨) 따라서 printf문으로 문자를 출력해주어야 한다. 또한 _getch함수는 키가 눌리기 전까지 다음 동작으로 넘어가지 않기 때문에 _kbhit함수를 사용하여 키가 눌렸을 때만 _getch함수가 실행되게끔 해줘야 한다.

_getch()와 _kbhit()은 conio.h에 선언되어 있다.

자세한 것은 아래 코드를 보면서 설명하도록 하겠다.

char ch;
int wordLength;
int s_time, j = 0;
while(1)
{
    if (_kbhit())
    {
        ch = _getch();
        gotoxy(COLS / 2 - 5 + j, 5); //커서 위치 변경
        //Backspace 처리
        if (ch == 8)
        {
            if (j > 0)
            {
                j--;
                gotoxy(COLS / 2 - 5 + j, 5);
                printf(" ");
                printf("\b");
            }
        }
        if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
        {
            printf("%c", ch);
            input[j] = ch;
            j++;
            if (j == wordLength)
            { b = 1; }
        }
    }
}

프로그램에서 영단어만을 입력값으로 받기 때문에 알파벳이 눌렸을 때만 배열에 값이 저장되도록 하였다. 또한 알파벳이 입력되었을 경우 화면에 문자가 출력되어 보이게끔 하였고, 배열에는 인덱스 값을 하나씩 늘려주면서 문자가 저장되게 하였다.

if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
{
    printf("%c", ch);
    input[j] = ch;
    j++;
    if (j == wordLength)
    { b = 1; }
}

위 코드에서 j++; 다음 라인을 보면 wordLength와 j를 비교하는 조건식이 나오는데, 이는 만약 입력한 문자의 길이가 주어진 단어의 길이와 동일해졌을 경우 다음 동작을 실행시키기 위한 조건문이다.
위에서 조건문이 성립되면 b의 값이 1로 바뀌는데, 이때 어떤 동작이 수행되는지는 밑에서 다루도록 하겠다.

*wordLength는 저번 글에서 등장하지 않은 변수이니 간단히 설명하도록 하겠다.


먼저, get_random_word함수에 약간의 수정이 있었는데, 랜덤 인덱스 값을 가져오는 동시에 가져온 인덱스 값으로 단어 배열에 접근하여 단어를 가져온 후, 그 단어의 길이를 wordLength 포인터 변수에 저장한다.

get_random_word함수에서 매개변수를 포인터로 사용하여 특정 변수 주소에 단어의 길이를 저장할 수 있게 된다.
-> 사용 예시 get_random_word(&wordLength);
이렇게 사용하면 함수를 불러와서 단어가 바뀔 때마다 그 바뀐 단어의 길이를 알 수 있게 된다.


if (ch == 8)
{
    if (j > 0)
    {
        j--; //j는 input배열의 인덱스값을 다루는 변수이다.
        gotoxy(COLS / 2 - 5 + j, 5); //커서 위치 이동
        printf(" "); //출력되어 있는 문자 지우기
        printf("\b"); //커서위치 뒤로 두번 이동
    }
}

백스페이스가 눌렸을 경우, 글자를 지워야 하기 때문에 입력받은 값이 백스페이스의 아스키코드 값과 동일하다면 화면에 출력된 글자와 그 글자를 배열에서 지워지도록 하였다. (정확히 말하면 배열의 인덱스 값을 조정하여, 새로운 문자를 입력할 때 그 위치에 덮어씌워 저장되도록 했다.)

또한 j가 0이 되었을 때, 즉, 입력 배열의 인덱스 값이 0이 되어버리면 j--를 할 필요가 없기 때문에 j>0일 때만 해당 동작이 수행토록 하였다. (j==0인 상태이면 새로운 값을 입력했을 때 input [0]에 저장되므로)


*b==1일 경우 수행되는 동작


b가 1이 되었을 경우는 입력을 끝마친 상태이다.
그렇다면 다음으로 해줘야 하는 동작은 입력값과 주어진 단어를 비교하여 그에 맞는 동작을 실행하게 하면 된다. 이 내용은 전 글에서 다루었으니 코드를 첨부하는 것으로 설명을 마무리하겠다.

while(1)
{
    if (b == 1)
    {
        input[wordLength] = 0; //배열끝에 null값을 넣어줌으로써 입력값의 끝을 알려준다.
        for (int i = 0; wordBase[a][i] != 0; i++) //배열값 마지막에 붙어있는 \n 제거
        {
            if (wordBase[a][i] == '\n')
            {
                wordBase[a][i] = 0; break;
            }
        }
        check = strcmp(input, wordBase[a]); //문자열 비교
        //printf("%d", check);
        b = 0;
        system("cls");
        switch (check) // 문자열 비교값에 따른 출력
        {
            case 0:
                gotoxy(COLS / 2 - 5, 10);
                printf("맞았습니다!\n");
                score = score + 10;
                break;
            case 1:
                gotoxy(COLS / 2 - 5, 10);
                printf("틀렸습니다!\n");
                heart = heart - 1;
                break;
            case -1:
                gotoxy(COLS / 2 - 5, 10);
                printf("틀렸습니다!\n");
                heart = heart - 1;
                break;
        }
        life_bar(heart);
        gotoxy(5, 5);
        printf("%d", score);
        a = get_random_word(&wordLength);
        gotoxy(COLS / 2 - 5, 3);
        printf("%s\n", wordBase[a]);
        s_time = time(0);
        j = 0;
    }
}





2. 난이도 조절 방식 변경

time함수를 사용하여 타이머처럼 일정 시간이 지나가면 다음 단어가 나오게 하였다.
(타이머 시간을 조절하면 난이도 조정 가능)
* time함수는 time.h에 선언되어 있다.

int s_time;
s_time = time(0);
while(1)
{
    if (time(0) == s_time + level) //시간 확인
    {
        system("cls");
        heart = heart - 1;
        life_bar(heart);
        gotoxy(5, 5);
        printf("%d", score);
        a = get_random_word(&wordLength);
        gotoxy(COLS / 2 - 5, 3);
        printf("%s\n", wordBase[a]);
        s_time = time(0);
        j = 0;
    }
}

조건문안에 등장하는 level은 게임함수의 매개변수로, 이 함수를 호출할 때 난이도에 따라 특정값을 전달해 준다.
먼저, 프로그램 시작과 동시에 s_time에 프로그램 시작시간을 저장하고, 조건문에서 현재시간과 s_time+level을 비교하여 같아졌을 경우 체력을 1 차감하고 새로운 단어로 재시작되도록 다시 초기값을 설정해준다. (life_bar함수는 체력바를 화면에 출력되도록 하는 함수이다.)




+이 게임함수에서는 다음 코드 묶음이 총 3번 등장한다.

s_time = time(0);
a = get_random_word(&wordLength);
gotoxy(COLS / 2 - 5, 3);
printf("%s\n", wordBase[a]);

위 코드 묶음이 등장하는 위치는 각각 다음과 같다.
1. 처음 프로그램이 실행될 때
2. 사용자의 입력값을 다 받고 난 뒤(b==1 조건문 마지막)
3. 시간 초과 시
이 경우일 때는 모두 게임이 재시작 또는 시작되어야 하기 때문에 새로운 단어가 나올 수 있도록 초기화해주는 것이다.
(+시간도 초기화)
2,3의 경우 입력 배열의 값도 초기화해줘야 하기 때문에 j=0;도 추가된다.



전체코드

#include "main.h"
int game_run(int level)
{
    char input[15]; //입력받을 단어 배열
    int a; //랜덤 숫자 받을 변수
    int check; //문자열 비교한 값 담는 변수
    int score = 0; //점수 변수
    int heart = 5; //남은 목숨 변수
    double result; //시간값을 저장하기 위한 변수
    int b = 0;
    char ch;
    int s_time, j = 0;
    int wordLength;
    //system("mode con cols=120 lines=45"); //콘솔창 크기
    system("title 건덕이를 잡아라!"); //콘솔창 제목
    system("cls"); // 콘솔창 초기화
    //srand(time(NULL));
    gotoxy(110, 0);
    printf("■■■■■\n"); //체력바 테스트
    srand(time(0));
    s_time = time(0);
    a = get_random_word(&wordLength);
    gotoxy(COLS / 2 - 5, 3);
    printf("%s\n", wordBase[a]);
    while (1)
    {
        //a = get_random_word(); //배열에서 단어 추출하기 위한 랜덤 인덱스 값
        //gotoxy(COLS / 2 - 5, 3);
        //printf("%s\n", wordBase[a]); //배열에서 랜덤 추출된 단어 출력
        if (time(0) == s_time + level) //시간 확인
        {
            system("cls");
            heart = heart - 1;
            life_bar(heart);
            gotoxy(5, 5);
            printf("%d", score);
            a = get_random_word(&wordLength);
            gotoxy(COLS / 2 - 5, 3);
            printf("%s\n", wordBase[a]);
            s_time = time(0);
            j = 0;
            
        }
        if (_kbhit())
        {
            ch = _getch();
            gotoxy(COLS / 2 - 5 + j, 5);
            //Backspace 처리
            if (ch == 8)
            {
                if (j > 0)
                {
                    j--;
                    gotoxy(COLS / 2 - 5 + j, 5);
                    printf(" ");
                    printf("\b");
                }
            }
            //printf("%c", ch);
            if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
            {
                printf("%c", ch);
                input[j] = ch;
                j++;
                if (j == wordLength)
                {
                    b = 1;
                }
            }
        }
        if (b == 1)
        {
            //printf("%s\n", input);
            input[wordLength] = 0;
            for (int i = 0; wordBase[a][i] != 0; i++) //배열값 마지막에 붙어있는 \n 제거
            {
                if (wordBase[a][i] == '\n')
                {
                    wordBase[a][i] = 0; break;
                }
            }
            check = strcmp(input, wordBase[a]); //문자열 비교
            //printf("%d", check);
            b = 0;
            system("cls");
            switch (check) // 문자열 비교값에 따른 출력
            {
                case 0:
                    gotoxy(COLS / 2 - 5, 10);
                    printf("맞았습니다!\n");
                    score = score + 10;
                    break;
                case 1:
                    gotoxy(COLS / 2 - 5, 10);
                    printf("틀렸습니다!\n");
                    heart = heart - 1;
                    break;
                case -1:
                    gotoxy(COLS / 2 - 5, 10);
                    printf("틀렸습니다!\n");
                    heart = heart - 1;
                    break;
            }
            life_bar(heart);
            gotoxy(5, 5);
            printf("%d", score);
            a = get_random_word(&wordLength);
            gotoxy(COLS / 2 - 5, 3);
            printf("%s\n", wordBase[a]);
            s_time = time(0);
            j = 0;
        }
        if (score >= 50) // 점수에 따른 동작
        {
            system("cls"); // 콘솔창 초기화
            gotoxy(COLS / 2 - 10, LINES / 2);
            printf("1단계를 클리어 하셨습니다!");
            Sleep(2000); //2초 딜레이
            return 1;
            break;
        }
        else if (heart == 0) //목숨이 0이 되었을때의 동작
        {
            system("cls"); // 콘솔창 초기화
            gotoxy(COLS / 2 - 10, LINES / 2);
            printf("당신의 점수: %d", score);
            Sleep(1000); //1초 딜레이
            system("cls"); // 콘솔창 초기화
            gotoxy(COLS / 2 - 10, LINES / 2);
            printf("게임오버");
            Sleep(1000); //1초 딜레이
            return 0;
            break;
        }
    }
}

 

반응형

댓글