# **俄羅斯方塊-改造計畫**
###### tags: `小專題` `C` `大一`

# 新增部分 :
1.開始畫面
2.分數計算
3.等級分布
4.加速
5.圖案 & 顏色不同
6.瞬降 --> space鍵
7.刪除 --> Enter鍵
8.音樂
9.結束畫面
10.分成.c跟.h檔
# 改過的地方 :
**1.開始畫面**

   
```c=
int main(){
setColor(6); //顏色為黃色
printf("\n\n\t\t遊戲說明");
printf("\n\t tips : \n");
printf("\t 1.等級6為MAX\n");
printf("\t 2.每消一行會加速一點\n");
printf("\t 3.↑為改變方向\n");
printf("\t 4.↓為加速向下\n");
printf("\t 5.← →為橫向移動\n");
printf("\t 6.space鍵為瞬間降落\n");
printf("\t 7.enter鍵為刪除方塊\n");
Sleep(8000); //1000==1秒,類似delay -->停8秒
PlaySound(TEXT("count.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
system("cls"); //清空頁面
printf("\n\n\n\t\t3");
Sleep(1000); //停1秒
system("cls"); //清空頁面
printf("\n\n\n\t\t2");
Sleep(1000); //停1秒
system("cls"); //清空頁面
printf("\n\n\n\t\t1");
Sleep(1000); //停1秒
system("cls"); //清空頁面
printf("\n\n\n\t\tGO!");
Sleep(1000); //停1秒
system("cls"); //清空頁面
PlaySound(TEXT("music_tetris.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
//...
}
```
**2.分數計算**
>分數為消的行數的150倍
```c=
//程式碼
if(is_line_fill(h)==1){
clear_one_line(h);
total_line++; //消掉的行數增加
score+=total_line*150; //分數為行數的150倍
print_surface();
tm-=30;
set_timer(tm);
}
```
**3.等級分布**

>等級分布由分數決定(1~6等)
>如果有消掉,分數跟等級都會增加
```c=
//程式碼
if(score<310){ // level 1
level=1;
}
else if(score>400 && score<3100){ // level 2
level=2;
}
else if(score>3100 && score<=6000){ // level 3
level=3;
}
else if(score>6000 && score<=10000){ // level 4
level=4;
}
else if(score>10000 && score<=20000){ // level 5
level=5;
}
else if(score>20000){ // level6
level=6;
}
```
**4.加速**
>每消掉一行會使速度加快30
```c=
//程式碼
void check_line(){
int total_line = 0; //把消的行數清0
int h;
for(h=cur_y;h<HEIGHT;h++){
if(is_line_fill(h)==1){ //如果一行滿了就清掉
clear_one_line(h); //把一行清掉
total_line++;
score+=total_line*150;
print_surface(); //印表面
tm-=30; //時間每次-30
set_timer(tm); //重新設定時間
}
}
}
```
**5.圖案 & 顏色不同**

>圖形會依照顏色不同而改變
```c=
void setColor(int color){ //換顏色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),color);
}
```
```c=
void make_new_block(){
enum block_type type = (int)(rand()%block_type_num);
switch(type){
case O:
setColor(2); //設定顏色=2,綠
color_to_change_pattern=2; //記住顏色
copy_block(Block0,current_block);
break;
case J:
setColor(14); //設定顏色=14,淡黃
color_to_change_pattern=14;
copy_block(BlockJ,current_block);
break;
case L:
setColor(8); //設定顏色=8
color_to_change_pattern=8;
copy_block(BlockL,current_block);
break;
case I:
setColor(12); //設定顏色=12
color_to_change_pattern=12;
copy_block(BlockI,current_block);
break;
case Z:
setColor(6); //設定顏色=6
color_to_change_pattern=6;
copy_block(BlockZ,current_block);
break;
case S:
setColor(9); //設定顏色=9
color_to_change_pattern=9;
copy_block(BlockS,current_block);
break;
case T:
setColor(11); //設定顏色=11
color_to_change_pattern=11;
copy_block(BlockT,current_block);
break;
default:
break;
}
cur_x = (WIDTH-block_w)/2;
cur_y = 0;
}
```
```c=
void print_block(int block[][block_w],int x,int y){
int w,h;
for(w=0;w<block_w;w++){
for(h=0;h<block_h;h++){
if(block[h][w]==1 && over==0){
if(color_to_change_pattern==2){ //如果顏色是綠色
printxy("+",x+w,y+h); //印出'+'
}
else if(color_to_change_pattern==14){ //如果顏色是淡黃色
printxy("X",x+w,y+h); //印出'X'
}
else if(color_to_change_pattern==8){ //如果顏色是灰色
printxy("#",x+w,y+h); //印出'#'
}
else if(color_to_change_pattern==12){ //如果顏色是桃紅色
printxy("$",x+w,y+h); //印出'$'
}
else if(color_to_change_pattern==6){ //如果顏色是黃色
printxy("&",x+w,y+h); //印出'&'
}
else if(color_to_change_pattern==9){ //如果顏色是藍色
printxy("~",x+w,y+h); //印出'~'
}
else if(color_to_change_pattern==11){ //如果顏色是藍綠色
printxy("@",x+w,y+h); //印出'@'
}
}
}
}
}
```
**6.瞬降 --> space鍵**


