(100分)策划 俄罗斯方块 完整的游戏过程 (可以的话还加50分,谢谢)

设计一个新的“俄罗斯方块”单机游戏。请策划一个完整的游戏过程,包括:
1.策划的总体思路和产品卖点(简洁表达);
2.游戏界面总结构、流程;
3.每个界面的安排(不需要美工实现,有框架结构即可);
4.用户交互和基本效果设计,越详细越好;
5.积分或者其他成就体系的设计;
6.可以增加你认为可以提高产品能力的附加设计

可将答案发送到邮箱:[email protected]

  网上下载的CSDN里面的代码^^^
  分享…………
  我用TC调试成功了
  因为头文件里有<graphics.h> 所以不能在VC中运行
  #include <stdio.h>
  #include <stdlib.h>
  #include <bios.h> /*这里须要读取系统运行时间来作为定时器*/
  #include <graphics.h> /*很不幸,TC2的简单图形,让我放弃了用*/
  #include <conio.h> /*win32+openGL来讲解.*/

  #define MAX_X 14 /*可见最大X*/
  #define MAX_Y 21 /*可见最大Y*/
  /*我们定义了最大的可见X和Y,那么即还有不
  可见的部分,事实上地图(大盒子)里的左右
  两侧和底部各两行都被1填充,这样大大简化
  出界的判断,事实上,在本例中没有这样的
  代码,因为旁边有一圈1阻止小盒子越出大
  盒子的按制范围
  */
  #define MAX_C 7 /*最大种类,这个无须解释*/

  #define KEY_UP 'w' /*定义上下左右按按键*/
  #define KEY_DOWN 's'
  #define KEY_LEFT 'a'
  #define KEY_RIGHT 'd'
  #define KEY_ESC 27 /*退出*/

  typedef int BOOL;
  #define FALSE 0
  #define TRUE 1 /*这几个TC中没有...自己定义一下吧:)*/

  /*时钟结构*/
  typedef struct { /*时钟结构*/
  BOOL enabled; /*时钟是否开启*/
  unsigned int intervel; /*定时间隔*/
  unsigned int lasttime; /*这个属于内部使用变量*/
  } Timer;

  /*
  *现在进入了编程的初质阶段
  *在开始处我会写出所有的函数原形,以及它们的作用
  *main函数在程序的最后,你可以在这里看到整个游戏的组织架构
  *很好,它只有几十行,并且非常容易理解,当然,还是先看一下函数原形
  *及解释
  */
  /******************************************************\
  * 函数原形及说明 *
  \******************************************************/
  /*以下三个函数可以参照Timer结构体.在函数声明后面*/

  int GetTickCount(); /*返回电脑或操作系统运行逝去的时间*/
  /*在win32环境下已包含在windows.h里边,返回的是4byte*/
  /*在DOS(本代码)环境下,要自己编写,使用到BIOS.h内容*/
  int setTimer(Timer *t, unsigned int intv, BOOL en);
  /*设置时钟t,参数分别为时钟指针,时间间隔,是否活动*/
  /*时间间隔,win32下为毫秒,DOS下为1/18秒(有点低)*/
  BOOL testTimer(Timer *t); /*测试时钟t是否到达定时时间*/
  /*如下面这段代码:*/
  /*
  setTimer(&t, 1, 1); 设置1个单位的间隔
  while(1) {
  if(testTimer(&t)) printf("Active!\n");
  }
  将会定时(1个单位)在屏幕上打印Active!
  一般来说testTimer必须放在循环中反复执行,激活时返回1
  */
  void render(void); /*唯一的绘图函数*/
  /*注意,此函数重画整个地图,根据地图中的点阵,以及根据
  小盒在地图的中坐标在恰当位置画出小盒子*/
  /*DOS的图形当然是很低的,但,全屏绘图在这里还是过得去
  的,我用的是双缓冲,交换绘图,这样感觉好点*/
  void initMap(void); /*初始化地图(大盒子)*/
  /*之前提到过在这个两维数组中有一圈为1的东西来阻止
  小盒子出界,这就是生成这一圈的函数*/
  void newGame(); /*新建一个游戏*/
  /*这个函数初始化一几个时钟和建造第一个下落的小盒子*/
  /*当然建造完后要生成一个个的预览*/

  void rotateBox(int box1[5][5], int box2[5][5]);
  /*核心函数成员,把box1逆时针旋转90度,并保存到box2中*/
  void rebuidNext();
  /*核心函数成员,生成下一个方块*/
  int drop();
  /*核心函数成员,将下落的盒子向下移(实际上增加下落盒
  子的Y值而已,当然要判断是否与地图点阵重叠*/
  /*与地图重叠,无法完成下落操作,返回0*/
  void putBox();
  /*在这之上,下落的盒子与地图之前是独立的两个两维数*/
  /*当下落失败后,小盒子要回到顶端再次重新执行下落,这*/
  /*时原来的盒子内容当然就要变成地图上的内容了,putBox
  就是将下落盒子的内容根据XY写到地图上*/
  void clear();
  /*这个函数在下落失败并putBox后执行,扫描整个地图*/
  /*清除掉满行的点阵,具体细节在函数内讲*/
  int move(int dir);
  /*左右移动下落盒子,dir指出向左还是向右,这个与drop
  是一样的*/
  int test(int mx, int my, int box[5][5]);
  /*这个比较重点,判断box在mx,my为坐标上,与地图上的
  非空点阵是否有重叠.很通用的一个函数*/
  int rotate();
  /*旋转下落的盒子,当然如果转了之后与地图有冲突,会
  取消转动,返回0,但返回的值好像没什么用~*/
  int newfall();
  /*创建下落元素,把"下一个"预览的内容复制到下落盒子*/
  /*并将下落的盒子移动到地图顶部,当然这个过程,如果顶
  部有冲突,会返回0,这时说明已经满了...gameOver*/

  /******************************************************\
  * 变量区 *
  \******************************************************/

  /*在上面的说明中,可能会有一些蒙,因为可能对所用到的实际变量没
  *有了解
  */
  int map[MAX_Y+4][MAX_X+4]; /*地图\大盒子...MAX_X,Y是可见面积*/
  /*我已说过需要在外面布两圈"卫兵"*/
  int curbox[5][5]; /*当前下落的盒子*/
  int curx, cury; /*保存着当前活动盒子在地图上的位置*/
  int nextbox[5][5]; /*保存着下一个形状的盒子*/

  /*以上就是这么几个盒子和坐标了*/

  /*这里列出了标准七种俄罗斯方块图形点阵,用到时它们会被复制到相*/
  /*应的盒子...:)*/
  int box[MAX_C][5][5] = { /*MAX_C(7)种预定义的盒子*/
  {
  {0,0,0,0,0},
  {0,0,0,0,0},
  {1,1,1,1,0},
  {0,0,0,0,0},
  {0,0,0,0,0}
  },

  {
  {0,0,0,0,0},
  {0,0,1,0,0},
  {0,1,1,1,0},
  {0,0,0,0,0},
  {0,0,0,0,0}
  },

  {
  {0,0,0,0,0},
  {0,1,1,0,0},
  {0,0,1,1,0},
  {0,0,0,0,0},
  {0,0,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,0,0}
  },

  {
  {0,0,0,0,0},
  {0,1,1,0,0},
  {0,0,1,0,0},
  {0,0,1,0,0},
  {0,0,0,0,0}
  },

  {
  {0,0,0,0,0},
  {0,0,1,1,0},
  {0,0,1,0,0},
  {0,0,1,0,0},
  {0,0,0,0,0}
  },

  {
  {0,0,0,0,0},
  {0,0,1,1,0},
  {0,0,1,1,0},
  {0,0,0,0,0},
  {0,0,0,0,0}
  }
  };

  /******************************************************\
  * 时钟 *
  \******************************************************/
  /*时钟部分也非常理解的,一个用到设置时钟,一个用来测试时钟激活态*/

  Timer tDown; /*正常下落定时时钟intervel会比较大*/
  Timer tFast; /*按KEY_DOWN时使用的快速下落*/
  int speed = 13; /*控制下落时间间隔*/
  #define FAST_INTV 1 /*快时钟的间隔*/

  /******************************************************\
  * 时钟 *
  \******************************************************/
  /*时钟部分也非常理解的,一个用到设置时钟,一个用来测试时钟激活态*/

  Timer tDown; /*正常下落定时时钟intervel会比较大*/
  Timer tFast; /*按KEY_DOWN时使用的快速下落*/

  #define FAST_INTV 1 /*快时钟的间隔*/

  int GetTickCount() { /*读取BIOS时钟*/
  int ret;
  ret = peek(0x0,0x46e); /*实际上读取了内存0:046e处的内容*/
  ret <<= 8; /*这个地方是$%#$^$%&^*/
  ret += peek(0x0,0x46c); /*太多新的东西了,找点书看一看吧*/
  return (ret);
  }

  int setTimer(Timer *t, unsigned int intv, BOOL en) {
  t -> enabled = en; /*设置一个时钟罗*/
  t -> intervel = intv;
  t -> lasttime = GetTickCount(); /*lasttime记录的是上一个*/
  /*tickcount返回的东西*/
  /*这样当再一次测试时间时新的tickcount产生了
  它来减去上一次的tickcount就得出了一个时间
  间隔,这个就可以和intervel比较从而得出是否
  激活了
  */
  return 0;
  }

  BOOL testTimer(Timer *t) { /*在上面6行的地方解释了:)*/
  unsigned int tmp, dt;
  if (!(t -> enabled)) return FALSE;
  tmp = GetTickCount();
  dt = tmp - (t -> lasttime);
  if(dt >= t -> intervel) {
  t -> lasttime = tmp;
  return TRUE;
  }
  return FALSE;
  }

  /******************************************************\
  * 渲染部分 *
  \******************************************************/
  /*提供render更新整个屏幕*/
  /*关于这个函数,要说的东西还是比较多,为了追求漂亮和编译*/
  /*时的灵活性,这个函数被写得颇为冗长...*/

  /*现在写一下本游戏图形的东西...使用TC2的Graphics我也不
  太乐意,毕竟它本身已过时,但鉴于实在简单实用,它用来教学
  再合适不过,这也是教学总是用TC的原因,老师们不喜欢让学
  生问一些让他们掌握起来也困难的东西...*/
  /*这里我使用了VGAMED模式,而不是 VGAHI,因为VGAMED有两个
  页(可以想像成缓冲),这样可以用来做到不闪动画.即:在后台
  页绘制图形,完成后再显示出来.
  这里用到了两个函数:
  setactivepage(1 | 0) 参数只能是1或0,选择绘图页,例如选
  择了1后,以后所有的绘图动作将画到页1上.
  setvisualpage(1 | 0) 这个叫做选择可见页,即选择在屏幕上
  显示页面1还是0
  */

  void render(void) {
  int x, y;
  static int cPage = 0; /*当前页,换页用*/

  #define STARTX 50 /*定义几个常量*/
  #define STARTY 0
  #define LEN 18

  setactivepage(cPage=(cPage == 0?1:0)); /*选择页*/
  cleardevice(); /*清屏*/
  setcolor(15);
  rectangle( STARTX + LEN * 2 - 2,
  STARTY + LEN * 3 - 2,
  STARTX + LEN * (MAX_X - 2) + 2,
  STARTY + LEN * (MAX_Y - 2) + 2);
  /*用白色画一个外框*/
  setfillstyle(SOLID_FILL, 5);
  for(y = 3; y < MAX_Y - 2; y++) { /*画地图 */
  for(x = 2; x < MAX_X - 2; x++) {
  if(map[y][x]) {
  rectangle( x * LEN + STARTX,
  y * LEN + STARTY,
  x * LEN + STARTX + LEN,
  y * LEN + STARTY + LEN);
  bar( x * LEN + STARTX + 1,
  y * LEN + STARTY + 1,
  x * LEN + STARTX + LEN - 2,
  y * LEN + STARTY + LEN - 2);
  }
  }
  }

  /*绘图操作就不要作太复杂的介绍了,这只写作用*/
  /*以上段,根据地图上的点阵情况将地图反映到屏幕上*/

  for(y = 0; y < 5; y++) { /*画下落物*/
  for(x = 0; x < 5; x++) {
  if(curbox[y][x]) {
  if(y + cury > 2) {
  rectangle( (x + curx) * LEN + STARTX,
  (y + cury) * LEN + STARTY,
  (x + curx) * LEN + STARTX + LEN,
  (y + cury) * LEN + STARTY + LEN);
  bar( (x + curx) * LEN + STARTX + 1,
  (y + cury) * LEN + STARTY + 1,
  (x + curx) * LEN + STARTX + LEN - 2,
  (y + cury) * LEN + STARTY + LEN - 2);
  }
  }
  }
  }

  /*以上将下落的盒子按昭它在地图上的坐标,画到对应的区域里*/
  for(y = 0; y < 5; y++) { /*画下一个*/
  for(x = 0; x < 5; x++) {
  if(nextbox[y][x]) {
  rectangle( x * LEN + 320,
  y * LEN + 10,
  x * LEN + 338,
  y * LEN + 28);
  bar( x * LEN + 321,
  y * LEN + 11,
  x * LEN + 336,
  y * LEN + 26);
  }
  }
  }

  /*这个画出下一个盒子的预览*/
  setvisualpage(cPage); /*确认在cPage页里画好了*/
  /*将它显示出来*/
  }

  /******************************************************\
  * 初始化部分 *
  \******************************************************/
  /*提供newGame()初始化新游戏*/

  void initMap(void) { /*初始化地图*/
  int x, y; /*我们须要一圈卫兵...*/
  for(y = 0; y < MAX_Y; y++) {
  for(x = 0; x < MAX_X; x++) {
  if(x < 2 || x > MAX_X - 3 || y > MAX_Y - 3)
  map[y][x] = 1;
  else map[y][x] = 0;
  }
  } /*这里初始化出这个形状*/
  } /*当然是无盖的...*/

  void newGame() { /*新建游戏*/
  int x, y;
  initMap(); /*初始化地图*/
  srand(GetTickCount()); /*初始化随机发生器*/
  rebuidNext(); /*建立下一个*/
  setTimer(&tDown, speed, 1); /*启动时钟(快慢两个)*/
  setTimer(&tFast, FAST_INTV, 1);
  newfall(); /*对下落的盒子操作一下*/
  /*这样第一个下落的方块
  就在地图顶部准备好了*/
  }

  /******************************************************\
  * 核心函数 *
  \******************************************************/

  void rotateBox(int box1[5][5], int box2[5][5]) {
  /*旋转box1输出到box2*/
  int x, y;
  for(x = 0; x < 5; x++) /*这个函数可以须要实际*/
  for(y = 4; y >= 0; y--) /*编写一下才能印像深刻*/
  box2[y][x] = box1[x][4 - y];
  }

  void rebuidNext() { /*新建下一个形状并放到nextbox中*/
  int i, x, y;
  i = random(MAX_C); /*从几种方块里面选一种*/
  for(y = 0; y < 5; y++) /*并复制过来*/
  for(x = 0; x < 5; x++)
  nextbox[y][x] = box[i][y][x]; /*复制*/
  }

  int drop() { /*下落,返回成功与否*/
  int newy; /*盒子要下落的新位置*/
  newy = cury + 1; /*为当前Y位置+1*/
  if(test(curx, newy, curbox)) {
  cury = newy; /*测试下落盒在这个位置*/
  return 1; /*上是否有冲突,没有的话*/
  } /*直接设置cury*/
  return 0;
  }

  void putBox() { /*将curbox填充到地图上*/
  int x, y;
  for(y = 0; y < 5; y++) /*这个也简单,主要是要根*/
  for(x = 0; x < 5; x++) /*据curx,cury指出位置 */
  if(curbox[y][x])
  map[y + cury][x + curx] = curbox[y][x];
  }

  void clear() { /*清除掉满行*/
  /*这个函数实际上效率也很低的,为了简便
  它从头到尾作了测试*/
  /*具体的算法为:
  从第0行开始到最后一行,测试地图点阵是否为满,如果是的话
  从当前行算起,之上的地图向下掉一行*/
  int x, y;
  int dx, dy;
  int fullflag;
  for(y = 0; y < MAX_Y - 2; y++) { /*最后两行保留行*/
  fullflag = 1; /*假设为满*/
  for(x = 2; x < MAX_X - 2; x++) { /*保留列~*/
  if(!map[y][x]) {
  fullflag = 0;
  break;
  }
  }
  if(fullflag) { /*向下移动一行*/
  for(dy = y; dy > 0; dy--)
  for(dx = 2; dx < MAX_X - 2; dx++)
  map[dy][dx] = map[dy - 1][dx];
  for(dx = 2; dx < MAX_X - 2; dx++)
  map[0][dx] = 0;
  /*并清除掉第一行*/
  }
  }
  }

  int move(int dir) { /*返回成功与否*/
  int newx;
  if(dir) newx = curx + 1;
  /*与drop一样,准备移动后的坐标*/
  else newx = curx - 1;
  if(test(newx, cury, curbox)) { /*测试是否冲突*/
  curx = newx; /*可以的话切换curx*/
  return 1;
  }
  return 0;
  }

  int test(int mx, int my, int box[5][5]) {
  /*测试box在map里mx,my位置上是否能着陆*/
  /*这个是最关键的一个函数,它判断是否产生非空冲突*/
  /*但算法还是很简单的*/
  int x, y;
  for(y = 0; y < 5; y++)
  for(x = 0; x < 5; x++)
  if(map[y + my][x + mx] && box[y][x])
  return 0;
  return 1;
  }

  int rotate() {
  int x, y;
  int newbox[5][5]; /*我们必须将当前盒子转动到新的盒子*/
  /*再对这个新的盒子的冲突作测试*/
  rotateBox(curbox, newbox); /*转动到新的盒子*/
  if(test(curx, cury, newbox)) {
  /*并且新的盒子能放到地图上而不冲突*/
  for(y = 0; y < 5; y++)
  for(x = 0; x < 5; x++)
  curbox[y][x] = newbox[y][x]; /*复制进来*/
  return 1;
  }
  else return 0;
  }

  int newfall() { /*创建下落元素失败返回0*/
  int x, y;
  curx = MAX_X / 2 - 2; /*重新指定小盒位置*/
  cury = 0;
  for(y = 0; y < 5; y++)
  for(x = 0; x < 5; x++)
  curbox[y][x] = nextbox[y][x];/*将nextBox复制过来*/
  rebuidNext(); /*重建nextBox*/
  return test(curx, cury, curbox);
  }

  /************************************************************\
  * 主函数 -- 整个游戏架构 *
  \************************************************************/

  int main() {
  char key; /*记录当前按键*/
  int i;
  int gd = VGA, gm = VGAMED; /*初始化的图形模式*/
  Timer *ptDown; /*下落所指向的时钟(有快慢)*/
  Timer trender; /*为了避免渲染给程序造成过大的负担*/
  /*用一个时钟来控制渲染速度*/
  /*把它设置interval = 1,*/
  /*这样就是18 FPS了,当然无法达到标*/
  /*准的60 FPS...毕竟这是DOS...*/

  setTimer(&trender, 1, 1);
  initgraph(&gd, &gm, ""); /*初始化图形*/
  newGame(); /*新游戏...*/

  while(1) { /*主游戏循环*/
  if(kbhit()) { /*如果键盘有按下*/
  key = getch(); /*读取一个按键值到key*/
  }
  else key = 0;

  switch(key) { /*对读到的key进行判断*/
  case KEY_UP:
  rotate(); /*上,旋转下落盒子*/
  break;
  case KEY_DOWN:
  ptDown = &tFast; /*使用tFast时钟 */
  break;
  case KEY_LEFT:
  move(0); /*左移*/
  break;
  case KEY_RIGHT:
  move(1); /*右移*/
  break;
  case KEY_ESC:
  closegraph(); /*结束游戏*/
  exit(0);
  default:
  ptDown = &tDown; /*使用原来速度 */
  }

  if(testTimer(ptDown)) { /*在上面已设置了下落要
  使用的时钟在ptDown里*/
  if(!drop()) { /*下落,失败返回0*/
  putBox(); /*写到地图里*/
  clear(); /*清除满行*/
  if(!newfall()) { /*新建下落,失败则游戏结束*/
  closegraph();
  exit(0);
  }
  }
  }
  if(testTimer(&trender)) /*最后...渲染...*/
  render();
  }
  }
温馨提示:答案为网友推荐,仅供参考
第1个回答  2009-06-13
100分就想买?你白日梦型的?这种设计一般是人名币算的
第2个回答  2009-06-13
二楼 你忒牛咯!!!
第3个回答  2009-06-12
好难哦!
第4个回答  2009-06-19
2楼吊
相似回答