L'implementazione del proprio linguaggio di scripting è praticabile?


21

Sto programmando un picchiaduro in C ++ ed è giunto il momento di implementare lo scripting per eventi, trigger, filmati ecc. Ho letto su Internet e ho ottenuto un bel po 'di informazioni. La mia soluzione di prima scelta sarebbe quella di implementare il mio linguaggio di scripting come quello di Cave Story . Ho visto questo suggerito, ma la maggior parte delle persone suggerisce lua ma questo non sembra adattarsi al mio tipo di programmazione.

Hai creato il tuo linguaggio di scripting? Perché hai scelto di arrotolare il tuo invece di usarne uno esistente? Quali risorse hai consultato durante lo sviluppo?


43
La mia regola personale è: se hai bisogno di chiedere ad altre persone se è una buona idea lanciare il tuo _____, allora non è una buona idea.
Sam Hocevar,

2
Nota che se implementi la tua lingua, le persone devono impararla e sperare che non ci siano bug nel tuo interprete, mentre le lingue come Lua sono più popolari e molto meno propense ad avere bug.
Nick Caplinger,

2
@NickCaplinger lo colpisce in testa. Rotolare da solo significa che non c'è documentazione, comunità, tutorial di terze parti, StackExchange, ecc. Qualunque piccolo progresso nella sintassi o integrazione sarà compensato dalla mancanza di supporto a meno che tu non sia uno sviluppatore molto noto con milioni di fan.
Sean Middleditch,

4
Tieni presente anche gli strumenti. Questo è il mio problema con D, Rust, Dart, ecc. La tua sintassi è inutile da sola. È necessario un editor appropriato, l'evidenziazione, "Intellisense" (completamento del codice), una buona diagnostica, supporto per il refactoring, supporto per la documentazione in linea, ecc. Per valere davvero qualsiasi cosa. Per non parlare di tutte le funzionalità linguistiche, integrazione, efficienza e così via.
Sean Middleditch,

1
Se sei un programmatore C ++ e non ti piace LUA, prova invece JavaScript.
zeel

Risposte:


42

No. Almeno, probabilmente no.

Questo è un caso molto frequente di reinventare la ruota è lo sviluppo del gioco, un errore che è ancora abbastanza popolare.

Se stai ponendo questa domanda, molto probabilmente sarai influenzato da ciò che fanno gli altri, quindi dai un'occhiata a ciò che Epic Games ha appena fatto con Unreal Engine:

  • UE3 aveva un oggetto UnrealScript personalizzato, strano, non ottimizzato, difficile da eseguire il debug,
  • Se la voce è vera, il suo supporto viene rimosso in UE4 , a favore di DLL C ++ ricaricabili a caldo.

Pensi di poter fare meglio di Epic?

La creazione di linguaggi di programmazione appartiene ai creatori di linguaggi di programmazione , non agli ingegneri di gioco.

Ci vogliono anni e anni prima che una lingua diventi completamente matura e che il relativo set di strumenti (compilatore, linker, interprete, debugger ...) sia utilizzabile. Al giorno d'oggi hai molte soluzioni disponibili a portata di mano, quindi non c'è assolutamente alcun motivo reale per iniziare una nuova cosa da zero, almeno non se l'obiettivo è semplicemente quello di fare un gioco. Periodo.

Per rispondere alle tue domande secondarie, no, proprio per questi motivi non ho mai implementato il mio linguaggio di scripting. Ma ho sofferto molto con alcuni semi-cotti. Poiché sono stati creati pensando a una funzionalità molto ristretta, hanno sempre avuto queste piccole stranezze folli che ti fanno impazzire. Spesso ti ritroverai a passare moltissimo tempo a cercare di aggirare i limiti della lingua invece di creare il tuo gioco.

Se il motivo si desidera creare una lingua è, perché è destinato all'uso da parte di persone che non conoscono la programmazione molto bene, o se credete avete bisogno perché si vuole qualcosa di molto Domain-Specific, lasciate che vi dica queste sono anche cattive ragioni. È possibile scrivere un'API di livello molto elevato con funzioni che do_what_they_say_and_say_what_they_do()e un codice della caldaia molto semplice che ne espone l'utilizzo di base. I tuoi utenti non così tecnici saranno felici di imparare un po 'di programmazione e sarai felice di non essere limitato da un linguaggio mal implementato.

Quindi, dato che questo sembrerà un po 'brusco o addirittura duro, dirò che c'è un caso in cui potrebbe avere senso: se vuoi imparare come è fatto un linguaggio di scripting. Ma per favore, per favore, se lo fai: non forzare gli altri a usarlo.

