C언어 로 무기 강화 게임(강화의 노예)을 만들어보자.

C언어 로 무기 강화 게임(강화의 노예)을 만들어보자.

몇일전부터 C언어 공부를 다시하게 되었다. 여러가지 빼먹은 문법들도 공부하면서

포인터 부분은 이해하지 못한 부분도 있기때문에 새로운 마음가짐으로 공부하는데

역시 지루한 부분은 있는것같다. 그래서 어느 강사님 블로그 에 C언어로 게임 만드는 코드가

있었다. 이코드는 C언어를 입문하는 학생한테도 충분히 좋은 코드다 설명 주석처리도

많고 함수도 없고 하지만 나같은경우 C언어의 라이브러리 같은건 잘 모르기에 그부분을

이해하는되는 힘든 부분이있었다.

#include #include //문자열 변환 , 사난수 생성,동적 메모리 //관리 등의 함수들을 포함하고 있다. #include //시간과 날짜를 얻거나 조작하는 함수들을 //포함하고있다. #include //콘솔에서 입력과 출력에 관한 헤더이다. #define MAX_PROBABILITY 100.0f //성공확률 최대치 #define WAIT_TIME 2 // 강화 대기시간 int main(void) { int isTry = 0; //강화를 할 것인지 선택 int level = 0; //현재 무기의 레벨 float probability = MAX_PROBABILITY; //현재 강화 성공확률 time_t retTime = 0; //대기시간 임시 저장 변수 int randNum = 0;//랜덤값을 저장할 변수 srand((int)time(NULL)); //랜덤 시드값 설정 while(1) { //화면 정리 system("@cls||clear"); //타이틀 화면 출력 printf("*= Blacksmith With C = *

"); printf(" a game by catHuman

"); //현재 상태와 강화 도전 질의 출력 printf("무기레벨 : + %d

", level); printf("성공확률 : %.2f%%

", probability); printf("도전하시겠습니까?

"); printf("1.강화 2.포기

"); scanf_s("%d", &isTry;); switch (isTry) { case 1: //강화에 도전 할 경우 printf("

강화중..

"); //지정된 시간(초) 만큼 대기 retTime = time(0) + WAIT_TIME; while (time(0) < retTime); //랜덤 값 추출 randNum = rand() % 100; //추출한 랜덤 값이 성공확률 보다 작으면 성공 if (randNum < probability) { printf("***** SUCCESS *****

"); printf("* *

"); printf("* + %d -> + %d *

", level, level + 1); printf("* *

"); printf("***** SUCCESS *****

"); //강화에 성공 했을 시 , 레벨을 하나 증가시키고 //성공 확률을 보정 //이떄 현재 성공확률의 10%에 현재 레벨로 //가중치를 추가로 적용 level++; probability -= (probability / 10.0f) * level; } else { //실패화면 출력 printf("어이쿠.. 손이 미끌어졌네..

"); printf("+ %d 무기를 잃었습니다.

",level); level = 0; probability = MAX_PROBABILITY; } break; case 2: //포기할 경우 프로그램 종료 printf("okay bye....

"); return -1; } //진행상황 확인이 용이 하도록 대기 printf("

계속하려면 아무키나 누르십시오.

"); _getch(); } return 0; }

코드가 간결하고 이해하는게 크게 어렵지는 않았다.

system("@cls||clear");

루프가 매번 반복되면서 프로그램 씬을 모두 초기화 해주는 함수인것같다.

scanf_s("%d" , &isTry;);

뭔가 의아하다 scanf 는 #define _CRT_SECURE_NO_WARNINGS라는 전처리기 를 사용해야된다.

이는 오류를 발생하기 쉽다고 인터넷에 나와있으며 이를 대체하기위해서 scanf_s라는 것을

사용할수 있다고 인터넷에 나와있다. scanf_s 의 사용법은 scanf_s("%d" , 입력할것 , 입력할것의 사이즈 );

인것같다. 그치만 위는 사이즈부분을 생략해도 사용이가능하다. 조금더 c언어 공부를 하면 알아낼것같다.

randNum = rand() % 100;

인터넷에 검색해보니 rand()는 무작위 숫자를 가져오는거다. 근데 rand() % 100 나머지 연산을 하면

아무리 숫자가 높아도 100%으로나누면 0~99의 값이 나온다고한다. 음 코드상 문제가 있는건지

잘모르겠지만 99까지나오기에 나는 if(randNum + 1 < probability)로 수정하긴했으나 일단

기존 코드로 올리겠다.

retTime = time(0) + WAIT_TIME;

while(time(0) < retTime);

