如何在游戏中实现智能脚本编制?


18

我正在开发一个游戏引擎。它应该是一个基于实体/组件的实体。为了开发游戏本身,我想使用某种脚本语言来实际创建实体。

例如,如果我想添加一种对玩家具有侵略性的怪物,它将是一个具有多个组成部分的实体。这些组件会随着怪物类型的变化而变化,因此,如果我有一百种不同类型的怪物,那么在我的游戏中,我就不必直接在游戏代码中为每个怪物创建新的方法。

我应该使用脚本语言来描述该实体,还是使用组件?更一般而言,我应该如何在游戏中使用脚本?


仅用于实体描述,您可以仅使用xml或类似内容,而无需编写脚本。对于脚本编写,我将使用C#,但
前提

@Kikaimaru C#不是脚本语言。使用lua可能是一个更好的主意,或者使用其他可以嵌入到引擎中的语言。
JDSweetBeat

@DJMethaneMan“ C#不是脚本语言”没有任何意义,在用C#编写的游戏中用C#编写脚本并使用诸如Roselyn之类的东西进行编译绝对没有问题...但是4年后,我会使用json a javascript而不是xml和C#:)
Kikaimaru '16

Answers:


17

我的游戏使用实体组件框架并使用脚本来定义实体(这不会直接定义行为,我将在最后详细讨论)。脚本定义了用于创建每个实体的实际组件。它使用我创建的简单脚本语言。这是我的脚本之一的简化​​版本:

ENTITY:"Goblin"
{
    description="It's currently their age."
    commonname="goblin"
    pluralCommonName="goblins"
    childname="gob'in"
    pluralChildName="gob'ins"
    active=Nocturnal
    tags=Mobile
    baseAttributes="OrganicMobileCreature"

    [Model]{
            meshname="Goblin"
            texturename="GoblinTexture"
    }

    [Motion]{
            maxvelocity=0.01:0.015
            locomotion=Walk,Swim
    }

    [Skills]{
            ALL=0.01:0.05,Mine=8.3:8.8,PlaceCube=8.3:8.8
    }

    [Inventory]{
            maxItems=2
            Allow=ALL
            Disallow=NONE
    }
}

其中大部分是自我描述,但以下是一些要点:

  • 第一部分描述了实体的公共信息。其中包括实体各个方面的描述和显示名称。
  • baseAttributes标记引用了另一个脚本文件,该文件定义了我不想多次重新定义的通用组件。它包含类似的组件positionliferequirements依此类推。如果再次在此处定义任何组件,则此组件将覆盖通用组件。
  • 每个[NAME] { }集合都定义了一个将添加到这些实体的新组件。
  • 此描述不仅针对单个实体,还针对创建的所有地精。您会看到其中一些值具有范围(即0.01:0.015),当创建新的妖精时,它将使用具有该范围内随机值的组件来创建。因此,每个妖精的技能和速度都会略有不同。此设置定义了所有妖精将具有放置立方体和挖掘的非常好的技能,这实际上只是出于我自己的测试目的。但是,我敢肯定,您可以猜到,将值更改为我想要的值非常容易。

这整个过程包括创建一个自定义解析器,某种用于保存实体定义的结构(我称我的Lexicon!)和一个用于获取这些实体定义并生成新实体的工厂。对我来说,该系统仍处于早期阶段,但事实证明它确实非常好。这是一个非常强大的系统,用于快速定义实体,并允许您使用创建的组件来创建所需的任何实体。如果您不愿意创建自己的解析器,我认为XML会很好地工作。我将我的推后递归解析器转换为我自己,该解析器是用某种编成的编程语言编写的。

如您所见,这定义了实体。我提到它并没有直接定义行为。但是,它可以轻松地定义诸如仇恨的敌人以及对所述敌人的反应有多积极。这就像定义用于控制此类行为的任何组件一样简单。我的实体还具有定义以下内容的智能组件(未显示):

  • 他们如何找到路径(简单的视线移动,简单的A *,预测性A *等)
  • 他们有多进取/防守。实体可以拥有将要防御的家乡区域,但在这些区域之外可能不是好斗的。
  • 技术意识(开门,使用小工具,避免陷阱等)
  • 和更多...

无论您的定义如何,都是系统驱动该组件中的数据,从而影响实体的行为。


