Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

LeBusch

Frischling

  • »LeBusch« ist der Autor dieses Themas

Beiträge: 81

Beruf: Student B.Sc. Informatik

  • Private Nachricht senden

1

29.12.2013, 14:24

Scriptsprache für Engine

Moin,

Ich bin mit meiner neugeschriebenen RPG-Engine wieder auf dem Stand der Urversion, die ich hier mal vorgestellt hatte. Wie auch bei der letzten Version schon, möchte ich (wieder) eine Scriptsprache implementieren, mit der NPCs gesteuert, Textboxen ausgegeben, am besten auch Fallunterscheidungen getätigt werden können. Mein letzter Versuch sah so aus:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
NPC.Goto(15 10)
NPC.WaitForInput
Script.LockUserInput
NPC.LookAtPlayer
Script.AddToTextbuffer(Moin!)
Script.AddToTextbuffer(Ich bin ein NPC und ich kann jetzt)
Script.AddToTextbuffer(endlich sprechen!)
Script.ShowTextbox
Script.WaitForTextbox
NPC.Goto(15 4)
NPC.Goto(12 4)
NPC.Goto(12 6)
NPC.Goto(15 6)
Script.UnlockUserInput
Script.Wait(2500)
NPC.Direction(3)
Script.Wait(2500)
NPC.Direction(1)
Script.Wait(2500)
NPC.Direction(0)
Script.Wait(2500)
NPC.Direction(2)
Script.Loop(13)

Mit diesem Code ging der NPC zur Position X=15 und Y=10, hat dann darauf gewartet, dass der Spieler ihn anspricht, hat den Spieler angesehen, ein wenig geredet, ist dann "weggelaufen" und stand danach die ganze Zeit auf der Stelle und hat sich gedreht. An sich hat das schon ganz gut funktioniert, nur war die Verarbeitung im Programm eine Qual und es gab weder Fallunterscheidungen noch frei belegbare Variablen. Ich hab die Datei in einem separaten Thread Zeile für Zeile ausgelesen und mit InStr abgefragt, ob sich in dieser Zeile ein Keyword befindet. Hier mal ein Beispiel (Achtung, VB-Code):

Quellcode

1
2
3
4
5
6
7
ElseIf InStr(Temp_String, "Script.AddToTextbuffer(") Then

                    Startindex = InStr(Temp_String, "(")
                    Endindex = InStr(Temp_String, ")") - 1

                    Dim Temp_TextbufferLine As String = Temp_String.Substring(Startindex, (Endindex - Startindex))
                    Rendering.Textbuffer.Lines.Add(Temp_TextbufferLine)

War das Konzept am Ende doch gar nicht mal so blöd? Ein alternatives Konzept wäre folgendes:
Es gibt jeweils 50 Variablen der Typen Integer, String und Boolean, welche sich in der Klasse "Variables" befinden.

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
    static class Variables
    {

        public int[] i = new int[50];
        public string[] s = new string[50];
        public Boolean[] b = new Boolean[50];

        public Boolean ShowTextBox = false;

    }

Auf diese Variablen kann man nun aus dem Script zugreifen.

Quellcode

1
assign  i_5 25

Hier wird i_5, also i[5] der Wert 25 zugewiesen. NPC Befehle könnten dann später so aussehen:

Quellcode

1
move    npc_0   10  15

Dann sollte sich z.B. der NPC mit dem Index 0 zum Punkt X=10, Y=15 bewegen.
In C# sieht das ganze so aus:

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
            foreach (string line in script)
            {
                if (line.Contains("assign") == true)
                {
                    int startindex = line.IndexOf("\t") + 1;
                    int stopindex = line.IndexOf("\t", startindex);

                    string var = line.Substring(startindex, stopindex - startindex);
                    int varindex;

                    if (var.Contains("i_") == true)
                    {
                        varindex = Convert.ToInt32(var.Substring(var.IndexOf("i_") + 2));
                        startindex = stopindex + 1;
                        string value = line.Substring(startindex);
                        i[varindex] = Convert.ToInt32(value);
                    }
                }
            }

Allerdings weiß ich auch hier nicht, wie ich If-Abfragen umsetzen sollte. Darüber kann ich mir aber immer noch Gedanken machen, wenn die Scripts überhaupt erstmal arbeiten. Was haltet ihr von den einzelnen Ansätzen? Welchen würdet ihr bevorzugen oder würdet ihr gar einen komplett anderen Weg wählen?

