게임프로그래밍(C++)

[게임프로그래밍] 난수와 시간1 ⭐

susot 2025. 3. 19. 22:45

난수

난수: 정의된 범위 내에서 무작위로 추출된 수

 

난수의 필요성: 난수는 게임에서 랜덤 요소를 뽑을 수 있기 때문에 중요합니다. 하지만 컴퓨터는

난수를 스스로 뽑아내는 것이 불가능합니다.

 

C++에서 난수를 뽑아내는 방법

 

rand() 함수 사용

하지만 rand()함수만 사용하면

 

 

매번 같은 값만 나옵니다. 랜덤이 아닙니다.

왜냐하면 컴퓨터는 랜덤을 스스로 뽑아내는 게 불가능하기 때문에 난수 테이블이 존재합니다.

 

그러면 랜덤은 어떻게 만드는가?

 

Srand()

 

Srand는 난수 테이블 시드값을 변경할 수 있는 함수입니다. 

 

그러면 Srand안에는 매개변수로 무엇을 넣어줘야 할까요?

컴퓨터가 모두 실시간으로 값이 변하는 수인 시간을 넣어주면 됩니다.

 

 

srand((unsigned int)time(NULL));을 넣어주면 그때그때마다 시드값이 바뀌기 때문에 다른 값이 뽑힙니다.

 

하지만 rand값이 완전 날것이기 때문에 가공을 해야합니다. 만약 rand값이 1~6이 나오게 하고 싶다면

rand() % 6 + 1을 하면 1 ~ 6까지 숫자로 가공이 되어 뽑히게 됩니다.

 

이를 이용하여 확률게임을 C++로 제작할 수 있습니다.

 

1. 숫자 맞추기

 

 

 

#include<iostream>
using namespace std;
int main()
{
    cout << "==============" << endl;
    cout << "  숫자 맞추기" << endl;
    cout << "==============" << endl;
    cout << "설명: 1~100 숫자 중 하나를 알아내보세요." << endl;
    cout << "종료는 0을 누르세요." << endl;

    // 난수뽑아야됩니다. (1 ~ 100)
    // 입력을 받고 판단
    // 반복
    srand((unsigned int)time(NULL));
    int num;
    num = rand() % 100 + 1;
    int inp, cnt = 1;
    while (true)
    {
        cout << "숫자를 입력하세요:";
        cin >> inp;
        if (inp == 0)
        {
            cout << "0이 눌려 게임이 종료됩니다." << endl;
            break;
        }
        else if (inp == num)
        {
            cout << "축하합니다. 당신은 " << cnt << "번만에 알아냈습니다." << endl;
        }
        else if (inp < num)
            cout << inp << "보다 큽니다." << endl;
        else
            cout << inp << "보다 작습니다." << endl;
        cnt++;
    }

}

 

 

프로그램이 시작되면 num에다가 1부터 100중에 숫자 하나를 랜덤 하게 넣습니다.

 

그리고 while(true) 문에서 계속 입력을 받으면서 입력이 0이면 프로그램 종료를 하고

아니라면 입력과 랜덤수를 비교해서 같다면 정답, 아니면 각각을 알려주고 count를 1 증가시킵니다.

 

2. 무기 강화 게임

 

 

#include<iostream>
using namespace std;

int main()
{
    // 변수
    // 레벨, 라이프, 성공확률
    // 난수 => srand(), rand()
    srand((unsigned int)time(NULL));
    int weaponLevel = 1; 
    int life = 3;
    int successRate = 50;

    // 초기 출력
    cout << "무기 강화 게임에 오신 것을 환영합니다!" << endl;
    cout << "현재 무기 강화 레벨: " << weaponLevel << endl;
    cout << "현재 강화 성공 확률: " << successRate << endl;
    cout << "남은 생명: " << life << endl;
    int inp;
    while (true) 
    {
        cout << "어떤작업을 수행하시겠습니까?" << endl;
        cout << "1. 무기 강화하기" << endl;
        cout << "2. 나가기" << endl;
        cout << "선택: ";
        cin >> inp;
        if (inp == 1)
        {
            bool IsSuccess = (rand() % 100) < successRate;
            if (IsSuccess)
            {
                cout << "무기 강화에 성공했습니다!" << endl;
                weaponLevel++;
                successRate -= rand() % 5 + 1;
            }
            else
            {
                cout << "무기 강화에 실패했습니다." << endl;
                successRate += rand() % 6 + 5; // 5 ~10 
                // 0 ~ 5 => 5 ~ 10
                life--;
            }
            cout << "======================" << endl;
            cout << "무기 강화 게임에 오신 것을 환영합니다!" << endl;
            cout << "현재 무기 강화 레벨: " << weaponLevel << endl;
            cout << "현재 강화 성공 확률: " << successRate << endl;
            cout << "남은 생명: " << life << endl;
        }
        else if (inp == 2)
        {
            cout << "나가기를 선택했습니다. 게임이 종료됩니다." << endl;
            break;
        }
        
        if (weaponLevel >= 10)
        {
            cout << "축하합니다. 레벨 10이 되었습니다" << endl;
            break;
        }
        else if (life <= 0)
        {
            cout << "죽었습니다" << endl;
            break;
        }
    }
}

 

