这是个俄罗斯方块加速器的游戏代码,报错在清屏和从写的时候,有时候shape刚出来就会报错,给函数加了锁也不行

记住登录一个月发表随想还能输入:200字该用户最新代码编程随想&by by by by by by [c]代码库#include &stdio.h&
#include &string.h&
#include &stdlib.h&
#include &time.h&
#include &conio.h&
#include &windows.h&
#ifdef _MSC_VER
// M$的编译器要给予特殊照顾
#if _MSC_VER &= 1200
// VC6及以下版本
#error 你是不是还在用VC6?!
// VC6以上版本
#if _MSC_VER &= 1600
// 据说VC10及以上版本有stdint.h了
#include &stdint.h&
// VC10以下版本,自己定义int8_t和uint16_t
typedef signed char int8_t;
typedef unsigned short uint16_t;
#ifndef __cplusplus
// 据说VC都没有stdbool.h,不用C++编译,自己定义bool
#define true 1
#define false 0
// 其他的编译器都好说
#include &stdint.h&
#ifndef __cplusplus
// 不用C++编译,需要stdbool.h里的bool
#include &stdbool.h&
// =============================================================================
// 7种方块的4旋转状态(4位为一行)
static const uint16_t gs_uTetrisTable[7][4] = { { 0x00F0U, 0x2222U, 0x00F0U,
0x2222U },
{ 0x0072U, 0x0262U, 0x0270U, 0x0232U },
{ 0x0223U, 0x0074U, 0x0622U, 0x0170U },
{ 0x0226U, 0x0470U, 0x0322U, 0x0071U },
{ 0x0063U, 0x0264U, 0x0063U, 0x0264U },
{ 0x006CU, 0x0462U, 0x006CU, 0x0462U },
{ 0x0660U, 0x0660U, 0x0660U, 0x0660U }
// =============================================================================
// 初始状态的游戏池
// 每个元素表示游戏池的一行,下标大的是游戏池底部
// 两端各置2个1,底部2全置为1,便于进行碰撞检测
// 这样一来游戏池的宽度为12列
// 如果想要传统的10列,只需多填两个1即可(0xE007),当然显示相关部分也要随之改动
// 当某个元素为0xFFFFU时,说明该行已被填满
// 顶部4行用于给方块,不显示出来
// 再除去底部2行,显示出来的游戏池高度为22行
static const uint16_t gs_uInitialTetrisPool[28] = { 0xC003U, 0xC003U, 0xC003U,
0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U,
0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U,
0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xFFFFU,
0xFFFFU };
#define COL_BEGIN 2
#define COL_END 14
#define ROW_BEGIN 4
#define ROW_END 26
// =============================================================================
typedef struct TetrisManager
// 这个结构体存储游戏相关数据
uint16_t pool[28];
// 当前方块x坐标,此处坐标为方块左上角坐标
// 当前方块y坐标
int8_t type[3];
// 当前、下一个和下下一个方块类型
int8_t orientation[3];
// 当前、下一个和下下一个方块旋转状态
unsigned erasedCount[4];
unsigned erasedT
// 消行总数
unsigned tetrisCount[7];
// 各方块数
unsigned tetrisT
// 方块总数
// =============================================================================
typedef struct TetrisControl
// 这个结构体存储控制相关数据
// 旋转方向:顺时针为true
// 移动方向:0向左移动 1向右移动
// 游戏池内每格的颜色
// 由于此版本是彩色的,仅用游戏池数据无法存储颜色信息
// 当然,如果只实现单色版的,就没必要用这个数组了
int8_t color[28][16];
HANDLE g_hConsoleO
// 控制台输出句柄
// =============================================================================
// 函数声明
// 如果使用全局变量方式实现,就没必要传参了
void initGame(TetrisManager *manager, TetrisControl *control);
// 初始化游戏
void restartGame(TetrisManager *manager, TetrisControl *control);
// 重新开始游戏
void giveTetris(TetrisManager *manager);
// 给一个方块
bool checkCollision(const TetrisManager *manager);
// 碰撞检测
void insertTetris(TetrisManager *manager);
// 插入方块
void removeTetris(TetrisManager *manager);
// 移除方块
void horzMoveTetris(TetrisManager *manager, TetrisControl *control);
// 水平移动方块
void moveDownTetris(TetrisManager *manager, TetrisControl *control);
// 向下移动方块
void rotateTetris(TetrisManager *manager, TetrisControl *control);
// 旋转方块
void dropDownTetris(TetrisManager *manager, TetrisControl *control);
// 方块直接落地
bool checkErasing(TetrisManager *manager, TetrisControl *control);
// 消行检测
void keydownControl(TetrisManager *manager, TetrisControl *control, int key); // 键按下
void setPoolColor(const TetrisManager *manager, TetrisControl *control); // 设置颜色
void gotoxyWithFullwidth(short x, short y);
// 以全角定位
void printPoolBorder();
// 显示游戏池边界
void printTetrisPool(const TetrisManager *manager, const TetrisControl *control); // 显示游戏池
void printCurrentTetris(const TetrisManager *manager,
const TetrisControl *control);
// 显示当前方块
void printNextTetris(const TetrisManager *manager);
// 显示下一个和下下一个方块
void printScore(const TetrisManager *manager);
// 显示得分信息
void runGame(TetrisManager *manager, TetrisControl *control);
// 运行游戏
void printPrompting();
// 显示提示信息
bool ifPlayAgain();
// 再来一次
// =============================================================================
// 出处:http://www.oschina.net/code/snippet_22
int main() {
TetrisManager tetrisM
TetrisControl tetrisC
initGame(&tetrisManager, &tetrisControl);
// 初始化游戏
printPrompting();
// 显示提示信息
printPoolBorder();
// 显示游戏池边界
runGame(&tetrisManager, &tetrisControl);
// 运行游戏
if (ifPlayAgain())
// 再来一次
SetConsoleTextAttribute(g_hConsoleOutput, 0x7);
system("cls");
restartGame(&tetrisManager, &tetrisControl);
// 重新开始游戏
} while (1);
gotoxyWithFullwidth(0, 0);
CloseHandle(g_hConsoleOutput);
// =============================================================================
// 初始化游戏
void initGame(TetrisManager *manager, TetrisControl *control) {
CONSOLE_CURSOR_INFO cursorInfo = { 1, FALSE };
// 光标信息
g_hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
// 获取控制台输出句柄
SetConsoleCursorInfo(g_hConsoleOutput, &cursorInfo);
// 设置光标隐藏
SetConsoleTitleA("俄罗斯方块");
restartGame(manager, control);
// =============================================================================
// 重新开始游戏
void restartGame(TetrisManager *manager, TetrisControl *control) {
memset(manager, 0, sizeof(TetrisManager));
// 全部置0
// 初始化游戏池
memcpy(manager-&pool, gs_uInitialTetrisPool, sizeof(uint16_t[28]));
srand((unsigned) time(NULL ));
// 设置随机种子
manager-&type[1] = rand() % 7;
manager-&orientation[1] = rand() & 3;
manager-&type[2] = rand() % 7;
// 下下一个
manager-&orientation[2] = rand() & 3;
memset(control, 0, sizeof(TetrisControl));
// 全部置0
giveTetris(manager);
// 给下一个方块
setPoolColor(manager, control);
// 设置颜色
// =============================================================================
// 给一个方块
void giveTetris(TetrisManager *manager) {
manager-&type[0] = manager-&type[1];
// 下一个方块置为当前
manager-&orientation[0] = manager-&orientation[1];
manager-&type[1] = manager-&type[2];
// 下下一个置方块为下一个
manager-&orientation[1] = manager-&orientation[2];
manager-&type[2] = rand() % 7;
// 随机生成下下一个方块
manager-&orientation[2] = rand() & 3;
tetris = gs_uTetrisTable[manager-&type[0]][manager-&orientation[0]]; // 当前方块
// 设置当前方块y坐标,保证刚给出时只显示方块最下面一行
// 这种实现使得玩家可以以很快的速度将方块落在不显示出来的顶部4行内
if (tetris & 0xF000) {
manager-&y = 0;
manager-&y = (tetris & 0xFF00) ? 1 : 2;
manager-&x = 6;
// 设置当前方块x坐标
if (checkCollision(manager))
// 检测到碰撞
manager-&dead =
// 标记游戏结束
// 未检测到碰撞
insertTetris(manager);
// 将当前方块加入游戏池
++manager-&tetrisT
// 方块总数
++manager-&tetrisCount[manager-&type[0]];
// 相应方块数
printNextTetris(manager);
// 显示下一个方块
printScore(manager);
// 显示得分信息
// =============================================================================
// 碰撞检测
bool checkCollision(const TetrisManager *manager) {
// 当前方块
uint16_t tetris = gs_uTetrisTable[manager-&type[0]][manager-&orientation[0]];
uint16_t dest = 0;
// 获取当前方块在游戏池中的区域:
// 游戏池坐标x y处小方格信息,按低到高存放在16位无符号数中
dest |= (((manager-&pool[manager-&y + 0] && manager-&x) && 0x0) & 0x000F);
dest |= (((manager-&pool[manager-&y + 1] && manager-&x) && 0x4) & 0x00F0);
dest |= (((manager-&pool[manager-&y + 2] && manager-&x) && 0x8) & 0x0F00);
dest |= (((manager-&pool[manager-&y + 3] && manager-&x) && 0xC) & 0xF000);
// 若当前方块与目标区域存在重叠(碰撞),则位与的结果不为0
return ((dest & tetris) != 0);
// =============================================================================
// 插入方块
void insertTetris(TetrisManager *manager) {
// 当前方块
uint16_t tetris = gs_uTetrisTable[manager-&type[0]][manager-&orientation[0]];
// 当前方块每4位取出,位或到游戏池相应位置,即完成插入方块
manager-&pool[manager-&y + 0] |= (((tetris && 0x0) & 0x000F) && manager-&x);
manager-&pool[manager-&y + 1] |= (((tetris && 0x4) & 0x000F) && manager-&x);
manager-&pool[manager-&y + 2] |= (((tetris && 0x8) & 0x000F) && manager-&x);
manager-&pool[manager-&y + 3] |= (((tetris && 0xC) & 0x000F) && manager-&x);
// =============================================================================
// 移除方块
void removeTetris(TetrisManager *manager) {
// 当前方块
uint16_t tetris = gs_uTetrisTable[manager-&type[0]][manager-&orientation[0]];
// 当前方块每4位取出,按位取反后位与到游戏池相应位置,即完成移除方块
manager-&pool[manager-&y + 0] &=
~(((tetris && 0x0) & 0x000F) && manager-&x);
manager-&pool[manager-&y + 1] &=
~(((tetris && 0x4) & 0x000F) && manager-&x);
manager-&pool[manager-&y + 2] &=
~(((tetris && 0x8) & 0x000F) && manager-&x);
manager-&pool[manager-&y + 3] &=
~(((tetris && 0xC) & 0x000F) && manager-&x);
// =============================================================================
// 设置颜色
void setPoolColor(const TetrisManager *manager, TetrisControl *control) {
// 由于显示游戏池时,先要在游戏池里判断某一方格有方块才显示相应方格的颜色
// 这里只作设置即可,没必要清除
// 当移动方块或给一个方块时调用
int8_t i, x,
// 当前方块
uint16_t tetris = gs_uTetrisTable[manager-&type[0]][manager-&orientation[0]];
for (i = 0; i & 16; ++i) {
y = (i && 2) + manager-&y;
// 待设置的列
if (y & ROW_END)
// 超过底部限制
x = (i & 3) + manager-&x;
// 待设置的行
if ((tetris && i) & 1)
// 检测的到小方格属于当前方块区域
control-&color[y][x] = (manager-&type[0] | 8);
// 设置颜色
// =============================================================================
// 旋转方块
void rotateTetris(TetrisManager *manager, TetrisControl *control) {
int8_t ori = manager-&orientation[0];
// 记录原旋转状态
removeTetris(manager);
// 移走当前方块
// 顺/逆时针旋转
manager-&orientation[0] =
(control-&clockwise) ? ((ori + 1) & 3) : ((ori + 3) & 3);
if (checkCollision(manager))
// 检测到碰撞
manager-&orientation[0] =
// 恢复为原旋转状态
insertTetris(manager);
// 放入当前方块。由于状态没改变,不需要设置颜色
insertTetris(manager);
// 放入当前方块
setPoolColor(manager, control);
// 设置颜色
printCurrentTetris(manager, control);
// 显示当前方块
// =============================================================================
// 水平移动方块
void horzMoveTetris(TetrisManager *manager, TetrisControl *control) {
int x = manager-&x;
// 记录原列位置
removeTetris(manager);
// 移走当前方块
control-&direction == 0 ? (--manager-&x) : (++manager-&x);
// 左/右移动
if (checkCollision(manager))
// 检测到碰撞
manager-&x =
// 恢复为原列位置
insertTetris(manager);
// 放入当前方块。由于位置没改变,不需要设置颜色
insertTetris(manager);
// 放入当前方块
setPoolColor(manager, control);
// 设置颜色
printCurrentTetris(manager, control);
// 显示当前方块
// =============================================================================
// 向下移动方块
void moveDownTetris(TetrisManager *manager, TetrisControl *control) {
int8_t y = manager-&y;
// 记录原行位置
removeTetris(manager);
// 移走当前方块
++manager-&y;
// 向下移动
if (checkCollision(manager))
// 检测到碰撞
manager-&y =
// 恢复为原行位置
insertTetris(manager);
// 放入当前方块。由于位置没改变,不需要设置颜色
if (checkErasing(manager, control))
// 检测到消行
printTetrisPool(manager, control);
// 显示游戏池
insertTetris(manager);
// 放入当前方块
setPoolColor(manager, control);
// 设置颜色
printCurrentTetris(manager, control);
// 显示当前方块
// =============================================================================
// 方块直接落地
void dropDownTetris(TetrisManager *manager, TetrisControl *control) {
removeTetris(manager);
// 移走当前方块
for (; manager-&y & ROW_END; ++manager-&y)
// 从上往下
if (checkCollision(manager))
// 检测到碰撞
--manager-&y;
// 上移一格当然没有碰撞
insertTetris(manager);
// 放入当前方块
setPoolColor(manager, control);
// 设置颜色
checkErasing(manager, control);
// 检测消行
printTetrisPool(manager, control);
// 显示游戏池
// =============================================================================
// 消行检测
bool checkErasing(TetrisManager *manager, TetrisControl *control) {
static const unsigned scores[5] = { 0, 10, 30, 90, 150 };
// 消行得分
int8_t count = 0;
int8_t k = 0, y = manager-&y + 3;
// 从下往上检测
if (y & ROW_END && manager-&pool[y] == 0xFFFFU)
// 有效区域内且一行已填满
// 消除一行方块
memmove(manager-&pool + 1, manager-&pool, sizeof(uint16_t) * y);
// 颜色数组的元素随之移动
memmove(control-&color[1], control-&color[0],
sizeof(int8_t[16]) * y);
} while (y &= manager-&y && k & 4);
manager-&erasedTotal +=
// 消行总数
manager-&score += scores[count];
if (count & 0) {
++manager-&erasedCount[count - 1];
giveTetris(manager);
// 给下一个方块
setPoolColor(manager, control);
// 设置颜色
return (count & 0);
// =============================================================================
void keydownControl(TetrisManager *manager, TetrisControl *control, int key) {
if (key == 13)
// 暂停/解除暂停
control-&pause = !control-&
if (control-&pause)
// 暂停状态,不作处理
switch (key) {
control-&clockwise =
// 顺时针旋转
rotateTetris(manager, control);
// 旋转方块
control-&direction = 0;
// 向左移动
horzMoveTetris(manager, control);
// 水平移动方块
control-&direction = 1;
// 向右移动
horzMoveTetris(manager, control);
// 水平移动方块
moveDownTetris(manager, control);
// 向下移动方块
// 直接落地
dropDownTetris(manager, control);
control-&clockwise =
// 逆时针旋转
rotateTetris(manager, control);
// 旋转方块
// =============================================================================
// 以全角定位
void gotoxyWithFullwidth(short x, short y) {
static COORD
cd.X = (short) (x && 1);
SetConsoleCursorPosition(g_hConsoleOutput, cd);
// =============================================================================
// 显示游戏池边界
void printPoolBorder() {
SetConsoleTextAttribute(g_hConsoleOutput, 0xF0);
for (y = ROW_BEGIN; y & ROW_END; ++y)
// 不显示顶部4行和底部2行
gotoxyWithFullwidth(10, y - 3);
printf("%2s", "");
gotoxyWithFullwidth(23, y - 3);
printf("%2s", "");
gotoxyWithFullwidth(10, y - 3);
// 底部边界
printf("%28s", "");
// 定位到游戏池中的方格
#define gotoxyInPool(x, y) gotoxyWithFullwidth(x + 9, y - 3)
// =============================================================================
// 显示游戏池
void printTetrisPool(const TetrisManager *manager, const TetrisControl *control) {
for (y = ROW_BEGIN; y & ROW_END; ++y)
// 不显示顶部4行和底部2行
gotoxyInPool(2, y);
// 定点到游戏池中的方格
for (x = COL_BEGIN; x & COL_END; ++x)
// 不显示左右边界
if ((manager-&pool[y] && x) & 1)
// 游戏池该方格有方块
// 用相应颜色,显示一个实心方块
SetConsoleTextAttribute(g_hConsoleOutput, control-&color[y][x]);
printf("■");
// 没有方块,显示空白
SetConsoleTextAttribute(g_hConsoleOutput, 0);
printf("%2s", "");
// =============================================================================
// 显示当前方块
void printCurrentTetris(const TetrisManager *manager,
const TetrisControl *control) {
// 显示当前方块是在移动后调用的,为擦去移动前的方块,需要扩展显示区域
// 由于不可能向上移动,故不需要向下扩展
y = (manager-&y & ROW_BEGIN) ? (manager-&y - 1) : ROW_BEGIN;
// 向上扩展一格
for (; y & ROW_END && y & manager-&y + 4; ++y) {
x = (manager-&x & COL_BEGIN) ? (manager-&x - 1) : COL_BEGIN;
// 向左扩展一格
for (; x & COL_END && x & manager-&x + 5; ++x)
// 向右扩展一格
gotoxyInPool(x, y);
// 定点到游戏池中的方格
if ((manager-&pool[y] && x) & 1)
// 游戏池该方格有方块
// 用相应颜色,显示一个实心方块
SetConsoleTextAttribute(g_hConsoleOutput, control-&color[y][x]);
printf("■");
// 没有方块,显示空白
SetConsoleTextAttribute(g_hConsoleOutput, 0);
printf("%2s", "");
// =============================================================================
// 显示下一个和下下一个方块
void printNextTetris(const TetrisManager *manager) {
SetConsoleTextAttribute(g_hConsoleOutput, 0xF);
gotoxyWithFullwidth(26, 1);
printf("┏━━━━┳━━━━┓");
gotoxyWithFullwidth(26, 2);
printf("┃%8s┃%8s┃", "", "");
gotoxyWithFullwidth(26, 3);
printf("┃%8s┃%8s┃", "", "");
gotoxyWithFullwidth(26, 4);
printf("┃%8s┃%8s┃", "", "");
gotoxyWithFullwidth(26, 5);
printf("┃%8s┃%8s┃", "", "");
gotoxyWithFullwidth(26, 6);
printf("┗━━━━┻━━━━┛");
// 下一个,用相应颜色显示
tetris = gs_uTetrisTable[manager-&type[1]][manager-&orientation[1]];
SetConsoleTextAttribute(g_hConsoleOutput, manager-&type[1] | 8);
for (i = 0; i & 16; ++i) {
gotoxyWithFullwidth((i & 3) + 27, (i && 2) + 2);
((tetris && i) & 1) ? printf("■") : printf("%2s", "");
// 下下一个,不显示彩色
tetris = gs_uTetrisTable[manager-&type[2]][manager-&orientation[2]];
SetConsoleTextAttribute(g_hConsoleOutput, 8);
for (i = 0; i & 16; ++i) {
gotoxyWithFullwidth((i & 3) + 32, (i && 2) + 2);
((tetris && i) & 1) ? printf("■") : printf("%2s", "");
// =============================================================================
// 显示得分信息
void printScore(const TetrisManager *manager) {
static const char *tetrisName = "ITLJZSO";
SetConsoleTextAttribute(g_hConsoleOutput, 0xE);
gotoxyWithFullwidth(2, 2);
printf("■得分:%u", manager-&score);
gotoxyWithFullwidth(1, 6);
printf("■消行总数:%u", manager-&erasedTotal);
for (i = 0; i & 4; ++i) {
gotoxyWithFullwidth(2, 8 + i);
printf("□消%d:%u", i + 1, manager-&erasedCount[i]);
gotoxyWithFullwidth(1, 15);
printf("■方块总数:%u", manager-&tetrisTotal);
for (i = 0; i & 7; ++i) {
gotoxyWithFullwidth(2, 17 + i);
printf("□%c形:%u", tetrisName[i], manager-&tetrisCount[i]);
// =============================================================================
// 显示提示信息
void printPrompting() {
SetConsoleTextAttribute(g_hConsoleOutput, 0xB);
gotoxyWithFullwidth(26, 10);
printf("■控制:");
gotoxyWithFullwidth(27, 12);
printf("□向左移动:← A 4");
gotoxyWithFullwidth(27, 13);
printf("□向右移动:→ D 6");
gotoxyWithFullwidth(27, 14);
printf("□向下移动:↓ S 2");
gotoxyWithFullwidth(27, 15);
printf("□顺时针转:↑ W 8");
gotoxyWithFullwidth(27, 16);
printf("□逆时针转:0");
gotoxyWithFullwidth(27, 17);
printf("□直接落地:空格");
gotoxyWithFullwidth(27, 18);
printf("□暂停游戏:回车");
gotoxyWithFullwidth(25, 23);
printf("■By: wohaaitinciu 12.12.29");
// =============================================================================
// 运行游戏
void runGame(TetrisManager *manager, TetrisControl *control) {
clock_t clockLast, clockN
clockLast = clock();
printTetrisPool(manager, control);
// 显示游戏池
while (!manager-&dead)
while (_kbhit())
// 有键按下
keydownControl(manager, control, _getch());
// 处理按键
if (!control-&pause)
clockNow = clock();
// 两次记时的间隔超过0.45秒
if (clockNow - clockLast & 0.45F * CLOCKS_PER_SEC ) {
clockLast = clockN
keydownControl(manager, control, 80);
// 方块往下移
// =============================================================================
// 再来一次
bool ifPlayAgain() {
SetConsoleTextAttribute(g_hConsoleOutput, 0xF0);
gotoxyWithFullwidth(15, 10);
printf("游戏结束");
gotoxyWithFullwidth(13, 11);
printf("按Y重玩,按N退出");
ch = _getch();
if (ch == 'Y' || ch == 'y') {
} else if (ch == 'N' || ch == 'n') {
} while (1);
[代码运行效果截图]分享到:更多共3 条评论
发表评论:评论须知:1、评论每次加2分,每天上限为30;2、请文明用语,共同创建干净的技术交流环境;3、若被发现提交非法信息,评论将会被删除,并且给予扣分处理,严重者给予封号处理;4、请勿发布广告信息或其他无关评论,否则将会删除评论并扣分,严重者给予封号处理。最简单,最基本的俄罗斯方块C程序~~_百度知道
最简单,最基本的俄罗斯方块C程序~~
最好能帮我加一点注释,谢谢了~~~~
提问者采纳
其他类似问题
俄罗斯方块的相关知识
按默认排序
其他3条回答
/************************************************/面向对象课程设计:俄罗斯方块游戏修改版 制作人: 李梦松 时间:2007-5 单位: 湖工工程技术学院 工学系
软件(一)班 /************************************************/#include&graphics.h& #include &stdio.h& #include &stdlib.h& #include &conio.h& #include &dos.h& #include &bios.h& #include &time.h& //常数定义区 #define UNIT 28 #define ROWS 16 #define COLUMNS 12 //枚举定义区 enum Boolean{false,true}; //全局变量
int speed=9;
int hard=9;
int numrow=0;
B //对象定义区 //Location对象:Location是所有图形的基类 class Location { protected:
//所有图形的基本单位长度。 public: int x,y;
//在容器中的逻辑坐标 int left, //在屏幕中的物理坐标
Location(int x,int y,int left,int top,int unit,int color); }; Location::Location(int x,int y,int left,int top,int unit,int color) { this-&x=x; this-&y=y; this-&left= this-&top= this-&unit= this-&color= } //Brick对象:Brick是一个长方形的图形对象,由它可以组成俄罗斯方块所需要的各种形状。 class Brick:public Location { public: Brick(int x,int y,int left,int top,int unit,int color); void show(); void hide(); }; Brick::Brick(int x,int y,int left,int top,int unit,int color):Location(x,y,left,top,unit,color) {} void Brick::show()
//显示Brick {
tempColor=getcolor(); setfillstyle(1,color);
bar(left+1,top+1,left+unit-1,top+unit-1);
setfillstyle(0,color); setcolor(tempColor); } void Brick::hide() //隐藏Brick {
tempColor=getcolor(); setfillstyle(1,getbkcolor());
bar(left+1,top+1,left+unit-1,top+unit-1); setfillstyle(0,getbkcolor());
setcolor(tempColor); } //Figure对象:在Figure中有一个n*n的矩阵,在相应的位置上放置Brick对象就可以形成组合图形。 //每一种Figure图形由4个Brick对象组成。 class Figure:public Location { protected: //shape取值0~6,分别代表7种不同的图形。 public: //state共有0,1,2,3四个值,分别表示图形的四种摆放角度。 int map[4][4][2];//map的下标依次表示:4个状态(state),4个Brick,x和y坐标 Brick *p_bk[4]; //表示组成Figure的4个Brick
Figure(int x,int y,int left,int top,int unit,int color,int shape,int state); ~Figure(); void setBricks(); void show(); void hide(); }; Figure::Figure(int x,int y,int left,int top,int unit,int color,int shape,int state):Location(x,y,left,top,unit,color) { this-&shape= this-&state= //要想增加更多图形,只需扩充Brick的数目和相应的map的矩阵值。 if(this-&shape==0)
//长条形 {
map[0][0][0]=0;map[0][0][1]=1;
map[0][1][0]=1;map[0][1][1]=1;
map[0][2][0]=2;map[0][2][1]=1;
map[0][3][0]=3;map[0][3][1]=1;
map[1][0][0]=1;map[1][0][1]=0;
map[1][1][0]=1;map[1][1][1]=1;
map[1][2][0]=1;map[1][2][1]=2;
map[1][3][0]=1;map[1][3][1]=3;
map[2][0][0]=0;map[2][0][1]=1;
map[2][1][0]=1;map[2][1][1]=1;
map[2][2][0]=2;map[2][2][1]=1;
map[2][3][0]=3;map[2][3][1]=1;
map[3][0][0]=1;map[3][0][1]=0;
map[3][1][0]=1;map[3][1][1]=1;
map[3][2][0]=1;map[3][2][1]=2;
map[3][3][0]=1;map[3][3][1]=3;
} else if(shape==1) //正方形... {
map[0][0][0]=0;map[0][0][1]=0;
map[0][1][0]=1;map[0][1][1]=0;
map[0][2][0]=0;map[0][2][1]=1;
map[0][3][0]=1;map[0][3][1]=1;
map[1][0][0]=0;map[1][0][1]=0;
map[1][1][0]=1;map[1][1][1]=0;
map[1][2][0]=0;map[1][2][1]=1;
map[1][3][0]=1;map[1][3][1]=1;
map[2][0][0]=0;map[2][0][1]=0;
map[2][1][0]=1;map[2][1][1]=0;
map[2][2][0]=0;map[2][2][1]=1;
map[2][3][0]=1;map[2][3][1]=1;
map[3][0][0]=0;map[3][0][1]=0;
map[3][1][0]=1;map[3][1][1]=0;
map[3][2][0]=0;map[3][2][1]=1;
map[3][3][0]=1;map[3][3][1]=1;
} else if(shape==2) //T字形... {
map[0][0][0]=0;map[0][0][1]=1;
map[0][1][0]=1;map[0][1][1]=1;
map[0][2][0]=2;map[0][2][1]=1;
map[0][3][0]=1;map[0][3][1]=2;
map[1][0][0]=1;map[1][0][1]=0;
map[1][1][0]=0;map[1][1][1]=1;
map[1][2][0]=1;map[1][2][1]=1;
map[1][3][0]=1;map[1][3][1]=2;
map[2][0][0]=1;map[2][0][1]=0;
map[2][1][0]=0;map[2][1][1]=1;
map[2][2][0]=1;map[2][2][1]=1;
map[2][3][0]=2;map[2][3][1]=1;
map[3][0][0]=1;map[3][0][1]=0;
map[3][1][0]=1;map[3][1][1]=1;
map[3][2][0]=2;map[3][2][1]=1;
map[3][3][0]=1;map[3][3][1]=2;
} else if(shape==3) //正Z形... {
map[0][0][0]=0;map[0][0][1]=0;
map[0][1][0]=1;map[0][1][1]=0;
map[0][2][0]=1;map[0][2][1]=1;
map[0][3][0]=2;map[0][3][1]=1;
map[1][0][0]=1;map[1][0][1]=0;
map[1][1][0]=0;map[1][1][1]=1;
map[1][2][0]=1;map[1][2][1]=1;
map[1][3][0]=0;map[1][3][1]=2;
map[2][0][0]=0;map[2][0][1]=0;
map[2][1][0]=1;map[2][1][1]=0;
map[2][2][0]=1;map[2][2][1]=1;
map[2][3][0]=2;map[2][3][1]=1;
map[3][0][0]=1;map[3][0][1]=0;
map[3][1][0]=0;map[3][1][1]=1;
map[3][2][0]=1;map[3][2][1]=1;
map[3][3][0]=0;map[3][3][1]=2;
} else if(shape==4) //反Z形... {
map[0][0][0]=1;map[0][0][1]=0;
map[0][1][0]=2;map[0][1][1]=0;
map[0][2][0]=0;map[0][2][1]=1;
map[0][3][0]=1;map[0][3][1]=1;
map[1][0][0]=0;map[1][0][1]=0;
map[1][1][0]=0;map[1][1][1]=1;
map[1][2][0]=1;map[1][2][1]=1;
map[1][3][0]=1;map[1][3][1]=2;
map[2][0][0]=1;map[2][0][1]=0;
map[2][1][0]=2;map[2][1][1]=0;
map[2][2][0]=0;map[2][2][1]=1;
map[2][3][0]=1;map[2][3][1]=1;
map[3][0][0]=0;map[3][0][1]=0;
map[3][1][0]=0;map[3][1][1]=1;
map[3][2][0]=1;map[3][2][1]=1;
map[3][3][0]=1;map[3][3][1]=2;
} else if(shape==5) //正L形... {
map[0][0][0]=1;map[0][0][1]=0;
map[0][1][0]=1;map[0][1][1]=1;
map[0][2][0]=1;map[0][2][1]=2;
map[0][3][0]=2;map[0][3][1]=2;
map[1][0][0]=0;map[1][0][1]=1;
map[1][1][0]=1;map[1][1][1]=1;
map[1][2][0]=2;map[1][2][1]=1;
map[1][3][0]=0;map[1][3][1]=2;
map[2][0][0]=0;map[2][0][1]=0;
map[2][1][0]=1;map[2][1][1]=0;
map[2][2][0]=1;map[2][2][1]=1;
map[2][3][0]=1;map[2][3][1]=2;
map[3][0][0]=2;map[3][0][1]=0;
map[3][1][0]=0;map[3][1][1]=1;
map[3][2][0]=1;map[3][2][1]=1;
map[3][3][0]=2;map[3][3][1]=1;
} else if(shape==6) //反L形... {
map[0][0][0]=1;map[0][0][1]=0;
map[0][1][0]=1;map[0][1][1]=1;
map[0][2][0]=0;map[0][2][1]=2;
map[0][3][0]=1;map[0][3][1]=2;
map[1][0][0]=0;map[1][0][1]=0;
map[1][1][0]=0;map[1][1][1]=1;
map[1][2][0]=1;map[1][2][1]=1;
map[1][3][0]=2;map[1][3][1]=1;
map[2][0][0]=1;map[2][0][1]=0;
map[2][1][0]=2;map[2][1][1]=0;
map[2][2][0]=1;map[2][2][1]=1;
map[2][3][0]=1;map[2][3][1]=2;
map[3][0][0]=0;map[3][0][1]=1;
map[3][1][0]=1;map[3][1][1]=1;
map[3][2][0]=2;map[3][2][1]=1;
map[3][3][0]=2;map[3][3][1]=2;
} int bk_x,bk_y,bk_left,bk_ for(int i=0;i&4;i++) {
bk_x=map[state][i][0];
bk_y=map[state][i][1];
bk_left=left+bk_x*
bk_top=top+bk_y*
p_bk[i]=new Brick(bk_x,bk_y,bk_left,bk_top,unit,color); } } Figure::~Figure() { delete(p_bk[0]); delete(p_bk[1]); delete(p_bk[2]); delete(p_bk[3]); } void Figure::setBricks()//设置Brick的位置 {
for(i=0;i&4;i++) {
p_bk[i]-&x=map[state][i][0];
p_bk[i]-&y=map[state][i][1];
p_bk[i]-&left=left+(p_bk[i]-&x)*
p_bk[i]-&top=top+(p_bk[i]-&y)*
} } void Figure::show() //显示Figure {
for(int i=0;i&4;i++)
if (p_bk[i]-&top&5)
p_bk[i]-&hide();
//如果超过容器顶部则把Brick隐藏
else p_bk[i]-&show();
} } void Figure::hide()//隐藏Figure {
for(int i=0;i&4;i++)
p_bk[i]-&hide(); } //GameBox对象:GameBox所有组合图形的容器 class GameBox:public Location { protected:
int flag[50][50]; int colors[50][50]; public: Figure * p_ GameBox(int x,int y,int left,int top,int unit,int color,int rows,int columns); ~GameBox(); void setFigure(int x,int y,int color,int shape,int state); void show();
void hardBrick(); //以下的几个函数我曾经放到Figure里定义,但发现在这里定义更合理更简单。 Boolean canLeft(); void moveLeft(); Boolean canRight(); void moveRight(); void canDown(); void moveDown(); Boolean canRotate(); void rotate(); void delFigure();
void Over() ; void hideRow(int rowNum); void showRow(int rowNum); void downRow(int rowNum); void fresh(); void clear(); }; GameBox::GameBox(int x,int y,int left,int top,int unit,int color,int rows,int columns):Location(x,y,left,top,unit,color) { this-&rows= this-&columns= p_fg=NULL; int i,j; for(i=0;i&i++)
for(j=0;j&j++)
flag[j][i]=0;
colors[j][i]=0;
} } GameBox::~GameBox() { if(p_fg!=NULL) delete(p_fg); } void GameBox::setFigure(int x,int y,int color,int shape,int state) //在GameBox中构造新的Figure {
int fg_left,fg_ fg_left=left+x* fg_top=top+y*unit-1; //此处TOP修改为TOP-1更合理,不然会挡住边框 p_fg=new Figure(x,y,fg_left,fg_top,unit,color,shape,state); p_fg-&setBricks(); } void GameBox::show()//显示一个GameBox {
tempColor=getcolor();
setcolor(color);
rectangle(left-1,top-1,left+columns*unit+1,top+rows*unit+1);
setcolor(tempColor); if(p_fg!=NULL)
p_fg-&show(); } Boolean GameBox::canLeft() {
Boolean can= int gb_x,gb_y; for(i=0;i&4;i++) {
gb_x=p_fg-&x+p_fg-&p_bk[i]-&x-1;
gb_y=p_fg-&y+p_fg-&p_bk[i]-&y;
if(gb_x&0)
else if(flag[gb_x][gb_y]&0)
} } return(can); } void GameBox::moveLeft() { p_fg-&hide(); p_fg-&x=p_fg-&x-1; p_fg-&left=p_fg-&left- p_fg-&setBricks(); p_fg-&show(); } Boolean GameBox::canRight() {
Boolean can= int gb_x,gb_y; for(i=0;i&4;i++) {
gb_x=p_fg-&x+p_fg-&p_bk[i]-&x+1;
gb_y=p_fg-&y+p_fg-&p_bk[i]-&y;
if(gb_x&columns-1)
else if(flag[gb_x][gb_y]&0)
} } return(can); } void GameBox::moveRight() { p_fg-&hide(); p_fg-&x=p_fg-&x+1; p_fg-&left=p_fg-&left+ p_fg-&setBricks(); p_fg-&show(); } void GameBox::canDown() {
int gb_x,gb_y; for(i=0;i&4;i++) {
gb_x=p_fg-&x+p_fg-&p_bk[i]-&x;
gb_y=p_fg-&y+p_fg-&p_bk[i]-&y+1;
if(gb_y&rows-1)
else if(flag[gb_x][gb_y]&0)
else candown= } } void GameBox::moveDown()
//下落采用的是隐藏(hide)当前位置的Figure,在下方显示(show)同样的Figure {
p_fg-&hide(); p_fg-&y=p_fg-&y+1; p_fg-&top=p_fg-&top+ p_fg-&setBricks(); p_fg-&show(); } Boolean GameBox::canRotate() {
Boolean can= int gb_x,gb_y; int nextS nextState=(p_fg-&state+1)%4; for(i=0;i&4;i++) {
gb_x=p_fg-&map[nextState][i][0]+p_fg-&x;
gb_y=p_fg-&map[nextState][i][1]+p_fg-&y;
if(gb_x&0||gb_x&columns-1||gb_y&rows-1)
else if(flag[gb_x][gb_y]&0)
} } return(can); } void GameBox::rotate()//变形 { p_fg-&hide(); p_fg-&state=(p_fg-&state+1)%4; p_fg-&setBricks(); p_fg-&show(); } void GameBox::delFigure()
//Figure落下时,释放对该Figure的控制 { int gb_l,gb_t; int i,gb_x,gb_y; for(i=0;i&4;i++) {
gb_x=p_fg-&x+p_fg-&p_bk[i]-&x;
gb_y=p_fg-&y+p_fg-&p_bk[i]-&y;
flag[gb_x][gb_y]=1;
colors[gb_x][gb_y]=p_fg-& } delete(p_fg); p_fg=NULL; } /**********************************难度设计(pretty lee)************************************************/ void GameBox::clear() //清屏 { for(int k=0;k&k++)
hideRow(k); } void GameBox::hardBrick()//难度函数 {
int tempColor,
tempColor=getcolor();
for (int i=1;i&=9-i++)
for (int j=1;j&=columns-6;j++)
int n=random(12);
color=random(15)+1;
flag[n][ROWS-i]=1;
colors[n][ROWS-i]=
setfillstyle(1,color);
bar(left+n*unit+1,top+(rows-i)*unit,left+(n+1)*unit-1,top+(rows-i+1)*unit-2);
setfillstyle(0,color);
setcolor(tempColor); }
/**********************************************************************************************/ void GameBox::hideRow(int rowNum) {
tempColor=getcolor(); for(int i=0;i&i++) {
if(flag[i][rowNum]&0)
setfillstyle(1,getbkcolor());
bar(left+i*unit+1,top+rowNum*unit,left+(i+1)*unit-1,top+(rowNum+1)*unit-2);
flag[i][rowNum]=0;
colors[i][rowNum]=0;
setfillstyle(0,getbkcolor());
setcolor(tempColor);
} void GameBox::showRow(int rowNum) {
tempColor=getcolor(); for(int i=0;i&i++) {
if(flag[i][rowNum]&0)
setfillstyle(1,colors[i][rowNum]);
bar(left+i*unit+1,top+rowNum*unit,left+(i+1)*unit-1,top+(rowNum+1)*unit-2);
setfillstyle(0,colors[i][rowNum]);
setcolor(tempColor); } void GameBox::downRow(int rowNum) {
for(int i=0;i&i++) {
flag[i][rowNum+1]=flag[i][rowNum];
colors[i][rowNum+1]=colors[i][rowNum]; } showRow(rowNum+1); hideRow(rowNum); } void GameBox::fresh() //消除满行
int i,j,k,flagSum,ni=0; for(i=rows-1;i&0;i--) {
flagSum=0;
for(j=0;j&j++)
flagSum=flagSum+flag[j][i];
if(flagSum&=columns)
//如果一排满了则消行
for(k=i;k&0;k--)
hideRow(k);
downRow(k-1);
//计算得分
if ((numrow-ni)%100&numrow%100)
//当numrow+ni后,如果没满100,那么必有(numrow-ni)%100&numrow%100
if (speed&=1)
if (hard&=1)
hardBrick();
hard=hard-1;
hardBrick();
else speed=speed-1;
gotoxy(5, 5);
printf(&scores: %d\r&,numrow*10);
gotoxy(5,8);
printf(&speed : %d\r&,10-speed);
gotoxy(5,11);
printf(&hard
: %d\r&,10-hard);
while(flagSum&=columns); } } void GameBox::Over() {
int i,gb_x,gb_y;
for(i=0;i&4;i++) {
gb_x=p_fg-&x+p_fg-&p_bk[i]-&x;
gb_y=p_fg-&y+p_fg-&p_bk[i]-&y;
flag[gb_x][gb_y]=1;
colors[gb_x][gb_y]=p_fg-&
for(j=0;j&j++) {
if (flag[j][0]&0 && flag[j][0]&0 && candown==false)
else over=
} int getKey()
//系统自带函数bioskey(0)能达到几乎相同的功能 {
union REGS inReg,outR
int key_l;
inReg.h.ah = 0;
int86(22, &inReg, &outReg);
key_l=outReg.h.
return(key_l); } //函数指针,用来保存原来时间中断函数的句柄。 void interrupt far (*OldIntHandler)(...); //新的时间中断函数,最多1秒18次。 int ticker=0; int timeCyc= B void far interrupt TimeInt(...) //如何让中断程序带参数? { ticker=(ticker+1)%timeC if(ticker==0 && onTime==false)
void main() {
/*********************************欢迎界面(pretty lee)*********************************************/ char p1,p2;
int pp1,pp2; candown= over= textbackground(WHITE);
gotoxy(30,8);
textbackground(BLUE);
//将标题移到标题位置,然后输出标题
cprintf(&Welcome to the GAME WORLD\r\n&);
gotoxy(40,12);
textbackground(BLACK);
textcolor(WHITE);
cprintf(&the speed is\r\n&);
gotoxy(53,12);
textcolor(BLACK);
textbackground(WHITE);
cprintf(&%d\r\n&,10-speed);
gotoxy(40,15);
textbackground(BLACK);
textcolor(WHITE);
cprintf(&the hard
is\r\n&);
gotoxy(53,15);
textbackground(BLACK);
textcolor(WHITE);
cprintf(&%d\r\n&,10-hard);
gotoxy(51,20);
textbackground(BLACK);
textcolor(WHITE);
cprintf(&producer is pretty lee\r\n&); /*调节速度*/ re1: gotoxy(53,12);
textcolor(BLACK);
textbackground(WHITE);
p1=getch();
if (p1=='H' && speed&9)
speed=speed+1;
cprintf(&%d\r\n&,10-speed);
else if(p1=='P' && speed&1)
speed=speed-1;
cprintf(&%d\r\n&,10-speed);
else if(pp1!=13) goto re1;
textbackground(BLACK);
textcolor(WHITE);
cprintf(&%d\r\n&,10-speed);
} /*****************/ /*调节难度*/ re2: gotoxy(53,15);//获得光标时背景变白色
textcolor(BLACK);
textbackground(WHITE);
cprintf(&%d\r\n&,10-hard);
gotoxy(53,15);//重新定输出位置
p2=getch();
if (p2=='H' && hard&9)
hard=hard+1;
cprintf(&%d\r\n&,10-hard);
else if(p2=='P' && hard&1)
hard=hard-1;
cprintf(&%d\r\n&,10-hard);
else if(pp2!=13) goto re2; /*****************/ /******************************************************************************************/
int graphdriver = DETECT,
//初始化图形系统 initgraph(&graphdriver,&graphmode,&d:\\tc3\\bgi&); int key,nextnum1,nextnum2,nextnum3; srand((unsigned)time(NULL));
timeCyc= OldIntHandler=getvect(0x1c); disable(); setvect(0x1c,TimeInt); //中断矢量入口,相当如TIMER控件 enable(); clearviewport (); /*****************************得分,速度,难度,预测下一个
四功能(pretty lee)*******************************************/
gotoxy(5,5);
printf(&scores: 0\n&);
gotoxy(5,8);
printf(&speed : %d\n&,10-speed);
gotoxy(5,11);
printf(&hard
: %d\n&,10-hard);
GameBox gb(0,0,180,10,UNIT,getcolor(),ROWS,COLUMNS),nextgb(0,0,30,220,UNIT,getcolor(),4,4);
gb.show();
nextgb.show();
gb.hardBrick();
gb.p_fg=NULL;
nextnum1=random(15)+1;
nextnum2=random(7);
nextnum3=random(4);
nextgb.setFigure(0,0,
nextnum3); //预测下一个Figure
nextgb.p_fg-&show();
/*************************************************************************************************/
while(true) {
if(gb.p_fg==NULL)
gb.setFigure(5,-2,nextnum1,nextnum2,nextnum3);
gb.p_fg-&show();
nextnum1=random(15)+1;
nextnum2=random(7);
nextnum3=random(4) ;
nextgb.p_fg-&hide();
delete(nextgb.p_fg); //此处要释放nextgb.p_fg,不然会出现BUG
nextgb.setFigure(0,0,
nextnum3);
nextgb.p_fg-&show();
if(bioskey(1))
//kbhit()和bioskey(1)都是瞬间取值函数,有同样的效果。
key=getKey(); //系统自带函数bioskey(0)能达到几乎相同的功能
if(key==0x1c)
暂停(继续游戏)
onTime=~onT
stop: key=getKey();
if(key==0x1c) onTime=~onT
else if(key==0x01 ){
onTime=~onT }
else if(key==0x01 )//ESC
esc:delete(gb.p_fg);
gb.p_fg=NULL;
clearviewport ();
closegraph ();//关闭图形系统
else if(key==0x4b )//LEFT
if(gb.canLeft())
gb.moveLeft();
else if(key==0x4d)//RIGHT
if(gb.canRight())
gb.moveRight();
else if(key==0x50 )//DOWN
{ gb.canDown();
if(candown==true)
gb.moveDown();
else if(key==0x48)//UP
if(gb.canRotate())
gb.rotate();
if(onTime==true)
gb.canDown();
if(candown==true)
gb.moveDown();
gb.Over();
if (over==false)
gb.delFigure();
gb.fresh();
gotoxy(40,12);
printf(&GAME OVER!&);
disable(); setvect(0x1c, OldIntHandler); enable();
closegraph(); } 由于代码太长一个号发不完,这是我的小号发的请把分加给不爱到爱那个号上.以上代码是我自己写的,绝对可用我的QQ空间里也有这代码
前 言 visual basic继承了basic语言易学易用的特点,特别适合于初学者学习windows系统编程。随着21世纪信息社会的到来,计算机在人们的工作和生活中的深入,要求我们越来越多地与计算机打交道,为了使用户在繁忙的日程工作中得到放松,于是出现了各种各样的休闲软件,如聊天工具,游戏等等。于是我们小组着手设计开始一个这样的游戏软件。通过这学期来Visual Basic的学习,我初步掌握了Visual Basic语言的最基本的知识,于是在牛荣和李鹏等老师的指导下动手用Visual Basic编写俄罗斯方块游戏。 我们之所以选择开发俄罗斯方块游戏,无可争议,《俄罗斯方块》是有史以来最伟大的游戏之一。 在曾经发布过的所有游戏中,《俄罗斯方块》还被认为是仅有的一个能够真正吸引广泛人群的作品。谁能说清楚,迄今为止人们究竟花了多少万个小时在这个游戏上?也许这些时间本来可以被花在更具生产力的活动上。某些批评家也许会声称,《俄罗斯方块》要比过去二十年间出现的任何东西都要浪费人们的时间。至于我们,则要欣然提名它为GameSpot评选出的历史上最伟大游戏之一。 为了怀念经典,也为了能够给大多的计算机用户在工作之余找到一个休闲、娱乐的一个方式,我们小组开始着手用VB语言开发一个经典的俄罗斯方块游戏。 工程概况 2.1 项目名称 俄罗斯方块游戏 2.2 设计平台 VB 全称Visual Basic,它是以Basic语言作为其基本语言的一种可视化编程工具。 Vb是microsoft公司于1991年退出的windows应用程序开发工具visual意思是“可视化的”。在它刚推出来时,自身还存在一些缺陷,功能也相对少一些。但是经过多年的开发研究。最近microsoft公司又推出了VB6.0版本 VB6.0运行环境:硬件,要求486以上的处理器、16MB以上内存,50MB 以上的硬盘,cd-rom驱动器,鼠标。软件:要求windows 95以上版本。 2.3程序设计思想 游戏是用来给大家娱乐的,所以要能在使用的过程中给大家带来快乐,消除大家的疲劳,所以我们在游戏中添加了漂亮的场景和动听的音乐,设置了过关升级的功能,激发大家的娱乐激情。 从游戏的基本玩法出发,主要就是俄罗斯方块的形状和旋转,我们在设计中在一个图片框中构造了一个4*4的网状小块,由这些小块组合成新的形状,每四个小块连接在一起就可以构造出一种造型,因此我们总共设计了7中造型,每种造型又可以通过旋转而变化出2到4种形状,利用随机函数在一个欲览窗体中提前展示形状供用户参考,然后将展示的形状复制到游戏窗体中进行摆放,在游戏窗体中用户就可以使用键盘的方向键来控制方块的运动,然后利用递归语句对每一行进行判断,如果有某行的方块是满的,则消除这行的方块,并且使上面的方块自由下落,其中,方块向下的速度是有时钟控件控制的,在游戏中,用户也可以使用向下键加快下落速度,定义一个变量,对消除的函数进行记录,最后就可以得出用户的分数,用if 语句对分数判断,达到一定的积分就可以升级到下一个档次。 俄罗斯方块游戏设计的主要步骤为以下10个方面: (1)游戏界面的设计。 (2)俄罗斯方块的造型。 (3)俄罗斯方块的旋转。 (4)俄罗斯方块的运动情况(包括向左,向右和向下)。 (5)俄罗斯方块的自动消行功能。 (6)游戏级别的自由选择。 (7)游戏速度的自由选择。 (8)游戏得分的计算。 (9)游戏菜单选项的设计及功能实现。 (10)游戏的背景音乐及特效。 2.4运用的控件和主要对象 我们在设计过程中主要用到的控件有:command控件,image控件,picture控件,label控件,timer控件,text控件,windows media player控件等等。 2.5主要实现的功能 我们开发的俄罗斯方块游戏,主要实现了以下几种功能: 1.可以灵活控制方块在图形框中运动。 2.游戏过程中方块可以自由旋转。 3.当某一行的方块排列满时,将自动将这一行方块消除,然后将上面所有方块向下移动,可以支持连续消行。 4.游戏前可以选择游戏的速度和游戏的等级,游戏速度既为方块下落速度,游戏等级为初始游戏时在基层随机生成一定行数的无规律方块,生成的行数由你来选择,每行至少产生5个以上的无规律方块,这样增加了游戏难度,对于游戏高手来说,无疑不是一个新的挑战。 5.游戏的得分支持积分,并且按照公式: 得分 = 原来分数+ 100 * (2 ^ 同时消除的行数-1) 这样,你同一时间消除的行数越多,你的得分也就越高,当游戏积分到了一定时可以自动升级,这个升级指速度升级。 6.游戏中提供了一个漂亮的场景和动听的音乐,给你带来无限激情。 2.6开发人员 由于这次课程设计所选的题目太复杂,而时间又比较紧张,指导老师建议和同学分工完成。我们小组成员包括组长孙磊周,副组长邹海星,此游戏由我们两个人共同开发而成。 正文 3.1游戏设计的具体实现 在我们两个人共同努力下,此次设计,终于能够圆满完成。由于时间的紧促,在设计中,也许会有一些考虑不周之处,但其功能已经能够满足大多用户的需求,相信假以时日,一定能做出一个更经典,更完美的俄罗斯方块游戏,下面我们将对每一步的具体如何实现展示给大家。 3.1.1游戏界面的设计和背景音乐及特效的实现 俄罗斯方块游戏主要由两个界面构成,登陆界面和开始游戏界面,在登陆界面中我们可以首先看到圣诞节的晚上飘梅花的场景,梅花从窗体顶部做函数曲线的下落运动,在窗体中定义一个Image控件组,在通用中定义梅花X坐标变量动态数组,Y坐标变量动态数组,步距X的变量动态数组,步距Y的变量动态数组,以及振幅变量动态数组。然后在窗体form_load中可以定义梅花的数量,利用随机函数产生随机的梅花坐标,步距和振幅,Image控件在运行时候就调用梅花图片,Image控件就可以由时钟控件控制下落速度,可以自由调节,梅花按snow(i).Left = xp(i) + am(i) * Sin(dx(i))函数在做纵向的正玄函数轨迹运动,竖直方向上为自由下落运动,,有am(i)来控制梅花的左右移动振幅。因此,我们就可以看到一个梅花在空中自由飘舞的画面了。 背景画面是用photoshop软件处理的漂亮图案,原本画面中的动画效果都是由Image控件制作的,还有点击进入游戏的按钮是由Label控件实现的,因为Image控件没有置前置后功能,不能将下雪的场景体现完整性,所以将这些图案全部放在背景上,不影响雪花飘落的效果,当点击画面的时候一样可以进入游戏界面。 游戏的背景音乐是由一段代码调用系统播放器Windows Player播放背景音乐,由于本次设计主要是针对游戏如何设计的,所以在这里就不对播放背景音乐的功能做介绍了。 3.1.2俄罗斯方块的造型 相信朋友们都玩过俄罗斯方块,对这个游戏的玩法和方块形状都比较熟悉。我们这个游戏只选择了最基本的7中造型,包括长条型,正方型,正S型,反S型,正7型,反7型,T型。如果需要我们可以添加更多的造型。将游戏界面的游戏区图片框分割成10*20的小块,每个小块放置一个command控件,预览区图片框按同样比例分割成4*4的小块,同样有command控件构成,我们可以把预览区图片框看作是从游戏区图片框中选取的一个部分,游戏区的小方块编号和欲览区编号如下图: 0 1 2 3 4 5 6 7 8 9 … … … … … … … … … … … … … … … … … … … … 90 91 92 93 94 95 96 97 98 99 3 4 5 6 13 14 15 16 23 24 25 26 33 34 35 36 游戏区编号 欲览区编号 利用Select将方块的7中造型列出,比如长条型的设计,在欲览区中分别有3.4.5.6和5.15.25.35四个方块构成两中形态,用数组为: m(0) = 3: m(1) = 4: m(2) = 5: m(3) = 6: situation2 = 0 m(0) = 5: m(1) = 15: m(2) = 25: m(3) = 35: situation2 = 1 将它的形状编号为0和1,在后面方便调用,其他的方块造型同样的方法。 3.1.3俄罗斯方块的旋转 俄罗斯方块的旋转主要将方块的位置加以变换得到的,例如上述范例,长条型有两中样式,根据小方块的编号变动来实现整个造型的旋转,比如: If n(0) - 18 &= 2 And n(3) + 9 &= 198 Then If cmdfang(n(0) - 18).Visible = False And _ cmdfang(n(1) - 9).Visible = False And _ cmdfang(n(3) + 9).Visible = False Then hidefang 0 n(0) = n(0) - 18 n(1) = n(1) - 9 n(3) = n(3) + 9 showfang 0 situation = 1 End If End If 方块的造型在旋转的时候存在一个公式,当然首先要判断是否满足旋转的要求,以上是一个长条型由横着变成竖立状态的旋转,我们以它的造型中的第三个小方块n(3)为中心旋转,这样,在开始运动的时候,长条形要发生旋转最少要运动到第三行,才能由横着变成竖立状态,游戏区图形框中第三行的第一个方块的编号为20,所以长条造型的第一个小方块的编号n(0)必须要大于20。同样,长条型方块在下落到底部的时候也有限制。如果长条下落到最后一行也将无法由横着变成竖立状态。 3.1.4如何实现方块的运动和自动消除满行的方块 我们的这个俄罗斯方块游戏主要是利用command控件的visible属性完成效果的,其实在游戏区图形框可以看成是由许多的command小方块组成,方块运动的过程就是造型里方块显示或者隐藏,就像现在的霓虹灯效果一样,由时钟控件控制visible属性改变的速度,上一层的消失,下一层的显示,这样,从视觉效果可以看到方块的下落运动效果。 方块在下落的过程中会自动判断每一行方块的visible属性,如果全部为true时,就会将这一行小方块的visible属性全部变成false,在将上面的小方块向下移动,利用for语句进行循环判断,将所有这样情况的行改变小方块visible属性。当有多行同时出现这样情况时使用递归调用,实现连续消行。具体程序代码如下: For i = 190 To 10 Step -10 If cmdfang(i).Visible = True And _ cmdfang(i + 1).Visible = True And _ cmdfang(i + 2).Visible = True And _ cmdfang(i + 3).Visible = True And _ cmdfang(i + 4).Visible = True And _ cmdfang(i + 5).Visible = True And _ cmdfang(i + 6).Visible = True And _ cmdfang(i + 7).Visible = True And _ cmdfang(i + 8).Visible = True And _ cmdfang(i + 9).Visible = True Then For j = i + 4 To i Step -1 t = 1 cmdfang(j).Visible = False cmdfang(2 * i + 9 - j).Visible = False For k = 1 To 4000 DoEvents Next t = 0 Next linenum = linenum + 1 For j = i - 1 To 0 Step -1 If cmdfang(j).Visible = True Then cmdfang(j).Visible = False cmdfang(j + 10).Visible = True End If Next clearline '为了实现连消数行,这里使用递归调用 End If Next 3.1.5游戏速度和游戏级别自由选择 游戏速度的自由选择无非就是改变时钟控件的频率,我们在菜单中添加了选择速度的功能,还有添加了考验功能,将欲览窗中的方块造型隐藏,给玩家提高了难度,如果你不愿意接受考验也可以点击显示还原成原来状态。 游戏级别的自由选择是让用户选择游戏开始时候,游戏区底部出现一定行数的随机方块,同样给玩家增加了难度,功能代码如下: For i = 19 To 20 - Val(txthard.Text) Step -1 For j = i * 10 To i * 10 + 9 If Rnd &= 0.5 Then cmdfang(j).Visible = True Next Next 可以根据你选择的难度系数在底层的每一行随机产生超过半数(即5个以上)以上的小方块,这样适合喜欢高难度的玩家。 3.1.6游戏得分的计算和游戏菜单的编辑 游戏得分的计算主要是根据消除的行数来决定的,当然每一次同时消除的行数不一样,每一行的得分也不一样,如果你每次消除的行数为1,则最后得分是100分,如果同时消除2行,则最后得分是300分,同时消除3行,得分为700分,同时消除4行,得分为1500分,这由公式:得分 = 原来分数+ 100 * (2 ^ 同时消除的行数-1)。 游戏的编辑,读者可以参照下面的功能介绍。 3.2 游戏功能的介绍 文件-------开始:开始游戏。 继续:继续游戏。 暂停:暂时停止游戏,点击继续的时候可以继续游戏。 退出:退出游戏。 设置-------选择游戏级别。 选择游戏速度。 考验-------显示:显示欲览去方块。 隐藏:隐藏欲览去方块。 帮助-------操作提示以及版本信息和作者资料。 用户界面具体如图: 图—登陆界面 图—游戏界面 图—菜单编辑界面 图—游戏帮助界面 有关说明 经过两个多星期的设计和开发,俄罗斯方块游戏已经成功。其功能基本符合用户需求,能够完成游戏的控制,方块的变换以及消层等功能。并提供游戏设置,对于一些技术性比较过硬的玩家,可以调游戏级别、以及游戏速度,使得玩家能够充分的发挥竞技游戏的特色,可以不断的挑战自我,挑战极限。 4.1游戏设计中的不足之处 但是由于课程设计时间较短,所以该游戏还有许多不尽如人意的地方,比如方块类型太少,退出游戏不能存储进度等多方面问题。这些都有待进一步改善,我们在游戏中还可以更换背景音乐,以适合不同的玩家,在每通过一关可以给玩家播放一段flash,吸引玩家去挑战极限,不断提高玩家的兴趣,相信在以后的制作过程中我们将给大家带来一个更新功能更全面的游戏。 4.2VB与C语言之间的不同之处 我们这个小游戏也可以用C语言来实现,在程序的编程上没有VB语言方便实用,C语言和VB语言之间存在很多的共同点,虽然语法方面有点差异,但是在编程思路上完全一样,VB能够实现很多C#不能做到的功能,如When语句、Optional参数、局部Static变量、对象实例访问静态方法、Handles绑定事件、On Error处理异常、Object直接后期绑定等等。VB和C#语言,编译出来的是同样的CIL,但为什么VB支持很多有趣的特性呢。我们一起来探究一下。 4.21局部静态变量 VB支持用Static关键字声明局部变量,这样在过程结束的时候可以保持变量的数值: Public Sub Test1() Static i As Integer i += 1 '实现一个过程调用计数器 End Sub 我们实现了一个简单的过程计数器。每调用一次Test,计数器的数值就增加1。其实还有很多情况我们希望保持变量的数值。而C#的static是不能用在过程内部的。因此要实现过程计数器,我们必须声明一个类级别的变量。这样做明显不如VB好。因为无法防止其他过程修改计数器变量。这就和对象封装一个道理,本来应该是一个方法的局部变量,现在我要被迫把它独立出来,显然是不好的设计。那么VB是怎么生成局部静态变量的呢?将上述代码返汇编,我们可以清楚地看到在VB生成的CIL中,i不是作为局部变量,而是作为类的Field出现的: .field private specialname int32 $STATIC$Test1$2001$i 也就是说,i被改名作为一个类的字段,但被冠以specialname。在代码中试图访问$STATIC$Test1$2001$i是不可能的,因为它不是一个有效的标识符。但是在IL中,将这个变量加一的代码却与一般的类字段完全一样,是通过ldfld加载的。我觉得这个方法十分聪明,把静态变量变成生命周期一样的类字段,但是又由编译器来控制访问的权限,让它成为一个局部变量。同时也解释了VB为什么要用两个不同的关键字来声明静态变量——Static和Shared。由于局部静态变量的实质是类的字段,所以它和真正的局部变量还是有所不同的。比如在多线程条件下,对局部静态变量的访问就和访问字段相同。 4.2.2Handles和WithEvents VB除了可以用C#那样的方法来处理事件响应以外,还有从VB5继承下来的独特的事件处理方式——WithEvents。 我喜欢称这种事件处理方式为静态的事件处理,书写响应事件的方法时就已经决定该方法响应的是哪一个事件,而C#则是在代码中绑定事件的。VB中WithEvents静态方法是非常有用的,它可以显著增强代码可读性,同时也让VB.net中的事件处理非常方便,不像C#那样离开了窗体设计器就必须手工绑定事件。 4.2.3类型转换运算符 在Visual Basic 2005中将加入一个新的运算符——TryCast,相当于C#的as运算符。我一直希望VB有这样一个运算符。VB目前的类型转换运算符主要有CType和DirectCast。他们的用法几乎一样。我详细比较了一下这两个运算符,得出以下结论: 1.在转换成引用类型时,两者没有什么区别,都是直接调用castclass指令,除非重载了类型转换运算符CType。DirectCast运算符是不能重载的。 2.转换成值类型时,CType会调用VB指定的类型转换函数(如果有的话),比如将String转换为Int32时,就会自动调用。 4.2.4默认属性和属性参数 在原先的VB6里,有一项奇特的功能——默认属性。在VB6中,对象的名称可以直接表示该对象的默认属性。 4.2.5可选参数和按名传递 VB从4.0开始支持“可选参数”这一特性。就是说,函数或子程序的参数有些是可选的,调用的时候可以不输入。其实VB从1.0开始就有一些函数带有可选参数,只不过到了4.0才让用户自己开发这样的过程。在VB4里,可选参数可以不带默认值,而在VB里,如果使用可选参数,则必须带有默认值。在调用的时候,VB若发现参数被省略,则自动读取.param部分的默认值,并显式传递给过程。这一部分完全由编译器处理,而且没有任何性能损失,和手工传递所有参数是完全一样的。至于按名传递,VB会自动调整参数的顺序,其结果与传统方式的传递也没有任何的不同。这说明我们可以放心地使用这项便利。而且带有可选参数的过程拿到C#中,顶多变成不可选参数,也不会造成什么其他的麻烦。 PS.很多COM组件都使用了默认参数,而且有些过程的参数列表非常长,在VB里可以轻松地处理它们,而在C#中经常让开发者传参数传到吐血。 4.2.6在经过对比之后可得以下一个结论: 1.目前的主流编程语言没有简单的,如果你想学精通的话。 2.VB的门槛比较低,编程思想较容易接受。 3.学习C不能短期内见到成效。 4.据用户调查69%的考生觉得VB更容易接受 致谢 在本次课程设计中,我从指导老师牛荣和李鹏身上学到了很多东西。老师认真负责的工作态度,严谨的治学精神和深厚的理论水平都使我收益匪浅。他无论在理论上还是在实践中,都给与我很大的帮助,使我得到不少的提高这对于我以后的工作和学习都有一种巨大的帮助,感谢他耐心的辅导。 另外,在游戏开发过程中化希耀老师和杜义君老师也给于我们很大的帮助,帮助解决了不少的难点,使得游戏能及时开发完成,还有所有的同学同样给与我不少帮助,这里一并表示感。 参考文献: [1]Vsual Basic 程序设计教程 作者:龚沛曾,陆慰民,杨志强 高等教育出版社出版 [2]Vsual Basic 6.0程序设计 作者:刘新民,蔡琼,白糠生 清华大学出版社出版 [3]80例上手 VB6 编程 作者:唐凯军,汤惠莉 山东电子音像出版社 [4]Vsual Basic 实例教程 作者:卢毅 科学出版社出版 [5]Vsual Basic 经典范例50讲 作者:赵欣胜,亢慧娟,刘晟宏 科学出版社出版
您可能关注的推广
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁

我要回帖

更多关于 俄罗斯方块下载 的文章

 

随机推荐