인터넷에 검색해보니 time(0)는 실제시간을 초로 나타내는것같다. 지금시간이 오후 12:00 라면

time(0) + WAIT_TIME(2); 는 현재시간에 2초를 더한거랑 같은거다

시간이 2초이상흐르면 자동되는것같다.

srand(int)time(NULL);//랜덤 시드값

이 함수를 사용하지않으면 랜덤함수가 항상 정해진값으로 나오는것같다.

추가로 원글에는 소스코드를 이해하는데 문제가 없으면 다음과같은 내용을 추가해보라고 했다

1.예외처리

2.기능별 함수화

3. 발전되고 흥미로운 형태의 확률 시스템

4. 자본금과 강화비용 시스템 추가

5. 강화된 무기를 판매

1.예외처리

흠 예외처리 해야할부분을 고민해보았다 일단 1, 2 선택지말고 3번의 선택지를 고를경우의

예외처리를 해야할것이다. case 1 , 2 의 선택지가 있다 즉 1, 2 번 선택지이외의

3~ 무한 의 숫자를 입력한다면 어떻게 할것인다를 넣으면된다 이는 default를 활용할것같다.

case 2: //포기할 경우 프로그램 종료 printf("okay bye....

"); return -1; default: printf("지정범위를 벗어났습니다. 다시 고르십시오."); _getch(); continue; }

case2 밑에 default문을 추가하였다. 그리고 continue로 다시 반복문을 반복하게 만들었다. 이런식으로하니

잘실행이되었습니다.

그다음 문항에는 기능별 함수화 라고 나와있다. C 언어의 함수를 잘 나누는법 까진 공부하지 못했다.

자신은 없지만 그래도 이해를 할필요가 있으니 한번 나눠보자.

#include #include //문자열 변환 , 사난수 생성,동적 메모리 //관리 등의 함수들을 포함하고 있다. #include //시간과 날짜를 얻거나 조작하는 함수들을 //포함하고있다. #include //콘솔에서 입력과 출력에 관한 헤더이다. #define MAX_PROBABILITY 100.0f //성공확률 최대치 #define WAIT_TIME 2 // 강화 대기시간 void RenewalScene(); void TitleScene(); void UpgradeScene(int *level, float *probability); int Upgrade(int isTry, time_t retTime, int randNum , float *probability, int *level); void Restart(); int main(void) { int isTry = 0; //강화를 할 것인지 선택 int level = 0; //현재 무기의 레벨 float probability = MAX_PROBABILITY; //현재 강화 성공확률 time_t retTime = 0; //대기시간 임시 저장 변수 int randNum = 0;//랜덤값을 저장할 변수 int zero = 0; srand(int)time(NULL);//랜덤 시드값 while (1) { RenewalScene();//화면 정리 TitleScene();//타이틀 화면 출력 //현재 상태와 강화 도전 질의 출력 UpgradeScene(&level;, &probability;); //실제 강화 로직을 짜는곳 zero = Upgrade(isTry, retTime, randNum ,&probability;, &level;); if (zero == 1) { } else if (zero == 2) { return -1; } else { continue; } //진행상황 확인이 용이 하도록 대기 Restart(); } return 0; } void RenewalScene() { //화면 정리 system("@cls||clear"); } void TitleScene() { //타이틀 화면 출력 printf("강화의 노예

"); } void UpgradeScene(int *level , float *probability) { printf("무기레벨 : + %d

", *level); printf("성공확률 : %.2f%%

", *probability); printf("도전하시겠습니까?

"); printf("1.강화 2.포기

"); } int Upgrade(int isTry , time_t retTime , int randNum ,float *probability , int *level) { scanf_s("%d", &isTry;); switch (isTry) { case 1: //강화에 도전 할 경우 printf("

강화중..

"); //지정된 시간(초) 만큼 대기 retTime = time(0) + WAIT_TIME; while (time(0) < retTime); //랜덤 값 추출 randNum = rand() % 100; //추출한 랜덤 값이 성공확률 보다 작으면 성공 if (randNum + 1 < *probability) { printf("***** SUCCESS *****

"); printf("* *

"); printf("* + %d -> + %d *

", *level, *level + 1); printf("* *

"); printf("***** SUCCESS *****

"); //강화에 성공 했을 시 , 레벨을 하나 증가시키고 //성공 확률을 보정 //이떄 현재 성공확률의 10%에 현재 레벨로 //가중치를 추가로 적용 ++* level; *probability -= (*probability / 10.0f) * *level; } else { //실패화면 출력 printf("어이쿠.. 손이 미끌어졌네..

