Ablauf-Script-Engine

Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Neue Antwort erstellen

Jolinah

Betreff: Ablauf-Script-Engine

BeitragMo, Okt 10, 2005 21:04
Antworten mit Zitat
Benutzer-Profile anzeigen
Habe eine kleine Ablauf-Script-Engine programmiert. Ok, das klingt komisch Smile Ich habs Ablauf-Script genannt weil es nicht eine Scriptsprache ist wo man mit Variablen arbeiten kann sondern die Scripts sind lediglich da um einen Ablauf für Objekte vorzugeben.

Für jeden Objekttype kann man eigene Scriptbefehle definieren. Das ganze besteht aus zwei Types: Script und Scriptable.

Der Script-Type dient zum erstellen, laden und speichern der Scripte sowie die Ausführung, wobei die Ausführung intern geregelt wird über den Scriptable-Type. Erstellen kann man die Scripte natürlich auch mit nem Text-Editor.

Der Scriptable-Type stellt ein Objekt dar welches mit dem Script verbunden ist. Dieser Type ist also eine Grundlage und ist deshalb Abstrakt, es muss ein eigener Type erstellt werden der davon ableitet.

Hier die wichtigsten Methoden:

Type Script
- Create(Name:String) 'Um ein Script direkt im Speicher zu erstellen
- Open(filename:String) 'Laden von einer Datei
- Save(filename:String) 'Speichern
- AddLine(line:String) 'Zeile hinzufügen (sinnvoll bei Create)

Type Scriptable
- Update() 'Aktualisiert das Ganze (inkl. Skript-Abarbeitung)
- SetScript(s:Script) 'Festlegen welches Script das Objekt benutzt
- SetAction(a:Byte) 'Gegenwärtige Aktion des Objekts festlegen
- Start() 'Nur wenn Start aufgerufen wurde macht Update auch was.
- Stop() 'Nach dem Stop macht Update nichts mehr (Anfangszustand).
- OnCommand(cmd:String, args:String[]) Eventhandler für Scriptbefehle
- OnScriptEnd() Eventhandler (Scriptende erreicht)

Edit: Hier noch als kleines Demo, für die die keine Lust haben den Code selber zusammen zu bauen Wink
http://zehr.de/blitz3d/test.zip


Und hier der Code:
Code: [AUSKLAPPEN]
Const ACTION_NONE:Byte = 0


'Script-Type ---------------------------------------------------
'Dieser Type wird zum Laden, Speichern oder direkt erstellen benutzt,
'Die Run Methode wird eigentlich nur Intern benutzt und vom Scriptable Type angesteuert.
Type Script
   Field count:Int
   Field lines:String[]
   Field Name:String

   'Create - Erstellt einen Script-Type und gibt ihn zurück
   Function Create:Script(name:String)
      Local s:Script = New Script
      s.Name = name
      Return s
   End Function

   'Open - liest eine Datei als Script ein
   Function Open:Script(filename:String)
      Local file:TStream = ReadStream(filename)
      If file = Null Then Return Null

      Local line:String
      Local s:Script = New Script

      While Not Eof(file)
         line = ReadLine(file)
         If line <> "" Then
            If Left(line,1) <> "#" And Left(line,2) <> "//"
               s.AddLine(line)
            Else
               If Lower(Left(line, 9)) = "# script:"
                  s.Name = Mid(line, 11)
               EndIf
            EndIf
         EndIf
      Wend
      
      CloseStream(file)
      
      Return s
   End Function
   

   'Save - Speichert das Script in eine Datei
   Method Save(filename:String)
      Local file:TStream = WriteStream(filename)
      If file = Null Then Return
      
      WriteLine(file, "# Script: " + Name)
      For Local s:String = EachIn lines
         WriteLine(file, s)
      Next
      
      CloseStream(file)
   End Method


   'AddLine - fügt zu dem Script eine Zeile hinzu
   Method AddLine(line:String)
      lines = lines[..count + 1]
      lines[count] = line
      count :+ 1
   End Method

   
   'SetName - Name des Scripts setzen, zur Identifizierung unter Umständen
   Method SetName(name:String)
      Self.Name = name
   End Method

   
   'GetName - Name des Scripts abrufen
   Method GetName:String()
      Return Name
   End Method

   
   'Run - Ausführen des Scripts (Interaktionsobjekt übergeben)
   Method Run(Obj:Scriptable = Null)
      If lines = Null Then Return
      If Obj = Null Then Return
      If Obj.CurrentCmd = -1 Or Obj.CurrentCmd >= lines.Length Then Return

      Local ms:Int = MilliSecs()
      If ms < Obj.NextCmd Then Return

      Local args:String[] = Split(lines[Obj.CurrentCmd])
      Obj.CurrentCmd :+ 1
      
      args[0] = Upper(args[0])

      Select args[0]
         Case "WAIT"
            If args.Length > 1
               Try
                  Obj.NextCmd = ms + Int(args[1])
               Catch ex:Object
                  Obj.NextCmd = ms + 100
               End Try
            EndIf
            
         Case "END"
            Obj.CurrentCmd = 0
            Obj.OnScriptEnd()

         Default
            If args.Length > 1 Then
               Obj.OnCommand(args[0], args[1..])
            Else
               Obj.OnCommand(args[0], Null)
            EndIf
            
      End Select

   End Method

