为游戏选择脚本语言并实现它

时间:2010-06-13 11:44:30

标签: scripting

我目前正在用C ++开发3D动作/ RPG游戏,我想在选择脚本语言来编写游戏的AI方面有一些建议。我的团队来自一个改装背景,事实上我们仍然在完成哥特式游戏的模型工作。在那个游戏中(我们也从中得到了灵感)使用了DAEDALUS语言(由游戏制作者Piranha Bytes创建)。 Here is a full description of said language.

要注意的主要问题是它使用的实例比类更多。游戏引擎是关闭的,因此人们只能猜测这种语言的内部实现,但我在脚本语言中寻找的主要内容(理想情况下,它非常相似,但最好也比DAEDALUS更强大)是事实有事实上的3'分离'的类 - 即类,实例和(实例的实例?)。

如果我提供一个例子,我认为理解我想要的东西会更容易。定期NPC。首先,你定义了一个类(我理解)镜像引擎内的(类或结构):

CLASS C_NPC 
{
    VAR INT     id                              ;       //  absolute ID des NPCs
    VAR STRING  name            [5]             ;       //  Namen des NPC
    VAR STRING  slot                            ;           
    VAR INT     npcType                         ;           
    VAR INT     flags                           ;           
    VAR INT     attribute       [ATR_INDEX_MAX] ;           
    VAR INT     protection      [PROT_INDEX_MAX];           
    VAR INT     damage          [DAM_INDEX_MAX] ;           
    VAR INT     damagetype                      ;
    VAR INT     guild,level                     ;           

    VAR FUNC    mission         [MAX_MISSIONS]  ;           
    var INT     fight_tactic                    ;           
    VAR INT     weapon                          ;           

    VAR INT     voice                           ;           
    VAR INT     voicePitch                      ;           
    VAR INT     bodymass                        ;           

    VAR FUNC    daily_routine                   ;       //  Tagesablauf
    VAR FUNC    start_aistate                   ;       //  Zustandsgesteuert

    // **********************                   
    // Spawn                                    
    // **********************                   
    VAR STRING  spawnPoint                      ;       //  Beim Tod, wo respawnen ?
    VAR INT     spawnDelay                      ;       //  Mit Delay in (Echtzeit)-Sekunden

    // **********************                   
    // SENSES                                   
    // **********************                   
    VAR INT     senses                          ;       //  Sinne
    VAR INT     senses_range                    ;       //  Reichweite der Sinne in cm

    // **********************                   
    // Feel free to use                         
    // **********************                   
    VAR INT     aivar           [50]            ;                       
    VAR STRING  wp                              ;           

    // **********************                   
    // Experience dependant                     
    // **********************                   
    VAR INT     exp                             ;       // EXerience Points
    VAR INT     exp_next                        ;       // EXerience Points needed to advance to next level
    VAR INT     lp                              ;       // Learn Points     
};

然后,您还可以定义原型(设置一些默认值)。但是你如何实际定义一个NPC是这样的:

instance BAU_900_Ricelord (Npc_Default) //Inherit from prototype Npc_Default
{
    //-------- primary data --------

    name        =   "Ryzowy Ksiaze";
    npctype     =   NPCTYPE_GUARD;  
    guild       =   GIL_BAU;      
    level       =   10;
    voice       =   12;
    id          =   900; 

    //-------- abilities --------
    attribute[ATR_STRENGTH]     = 50;
    attribute[ATR_DEXTERITY]    = 10;
    attribute[ATR_MANA_MAX]     = 0;
    attribute[ATR_MANA]         = 0;
    attribute[ATR_HITPOINTS_MAX]= 170;
    attribute[ATR_HITPOINTS]    = 170;

    //-------- visuals --------
    //              animations
    Mdl_SetVisual       (self,"HUMANS.MDS");
    Mdl_ApplyOverlayMds (self,"Humans_Arrogance.mds");
    Mdl_ApplyOverlayMds (self,"HUMANS_DZIDA.MDS");
    //          body mesh     ,bdytex,skin,head mesh     ,headtex,teethtex,ruestung 
    Mdl_SetVisualBody (self,"Hum_Body_CookSmith",1,1,"Hum_Head_FatBald",91 ,  0,-1);

    B_Scale (self); 
    Mdl_SetModelFatness(self,2);

    fight_tactic    =   FAI_HUMAN_STRONG;

    //-------- Talente --------                                    
    Npc_SetTalentSkill  (self,NPC_TALENT_1H,1); 


    //-------- inventory --------                                    

        CreateInvItems (self, ItFoRice,10);
        CreateInvItem (self, ItFoWine);
        CreateInvItems(self, ItMiNugget,40);
        EquipItem  (self, Heerscherstab); 

        EquipItem  (self, MOD_AMULETTDESREISLORDS); 

        CreateInvItem (self, ItMi_Alchemy_Moleratlubric_01);
        //CreateInvItem (self,ItKey_RB_01);

        EquipItem (self, Ring_des_Lebens);

    //-------------Daily Routine-------------
    daily_routine = Rtn_start_900;

};