"); printf("+ %d 무기를 잃었습니다.

", level); level = 0; *probability = MAX_PROBABILITY; } return isTry; break; case 2: //포기할 경우 프로그램 종료 printf("okay bye....

"); return isTry; default: printf("지정범위를 벗어났습니다. 다시 고르십시오."); _getch(); return isTry; } } void Restart() { //진행상황 확인이 용이 하도록 대기 printf("

계속하려면 아무키나 누르십시오.

"); _getch(); }

음 함수를 나눠짜긴했으나 switch문을 함수로 나누는 조금 헷갈렸다. 일단 int형 함수로 만들어서

전부다 isTry를 반환값을주고 main에서 반환값이 조건문을 통해 동일하며 해당 조건을 실행하도록

만들었다. 또한 포인터를 써서 값을 전달해주었다. 분명이보다 좋은 방법이 코드가 있을것 같다.

그다음 항목은 발전되고 흥미로운 형태의 확률 시스템 이라고한다. 가중치 10%를 더해

확률을 짠다는건 너무 재미가없다. 무슨 방법이 좋을지 같이 생각을 해보자..

일단 이런식으로 확률을 짠다면 특정 레벨일때마다 확률을 줄이는 방식으로 바꾸었다.

이럼 어느정도는 계속 확률업을하여 초반단계에는 기분이좋다 하지만 나중가면 갈수록 화가 치밀어

오르는 확률... 유사 많은 강화 시스템에 씨이는 방식인것같다.

++*level; if (*level > 0 && *level <= 5) { *probability = 90; } else if (*level > 5 && *level <= 10) { *probability = 75; } else if (*level > 10 && *level <= 15) { *probability = 50; } else if (*level > 15 && *level < 20) { *probability = 20; } else { *probability = 10; }

그 다음 문항은 자본금과 강화비용 시스템 추가 흠 이부분은 3번 항목을 만들어서 일하는 시스템을 만들고

강화를 실패하더라도 파괴가아닌 어느구간에선 유지 어느구간에선 1단계하락으로 바꿔보자.

또한 실수로 2번을 누를수도 있기에 최대한 누르기 힘든 0번 칸에 두겠다.

#include #include //문자열 변환 , 사난수 생성,동적 메모리 //관리 등의 함수들을 포함하고 있다. #include //시간과 날짜를 얻거나 조작하는 함수들을 //포함하고있다. #include //콘솔에서 입력과 출력에 관한 헤더이다. #define MAX_PROBABILITY 100.0f //성공확률 최대치 #define WAIT_TIME 0.3f // 강화 대기시간 void RenewalScene(); void TitleScene(); void UpgradeScene(int *level, float *probability , int *gold); int Upgrade(int isTry, time_t retTime, int randNum , float *probability, int *level , int *gold); void Restart(); int main(void) { int isTry = 0; //강화를 할 것인지 선택 int level = 0; //현재 무기의 레벨 float probability = MAX_PROBABILITY; //현재 강화 성공확률 time_t retTime = 0; //대기시간 임시 저장 변수 int randNum = 0;//랜덤값을 저장할 변수 int gold = 0; int zero = 0; srand((int)time(NULL));//랜덤 시드값 while (1) { RenewalScene();//화면 정리 TitleScene();//타이틀 화면 출력 //현재 상태와 강화 도전 질의 출력 UpgradeScene(&level;, &probability; , &gold;); //실제 강화 로직을 짜는곳 zero = Upgrade(isTry, retTime, randNum ,&probability;, &level; , &gold;); if (zero == 0) { return -1; } else if (zero == 1) { } else if (zero == 2) { } else { continue; } //진행상황 확인이 용이 하도록 대기 Restart(); } return 0; } void RenewalScene() { //화면 정리 system("@cls||clear"); } void TitleScene() { //타이틀 화면 출력 printf("강화의 노예

"); } void UpgradeScene(int *level , float *probability ,int *gold) { printf("보유중이 골드 : %d

", *gold); printf("무기레벨 : + %d

", *level); printf("성공확률 : %.2f%%

", *probability); printf("도전을 하시려면 50골드를 지불하십시오.

"); printf("1.강화 2.돈벌기 0.포기하기

"); } int Upgrade(int isTry , time_t retTime , int randNum ,float *probability , int *level , int *gold) { int ran = 0; int randgold = 0; scanf_s("%d", &isTry;); switch (isTry) { case 0: //포기할 경우 프로그램 종료 printf("okay bye....

"); return isTry; case 1: //강화에 도전 할 경우 if (*gold < 50) { printf("골드가 부족합니다."); return isTry; break; } printf("

