¿Cómo puedo implementar scripting inteligente en mi juego?

18

Estoy desarrollando un motor de juego. Se supone que se basa en una entidad / componentes. Para desarrollar mi juego, pensé en usar un lenguaje de script para crear las entidades.

Por ejemplo, si quiero agregar un tipo de monstruo que sea agresivo para el jugador, será una entidad con varios componentes; esos componentes cambiarán con el tipo de monstruo, por lo que si tengo cien tipos diferentes de monstruos, en mi juego, no tendré que crear un nuevo método para cada uno de ellos directamente en mi código de juego.

¿Debo usar un lenguaje de scripting para describir esta entidad, en términos de componentes o hay algo más que funcione mejor? En términos más generales, ¿cómo debo usar las secuencias de comandos en mi juego?

Nathan
fuente
Solo para la descripción de la entidad, puede usar solo xml o algo similar, sin necesidad de secuencias de comandos. Para las secuencias de comandos, usaría C #, pero solo si su motor está en .NET ...
Kikaimaru
@Kikaimaru C # no es un lenguaje de script. Usar lua sería una mejor idea, o algún otro lenguaje que pueda integrarse en su motor.
JDSweetBeat
@DJMethaneMan "C # no es lenguaje de scripts" no significa nada, no hay absolutamente ningún problema con escribir scripts en C # en un juego escrito en C # y usar algo como Roselyn para compilar ... Pero después de 4 años, usaría json a javascript en lugar de xml y C # :)
Kikaimaru

Respuestas:

17

Mi juego usa un marco de componentes de entidad y usa scripts para definir entidades (esto no define directamente el comportamiento, hablaré más sobre eso al final). Los scripts definen los componentes reales que se utilizarán para crear cada entidad. Utiliza un lenguaje de script simple que creé. Aquí hay una versión simplificada de uno de mis scripts:

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

Gran parte de eso se describe a sí mismo, pero aquí hay algunos aspectos destacados:

  • La primera sección describe la información común para la entidad. Eso incluye una descripción y nombres para mostrar para varios aspectos de la entidad.
  • La baseAttributesetiqueta hace referencia a otro archivo de script que define componentes comunes que no quiero tener que redefinir varias veces. Contiene componentes como position, liferequirementsetc. Si algún componente se define aquí nuevamente, este componente sobrescribirá el común.
  • Cada [NAME] { }conjunto define un nuevo componente que se agregará a estas entidades.
  • Esta descripción no es solo para una sola entidad , es para todos los duendes creados. Verá que algunos de los valores tienen rangos (es decir 0.01:0.015), cuando se crea un nuevo duende se crea con un componente que tiene un valor aleatorio en ese rango. Por lo tanto, cada duende tendrá habilidades ligeramente diferentes y velocidades ligeramente diferentes. Esta configuración define que todos los duendes comenzarán con habilidades realmente buenas para colocar cubos y minar, lo cual es solo para mis propios fines de prueba. Pero como estoy seguro de que puedes adivinar, es muy fácil cambiar los valores a lo que quiera.

Todo esto implica crear un analizador personalizado, algún tipo de estructura para contener las definiciones de entidad (¡yo llamo el mío, el Léxico!) Y una fábrica para tomar esas definiciones de entidad y generar nuevas entidades. Para mí, este sistema todavía está en sus primeras etapas, pero está resultando muy, muy bien. Es un sistema bastante poderoso para definir entidades rápidamente y le permite crear cualquier entidad que desee utilizando los componentes que ha creado. Si no se siente cómodo creando su propio analizador, creo que XML funcionará bien. Convertí el mío de un analizador recursivo pushback que escribí para un pequeño lenguaje de programación inventado.

Como puede ver, esto define la entidad. Mencioné que no define directamente el comportamiento. Sin embargo, puede definir fácilmente cosas como enemigos odiados y qué tan agresivamente reaccionar ante dichos enemigos. Esto sería tan simple como definir cualquier componente que use para controlar dicho comportamiento. Mis entidades también tienen un componente de inteligencia (no mostrado) que define cosas como:

  • Cómo encuentran el camino (movimiento simple de línea de visión, A * simple, A * predictivo, etc.)
  • Qué agresivos / defensivos son. Las entidades pueden tener zonas de origen que serán defendidas, pero tal vez no sean agresivas fuera de esas zonas.
  • Conocimiento de la tecnología (abrir puertas, usar dispositivos, evitar trampas, etc.)
  • Y más...

Independientemente de cómo se defina el suyo, es su sistema el que manejará los datos en ese componente, lo que a su vez afecta el comportamiento de sus entidades.

