文章目录
- 1 前言
- 2 游戏截图
- 3 源代码
1 前言
本文介绍的是我空闲时间用C语言写的一个俄罗斯方块游戏,整个程序只有一个文件,实现了基本的游戏功能,但还是有些缺陷,希望有心之士能够继续完善,感谢各位!
2 游戏截图
请注意!a、d、s、w都是小写
3 源代码
/*
author: New_Teen
time: 2023.11.2 20:14 周四
IDE: visual studio 2019
俄罗斯方块
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#include <stdbool.h>
#include <conio.h>#define BOARD_CUBE ' '
#define WIDTH 15
#define HEIGHT 15
#define FLUSH_RATE 200char curr_cube;
int curr_square;
int curr_x, curr_y;
int score = 0;
int start_number = 0;
char board[HEIGHT][WIDTH];
int tmp[4][2];
int square[5][4][4] = { {{1,0,0,0},{1,0,0,0},{1,0,0,0},{1,0,0,0}},{{1,0,0,0},{1,1,1,0},{0,0,0,0},{0,0,0,0}},{{0,1,0,0},{1,1,1,0},{0,0,0,0},{0,0,0,0}},{{1,1,0,0},{1,1,0,0},{0,0,0,0},{0,0,0,0}},{{0,1,0,0},{1,1,0,0},{1,0,0,0},{0,0,0,0}} };void init_board(); //初始化游戏面板
void clear_board(); //清空控制台
void delay_board(); //延时
void print_board(); //打印游戏面板
void init_square(); //初始化方块
void drop_square(); //方块默认下落
void update_board(); //更新游戏面板
bool is_collision_left(); //检测方块左侧是否碰撞
bool is_collision_right(); //检测方块右侧是否碰撞
bool is_collision_bottom(); //检测方块下方是否碰撞
bool is_collsion_rotate(); //检测方块是否可以旋转
bool is_game_over(); //检测游戏是否结束
void rotate(); //旋转方块
void rush_board(); //消除成层方块(得分)
void start_game(); //游戏开始面板int main() {srand((unsigned)time(NULL)); //根据程序执行时间产生随机数种子start_game();init_board();while (1) {init_square();if (is_game_over())break;for (;;) {if (!is_collision_bottom())drop_square();elsebreak;if (_kbhit()) {char ch = _getch();if (ch == 'a' && !is_collision_left())curr_x--;else if (ch == 'd' && !is_collision_right())curr_x++;else if (ch == 's' && !is_collision_bottom())curr_y++;else if (ch == 'w' && !is_collsion_rotate())rotate();}update_board();rush_board();print_board();delay_board();clear_board();}}printf("Game over!!\nYour score is %d\n", score);return 0;
}void init_board() {for (int i = 0; i < HEIGHT; ++i)for (int j = 0; j < WIDTH; ++j)board[i][j] = BOARD_CUBE;
}void clear_board() {system("cls");
}void delay_board() {Sleep(FLUSH_RATE);
}void print_board() {for (int i = 0; i < HEIGHT; ++i) {for (int j = 0; j < WIDTH; ++j)putchar(board[i][j]);puts("#");}puts("################");printf("score: %d\n", score);
}void init_square() {curr_cube = "ABCDEFGH"[rand()%8];start_number == 1 ? curr_square = 0 : curr_square = rand() % 5;curr_x = WIDTH / 2, curr_y = -4;int count = 0;for (int i = 0; i < 4; ++i)for (int j = 0; j < 4; ++j)if (square[curr_square][i][j]) {tmp[count][0] = curr_y + i;tmp[count][1] = curr_x + j;count++;}
}void drop_square() {curr_y++;
}void update_board() {//清除之前位置的方块int row, col;for (int i = 0; i < 4; ++i) {row = tmp[i][0];col = tmp[i][1];if (row >= 0 && row < HEIGHT&& col >= 0 && col < WIDTH)board[row][col] = BOARD_CUBE;}int count = 0;//画出现在位置的方块,并更新tmpfor (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {row = curr_y + i;col = curr_x + j;if (square[curr_square][i][j]) {tmp[count][0] = row;tmp[count][1] = col;count++;if (row >= 0 && row < HEIGHT&& col >= 0 && col < WIDTH)board[row][col] = curr_cube;}}}
}bool is_collision_left() {for (int i = 0; i < 4; i++)for (int j = 0; j < 4; j++)if (square[curr_square][i][j]) {//检测方块与面板左墙壁的碰撞if (curr_x + j <= 0)return true;//检测方块与左侧方块的碰撞if (j == 0) {if (board[curr_y + i][curr_x + j - 1] != BOARD_CUBE)return true;}else {if (!square[curr_square][i][j - 1] && board[curr_y + i][curr_x + j - 1] != BOARD_CUBE)return true;}}return false;
}bool is_collision_right() {for (int i = 0; i < 4; i++)for (int j = 0; j < 4; j++)if (square[curr_square][i][j]) {//检测方块与面板右墙壁的碰撞if (curr_x + j >= WIDTH-1)return true;//检测方块与右侧方块的碰撞if (j == 3) {if (board[curr_y + i][curr_x + j + 1] != BOARD_CUBE)return true;}else {if (!square[curr_square][i][j + 1] &&board[curr_y + i][curr_x + j + 1] != BOARD_CUBE)return true;}}return false;
}bool is_collision_bottom() {//找到当前方块的最下层int low = -99;for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++)if (square[curr_square][i][j] == 1)low = i;//如果达到面板最底部if(curr_y + low >= HEIGHT-1)return true;for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {//考虑方块下面有方块的情况if (i < 3) {if (square[curr_square][i][j] && !square[curr_square][i + 1][j]&& (curr_y + i + 1 >=0) && board[curr_y + i + 1][curr_x + j] != BOARD_CUBE)return true;}else {if (square[curr_square][i][j] && (curr_y + i + 1 >= 0) && board[curr_y + i + 1][curr_x + j] != BOARD_CUBE)return true;}}}return false;
}bool is_collsion_rotate() {int middle[4][4] = { 0 };//暂存旋转后方块for (int i = 0; i < 4; ++i)for (int j = 0; j < 4; ++j)middle[i][j] = square[curr_square][j][i];//旋转后方块是否与面板已有方块重叠for (int i = 0; i < 4; ++i)for (int j = 0; j < 4; ++j)if (!square[curr_square][i][j] && middle[i][j]&& board[curr_y + i][curr_x + j] != BOARD_CUBE)return true;return false;
}void rotate() {//清除之前位置的方块int row, col;for (int i = 0; i < 4; ++i) {row = tmp[i][0];col = tmp[i][1];if (row >= 0 && row < HEIGHT&& col >= 0 && col < WIDTH)board[row][col] = BOARD_CUBE;}//旋转方块int rotate_tmp[4][4] = { 0 };memcpy(rotate_tmp, square[curr_square], 16 * sizeof(int));for (int i = 0; i < 4; ++i)for (int j = 0; j < 4; ++j)square[curr_square][i][j] = rotate_tmp[j][i];int count = 0;//画出现在位置的方块,并更新tmpfor (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {row = curr_y + i;col = curr_x + j;if (square[curr_square][i][j]) {tmp[count][0] = row;tmp[count][1] = col;count++;if (row >= 0 && row < HEIGHT&& col >= 0 && col < WIDTH)board[row][col] = curr_cube;}}}
}bool is_game_over() {for (int j = 0; j < WIDTH; ++j)if (board[0][j] != BOARD_CUBE)return true; return false;
}void rush_board() {int count, floor;floor = 0;for (int i = HEIGHT - 1; i >= 0; --i) {count = 0;for (int j = 0; j < WIDTH; ++j)if (board[i][j] != BOARD_CUBE)count++;if (count == WIDTH)floor++;elsebreak;}//得到floor后,面板下移floor层if (floor != 0) {for (int i = HEIGHT - 1 - floor; i >= 0; --i)for (int j = 0; j < WIDTH; ++j)board[i + floor][j] = board[i][j];score += floor;}
}void start_game() {printf("----------------俄罗斯方块----------------\n");printf("\n游戏规则:a:左移 d:右移 s:下移 w:旋转\n");printf("\n输入1:全程长条方块 输入2:经典随机方块\n");while (start_number != 1 && start_number != 2) {\printf("\n请输入序号(1或者2): ");scanf_s("%d", &start_number);}clear_board();
}