강화중..

"); *gold -= 50; //지정된 시간(초) 만큼 대기 retTime = time(0) + WAIT_TIME; while (time(0) < retTime); //랜덤 값 추출 randNum = rand() % 100; //추출한 랜덤 값이 성공확률 보다 작으면 성공 if (randNum + 1 < *probability) { printf("***** SUCCESS *****

"); printf("* *

"); printf("* + %d -> + %d *

", *level, *level + 1); printf("* *

"); printf("***** SUCCESS *****

"); //강화에 성공 했을 시 , 레벨을 하나 증가시키고 //성공 확률을 보정 //이떄 현재 성공확률의 10%에 현재 레벨로 //가중치를 추가로 적용 ++*level; if (*level > 0 && *level <= 5) { *probability = 90; } else if (*level > 5 && *level <= 10) { *probability = 75; } else if (*level > 10 && *level <= 15) { *probability = 50; } else if (*level > 15 && *level < 20) { *probability = 20; } else { *probability = 10; } } else { if (*level <= 5) { printf("이런 강화에 실패하였습니다.

"); printf("+ %d 등급무기는 유지됩니다.

", *level); } else if (*level > 5 && *level < 15) { printf("이런 강화에 실패하였습니다,

"); printf("+ %d 등급무기가 한단계 하락합니다.

", *level); --* level; } //실패화면 출력 else { printf("어이쿠.. 손이 미끌어졌네..

"); printf("+ %d 무기를 잃었습니다.

", *level); *level = 0; *probability = MAX_PROBABILITY; } } return isTry; break; case 2: printf("돈 버는중....

"); retTime = time(0) + WAIT_TIME; while (time(0) < retTime); ran = rand() % 3; if (ran == 0) { printf("피자 배달하는중...

"); } else if (ran == 1) { printf("편의점 알바하는중...

"); } else if (ran == 2) { printf("다이소 물건 정리하는중...

"); } retTime = time(0) + WAIT_TIME; while (time(0) < retTime); randgold = rand() % 100; if (randgold < 10) { randgold += 10; } printf("%d골드를 획득하셧습니다.", randgold); *gold += randgold; return isTry; break; default: printf("지정범위를 벗어났습니다. 다시 고르십시오."); _getch(); return isTry; } } void Restart() { //진행상황 확인이 용이 하도록 대기 printf("

계속하려면 아무키나 누르십시오.

"); _getch(); }

5번째 문항은 다음과같다. 무기를 판매하는 기능을 넣어라. 음 이때까지 문항을 잘해왔으면 생각보다 어렵지 않을것같다. 일단 3번항문을 추가하여 현재 무기 판매를 넣어보자.또한 게임의 승리조건을 추가해보겠다.

골드를 어느 수준까지 모으면 게임을 승리한다라는 조건을 추가할것이다.

#include #include //문자열 변환 , 사난수 생성,동적 메모리 //관리 등의 함수들을 포함하고 있다. #include //시간과 날짜를 얻거나 조작하는 함수들을 //포함하고있다. #include //콘솔에서 입력과 출력에 관한 헤더이다. #define MAX_PROBABILITY 100.0f //성공확률 최대치 #define WAIT_TIME 2 // 강화 대기시간 void RenewalScene(); void TitleScene(); void UpgradeScene(int* level, float* probability, int* gold); int Upgrade(int isTry, time_t retTime, int randNum , float* probability, int* level, int* gold); void Restart(); int Winner(int* gold); int main(void) { int isTry = 0; //강화를 할 것인지 선택 int level = 0; //현재 무기의 레벨 float probability = MAX_PROBABILITY; //현재 강화 성공확률 time_t retTime = 0; //대기시간 임시 저장 변수 int randNum = 0;//랜덤값을 저장할 변수 int gold = 0; int zero = 0; int win = 0; srand((int)time(NULL));//랜덤 시드값 while (1) { win = Winner(&gold;); if (win == 1) { return -1; } RenewalScene();//화면 정리 TitleScene();//타이틀 화면 출력 //현재 상태와 강화 도전 질의 출력 UpgradeScene(&level;, &probability;, &gold;); //실제 강화 로직을 짜는곳 zero = Upgrade(isTry, retTime, randNum , &probability;, &level;, &gold;); if (zero == 0) { return -1; } else if (zero == 1) { } else if (zero == 2) { } else if (zero == 3) { } else { continue; } //진행상황 확인이 용이 하도록 대기 Restart(); } return 0; } void RenewalScene() { //화면 정리 system("@cls||clear"); } void TitleScene() { //타이틀 화면 출력 printf("강화의 노예

