Heute programmiere ich eine Console

Übersicht BlitzBasic FAQ und Tutorials

Neue Antwort erstellen

bruZard

Betreff: Heute programmiere ich eine Console

BeitragMi, Feb 04, 2004 22:10
Antworten mit Zitat
Benutzer-Profile anzeigen
Hier will ich einmal die Frage "Wie programmiere ich eine Console" bearbeiten, da sie ja desöfteren gestellt wird.
Zunächst klären wir einmal was eine Console tut:

Offenbar schaltet man sie mit einer Taste ein und aus und man kann mit ihr Eigenschaften innerhalb des Games verändern. Soweit so gut, aber wie kann man dies auf ein BB Programm übertragen? Um das zu erläutern müssen wir uns den Begriff STATE anschauen:
Ein State ist ein Zustand, ihr drückt zuhause auf den Lichtschalter, die Glühbirne geht in den State "an", Ihr drückt nocheinmal und der State wechselt auf "aus". Um die Console zu aktivieren und zu deaktivieren tun wir nichts anderes, wir drücken einen Schalter:
Code: [AUSKLAPPEN]

If KeyHit(15) Then zeige_console=1-zeige_console

Mit einem Druck auf die Tabulatortaste wechselt der Inhalt von "zeige_console" zwischen 0 und 1, ist "zeige_console" gleich 1, wird sie angezeigt, ansonsten nicht.
Ok, wir können jetzt die Console ein und ausschalten, jetzt muss das nur noch einen Sinn machen.
Für die Eingabe in die Console sollte eine Input-Routine verwendet werden die den normalen Programmablauf nicht anhält, demzufolge fällt die BB Funktion "Input()" für uns flach, wir benötigen mehr Power. Betrachten wir uns einmal die Funktion GetKey(), sie erfasst die Tastatureingaben und liefert uns einen ASCII Code zurück der dem eingegebenen Zeichen entspricht. Mit Chr() können wir aus diesem Code wieder ein Zeichen machen.
Stopp: Wie soll die Console eigentlich verwaltet werden? Natürlich in einer eigenen Funktion welche sich in einem Include befindet. Das erlaubt es den Code auch in anderen Projekten zu verwenden, während man dabei nur marginale Veränderungen vornehmen muss.
Jetzt stellt sich die Frage was wir denn alles brauchen um die Funktion in einem eigenen Modul "am Leben" zu halten. Nun, zunächst einmal müssen wir eine globale Variable definieren in die wir den Text speichern der zur Zeit eingegeben wird. Ich nenne sie einfach einmal "cline$" (abgeleitet von current line). Mit diesen Dingen haben wir jetzt folgenden Code:
Code: [AUSKLAPPEN]

Global cline$

Function Console()
  key=GetKey()
End Function

Nicht sehr umfangreich und kaum nützlich. Um das zu ändern fügen wir den Code zur Texteingabe hinzu, dazu führen wir eine weitere globale Variable ein, welche uns sagt ob die Console gerade offen ist: show_con. Ab jetzt nehmen wir nur noch Eingaben entgegen wenn die Console auch offen ist:
Code: [AUSKLAPPEN]

Global cline$
Global show_con = False

Function Console()
  If show_con
    key=GetKey()   
  EndIf
End Function

Super, Eingaben werden in key geschrieben ... damit können wir aber nichts anfangen, wir brauchen den Kram in einem String ... deshalb bekommt unsere globale Variable cline$ jetzt einen Job. Um sicher zu stellen dass nur sichtbare Zeichen in den String geschrieben werden beschränken wir die Annahme von Zeichen auf den Bereich 32 bis 255.
Code: [AUSKLAPPEN]

Global cline$
Global show_con = False

Function Console()
  If show_con
    key=GetKey()
    If key>=32 And key<=255 Then cline$=cline$+Chr(key)   
  EndIf
End Function

