Wie kann ich Smart Scripting in meinem Spiel implementieren?

18

Ich entwickle eine Spiel-Engine. Es soll eine Entität / Komponenten-basierte sein. Um mein Spiel selbst zu entwickeln, dachte ich daran, eine Skriptsprache zu verwenden, um die Entitäten tatsächlich zu erstellen.

Wenn ich beispielsweise eine Art Monster hinzufügen möchte, das für den Spieler aggressiv ist, handelt es sich um eine Einheit mit mehreren Komponenten. Diese Komponenten ändern sich mit dem Monstertyp. Wenn ich also 100 verschiedene Monstertypen in meinem Spiel habe, muss ich nicht für jeden von ihnen direkt in meinem Spielcode eine neue Methode erstellen.

Sollte ich eine Skriptsprache verwenden, um diese Entität in Bezug auf Komponenten zu beschreiben, oder gibt es etwas anderes, das besser funktionieren würde? Allgemeiner gesagt, wie soll ich in meinem Spiel Skripte verwenden?

Nathan
quelle
Für eine reine Entitätsbeschreibung können Sie nur XML oder ähnliches verwenden, ohne dass ein Skript erforderlich ist. Für das Skripting würde ich C # verwenden, aber nur, wenn Ihre Engine in .NET ist ...
Kikaimaru
@Kikaimaru C # ist keine Skriptsprache. Die Verwendung von lua ist eine bessere Idee oder eine andere Sprache, die in Ihre Engine eingebettet werden kann.
JDSweetBeat
@DJMethaneMan "C # ist keine Skriptsprache" hat keine Bedeutung. Es gibt absolut kein Problem, Skripts in C # in einem Spiel zu schreiben, das in C # geschrieben wurde, und etwas wie Roselyn zum Kompilieren zu verwenden ... Aber nach 4 Jahren würde ich json a verwenden Javascript anstelle von XML und C # :)
Kikaimaru

Antworten:

17

Mein Spiel verwendet ein Entity-Komponenten-Framework und verwendet Skripte, um Entities zu definieren (dies definiert das Verhalten nicht direkt, ich werde am Ende mehr darüber sprechen). Die Skripte definieren die tatsächlichen Komponenten, die zum Erstellen jeder Entität verwendet werden sollen. Es verwendet eine einfache Skriptsprache, die ich erstellt habe. Hier ist eine vereinfachte Version eines meiner Skripte:

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
    }
}

Vieles davon ist selbsterklärend, aber hier sind einige Highlights:

  • Der erste Abschnitt beschreibt die allgemeinen Informationen für die Entität. Dazu gehören eine Beschreibung und Anzeigenamen für verschiedene Aspekte der Entität.
  • Das baseAttributesTag verweist auf eine andere Skriptdatei, die allgemeine Komponenten definiert, die nicht mehrmals neu definiert werden müssen. Es enthält Komponenten wie position, liferequirementsund so weiter. Wenn eine Komponente hier erneut definiert wird, überschreibt diese Komponente die gemeinsame Komponente.
  • Jeder [NAME] { }Satz definiert eine neue Komponente, die diesen Entitäten hinzugefügt wird.
  • Diese Beschreibung gilt nicht nur für eine einzelne Entität , sondern für alle erstellten Goblins. Sie werden sehen, dass einige der Werte Bereiche haben (dh 0.01:0.015), wenn ein neuer Goblin erstellt wird, wird er mit einer Komponente erstellt, die einen zufälligen Wert in diesem Bereich hat. So wird jeder Goblin etwas andere Fähigkeiten und etwas andere Geschwindigkeiten haben. Dieses Setup definiert, dass alle Goblins mit wirklich guten Fähigkeiten beim Platzieren von Würfeln und beim Bergbau beginnen, was eigentlich nur für meine eigenen Testzwecke ist. Aber wie Sie sicher erraten können, ist es sehr einfach, die Werte in die von mir gewünschten Werte zu ändern.

