Npc, eine Skriptsprache?

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Artus
Beiträge: 280
Registriert: 15.01.2005 20:53

Npc, eine Skriptsprache?

Beitrag von Artus »

Hallo,

[Offtopic]
Erstmal möchte ich mich bei Kaeru Gaman und ZeHa entschuldigen, aber das hatt mich gestern echt zum kochen gebracht. Sorry.
[Offtopic]

Nun mal zum thema ich binn dabei ein RPG zu proggen binn auch schon weit und gerade an den NPC nun hab ich mir gedacht machst ne kleine skriptsprache. Gut sie is wahrscheinlich total langsam und umständlich, is aber nur ein test da ich noch nich weis wie ich das mit den variablen übergeben mach. Nun würd ich gern wissen wie ihr das machen würdet mit ner skriptsprache, alles im Code oder ganz anders?? und kann ich die variablennamen irgendwie übergeben?

hier mein Test Code:

Code: Alles auswählen

Global SpeakerName.s
Global Message.s

Procedure PlayScript(File.s)
  Protected ScriptString.s
  Protected ScriptStringLen.w

  If Not ReadFile(0,File.s)
    ProcedureReturn #False
  EndIf
  
  
  Repeat
  
    ScriptString = Trim(ReadString(0))
    ScriptStringLen = Len(ScriptString) 
  
    If Left(ScriptString, 7) = "Speaker"
      SpeakerName = Trim(Mid(ScriptString,10,30))
      Debug ">>"+SpeakerName
    
    ElseIf Left(ScriptString, 3) = "Say"
      Message = Trim(Mid(ScriptString,6,ScriptStringLen-5))
      Debug Message
     
    ElseIf Left(ScriptString, 4) = "/End"
      CloseFile(0)
      ProcedureReturn #True
    EndIf
  
  Until Eof(0)
  ProcedureReturn #True
EndProcedure

PlayScript("ScriptTest.txt")
und die txt:

Code: Alles auswählen

Speaker-> Helen
Say-> Wer bist du?
Say-> Was willst du?
Speaker-> Talon
Say-> Lass mich!
Say-> Und keine Ahnung!
/End
mfg
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Re: Npc, eine Skriptsprache?

Beitrag von Kaeru Gaman »

Artus hat geschrieben:Erstmal möchte ich mich bei Kaeru Gaman ... entschuldigen
akzeptiert. peace, man. :D
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
ZeHa
Beiträge: 4760
Registriert: 15.09.2004 23:57
Wohnort: Friedrichshafen
Kontaktdaten:

Beitrag von ZeHa »

Akzeptiere ich auch, hatte Dir ja noch 'ne PM geschrieben gestern ;)

Also wegen der Skriptsprache. Da gibt es natürlich viele Ansätze, wichtig ist auf jeden Fall, daß Du Dich von Anfang an nicht in eine Sackgasse begibst, sondern daß Du möglichst all das später abdecken kannst, was noch in Dein Spiel so reinkommen wird (und das weiß man ja oftmals nicht so genau, wenn man am Anfang steht).

Eine Möglichkeit wäre nun, ale Funktionalitäten für die Charaktere (und vielleicht auch für Gegenstände) in hübsche, klare Procedures zu packen. Somit hast Du schonmal den Vorteil, daß Du bestimmte Dinge in Deiner Skriptsprache 1:1 nachbilden kannst. Beispielsweise steht in Deiner Skriptsprache der Befehl "LoseLife", dann hast Du bestenfalls auch eine Procedure namens LoseLife, und kannst diese direkt aufrufen. Hierbei kannst Du natürlich auch perfekt Parameter übergeben.

