Terminal Game mit BasCom
Das folgende Programm ist für einen ATmega32 geschrieben, sollte aber auch auf den meisten anderen AVRs zum Laufen zu bringen sein. Leider ist beim BasCom-Terminal die VT100-Emulation nicht ganz umfassend, es konnten z.B. beim Testen keine Codes für die Pfeil-Tasten empfangen werden. Für das Spiel müßte also das Hyperterm oder etwas ähnliches verwendet werden. Das Spiel ist in keiner Weise beeindruckend, anspruchsvoll oder ausgereift, es soll nur demonstrieren, wie man Terminal-Steuersequenzen anwenden kann.
http://www.roboternetz.de/wiki/uploads/Main/game.jpg
Der Ball bewegt sich kreuz und quer über den Schirm. Der Spieler kann mit den Pfeiltasten Rechts / Links den "Schläger" verschieben, und so versuchen, den Ball zu treffen. Klappt das, gibt's rechts oben einen Punkt. (Mit "C" wird ein neues Spiel gestartet)
'======================================================================================= ' ANSII Demo ' Author R.Toegel '======================================================================================== $crystal = 8000000 ' Quarzfrequenz $baud = 9600 'Baudrate für RS232
Das sind die obligaten Definitionen. Es wäre durchaus günstig, die Baudrate zu erhöhen, das Beispiel verwendet mit Absicht die Standard-Definition.
Config Timer0 = Timer , Prescale = 1024 'Timer 10mS Const Tmr_c_preload = 178 Const Tmr_c_divisor = 10 ' gives 100ms flag On Timer0 Interrupt_ticker ' Timer Dim Irptflag As Byte ' Timer Interrupt occurred Const Irpt_0 = 0 'Timer 0 Dim Divis As Byte ' timer divisor
Es wird nur der Timer0 verwendet, der auf 10 mS eingestellt ist. Mit einem weiteren Zähler wird letztlich alle 100 mS ein Flag gesetzt, der eine Ballbewegung auslöst. Das erzeugt ein moderates Spiel. Um schneller werden zu können, müßte man die Baudrate hinaufsetzen.
Const Escape = &H1B Dim Hit As Integer ' current horz-position Dim X_pos As Integer ' current horz-position Dim Y_pos As Integer ' current vert-position Dim X_dir As Integer ' horz movement Dim Y_dir As Integer ' vert movement Dim Block As Byte ' Objekt
Das sind die Felder zur Ballkontrolle. Um problemlos mit Vorzeichen rechnen zu können, sind sie als "integer" definiert.
- x_pos ist die horizontale Position am Schirm, Bereich ist 1 - 80
- y_pos ist die vertikale Position am Schirm, Bereich ist 1 - 24
- .-dir sind +1, wenn die Bewegung nach rechts / unten gehen soll, und -1, wenn umgekehrt.
- Block ist der Ascii-Code des "Balles". Im Beispiel wird einfach "blank" (=32) verwendet, das ergibt in der reversen Darstellung einen weißen/schwarzen Würfel.
Dim X_bar As Byte ' current Bar-pos left Dim X_bar2 As Byte ' current Bar-pos right Dim X_barold As Byte ' previous
Diese Felder sind für den "Schläger", der sich immer in Zeile 24 befindet.
- x_bar ist die neue Schlägerposition 1 - 75
- x_bar2 ist dessen rechtes Ende
- x_barold ist vorhergegangene Position
Dim Rxchar As Byte ' Keyboard data Dim Rxflag As Byte ' Escape-State
Rxchar ist das gerade von der Tastatur empfangene Zeichen. Rxflag wird zu Interpretation der PfeilTasten Sequenz verwendet
- <ESC>[C Pfeil rechts
- <ESC>[D Pfeil links
Timer0 = Tmr_c_preload Enable Timer0 Enable Interrupts 'General enable Start Timer0 ' timer starten Gosub Re_set Rxflag = 0
Start & Initialisierung
'============================================================================== ' M A I N L O O P '============================================================================== Do If Irptflag.irpt_0 = 1 Then ' dieser Flag wir alle 10 mS von TIM0 ISR gesetzt Irptflag.irpt_0 = 0 ' löschen Gosub Set_cursor ' Ballposition Print " "; ' Ball loeschen Print Chr(8); X_pos = X_pos + X_dir ' ein Schritt horizontal +/- If X_pos >= 80 Or X_pos <= 1 Then ' limit ? X_dir = X_dir * -1 ' ja, richtungwechsel Print Chr(7) ; ' click or beep End If If Y_pos = 1 And X_pos >= 70 Then ' wenn der "score"-Text gelöscht wird, Gosub Show_score ' dann neu schreiben End If Y_pos = Y_pos + Y_dir ' ein Schritt vertial +/- If Y_pos = 23 Then ' collision ? If X_pos >= X_bar And X_pos <= X_bar2 Then ' schlaeger flaeche ? Y_dir = Y_dir * -1 ' ja, richtungwechsel Print Chr(7) ; ' click or beep Incr Hit ' erhöhen Score Gosub Show_score ' und zeigen End If End If If Y_pos >= 24 Or Y_pos <= 1 Then 'limit vertikal ? Y_dir = Y_dir * -1 'ja, richtungwechsel Print Chr(7) ; ' click or beep End If Gosub Set_cursor ' zeichnen block neu Gosub Set_reverse ' reverse Print Chr(block); ' der "Ball" Print Chr(8); Gosub Set_normal End If Rxchar = Inkey() ' Keyboard ? If Rxchar > 0 Then Gosub Keyboard ' Yes End If Loop End
Ein Hinweis: daß nach dem Ball ein "Backspace" chr(8)gesendet wird, hat den Grund, den blinkenden Cursor gewissermaßen "hinter" dem Ball zu verstecken.
'============================================================================== ' Timer 0 interrupt '============================================================================== Interrupt_ticker: Timer0 = Tmr_c_preload ' refresh Incr Divis ' inkrementieren /10 Teiler If Divis > Tmr_c_divisor Then Divis = 0 Irptflag.irpt_0 = 1 ' setzen 10mS Flag End If Return
Die Timer-Interrupt-Routine braucht nicht näher erklärt zu werden.
Keyboard-Routine
Je nach RxFlag hat diese Routine 3 Zustände:
- 0 Im Normalfall, für alle Einzeltasten. Bei "C" wird ein Spiel-Reset durchgeführt
Wird aber das Zeichen <ESC> ( 27 , &H1B) empfangen, wechselt der Zustand auf "1"
- 1 Nach einem Escape-Zeichen darf in unserm Spiel nur "[" kommen, was den Zustand auf "2" setzt, jedes andere Zeichen geht wieder auf "0", ein Klicken wird ausgelöst.
- 2 Jetzt kann "C" für Pfeil rechts oder "D" für Pfeil links kommen. darauf reagiert das Spiel, indem es die "Schläger" -Position verändert.
Auf jeden Fall ist die Sequenz aber beendet, wir gehen wieder auf Zustand "0" = normal
Keyboard: Select Case Rxflag Case 0: Select Case Rxchar Case Escape: Rxflag = 1 Case "C": Gosub Re_set Case "c": Gosub Re_set Case Else: Print Chr(7) ; ' click or beep End Select Case 1: If Rxchar = "[" Then Rxflag = 2 ' <ESC>[ Else Rxflag = 0 End If Case 2: Select Case Rxchar Case "C": ' Arr RIGHT If X_bar < 75 Then Incr X_bar Gosub Draw_bar End If Case "D": ' Arr LEFT If X_bar > 2 Then Decr X_bar Gosub Draw_bar End If End Select Rxflag = 0 ' anyhow End Select Return Die folgenden Routinen sind "gosubs", um das Programm übersichtlicher zu machen. Re_set: Gosub Clear_screen X_pos = 31 Y_pos = 1 Gosub Set_cursor Gosub Set_reverse Print " S T A R T VT100 "; ' text Gosub Set_normal X_pos = 1 X_dir = 1 Y_pos = 1 Y_dir = 1 Block = 32 Hit = 0 X_bar = 38 X_barold = X_bar Gosub Draw_bar Gosub Show_score Return '------------------------------------------------------------------- Draw_bar: Print Chr(escape) ; "[24;" ; Str(x_barold) ; "H "; Print Chr(escape) ; "[24;" ; Str(x_bar) ; "Hxxxxx"; X_bar2 = X_bar + 4 X_barold = X_bar Return '------------------------------------------------------------------- Show_score: Print Chr(escape) ; "[1;70" ; "HScore:" ; Str(hit) ; Return '------------------------------------------------------------------- Clear_screen: Print Chr(escape) ; "[1;1H"; 'Home Print Chr(escape) ; "[2J"; 'clear terminal screen Return '------------------------------------------------------------------- Set_cursor: Print Chr(escape) ; "[" ; Str(y_pos) ; ";" ; Str(x_pos) ; "H"; Return '------------------------------------------------------------------- Set_reverse: Print Chr(escape) ; "[7m" ; Return '------------------------------------------------------------------- Set_normal: Print Chr(escape) ; "[0m"; Return
Vielleicht konnte ich jemanden auf den Geschmack bringen, eigene Versuche weiterzuführen.