底层脚本、高层脚本和微线程 

2006-12-08 11:43 发布

引擎学习交流 /[各编程语言]
2584 0 0


    脚本在游戏中占据的位置是不可质疑的。不仅仅是由于其解释语言的特性(修改不需要对源代码进行编译);而且游戏的逻辑采用脚本语言更加容易描述。对于底层脚本和高层脚本,至今尚未有一个明确的定义。本系列文章试图从技术的角度,在概念上对底层和高层脚本进行一个划分,并对微线程在游戏引擎的引入的必要性进行分析。
以下面网上对于脚本与游戏主循环的同步作为一个引子,展开本文研究的话题。
    “基于命令的脚本语言可以用来控制游戏中的non-player character,可以让他们"自主"的转悠、动作,使游戏更生动。当然,这些NPCs的动作也可以使用Hard-code的方式跟游戏引擎写在同一处,显而易见的是,这种方式将游戏的底层(Gameengine)和游戏的高层(Logic)混在一起,对于游戏的扩展、游戏的调试。。。。没有可取之处。
    下面的这些脚本片断用来控制一个NPC,每个命令的含义很直观。
// RPG NPC Script
// A Command-Based Language Demo
// ---- Walking in a square pattern
ShowTextBox "THAT WAS SIMPLE ENOUGH."
Pause 2400
ShowTextBox "NOW LET'S WALK IN A SQUARE PATTERN."
Pause 2400
HideTextBox
Pause 800
SetCharDir "Right"
MoveChar 40 0
MoveChar 8 8
SetCharDir "Down"
MoveChar 0 80
MoveChar -8 8
    要让这个脚本控制一个NPC,我们必须编写一个"脚本解释器",从脚本文件内读入每行命令、解释、并执行。需要注意的是,如何与游戏的主循环同步呢?也就是说,如果我们顺序执行这个脚本序列(在一个循环中),则整个程序的其他部分得不到响应,那就会出现这样的情况:在NPC运动过程中,游戏主角将不会响应用户的控制。如何解决这个问题呢?多线程(Multi-Thread)?这是个自找麻烦的做法。
    实际上,为了解决面临的同步问题,我们可以把脚本的作用限制在"改变程序的状态"这个范围内,例如:NPC要从A处移动到B处,我们不会在解释这个命令脚本的时候做这样的事情:把代表NPC的图片从A处以一个微小的增量移动,直到它到到B处,这样就导致了"不同步",我们要做的是,设置这个NPC的状态为正在移动,并记录目标点的坐标,然后,在游戏的主循环中,我们检测到这个NPC的状态,如果它没有到目标点,我们就继续移动它。
同时需要注意的是,如果这个命令没有执行完,那么我们应该不允许下一个命令的开始,也就是说,我们在游戏的主循环中,依次解释每一条命令,并且设置相应的状态值,但是遇到类似"移动"这样的命令,如果没有执行完这条命令,程序将不会解释执行下一条命令,也就是说,移动到某处不是一蹴而就的,是需要过程的。”

    本文将针对六个方面的问题展开讨论:高层脚本和底层脚本;微线程;微线程与主循环同步;脚本组织与对象脚本;脚本与任务系统;网游客户端脚本与游戏的交互性。”
    
  本文内容仅代表星河工作室针对此类问题的观点。相关的技术在星河平台2.1版本全部得到支持(SRPV2.1),可访问相关网站:http://www.srplab.com

一:高层脚本和底层脚本

    高层脚本更适于描述逻辑,上述的例子是一个高层脚本,下面的一段描述也是高层脚本:
走到(死水沼泽,56,99)
等待(500)毫秒
走到(死水沼泽,56,42)
找到(首饰店掌柜)(死水沼泽【7】,52,31)
与首饰店掌柜对话
选择【出售首饰】
自动卖掉【手镯】类物品
自动卖掉【戒指】类物品
自动卖掉【项链】类物品
选择【返回】
结束对话
找到【服装店掌柜】(死水沼泽【7】,49,37)
与【服装店掌柜】对话
选择【出售衣服】
自动卖掉【衣服】类别物品
自动卖掉【头盔】类别物品
选择【返回】
结束对话
    对于底层脚本,更加类似于函数,如下一段代码(摘自:Game Programming With Python,lua and Ruby)是底层脚本:
function render_frame(screen, background)
-- When called renders a new frame.
        -- First clears the screen
        SDL.SDL_FillRect(screen, NULL, background);
        -- re-draws each actor in gamestate.actors
        for i = 1, getn(gamestate.actors) do
                gamestate.actors:render(screen)
        end
        -- updates
        SDL.SDL_UpdateRect(screen, 0, 0, 0, 0)
end
function engine_init(argv)
        local width, height;
        local video_bpp;
        local videoflags;
        videoflags = SDL.bit_or(SDL.SDL_HWSURFACE, SDL.SDL_ANYFORMAT)
        width = 800
        height = 600
        video_bpp = 16
        -- Set video mode
        gamestate.screen = SDL.SDL_SetVideoMode(width, height, video_bpp, videoflags);
        gamestate.background = SDL.SDL_MapRGB(gamestate.screen.format, 0, 0, 0);
        SDL.SDL_ShowCursor(0)
        -- initialize the timer/ticks
        gamestate.begin_time = SDL.SDL_GetTicks();
        gamestate.last_update_ticks = gamestate.begin_time;
end

    那么什么是高层脚本,什么是底层脚本,两者之间的区别是什么?
    如果脚本不能够顺序执行完毕,则该脚本是一个高层脚本。高层脚本更加适合于描述游戏逻辑。如果脚本能够顺序执行完毕,则该脚本是一个底层脚本,底层脚本使游戏在更新局部功能的时候不需要重新编译。
对于高层脚本描述游戏逻辑,有时一条脚本命令需要一个执行过程,比如:走到(死水沼泽,56,99),该脚本命令执行后,会触发一个移动的动作,需要几帧甚至更多的游戏循环,才能够执行完毕。类似命令“MoveChar 0 80”同样。因此在命令执行过程中,需要让出CPU,给游戏其它部分运行,直到达到目标状态。
对于底层脚本,不存在类似的问题,执行过程都是顺序的,中间不中断。
高层脚本执行如何进行,采用类似前面,通过引入状态的方法进行控制,该方法有哪些缺陷?有没有更好的方案,答案是有,哪就是采用微线程。
我们在第二部分讨论微线程,并与一个通过引入状态进行控制的代码进行比较。
abc

楼主新帖

TA的作品 TA的主页
B Color Smilies

你可能喜欢

底层脚本、高层脚本和微线程 
联系
我们
快速回复 返回顶部 返回列表