FUNC VOID Rtn_start_900 ()
{
    TA_Boss         (07,00,20,00,"NC_RICELORD");
    TA_SitAround    (20,00,24,00,"NC_RICELORD_SIT");
    TA_Sleep        (24,00,07,00,"NC_RICEBUNKER_10");
};

如您所见,实例声明更像是构造函数,从内部设置值和调用函数。如果不是另外一件事,这仍然不会造成太多问题:这个实例的多个副本。例如,你可以产生多个BAU_900_Ricelord,并且每个都跟踪它自己的AI状态,生命点等。

现在我认为实例在引擎内部表示为int(甚至可能是NPC的id),因为每当(在脚本中)使用表达式BAU_900_Ricelord时,它只能被赋值为int变量,以及在NPC上运行的大多数函数都采用该int值。但是要直接修改其生命值等,你必须做var C_NPC npc = GetNPC(Bau_900_Ricelord); npc.attribute[ATR_HITPOINTS] = 10;之类的事情,即得到代表它的实际C_NPC对象。

最后回顾一下 - 是否有可能在你所知道的任何脚本语言中获得这种行为,或者我不得不自己制作?或者也许有一种更好的方式来代表NPC及其行为。用于脚本编写的IDEAL语言将是C#,因为我只是喜欢这种语言,但不知何故我怀疑在C#中尝试实现类似的行为是可行的还是确实可行。

非常感谢

3 个答案:

答案 0 :(得分:3)

C#可以用作脚本语言。

除了c#之外,lua作为游戏脚本语言非常受欢迎

您的npc示例可以解决如下:

  • 创建基类npc
  • 继承npc类以创建具有特定特征/行为的自定义npc
  • 创建继承类的实例

答案 1 :(得分:1)

我会使用Javascript。我自己正在开发一款游戏引擎,用于实现Chrome中使用的V8 javascript引擎。它非常容易实现,Javascript是一种非常强大的语言,完全基于原型。

答案 2 :(得分:1)

我认为,虽然你希望语言支持3级/类实例,但如果你实际上只有1,那么它将有所帮助。

静态语言通常有两个级别 - 在编译时定义的“类”和在运行时从类创建的“实例”。这很有道理,因为确切地知道你想要预先确定多少个类是很实际的,并且通常不确切地知道有多少个实例。类成为千篇一律,实例是cookie。

但最终,抛开类和实例的概念是完全不同的,并认为一个类是一个东西,(a)允许你创造新的东西和(b)作为这些新东西应该如何应该的中心参考法案。那些事情反过来也可以创造新事物,等等。

在像C ++和Java这样的语言中,我们通常通过使用类构造函数定义的一组属性分配内存块来执行(a),并且(b)通过将一些引用保留回类的方法(例如,通过一个v-table)。但是你可以只复制一个对象,包括其中的所有方法引用,其中一个将是该对象的'实例'的构造函数。这是prototype-based programming并且提供了一个非常简单的继承模型,因为你的“类”与任何其他对象是一样的,除了它们提供了一种创建计为实例的新对象的方法。

恰巧世界上最流行的脚本语言 - 可能是世界上最流行的语言 - 为您提供原型继承。 Javascript就是我所指的,它是嵌入游戏中的一个非常好的选择,其优点是被开发人员广泛认可并且在今天非常积极地工作。网上有很多教程,但其中一个涉及各种继承方法的是here。可能需要一段时间才能习惯,特别是如果你来自传统的OO背景,并且有明确的课堂/实例部门,但是值得学习差异并评估自己的利弊。