Grüße,
LeBusch

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »LeBusch« (29.12.2013, 14:59)


2

29.12.2013, 15:16

Naja, es gibt genügend Skriptsprachen, die du einfach so einbinden könntest. Lua, AngelScript, Python ...

Wenn du ansonsten wirklich eine eigene Skriptsprache entwickeln willst, solltest du dich mal mit Compilerbau beschäftigen (dazu gibt es Uni-Vorlesungen und diverse Bücher).
Die Grundidee ist, aus dem Programmcode einen Syntaxbaum zu bauen, den du dann auswerten kannst.

Beispiel:

Quellcode

1
2
if Punkte > MaxPunkte-4
  print "fast geschafft"

Im Syntaxbaum stünde dann, dass du eine Abfrage mit einer Bedingung (Punkte > MaxPunkte-4) und einer Folge (print "fast geschafft") hast. Du wertest also den Ausdruck für die Bedingung aus, indem du die Werte für die Variablen in einer entsprechenden Tabelle nachschlägst und je nach Ergebnis, führst du danach die print-Anweisung aus oder eben nicht.

Im Allgemeinen ist das ein äußerst komplexes Thema. Wenn du wirklich nur Skripte haben willst, solltest du also eine fertige Skriptsprache einbinden.
Lieber dumm fragen, als dumm bleiben!

LeBusch

Frischling

  • »LeBusch« ist der Autor dieses Themas

Beiträge: 81

Beruf: Student B.Sc. Informatik

  • Private Nachricht senden

3

29.12.2013, 15:52

Danke für deine Antwort! Aber externe Scriptsprachen fallen für mich eigentlich aus, weil ich nur ein paar einfache Befehle brauche - keine komplette Sprache. Am besten erkläre ich mal, wofür ich If-Abfragen usw. überhaupt bräuchte. Im Grunde geht es darum, dass das Spiel sich merken kann, welche Ereignisse bereits geschehen sind. Ich hatte oben ja bereits das Script vom NPC, welcher vor dem Spieler weggelaufen und danach im Kreis gerannt ist gepostet. Das Problem ist jetzt, dass das komplette Ereignis jedes Mal erneut passiert ist, wenn der Spieler die Map betreten hat. Also war die Überlegung, dass ich eine Abfrage einbaue, ob das Ereignis bereits geschehen ist. Dass quasi der Einstiegspunkt, wenn der Spieler die Map erneut betritt nicht Zeile 1 ist, sondern die Zeile, ab der der NPC sich nur noch im Kreis dreht. Aber daran, so etwas flexibel hinzubekommen, beiße ich mir momentan die Zähne aus.

birdfreeyahoo

Alter Hase

Beiträge: 756

Wohnort: Schorndorf

Beruf: Junior Software Engineer

  • Private Nachricht senden

4

29.12.2013, 16:23

Mach das doch auch mit einem Befehl:
Script.RestrictExecutes(1)
Im Code speicherst du wie oft der Script ausgeführt wurde und wo er stehen geblieben ist und führst ihn je nachdem weiter aus oder nicht.

Sylence

Community-Fossil

Beiträge: 1 663

Beruf: Softwareentwickler

  • Private Nachricht senden

5

29.12.2013, 17:36

Wenn du eh schon C# benutzt, dann kannst du deine Scripts auch in C# (oder einer anderen .NET Sprache) schreiben und zur Laufzeit kompilieren und ausführen.

6

29.12.2013, 17:40

Eventuell willst du einfach nur ein Triggersystem? Age of Empires 2 hatte so eines, damit habe ich im Editor gerne rumgespielt (in unzähligen anderen Spielen gibt es die auch).

Die Grundidee ist folgende: Du hast Trigger und Aktionen. Von beiden gibt es verschiedene Typen, die jeweils Parameter haben können. Trigger kann man dabei auch mit Operationen wie 'und', 'oder', 'nicht' verknüpfen um komplexere Abfragen zu erstellen. Ist eine solche Abfrage erfüllt, wird einfach die Liste der Aktionen abgearbeitet.

Beispiel:

Quellcode

1
2
3
4
5
6
7
Wenn
  ObjektInBereich (Spieler, Kreis(Pos=(14, 16), Radius=5))
    und
  GesundheitVonFigurKleinerAls ( Spieler, 15)