이처럼 while(true)에서 계속 입력을 받으면서 강화를 실패하면 확률을 올려주고 생명을 깎고,

강화를 성공하면 확률을 낮추고 레벨을 올립니다. 만약 레벨 10이 되거나 생명이 0이 되면 텍스트를 출력하고 break문으로 빠져나갑니다.

 

그러면 만약 이 코드를 함수로 분리한다면?

 

크게 Init, Update, Render로 나눌 수 있습니다.

 

Init : 프로그램이 시작되었을 때, 가장 먼저 한 번만 실행하는 메서드

Update : 매 프레임마다 갱신시켜 주는 역할

Render : 매 프레임마다 콘솔창에 출력해 주는 역할

 

위에 코드를 Init, Update, Render로 분리하면 다음과 같이 분리할 수 있습니다.

 

#include<iostream>
using namespace std;



void Init(int weaponLevel, int life, int successRate); // 함수 전방선언
void Update(int& weaponLevel, int& life, int& successRate, bool& isRunning);
void Render(int weaponLevel, int life, int successRate);

int main()
{
	int weaponLevel = 1;
	int life = 3;
	int successRate = 50;
	bool IsRunning = true;


	Init(weaponLevel, life, successRate); // Start
	while (IsRunning)
	{
		Update(weaponLevel, life, successRate, IsRunning);
		Render(weaponLevel, life, successRate);
	}
}

void Init(int weaponLevel, int life, int successRate)
{
	srand((unsigned int)time(NULL));
	// 초기 출력
	cout << "무기 강화 게임에 오신 것을 환영합니다!" << endl;
	cout << "현재 무기 강화 레벨: " << weaponLevel << endl;
	cout << "현재 강화 성공 확률: " << successRate << endl;
	cout << "남은 생명: " << life << endl;
}

void Update(int& weaponLevel, int& life, int& successRate, bool& isRunning)
{
	cout << "어떤작업을 수행하시겠습니까?" << endl;
	cout << "1. 무기 강화하기" << endl;
	cout << "2. 나가기" << endl;
	cout << "선택: ";

	int inp;
	cin >> inp;
	if (inp == 1)
	{
		bool IsSuccess = (rand() % 100) < successRate;
		if (IsSuccess)
		{
			cout << "무기 강화에 성공했습니다!" << endl;
			weaponLevel++;
			successRate -= rand() % 5 + 1;
		}
		else
		{
			cout << "무기 강화에 실패했습니다." << endl;
			successRate += rand() % 6 + 5; // 5 ~10 
			// 0 ~ 5 => 5 ~ 10
			life--;
		}
		cout << "======================" << endl;
		cout << "무기 강화 게임에 오신 것을 환영합니다!" << endl;
		cout << "현재 무기 강화 레벨: " << weaponLevel << endl;
		cout << "현재 강화 성공 확률: " << successRate << endl;
		cout << "남은 생명: " << life << endl;
	}
	else if (inp == 2)
	{
		cout << "나가기를 선택했습니다. 게임이 종료됩니다." << endl;
		isRunning = false;
	}

	if (weaponLevel >= 10)
	{
		cout << "성공했습니다.";
		isRunning = false;
	}

	else if (life <= 0)
	{
		cout << "실패했습니다.";
		isRunning = false;
	}
}

void Render(int weaponLevel, int life, int successRate)
{
	// 현재 상태 출력
	cout << "====================" << endl;
	cout << "현재 무기 강화 레벨:" << weaponLevel << endl;
}

 

무조건 출력을 Render에서만 할 필요 없이 Update에서도 필요에 따라 출력을 해줘도 됩니다.