俄罗斯方块(Tetris)是一款风靡全球的电视游戏机和掌上游戏机游戏,也是作者最喜欢的游戏之一,所以作者就用zengl开发了俄罗斯方块,该游戏脚 本在windows和linux平台下都可以运行,本节开始...

    俄罗斯方块(Tetris)是一款风靡全球的电视游戏机和掌上游戏机游戏,也是作者最喜欢的游戏之一,所以作者就用zengl开发了俄罗斯方块,该游戏脚 本在windows和linux平台下都可以运行,本节开始将对俄罗斯方块的算法进行分析,而分析一套代码最好的方法就是从最初的版本开始研究,所以本节 就从v1第一个版本开始分析。

    v1版本的下载地址为:http://pan.baidu.com/share/link?shareid=396056&uk=940392313  (此为百度盘的共享链接地址) 在该链接里,进入zengl俄罗斯方块共享文件夹,在该文件夹中有个version_1_tetris.rar的压缩包就是v1版本的代码包,里面有个版本1说明.txt文件,包含了该版本的相关说明:

    该版本是俄罗斯方块的第一个测试版本,该版本并没有任何可玩的游戏环节,只是建立了一个初始的游戏脚本运行环境,运行俄罗斯方块版本1双击我运行.bat批处理文件,会得到一个S形状的俄罗斯方块,从顶部落到底部,到了底部后,游戏结束,可以按ESC键退出。如果要玩完整版,可以查看"zengl编程语言"栏目,其中的"zengl编程语言v1.0.5 编译,执行,源码调试一体化,开发俄罗斯方块"这篇文章里有俄罗斯方块正式发布版的下载地址。

    如果是linux用户,在成功编译了zengl v1.0.5或更高版本的程序后,可以将version_1_tetris.rar里的version_1_tetris文件夹拷贝到zengl根目录 中,最后运行./zenglrun version_1_tetris/tetris.zl -n 即可,如果要调试脚本,可以加个-d参数(参数的含义请参考上面提到的zengl v1.0.5的文章,或者通过-h参数来查看帮助)。

    首先来看下俄罗斯方块的坐标系(也是SDL游戏开发采用的坐标系):

    以(x,y)来代表游戏区域的坐标,那么(0,0)坐标即原点就在左上角,x坐标值是从左到右依次增大,y坐标值则是从上到下依次增大,坐标单位为像素。这个和数学里的常规坐标系是不一样的,所以是需要特别注意的地方。

    因为俄罗斯方块是以小方块为单位的,主游戏区域也是以小方块为一格单位的,所以在游戏脚本中还引入了虚拟坐标的概念,这个虚拟坐标不是以像素为单位,而是以小方块格子数为单位:

    所以在游戏脚本中,是对方块的虚拟坐标进行加减计算,然后再根据小方块的宽高值将虚拟坐标换算为实际的SDL游戏像素值。例如假设某方块的虚拟坐标为 (1,1) ,并且假设小方块为20像素宽和20像素高,那么方块在主游戏区域的实际像素值就是(20px,20px),再加上主游戏区域左上角的坐标值,假设为 (25px,25px),那么该方块在整个游戏窗口中的实际像素坐标就是(45px,45px),得到了该像素值后,最后调用SDL模块提供的脚本函数, 就可以将方块绘制到游戏窗口的正确位置了。

    现在看下本版本的游戏脚本中涉及到的一些SDL模块函数:

1) sdlFillRect(dest surface,dest rect , array color_alpha); 第一个参数dest surface是要填充的目标表面的指针值,第二个参数dest rect为要填充的矩形区域,如果是0则说明要填充目标的所有区域,第三个参数array color_alpha为要设置的颜色数组。
例如在该版本的tetris.zl脚本的第82行:
sdlFillRect(screen,array(TetrisWidth * tetris.members[i].vx + gameMainBg.pos.x,
                                TetrisHeight * tetris.members[i].vy + gameMainBg.pos.y,
                                TetrisWidth , TetrisHeight),tetris.color); //利用方块的颜色,和方块的坐标,宽高值将屏幕的指定矩形区域填充颜色

2) sdlGetTicks(); 返回当前的时间戳,在本脚本中主要用于设置方块下落的定时器。

3) sdlInit(); 初始化SDL库

