--------Write in front --------
The first time to do a title party, everyone lightly sprayed. This game was independently completed by the blogger during the freshman c language training, and all the content is original. The mini-game took 5 days to complete. In addition to the common single-player mode, cheating mode, double-player mode, time trial and other gameplays have been added, which is really fun. Although it looks very simple now, it was not easy for me at the time. From page design to the selection of game background music to the compilation of key algorithms, every step has condensed my own efforts, and the pictures of the all-night battle are still vivid. in sight. Now sharing it, on the one hand, I hope it can help everyone, and on the other hand, I want to commemorate the wonderful freshman year. The source code address is at the end of the article, everyone can pick it up.
If it is helpful to you, you can like and support it, it would be even better if you can follow it ✅ , thank you all!
-----------------------text-----------------------
final effect
Home
Mode selection
Press 1 to enter single player mode
Press 2 to enter duo mode
Standard Mode: In addition to moving left and right down, direct drop and pause have been added, and level judgment has been added
Hell Mode: Under the premise of standard mode, the falling speed is accelerated, and it is more exciting!
Cheat mode: add dazzling mode, deformation, acceleration and deceleration functions
Two-Person Standard: An algorithm was devised to determine a winner or loser
Double Hell Survival: Exciting! !
Two-person time trial: set a timer, reset the algorithm for determining the outcome of a draw, and the one with the highest score within the specified time wins!
end animation
code section
main.c
#include <stdio.h>
#include <stdlib.h>
#include "game.h"
#include "mywindows.h"
#include <conio.h>
#include <mmsystem.h>
#pragma comment (lib, "winmm.lib")
void chooseMode(){
if(kbhit()){
mciSendString("close g",NULL,0,NULL);
switch(getch()){
case 49:
case 97: gameInit(1);break;
case 50:
case 98: gameInit(2);break;
case 51:
case 99: gameInit(3);break;
}
}
}
void chooseMode2(){
if(kbhit()){
mciSendString("close g",NULL,0,NULL);
switch(getch()){
case 49:
case 97: gameInit1(1);break;
case 50:
case 98: gameInit1(2);break;
case 51:
case 99: gameInit1(3);break;
}
}
}
int main()
{
///初始化句柄,必须放在最开始
initHandle();
///开始动画
mciSendString("open 俄罗斯方块进入音乐.mp3 alias g",NULL,0,NULL);
mciSendString("play g repeat",NULL,0,NULL);
printAnimation();
if(kbhit()){
getch();
chooseWindow();
}
if(kbhit()){
switch(getch()){
case 49:
case 97: chooseWindow2();chooseMode();break;
case 50:
case 98: chooseWindow3();chooseMode2();break;
}
}
return 0;
}
mywindows.c
#include "mywindows.h" //尖括号常用于引入系统头文件,双引号常用于引入自己定义的头文件 默认检索顺序不同
HANDLE handle;
//函数定义
void initHandle(){
handle = GetStdHandle(STD_OUTPUT_HANDLE);
hideCursor();//游戏启动后隐藏光标位置
//
}
void setColor(int color){
SetConsoleTextAttribute(handle,color);
}
void setPos(int x,int y){
COORD coord = {x*2,y}; //字母abcd:一个字符,汉字:两个字符
SetConsoleCursorPosition(handle,coord); //设置句柄位置
}
void hideCursor(){
CONSOLE_CURSOR_INFO info; //系统的结构体变量名字都是大写
info.bVisible = FALSE; //设置光标是否可见
info.dwSize = 1; //设置光标宽度(1-100)
SetConsoleCursorInfo(handle,&info);//指针取地址符
}
game.c key code
Single mode form printing
void printGradeLevel1(int num){
switch(num){
case 1:
grade1+=10; break;
case 2:
grade1+=30; break;
case 3:
grade1+=50; break;
case 4:
grade1+=80; break;
}
if(grade1 < 100){
level1 = 1;
}
else if(grade1 >= 100 && grade1 < 300){
level1 =2;
}
setColor(0x0c);
setPos(4,8);
printf("分数:%d",grade1);
setPos(4,9);
printf("等级:%d",level1);
}
void printGradeLevel2(int num){
switch(num){
case 1:
grade2+=10; break;
case 2:
grade2+=30; break;
case 3:
grade2+=50; break;
case 4:
grade2+=80; break;
}
if(grade2 < 100){
level2 = 1;
}
else if(grade2 >= 100 && grade2 < 300){
level2 =2;
}
setColor(0x09);
setPos(51,8);
printf("分数:%d",grade2);
setPos(51,9);
printf("等级:%d",level2);
}
Double mode form printing
void windowPrint2(int x,int y){
int i,j; //用来遍历二维数组
for(i=0;i<25;i++){
for(j=0;j<58;j++){
if(windowShape2[i][j] == 1){
setColor(0xc0);
setPos(x+j,y+i); //x是列,y是行
printf("%2s",""); // <--> printf(" ");
}
}
}
for(i=0;i<25;i++){
for(j=29;j<58;j++){
if(windowShape2[i][j] == 1){
setColor(0x90);
setPos(x+j,y+i); //x是列,y是行
printf("%2s",""); // <--> printf(" ");
}
}
}
}
//操作规则框架
void printInfo(){
setColor(0x0c);
setPos(2,2);
printf("N");
setPos(2,3);
printf("E");
setPos(2,4);
printf("X");
setPos(3,3);
printf("T");
setPos(3,14);
printf("红方操作规则");
setPos(3,15);
printf("------------");
setPos(2,16);
printf("按 a 或 A 左移");
setPos(2,17);
printf("按 d 或 D 右移");
setPos(2,18);
printf("按 s 或 S 下移");
setPos(2,19);
printf("按 w 或 W 变方向");
setPos(2,20);
printf("按 q 直接下落");
setColor(0x03);
setPos(49,2);
printf("N");
setPos(49,3);
printf("E");
setPos(49,4);
printf("X");
setPos(50,3);
printf("T");
setPos(50,14);
printf("蓝方操作规则");
setPos(50,15);
printf("------------");
setPos(49,16);
printf("按 ←键 左移");
setPos(49,17);
printf("按 →键 右移");
setPos(49,18);
printf("按 ↑键 下移");
setPos(49,19);
printf("按 ↓键 变方向");
setPos(49,20);
printf("按 回车 直接下落");
setPos(27,1);
printf("--战况--");
setPos(27,3);
printf("--------");
}
square print
void printBlock1(int x,int y,int shape,int status,int color){
int i,j;
for(i = 0;i<4;i++){
for(j = 0;j<4;j++){
if(block[shape][status][i][j] == 1){
setColor(color);
setPos(x+j,y+i);
printf("■");
}
}
}
}
void printBlock2(int x,int y,int shape,int status,int color){
int i,j;
for(i = 0;i<4;i++){
for(j = 0;j<4;j++){
if(block[shape][status][i][j] == 1){
setColor(color);
setPos(x+j,y+i);
printf("■");
}
}
}
}
Impact checking
//碰撞检测基于下一个位置的检测,数组与界面坐标的对应
int crash1(int x,int y,int shape,int status){
int i,j;
for(i = 0;i<4;i++){
for(j = 0;j<4;j++){
if(block[shape][status][i][j] == 1){
if(windowShape2[y+i][x+j] == 1){
///发生碰撞
if(cur_block1.x == 17 && cur_block1.y == 1){
///游戏结束
return -2;
}
///方块落到游戏池底部,发生碰撞
return -1;
}
}
}
}
return 0;
}
Victory judgment
void bottomBlock1(){
while(crash1(cur_block1.x,cur_block1.y+1,cur_block1.shape,cur_block1.status) != -1&&crash1(cur_block1.x,cur_block1.y+1,cur_block1.shape,cur_block1.status) != -2){
cur_block1.y += 1;
}
if(crash1(cur_block1.x,cur_block1.y+1,cur_block1.shape,cur_block1.status) == -1){
///发生碰撞:方块落到游戏池底部
///产生新的方块:下一个方块值 -> 当前正在下落的方块,重新产生下一个方块
save1();
removeLine1();
// lineClear();
updateGame1();
copyBlock1();
}
else if(crash1(cur_block1.x,cur_block1.y+1,cur_block1.shape,cur_block1.status) == -2){
///游戏结束
}
}
Button detection and double win-lose judgment algorithm
int gameInit1(int mode){
if(mode == 1){
mciSendString("open 双人标准.mp3 alias d",NULL,0,NULL);
mciSendString("play d repeat",NULL,0,NULL);
}
if(mode == 2){
mciSendString("open 双人地狱.mp3 alias e",NULL,0,NULL);
mciSendString("play e repeat",NULL,0,NULL);
}
if(mode == 3){
mciSendString("open 双人限时.mp3 alias f",NULL,0,NULL);
mciSendString("play f repeat",NULL,0,NULL);
}
int counter = 180;
float speed ;
if(mode == 1){
speed = 0.45;
}
else if(mode == 2){
speed = 0.25;
}
else if(mode == 3){
speed = 1;
}
///初始化句柄,必须放在最开始
initHandle();
///打开音乐文件
windowPrint2(0,0);
printInfo();
printGradeLevel1(0);
printGradeLevel2(0);
///游戏开始时间
clock_t startTime = clock();
///定时器
clock_t time1,time2;
time1 = clock();
startBlock1();
startBlock2();
nextBlock1();
nextBlock2();
while(1){
//按键驱动
///检测是否有按键按下
if(kbhit()){
switch(getch()){
case 'w':
case 'W':
changeStatusBlock1();break;
case 'a':
case 'A':
leftBlock1();break;
case 'd':
case 'D':
rightBlock1();break;
case 's':
case 'S':
downBlock1();break;
case 72:
changeStatusBlock2();break;
case 75:
leftBlock2();break;
case 77:
rightBlock2();break;
case 80:
downBlock2();break;
case 32:
bottomBlock1();break;
case 13:
bottomBlock2();break;
}
}
time2 = clock();
if(mode == 1|| mode == 2){
///每0.45秒下落一次
if((float)(time2-time1)/CLOCKS_PER_SEC > speed){
setPos(27,2);
if(downBlock1() == -2) {
if(grade2>grade1){
printf("蓝 方 胜!");break;
}
else if(downBlock2() == -2){
if(grade1==grade2){
printf("平 局");break;
}
else{
printf("红 方 胜!");break;
}
}
}
setPos(27,3);
if(downBlock2() == -2) {
if(grade1>grade2){
printf("红 方 胜!");break;
}
else if(downBlock1() == -2){
if(grade1==grade2){
printf("平 局");break;
}
else{
printf("蓝 方 胜!");break;
}
}
}
time1 = time2;
}
}
else if(mode == 3){
setPos(2,10);
printf("剩余时间:%3dS",counter);
setPos(50,10);
printf("剩余时间:%3dS",counter);
if((float)(time2-time1)/CLOCKS_PER_SEC > speed){
counter--;
setPos(27,2);
if(counter == 0){
if(grade2>grade1){
printf("蓝 方 胜!");break;
}
if(grade1==grade2){
printf("平 局");break;
}
else{
printf("红 方 胜!");break;
}
}
if(downBlock1() == -2) {
if(grade2>grade1){
printf("蓝 方 胜!");break;
}
else if(downBlock2() == -2){
if(grade1==grade2){
printf("平 局");break;
}
else{
printf("红 方 胜!");break;
}
}
}
setPos(27,3);
if(downBlock2() == -2) {
if(grade1>grade2){
printf("红 方 胜!");break;
}
else if(downBlock1() == -2){
if(grade1==grade2){
printf("平 局");break;
}
else{
printf("蓝 方 胜!");break;
}
}
}
time1 = time2;
}
}
}
if(mode == 1){
mciSendString("close d",NULL,0,NULL);
}
if(mode == 2){
mciSendString("close e",NULL,0,NULL);
}
if(mode == 3){
mciSendString("close f",NULL,0,NULL);
}
Sleep(1150);
printOver();
printFinish(mode);
}
Initial interface animation printing
void printStart(int x,int y){
//随机产生颜色
int color = rand()%0x10;
//处理黑色的情况
if(color == 0x00)
{
color = 0x0f;
}
setColor(color);
setPos(x,y);
printf("■■■■■ ■■■■■ ■■■■■ ■■■■ ■■■ ■■■■");
setPos(x,y+1);
printf(" ■ ■ ■ ■ ■ ■ ■");
setPos(x,y+2);
printf(" ■ ■■■■ ■ ■■■ ■ ■■■");
setPos(x,y+3);
printf(" ■ ■ ■ ■ ■ ■ ■");
setPos(x,y+4);
printf(" ■ ■■■■■ ■ ■ ■ ■■■ ■■■");
setPos(25,14);
printf("按任意键开始游戏!");
setPos(50,30);
printf("author 赵敬轩");
}
game.c complete code
Source address
gitee:https://gitee.com/i-dream-code/Tetris/
github:https://github.com/zhaojingxuan123/StrongestTetris
Baidu Cloud Disk: Link: https://pan.baidu.com/s/1dJeANXcNqChrXf7zuRQRWw Extraction code: geee
import method
The blogger uses codeblocks, a very useful compiler
Network disk link: Link: https://pan.baidu.com/s/1JkgUL8852lwx87j1NK2nsw Extraction code: qqfm
After installing codeblocks, drag 20200705.cbp directly to the left panel of codeblocks
Above build=>run to run
Summarize
Looking back now, this project has many problems, such as bloated code, poor reusability, no use of design patterns, and repeated creation of many wheels. In addition, some function settings are not reasonable enough, such as not returning to the previous menu, switching modes can only be entered by recompiling the game. The game is a one-time game, and adding a scoreboard to store the player's highest score can also increase the gaming experience. There will be an opportunity to improve it in the future.
"Self-discipline in prosperity, self-healing in depression", in a trance, looking back on the years, I am calm.