8일차 (12/20)
콘솔창(CMD)
과거 아무 운영체제도 없었던 시절에 Dos라는 시스템이 있었다. Dos는 명령 줄 기반의 프로그램이다.
우리가 F5를 누르면 내 콘솔창을 실행하는 것이 아니다. 내 프로그램이 따로 실행되고 내 프로그램에서 콘솔창에 출력을 요청하는 것이다.
콘솔창은 특수문자를 통해 특수한 출력기호를 사용할 수 있는데 전부 \를 사용해서 표현핟.
\n 등을 콘솔창은 한글자로 본다.
Text RPG
게임을 만드때 중요한 점.
랜더링과 로직은 분리하는게 좋다.
한 함수가 두가지 목적을 가지면 안된다.
만약 그런 함수가 있다면 1가지 목적을 가진 함수 2개를 모아서 만드는게 유리하다.
쪼개서 사용해보면 처음에는 불편하다.
이 메인 루프에서 모든 일이 벌어진다.
이때 한번의 루프가 도는 것을 프레임이라고 합니다.
루프를 멈추기 위해 conio.h안에 있는 _getch를 사용할 것이다.
_getch => 아무키나 눌릴 때까지 기다려준다.
system() => 콘솔창에 명령을 입력하는 함수
cls => 콘솔창 내용을 지우는 명령어
system("cls"); => 코드로 구현한 콘솔창의 내용을 지우라는 코드
위의 함수들을 이용해 전투를 구현해보았다.
#include <iostream>
#include <conio.h>
void StatusRender(const char* _Name, const int _Hp, const int _Atk)
{
int NameLength = printf_s("%s", _Name);
for (int i = 0; i < 50 - NameLength; i++)
{
printf_s("-");
}
printf_s("\n");
printf_s("체 력 : %d\n", _Hp);
printf_s("공격력 : %d\n", _Atk);
for (int i = 0; i < 50; i++)
{
printf_s("=");
}
printf_s("\n\n");
}
//공격의 행동을 화면에 랜더링 하는 함수
void DamageRender(const char* _AtkName, const int& _Atk, const char* _DefName)
{
printf_s("%s가 %d의 공격력으로 %s를 공격했습니다.\n", _AtkName, _Atk, _DefName);
}
//실제 데미지를 데이터적으로 주는 함수
void DamageLogic(const int& _Atk, int& _DefHp)
{
_DefHp -= _Atk;
}
//죽음 판정
int DeadCheck(const int& _PlayerHp, const int& _MonsterHp)
{
if (_PlayerHp <= 0)
{
return _PlayerHp;
}
else if (_MonsterHp <= 0)
{
return _MonsterHp;
}
}
//누군가의 죽음을 화면에 랜더링
void DeadRender(const char* _DeadName)
{
printf_s("%s가 사망하였습니다.\n", _DeadName);
}
int main()
{
char PlayerName[100] = "Fighter";
int PlayerHp = 100;
int PlayerAtk = 10;
char MonsterName[100] = "Orc";
int MonsterHp = 50;
int MonsterAtk = 5;
int DeadCount = 1;
system("cls");
StatusRender(PlayerName, PlayerHp, PlayerAtk);
StatusRender(MonsterName, MonsterHp, MonsterAtk);
int Input = 0;
while (true)
{
if (DeadCount > 0)
{
Input = _getch();
system("cls");
DamageLogic(PlayerAtk, MonsterHp);
DeadCount = DeadCheck(PlayerHp, MonsterHp);
StatusRender(PlayerName, PlayerHp, PlayerAtk);
StatusRender(MonsterName, MonsterHp, MonsterAtk);
DamageRender(PlayerName, PlayerAtk, MonsterName);
Input = _getch();
system("cls");
DamageLogic(MonsterAtk, PlayerHp);
DeadCount = DeadCheck(PlayerHp, MonsterHp);
StatusRender(PlayerName, PlayerHp, PlayerAtk);
StatusRender(MonsterName, MonsterHp, MonsterAtk);
DamageRender(MonsterName, MonsterAtk, PlayerName);
}
else
{
break;
}
}
if (PlayerHp <= 0)
{
DeadRender(PlayerName);
}
else if (MonsterHp <= 0)
{
DeadRender(MonsterName);
}
}
난수
- 특정 공식에 따라서 어떠한 수를 변형시킨 수가 나오는 것.
난수 공식의 첫 값을 시드벨류라고 한다.
시드벨류를 바꾸는 함수 srand()
시드벨류를 이용해 난수값을 생성하는 함수 rand()
매번 다른 수가 나오려면 시드벨류의 값이 바뀌어야 한다. 그러나 한번 바꿔준 시드벨류는 또 바꿀 필요가 없다.
// 난수의 시드벨류
int Random = 0;
void SeedChange(int _Value) // srand
{
Random = _Value;
}
int Randomint() // rand
{
return ++Random;
}
위 코드의 Randomint도 ++뿐이지만 특정 공식에 따라 매번 값을 변화시키는 것이기 때문에 난수라고 할 수 있다.
signed와 unsigned
우리가 지금까지 쓰고 있는 int는 signed int를 생략한 것이다.
이 둘을 이해하려면 2의 보수법을 기억해야 한다.
2의 보수법은 부호비트를 기준으로하여 해석된다.
int는 계산을 해보면 32비트이므로 2의 32승까지의 양수를 표현할 수 있지만 부호비트 때문에 31승 까지밖에 표현하지 못한다. 음수는 31승 +1만큼의 음수를 표현할 수 있다.
그러나 음수를 쓸일이 없는 변수가 있을 때가 있다. 이때 부호비트도 양수 표현으로 사용하고 싶다고 붙이는 keyword가 있다. 이것이 unsigned이다. 음수도 사용해야할 경우는 signed를 사용하면 된다.
signed int Value = -1;
// Value의 값은 -1이다.
unsigned int UValue = -1;
// unsigend int에 -1을 넣어주면 부호가 없을때의 양수 최대값이 된다.
typedef
자료형에 별명을 붙이는 것이다.
예를 들어
typedef unsigned int unit;
라고 선언하고
unit Value;
를 선언한다면 Value는 unsigned int로 선언된 것이다.
객체지향(OOP)
지금은 생산성의 시대이다. 객체지향으로 코드를 짜면 컴파일이든 실행이든 속도는 느려지지만 생산성이 좋아진다.
객체지향이란 현실적으로는 프로그래밍 패러다임의 1가지 종류이다.
객체(Object)라는 개념만을 사용해서 코딩하는 것을 객체지향이라고 한다.
프로그래밍 언어는 각각 추구하는 이상이 있다.
C++은 객체지향 언어라는 표현은 잘못됐다. 정확히는 객체지향도 할 수 있는 언어(멀티패러다임 언어)이다.
절차지향
객체지향
템플릿메타
함수형
등등 여러 패러다임을 사용한다.
지금까지 강의에서는 절차지향만을 사용했다. (C가 절차지향 언어이다.)
객체(object)
객체지향의 기본은 private형에서 나온다. 객체지향은 전역이라는 개념이 존재하면 안된다. 모든 것은 개념안에 묶여있어야 한다. 즉, 개념이 메모리화된 것을 객체라고 한다.
몬스터 => 개념
몬스터1을 생성 <= 객체
그래서 보통 자료형 == 개념이라고도 볼 수 있다.
int는 정수라고하는 개념이다. 이 개념만으로는 아무것도 할 수 없다.
정수를 사용하고 정수로 계산을 하려면 객체화라는 것을 해야한다.
int A = 0과 같이 객체화해야 우리는 정수를 사용할 수 있다.
이런 것들은 C++만든 사람들이 먼저 만들어준 개념이라고 생각하면 된다.
이런 기본적으로 있어야해서 만들어준 개념들을 기본 자료형이라고 부른다.
class
class라는 것은 개념을 만드는 것이라고 보면 된다.
예를들어 몬스터를 만드려고 하면
class Monster
{
};
를 만들어야한다. 이런 class를 사용자정의 자료형이라고 한다.
그리고 Monster NewMonster; 와 같이 객체화해서 사용하는 것이다.
이때 만들기만 해도 초기화하는 방법이 한가지 있다.
Monster NewMonster = Monster();
이렇게 사용하는 것이다.
class 내부를 멤버공간이라고 한다. 보통은 클래스 내부라고 한다.
클래스 내부에는 상태와 행동이 있어야한다. 이것을 채우는 것을 구체화를 한다고 생각하면 된다.
상태는 변수로 표현한다.
int Hp;
행동은 함수로 표현한다.
void Damage(int _Atk);
단축키
- F12 => 커서를 자료형이나 함수 사이에 놓고 그 자료형이나 함수에 프로그래머가 만든 선언이 존재할 경우 그 선언으로 이동한다. (주의할 점 : 프로젝트를 만약 처음 킨 것이라면 느릴 수도 있다.)