>按space的前後圖
>方塊會瞬間掉到最底下
```c=
//程式碼:
case 32: //space
rem_ch=32; //記住按鍵的號碼
if(isCollision(cur_x,cur_y+1)==0){
erase_block(current_block,cur_x,cur_y);
while(isCollision(cur_x,cur_y+1)==0){ //跑到最底下再印出
cur_y++;
}
}
print_block(current_block,cur_x,cur_y);
break;
```
**7.刪除 --> Enter鍵**


>以上為刪除前後圖
>按下enter鍵會直接換另一個方塊
```c=
//程式碼:
case 13: //enter --> 刪除鍵
if(isCollision(cur_x-1,cur_y)==0){
if(rem_ch!=13){
erase_block(current_block,cur_x,cur_y); //擦掉原本的方塊
rem_ch=13; //判斷是不是有一直換方塊
print_surface();
make_new_block(); //再印新的方塊
print_block(current_block,cur_x,cur_y);
}
}
break;
```
**8.音樂**
```c=
//程式碼
PlaySound(TEXT("count.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_LOOP); //放倒數3 2 1的音樂
system("cls");
printf("\n\n\n\t\t3");
Sleep(1000);
system("cls");
printf("\n\n\n\t\t2");
Sleep(1000);
system("cls");
printf("\n\n\n\t\t1");
Sleep(1000);
system("cls");
printf("\n\n\n\t\tGO!");
Sleep(1000);
system("cls");
PlaySound(TEXT("music_tetris.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_LOOP); //放tetris的音樂
```
**9.結束畫面**