MichaelHouse
fuente
Gracias por compartir. De hecho, creo que voy a intentar hacerlo usando el formato XML. He pensado mucho en eso (gracias a AbstractChaos por cierto) y debería satisfacer mis necesidades (al menos para las descripciones de las entidades).
nathan
1
@nathan Estoy de acuerdo en que debes ir con XML. La razón de mi publicación fue más qué datos incluir en su XML y cómo usarlos. El formato de los datos puede ser lo que quieras. La información que elige incluir y cómo implementa su uso es mucho más importante.
MichaelHouse
@ Byte56 Sé que esta publicación es antigua, pero ¿cómo podría manejar las relaciones entre padres e hijos? Digamos que tenemos un árbol de habilidades y necesitas 10 puntos en la habilidad A [0] para habilitar A [1], y 10 puntos en eso para habilitar A [2], etc. ¿Debo anidarlos, o aplanarlos y teclear un ¿Identificación de los padres? Obviamente son lógicamente equivalentes, pero esperaba que tuvieras alguna idea del mundo real.
Superstringcheese
@Superstringcheese if player.hasPoints(10) then i++ end skillTree[i]sería un pseudocódigo. Sin embargo, no tengo idea de cómo esa pregunta es relevante para la publicación.
JDSweetBeat
4

Si todo lo que realmente necesita es una forma de definir los componentes de un Monstruo, entonces XML funcionaría bien, tanto C # como Java tienen una implementación increíblemente rápida.

Tu xml podría ser

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

Entonces su clase Mob podría verse así. (Java)

public class Mob {
  private IPersonality personality;
  private Integer intelligence

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

Donde IPersonality es una interfaz.

Luego puede cargar su xml y analizar cada valor a través de una fábrica.

por ejemplo, analizar el valor de personalidad en la fábrica de personalidad que es simplemente:

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

Entonces podrías crear una mafia así

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

La clave es que su motor conoce el formato del xml y tiene una fábrica para todo lo que necesita.

Una ventaja de xml es que puede definir su propio esquema para asegurarse de que el formato sea siempre correcto. Consulte aquí .

Espero que esto ayude

AbstractChaos
fuente
En realidad, necesito encontrar una manera de crear fácilmente una nueva entidad sobre el proceso de desarrollo del juego. ¿Es xml lo suficientemente flexible? Necesitaré agregar secuencias de comandos de todos modos para la lógica interna del juego.
nathan
Si lee la clase Mob como Entity, entonces está creando una nueva Enitity (Mob) usando XML con diferentes componentes (IPersonality, Intelligence [ejemplo de datos para esa mafia]). Y desafortunadamente no puedo responder si será lo suficientemente flexible, ya que no sé qué más desea que haga además de lo que especificó. Sin embargo, XML es un formato donde los únicos límites son cómo interpreta cada sección. Actualice su pregunta con un ejemplo detallado y le mostraré un xml que puede manejar eso. ¿Parece que la lógica interna del juego debería ser interna?
AbstractChaos
0

Python está bien, creo. A menudo, LUA también es una buena alternativa si desea agregar capacidades de secuencias de comandos a sus programas.

Puedes usar XML para describir el comportamiento de tus monstruos, esto implicaría algo de codificación en el código del juego real porque guardarás solo el "nombre" o algunos atributos de acuerdo con el comportamiento (velocidad, tipo de arma que usa el monstruo, etc.) del comportamiento a utilizar en su código de juego.

Si utiliza un Scriptengine (por ejemplo, LUA), puede transferir este código desde su programa precompilado a los archivos de script que se cargan durante el tiempo de ejecución. Para hacer esto, debe exponer la API de sus "monstruos" al scriptengine. Eso le permite llamar a los métodos del código del juego de monstruos desde el exterior.

Aron_dc
fuente
¿La API de mi monstruo? Quiero decir, tendré que poder crear nuevos componentes a partir del script (instanciación). ¿Es posible?
nathan
Afaik esto debería ser posible. También podría utilizar un enfoque mixto de almacenamiento externo (como se menciona en abstractchaos o byte56) y lenguaje de script (LUA, Python ...). La principal ventaja de, por ejemplo, LUA es que puede cambiar su código en tiempo de ejecución y está disponible instantáneamente en su juego / motor en
ejecución
Ho en serio? Es una gran ventaja de hecho. También he pensado en LUA (u otro lenguaje de script) para la "línea de tiempo del juego". Quiero decir, para crear algunas escenas en las que el jugador tiene que ser bloqueado, este sprite tiene que moverse aquí, iluminar aquí y allá ... Entonces, ¿tal vez también podría usar un lenguaje de script para cargar entidades? También voy a publicar otra pregunta para exponer mi forma actual de administrar entidades / componentes sobre lo que llamo "gerente" para ver si me está yendo bien.
nathan