回 帖 发 新 帖 刷新版面

主题:[改编]俄罗斯方块(游戏)

本程序是在[url=http://pfan.cn/club/showbbs.asp?id=26558]刘红石 的俄罗斯方块源码[/url]的基础上改编而成的,在此表示感谢。
相对原程序主要的改动有:
合并 原程序中的FUNCTION xialuo% () 和SUB yidong (p%) 为FUNCTION move% (dx%, dy%)
合并 原程序中的SUB hua(),SUB ca()和SUB kuai(x%, y%, c%)为SUB drawfk (cc$)
另外 将原程序中的SUB zhuan () 改进为SUB turn (side%)使之能在两个方向旋转
在检测有无满行时,只检测刚落下的方块所在的几行以增加程序的效率。
欢迎各位QBASIC爱好者对本程序提出更多的宝贵意见,使该程序更加完善。
本人邮箱为turebaojian@163.com QQ为281860270


DECLARE SUB nextfk ()       '产生下一个方块
DECLARE SUB turn (side%)    '旋转拼块的子程序
DECLARE SUB drawfk (cc$)    '画或擦除小方块的子程序
DECLARE SUB ending ()     '结束画面
DECLARE FUNCTION move% (dx%, dy%) '拼块左右移动及下落的函数
DECLARE FUNCTION max% (array() AS INTEGER, n%) '求数列中最大项
DECLARE FUNCTION min% (array() AS INTEGER, n%) '求数列中最小项
DIM SHARED fk(7, 4, 2) AS INTEGER  ' 定义数组 FK,此数组存放7种拼块的形状
DIM SHARED tong(-1 TO 14, 1 TO 25) AS INTEGER
DIM SHARED kx(4) AS INTEGER, ky(4) AS INTEGER  '此数组存放当前拼块的位置
DIM SHARED kx0(4) AS INTEGER, ky0(4) AS INTEGER  '此数组存放下一个拼块的形状

CONST x0 = 20, left = -1, right = 1, down = 1, still = 0
DIM i AS INTEGER, j AS INTEGER, k AS INTEGER, t AS INTEGER, m AS INTEGER

' 下段程序段读入拼块形状数据
FOR i = 1 TO 7: FOR j = 1 TO 4: FOR k = 1 TO 2
  READ fk(i, j, k)
NEXT k, j, i
DATA 1,1,1,2,1,3,1,4
DATA 1,1,1,2,1,3,2,3
DATA 1,3,2,1,2,2,2,3
DATA 1,1,1,2,2,1,2,2
DATA 1,2,1,3,2,1,2,2
DATA 1,1,1,2,2,2,2,3
DATA 1,1,1,2,1,3,2,2
FOR i = 1 TO 25
  tong(0, i) = 1: tong(13, i) = 1
NEXT i
FOR i = 1 TO 12
  tong(i, 25) = 1
NEXT i
CLS : VIEW PRINT 1 TO 25
LOCATE 14, 9: PRINT "NEXT"
LOCATE 8, 50: PRINT "KEY PRESS:"
LOCATE 10, 50: PRINT "LEFT  :move left"
LOCATE 11, 50: PRINT "RIGHT :move right"
LOCATE 12, 50: PRINT "UP    :turn left"
LOCATE 13, 50: PRINT "DOWN  :turn right"
LOCATE 14, 50: PRINT "SPACE :move down fast"
LOCATE 15, 50: PRINT "ENTER :pause"
LOCATE 16, 50: PRINT "ESC   :exit"
LOCATE 1, x0 + 1: PRINT CHR$(201); STRING$(24, CHR$(205)); CHR$(187)
FOR j = 2 TO 24
   LOCATE j, x0 + 1: PRINT CHR$(186); SPC(24); CHR$(186)
NEXT j
DEF SEG = &HB800
POKE 24 * 160 + 2 * x0, 200
FOR i = 2 TO 48 STEP 2
POKE 24 * 160 + 2 * x0 + i, 205
NEXT i
POKE 24 * 160 + 2 * x0 + 50, 188

DIM score AS INTEGER
RANDOMIZE TIMER
CALL nextfk
DO
  FOR i = 1 TO 4
   kx(i) = kx0(i) + 5
   ky(i) = ky0(i) + 1
  NEXT i
  CALL drawfk("[]")
  CALL nextfk
  LOCATE 10, 8: PRINT "SCORE:"; score
  FOR i = 1 TO 4
   IF tong(kx(i), ky(i)) = 1 THEN   '如果有其它的块,则桶满,游戏结束
     CALL ending
     END
   END IF
  NEXT i
  DO
    newtime = TIMER + .5
    DO
     key$ = INKEY$
     SELECT CASE key$
      CASE CHR$(0) + CHR$(72)  '按键 上:左旋
       CALL turn(left)
      CASE CHR$(0) + CHR$(80)  '按键 下:右旋
       CALL turn(right)
      CASE CHR$(0) + CHR$(75)  '按键 左:左移
       t = move%(left, still)
      CASE CHR$(0) + CHR$(77)  '按键 右:右移
       t = move%(right, still)
      CASE " "                 '按键 空格:速降
       EXIT DO
      CASE CHR$(13)            '按键 回车:暂停
       DO WHILE INKEY$ = ""
       LOOP
     CASE CHR$(27)            '按键 ESCape :退出
       CALL ending
       END
    END SELECT
   LOOP UNTIL TIMER > newtime
  t = move%(still, down)
  LOOP UNTIL t = 0
REM 消去满行的方块行
under = max%(ky(), 4): upon = min%(ky(), 4)
FOR j = under TO upon STEP -1    '从方块底到方块顶依次检查是否有填满的行
   p = 0       'P为此行方块数
   FOR i = 1 TO 12
    p = p + tong(i, j)   '计算此行的方块数
   NEXT i
  IF p = 12 THEN      '如果此行填满(方块数为12),则奏乐、清除此行、上面的行下移一行
    score = score + 1
    PLAY "mbc16d16g16"
   FOR k = j TO 1 STEP -1
     q = 0        'q为当前行的方块数
    FOR i = 1 TO 12     '依次将上一行的1至12块移至当前行
     tong(i, k) = tong(i, k - 1): q = q + tong(i, k)
     IF tong(i, k) = 1 THEN cc$ = "[]" ELSE cc$ = "  "
      LOCATE k, i * 2 + x0: PRINT cc$
    NEXT i
   IF q = 0 THEN EXIT FOR     '当前行的方块数为0,即是空行则转入上一行的检测
   NEXT k
    j = j + 1: upon = upon + 1  '下移后,当前行不变,方块最高行下移
  END IF
NEXT j
LOOP

SUB drawfk (cc$)      'cc$为"[]"画出拼块;为"  "擦除拼块
DIM i AS INTEGER
FOR i = 1 TO 4
LOCATE ky(i), kx(i) * 2 + x0: PRINT cc$
NEXT i
END SUB

SUB ending      '结束画面
DIM i AS INTEGER
FOR i = 24 TO 1 STEP -1
  LOCATE i, x0 + 2: PRINT "[][][][][][][][][][][][]"
  FOR j = 1 TO 10000: NEXT j
NEXT i
FOR i = 24 TO 1 STEP -1
  LOCATE i, x0 + 2: PRINT SPACE$(24)
NEXT i
END SUB

FUNCTION max% (array() AS INTEGER, n%) '求数列中最大项,n%为项数
DIM i AS INTEGER, num AS INTEGER
num = array(1)
FOR i = 2 TO n%
IF num < array(i) THEN num = array(i)
NEXT i
max% = num
END FUNCTION

FUNCTION min% (array() AS INTEGER, n%) '求数列中最小项,n%为项数
DIM i AS INTEGER, num AS INTEGER
num = array(1)
FOR i = 2 TO n%
IF num > array(i) THEN num = array(i)
NEXT i
min% = num
END FUNCTION

FUNCTION move% (dx%, dy%)  'dx%取left:左移 right:右移 still: 水平方向不动
DIM i AS INTEGER, t AS INTEGER    'dy%取down:下移 still:竖直方向不动
CALL drawfk("  ")   '擦除拼块
t = 1       '先设拼块还能移动
FOR i = 1 TO 4         '依次检查组成拼块的各个方块的位置
  IF tong(kx(i) + dx%, ky(i) + dy%) = 1 THEN
    t = 0: EXIT FOR     '如果方块运动方向已有方块则不能移动
  END IF                '如果方块到桶壁或桶底则不能再移动
NEXT i
IF t = 1 THEN        '如果拼块能移动时,拼块移动一格
  FOR i = 1 TO 4
    kx(i) = kx(i) + dx%: ky(i) = ky(i) + dy%
  NEXT i
  move% = 1
ELSEIF dy% = down THEN    '拼块不能下落
  FOR i = 1 TO 4
    tong(kx(i), ky(i)) = 1
  NEXT i
  move% = 0
ELSE                    '拼块不能左右移动
  move% = -1
END IF
CALL drawfk("[]")    '画出此时的拼块
END FUNCTION

SUB nextfk   '产生一个方块
  m = INT(RND * 7 + 1)     '随机产生一个数,这个数是拼块的编号
  FOR i = 1 TO 4           '用kx0(i),ky0(i)记录下一个方块
   kx0(i) = fk(m, i, 1)
   ky0(i) = fk(m, i, 2)
  NEXT i
  FOR i = x0 - 10 TO x0 - 2     '清空上一个方块
  FOR j = 16 TO 20
   LOCATE j, i: PRINT "  "
  NEXT j, i
  FOR i = 1 TO 4         '显示下一个方块
    LOCATE ky0(i) + 15, kx0(i) * 2 + 8: PRINT "[]"
  NEXT i
END SUB

' 转动拼块
SUB turn (side%)        'side%取left:左旋 right:右旋
DIM i AS INTEGER, t AS INTEGER, x AS INTEGER, y AS INTEGER
DIM kx1(4) AS INTEGER, ky1(4) AS INTEGER '定义暂时存放拼块状态的数组
CALL drawfk("  ")       '擦除拼块
IF side% = right THEN   '右旋
  x = max(kx(), 4): y = max(ky(), 4)
ELSEIF side% = left THEN    '左旋
  x = min(kx(), 4): y = max(ky(), 4)
END IF
FOR i = 1 TO 4     '依次计算旋转后各个方块的位置
  kx1(i) = -side% * (ky(i) - y + 1) + x  '左旋则以左下角方块或空格的右上角为旋转中心
  ky1(i) = side% * (kx(i) - x) + y       '右旋则以右下角方块或空格的左上角为旋转中心
NEXT i
t = 1       't是一个标志, 拼块能旋转时为1
FOR i = 1 TO 4                        '如果旋转后的方块出了桶的边界
  IF tong(kx1(i), ky1(i)) = 1 THEN    '或与已有方块重叠,则不能旋转拼块
    t = 0: EXIT FOR
  END IF
NEXT i
IF t = 1 THEN          '如果拼块能够旋转,则给出旋转后方块的位置
  FOR i = 1 TO 4
   kx(i) = kx1(i): ky(i) = ky1(i)
  NEXT i
END IF
CALL drawfk("[]")     '画出此时的拼块
END SUB

回复列表 (共4个回复)

沙发

非常支持!
希望能有背景音乐!做成图形模式!

板凳

对于 背景音乐 使用 SOUND 或是 PLAY 都不能得到很好的效果,对屏幕显示有延迟
即便用 PLAY "mbccdd"效果也不太好。

不知谁在这方面有些研究,请指点指点。

3 楼

用喇叭本来应该没啥延迟的,是qbasic的sound函数设计成这样的,它本身包括了开喇叭,让喇叭按你设定频率产生声音,延时等到你设定的时间,关喇叭,全包了....真勤劳
由于延时也让它给包了,所以放声音的时候,你程序做不了事,延时就是这个原因造成的....汗
要想不延迟,一般自己直接控制喇叭就行啦
初始化
out &h43,&hb6
设置频率
out &h42,&h1234dc/设定的频率
打开喇叭
out &h61,3
延迟
这个不用说了......要利用的就是这个.....,只要不关,那个频率的声音一直在,你的程序也可以做别的事情,喇叭是由一块独立的电路来控制的
关喇叭
out &h61,0
从汇编书上分析来的,没实验过.....如果有错,那不好意思啦~

4 楼

不行 没有发声

我来回复

您尚未登录,请登录后再回复。点此登录或注册