4) sdlCreateWin(width,height,bpp,flags,repeat[option]); option表示可选参数,第一个参数是窗口宽,第二个参数是窗口高,第三个参数是位深,即分辨率,第四个参数是SDL的视频模式的一些可选标志或者参 数。第五个可选参数是用来设置按键检测的重复间隔,SDL默认只检测一次按键,有了这个参数就可以开启重复检测按键。俄罗斯方块游戏中,只有在最后的版本中才用到了这个参数。

例如在脚本的第107行:
screen = sdlCreateWin(WinWidth,WinHeight,32,0); //创建窗口

5) sdlPollEvent(event); event参数是一个数组或类,用于存放SDL事件的类型等信息,event类型原型如下:

    class clsMouseMotionEvt  //SDL定义的鼠标移动事件C结构体对应的zengl类型
        type;    //SDL_MOUSEMOTION
        which;    //The mouse device index
        state;    //The current button state
        x; y;    //The X/Y coordinates of the mouse
        xrel;   //The relative motion in the X direction
        yrel;    //The relative motion in the Y direction
    endcls

    class clsMouseButtonEvt  //SDL定义的鼠标点击事件C结构体对应的zengl类型
        type;    //SDL_MOUSEBUTTONDOWN or SDL_MOUSEBUTTONUP
        which;    //The mouse device index
        state;    //SDL_PRESSED or SDL_RELEASED
        x; y;    //The X/Y coordinates of the mouse at press time
        button;    //The mouse button index
    endcls

    class clsEvent  //event对应的zengl类型
        type; //事件类型,判断是按键事件,还是鼠标事件等。
        keytype;  //如果是按键,则keytype中存放了按键的类型
        clsMouseMotionEvt motion; //如果是鼠标移动事件,则将移动的坐标等信息存放到motion中。 
        clsMouseButtonEvt button; //如果是鼠标点击事件,则将点击相关的信息存放到button中。
    endcls

例如在脚本的第121行:
while(sdlPollEvent(event)!=NoEvent)

6) sdlDelay(millisecond); 第一个参数millisecond是要延时的毫秒数

例如在该版本tetris.zl脚本的第135行:
sdlDelay(10); //设置10毫秒延时。防止CPU持续占用资源

7) sdlShowScreen(); 将游戏绘制好的帧显示出来,因为SDL的绘制操作都是绘制在缓存中的,必须通过sdlShowScreen脚本函数内部调用SDL_Flip进行翻转,才能将缓存中的数据输出到显卡显示出来。

    该版本的tetris.zl脚本的主要计算逻辑集中在myTetrisMove自定义函数中:
/*
    计算运动中的方块的虚拟坐标,并判断是否下落到了主游戏区域的底部
*/

fun myTetrisMove()
    global time,isneedDraw,tetris;
    clsTetris tetris;
    if(sdlGetTicks() - time > 1000) //每隔1000毫秒,就进行匀速自由落体运动。
        if(tetris.members[tetris.bottomIndex].vy+1 >= 20) //主游戏区域是20格的高度,如果运动方块的正下方是底部,则返回。
            return;
        endif
        for(i=0;i<4;i++) //循环将俄罗斯方块的每个小方块的vy虚拟纵坐标加一
            tetris.members[i].vy++;
        endfor
        isneedDraw = TRUE; //因为方块下落了一格,所以设置isneedDraw为TRUE,表示需要绘制游戏主区域和运动方块
        time = sdlGetTicks(); //重置定时器
    endif
endfun

    至于脚本中的其他代码都在重要的部分加了注释,可以结合注释和调试器进行分析,该版本的运行界面如下:

    当到达最底部时,方块就不再运动了,此时可以按ESC键退出。

    OK,下节介绍v2的版本,休息,休息一下 O(∩_∩)O~

上下篇

下一篇: zengl俄罗斯方块v2 初始化七种形状

上一篇: 暂无

相关文章

zengl俄罗斯方块v8 修复消行BUG

zengl俄罗斯方块v7 添加暂停功能

zengl俄罗斯方块v6 传统消行法

zengl俄罗斯方块v9 添加下一次出现方块的预览功能

zengl俄罗斯方块v11 使用zengl v1.0.6新语法

zengl俄罗斯方块v10 连续按键,顶部非可见区域