군대를 다녀오고 c언어를 가물가물해서
c언어를 복습할 겸 테트리스 게임을 만들고, 최적화 시켜보려고 프로젝트를 진행한다.
main.c: 프로그램의 진입점이 되는 메인 함수가 있는 파일.
tetris.c: 게임의 핵심 로직을 구현하는 파일.
tetris.h: 필요한 함수와 변수들을 선언하는 헤더 파일.
(추가 사항) graphics.h 및 graphics.c : 그래픽 관련 기능이 필요한 경우 사용
1. 테트리스 GUI


2. 블록 정의 (회전축을 어디로 잡아야 할까..?)

2-1. L
{{0, 0, 0, 0}, {1, 0, 0, 0}, {1, 1, 1, 0}, {0, 0, 0, 0}}
| 1 | |||
| 1 | 1 | 1 | |
| 1 | |||
| 1 | |||
| 1 | 1 |
| 1 | 1 | 1 | |
| 1 | |||
| 1 | 1 | ||
| 1 | |||
| 1 | |||
2-2. J
| 1 | |||
| 1 | 1 | 1 | |
| 1 | 1 | ||
| 1 | |||
| 1 | |||
| 1 | 1 | 1 | |
| 1 | |||
| 1 | |||
| 1 | |||
| 1 | 1 |
2-3 T
| 1 | |||
| 1 | 1● | 1 | |
| 1 | |||
| 1 | 1● | ||
| 1 |
| 1 | 1● | 1 | |
| 1 |
| 1 | |||
| 1● | 1 | ||
| 1 |
2-4 I
| 1 | |||
| 1 | |||
| 1 | |||
| 1 |
| 1 | 1 | 1 | 1 |
2-5 O
| 1 | 1 | ||
| 1 | 1 | ||
2-6 Z
| 1 | 1● | ||
| 1 | 1 | ||
| 1 | |||
| 1 ● | 1 | ||
| 1 | |||
2-7 S
| 1● | 1 | ||
| 1 | 1 | ||
| 1 | |||
| 1● | 1 | ||
| 1 | |||
3. 블록 생성 + GUI
issue 1
블록 생성 후 맵과 grid 혼합
=> 한 칸 씩 내려가지를 않음
block이 쌓인다..

int moveBlockDown(Block *block) {
block->y++;
// 블록이 보드의 경계를 넘거나 다른 블록과 충돌하는지 확인
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (blockModel[block->type * 4 + block->rotation][i][j] && (block->y + i >= HEIGHT || grid[block->y + i][block->x + j] != ' ')) {
block->y--; // 이전 위치로 복구
placeBlock(block); // 복구된 위치에 블록 배치
return 0; // 이동 실패 (블록이 바닥에 닿음)
}
}
}
placeBlock(block);
displayMap();
return 1; // 이동 성공
}
이전 위치에 있는 블럭을 삭제하고 다음 위치로 이동한 후 그 다음 grid를 업데이트해야지 아니면 잔상이 계속 남게 된다.
issue 2
블럭을 그냥 뭉개버린다.
=> 충돌 시 처리하는 코드가 필요하다.

issue 3
블럭이 충돌하면 해당 모양도 아닌데 grid에 생성된다.
- 자세히 보면 블럭이 한칸씩 밀려서 grid와 합성되고 있다.
즉, 한 칸 밀려서 합성되고 있던 것이였다.


--> 디버깅할 파일을 하나 만들어야 겠다.
#include <stdio.h>
#include <windows.h>
FILE* debugFile;
void openDebugFile() {
debugFile = fopen("debug_log.txt", "w"); // 디버그 파일 열기
if (!debugFile) {
printf("Failed to open debug file.\n");
exit(1);
}
}
void closeDebugFile() {
if (debugFile) {
fclose(debugFile); // 디버그 파일 닫기
}
}
int main() {
Block currentBlock;
openDebugFile(); // 디버그 파일 열기
initializeGame();
generateNewBlock(¤tBlock);
while (!isGameOver()) {
clearScreen();
displayMap();
if (_kbhit()) {
handleInput(¤tBlock);
}
if (!moveBlockDown(¤tBlock)) {
generateNewBlock(¤tBlock);
}
printBlockShape(¤tBlock);
// 디버그 파일에 출력
fprintf(debugFile, "Block position: (%d, %d)\n", currentBlock.x, currentBlock.y, currentBlock.shape);
fflush(debugFile); // 출력 내용을 파일에 즉시 기록
Sleep(200);
}
}


.으로 표시되어있는 곳이 20*40의 좌표다.
현재 문제는 블록(8,37)의 위치를 인지함에도
블록(8,37) 블록(8,38)을 or연산되어 같이 grid에 표시된다는 점이다.
// 충돌 체크
int checkCollision(Block *block) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (block->shape[i][j]) {
int y = block->y + i;
int x = block->x + j;
if (x < 0 || x >= WIDTH || y >= HEIGHT || (y >= 0 && grid[y][x])) {
// fixBlock(block);
return 1; // 충돌 발생
}
}
}
}
return 0; // 충돌 없음
}
원인은,, fixBlock 함수에서 블럭을 하나 더 생성해서 그렇게 되었다..
fixBlock은 기존 설계할 떄 합성 후 grid 생성하는 함수 였었는데 이중 선언이 되버린 꼴이였다.
블록 회전
issue 1
블록 회전 시 L자블럭이 Z로 변경된다.
처음에는 메모리 관리가 안되서 이상한 값이 들어갔나 싶었는데
그저 코드 실수,, 머쓱..
BEFORE
// 블록 생성
void generateNewBlock(Block *block) {
block->x = WIDTH / 2 - 2; // 중간 위치에서 블록 생성
block->y = 1; // 최상단에서 블록 생성
block->type = rand() % 7; // 블록 종류를 랜덤으로 선택
block->rotation = 0; // 기본 회전 상태
memcpy(block->shape, blockModel[block->type*4*block->rotation], sizeof(block->shape));
placeBlock(block); // 블록을 보드에 배치
}AFTER
// 블록 생성
void generateNewBlock(Block *block) {
block->x = WIDTH / 2 - 2; // 중간 위치에서 블록 생성
block->y = 1; // 최상단에서 블록 생성
block->type = rand() % 7; // 블록 종류를 랜덤으로 선택
block->rotation = 0; // 기본 회전 상태
memcpy(block->shape, blockModel[block->type*4+block->rotation], sizeof(block->shape));
placeBlock(block); // 블록을 보드에 배치
}
중간 기능 영상
https://youtu.be/UIBjQURfSMY
앞으로 해야 할 일
1. 기능리스트 작성
- 다음 블럭 표시
- 점수 표시
- 게임시작 창 추가
- push 버튼 같은 요소들을 추가하여 1인, 2인용 선택
2. 디자인적인 요소 개선
3. 네트워크 관리
'ProgramingLagnuage > C' 카테고리의 다른 글
| [C언어] 포인터, 메모리 관리, 구조체 완벽 복습 (2) | 2024.11.01 |
|---|---|
| memcpy or 대입을 통한 데이터 복사 (0) | 2024.08.27 |