End Type


'Scriptable-Type ---------------------------------------------------
'Stellt ein Objekt welches mit einem Script verknüpft ist dar.
Type Scriptable Abstract
   Field Running:Byte
   Field CurrentCmd:Int
   Field NextCmd:Int
   Field CurrentAction:Byte
   Field Script:Script
   
   'Update - Führt das Script aus (Nur wenn gerade sonst keine Aktion läuft)
   Method Update()
      If CurrentAction = ACTION_NONE And Running And Script <> Null Then Script.Run(Self)
   End Method
   
   'SetScript - Setzt das aktuelle Script
   Method SetScript(s:Script)
      Script = s
   End Method
   
   'SetAction - Setzt die Aktuelle Aktion
   Method SetAction(action:Byte)
      CurrentAction = action
   End Method

   'Start - Startet die Ausführung des Scripts
   Method Start()
      Running = True
      CurrentCmd = 0
   End Method
   
   'Stop - Stoppt die Ausführung des Scripts
   Method Stop()
      Running = False
   End Method
   
   'OnCommand - Eventhandler der aufgerufen wird wenn vom Script ein Befehl abgearbeitet wird
   Method OnCommand(cmd:String, args:String[])
   End Method
   
   'OnScriptEnd - Eventhandler der beim Scriptende aufgerufen wird
   Method OnScriptEnd()
   End Method
End Type






'Hilfs-Funktionen ----------------------------------------------------

'Trennt einen String in mehrere Substrings und gibt ein String Array zurück (Trennzeichen kann angegeben werden)
Function Split:String[](str:String, char:String = " ")
   Local ret:String[] = New String[1]
   Local length:Int = 1
   Local oldpos:Int = 0
   Local pos:Int = 0
   Local trenn:Byte = Len(char)
   
   pos = Instr(str, char)
   
   If pos > 0
      ret[0] = Left(str, pos-1)

      While pos > 0
         oldpos = pos
         pos = Instr(str, char, oldpos+trenn)

         ret = ret[..length + 1]
         
         If (pos > oldpos)
            ret[length] = Mid(str, oldpos + trenn, pos - (oldpos + trenn))
         Else
            ret[length] = Mid(str, oldpos + trenn)
         EndIf
         
         length :+ 1
      Wend

   Else
      ret[0] = str
   EndIf
   
   Return ret
End Function


'Fügt ein String Array zu einem String zusammen mit dem angegebenen Trennzeichen.
Function Concat:String(str:String[], char:String = " ")
   Local ret:String = ""

   For Local i = 0 To str.length - 1
      ret :+ str[i]
      If i < str.length - 1 Then ret :+ char
   Next

   Return ret
End Function




Nachträglich noch ein Beispiel:
Code: [AUSKLAPPEN]
Strict

Include "TScript.bmx"

'Aktionen
Const ACTION_MOVE:Byte = 1

