zengl v1.4.1版本主要是为了修复zengl_SDL项目的Android工程开发时提交的BUG。zengl v1.4.1版本的描述信息如下(该信息可以在github.com上查看到,也可以在v1.4.1的readme...

    zengl v1.4.1版本主要是为了修复zengl_SDL项目的Android工程开发时提交的BUG。

    zengl v1.4.1版本的描述信息如下(该信息可以在github.com上查看到,也可以在v1.4.1的readme文件里查看到):

  zengl v1.4.1 , 修复zengl_symbol.c里zengl_ScanInsertGlobalSym函数在插入变量符号信息时,当parentnum为-1时,可能出现的nodes[parentnum]数组访问异常。
   
  该Bug由android SDK里的ndk-stack工具发现,该BUG有时候会导致程序直接挂掉,在android日志里就是提示terminated by signal (11)的错误。

  作者:zenglong 时间:2014年2月19日 官网:www.zengl.com

    v1.4.1源代码的相关地址如下:

    github.com项目地址:https://github.com/zenglong/zengl_language/

    百度盘的下载地址:http://pan.baidu.com/s/1mgjZiiO (zip压缩包里包含zengl_language.apk的Android安装包)

    sourceforge的地址:http://sourceforge.net/projects/zengl/files/ (包含所有历史版本,还有个额外的zengl_SDL.apk的安装包,这是zengl_SDL项目的签名过的Android安装包)

    zengl_SDL开源项目的相关地址如下:

    github.com项目地址:https://github.com/zenglong/zengl_SDL

    zengl_SDL.apk的安装包文件除了存在于上面的v1.4.1的sourceforge地址里外,还在zengl俄罗斯方块的百度盘里也放了一个:http://pan.baidu.com/share/link?shareid=396056&uk=940392313

    下面是zengl_SDL项目的相关描述信息(可以在github.com或该项目的readme文件里查看到):

  zengl_SDL为zengl嵌入式脚本语言的另一个测试项目,在SDL引擎的帮助下,可以在zengl脚本里编写一些简单的小游戏或者其他的小程式。该项目仅供学习研究和测试用途。

  该项目里面默认有一个俄罗斯方块的小游戏。测试方法如下:

  linux系统下,进入linux目录,如果要将zengl嵌入式脚本语言编译为动态链接库,则需要首先获得root权限,然后make (ubuntu下常见的方式是sudo make命令来提权和编译)

  如果要在linux下编译静态库,则直接在linux目录里输入make static命令(静态库无需root权限)

  生成的可执行文件为zengl_SDL和encrypt,encrypt为加密脚本文件,暂时用不到,因为要运行加密的脚本需要修改main.c来开启加密支持。

  zengl_SDL为主程式,该程式利用zengl语言库来编译执行脚本,利用SDL库来渲染图形。

  可以使用./zengl_SDL gui_Tetris/tetris.zl命令来编译执行俄罗斯方块脚本,或者使用./zengl_SDL gui_Tetris/tetris.zl -d来开启脚本调试。

  windows系统下,进入windows目录,该目录中的zengl_vc6.dsw是VC6的工作空间,zengl_SDL.sln是vs2008的解决方案文件(vs2010或更高版本则直接导入vs2008的解决方案即可)。

  在成功编译windows里的zengl_SDL项目后,可以在调试的命令参数里输入gui_Tetris/tetris.zl 或 gui_Tetris/tetris.zl -d 来测试俄罗斯方块脚本

  调试时,可以通过h命令来查看帮助

  新增的android工程文件,需要ndk开发环境。在配置好ndk的情况下,编译运行工程即可,最好是在真机上进行调试运行,详情参考官网。

  zengl_SDL.apk是签名过的发布版的apk安装包,默认运行的是俄罗斯方块,可以通过修改init.zl配置脚本来切换到21点小游戏,
 
  这些小游戏的zengl脚本都可以直接在手机上编辑,从而可以动态的调整游戏,作者是以320 x 480尺寸的机子写的默认脚本,如果你的系统是更大或更小的尺寸,

  可以通过手机自带的文件管理器和文本编辑器将游戏脚本里和窗口大小有关的数据进行修改,从而让游戏可以完整的覆盖你的手机屏幕,详情参见官网。

  作者:zenglong
  时间:2014年2月19日
  官网:www.zengl.com

    下面是zengl_SDL在手机上的截图:


图1

    上面是320x480的尺寸,因为本人的手机是这个尺寸的,在脚本里默认就是按照这个尺寸来写的,在安装完zengl_SDL.apk后,如果有SD卡,就会在SD卡的根目录生成一个zengl_SDL的目录,该目录里有个games目录,俄罗斯方块的脚本和21点扑克牌的脚本都放在该目录里,进入games目录,该目录里的结构如下:
 

图2

    init.zl就是上面zengl_SDL描述里所说的配置脚本,gui_21_point目录里存放的是21点扑克游戏的脚本和相关图片字体等资源,tetris目录里存放的是和俄罗斯方块有关的脚本和图片、字体等资源,zengl_debuglogs.txt暂时没用到,脚本里print指令或者printf模块函数输出的字符串都会保存在zengl_printlogs.txt文件里,同时如果脚本出现了语法错误或运行时错误,这些错误信息也会保存在zengl_printlogs.txt文件里。

    init.zl文件内容如下:

/*需要运行的游戏脚本*/
GameStartScript = 'tetris/tetris.zl';
//GameStartScript = 'gui_21_point/sdl_21_point.zl';
 

    GameStartScript变量默认设置的是tetris/tetris.zl即俄罗斯方块的脚本,所以zengl_SDL默认运行时,运行的就是俄罗斯方块,可以将上面的//GameStartScript = 'gui_21_point/sdl_21_point.zl';前面的两个杠杠注释给去掉(可以直接用手机里的文件编辑器来编辑),如下:

/*需要运行的游戏脚本*/
GameStartScript = 'tetris/tetris.zl';
GameStartScript = 'gui_21_point/sdl_21_point.zl';

    这样的话,一开始GameStartScript变量的值被设置为tetris/tetris.zl,随后又被gui_21_point/sdl_21_point.zl的字符串值给覆盖掉了,所以最终GameStartScript的值就是gui_21_point/sdl_21_point.zl即21点游戏脚本的相对路径。将修改保存,再次运行zengl_SDL(首先要确保前面的俄罗斯方块被正确关闭了,在俄罗斯方块一轮结束后,会提示点屏幕上半部分重玩,点下半部分正常退出,作者用的SDL 1.3.0在临时切换出去后,再切换回来时,就会什么都看不到,因为OpenGL的表面和上下文没有被很好的记忆下来,此时就只有在任务管理器里终止掉),21点扑克牌的截图如下:


图3

    另外还有个测试脚本,可以将init.zl里的GameStartScript变量设置为tetris/test.zl,得到的截图如下:


图4

    上面的脚本默认都是针对320x480尺寸的,像 tetris_def.zl 俄罗斯方块的常量定义脚本的内容如下:

..................................... //省略N行

//sdl event def end
def WinWidth 320; //整个游戏窗口的宽
def WinHeight 430; //游戏窗口的高
def GameMainWidthNum 10; //俄罗斯方块主区域水平格数
def GameMainHeightNum 16; //俄罗斯方块主区域垂直格数

..................................... //省略N行
 

    上面脚本代码里将WinWidth常量宏设为320,将WinHeight设为430(480的有效的图形绘制表面是小于480的,因为480还包括了标题栏,以及最顶端显示时间的那栏)。GameMainHeightNum在PC电脑上设置的是20格,这里因为WinHeight只有430,所以就调整为16格。

    如果你的手机尺寸是480x800的话,在不修改脚本常量值的默认情况下,运行情况就会如下:


图5

    可以看出来,周围有黑边,而且手指点击的时候,需要点击上面黑色部分才会让俄罗斯方块变化形状,左右移动也会有点失准,可以将tetris/tetris_def.zl里的常量进行如下调整:

..................................... //省略N行

//sdl event def end
def WinWidth 480; //整个游戏窗口的宽
def WinHeight 700; //游戏窗口的高
def GameMainWidthNum 10; //俄罗斯方块主区域水平格数
def GameMainHeightNum 18; //俄罗斯方块主区域垂直格数

..................................... //省略N行

    这里将WinWidth宽设为480,WinHeight高设为700(不要设800,在某些机子上分辨率超出有效绘制范围,SDL库会异常),GameMainHeightNum设为18格(也可以设为20格),保存tetris_def.zl脚本,再次运行zengl_SDL截图如下:


图6

    可以看到它能将游戏完整的显示出来,连zengl program的字样都显示出来了。

    下面是在百度MTC上测试通过的手机清单(时间关系只勾选了一部分机子,也等了好几个小时):

coolpad 8190 android 4.0.3 540x960
酷派5890 android 4.1.2 540x960
酷派5930 android 4.1.2 960x540
酷派7295C android 4.2.2 540x960
酷派8150D android 4.0.3 480x800
酷派8270 android 4.0.3 720x1280
酷派9900 android 4.0.3 480x960
Dell V04B android 2.3.5 540x960
GT-I8268 android 4.1.2 480x800
三星 GT-I9128 android 4.1.2 480x800
三星 GT-I9128V android 4.1.2 480x800
三星B9062 android 2.3.6 480x800
三星GT-I9105P android 4.1.2 480x800
三星I559(Galaxy Mini) android 2.3.5 240x320
三星I579 android 2.3.4 320x480
三星I699 android 2.3.6 480x800
三星I739 android 4.1.2 480x800
三星I779 android 2.3.6 480x800
三星I809(Galaxy S) android 2.2.2 480x800
三星I809(Galaxy S) android 2.2.3 480x800
三星I8150(Galaxy W) android 2.3.6 480x800
三星I8160 android 2.3.6 320x480
三星I8250 android 2.3.6 480x800
三星I8262D android 4.1.2 480x800
三星I8530 android 2.3.6 480x800
三星I8552 android 4.1.2 480x800
三星I879 android 4.1.2 480x800
三星I889(Galaxy Note 电信版) android 2.3.6 800x1280
三星I9070(Galaxy S Advance) android 2.3.6 480x800
三星I9082 android 4.1.2 480x800
三星I909(Galaxy S) android 2.2.1 480x800
三星I9100(Galaxy SII) android 2.3.5 480x800
三星I919 android 2.3.6 480x800
三星I919U android 2.3.6 480x800
三星I9300(Galaxy S3) android 4.1.1 720x1280
三星S5660(Galaxy Gio) android 2.3.6 320x480
三星S5670(Galaxy Fit) android 2.3.4 240x320
三星S5820 android 2.3.6 320x480
三星S5830i android 2.3.6 320x480
三星S6352 android 2.3.6 320x480
三星S6358 android 2.3.6 480x320
三星S6500D android 2.3.6 320x480
三星S7572 android 4.1.2 480x800
三星SCH-N719(Galaxy Note II) android 4.1.2 720x1280
HTC A310e android 2.3.5 320x480
HTC A320e android 4.0.3 320x480
HTC A6390(天姿) android 2.3 320x480
HTC G14 灵感(Z710e) android 4.0.3 540x960
HTC G22(HTC Ruby) android 2.3.4 540x960
HTC One S android 4.0.3 540x960
HTC S510b(倾心) android 2.3.5 480x800
HTC S710d android 2.3.5 480x800
HTC Sensation XE(G18) android 2.3.4 540x960
HTC Sensation(G14) android 4.0.3 540x960
HTC T320e One V android 4.0.3 480x800
HTC T329t android 4.1.1 480x800
HTC T528t android 4.1.1 480x800
HTC X315e(灵感XL) android 2.3.5 480x800
HTC X720d(One XC) android 4.0.3 720x1280
HTC 天玺 A9188 android 2.3 480x800
HTC 惊艳 S710d android 2.3.4 480x800
HTC 渴望S S510e(G12) android 2.3.5 480x800
HTC 野火S(A510e) android 2.3.5 320x480
HUAWEI C8813Q android 4.1.2 480x854
华为 Y300-0000 android 4.1.1 480x800
华为C8810(Ascend G300C) android 2.3.6 480x800
华为C8812 android 4.0.3 480x800
华为C8813 android 4.1.1 854x480 
华为C8813D android 4.1.1 480x854
华为G520 android 4.1.2 480x854
华为U8818(Ascend G300) android 2.3.6 480x800
华为U8860 android 2.3.6 480x854
华为U8860 android 4.0.3 480x854
华为U9200(Ascend P1) android 4.1.1 540x960
华为U9500 android 4.0.3 720x1280
华为X6(U9000) android 2.2.2 480x800
LG P705 android 4.0.3 480x800
OPPO X907 android 4.0.3 480x800
中兴N760 android 2.3.5 320x480
中兴N909 android 4.1.2 480x854
中兴U885 android 2.3.7 480x800
中兴U960s android 2.3.7 480x800
中兴U970 android 4.0.3 540x960
中兴V880 android 2.2.2 480x800
华硕K004(Intel x86) android 4.1.2 1280x800
夏新N890 android 4.2.1 540x960
小米2 android 4.1.1 480x854
小米MI-ONE Plus android 2.3.5 480x854
戴尔D43百度易手机 android 2.3.4 540x960
摩托罗拉ME811(Droid X) android 2.2.2 480x854
摩托罗拉ME863(里程碑3) android 2.3.5 540x960
摩托罗拉MT680 android 2.3.7 480x800
摩托罗拉MT870 android 2.3.6 540x960
摩托罗拉MT917 android 2.3.6 720x1280
摩托罗拉XT531 android 2.3.5 320x480
摩托罗拉XT535 android 2.3.7 480x854
摩托罗拉XT536 android 2.3.7 480x854
摩托罗拉XT615 android 2.3.7 480x854
摩托罗拉XT681 android 2.3.6 480x854
摩托罗拉XT720 android 2.2.1 480x854
摩托罗拉XT882 android 2.3.4 540x960
摩托罗拉XT882 android 2.3.6 540x960
步步高vivo X1St android 4.2.1 480x800
步步高vivo Y15T android 4.2.2 480x854
海信 T96 android 4.0.3 480x800
海信 U970 android 4.2.1 540x960
索尼S39h android 4.2.2 540x960
索尼ST25i(Xperia U) android 2.3.7 480x854
联想A820t android 4.1.2 540x960
联想乐Phone A366t android 2.3.6 320x480
青橙 GO M1 android 2.3.5 320x480

    可以看出来主要是Android 2.2到Android 4.2的系统,在MTC的Android 4.3的机子上运行失败,通过日志分析,发现backtrace最终定位在libSDL.so的Android_Jni_File...之类的函数里,说明SDL 1.3还不兼容Android 4.3的系统。所以如果是Android 4.3的用户运行起来的希望不大,作者之所以使用SDL 1.3的Android移植版,而不是用的最新的SDL2,是因为SDL2对Android系统的最低要求是2.3.3,而作者的手机只有2.2,所以SDL2不能在作者的手机上运行,读者如果有兴趣,手机又是4.3的系统,可以试着用下SDL2 (作者也不清楚SDL2是否兼容Android 4.3,听说Android 4.3对不少软件不兼容)。不过作者对SDL 1.3里的一些函数做过一些调整,让SDL 1.3可以访问SD卡里的资源,原版的SDL 1.3只能访问apk里的assets里的资源,所以如果你想改用SDL2的话,也需要对应进行修改。

    下面我们对源代码做些简单的分析。

    首先是zengl v1.4.1里涉及到的BUG,在移植21点扑克游戏的脚本时,经常间歇性的发生terminated by signal (11)的错误,在Android日志里的错误如下:

........................................... //省略N行

02-19 22:10:49.350: I/DEBUG(1159): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
02-19 22:10:49.350: I/DEBUG(1159): Build fingerprint: 'ZTE/U830/U830/U830:2.2.2/FRF91/eng.svnadmin.20110928.203625:user/release-keys'
02-19 22:10:49.350: I/DEBUG(1159): pid: 5383, tid: 5402  >>> com.zengl.SDL <<<

........................................... //省略N行

02-19 22:10:49.410: I/DEBUG(1159): stack:
02-19 22:10:49.410: I/DEBUG(1159):     4bd11950  80d141ed  /data/data/com.zengl.SDL/lib/libmain.so
02-19 22:10:49.420: I/DEBUG(1159):     4bd11954  80d13c1d  /data/data/com.zengl.SDL/lib/libmain.so
02-19 22:10:49.420: I/DEBUG(1159):     4bd11958  00219f88  [heap]
02-19 22:10:49.420: I/DEBUG(1159):     4bd1195c  00000930  
02-19 22:10:49.420: I/DEBUG(1159):     4bd11960  00000000  
02-19 22:10:49.420: I/DEBUG(1159):     4bd11964  80d13b9d  /data/data/com.zengl.SDL/lib/libmain.so

........................................... //省略N行

    上面只有一些.so动态链接库里的内存地址信息,如果想定位到哪一行就需要用到NDK安装目录里的ndk-stack工具:



图7

    可以看到如果选择libs\armeabi目录则会提示Bad file descriptor的错误,正确的符号路径应该是在android\obj\local\armeabi目录下。日志信息保存在log.txt文件里,通过-dump参数来指定日志文件,这样最后就会将栈错误的位置显示错误,例如本例中就是zengl_symbol.c文件的164行,位于zengl_ScanInsertGlobalSym函数里,该函数的定义如下:

/*
    扫描并插入全局变量符号表
*/

ZL_VOID zengl_ScanInsertGlobalSym(ZL_VOID * VM_ARG,ZL_INT arg_nodenum)
{
.............................................//省略N行
        else if(nodes[tmpstack.nodenum].toktype == ZL_TK_ID ||
                nodes[tmpstack.nodenum].toktype == ZL_TK_ARRAY_ITEM)
        {
            parentnum = nodes[tmpstack.nodenum].parentnode;
            /*下面的parentnum一定要进行大于等于0的测试,
             * 如果小于0,则在android下会出现terminated by signal (11)的错误,
             * 此错误由ndk-stack工具发现*/

            if(parentnum >=0 && nodes[parentnum].toktype == ZL_TK_DOT) //如果ID的父节点是点运算符,则交由SymInsertDotID处理
                compile->SymInsertDotID(VM_ARG,tmpstack.nodenum,parentnum);
            else
                compile->SymInsertHashTableForGlobal(VM_ARG,tmpstack.nodenum);
        }
.............................................//省略N行
}

    上面代码里parentnum默认值为-1,所以之前的版本没有对parentnum是否大于等于0做测试,就会访问到nodes数组以外的部分,从而导致terminated by signal (11)的错误。

    前面我提到对SDL 1.3做了修改让其可以访问SD卡里的资源,具体修改的位置在jni/SDL/src/core/android/SDL_android.cpp文件里:

static int Android_JNI_FileOpen(SDL_RWops* ctx)
{
........................................................ //省略N行
    fileNameJString = (jstring)ctx->hidden.androidio.fileName;
    tmpstr = (char *)mEnv->GetStringUTFChars(fileNameJString,NULL);
    if(tmpstr[0] == '/')
    {
        mid = mEnv->GetStaticMethodID(mActivityClass,
                "MyOpenFile","(Ljava/lang/String;)Ljava/io/InputStream;");
        inputStream = mEnv->CallStaticObjectMethod(mActivityClass,mid,fileNameJString);
        //mid = mEnv->GetStaticMethodID(mActivityClass,"PrintCallBack","(Ljava/lang/String;)V");
        //mEnv->CallStaticVoidMethod(mActivityClass,mid,fileNameJString);

    }
    else
    {
........................................................ //省略N行
}

    通过反向调用SDLActivity.java里的MyOpenFile类函数来读取SD卡里指定文件的数据流。

    另外当手指点击屏幕时,原版的SDL 1.3无法获取到正确的(x,y)即手指点击的坐标值,原因位于jni/SDL/src/events/SDL_touch.c文件里:

int
SDL_SendFingerDown(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down,
                   float xin, float yin, float pressurein)
{
........................................................ //省略N行
    //scale to Integer coordinates
    x = (Uint16)((xin+touch->x_min)*(touch->xres)/(touch->native_xres));
    y = (Uint16)((yin+touch->y_min)*(touch->yres)/(touch->native_yres));
    if(x > touch->native_xres)
        x = (Uint16)((Uint32)xin);
    if(y > touch->native_yres)
        y = (Uint16)((Uint32)yin);
........................................................ //省略N行
}
 

    最初的xin和yin坐标值是浮点数,在经过x = (Uint16)((xin+touch->x_min)*(touch->xres)/(touch->native_xres));和y = (Uint16)((yin+touch->y_min)*(touch->yres)/(touch->native_yres));两条代码后,浮点值会被转为整数坐标,但是这个整数坐标因为touch->xres与touch->yres信息的不准确,导致最终的x,y值会很大(有好几万的大小),所以我加了两条if语句,当x大于touch->native_xres(如果是320的手机上,这个native_xres就是320的值)时,就直接将xin通过Uint32和Uint16强制类型转换,将其转为整数值。同理得到y值,如果读者对这种方法不满意,可以自行测试和修改。

    另外在jni/src目录里,有个jni_glue.cpp文件,之所以有这个文件是因为我将SDL 1.3的包名改为自己的com.zengl.SDL,所以很多jni函数调用(java调用C里的代码)都需要通过该文件里的函数进行中转:

........................................................ //省略N行
extern "C" void Java_com_zengl_SDL_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj) {
    Java_org_libsdl_app_SDLActivity_nativeInit(env, cls, obj);
}
........................................................ //省略N行

    如上面代码里,当java调用Java_com_zengl_SDL_SDLActivity_nativeInit函数时,该函数再调用原来的Java_org_libsdl_app_SDLActivity_nativeInit函数。

    至于NDK环境如何搭建,请参考之前的zengl v1.3.1 Android编译执行zengl脚本的文章。

    最后再看下tetris/tetris.zl俄罗斯方块脚本里和手指点击屏幕有关的代码:

FingerUp = WinHeight/4;
FingerDown = WinHeight - FingerUp;
FingerLeft = WinWidth/2;

while(!gameover)
    while(sdlPollEvent(event)!=NoEvent)
        switch(event.type)
        case EvQuit: //点击了窗口右上角的叉叉则game over游戏结束
            gameover = TRUE;
            break;
        case EvResume:
            sdlAndroidLog('tetris:resume event\n');
            //screen = sdlGetWindowSurface(); //当系统切换出去后,目前还没找到恢复场景图像的方法,所以Android里一旦切换出去,再切换回来就什么也看不到了!!!
            break;
        case EvFingerDown:
                if(event.finger.y < FingerUp)
                    if(!turn_over)
                        tetris.direct = KeyUp;
                    else
                        myReStartGame();
                    endif
                elif(event.finger.y > FingerDown)
                    if(!turn_over)
                        tetris.direct = KeyDown;
                    else
                        gameover = TRUE;
                    endif
                else
                    if(event.finger.x < FingerLeft)
                        tetris.direct = KeyLeft;
                    else
                        tetris.direct = KeyRight;
                    endif
                endif
            break;

    FingerUp变量的值为WinHeight/4即窗口有效绘制区域高度的4分之1,所以当点击游戏窗口上面4分之1的区域时,就可以改变俄罗斯方块的形状,FingerDown变量的值为WinHeight - FingerUp即高度减4分之1,即当手指点击区域在窗口4分之3以下的区域时,就可以加速下落,FingerLeft变量值为WinWidth/2,即当手指点击区域在4分之1到4分之3之间,且在左半边的时候,方块就往左移,在右半边时,方块就往右移。

    虽然zengl_SDL.apk可能不兼容android 4.3的系统,但是zengl语言本身是可以在4.3上运行的,如下图:


图8

    OK,以上就是zengl v1.4.1与zengl_SDL的相关介绍,到这里,休息,休息一下 o(∩_∩)o~~
 
上下篇

下一篇: zengl v1.5.0 移植到zenglOX系统

上一篇: zengl v1.4.0 调试接口 zengl_SDL项目

相关文章

zengl v1.5.0 移植到zenglOX系统

zengl v1.2.1 修复函数调用BUG

zengl编程语言v0.0.12函数的实现

zengl编程语言v0.0.22实现switch...case

zengl编程语言v1.0.5 编译,执行,源码调试一体化,开发俄罗斯方块

zengl编程语言v0.0.19 def宏定义