Das Ganze beinhaltet die Erstellung eines benutzerdefinierten Parsers, einer Art Struktur für die Entitätsdefinitionen (ich nenne sie das Lexikon!) Und einer Factory für die Aufnahme dieser Entitätsdefinitionen und die Generierung neuer Entitäten. Für mich ist dieses System noch in den Anfängen, aber es entwickelt sich wirklich sehr, sehr gut. Es ist ein ziemlich leistungsfähiges System zum schnellen Definieren von Entitäten und ermöglicht es Ihnen, jede gewünschte Entität mit den von Ihnen erstellten Komponenten zu erstellen. Wenn Sie nicht gerne Ihren eigenen Parser erstellen, funktioniert XML meiner Meinung nach einwandfrei. Ich habe meinen von einem rekursiven Pushback-Parser konvertiert, den ich für eine kleine erfundene Programmiersprache geschrieben habe.

Wie Sie sehen, definiert dies die Entität. Ich erwähnte, dass es das Verhalten nicht direkt definiert. Es kann jedoch leicht Dinge wie gehasste Feinde definieren und wie aggressiv man auf diese Feinde reagiert. Dies ist so einfach wie die Definition der Komponenten, mit denen Sie dieses Verhalten steuern. Meine Entitäten haben auch eine Nachrichtenkomponente (nicht gezeigt), die Folgendes definiert:

  • Wie sie den Weg finden (einfache Sichtlinienbewegung, einfaches A *, voraussagendes A * usw.)
  • Wie aggressiv / defensiv sie sind. Entitäten können Heimatzonen haben, die verteidigt werden, aber außerhalb dieser Zonen möglicherweise nicht aggressiv sind.
  • Technologiebewusstsein (Türen öffnen, Geräte verwenden, Fallen meiden usw.)
  • Und mehr...

Wie auch immer Ihre definiert ist, es ist Ihr System, das die Daten in dieser Komponente steuert, was sich wiederum auf das Verhalten Ihrer Entitäten auswirkt.

MichaelHouse
quelle
Danke für das Teilen. Ich denke tatsächlich, ich werde versuchen, es mit XML-Format zu tun. Ich habe viel darüber nachgedacht (dank AbstractChaos übrigens) und es sollte meine Bedürfnisse erfüllen (zumindest für Entitätsbeschreibungen).
Nathan
1
@ Nathan Ich bin damit einverstanden, dass Sie mit XML gehen sollten. Der Grund für meinen Beitrag war eher, welche Daten in Ihr XML aufgenommen werden sollen und wie man sie verwendet. Das Format der Daten kann beliebig sein. Die Daten, die Sie aufnehmen möchten, und die Art und Weise, wie Sie ihre Verwendung implementieren, sind weitaus wichtiger.
MichaelHouse
@ Byte56 Ich weiß, dass dieser Beitrag alt ist, aber wie könnten Sie mit Eltern-Kind-Beziehungen umgehen? Angenommen, wir haben einen Fähigkeitsbaum und Sie benötigen 10 Punkte in Fähigkeit A [0], um A [1] zu aktivieren, und 10 Punkte, um A [2] zu aktivieren Eltern ID? Natürlich sind sie logisch gleichwertig, aber ich hatte gehofft, Sie hatten einen Einblick in die reale Welt.
Superstringcheese
@ Superstringcheese if player.hasPoints(10) then i++ end skillTree[i]wäre ein Pseudocode. Ich habe jedoch keine Ahnung, wie wichtig diese Frage für den Beitrag ist.
JDSweetBeat
4

Wenn Sie nur die Komponenten eines Monsters definieren möchten, funktioniert XML sehr gut. Sowohl C # als auch Java lassen sich blitzschnell implementieren.

Dein xml könnte sein

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

Dann könnte deine Mob-Klasse so aussehen. (Java)