'Objekt welches Scriptable erweitert
Type Test Extends Scriptable
   Field x, y, tx, ty 'tx, ty = Ziel-Position (für Move)
   Field speed
   
   Method New()
      'Standardspeed
      speed = 2
   End Method

   Method Update()
      'Sorgt für den Scriptablauf
      Super.Update()

      'Die Methoden OnCommand bzw. OnScriptEnd werden intern aufgerufen
      'Nach dem Update müsste also die aktuelle Aktion gespeichert sein

      'Aktion prüfen
      Select CurrentAction
         'Bei MOVE auf das Ziel bewegen
         Case ACTION_MOVE
            If x < tx
               x :+ speed
            Else If x > tx
               x :- speed
            EndIf
            
            If y < ty
               y :+ speed
            Else If y > ty
               y :- speed
            EndIf
            
            'Beim Ziel angekommen Aktion wieder auf nichts setzen,
            'so dass der nächste Scriptbefehl abgearbeitet wird.
            If x = tx And y = ty Then SetAction(ACTION_NONE)
      End Select
      
   End Method
   
   'Zeichnen
   Method Draw()
      DrawRect x, y, 20, 20
   End Method
   
   'Eventhandler wird aufgerufen wenn ein Befehl abgearbeitet wurde
   'cmd = Befehl in Uppercase
   'args = Argumente des Befehls als String Array
   Method OnCommand(cmd:String, args:String[])
      Select cmd
         'Bei dem Setspeed Befehl den speed setzen auf das erste Argument
         Case "SETSPEED"
            speed = Int(args[0])
            
         'Bei Move das Ziel setzen (1. und 2. Argument)
         'Da diese Tätigkeit etwas dauern kann muss hier eine Aktion
         'ungleich 0 gesetzt werden (ACTION_NONE = 0)            
         Case "MOVE"
            tx = x + Int(args[0])
            ty = y + Int(args[1])
            SetAction(ACTION_MOVE)
      End Select
   End Method
   
   'Wird aufgerufen wenn das Script beim END Befehl angelangt ist.
   'Ohne den Stop() Befehl läuft das Script als Loop
   Method OnScriptEnd()
      Print "Durchlauf abgeschlossen"
      'Stop()
   End Method
End Type



Graphics 800, 600, 0

'Scripts laden
Local s:Script = Script.Open("Test.txt")
Local s2:Script = Script.Open("Test2.txt")

'Liste erstellen wo die Scriptable Objekte reinkommen
Local list:TList = New TList

'Erstes Scriptable Objekt
Local t:Test = New Test
t.SetScript(s)
t.x = 100
t.y = 100
t.Start()

'Zweites Scriptable Objekt
Local t2:Test = New Test
t2.SetScript(s2)
t2.x = 100
t2.y = 400
t2.Start()

'Der Liste hinzufügen
list.AddLast(t)
list.AddLast(t2)

'Hauptschleife
Repeat
Cls

'Alle Objekte in der Liste durchgehen und aktualisieren, Zeichnen
For Local test:Test = EachIn list
   test.Update()
   test.Draw()
Next

Flip
FlushMem
Until KeyHit(KEY_ESCAPE)

EndGraphics

t = Null
t2 = Null
list = Null
s = Null

FlushMem
End



Und die zwei Scripts:
test.txt
Code: [AUSKLAPPEN]
# Script: Test
SETSPEED 10
MOVE 100 0
WAIT 500
MOVE 0 100
WAIT 500
MOVE -100 0
WAIT 500
MOVE 0 -100
WAIT 500
MOVE 100 100
WAIT 500
MOVE -100 0
WAIT 500
MOVE 100 -100
WAIT 500
END


test2.txt
Code: [AUSKLAPPEN]
# Script: Test2
MOVE 100 0
WAIT 500
MOVE -100 100
WAIT 500
MOVE 100 0
WAIT 500
MOVE -100 -100
WAIT 500
MOVE 200 0
WAIT 500
END



Ich weiss dass es nichts besonderes ist, aber vielleicht kanns ja jemand brauchen Wink

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group