"); } void UpgradeScene(int* level, float* probability, int* gold) { printf("승리조건 골드를 20000골드 이상 모아라

"); printf("보유중이 골드 : %d

", *gold); printf("무기레벨 : + %d

", *level); printf("성공확률 : %.2f%%

", *probability); printf("도전을 하시려면 50골드를 지불하십시오.

"); printf("1.강화 2.돈벌기 3.무기판매 0.포기하기

"); } int Upgrade(int isTry, time_t retTime, int randNum , float* probability, int* level, int* gold) { int ran = 0; int randgold = 0; int randgold2 = 0; scanf_s("%d", &isTry;); switch (isTry) { case 0: //포기할 경우 프로그램 종료 printf("okay bye....

"); return isTry; case 1: //강화에 도전 할 경우 if (*gold < 50) { printf("골드가 부족합니다."); return isTry; break; } printf("

강화중..

"); *gold -= 50; //지정된 시간(초) 만큼 대기 retTime = time(0) + WAIT_TIME; while (time(0) < retTime); //랜덤 값 추출 randNum = rand() % 100; //추출한 랜덤 값이 성공확률 보다 작으면 성공 if (randNum + 1 < *probability) { printf("***** SUCCESS *****

"); printf("* *

"); printf("* + %d -> + %d *

", *level, *level + 1); printf("* *

"); printf("***** SUCCESS *****

"); //강화에 성공 했을 시 , 레벨을 하나 증가시키고 //성공 확률을 보정 //이떄 현재 성공확률의 10%에 현재 레벨로 //가중치를 추가로 적용 ++* level; if (*level > 0 && *level <= 5) { *probability = 95; } else if (*level > 5 && *level <= 10) { *probability = 90; } else if (*level > 10 && *level <= 15) { *probability = 80; } else if (*level > 15 && *level < 20) { *probability = 60; } else { *probability = 10; } } else { if (*level <= 5) { printf("이런 강화에 실패하였습니다.

"); printf("+ %d 등급무기는 유지됩니다.

", *level); } else if (*level > 5 && *level < 16) { printf("이런 강화에 실패하였습니다,

"); printf("+ %d 등급무기가 한단계 하락합니다.

", *level); --* level; } //실패화면 출력 else { printf("어이쿠.. 손이 미끌어졌네..

"); printf("+ %d 무기를 잃었습니다.

", *level); *level = 0; *probability = MAX_PROBABILITY; } } return isTry; break; case 2: printf("돈 버는중....

"); retTime = time(0) + WAIT_TIME; while (time(0) < retTime); ran = rand() % 3; if (ran == 0) { printf("피자 배달하는중...

"); } else if (ran == 1) { printf("편의점 알바하는중...

"); } else if (ran == 2) { printf("다이소 물건 정리하는중...

"); } retTime = time(0) + WAIT_TIME; while (time(0) < retTime); randgold = rand() % 150; if (randgold < 10) { randgold += 10; } printf("%d골드를 획득하셧습니다.", randgold); *gold += randgold; return isTry; break; case 3: printf("현재 무기를 판매 하겠습니다.

"); for (int i = 0; i <= 20; i++) { if (*level == i) { randgold2 = rand() % 150; if (randgold2 < 20) { randgold2 += 20; } if (i > 10) { randgold2 += 40; } else if (i > 14) { randgold2 += 100; } else if (i > 15) { randgold2 += 200; } else if (i > 16) { randgold2 += 300; } else if (i > 17) { randgold2 += 500; } else if (i > 18) { randgold2 += 1000; } else if (i > 19) { randgold2 += 10000; } *gold += randgold2 * i; printf("골드를 %d 만큼 획득하였습니다.

", randgold2 * i); *probability = MAX_PROBABILITY; *level = 0; } } return isTry; break; default: printf("지정범위를 벗어났습니다. 다시 고르십시오."); _getch(); return isTry; } } void Restart() { //진행상황 확인이 용이 하도록 대기 printf("

계속하려면 아무키나 누르십시오.

"); _getch(); } int Winner(int* gold) { if (*gold > 20000) { printf("승리하셧습니다."); return 1; } }

일단 어떻게든 구현은해보았다 하지만 밸런스적인 부분까지는 건들지않았다. 그부분까지 건들어버리면

시간이 어마하게 소모되고 로직도 다시짜야될것이다. 그래서 그부분은 패스했다.

from http://cathuman.tistory.com/26 by ccl(A) rewrite - 2021-07-22 18:25:35

댓글