C语言 WIN32窗口实现 俄罗斯方块Tetris 源代码

本文介绍了作者使用C语言在WIN32环境下开发俄罗斯方块游戏的过程,包括游戏的基本功能如开始、暂停、空格键落地等,并提供了完整的源代码。读者可以下载代码在VS2010 WIN32工程下编译运行。
摘要由CSDN通过智能技术生成

      最近有空闲时间,就想编一个俄罗斯方块试试,期间也碰到了一些问题,在网上查找了很多资料。

      现在代码已经完成了,游戏支持开始(包括从暂停恢复和结束后重新开始)、暂停、空格键落地及基本功能,玩起来会更好一些。

     游戏截图


 

      附上全部游戏代码(复制后保存为.c文件,编译即可),windows xp ,VS2010 WIN32工程下,C编译通过:

 

/******************************
软件:Tetris
别名: 俄罗斯方块
作者: su
完成日期: 2012-9-14
遗留问题:
- 画文字超出界面无法显示提示问题
- 局部刷新
- 速度问题因为定时器机制,导致10级之后没明显变化,没达到要求

修改记录:
2014.05.19 Ver: 1.2.2014.519
- 取消列对齐辅助线,仿照俄罗斯方块流行游戏功能,替换为指示当前方块下落位置,动态,更直观。

2013.11.07 Ver: 1.1.2013.1107
- 解决Tetris的位图对象内存泄露问题

2012.10.20 Ver: 1.0.2012.1020
- 检查游戏结束条件不变,(如果变为允许堆积到顶,需要生成新方块时,当前方块已经超出容器顶部,则游戏结束,则需要修改消行,最顶行需要填充为0)

2012.9.29 Ver: 1.0.2012.929
- 增加初速度选择,速度达到50后会反转
- 重新开始游戏会继承上次初速度,关闭程序才会再次出现速度选择界面
- 任何情况下都可以调整初速度,但调整完初速度后会重新开始游戏

2012.9.28 Ver: 1.0.2012.928
- 增加列对齐辅助线
- 使用实心矩形方块(空心,玩久了有些眼花)
- 解决当前下落方块最顶端贴边问题(未出现方块部分不画)
- 调整窗口创建style样式,不支持最大化,最小化,只支持关闭按钮

2012.9.20 Ver: 1.0.2012.920
- memcpy优化复制行
- 消行时一行行进行,有些复杂,继续优化

2012.9.19 Ver: 1.0.2012.919
- 内存越界问题已经解决
- 新增功能,按空格键直接落地
- 解决游戏结束,顶部绘新方块问题
- 新增功能,开始,暂停

2012.9.18 Ver: 1.0.2012.918
- 优化消行,消行只会出现在下落方块的4行里

2012.9.16 Ver: 1.0.2012.916
- 修正游戏首次生成方块。当前方块和下一方块随机数相同问题,
- 采用double buffer绘制游戏屏幕,去掉背景刷,解决重绘背景的区域闪烁问题。
- 显示下一方块。
- 加入消多行分数奖励。
- 增加速度等级,从1-50级。
- 按键Esc直接退出游戏。
- 开始程序时,显示在屏幕中间
- 解决方块刚出现,顶部无法旋转问题
- 解决游戏结束判断延迟问题
- 解决方块快堆满时,新方块碰撞计算失误问题

2012.9.15 Ver: 1.0.2012.915
- 修改随机数种子,避免随机数规律性出现。
- 修改旋转形状数组,为确保底部旋转不会导致方块上升一格,从而继续下降,旋转规则为保持底部水平(变形需要调整,到底后变形可以增高一行继续下落。)
- 优化代码,优化当前方块变量
******************************/
#include <time.h>
#include <windows.h>

/* 方块细胞之间的参数 */
#define CELLS_WIDTH (30)
#define CELLS_DISTANCE (1)

