티스토리 뷰

일단 멀티플레이는 나중에 생각하고 기본적인 게임을 코드로 구현해보자.

배포 : https://puyo.cspc.me

게임 방식 설명


  • 블럭의 색깔이 4개이고 한번에 2 X 1 블럭에 한칸마다 색깔이 랜덤하게 나온다.
  • 블럭은 회전이 가능하며 위에서 아래로 떨어지게 되고 블럭은 밑에서부터 채우게 된다.
  • 같은 색깔의 블럭이 4개가 이상 뭉치면 같이 지워진다.
  • 블럭이 지워지고 위에 있던 블럭이 아래로 내려와 채우게 된다. 이 때 만약 4개의 블럭이 모여있다면 블럭이 다시 지워지며 추가점수를 얻는다. (연쇄)

 

설계


구현해야할 기능

  1. 블럭이 주기적으로 아래로 내려 쌓기 + 블럭이 아래부터 쌓이게 만들기
  2. 랜덤으로 새로운 블럭 생성하기
  3. 블럭 4개가 뭉쳐있나 확인후 터트리기 + 블럭을 아래로 내려 해당 내용 반복

 

 

우린 1초마다 블럭을 아래로 내려야 한다. 이를 구현하기 위해서 signal을 사용해보자.

 

SIGNAL

signal은 process가 받는 interrupt로 우리가 구현한 게임은 single process 환경이므로 main process에서 1초마다 interrupt되어 블럭을 한칸 아래로 내리는 과정을 반복한다. 아래는 리눅스 환경에서 사용되는 signal list이다.

ex) ctrl + c : 프로그램 종료

process signal list

 

alarm() 함수를 사용하여 SIGALRM을 발생시켜 1초마다 블럭이 내려오게 만들자.

 

시그널을 활용하여 1초마다 "HI"를  출력하는 예제

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

static struct sigaction act, oact;
void print(int);
int timed_out;

int main(){
   act.sa_handler = print;
   timed_out = 1;
   sigaction(SIGALRM,&act,&oact);
   alarm(1);
   while(1){
       if(timed_out == 0){
           alarm(1);
           timed_out= 1;
       }
   }
   return 0;
}

void print(int sig){
   printf("HI\n");
   timed_out =0;
}

act는 시그널을 받았을 때 실행하는 함수, 이외 각종 플래그들을 저장하는  sigaction 구조체이다. 구조체 안에 sa_handler에 실행할 함수를 저장한다. 알람이 울리고 다시 알람을 설정하기 위해 시그널이 보내질 때마다 timed_out에 알람의 세팅 여부를 저장한다. sigaction()함수를 호출하여 alarm 시그널에 act를 실행하도록 하고 이전 액션을 oact에 저장한다. 이후 알람을 계속 세팅하며 1초마다 print가 호출되도록 한다.

 

 

코드


세세한 코드보다 바탕이 되는 함수만 설명

 

 

 

게임 진행중에 main이 될 play 함수 작성

 

- 시작 시

  • 시그널 발생 시 실행 함수 세팅
  • 그래픽 그리기

- 게임 진행 중

  • command를 수시로 받아 블럭의 위치 조정
  • alarm 함수를 1초마다 반복 call

- 게임 종료 시

  • alarm을 멈추고 menu로 돌아감
void play(){
	int command;
	clear(); // ncurses 그래픽을 표현하기 전 화면 초기화
	act.sa_handler = BlockDown; // signal 받을 때 실행할 함수 설정
	sigaction(SIGALRM,&act,&oact);
	InitTetris();



	do{
		if(timed_out==0 && !process_flag){
        	//signal 발생한지, 현재 blockdown 함수 실행 중인지 확인
			alarm(1);
			timed_out=1;
		}

		command = GetCommand();

		if(ProcessCommand(command)==QUIT){ // 커맨드 입력으로 인한 종료
			alarm(0);
			DrawBox(HEIGHT/2-1,WIDTH/2,1,10);
			move(HEIGHT/2,WIDTH/2 +2);
			printw("Good-bye!!");
			refresh();
			getch();

            system("clear");
			return;

		}

	}while(!gameOver);
    // 게임오버시 종료

	alarm(0);
	DrawBox(HEIGHT/2-1,WIDTH/2-5,1,10);

	refresh();
	getch();

}

 

 

1초마다 실행되는 BlockDown 함수

 

- 블럭이 떨어질 때

  • 현재 낙하중인 블럭을 1칸씩 내림

- 블럭이 바닥에 닿았을 때

  • 블럭이 바닥에 닿으면 Field에 블럭 추가
  • Field에 공중에 떠 있는 블럭을 내림
  • Field에 뭉쳐있는 블럭 터트리기
  • 다음 블럭 준비
void BlockDown(int sig){

	if(process_flag) //현재 BlockDown 함수를 실행중인지 확인
		return; 

	if(CheckToMove(field,nextBlock[0],blockRotate, blockY+1, blockX)){
    	//낙하 중인 블럭이 아직 떨어질 자리가 있다면 block의 위치를 내림
		process_flag=0;
		blockY++;
		DrawField(field);
		DrawBlockWithFeatures(blockY,blockX,nextBlock[0],blockRotate);

	}
	else{
    	//블럭이 이동하지 않을 때
		alarm(10);
		num_of_chains = 0;
		process_flag = 1;

		if(blockY == -1)
			gameOver = 1;
		AddBlockToField(field,nextBlock[0],blockRotate,blockY,blockX);

		CheckFall(field); //블럭이 공중에 떠 있는지 확인 후 내림

		PuyoBomb(field); //지워질 블럭을 지움

		nextBlock[0] = nextBlock[1]; // 다음 블럭을 현재 블럭으로 준비
		nextBlock[1] = rand() % 10; // 새로운 랜덤 블럭을 다음 블럭으로 세팅

		//블럭 위치 초기화
		blockRotate = 0;
		blockY = -1;
		blockX = WIDTH/2 -2;


		CheckFall(field);
		DrawNextBlock(nextBlock);
		DrawField(field);
		PrintScore(score);




	}
	process_flag = 0;
	timed_out = 0;

}

 

 

코드 :  https://github.com/ljy2855/puyo_tetris

 

GitHub - ljy2855/puyo_tetris

Contribute to ljy2855/puyo_tetris development by creating an account on GitHub.

github.com

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/02   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
글 보관함