>結束畫面會先把原本的方塊清空
>印出得分與等級
```c=
//程式碼
if(isCollision(cur_x,cur_y)==1){
erase_block(current_block,cur_x,cur_y); //擦掉原本的方塊
close_timer(); //暫停時間
system("cls"); //清空頁面
setColor(4); //顏色換紅色
erase_block(current_block,cur_x,cur_y); //擦掉原本的方塊
printf("\n\n\n\t遊戲結束!!!");
over=1; //遊戲結束-->不要再印出方塊了
printf("\n\n\t您的得分是 : %d",score); //印出分數
printf("\n\n\t您的等級是 : %d",level); //印出等級
Sleep(4000); //暫停4秒
}
```
**10.分割檔案**
>.h檔
```c=
// 標頭檔
#include<stdio.h>
#include<stdlib.h>
#include <conio.h>
#include<time.h>
#include <windows.h>
#define HEIGHT 14
#define WIDTH 18
#define block_h 4
#define block_w 4
enum block_type{ //總共有這7種方塊
O,J,L,I,Z,S,T
};
int block_type_num = 7; //要跑亂數的總數
int cur_x=0,cur_y=0;
int color_to_change_pattern; //記住顏色 --> 改變形狀
int over=0; //判斷遊戲是否結束
int Block0[block_h][block_w] = { //正方形
{0,0,0,0},
{0,1,1,0},
{0,1,1,0},
{0,0,0,0}
};
int BlockJ[block_h][block_w] = { //J形
{0,0,1,0},
{0,0,1,0},
{0,1,1,0},
{0,0,0,0}
};
int BlockL[block_h][block_w] = { //L形
{0,1,0,0},
{0,1,0,0},
{0,1,1,0},
{0,0,0,0}
};
int BlockI[block_h][block_w] = { //I形
{0,1,0,0},
{0,1,0,0},
{0,1,0,0},
{0,1,0,0}
};
int BlockZ[block_h][block_w] = { //Z形
{0,0,0,0},
{1,1,0,0},
{0,1,1,0},
{0,0,0,0}
};
int BlockS[block_h][block_w] = { //S形
{0,0,0,0},
{0,1,1,0},
{1,1,0,0},
{0,0,0,0}
};
int BlockT[block_h][block_w] = { //T型
{0,0,0,0},
{1,1,1,0},
{0,1,0,0},
{0,0,0,0}
};
int current_block[block_h][block_w];
int surface[HEIGHT][WIDTH] = {0} ;
void print_block(int block[][block_w],int x,int y);
void copy_block(int block_s[][block_w],int block_d[][block_w]);
void make_new_block();
void rotate_block();
void land_block();
int get_block_x_fill(int col);
int get_block_y_fill(int row);
void get_block_top_bottom_margin(int *top_margin, int *bottom_margin);
void get_block_left_right_margin(int *left_margin, int *right_margin);
int isCollision(int x,int y);
void print_surface();
void setCursorVisable(int v);
void gotoxy(int x,int y);
void printxy(char*str , int x, int y );
void erase_block(int block[][block_w],int x,int y);
void setColor(int color);
void clear_one_line(int h);
int is_line_fill(int h);
void check_line();
static void set_timer(int t);
static void close_timer();
void move_block_down();
void key_control();
int tm = 800;
UINT_PTR timerId;
MSG msg;
int score=0;
int level=0;
void print_block(int block[][block_w],int x,int y){ //印出方塊形狀
int w,h;
for(w=0;w<block_w;w++){
for(h=0;h<block_h;h++){
if(block[h][w]==1 && over==0){ //如果沒結束 && =1
if(color_to_change_pattern==2){ //如果顏色是綠色
printxy("+",x+w,y+h); //印出'+'
}
else if(color_to_change_pattern==14){ //如果顏色是淡黃色
printxy("X",x+w,y+h); //印出'X'
}
else if(color_to_change_pattern==8){ //如果顏色是灰色
printxy("#",x+w,y+h); //印出'#'
}
else if(color_to_change_pattern==12){ //如果顏色是桃紅色
printxy("$",x+w,y+h); //印出'$'
}
else if(color_to_change_pattern==6){ //如果顏色是黃色
printxy("&",x+w,y+h); //印出'&'
}
else if(color_to_change_pattern==9){ //如果顏色是藍色
printxy("~",x+w,y+h); //印出'~'
}
else if(color_to_change_pattern==11){ //如果顏色是藍綠色
printxy("@",x+w,y+h); //印出'@'
}
}
}
}
}
void copy_block(int block_s[][block_w],int block_d[][block_w]){ //複製方塊
int w,h;
for(w=0;w<block_w;w++){
for(h=0;h<block_h;h++){
block_d[h][w] = block_s[h][w];
}
}
}
void make_new_block(){
enum block_type type = (int)(rand()%block_type_num); //隨機選擇一種方塊
switch(type){ //將current_block變成隨機產生的方塊(產生方塊)
case O:
setColor(2); //設定顏色=2
color_to_change_pattern=2; //記住顏色
copy_block(Block0,current_block);
break;
case J:
setColor(14); //設定顏色=14
color_to_change_pattern=14;
copy_block(BlockJ,current_block);
break;
case L:
setColor(8); //設定顏色=8
color_to_change_pattern=8;
copy_block(BlockL,current_block);
break;
case I:
setColor(12); //設定顏色=12
color_to_change_pattern=12;
copy_block(BlockI,current_block);
break;
case Z:
setColor(6); //設定顏色=6
color_to_change_pattern=6;
copy_block(BlockZ,current_block);
break;
case S:
setColor(9); //設定顏色=9
color_to_change_pattern=9;
copy_block(BlockS,current_block);
break;
case T:
setColor(11); //設定顏色=11
color_to_change_pattern=11;
copy_block(BlockT,current_block);
break;
default:
break;
}
cur_x = (WIDTH-block_w)/2; //產生的位置
cur_y = 0;
}
void rotate_block(){ //旋轉方塊
int temp[block_h][block_w] = {0};
copy_block(current_block,temp);
int w,h;
for(w=0;w<block_w;w++){
for(h=0;h<block_h;h++){
current_block[h][w] = temp[block_w-1-w][h];
}
}
}
void land_block(){ //方塊落定到邊界
int w,h;
for(w=0;w<block_w;w++){
for(h=0;h<block_h;h++){
if(current_block[h][w]==1){
surface[cur_y+h][cur_x+w]=1;
}
}
}
}
int get_block_x_fill(int col){
int is_fill = 0;
int row;
for(row=0;row<block_w;row++){
if(current_block[row][col]==1){
return 1;
}
}
return is_fill;
}
int get_block_y_fill(int row){ //傳入方塊的row --> 檢查是不是真的有方塊
int is_fill =0;
int col;
for(col=0;col<block_w;col++){ //檢查方塊中,該row的每個col,是不是真的有方塊(1)
if(current_block[row][col]==1){
is_fill=1;
}
}
return is_fill;
}
void get_block_top_bottom_margin(int *top_margin, int *bottom_margin){
int i = 0;
for(i=0;i<block_h/2;i++){
if(get_block_y_fill(i)==0){
(*top_margin)+=1;
}
}
for(i=block_h-1;i>=block_h/2;i--){
if(get_block_y_fill(i)==0){
(*bottom_margin)+=1;
}
}
}
void get_block_left_right_margin(int *left_margin, int *right_margin){ //計算上下左右邊的白邊
int i = 0;
for(i=0;i<block_w/2;i++){ //檢查左半邊的白邊
if(get_block_x_fill(i)==0){
(*left_margin)+=1;
}
}
for(i=block_w-1;i>=block_w/2;i--){ //檢查右半邊的白邊
if(get_block_x_fill(i)==0){
(*right_margin)+=1;
}
}
}
int isCollision(int x,int y){ //邊界判斷
int top = 0,bottom = 0,left = 0,right = 0;
get_block_left_right_margin(&left,&right);
get_block_top_bottom_margin(&top,&bottom);
if(x<0-left || x+block_w>WIDTH+right){
return 1;
}
else if(y<0-top || y+block_h>HEIGHT+bottom){
return 1;
}
int w,h;
for(w=0;w<block_w;w++){
for(h=0;h<block_h;h++){
if(current_block[h][w]==1){
if(surface[y+h][x+w]==1){
return 1;
}
}
}
}
return 0;
}
void print_surface(){ //列印畫面
int x,y;
for(x=0;x<=WIDTH;x++){
for(y=0;y<HEIGHT;y++){
int row = y;
int col = x;
if(surface[row][col]==0){
printxy(" ",x,y);
}
if(score<310){ // level 1
level=1;
}
else if(score>400 && score<3100){ // level 2
level=2;
}
else if(score>3100 && score<=6000){ // level 3
level=3;
}
else if(score>6000 && score<=10000){ // level 4
level=4;
}
else if(score>10000 && score<=20000){ // level 5
level=5;
}
else if(score>20000){ // level6
level=6;
}
if(x == WIDTH && y == 0){
setColor(7);
printf("score : %d\n",score);
}
else if(x == WIDTH && y == 1){
setColor(7);
printf("level : %d\n",level);
}
else if(x == WIDTH && y == 2){
setColor(7);
printf("enter is delete\n");
}
else if(x == WIDTH && y == 3){
setColor(7);
printf("space is down rapidly\n");
}
}
}
}
HANDLE hand;
void setCursorVisable(int v){
CONSOLE_CURSOR_INFO cursor_info = {100,v};
SetConsoleCursorInfo(hand,&cursor_info);
}
void gotoxy(int x,int y){ //更改cursor位置並列印
COORD loc;
loc.X = x;
loc.Y = y;
SetConsoleCursorPosition(hand,loc);
}
void printxy(char*str , int x, int y ){ //更改cursor位置並列印
gotoxy(x,y);
printf("%s",str);
}
void erase_block(int block[][block_w],int x,int y){ //列印+暫停+擦掉方塊
int w,h;
for(w=0;w<block_w;w++){
for(h=0;h<block_h;h++){
if(block[h][w]==1){
printxy(" ",x+w,y+h);
}
}
}
}
void clear_one_line(int h){ //清除連線
int w,row;
for(row = h;row>0;row--){
for(w=0;w<WIDTH;w++){
surface[row][w] = surface[row-1][w];
}
}
for(w=0;w<WIDTH;w++){
surface[0][w] = 0;
}
}
int is_line_fill(int h){ //是否連線
int w;
for(w=0;w<WIDTH;w++){
if(surface[h][w]==0){
return 0;
}
}
return 1;
}
void check_line(){ //是否連線
int total_line = 0; //把消的行數清0
int h;
for(h=cur_y;h<HEIGHT;h++){
if(is_line_fill(h)==1){ //如果一行滿了就清掉
clear_one_line(h); //把一行清掉
total_line++; //消掉的行數增加
score+=total_line*150; //分數為行數的150倍
print_surface(); //印表面
tm-=30; //時間每次-30
set_timer(tm); //重新設定時間
}
}
}
static void set_timer(int t){
KillTimer(NULL, timerId);
timerId = SetTimer(NULL,0,t,NULL);
}
static void close_timer(){
KillTimer(NULL,timerId);
}
void move_block_down(){
if(isCollision(cur_x,cur_y+1)==0){
erase_block(current_block,cur_x,cur_y);
cur_y++;
print_block(current_block,cur_x,cur_y);
}
else{
land_block();
check_line();
make_new_block();
if(isCollision(cur_x,cur_y)==1){
erase_block(current_block,cur_x,cur_y); //擦掉原本的方塊
close_timer(); //暫停時間
system("cls"); //清空頁面
setColor(4); //顏色換紅色
erase_block(current_block,cur_x,cur_y); //擦掉原本的方塊
printf("\n\n\n\t遊戲結束!!!");
over=1; //遊戲結束-->不要再印出方塊了
printf("\n\n\t您的得分是 : %d",score); //印出分數
printf("\n\n\t您的等級是 : %d",level); //印出等級
Sleep(4000); //暫停4秒
}
print_block(current_block,cur_x,cur_y);
}
}
void key_control(){
int ch;
while(1){
if(PeekMessage(&msg,NULL,WM_TIMER,WM_TIMER,PM_REMOVE)!=0){
move_block_down();
}
if(kbhit()!=0){
ch = getch();
int rem_ch;
switch(ch){
case 13: //enter
if(isCollision(cur_x-1,cur_y)==0){
if(rem_ch!=13){
erase_block(current_block,cur_x,cur_y); //擦掉原本的方塊
rem_ch=13; //判斷是不是有一直換方塊
print_surface();
make_new_block(); //再印新的方塊
print_block(current_block,cur_x,cur_y);
}
}
break;
case 32: //space
rem_ch=32;
if(isCollision(cur_x,cur_y+1)==0){
erase_block(current_block,cur_x,cur_y);
while(isCollision(cur_x,cur_y+1)==0){
cur_y++;
}
}
print_block(current_block,cur_x,cur_y); //瞬降
break;
case 72: //up
rem_ch=72;
erase_block(current_block,cur_x,cur_y);
rotate_block();
if(isCollision(cur_x,cur_y)==1){ //如果發生碰撞,就要轉回來。
rotate_block();
rotate_block();
rotate_block();
}
print_block(current_block,cur_x,cur_y);
break;
case 80: //down
rem_ch=80;
if(isCollision(cur_x,cur_y+1)==0){
erase_block(current_block,cur_x,cur_y);
cur_y++;
print_block(current_block,cur_x,cur_y);
}
break;
case 75: //left
rem_ch=75;
if(isCollision(cur_x-1,cur_y)==0){
erase_block(current_block,cur_x,cur_y);
cur_x--;
print_block(current_block,cur_x,cur_y);
}
break;
case 77: //right
rem_ch=77;
if(isCollision(cur_x+1,cur_y)==0){
erase_block(current_block,cur_x,cur_y);
cur_x++;
print_block(current_block,cur_x,cur_y);
}
break;
}
}
}
}
void setColor(int color){ //換顏色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),color);
}
```
>.c檔
```c=
#include<stdio.h>
#include "HEAD.h"
#include <windows.h>
int main(){
setColor(6); //顏色為黃色
printf("\n\n\t\t遊戲說明");
printf("\n\ttips : \n");
printf("\t 1.等級6為MAX\n");
printf("\t 2.每消一行會加速一點\n");
printf("\t 3.↑為改變方向\n");
printf("\t 4.↓為加速向下\n");
printf("\t 5.← →為橫向移動\n");
printf("\t 6.space鍵為瞬間降落\n");
printf("\t 7.enter鍵為刪除方塊\n");
Sleep(8000); //1000==1秒,類似delay -->停8秒
PlaySound(TEXT("count.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_LOOP); //放倒數3 2 1的音樂
system("cls"); //清空頁面
printf("\n\n\n\t\t3");
Sleep(1000); //停1秒
system("cls"); //清空頁面
printf("\n\n\n\t\t2");
Sleep(1000); //停1秒
system("cls"); //清空頁面
printf("\n\n\n\t\t1");
Sleep(1000); //停1秒
system("cls"); //清空頁面
printf("\n\n\n\t\tGO!");
Sleep(1000); //停1秒
system("cls"); //清空頁面
PlaySound(TEXT("music_tetris.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_LOOP); //放tetris的音樂
hand = GetStdHandle(STD_OUTPUT_HANDLE);
setCursorVisable(0);
print_surface();
srand(time(NULL));
make_new_block();
print_block(current_block,cur_x,cur_y);
set_timer(tm);
key_control();
system("pause") ;
return 0;
}
```