/* 方块的种类 */
#define BLOCK_KINDS (7)
#define BLOCK_ROTATES (4)
#define BLOCK_WIDTH (4) /* 方块边长4 */
#define BLOCK_SIZE (16) /* 方块占用矩阵大小4x4 BLOCK_WIDTH x BLOCK_WIDTH */

/* 消多行分数奖励 */
static const int ScoreSets[BLOCK_WIDTH] = {100, 400, 800, 1600};

/* 容纳方块的空间 逻辑坐标系 从左到右width 从上到下high */
#define CONTAINER_WIDTH (10)
#define CONTAINER_HIGH (20)

/* 容器矩形坐标 */
RECT ContainerRect = {CELLS_DISTANCE, CELLS_DISTANCE,
  CELLS_DISTANCE + CELLS_DISTANCE + CONTAINER_WIDTH * (CELLS_WIDTH + 1) + CELLS_DISTANCE + CELLS_DISTANCE,
  CELLS_DISTANCE + CELLS_DISTANCE + CONTAINER_HIGH * (CELLS_WIDTH + 1) + CELLS_DISTANCE + CELLS_DISTANCE};

/* 下一个方块容器矩形坐标 */
RECT NextBlockRect = {CELLS_DISTANCE + CELLS_DISTANCE + CONTAINER_WIDTH * (CELLS_WIDTH + 1) + CELLS_DISTANCE + CELLS_DISTANCE + CELLS_DISTANCE + CELLS_DISTANCE,
  CELLS_DISTANCE,
  CELLS_DISTANCE + CELLS_DISTANCE + CONTAINER_WIDTH * (CELLS_WIDTH + 1) + CELLS_DISTANCE + CELLS_DISTANCE + CELLS_DISTANCE + CELLS_DISTANCE + CELLS_DISTANCE + BLOCK_WIDTH * (CELLS_WIDTH + 1) + CELLS_DISTANCE + CELLS_DISTANCE,
  CELLS_DISTANCE + CELLS_DISTANCE + BLOCK_WIDTH * (CELLS_WIDTH + 1) + CELLS_DISTANCE + CELLS_DISTANCE};

/* 窗口大小 */
/* 窗口宽度 = 空隙 + 容器左边界 + 方块CONTAINER_WIDTH * (空隙 + CELLS_WIDTH) + 空隙 + 容器右边界 + 空隙 + 下一个容器左边界 + BLOCK_WIDTH * (空隙 + CELLS_WIDTH) + 空隙 + 下一个容器右边界 + 空隙 + 窗口两边占用部分 */
#define WINDOW_WIDTH (CELLS_DISTANCE + CELLS_DISTANCE + CONTAINER_WIDTH * (CELLS_WIDTH + 1) + CELLS_DISTANCE + CELLS_DISTANCE + CELLS_DISTANCE + CELLS_DISTANCE + BLOCK_WIDTH * (CELLS_WIDTH + 1) + CELLS_DISTANCE + CELLS_DISTANCE + CELLS_DISTANCE + 7) /* 7 为窗口边占用 */
/* 窗口高度 = 空隙 + 容器上边界 + 方块CONTAINER_HIGH * (空隙 + CELLS_WIDTH) + 空隙 + 容器下边界 + 空隙 + 窗口上下两边占用部分 */
#define WINDOW_HIGH (CELLS_DISTANCE + CELLS_DISTANCE + CONTAINER_HIGH * (CELLS_WIDTH + 1) + CELLS_DISTANCE + CELLS_DISTANCE + CELLS_DISTANCE + 33) /* 33 为标题栏高度 */

