스네이크에 이어서 테트리스를 천천히 진행해보고자 하여 진행하게 되었습니다.




일단 다른 사람들이 만들어 놓은 예제에 대해서 참고하지 않고 제가 생각하는대로 만들어 보기로 하였습니다.


도스창에 좌표를 통해서 참조하고 값을 바꾸는 것이 윈도우api내에 있긴하지만 이에 의존하지 않고 Window.h 에서는 그냥 지연시간을 넣기 위한 Sleep() 함수 하나를 사용하기 위해서 소스코드내에 포함하기로 하였습니다.



1. 멀티 플랫폼

다른 운영체제에서도 실행한 모습을 보고 싶기 때문에 다른 운영체제에 이식하기 편하도록 일부 간을 보아놨습니다.

스네이크에서도 그렇고 테트리스에서도 자주 쓰이는 _getch()나 _kbhit() 함수의 경우에는 conio.h 에 포함되어 있는데.

이는 표준도 아니며, 윈도우에 종속적 입니다. 그렇기때문에 리눅스에서 사용하려면 이 함수를 제가 만들어야 합니다.



반면, 안드로이드의 C4Droid 어플리케이션의 경우 conio.h 파일을 제공해주고 있기 때문에 _getch()라는 최신 C언어 네이밍이 아닌 getch()로 변경해주기만 하면 되는 간편함 때문에 C4Droid는 지원해보기로 하였습니다.




그렇기에 이번 테트리스의 경우에도 일부분의 소스를 전처리기로 쪼개놨습니다.



2. #define 상수의 사용 자제

define 전처리기를 상수말고 헤더파일 중복 방지같은 용도로만 최대한 사용하기로 하였습니다. 그러한 목적 하에 enum을 최대한 활용하였습니다.


3. 헤더 파일 분할

테트리스의 경우에는 저작권이 걸려있기 때문에 소스 전문을 게시할 수 없는 관계로 저 혼자 잘 보관하고 이쁘게 보기 위해서 소스코드를 헤더파일에 일부 분할하였습니다.


4. 전각 문자 사용

스네이크에서는 전각문자를 사용하지 않았지만 테트리스는 아무래도 네모난 블럭이 깔끔하기에 전각 문자를 그냥 사용했습니다.

(어려울게 하나도 없지만 보이는건 큰 차이가...)







소스 파일의 일부


다음은 소스파일의 함수의 선언 부분들 입니다.


const int BLOCK_LENGTH = 4;

/*시작 후 메뉴*/

void PrintMainMenu(void); //메뉴 출력

void GameStart(void); //게임 시작

void Setting(void); //게임 설정

void GameExit(void); //게임 종료


/*출력*/

inline void ClearScreen(void); //화면의 텍스트를 비움

inline char* GetObjectChar(Object code); //오브젝트 코드에 대응되는 문자를 반환


/*맵*/

Map* main_map; //메인이 될 맵

void InitMap(Map *map, int width, int height); //맵의 초기화(메모리 할당)

void MainMapMemoryReturn(void); //메인 맵의 메모리반환

void PrintMap(const Map *map); //맵을 출력함

void FillMap(Map *map, Object code); //맵 전체를 빈 공간으로 채움

void SetWall(Map *map); //맵에 벽을 두름

void PlaceBlock(Map *map, const Block* block); //블럭을 비활성화 시켜 맵에 등록함.

void RefleshMap(Map *map); //맵 새로고침

void DeleteLine(Map *map, int line_number);


/*블럭*/

Block* InitBlock(Block* block); //블럭 메모리 할당

Block* SetBlockType(Block* block, BlockType type, unsigned int rotate_count); //블럭을 생성하는 함수

BlockType GetRandomBlockCode(); //랜덤 블럭을 생성하는 함수

int GetRandomRotateCode();

int MoveBlock(Map* map, Way dir); //블럭 이동 함수

Pos GetTilePos(const Block* block, int tile_num); //타일이 맵에 적용된 좌표를 얻는다.


/*Pos*/

Pos GetPos(int x, int y);


/*기타*/

inline void KeyEvent(void);

void Swap(int* a, int* b);



이건 구조체들

#ifndef __STRUCTS_H_

#define __STRUCTS_H_


#include "Enum.h"


typedef struct MenuItem

{

void(*menu_func)(void); //메뉴 선택시 실행할 함수

char* text; //메뉴 아이템의 이름

} MenuItem;


typedef struct Pos

{

int x;

int y;

} Pos;


typedef struct Block

{

Pos* tiles;

int top;

int left;

BlockType type;

unsigned int rotate_count;

} Block;


typedef struct Map

{

Block active_block;

int** map;

int max_height;

int max_width;

} Map;

#endif





앞으로 필요한 사항

1. 블럭을 회전할 때 있어서 블럭이 이미 배치된 블럭들이나 맵밖으로 튀어나가지 않도록 방지

2. 다음에 나올 블럭 예약하기

3. 점수

4. 게임 오버를 화려하게(?)