modificare

Ho appena dato un'occhiata all'elenco dei comandi di Cave Story che hai collegato. Ahia:

<ECJx:y      [EC?] Jump           @ Jump to event Y if any npc with ID X is present

Non voglio mostrare mancanza di rispetto allo sviluppatore dietro Cave Story, ma questo è un perfetto esempio di un semplice elenco di comandi mutato in un linguaggio di scripting personalizzato incontrollabile. Questo potrebbe essere ancora utilizzabile per un singolo sviluppatore o un team molto piccolo, ma in questa fase ti consiglio di passare a un linguaggio completo e ben collaudato di Turing (ad esempio Lua), dove puoi fare:

if (npc.id == x) then
    jump_to_event(y)
end

Ciò renderà le cose molto più facili quando, ad esempio, avrai bisogno di una condizione più complessa:

if (npc.id == x) or (npc.type == "enemy") then
    jump_to_event(y)
end

21
+1 "La creazione di linguaggi di programmazione appartiene ai creatori di linguaggi di programmazione, non agli ingegneri di gioco." Questa citazione non potrebbe essere più corretta. Avendo preso una lezione di concetti di linguaggio di programmazione insegnata da un ragazzo che era un mago con linguaggi di programmazione, queste persone sono una razza diversa. Una lezione mi ha fatto capire la quantità di teoria e matematica del CS che vanno alla creazione di un vero linguaggio di programmazione. Questo mi ha fatto apprezzare ancora di più queste persone e le loro competenze. Mi lasciano creare i giochi, resto fuori dai piedi e faccio loro creare le lingue.
Dean Knight,

+1, non conosco lua o il linguaggio di scripting personalizzato, ma era evidente esattamente cosa stava succedendo in lua ed è qui che l'usabilità è importante
RhysW,

1
Non c'è niente di magico nell'uno o nell'altro che rende impossibile imparare entrambi. Unreal sta forse rimuovendo UnrealScript ma stanno migliorando e completando notevolmente Kismet per essere un linguaggio di scripting visivo completo e capace. Non hanno rimosso UnrealScript perché è un errore, lo stanno rimuovendo perché è superato da caratteristiche significativamente più difficili (C ++ con ricarica a caldo, Kismit aggiornato). Non prendere questo per dire che non sono d'accordo con il tuo punto: scrivere la tua lingua è una grande perdita di tempo, una fonte di bug e una causa di grandi curve di apprendimento, ecc.
Sean Middleditch,

2
@ ott-- Non temo neanche, il mio punto è che espandere questa notazione renderà sempre più complicata, mentre l'uso di un linguaggio appropriato in primo luogo aiuterà a lungo termine. Il sovraccarico non è rilevante rispetto alla facilità d'uso in quel caso, IMHO.
Laurent Couvidou,

1
Nota che UnrealScript è sostituito da Blueprints (ma ho scommesso che i miei colleghi torneranno). Hotloading DLL è una funzionalità ortogonale.
sam hocevar,

9

Hai creato il tuo linguaggio di scripting e perché hai scelto di usare il tuo linguaggio invece di usarne uno esistente?

Ho, anche se ho preso in prestito la sintassi da altre lingue. Tutto sommato è stata una grande esperienza di apprendimento e nel mio caso non così difficile perché la lingua era semplice.

L'ho fatto principalmente perché volevo usare una normale sintassi in stile C per i miei script, poiché tutti i membri del team lo conoscevano.

Mi interessava anche imparare un po 'sull'implementazione dei linguaggi di programmazione e dato che avevo solo bisogno di un sottoinsieme molto semplice di funzionalità (variabili, aritmetica, condizionali, loop e chiamate in-game funzioni o coroutine) ho deciso di provarlo.

Quali risorse hai consultato durante lo sviluppo?

La mia risorsa principale era questo libro:

inserisci qui la descrizione dell'immagine

Sono riuscito a imparare abbastanza da questo libro per implementare:

  • Un lexer: che era quasi banale usando le espressioni regolari, semplicemente usando Regex.Match per identificare e dividere i token.
  • Un parser di discesa ricorsivo: sostanzialmente una funzione per ciascuna regola della grammatica e alcuni metodi di supporto per guardare avanti e consumare i token. Ho preso in considerazione le specifiche grammaticali C # per l'ispirazione. La parte più difficile riguardava l'aritmetica e le precedenti delle relazioni con gli operatori senza andare in una ricorsione infinita.
  • Un interprete AST: usando il modello di progettazione del visitatore, ho attraversato l'albero generato dal parser ed eseguito ricorsivamente ogni nodo di istruzione.