typedef struct Tetris
{
  unsigned int timerid;
  unsigned int GameState; /* 游戏状态,0,游戏运行; 1,游戏开始;2,游戏暂停 */
  unsigned int initalSpeed; /* 初速度 */
  unsigned int speed; /* 速度 */
  unsigned int score; /* 得分 */

  /* 下一个方块 */
  const unsigned char *next_block;
  unsigned int next_kind;
  unsigned int next_rotate;

  /* 当前方块 */
  const unsigned char *current_block;
  unsigned int kind;
  unsigned int rotate;
  int offset_left; /* 逻辑坐标 left, 正常范围 -min_left ~ CONTAINER_WIDTH - max_right */
  int offset_top; /* 逻辑坐标 top, 正常范围 -min_top ~ CONTAINER_HIGH - max_bottom */
  int offset_top_destination; /* 用来表明当前方块直线下落位置 */

  int min_left;
  int max_right;
  int min_top;
  int max_bottom;
} Tetris;

Tetris tetris = {0};

static unsigned char Container[CONTAINER_HIGH][CONTAINER_WIDTH] = {0};
/*   行列式
0 1 2 3 4 5 6 7 8 9 x CONTAINER_WIDTH
00□□□□□□□□□□
01□□□□□□□□□□
02□□□□□□□□□□
03□□□□□□□□□□
04□□□□□□□□□□
05□□□□□□□□□□
06□□□□□□□□□□
07□□□□□□□□□□
08□□□□□□□□□□
09□□□□□□□□□□
10□□□□□□□□□□
11□□□□□□□□□□
12□□□□□□□□□□
13□□□□□□□□□□
14□□□□□□□□□□
15□□□□□□□□□□
16□□□□□□□□□□
17□□□□□□□□□□
18□□□□□□□□□□
19□□□□□□□□□□
y
CONTAINER_HIGH
*/

static const unsigned char BlockSets[BLOCK_KINDS * BLOCK_ROTATES * BLOCK_SIZE] = 
{
  /*
  所有方块的集合(I, J, L, O, S, T, Z),每个方块依次顺时针旋转4次,每个4x4矩阵记录一个形状.
  为确保底部旋转不会导致方块上升一格,从而继续下降,旋转规则为保持底部水平
  ▓
  ▓    ▓   ▓
  ▓    ▓   ▓    ▓▓     ▓▓   ▓▓▓   ▓▓
  ▓  ▓▓   ▓▓  ▓▓   ▓▓       ▓       ▓▓
  */
  /*
  I
  □■□□
  □■□□
  □■□□
  □■□□
  */
  0, 1, 0, 0,
  0, 1, 0, 0,
  0, 1, 0, 0,
  0, 1, 0, 0,

  0, 0, 0, 0,
  0, 0, 0, 0,
  0, 0, 0, 0,
  1, 1, 1, 1,

  0, 1, 0, 0,
  0, 1, 0, 0,
  0, 1, 0, 0,
  0, 1, 0, 0,

  0, 0, 0, 0,
  0, 0, 0, 0,
  0, 0, 0, 0,
  1, 1, 1, 1,
  /*
  J
  □□□□
  □□■□
  □□■□
  □■■□
  */
  0, 0, 0, 0,
  0, 0, 1, 0,
  0, 0, 1, 0,
  0, 1, 1, 0,

  0, 0, 0, 0,
  0, 0, 0, 0,
  0, 1, 0, 0,
  0, 1, 1, 1,

  0, 0, 0, 0,
  0, 1, 1, 0,
  0, 1, 0, 0,
  0, 1, 0, 0,

  0, 0, 0, 0,
  0, 0, 0, 0,
  1, 1, 1, 0,
  0, 0, 1, 0,
  /*
  L
  □□□□
  □■□□
  □■□□
  □■■□
  */
  0, 0, 0, 0,
  0, 1, 0, 0,
  0, 1, 0, 0,
  0, 1, 1, 0,

  0, 0, 0, 0,
  0, 0, 0, 0,
  0, 1, 1, 1,
  0, 1, 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, 0,
  0, 0, 1, 0,
  1, 1, 1, 0,
  /*
  O
  □□□□
  □□□□
  □■■□
  □■■□
  */
  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, 1, 1, 0,
  0, 1, 1, 0,
  /*
  S
  □□□□
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值