感谢分享。我实际上认为我将尝试使用XML格式来做到这一点。我对此深思熟虑(感谢AbstractChaos btw),它应该满足我的需求(至少对于实体描述而言)。
森2012年

1
@nathan我同意您应该使用XML。我发表这篇文章的原因更多是要在XML中包含哪些数据以及如何使用它们。数据的格式可以是您喜欢的任何格式。您选择包括的数据以及如何实现其使用更为重要。
MichaelHouse

@ Byte56我知道这篇文章很旧,但是您将如何处理亲子关系?假设我们有一棵技能树,您需要在技能A [0]中获得10点才能启用A [1],而在其中需要获得10点才能启用A [2],依此类推。我应该嵌套它们,还是将它们展平并在ParentId?显然,它们在逻辑上是等效的,但我希望您对现实世界有所了解。
Superstringcheese 2015年

@Superstringcheese if player.hasPoints(10) then i++ end skillTree[i]将是一些伪代码。但是,我不知道该问题与该职位有何关系。
JDSweetBeat '16

4

如果您真正需要的只是一种定义Monster组件的方法,那么XML可以很好地在C#和Java上快速实现。

您的xml可能是

<?xml version="1.0" encoding="UTF-8"?>
<mobs>
  <mob>
    <personality>Aggressive</personality>
    <intelligence>20</intelligence>
  </mob>
</mobs>

然后您的Mob类可能看起来像。(Java)

public class Mob {
  private IPersonality personality;
  private Integer intelligence

  //**  Getters & Setters **//
}

IPpersonality是接口。

然后,您可以加载xml并通过工厂解析每个值。

例如,将Personality Value解析到PersonalityFactory中,这很简单:

public IPersonality getPersonality(String personalityName) {
  if(personalityName.equals("Aggressive")) {
    return new AggressivePersonality();
  }
  else if(personalityName.equals("Passive")) {
    return new PassivePersonality();
  }
  else {
     //Maybe allow for no personality (We all know monster like that ;) )
     return null; 
  }
}

然后你可以像这样建立暴民

Mob mob = new Mob();
mob.setPersonality(getPersonality(xmlValue));
mobList.add(mob);

关键是您的引擎知道xml的格式,并拥有所有需要的工厂。

xml的优点之一是您可以定义自己的模式以确保格式始终正确,请参见此处

希望这可以帮助


实际上,我需要找到一种在游戏开发过程中轻松创建新实体的方法。xml是否足够灵活?无论如何,我将需要为内部游戏逻辑添加脚本。
森2012年

如果将Mob类读为Entity,则将使用具有不同组件(IPersonality,Intelligence [该mob的数据示例])的XML创建新的Enitity(Mob)。不幸的是,我不能回答它是否足够灵活,因为除了您指定的内容外,我不知道您希望它做些什么。但是XML是一种格式,其中唯一的限制就是您如何解释每个部分。用详细的示例更新您的问题,我将显示可以处理该问题的xml。内部游戏逻辑听起来应该是内部的?
AbstractChaos

0

我认为Python很好。如果要向程序中添加脚本功能,则LUA通常也是不错的选择。

您可以使用XML来描述怪物的行为,这将涉及实际游戏代码中的一些编码,因为您将根据行为(速度,怪物使用的武器类型,等)在您的游戏代码中使用的行为。

如果使用脚本引擎(例如LUA),则可以将此代码从预编译程序转移到运行时加载的脚本文件中。为此,您必须将“怪物”的API公开给脚本引擎。这样您就可以从外部调用怪物游戏代码的方法。


我的怪物的API?我的意思是,我将必须能够从脚本(实例化)创建新组件。可能吗?
森2012年

Afaik这应该是可能的。您还可以使用外部存储(如abstractchaos或byte56所述)和脚本语言(LUA,Python ...)的混合方法。例如,LUA的主要优点是您可以在运行时更改代码,并且可以在正在运行的游戏/引擎中立即使用它
Aron_dc 2012年

呵呵认真吗?确实,这是一个巨大的优势。我也有LUA(或其他脚本语言)的“游戏时间表”。我的意思是,要创建一些必须阻止玩家的场景,必须将此精灵移动到这里,到处晃动……所以也许我也可以使用脚本语言来加载实体?另外,我还将发布另一个问题,以公开我目前所谓的“经理”管理实体/组件的方式,以查看我是否做得很好。
森2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.