Mi sarei fermato lì poiché quasi tutto ciò di cui avevo bisogno stava già funzionando, tranne una cosa: chiamare e cedere alle coroutine Unity3D in profondità dall'interprete ricorsivo. Per risolvere quel problema, ho dovuto sbarazzarmi della ricorsione e mi sono rivolto di nuovo al libro. Questa volta ho finito per aggiungere:

  • Un compilatore: un altro visitatore, ma invece di eseguire il codice, genera un elenco di piccole istruzioni atomiche da ciascun nodo dell'AST (ovvero un semplice linguaggio di assemblaggio personalizzato basato su stack). Operazioni come un ciclo while o una condizione if vengono convertite in etichette e istruzioni goto-type. A questo punto scrivo anche lo script compilato su disco come file binario.
  • Un interprete bytecode: scorre semplicemente su un elenco semplice di istruzioni. Senza la ricorsione era ora facile integrarsi con le coroutine Unity3D.

L'intero processo è durato circa 2 settimane da zero conoscenze ed è stato molto divertente :)

PS: Alla fine volevo anche aggiungere l'evidenziazione della sintassi e l'intellisense per il mio linguaggio personalizzato sui nostri strumenti. Scintilla ha salvato la vita in questo senso. Ho usato il seguente wrapper:

http://scintillanet.codeplex.com/


5

Ho visto questo suggerito, ma la maggior parte delle persone suggerisce lua ma questo non sembra adattarsi al mio tipo di programmazione.

OK, proviamo questo da una prospettiva diversa: cosa ti piace di Lua che non ti piace? È qualcosa che è facilmente risolvibile o è qualcosa di fondamentale?

Ad esempio, utilizzare parole chiave come then/do/endper indicare il blocco di codice anziché le parentesi graffe in stile C / C ++. Se questo è il tuo problema ... è qualcosa che puoi risolvere. Tutto quello che devi fare è definire il tuo piccolo dialetto di Lua e scrivere un semplice strumento di trasformazione che convertirà la sintassi del parentesi graffa in Lua reale.

Vuoi + = in qualche forma? È anche qualcosa che puoi facilmente fare in un sistema di pre-elaborazione. Trasforma semplicemente le dichiarazioni del modulo expr1 += expr2in expr1 = expr1 + expr2.

Certo, dovrai trovare un modo per rilevare se una coppia di parentesi graffe rappresenta una tabella o una do/endcoppia. E che avrebbe dovuto collegare il sistema di pre-elaborazione in Lua da imperativi dofile, loadstringe altre funzioni della libreria standard Lua. Ma alla fine è tutto fattibile.

Se i piccoli problemi di questo tipo sono la tua preoccupazione e sei troppo legato a uno stile di programmazione per cambiare il modo in cui scrivi il codice (nota: questa è generalmente una qualità terribile da avere come programmatore), questa è un'alternativa molto più praticabile che semplicemente scrivendo la tua lingua. Ciò richiederebbe forse un paio di settimane al massimo . Confrontalo con gli anni che verrebbero spesi in un linguaggio corretto, con un ricco supporto per il debug e simili.