Schon besser, alles was sich tippen lässt wird nun auch in cline$ gesichert. Das aber nur wenn die Console auch offen ist. Da wir in der Hauptschleife nur den Aufruf Console zu stehen haben wollen, muss der Code zum switchen in die Funktion, wir dieser aussieht hatten wir oben schonmal:
Code: [AUSKLAPPEN]

Global cline$
Global show_con = False

Function Console()
  If KeyHit(15) Then show_con=1-show_con

  If show_con
    key=GetKey()
    If key>=32 And key<=255 Then cline$=cline$+Chr(key)   
  EndIf
End Function

Repeat
  Cls

  Console

  Flip
Until KeyHit(1)
End

Was haben wir jetzt? Wir haben eine Console die sich ein und ausschalten lässt und die Möglichkeit den String cline$ mit Zeichen zu füllen wenn die Console offen ist. Super, aber man sieht nichts, weder dass die Console offen ist, noch dass etwas geschrieben wird ... ausgesprochen unvorteilhaft. Wir benötigen mehr Daten:
Code: [AUSKLAPPEN]

Global cursor
Global cursor_time = MilliSecs()
Global cursor_speed= 250

Die neue Variable cursor sagt uns ob der Cursor gerade angezeigt wird, cursor_time beinhaltet den Zeitpunkt an dem der Cursor zuletzt angezeigt wurde und cursor_speed gibt uns die Blinkgeschwindigkeit an. Jetzt müssen wir nur noch abfragen wie spät es jetzt ist, feststellen ob die Blinkgeschwindigkeit erreicht wurde und dann den Cursor umschalten:
Code: [AUSKLAPPEN]

Global cline$
Global show_con = False
Global cursor
Global cursor_time = MilliSecs()
Global cursor_speed= 250

Function Console()
  If KeyHit(15) Then show_con=1-show_con

  If show_con

    key=GetKey()
    If key>=32 And key<=255 Then cline$=cline$+Chr(key)   

    ; Cursor anzeigen
    If MilliSecs()-cursor_time>cursor_speed
      cursor=1-cursor
      cursor_time=MilliSecs()
    EndIf
    If cursor
      x=StringWidth(cline$)
      Text x,0,"_"
    EndIf
   
  EndIf
End Function

Repeat
  Cls

  Console

  Flip
Until KeyHit(1)
End

WOW, ein schöner blinkender Cursor ... fügen wir nun die Ausgabe der derzeit eingegebenen Zeichen hinzu:
Code: [AUSKLAPPEN]

Global cline$
Global show_con = False
Global cursor
Global cursor_time = MilliSecs()
Global cursor_speed= 250

Function Console()
  If KeyHit(15) Then show_con=1-show_con

  If show_con

    key=GetKey()
    If key>=32 And key<=255 Then cline$=cline$+Chr(key)   

    ; Cursor anzeigen
    If MilliSecs()-cursor_time>cursor_speed
      cursor=1-cursor
      cursor_time=MilliSecs()
    EndIf
    If cursor
      x=StringWidth(cline$)
      Text x,0,"_"
    EndIf
    Text 0,0,cline$,0,0

  EndIf
End Function

Repeat
  Cls

  Console

  Flip
Until KeyHit(1)
End

Nun könnt Ihr die Console ein und ausschalten, den eingegebenen Text anzeigen und auch noch einen lustig blinkenden Cursor anzeigen ...

... Morgen klären wir dann das Geheimnis der Backspace- und Returntaste, wie man den eingegebenen String verarbeitet und werden uns Beispiel anschauen wie so eine Console sinnvoll zu verwenden ist...

stay t00ned.
PIV 2,4GHz - 1GB DDR 333 - ATI Radeon9600 - WinXP - DX9.0c - BMax 1.14 - B3D 1.91 - 1280x1024x32

User posted image

bruZard

BeitragDo, Feb 05, 2004 10:58
Antworten mit Zitat
Benutzer-Profile anzeigen
Teil II