public class Mob {
  private IPersonality personality;
  private Integer intelligence

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

Wobei IPersonality eine Schnittstelle ist.

Sie können dann Ihre XML-Datei laden und jeden Wert über eine Factory analysieren.

Analysieren Sie zum Beispiel den Personality Value in die PersonalityFactory. Dies ist einfach:

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; 
  }
}

Dann könnten Sie so einen Mob aufbauen

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

Der Schlüssel ist, dass Ihre Engine das Format der XML kennt und eine Factory für alles hat, was sie benötigt.

Ein Vorteil von XML ist, dass Sie Ihr eigenes Schema definieren können, um sicherzustellen, dass das Format immer korrekt ist (siehe hier) .

Hoffe das hilft

AbstractChaos
quelle
Eigentlich muss ich einen Weg finden, um im Spielentwicklungsprozess auf einfache Weise eine neue Entität zu erschaffen. Ist XML flexibel genug? Ich muss sowieso Skripte für die interne Spielelogik hinzufügen.
Nathan
Wenn Sie die Mob-Klasse als Entität lesen, erstellen Sie eine neue Enitity (Mob) unter Verwendung von XML mit verschiedenen Komponenten (IPersonality, Intelligence [Beispiel für Daten für diesen Mob]). Und leider kann ich nicht antworten, ob es flexibel genug ist, da ich nicht weiß, was Sie mehr wollen als das, was Sie angegeben haben. XML ist jedoch ein Format, bei dem die einzigen Einschränkungen darin bestehen, wie Sie jeden Abschnitt interpretieren. Aktualisiere deine Frage mit einem detaillierten Beispiel und ich zeige eine XML, die damit umgehen kann. Interne Spiellogik klingt wie es sollte intern sein?
AbstractChaos
0

Python ist in Ordnung, denke ich. Oft ist LUA auch eine gute Alternative, wenn Sie Ihren Programmen Skriptfunktionen hinzufügen möchten.

Sie könnten entweder XML verwenden, um das Verhalten Ihrer Monster zu beschreiben. Dies würde eine Codierung im tatsächlichen Spielcode erfordern, da Sie nur den "Namen" oder einige Attribute entsprechend dem Verhalten (Geschwindigkeit, Art der vom Monster verwendeten Waffe, etc.) des Verhaltens in Ihrem Spielcode zu verwenden.

Wenn Sie eine Scriptengine (zB LUA) verwenden, können Sie diesen Code aus Ihrem vorkompilierten Programm in Skriptdateien übertragen, die zur Laufzeit geladen werden. Dazu musst du die API deiner "Monster" der Scriptengine aussetzen. Damit können Sie die Methoden des Monster-Game-Codes von außen aufrufen.

Aron_dc
quelle
Die API meines Monsters? Ich meine, ich muss in der Lage sein, neue Komponenten aus dem Skript zu erstellen (Instanziierung). Ist es möglich?
Nathan
Afaik sollte dies möglich sein. Sie können auch einen gemischten Ansatz aus externem Speicher (wie in abstractchaos oder byte56 erwähnt) und Skriptsprache (LUA, Python ...) verwenden. Der Hauptvorteil von zB LUA ist, dass Sie Ihren Code zur Laufzeit ändern können und er sofort in Ihrem laufenden Spiel / Ihrer laufenden Engine verfügbar ist
Aron_dc
Ernsthaft? Das ist in der Tat ein großer Vorteil. Ich habe aber auch LUA (oder eine andere Skriptsprache) für "Spiel Timeline". Ich meine, um einige szenarisierte Szenen zu erstellen, in denen der Player blockiert werden muss, muss sich dieses Sprite hier bewegen, hier und da beleuchten ... Vielleicht könnte ich auch eine Skriptsprache zum Laden von Entitäten verwenden? Außerdem werde ich eine weitere Frage stellen, um meine derzeitige Art der Verwaltung von Entitäten / Komponenten über das, was ich als "Manager" bezeichne, darzulegen, um zu sehen, ob es mir gut geht.
Nathan