Se i tuoi problemi sono più grandi di questo (i globali sono quelli predefiniti, quindi ti richiedono di usarli localovunque), alcuni di questi possono essere gestiti (rendi semplicemente la dichiarazione di un nuovo globale un errore, attraverso l'uso di ambienti e metatable alterati). Se odi le funzioni come oggetti di prima classe, coroutine, raccolta dei rifiuti o altri elementi di base di Lua ... beh, allora sei in un inferno di tua creazione;)

E se davvero, vuoi davvero essere hardcore, puoi scrivere la tua lingua che compili in Lua. Quindi almeno sarai in grado di sfruttare il runtime Lua molto collaudato, l'eccezionale API Lua e altre strutture Lua di base, tutto dalla tua lingua! Lua. Ci vorrà del tempo, ma non saranno ancora gli anni a spendere qualcos'altro.


A me sembra che potrei semplicemente codificare le funzioni se dovessi usare Lua. Mi sento come se stessi spostando il codice.
skiperic,

1
@skiperic: Non so cosa intendi con questo. Puoi fare un esempio?
Nicol Bolas,

Vedi la risposta di Laurent sopra.
skiperic,

2
@skiperic: Questo non spiega davvero di cosa ti preoccupi. Sai programmare in Lua? Sì. E il problema è ...?
Nicol Bolas,

1
@BartekBanachewicz: Anche accettando che sia un'API C, è ancora superiore a molte API di scripting basate su C ++ che ho visto. È l'unica API di scripting che prenderei effettivamente in considerazione l'utilizzo di raw , senza un raccoglitore automatizzato in qualche modo.
Nicol Bolas,

3

Per completare le altre risposte, questa non è un'opzione strettamente binaria. All'interno di un linguaggio di scripting esistente, puoi anche creare il tuo linguaggio specifico per il dominio . I vantaggi di questo approccio sono:

  • In realtà non devi fare confusione con grammatiche formali, parser, implementare editor personalizzati ecc.
  • Stai ottenendo il massimo beneficio dall'implementazione di un linguaggio di scripting specializzato, ovvero un'astrazione aggiuntiva, specifica per il tuo gioco.
  • vs. homebrew: gli utenti che hanno familiarità con il linguaggio di scripting di tua scelta saranno immediatamente in grado di utilizzare il tuo DSL.
  • rispetto al semplice linguaggio esistente: gli utenti che non conoscono il linguaggio di scripting dovranno solo conoscere il DSL per modificare il gioco.

Lo svantaggio principale è che si progetterebbe il DSL con i vincoli del linguaggio "base".


2

Si potrebbe dare un senso a seconda delle meccanica del vostro gioco. Alcuni giochi con una meccanica abbastanza semplice potrebbero usare un linguaggio interpretato per salvarsi da una codifica Lua / Python troppo complicata, ma i risparmi di complessità potrebbero non valere troppo. Ad esempio, uno di quei giochi di Interactive Novel potrebbe facilmente utilizzare un motore di scripting personalizzato.

Se il tuo gioco coinvolge un motore fisico, vari componenti del gioco e una diversa complessità di personaggi e abilità, dovresti assolutamente considerare di guardare altri linguaggi di scripting esistenti, quindi non stai cercando di aggiungere le funzionalità necessarie a quello personalizzato o correggere i bug con esso. Mentre Lua è probabilmente il più veloce, ce ne sono molti altri che potrebbero piacerti di più per la loro sintassi, e molti di loro si vantano della facilità con cui si integrano con C. Python, Ruby e Angelscript. (Sentiti libero di menzionare gli altri nei commenti)

Se si garantisce che tali linguaggi vengano utilizzati solo per il "controllo logico" (ovvero la gestione di un caso di collisione specifico per determinati tipi di oggetti, come l'esplosione di fiamma che tocca un blocco di ghiaccio), le prestazioni non saranno quasi mai un problema. Naturalmente, d'altra parte, se li usi per più codice di routine (creando un algoritmo di controllo delle collisioni personalizzato che esegue ciascun frame) è più probabile che ti impantoni.


1
Lua è anche un linguaggio di scripting molto popolare nello sviluppo di giochi.
Philipp,

Sì, Lua è usata dappertutto, ma l'OP ha notato che non gli piaceva molto. Le preferenze di stile di codifica possono essere importanti.
Katana314,

1
" Ad esempio, uno di quei giochi di Interactive Novel potrebbe facilmente utilizzare un motore di scripting personalizzato " . Ovviamente non hai visto Inform . Davvero, anche per le avventure testuali, non ha senso inventare la tua lingua.
Nicol Bolas,

1
@ Katana314: "Le preferenze dello stile di programmazione possono essere importanti. " Onestamente, il mondo starebbe meglio se i programmatori scendessero dai loro cavalli alti riguardo allo "stile di programmazione". Saremmo tutti programmatori migliori se smettessimo di pensare che <inserire qui la lingua preferita> fosse fondamentalmente migliore rispetto a <inserire qui la lingua preferita>. L'uso di linguaggi che potrebbero non piacerti la sintassi del carattere build e aiuta a evitare questo tipo di errore.
Nicol Bolas,

1

Dico, provaci. Su un curriculum sarebbe uno spettacolo in più di abilità. Tuttavia, tieni presente che devi prima avere questa capacità. Non sarà facile, sarà piuttosto difficile. Ci sono libri sull'argomento e anche tutorial online, ma alla fine dipenderà da te e dalla tua comprensione di come funziona un compilatore e di come il codice viene analizzato e tradotto.

Assicurati di iniziare in modo semplice, testare frequentemente e mantenere il tuo ideale. Ma ricorda sempre, LUA è lì per te.


1
Immagino che la domanda qui sia se l'obiettivo è fare un gioco o fare qualcosa che appaia bello in un curriculum.
Tridus,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.