Bisher kann man zwar alles eingeben was man möchte, man kann es jedoch weder editieren, noch die Eingabe bestätigen.
Um das zu realisieren müssen wir die ASCII Codes vor 32 prüfen und dann die entsprechende Aktion ausführen. Kümmern wir uns zunächst um Backspace.
Der ASCII Code für Backspace lautet 8, wir prüfen also ob dieser Code bei GetKey() angekommen ist und checken dann noch ob der String noch lang genug ist um ein Zeichen entfernen zu können:
Code: [AUSKLAPPEN]

If key=8 And (Len(cline$)-1)>=0 cline$=Left(cline$,Len(cline$)-1)

Mit dieser Zeile tun wir folgendes: Wir prüfen zunächst ob die Tastatureingabe dem ASCII Code 8 entspricht, was ja die Backspace Taste ist, checken dann ob der bisher eingegebene Text noch einen Zeichenabzug verträgt und nehmen dann den linken Teil des Strings und schreiben ihn zurück.

Weiter gehts mit der Return/Enter Taste. Wenn diese gedrückt wird, soll der String gelöscht werden, die Console soll sich schliessen und der eingegebene Text analysiert werden.
Die Analyse erledigen wir durch ein Select ... Case Konstrukt, einen String sollte wohl jeder löschen können.
Code: [AUSKLAPPEN]

If key=13
  show_con=0
  ; Gleichheitszeichen suchen
  eq=Instr(cline$,"=")
  If eq
    ; Wir trennen den String am Gleichheitszeichen
    cmd$=Lower(Trim(Left(cline$,eq-1)))
    par$=Trim(Right(cline$,Len(cline$)-eq))
    Select cmd$
      ; Hier wird der String vor dem = analysiert
    End Select
  Else
    ; Es wurde ein String ohne = eingegeben
    Select Lower(cline$)
      ; Hier werden die Eingaben analysiert.
    End Select
  End If
  cline$=""
End If

Was haben wir jetzt hier. Zunächst einmal wird die Console nach Return geschlossen, das erledigt show_con=0. Dann schauen wir nach ob es sich um eine Wertzuweisung handelt indem wir nach einem Gleichheitszeichen suchen. Wurde eines entdeckt trennen wir den String in zwei Teile, genau am Gleichheitszeichen. Trim soll sicherstellen dass der String auch dann erkannt wird wenn der User vor und/oder nach dem Gleichheitszeichen ein Leerzeichen getippt hat. Mit Lower wandeln wir den Variablennamen in Kleinbuchstaben um, das erleichtert den Vergleich.

Wurd kein Gleichheitszeichen gefunden, gehen wir davon aus dass der User einen einzelnen Befehl eingetippt hat. Beispielsweise quit um das Programm zu beenden.
Damit das Programm quit auch erkennt muss es in das Select ... Case Konstrukt.
Code: [AUSKLAPPEN]

Select Lower(cline$)
  Case "quit" : End
End Select

Sehr einfach.

Eine Variablenzuweisung ist ebenso simpel, so können wir z.B. die Blinkgeschwindigkeit des Cursors direkt in der Console ändern:
Code: [AUSKLAPPEN]

Select cmd$
  case "cursorspeed" : cursor_speed=Int(par$)
End Select

Das war auch schon das ganze Geheimnis. Ihr könnt natürlich auch ein Leerzeichen anstatt dem Gleichheitszeichen als Trennung verwenden. Durch Erweiterungen können auch Parameterketten, welche durch Kommatas getrennt sind, verarbeitet werden. Für die meisten Anwendungen sollte dieser Code hier aber genügen.
Zum Abschluss nocheinmal der komplette Code:
Code: [AUSKLAPPEN]

Global cline$
Global show_con = False
Global cursor
Global cursor_time = MilliSecs()
Global cursor_speed= 250