Mit Variablen kannst Du natürlich auch arbeiten, allerdings wird das dann natürlich etwas komplizierter. Eine ganz simple, aber auch relative beschränkte Methode ist, jedem Objekt z.B. 20 Longs zu spendieren (als Array z.B.), die Du über Deine Skriptsprache setzen kannst. Zum Beispiel über einen Befehl wie "Set Var1 = 99". Natürlich könntest Du dann auch Aliase einbauen, sodaß Du tatsächlich "Set Energie = 99" eingeben kannst (wobei Energie ein schlechtes Beispiel ist, weil das eine so generelle Eigenschaft ist, daß Du da besser "native" Funktionalitäten einbaust anstatt dafür Variablen zu nehmen.

Wenn Dir das mit den 20 Variablen nicht reicht oder zu "unsauber" ist, kannst Du natürlich auch jedesmal Speicher allozieren, z.B. indem Du eine LinkedList benutzt. Diese muß dann natürlich mit einer Structure arbeiten, die sowohl Namen als auch Wert speichert. Um es performanter zu machen, sollte natürlich kein Name sondern eine Nummer vergeben werden, und der Name sollte nur in der Skriptsprache auftauchen (zur besseren Benutzbarkeit) und vor dem Spielstart entsprechend in eine fortlaufende Nummer konvertiert werden.

Letztendlich solltest Du dann eine Liste aller Befehle haben, sodaß Du diese komplett abarbeiten kannst. Oft ist es auch wichtig, daß Du in Deiner Skriptsprache Schleifen oder "Gotos" drin hast, daher solltest Du das Skript nicht live parsen, sondern bereits alles schön fertig im RAM haben und dort dann auslesen.

Allgemein noch ein Wort zur Performance: Natürlich empfiehlt es sich, das Skript hinterher nicht als Klartext in den Dateien zu haben, sondern jeden Befehl durch eine Zahl zu ersetzen (da reicht ja dann 1 Byte für 256 Befehle) und dahinter dann die entsprechenden Werte. Natürlich mußt Du Dir dafür dann einen kleinen Compiler schreiben. Ist aber bei einem größeren Projekt dann auf jeden Fall von Vorteil. Natürlich kannst Du dann den Skript-Compiler auch direkt noch in Dein Spiel einbauen, sodaß Du weiterhin mit Klartext-Skripten arbeiten kannst, die dann aber vor dem Spielstart direkt kompiliert werden und von nun an im RAM in Zahlen vorliegen. Damit ersparst Du Dir das lästige "von Hand kompilieren". Später kannst Du das dann ja auch wieder entfernen bzw. den Compiler dazu bringen, daß er erkennt, ob Du mit Klartext oder mit "Bytecode" arbeitest, somit kannst Du dann beim finalen Release die fertig kompilierten Skripte anbieten, um Cheatern das Leben schwerer zu machen (falls das in Deinem Interesse liegt).

Ich hab mal für eine Adventure-Engine eine Skriptsprache für jeden Raum erstellt, das war so 'ne Art Assembler, wurde dann hinterher auch in einen Bytecode umgesetzt. War benutzbar aber auch nicht perfekt durchdacht. Also wie schon gesagt, vorher auf jeden Fall gut planen und strukturieren, wissen was rein muß und was nicht, und dafür sorgen, daß es jederzeit gut erweiterbar bleibt.
Bild     Bild

ZeHa hat bisher kein Danke erhalten.
Klicke hier, wenn Du wissen möchtest, woran ihm das vorbeigeht.
Benutzeravatar
Artus
Beiträge: 280
Registriert: 15.01.2005 20:53

Beitrag von Artus »

Danke, ich wollt eigentlich schon das so machen das man die namen verwänden kann, das mit den Longs is mir zu eingeschränkt hab gerade etwas weiter gebaut und das kam bis jetzt raus:


Code: Alles auswählen

Global SpeakerName.s
Global Message.s
Global Answer.b = 1
Global Dim Answer.s(3)




Procedure PlayScript(File.s)
  Protected ScriptString.s
  Protected ScriptStringLen.w
  Protected WaitForEndIf.b

  If Not ReadFile(0,File.s)
    ProcedureReturn #False
  EndIf
  
  
  Repeat
  
    ScriptString = Trim(ReadString(0))
    ScriptStringLen = Len(ScriptString) 
  
  
    If Left(ScriptString, 3) = "/If"
      If Mid(ScriptString,5, 6) = "Answer" 
        If Not Val(StringField(ScriptString,2,"=")) = Answer
          WaitForEndIf = #True 
        EndIf
      EndIf
    ElseIf Left(ScriptString, 6) = "/EndIf"
      WaitForEndIf = #False
    EndIf
    
    
    
    If WaitForEndIf = #False
      If Left(ScriptString, 7) = "Speaker"
        SpeakerName = Trim(Mid(ScriptString,10,30))
        Debug ">>"+SpeakerName
      
      ElseIf Left(ScriptString, 3) = "Say"
        Message = Trim(Mid(ScriptString,5,ScriptStringLen-4))
        Debug Message
        
      ElseIf Left(ScriptString, 3) = "Say"
       
      ElseIf Left(ScriptString, 10) = "/EndScript"
        CloseFile(0)
        ProcedureReturn #True
      EndIf
    EndIf
  
  Until Eof(0)
  CloseFile(0)
  ProcedureReturn #True
EndProcedure

PlayScript("ScriptTest.txt")
script:
/ClearAll
Speaker-> Helen
Say: Wer bist du?
Say: Was willst du?
/Answer(1): Was is?
/Answer(2): Jo der Baum is schön!
/ClearAll
/If Answer = 1
Speaker-> Talon
Say: Das ist Antwort 1
Say: Und keine Ahnung!
/EndIf
/If Answer = 2
Speaker-> Talon
Say: Das ist Antwort 2
/EndIf
/EndScript
Benutzeravatar
ZeHa
Beiträge: 4760
Registriert: 15.09.2004 23:57
Wohnort: Friedrichshafen
Kontaktdaten:

Beitrag von ZeHa »

Naja für solche Dinge wie Namen usw wirst Du um einen einfachen kleinen Compiler nicht drumrumkommen. Ist aber halb so wild, meiner Meinung nach.

Um eine gute, funktionierende Sprache zu entwerfen, ist es meist das beste, tatsächliche Situationen nachzuskripten, die man gerne einbauen möchte. Hierbei kann man dann an bestimmten Stellen noch ??? oder sowas einbauen, wenn man sich nicht sicher ist. Wenn man die Komplexität der Skripte dann immer weiter steigert, kristallisiert sich meist eine nette kleine Sprache heraus. Ist auf jeden Fall wichtig, um hinterher so flexibel wie möglich damit zu sein.

Dein momentaner Code ist auf jeden Fall noch zu unübersichtlich, aber das wirst Du sicher selbst schon gemerkt haben. Im Endeffekt sollte das ganze Left() usw. dem Compiler überlassen sein, dann brauchst Du nur noch Befehle aus 'nem Bytecode auszulesen und diese dann mit einer Select Case-Konstruktion Stück für Stück abarbeiten.
Bild     Bild

ZeHa hat bisher kein Danke erhalten.
Klicke hier, wenn Du wissen möchtest, woran ihm das vorbeigeht.
Antworten