大一实训----C语言编写俄罗斯方块游戏
一、代码
main.c
#include <stdio.h>
#include <stdlib.h>
#include "game.h"
int main()
{
gameInit();
return 0;
}
mywindows.h
#ifndef MYWINDOWS_H_INCLUDED
#define MYWINDOWS_H_INCLUDED
/*系统调用模块*/
#include <windows.h>
//函数声明
//初始化句柄
void initHandle();
//设置颜色
void setColor(int color);
//设置光标位置
void setPos(int x,int y);
//隐藏光标
void hideCursor();
#endif // MYWINDOWS_H_INCLUDED
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};
SetConsoleCursorPosition(handle,coord);
}
void hideCursor()
{
CONSOLE_CURSOR_INFO info;
info.bVisible = FALSE; //设置光标是否可见
info.dwSize = 1; //光标的宽度(1~100)
SetConsoleCursorInfo(handle,&info);
}
game.h
#ifndef GAME_H_INCLUDED
#define GAME_H_INCLUDED
/*游戏逻辑模块*/
#include <stdio.h>
#include <time.h>
typedef struct{
int x;
int y;
int shape;
int status;
int color;
}BLOCK;
//绘制游戏池边框
void windowPrint(int x, int y);
//游戏初始化
void gameInit();
//打印操作说明
void printInfo();
//打印分数等级
void printGradeLevel(int num);
//游戏计时
void gameTime(clock_t star_time);
//打印方块
void printBlock(int x ,int y ,int shape ,int status ,int color);
//删除方块
void deleteBlock(int x, int y, int shape ,int status);
//拷贝方块
void copyBlock();
//产生游戏第一个方块
void startBlock();
//产生下一个方块
void nextBlock();
//方块下移
//返回值:标志方块是否到游戏池底部
int downBlock();
//方块左移
int leftBlock();
//方块右移
int rightBlock();
//方块变形
void changeBlock();
//碰撞检测
int crash(int x, int y, int shape, int status);
//保存方块
void save();
//刷新游戏池
void undateGame();
//暂停
void pause();
//落地
void bottomBlock();
//消行检测
void lineClear();
//消行下移
void lineDown(int line);
//游戏结束动画
void printOver();
//重新开始提示
void printFinish();
//重新开始游戏
void againGame();
//打印开始图案
void printStart(int x, int y);
//清除开始动画
void deleteStart(int x, int y);
//动画效果->定时(边界控制)
void printAnimation();
//读取最高记录
void readFile();
//保存最高记录
void writeFile();
#endif // GAME_H_INCLUDED
game.c
#include "game.h"
#include "data.h"
#include "mywindows.h"
#include <conio.h>
#include <mmsystem.h>
#pragma comment(lib,"winmm.lib")
int grade = 0; //分数
int level = 1; //等级
int max=0; //最高记录
BLOCK cur_block; //当前方块
BLOCK next_block; //下一个方块
void windowPrint(int x, int y)
{
int i,j;
for(i = 0; i < 25; i++){
for( j = 0; j < 37; j++){
if(windowShape[i][j] == 1){
setPos(x+j,y+i);//打印位置,坐标位置和数组内容相反
setColor(0x0f);
printf("■");
}else if(windowShape[i][j] == 2){
setPos(x+j,y+i);
setColor(0x04);
printf("■");
}else if(windowShape[i][j] == 3){
setPos(x+j,y+i);
setColor(0x0e);
printf("■");
}else if(windowShape[i][j] == 4){
setPos(x+j,y+i);
setColor(0x06);
printf("■");
}
}
}
}
void printInfo()
{
setColor(0x0f);
setPos(31,8);
printf("操作规则:");
setPos(33,9);
printf("变形:↑");
setPos(33,11);
printf("下移:↓");
setPos(33,13);
printf("左移:←");
setPos(33,15);
printf("右移:→");
setPos(33,17);
printf("直接下落:Enter");
setPos(33,19);
printf("暂停:space");
setPos(33,21);
printf("退出:ESC");
setPos(33,23);
printf("音乐:开O/关C");
}
void printGradeLevel(int num)
{
switch(num){
case 0:break;
case 1:grade += 10;break;
case 2:grade += 20;break;
case 3:grade += 30;break;
case 4:grade += 40;break;
}
setColor(0x0f);
if(grade < 20){
level = 1;
setPos(10,9);
printf("速度:0.45s");
}
else if(grade <= 40 && grade >= 20){
level = 2;
setPos(10,9);
printf("速度:0.30s");
}
else if(grade <= 60 && grade > 40){
level = 3;
setPos(10,9);
printf("速度:0.20s");
}
else if(grade <= 100 && grade > 60){
level = 4;
setPos(10,9);
printf("速度:0.15s");
}
setColor(0x0f);
setPos(10,6);
printf("分数:%d", grade);
setPos(10,7);
printf("等级:%d", level);
setPos(10,8);
printf("最高分:%d", max);
setPos(11,16);
setColor(0x04);
printf("■");
setPos(10,10);
setColor(0x0e);
printf("■■■");
setPos(9,11);
setColor(0x0e);
printf("■■■■■");
setPos(9,12);
setColor(0x0e);
printf("■■■■■");
setColor(0x0e);
setPos(9,13);
printf("■■■■■");
setPos(8,14);
setColor(0x0e);
printf("■■■■■■■");
}
void gameTime(clock_t star_time)
{
setColor(0x06);
setPos(42,12);
printf("本次游戏已运行 %ld s",(clock()-star_time)/CLOCKS_PER_SEC);
}
void printBlock(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 deleteBlock(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){
setPos(x+j, y+i);
printf(" ");
}
}
}
}
void startBlock()
{
//第一个方块:形状/形态/颜色->随机 位置(x,y)固定
//初始化cur_block
//设置随机数种子(时间永远不一样)
srand((unsigned)time(NULL));
cur_block.x = 22;
cur_block.y = 1;
cur_block.shape = rand()%7;
cur_block.status = rand()%4;
cur_block.color = rand()%0x10; //0x00~0x0f
if(cur_block.color == 0x00){
cur_block.color = 0x01;
}
else if(cur_block.color == 0x0f){
cur_block.color = 0x06;
}
else if(cur_block.color == 0x07){
cur_block.color = 0x0d;
}
else if(cur_block.color == 0x08){
cur_block.color = 0x09;
}
printBlock(cur_block.x, cur_block.y, cur_block.shape, cur_block.status, cur_block.color);
}
void nextBlock()
{
//形状、形态、颜色->随机,位置->固定
//初始化next_block值
deleteBlock(next_block.x, next_block.y, next_block.shape, next_block.status);
next_block.x = 34;
next_block.y = 2;
next_block.shape = rand()%7;
next_block.status = rand()%4;
next_block.color = rand()%0x10; //0x00~0x0f
if(next_block.color == 0x00){
next_block.color = 0x01;
}
else if(next_block.color == 0x0f){
next_block.color = 0x06;
}
else if(next_block.color == 0x07){
next_block.color = 0x0d;
}
else if(next_block.color == 0x08){
next_block.color = 0x09;
}
printBlock(next_block.x, next_block.y, next_block.shape, next_block.status, next_block.color);
}
void copyBlock()
{
//当前方块=下一个方块,并且产生新的下一个方块
cur_block = next_block;
cur_block.x= 22;
cur_block.y = 1;
printBlock(cur_block.x, cur_block.y, cur_block.shape, cur_block.status, cur_block.color);
nextBlock();
}
int downBlock()
{
//原理:删除正在显示的方块,纵坐标加1,重新打印
if(crash(cur_block.x, cur_block.y+1, cur_block.shape,cur_block.status) == -1){
//发生碰撞,方块落地游戏池底部
//产生新的方块:下一个方块值->当前正在下落的方块,重新产生下一个方块
//保存方块->检测消行—>打印游戏池->产生新方块
save();
lineClear();
updateGame();
copyBlock();
return -1;
}
else if(crash(cur_block.x, cur_block.y+1, cur_block.shape, cur_block.status))
{
//游戏结束
return -2;
}
else{
deleteBlock(cur_block.x, cur_block.y, cur_block.shape, cur_block.status);
cur_block.y += 1;
printBlock(cur_block.x, cur_block.y, cur_block.shape, cur_block.status, cur_block.color);
return 0;
}
}
int leftBlock(){
if(crash(cur_block.x-1, cur_block.y, cur_block.shape,cur_block.status) == -1){
//如果发生碰撞,什么都不做,直接返回
return;
}
deleteBlock(cur_block.x, cur_block.y, cur_block.shape, cur_block.status);
cur_block.x -= 1;
printBlock(cur_block.x, cur_block.y, cur_block.shape, cur_block.status, cur_block.color);
}
int rightBlock()
{
if(crash(cur_block.x+1, cur_block.y, cur_block.shape,cur_block.status) == -1){
return;
}
deleteBlock(cur_block.x, cur_block.y, cur_block.shape, cur_block.status);
cur_block.x += 1;
printBlock(cur_block.x, cur_block.y, cur_block.shape, cur_block.status, cur_block.color);
}
void changeBlock()
{
if(crash(cur_block.x, cur_block.y, cur_block.shape,(cur_block.status+1)%4) == -1){
return;
}
//通过数组下标加一,获得下一个形态,下标[0~3]
deleteBlock(cur_block.x, cur_block.y, cur_block.shape, cur_block.status);
cur_block.status = (cur_block.status+1) % 4;
printBlock(cur_block.x, cur_block.y, cur_block.shape, cur_block.status, cur_block.color);
}
int crash(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(windowShape[i+y][j+x-15] == 1){
//发生碰撞
if(cur_block.x == 22 && cur_block.y == 1)
{
//方块产生就发生碰撞,游戏结束
return -2;
}
//方块落到游戏池底部发生碰撞
return -1;
}
}
}
}
}
void save()
{
//根据方块在界面上的坐标,把坐标对应到游戏池下标的对应位置
//方块为1保存到windowShape数组中
int i,j;
for(i = 0; i < 4; i++){
for(j = 0; j < 4; j++){
if(block[cur_block.shape][cur_block.status][i][j] == 1){
windowShape[i+cur_block.y][j+cur_block.x-15] = 1;
}
}
}
}
void updateGame()
{
int i,j;
for(i = 23; i > 0; i--){
for(j = 1; j < 15; j++){
if(windowShape[i][j] == 1){
setColor(0x0e);
setPos(15+j,i);
printf("■");
}else{
setColor(0x00);
setPos(15+j,i);
printf(" ");
}
}
}
}
void pause()
{
while(1){
if(getch() == 32){
break;
}
}
}
void bottomBlock()
{
while(1){
if(crash(cur_block.x, cur_block.y+1, cur_block.shape, cur_block.status) == -1){
save();
lineClear();
updateGame();
copyBlock();
return;
}else if(crash(cur_block.x, cur_block.y+1, cur_block.shape, cur_block.status) == -2){
//游戏结束
return;
}else{
++ cur_block.y;
}
}
}
void lineClear()
{
//遍历windowShape,判断是否有满行,这行所有值加起来为14
int i,j;
int number = 0;
for(i = 23; i > 0; i--){
int total = 0;
for(j = 1; j < 15; j++){
total += windowShape[i][j];
}
if(total == 14){
lineDown(i);
i += 1;
//统计一次消几行
number += 1;
}
}
printGradeLevel(number);
}
void lineDown(int line)
{
//从第line行开始,i = i - 1
int i,j;
for(i = line; i > 1; i --){ //i>1,保证方块不被下移
for(j = 1; j < 15; j ++){
windowShape[i][j] = windowShape[i-1][j];
}
}
}
void printOver()
{
int i,j;
for(i = 23; i > 0; i --){
for(j = 1; j < 15; j++){
setColor(0x00);
setPos(j+15,i);
printf("□");
Sleep(5);
}
}
}
void printFinish()
{
mciSendString("open E:\\project\\tetris\\bin\\Debug\\res\\gameover.wav alias o",NULL, 0, NULL);
mciSendString(TEXT("play o"), NULL, 0, NULL);
setColor(0x0f);
setPos(21,21);
printf("游戏结束!");
setPos(17,23);
printf("按Y重新开始");
setPos(23,23);
printf("按N结束游戏");
setPos(17,10);
setColor(0x0e);
if(grade > max)
{
printf("纪录打破,目前最高纪录:%d",grade);
writeFile();
}else if(grade == max){
printf("纪录持平,请突破你的极限!");
}else{
printf("继续努力,与最高记录差:%d",max-grade);
}
switch(getch())
{
case 'y':
case 'Y':
againGame();break;
case 'n':
case 'N':
system("cls");
exit(0);
break;
default:
printFinish();break;
}
}
void againGame()
{
//重置分数、等级、游戏池数据->开始游戏
int level = 1;
int grade = 0;
//重置游戏池数据
int i,j;
for(i = 1; i < 24; i ++){
for(j = 1; j < 15; j ++){
windowShape[i][j] = 0;
}
}
setColor(0x00);
system("cls"); //清屏
gameInit();
}
void printStart(int x, int y)
{
int color = rand()%0x10;
if(color == 0x00){
color = 0x01;
}
else if(color == 0x07){
color = 0x0d;
}
else if(color == 0x08){
color = 0x09;
}
//绘制图案
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(x,y+8);
printf("~~~~");
setPos(x+2,y+6);
printf("┌═════════┐...┌════════┐...┌═════════┐ ╭═════╮\n");
setPos(x+2,y+7);
printf("║ ║ ═ ║ ║ ═ ║ ║═ ║ ║\n");
setPos(x+2,y+8);
printf("└⊙═⊙═⊙═⊙ ⊙═⊙═⊙═⊙ ~ └⊙═⊙═⊙═⊙~~╰⊙═⊙╯\n");
setPos(28,15);
setColor(0x0f);
printf("按R键开始游戏!");
}
void deleteStart(int x, int y)
{
int i,j;
for(i = y- 5; i <= y+8; i++){
for(j = x-5; j <= x+36; j++){
setPos(j,i);
printf(" ");
}
}
}
void printAnimation()
{
clock_t time1, time2;
time1 = clock();
int x = 5;
printStart(x,5);
while(1)
{
time2 = clock();
if(time2 - time1 > 300){ //300ms
time1 = time2;
deleteStart(x,5);
printStart(++x,5);
if(25 == x){
deleteStart(x,5);
x = 5;
}
}
//按任意键退出:检测是否有按键输入,若有则返回一个非0值,否则返回0
if(kbhit()){
break;
}
}
system("cls");
}
void readFile()
{
FILE *fp;
fp = fopen("俄罗斯方块记录.txt","r+");
if(fp == NULL)
{
fp = fopen("俄罗斯方块记录.txt","w+");
fwrite(&max,sizeof(int),1,fp);
}
fseek(fp,0,0);
fread(&max,sizeof(int),1,fp);
fclose(fp);
}
void writeFile()
{
FILE *fp;
fp = fopen("俄罗斯方块记录.txt","r+");
fwrite(&grade,sizeof(int),1,fp);
fclose(fp);
}
void gameInit()
{
//初始化句柄必须放在最前面
initHandle();
//打开音乐文件
mciSendString("open E:\\project\\tetris\\bin\\Debug\\res\\俄罗斯方块游戏背景音乐.mp3 alias a",NULL, 0, NULL);
//播放音乐
mciSendString(TEXT("play a"), NULL, 0, NULL);
//开始动画
printAnimation();
//读写最高值
readFile();
windowPrint(15,0);
printInfo();
printGradeLevel(0);
//游戏开始时间
clock_t startTime = clock();
//定时器
clock_t time1,time2;
time1 = clock();
startBlock();
nextBlock();
while(1){
//检测是否有按键按下
if(kbhit()){
switch(getch()){
//变形
case 72:
PlaySound("E:\\project\\tetris\\bin\\Debug\\res\\change.wav", NULL, SND_FILENAME | SND_ASYNC);
changeBlock();break;
//左移
case 75:
PlaySound("E:\\project\\tetris\\bin\\Debug\\res\\move.wav", NULL, SND_FILENAME | SND_ASYNC);
leftBlock();break;
//右移
case 77:
PlaySound("E:\\project\\tetris\\bin\\Debug\\res\\move.wav", NULL, SND_FILENAME | SND_ASYNC);
rightBlock();break;
//下移
case 80:
PlaySound("E:\\project\\tetris\\bin\\Debug\\res\\move.wav", NULL, SND_FILENAME | SND_ASYNC);
downBlock();break;
//暂停
case 32:
PlaySound("E:\\project\\tetris\\bin\\Debug\\res\\matchend.wav", NULL, SND_FILENAME | SND_ASYNC);
pause();break;
//落地
case 13:
PlaySound("E:\\project\\tetris\\bin\\Debug\\res\\garbage.wav", NULL, SND_FILENAME | SND_ASYNC);
bottomBlock();break;
case 27:
system("cls");
setColor(0x0f);
setPos(10,10);
printf("---游戏结束!---");
setPos(9,11);
printf("---按任意键退出!---");
getch();
exit(0);
break;
case 'c':
case 'C':
//关闭音乐
mciSendString(TEXT("stop a"), NULL, 0, NULL);
break;
case 'o':
case 'O':
//播放音乐
mciSendString(TEXT("play a"), NULL, 0, NULL);
}
}
time2 = clock();
//每0.45s下落一次
if(level == 1){
if(time2 - time1 > 0.45 * CLOCKS_PER_SEC){
//游戏计时
gameTime(startTime);
if(downBlock() == -2){
break;
}
time1 = time2;
}
}else if(level == 2){
if(time2 - time1 > 0.30 * CLOCKS_PER_SEC){
//游戏计时
gameTime(startTime);
if(downBlock() == -2){
break;
}
time1 = time2;
}
}else if(level == 3){
if(time2 - time1 > 0.20 * CLOCKS_PER_SEC){
//游戏计时
gameTime(startTime);
if(downBlock() == -2){
break;
}
time1 = time2;
}
}else if(level == 4){
if(time2 - time1 > 0.15 * CLOCKS_PER_SEC){
//游戏计时
gameTime(startTime);
if(downBlock() == -2){
break;
}
time1 = time2;
}
}
}
printOver();
printFinish();
}
data.h
#ifndef DATA_H_INCLUDED
#define DATA_H_INCLUDED
/*数据模块*/
//界面数组
int windowShape[25][37] =
{
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,2,2,2,2,2,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,2,2,1,0,2,2,0,0,0,4,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,2,2,1,1,2,2,0,0,4,3,4},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,2,2,2,2,2,2,0,0,4,3,4},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,2,2,2,0,0,0,2,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,2,2,2,0,0,2,2,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,2,2,2,2,2,2,2,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,2,2,2,2,2,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,2,2,2,2,0,0,0,0},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,2,0,2,0,0,0,0,0,0}
};//边框为1,游戏池长度为14
//第一维:七种类型的方块
//第二维:每种方块有4种形态
//第三维,第四维:保存方块数据{}
int block[7][4][4][4] =
{
{//Z
{{1,1,0,0},{0,1,1,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}},
{{1,1,0,0},{0,1,1,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}}
},
{//S
{{0,1,1,0},{1,1,0,0},{0,0,0,0},{0,0,0,0}},
{{1,0,0,0},{1,1,0,0},{0,1,0,0},{0,0,0,0}},
{{0,1,1,0},{1,1,0,0},{0,0,0,0},{0,0,0,0}},
{{1,0,0,0},{1,1,0,0},{0,1,0,0},{0,0,0,0}}
},
{//L
{{1,0,0,0},{1,0,0,0},{1,1,0,0},{0,0,0,0}},
{{1,1,1,0},{1,0,0,0},{0,0,0,0},{0,0,0,0}},
{{1,1,0,0},{0,1,0,0},{0,1,0,0},{0,0,0,0}},
{{0,0,1,0},{1,1,1,0},{0,0,0,0},{0,0,0,0}}
},
{//J
{{0,1,0,0},{0,1,0,0},{1,1,0,0},{0,0,0,0}},
{{1,0,0,0},{1,1,1,0},{0,0,0,0},{0,0,0,0}},
{{1,1,0,0},{1,0,0,0},{1,0,0,0},{0,0,0,0}},
{{1,1,1,0},{0,0,1,0},{0,0,0,0},{0,0,0,0}}
},
{//I
{{1,1,1,1},{0,0,0,0},{0,0,0,0},{0,0,0,0}},
{{1,0,0,0},{1,0,0,0},{1,0,0,0},{1,0,0,0}},
{{1,1,1,1},{0,0,0,0},{0,0,0,0},{0,0,0,0}},
{{1,0,0,0},{1,0,0,0},{1,0,0,0},{1,0,0,0}}
},
{//T
{{1,1,1,0},{0,1,0,0},{0,0,0,0},{0,0,0,0}},
{{0,1,0,0},{1,1,0,0},{0,1,0,0},{0,0,0,0}},
{{0,1,0,0},{1,1,1,0},{0,0,0,0},{0,0,0,0}},
{{1,0,0,0},{1,1,0,0},{1,0,0,0},{0,0,0,0}}
},
{//田
{{1,1,0,0},{1,1,0,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}},
{{1,1,0,0},{1,1,0,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}}
}
};
#endif // DATA_H_INCLUDED
二、运行效果图:
游戏开始界面动画,以左右移动的火车和“TETRIS”为主,颜色为随机变化。“按R键开始游戏”–>其实设置的是任意键,但在后面游戏中有一些按键被利用,为了保证游戏体验的正常进行,则写的是R键进入游戏
游戏过程中,按ESC退出游戏的效果图
游戏版面
游戏池和右边的小恐龙是由一个二维数组完成,详细代码位于data.h中。左边的铃铛是直接打印的。
这是游戏结束的效果图,游戏结束自带动画效果,当方块触碰到游戏池顶部时,方块自上而下消失并打印游戏结束和分数比较等字样。
三、实训笔记
1.开发环境的安装:
安装文档,安装流程,新建工程以及无法编译解决方法。
2.程序开发流程:
可行性研究:项目是否可行
需求分析:目标系统必须完整提现用户需求
总体设计:系统的体系结构,是定义程序由哪些模块组成以及模块之间的关系
详细设计:详细设计每个模块确定每个实现模块功能所需要的算法和数据结构
编码/单元测试:代码编写和测试.
综合测试:通过各种测试手段使软件达到用户需求.
运行维护:使软件持款的满足用户需求.
3.windows.h
句柄:标识windows资源(菜单图标,窗口)或设备对象
STD_INPUT_HANDLE(标准输入设备句柄):键盘\鼠标
STD_OUTPUT_HANDLE(标准输出设备句柄):屏幕
STD_ERROR_HANDLE(标准错误句柄):屏幕
设置控制台窗口标题 : SetConsoleTitle
获取句柄:GetStdHandle(handle,nstdhandle)
设文字颜色:SetConsoleTextAttribute(handle,color)
FOREGROUND_BLUE 蓝色 FOREGROUND_GREEN 绿色
FOREGROUND_RED 红色 BACKGROUND_INTENSITY 背景色加强
设置输出字体高亮并添加红色背景:
SetConsoleTextAttribute(handle,\BACKGROUND_INTENSITY|BACKGROUND_RED);
设光标位置:COORD pos->SetConsoleCursorPosition(handle,pos)
定时器:clock()
CLOCKS_PER_SEC:1000
4.需求分析
必要需求:
游戏开始:开始动画,游戏说明,开始按钮,游戏设置(分数/难度),游戏模式
游戏界面:游戏池边界,计时,图案,得分情况,方块数目,提示下一个方块,正在下落的方块,最高分记录
方块:颜色,形状,形态,位置信息
方块运动:定时下落,用户控制(方块下移,左移,右移,变形,落地,暂停)
消行:消行得分
重新开始
退出游戏
次级需求:
登录,分辨率,音乐,声音,存档,排行榜,双人对战,成绩分享,成就系统,充值
5.总体设计
系统调用模块:封装windows.h里常用函数
数据模块:程序里共用数据
游戏逻辑模块
6.函数:
返回值:int,void,double
函数名:字母\数字\下划线,只能以字母和下划线开头
命名:小驼峰:第一个单词首字母小写,后面单词首字母大写(函数/变量)
大驼峰:每个单词首字母都大写(类)
形参:(),(int)
7.结构体
是一种集合,可以包含多个变量或者数组(成员)
struct 结构体名{
结构体包含的变量或者数组;
};
(1).先定义结构体类型,在定义结构体变量
struct stu{
char *name;
int age;
float score;
};
struct stu stu1, stu2; //stu1,stu2是结构体变量
(2).定义结构体类型的同时定义结构体变量
struct stu{
char *name;
int age;
float score;
}stu1,stu2;
struct stu stu3,stu4;
(3).直接定义结构体变量
struct{
char *name;
int age;
float score;
}stu1,stu2;
(没有结构体名称,后面无法定义结构体变量)
(4).取别名
typedef struct stu{
char *name;
int age;
float score;
}STU;
STU stu1,stu2;
8.getch()
是编程中所用的函数,这个函数是一个不回显函数,当用户按下某个字符时,函数自动读取,无需按回车,是一个计算机函数,在windows平台下从控制台无回显地取一个字符。有的C语言命令行程序会用到此函数做游戏。
getch():
所在头文件:conio.h
函数用途:从控制台读取一个字符,但不显示在屏幕上
函数原型:int getch(void)
返回值:读取的字符
例如:
char ch;或int ch;
getch();或ch=getch();
用getch();会等待你按下任意键,再继续执行下面的语句;
用ch=getch();会等待你按下任意键之后,把该键字符所对应的ASCII码赋给ch,再执行下面的语句。
CodeBlocks播放音乐
1.playSound
PlaySound函数功能比较灵活,可以播放系统声音,也可以播放指定音频文件。音频可以是作为资源插在程序中、可以存放在内存中、还可以是本地的音频文件。但是,有一一个缺点就是,使用PlaySound不能同时播放两个或者多个声音,因为PlaySound是独占播放音频文件的。如果使用PlaySound播放新的声音,那么之前使用它播放的声音会立即停止,从而播放新声音。要实现同时播放多个声音,需要使用mciSendString来实现了。
PlaySound函数的声明为:
BOOL PlaySound(LPCSTR pszSound, HMODULE hmod,DWORD fdwSound);
(1).参数pszSound是指定了要播放声音的字符串,该参数可以是WAVE文件的名字,或是WAV资源的名字,或是内存中声音数据的指针,或是在系统注册表WIN.INI中定义的系统事件声音。如果该参数为NULL则停止正在播放的声音。
(2).参数hmod是应用程序的实例句柄,当播放WAV资源时要用到该参数,否则它必须为NULL。参数fdwSound是标志的组合,如下表所示。若成功则函数返回TRUE,否则返回FALSE。
(3).播放标志以及含义:
SND_APPLICATION
用应用程序指定的关联来播放声音。
SND_ALIAS
pszSound参数指定了注册表或WIN.INI中的系统事件的别名。
SND_ALIAS_ID
pszSound参数指定了预定义的声音标识符。
SND_ASYNC
用异步方式播放声音,PlaySound函数在开始播放后立即返回。
SND_FILENAME
pszSound参数指定了WAVE文件名。
SND_LOOP
重复播放声音,必须与SND_ASYNC标志一块使用。
SND_MEMORY
播放载入到内存中的声音,此时pszSound是指向声音数据的指针。
SND_NODEFAULT
不播放缺省声音,若无此标志,则PlaySound在没找到声音时会播放缺省声音。
SND_NOSTOP
PlaySound不打断原来的声音播出并立即返回FALSE。
SND_NOWAIT
如果驱动程序正忙则函数就不播放声音并立即返回。
SND_PURGE
停止所有与调用任务有关的声音。若参数pszSound为NULL,就停止所有的声音,否则,停止pszSound指定的声音。
SND_RESOURCE
pszSound参数是WAVE资源的标识符,这时要用到hmod参数。
SND_SYNC
同步播放声音,在播放完后PlaySound函数才返回。
(4).直接播出声音文件,相应的代码为:
PlaySound("c:\\win95\\media\\The Microsoft Sound.wav", NULL, SND_FILENAME | SND_ASYNC);
(5).用PlaySound播放系统声音,Windows启动的声音是由SystemStart定义的系统声音,因此可以用下面的方法播放启动声音:
PlaySound("SystemStart",NULL,SND_ALIAS|SND_ASYNC);
2.mciSendString
(1).添加头文件
#include <mmsystem. h>
#pragma comment (lib , “winmm.lib”)
头文件顺序错误
windows. h必须在mmsystem. h之前
文件名中有空格
不会报错,但是播放没有声音,应该是因为命令之间是用空格隔开的,所以不符合解析格式,所以没声音。
编译mciSendString报错
undefined reference to mcisendstri ngA@16
原因是#pragma comment(lib, "Winmm.lib)微软自家vC编译器cl.exe专有宏指令,别家的不认。解决方法:自己添加链接
settings->complier->linker settings->add->winmm
(2).打开音乐文件
mciSendString("open D:\\prolltetris\bin\\Debug\\res\\俄罗斯方块游戏背景音乐. mp3 alias a", NULL, 0, NULL);
这里使用的绝对路径,音乐文件路径改变后无法播放,替换成相对路径即可
(3).播放文件
mciSendString(TEXT("play a"), NULL, 0, NULL);
(4).程序结束关闭文件
mciSendString("stop a", NULL, 0, NULL);
本文地址:https://blog.csdn.net/qq_45799098/article/details/107310895
上一篇: about SQL, ORM, DSL