Function Console()
  If KeyHit(15) Then show_con=1-show_con

  If show_con

    key=GetKey()
    If key>=32 And key<=255 Then cline$=cline$+Chr(key)   

    ; Backspace
    If key=8 And (Len(cline$)-1)>=0 cline$=Left(cline$,Len(cline$)-1)

    ; Return
    If key=13
      show_con=0
      ; Gleichheitszeichen suchen
      eq=Instr(cline$,"=")
      If eq
        ; Wir trennen den String am Gleichheitszeichen
        cmd$=Lower(Trim(Left(cline$,eq-1)))
        par$=Trim(Right(cline$,Len(cline$)-eq))
        Select cmd$
          ; Hier wird der String vor dem = analysiert
          case "cursorspeed" : cursor_speed=Int(par$)
        End Select
      Else
        ; Es wurde ein String ohne = eingegeben
        Select Lower(cline$)
          ; Hier werden die Eingaben analysiert.
          case "quit" : End
        End Select
      End If
      cline$=""
    End If
   
    ; Cursor anzeigen
    If MilliSecs()-cursor_time>cursor_speed
      cursor=1-cursor
      cursor_time=MilliSecs()
    EndIf
    If cursor
      x=StringWidth(cline$)
      Text x,0,"_"
    EndIf
    Text 0,0,cline$,0,0

  EndIf
End Function

Repeat
  Cls

  Console

  Flip
Until KeyHit(1)
End


Viel Spass beim erweitern!
PIV 2,4GHz - 1GB DDR 333 - ATI Radeon9600 - WinXP - DX9.0c - BMax 1.14 - B3D 1.91 - 1280x1024x32

User posted image
 

graythread

BeitragDo, Feb 05, 2004 15:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Mh, sehr fein gemacht, nur sollteste den letzten Code entweder lauffähig machen, oder es nur bei der Funktion belassen (repeat...until weglassen).

bruZard

BeitragDo, Feb 05, 2004 15:27
Antworten mit Zitat
Benutzer-Profile anzeigen
Hmm, der Code läuft ... zudem sollte jemand, der ein Spiel mit Console schreiben will, in der Lage sein die paar Zeilen in ein Include auszulagern.
PIV 2,4GHz - 1GB DDR 333 - ATI Radeon9600 - WinXP - DX9.0c - BMax 1.14 - B3D 1.91 - 1280x1024x32

User posted image

Mr.Keks

BeitragDo, Feb 05, 2004 15:33
Antworten mit Zitat
Benutzer-Profile anzeigen
Nett geschrieben Smile

... Aber, he, kann es sein, dass du der totale Fan von Consolen bist? Sonst habe ich die noch so ziemlich keinem in der Community gesehen. Bei dir gibt es immer Consolen. Du hast ja vor längerer Zeit ja auch mal eine ins Codearchiv gepostet und so Smile
MrKeks.net
 

@uzingLG

BeitragDo, Feb 05, 2004 15:33
Antworten mit Zitat
Benutzer-Profile anzeigen
Toll! Sehr nützlich!

Aber es hatte den selben Bug wie Timemill: man kann auch was eingeben, wenn man die Konsole geschlossen hat.

Lösung: FlushKeys vor Funktionsende (nach endif)

das hab ich aus dem neuesten timemill source

Triton

BeitragDo, Feb 05, 2004 18:25
Antworten mit Zitat
Benutzer-Profile anzeigen
Inarie hat Folgendes geschrieben:
Nett geschrieben Smile

... Aber, he, kann es sein, dass du der totale Fan von Consolen bist? Sonst habe ich die noch so ziemlich keinem in der Community gesehen. Bei dir gibt es immer Consolen. Du hast ja vor längerer Zeit ja auch mal eine ins Codearchiv gepostet und so Smile


Nun, ich benutze auch immer eine Smile

Nur veröffentliche ich nie was, wo das anwendung findet. :/

Neue Antwort erstellen


Übersicht BlitzBasic FAQ und Tutorials

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group