1차원 배열 방식으로도 초기화가 된다. 그렇다고 메모리에 2차원으로 들어가 있는 것은 아니다.
char Arr[3][3] = {'0','1','2','3','4','5','6','7','8'};
좀 더 명시적인 초기화 방법.
char Arr[3][4] = { {'0','1','2'},{'3','4','5'},{'6','7','8'}};
char Arr2[3][4] = { "123", "345", "678"};
각각의 자료형은 다음과 같다.
Arr : char [3][4]
Arr[0] : char [4]
Arr[0][0] : char
char Arr[3][4] = { {'0','1','2', '2'},{'3','4','5'},{'6','7','8'}};
printf_s(Arr[0]);
Arr[0][3]의 자리를 비워두지 않고 값을 넣었더니 Arr[1]까지 읽고 0을 만나 출력이 끝난 모습이다.
Arr[0][3], Arr[1][3], Arr[2][3](각 행의 끝자리)도 채우면 메모리 속에서 0을 만날 때까지 출력되어 의도하지 않은 값들이 출력된다.
배열의 크기를 변수로 넣기
변수를 넣을 수 없다. 값이 변할 수 있기 때문이다.
exe파일에 적혀있다. (ex : main함수는 100바이트 사용한다.) 한 번 컴파일이 되고 나면 절대로 바뀔 수 없다.
const를 붙인 변수는 상수처럼 읽히기 때문에 가능하다.
char Arr[3][4]
배열의 주소를 보면 char형의 크기인 1바이트씩 연속으로 있는 것을 알 수 있다.
// ConsoleGame.cpp : 이 파일에는 'main' 함수가 포함됩니다. 거기서 프로그램 실행이 시작되고 종료됩니다.
//
#include <iostream>
#include <conio.h>
class int2
{
// 보통 이런 수학적 클래스는
// public으로 맴버변수를 두는 편입니다.
public:
int X = 0;
int Y = 0;
};
// 이런걸 정의하는것을 좋아하지는 않습니다.
// typedef int2 Pos;
// 전역변수는 영역과 관련없이
// 이름이 위에 있다면 그것을 사용할 수 있다.
const int ScreenX = 20;
const int ScreenY = 10;
const int ScreenXHalf = ScreenX / 2;
const int ScreenYHalf = ScreenY / 2;
class Bullet {
public:
void SetBullet(const int2& _Pos) {
Pos = _Pos;
}
int2 GetBulletPos() {
return Pos;
}
private:
int2 Pos = { 0,0 };
};
class ConsoleScreen
{
public:
// 생성자를 만든다는 것은
// 내가 만든 생성자 형식으로만 생성해라.
ConsoleScreen(char _BaseChar)
{
// [*][*][*][*][*][0]
// [*][*][*][*][*][0]
// [*][*][*][*][*][0]
// [*][*][*][*][*][0]
// [*][*][*][*][*][0]
BaseCh = _BaseChar;
for (int y = 0; y < ScreenY; y++)
{
for (int x = 0; x < ScreenX - 1; x++)
{
Arr[y][x] = BaseCh;
}
}
}
void PrintScreen()
{
for (int y = 0; y < ScreenY; y++)
{
char* Ptr = Arr[y];
printf_s(Ptr);
printf_s("\n");
}
}
void ClearScreen()
{
system("cls");
for (int y = 0; y < ScreenY; y++)
{
for (int x = 0; x < ScreenX - 1; x++)
{
if ((y == 0 || y == ScreenY - 1) || (x == 0 || x == ScreenX - 2)) {
Arr[y][x] = '#';
}
else {
Arr[y][x] = BaseCh;
}
}
}
}
void CreateBullet(const int2& _Bullet) {
if (_Bullet.X != 0 && _Bullet.Y != 0) {
Arr[_Bullet.Y - 1][_Bullet.X] = '|';
}
}
void SetPixel(const int2& _Position, char _Char)
{
SetPixel(_Position.X, _Position.Y, _Char);
}
void SetPixel(int _X, int _Y, char _Char)
{
Arr[_Y][_X] = _Char;
}
protected:
private:
char Arr[ScreenY][ScreenX] = { 0, };
char BaseCh = ' ';
//int2 Bullet = { 0, 0 };
//ScreenY가 5일 때
//0 [0][0][0][0][0][0]
//1 [0][0][0][0][0][0]
//2 [0][0][0][0][0][0]
//3 [0][0][0][0][0][0]
//4 [0][0][0][0][0][0]
};
class Player
{
public:
Player()
{
}
Player(const int2& _StartPos, char _RenderChar)
: Pos(_StartPos), RenderChar(_RenderChar)
{
}
// inline은 컴파일러가 함수를 삭제하고
// 그 위치에 치환시켜 버린다.
inline int2 GetPos()
{
return Pos;
}
inline char GetRenderChar()
{
return RenderChar;
}
void ClearScreen()
{
system("cls");
}
void Update(char ch)
{
// getch의 리턴값을 확인해서
// 상하좌우로 움직이게 하세요.
//char ch = _getch();
//ClearScreen();
switch (ch) {
case 'w':
case 'W':
if (Pos.Y - 1 > 0) {
Pos.Y -= 1;
}
break;
case 's':
case 'S':
if (Pos.Y + 1 < ScreenY - 1) {
Pos.Y += 1;
}
break;
case 'a':
case 'A':
if (Pos.X - 1 > 0) {
Pos.X -= 1;
}
break;
case 'd':
case 'D':
if (Pos.X + 1 < ScreenX - 2) { // X는 문자열의 끝에 0이 둘 자리가 있어야해서 하나 더 작음
Pos.X += 1;
}
break;
default:
break;
}
// 입력값이 w면 위로 y - 1
// 입력값이 s면 아래로 y + 1
// a면 왼쪽으로 x - 1
// d면 오른쪽으로 x + 1
}
private:
int2 Pos = { 0, 0 };
char RenderChar = '@';
};
int main()
{
ConsoleScreen NewScreen = ConsoleScreen('*');
Player NewPlayer = Player({ ScreenXHalf, ScreenYHalf }, '@');
Bullet NewBullet = Bullet();
while (true)
{
NewScreen.ClearScreen();
NewScreen.SetPixel(NewPlayer.GetPos(), NewPlayer.GetRenderChar());
NewScreen.CreateBullet(NewBullet.GetBulletPos());
NewScreen.PrintScreen();
; char ch = _getch();
if (ch == ';') {
NewBullet.SetBullet(NewPlayer.GetPos());
}
else {
NewPlayer.Update(ch);
}
}
}
// ConsoleGame.cpp : 이 파일에는 'main' 함수가 포함됩니다. 거기서 프로그램 실행이 시작되고 종료됩니다.
//
#include <iostream>
#include <conio.h>
class int2
{
// 보통 이런 수학적 클래스는
// public으로 맴버변수를 두는 편입니다.
public:
int X = 0;
int Y = 0;
// 디폴트 대입연산자.
void operator=(const int2& _Other)
{
X = _Other.X;
Y = _Other.Y;
}
int2 operator+(const int2& _Other)
{
return { X + _Other.X, Y + _Other.Y };
}
void operator+=(const int2& _Other)
{
X += _Other.X;
Y += _Other.Y;
}
};
const int2 Left = {-1, 0};
const int2 Right = { 1, 0 };
const int2 Up = { 0, -1 };
const int2 Down = { 0, 1 };
// 전역변수는 영역과 관련없이
// 이름이 위에 있다면 그것을 사용할 수 있다.
const int ScreenX = 20;
const int ScreenY = 12;
const int ScreenXHalf = ScreenX / 2;
const int ScreenYHalf = ScreenY / 2;
class ConsoleScreen
{
public:
// 생성자를 만든다는것은
// 내가 만든 생성자 형식으로만 생성해라.
ConsoleScreen(char _BaseChar)
{
// [*][*][*][*][*][0]
// [*][*][*][*][*][0]
// [*][*][*][*][*][0]
// [*][*][*][*][*][0]
// [*][*][*][*][*][0]
BaseCh = _BaseChar;
}
void PrintScreen()
{
for (int y = 0; y < ScreenY; y++)
{
char* Ptr = Arr[y];
printf_s(Ptr);
printf_s("\n");
}
}
void ClearScreen()
{
system("cls");
for (int y = 0; y < ScreenY; y++)
{
for (int x = 0; x < ScreenX - 1; x++)
{
Arr[y][x] = BaseCh;
}
}
}
void SetPixel(const int2& _Position, char _Char)
{
SetPixel(_Position.X, _Position.Y, _Char);
}
void SetPixel(int _X, int _Y, char _Char)
{
Arr[_Y][_X] = _Char;
}
protected:
private:
char Arr[ScreenY][ScreenX] = { 0, };
char BaseCh = ' ';
// [0][0][0][0][0][0]
// [0][0][0][0][0][0]
// [0][0][0][0][0][0]
// [0][0][0][0][0][0]
// [0][0][0][0][0][0]
};
class Galaga
{
public:
void GalagaWallDraw(ConsoleScreen& _Screen)
{
// [#][#][#][#][#][#]
// [0][0][0][0][0][0]
// [0][0][0][0][0][0]
// [0][0][0][0][0][0]
// [0][0][0][0][0][0]
{
int2 Start0 = { 0, 0 };
int2 Start1 = { 0, ScreenY -1 };
for (int i = 0; i < ScreenX - 1; i++)
{
_Screen.SetPixel(Start0, '#');
_Screen.SetPixel(Start1, '#');
Start0 += Right;
Start1 += Right;
}
}
{
int2 Start0 = { 0, 0 };
int2 Start1 = { ScreenX - 2, 0 };
for (int i = 0; i < ScreenY; i++)
{
_Screen.SetPixel(Start0, '#');
_Screen.SetPixel(Start1, '#');
Start0 += Down;
Start1 += Down;
}
}
}
};
class Player
{
public:
Player()
{
}
Player(const int2& _StartPos, char _RenderChar)
: Pos(_StartPos), RenderChar(_RenderChar)
{
}
// inline은 컴파일러가 함수를 삭제하고
// 그 위치에 치환시켜 버린다.
inline int2 GetPos()
{
return Pos;
}
inline char GetRenderChar()
{
return RenderChar;
}
void Update()
{
// Pos.X += 1;
// getch의 리턴값을 확인해서
int Value = _getch();
switch (Value)
{
case 'a':
case 'A':
{
if ((Pos + Left).X != 0)
{
Pos += Left;
}
break;
}
case 'd':
case 'D':
{
if ((Pos + Right).X != (ScreenX - 2))
{
Pos += Right;
}
break;
}
case 'w':
case 'W':
{
if ((Pos + Up).Y != 0)
{
Pos += Up;
}
break;
}
case 's':
case 'S':
{
if ((Pos + Down).Y != (ScreenY - 1))
{
Pos += Down;
}
break;
}
case 'q':
case 'Q':
{
if (nullptr != IsFire)
{
*IsFire = true;
}
// IsFire = true;
}
default:
break;
}
int a = 0;
}
void SetBulletFire(bool* _IsFire)
{
if (nullptr == _IsFire)
{
int a = 0;
return;
}
IsFire = _IsFire;
}
private:
int2 Pos = {0, 0};
char RenderChar = '@';
bool* IsFire = nullptr;
};
class Bullet
{
public:
Bullet(const int2& _StartPos, char _RenderChar)
: Pos(_StartPos), RenderChar(_RenderChar)
{
}
bool& GetIsFireRef()
{
return IsFire;
}
inline int2 GetPos()
{
return Pos;
}
inline char GetRenderChar()
{
return RenderChar;
}
private:
bool IsFire = false;
int2 Pos = { 0, 0 };
char RenderChar = '@';
};
// 함수의 실행 메모리는 고정되어 있어야 한다.
// => exe파일에 적혀있다. main함수는 100바이트 사용한다.
// 한번 컴파일이 되고나면 절대로 바뀔수 없다
int main()
{
// 과제 1
// 화면 외곽을 벽으로 채워라
// 플레이어가 벽 바깥으로 못나가게 만들어라.
// [#][#][#][#][#][0]
// [#][*][*][*][#][0]
// [#][*][@][*][#][0]
// [#][*][*][*][#][0]
// [#][#][#][#][#][0]
// 과제 2
// 플레이어가 키를 누르면
// [#][#][#][#][#][0]
// [#][I][*][*][#][0]
// [#][*][@][*][#][0]
// [#][*][*][*][#][0]
// [#][#][#][#][#][0]
// 변수가 들어갈수 없어요.
ConsoleScreen NewScreen = ConsoleScreen('*');
Galaga NewGalaga = Galaga();
Player NewPlayer = Player({ ScreenXHalf, ScreenYHalf }, '@');
Bullet NewBullet = Bullet({0,0}, '^');
bool& Ref = NewBullet.GetIsFireRef();
NewPlayer.SetBulletFire(&Ref);
while (true)
{
NewScreen.ClearScreen();
NewGalaga.GalagaWallDraw(NewScreen);
int2 Index = NewPlayer.GetPos();
char Ch = NewPlayer.GetRenderChar();
NewScreen.SetPixel(Index, Ch);
if (true == NewBullet.GetIsFireRef())
{
NewScreen.SetPixel(NewBullet.GetPos(), NewBullet.GetRenderChar());
}
NewScreen.PrintScreen();
NewPlayer.Update();
}
}
wsad로 이동
;로 총알 생성
플레이어@
모습
플레이어 이동 후 총알|
이 생긴 모습