dann
  TextZeigen("eine kleine Hilfe")
  ObjektErstellen(Medipack, (14, 16)


Es würde also eine Klasse für jeden Typ geben die über ein gemeinsames Interface angesprochen werden können (PruefeBedingung(), LoeseAus() ...). Wenn man es richtig macht, ist es relativ wenig Arbeit, sehr gut erweiterbar und unglaublich mächtig. Einige Dinge gehen natürlich nach wie vor mit einer echten Skriptsprache besser, aber ein Triggersystem ist für die allermeisten Level in den allermeisten Spielen ausreichend.
Lieber dumm fragen, als dumm bleiben!

LeBusch

Frischling

  • »LeBusch« ist der Autor dieses Themas

Beiträge: 81

Beruf: Student B.Sc. Informatik

  • Private Nachricht senden

7

29.12.2013, 19:59

Wenn du eh schon C# benutzt, dann kannst du deine Scripts auch in C# (oder einer anderen .NET Sprache) schreiben und zur Laufzeit kompilieren und ausführen.
Würde das nicht Schadsoftware Tür und Tor öffnen?

Die Grundidee ist folgende: Du hast Trigger und Aktionen. Von beiden gibt es verschiedene Typen, die jeweils Parameter haben können. Trigger kann man dabei auch mit Operationen wie 'und', 'oder', 'nicht' verknüpfen um komplexere Abfragen zu erstellen. Ist eine solche Abfrage erfüllt, wird einfach die Liste der Aktionen abgearbeitet.
[...]
Es würde also eine Klasse für jeden Typ geben die über ein gemeinsames Interface angesprochen werden können (PruefeBedingung(), LoeseAus() ...). Wenn man es richtig macht, ist es relativ wenig Arbeit, sehr gut erweiterbar und unglaublich mächtig. Einige Dinge gehen natürlich nach wie vor mit einer echten Skriptsprache besser, aber ein Triggersystem ist für die allermeisten Level in den allermeisten Spielen ausreichend.
Das trifft es ziemlich genau. Wusste aber bisher nicht, dass man so etwas "Triggersystem" nennt und habe es deshalb fälschlicherweise als Skriptsprache bezeichnet. Nur müsste man halt im Hintergrund noch ein paar Variablen haben, die bestimmte Zustände speichern. Habe ich das eigentlich richtig verstanden, dass es keine Anweisungen gibt, die immer ausgeführt werden, sondern alle Anweisungen von einer Fallunterscheidung abhängen?

Sylence

Community-Fossil

Beiträge: 1 663

Beruf: Softwareentwickler

  • Private Nachricht senden

8

29.12.2013, 20:24

Wenn du eh schon C# benutzt, dann kannst du deine Scripts auch in C# (oder einer anderen .NET Sprache) schreiben und zur Laufzeit kompilieren und ausführen.
Würde das nicht Schadsoftware Tür und Tor öffnen?


Die Frage ist: Wie wahrscheinlich ist es, dass deine Software überhaupt ein Ziel dafür ist?

Wenn du eine Skriptsprache wie Lua, AngelScript oder wie sie alle heißen integrieren würdest, dann würde das auch mit denen gehen. Und wenn du dir selber etwas schreibst und das fortgeschritten genug ist, dann kann man auch damit irgendwelchen Mist machen.

LeBusch

Frischling

  • »LeBusch« ist der Autor dieses Themas

Beiträge: 81

Beruf: Student B.Sc. Informatik

  • Private Nachricht senden

9

29.12.2013, 20:32

Die Frage ist: Wie wahrscheinlich ist es, dass deine Software überhaupt ein Ziel dafür ist?
Irgendwer hatte hier im Forum auch schon einmal davon berichtet, dass einer seiner Projektpartner Backdoors (Keylogger etc) in das gemeinsame Projekt eingeschleust hat. In der Hinsicht würde mich also nichts mehr wundern. Und nur, weil das Szenario unwahrscheinlich ist, ist es ja nicht ausgeschlossen.

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

10

29.12.2013, 22:05

Wenn du eh schon C# benutzt, dann kannst du deine Scripts auch in C# (oder einer anderen .NET Sprache) schreiben und zur Laufzeit kompilieren und ausführen.
Würde das nicht Schadsoftware Tür und Tor öffnen?


Um das zu vermeiden gibt es in .NET AppDomains. Wenn die Skripte in der normalen AppDomain deines Spiels laufen, würde das in der Tat Schadsoftware Tür und Tor öffnen.
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

Werbeanzeige