|
Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
Progger_X Mr. Lagg
Anmeldungsdatum: 24.11.2004 Beiträge: 784 Wohnort: Leipzig
|
Verfasst am: 20.11.2005, 00:51 Titel: Abstürzender Code |
|
|
Hallo!
Ich habe mal wieder versucht, ein kleines Netzwerkspiel zu schreiben. Diesmal hab ich mal etwas leichteres versucht, so eine Art die Stämme oder so, bloß halt derzeitig für 2 Spieler.
Hier ist der Code:
Code: | '$INCLUDE: "SDL/SDL_NET.bi"
DECLARE SUB Connect(socket as tcpsocket,nummer)
OPTION EXPLICIT
TYPE spielereigenschaften
gold AS integer
goldmiene AS integer
krieger AS integer
wall AS integer
angreifen AS integer
END TYPE
DIM spieler(5) AS spielereigenschaften
DIM SHARED AS byte threadcontrol=0
SCREEN 18,8,3,0
COLOR 1,7
CLS
DIM sockclient AS tcpsocket
DIM nummer AS integer
Connect(sockclient,nummer)
DIM gegi AS integer
IF nummer=1 THEN gegi=2 ELSE gegi=1
spieler(1).goldmiene=1
spieler(2).goldmiene=1
spieler(1).krieger=50
spieler(2).krieger=50
spieler(1).wall=2
spieler(2).wall=2
DIM nachricht AS string
DIM t#
t#=TIMER
DIM e AS integer
DIM dummy AS string
DIM zahler AS integer
DIM gold AS integer
DIM krieger AS integer
DIM gm AS integer
DIM angr AS integer
DIM vert AS integer
DIM wall AS integer
DIM angreifen AS integer
WHILE e=0
IF TIMER-t#>1 THEN
GOSUB senden
t#=TIMER
END IF
GOSUB tasten
GOSUB bildschirm
SLEEP 30
WEND
END
tasten:
IF MULTIKEY(&h02) AND spieler(nummer).goldmiene*spieler(nummer).goldmiene<spieler(nummer).gold THEN
spieler(nummer).gold=spieler(nummer).gold-spieler(nummer).goldmiene*spieler(nummer).goldmiene
spieler(nummer).goldmiene=spieler(nummer).goldmiene+1
END IF
IF MULTIKEY(&H03) AND spieler(nummer).gold>10 THEN
spieler(nummer).gold=spieler(nummer).gold-10
spieler(nummer).krieger=spieler(nummer).krieger+1
END IF
IF MULTIKEY(&H04) AND spieler(nummer).gold>1000 THEN
spieler(nummer).gold=spieler(nummer).gold-1000
spieler(nummer).krieger=spieler(nummer).krieger+100
END IF
IF MULTIKEY(&H05) AND spieler(nummer).wall*spieler(nummer).wall<spieler(nummer).gold THEN
spieler(nummer).gold=spieler(nummer).gold-spieler(nummer).wall*spieler(nummer).wall
spieler(nummer).wall=spieler(nummer).wall+1
END IF
IF MULTIKEY(&H06) AND spieler(nummer).krieger>0 THEN
spieler(nummer).angreifen=1
END IF
IF MULTIKEY(&H01) THEN e=1
dummy$=INKEY$
' IF spieler(nummer).gold<0 THEN spieler(nummer).gold=0
RETURN
senden:
nachricht=""
zahler=0
spieler(nummer).gold=spieler(nummer).gold+spieler(nummer).goldmiene*5
gold=spieler(nummer).gold
gm=spieler(nummer).goldmiene
krieger=spieler(nummer).krieger
wall=spieler(nummer).wall
angreifen=spieler(nummer).angreifen
SDLNET_TCP_SEND(sockclient, @gold,2)
SDLNET_TCP_SEND(sockclient, @gm,2)
SDLNET_TCP_SEND(sockclient, @krieger,2)
SDLNET_TCP_SEND(sockclient, @wall,2)
SDLNET_TCP_SEND(sockclient, @angreifen,2)
SDLNET_TCP_RECV(sockclient, @gold,2)
SDLNET_TCP_RECV(sockclient, @gm,2)
SDLNET_TCP_RECV(sockclient, @krieger,2)
SDLNET_TCP_RECV(sockclient, @wall,2)
SDLNET_TCP_RECV(sockclient, @angreifen,2)
spieler(gegi).gold=gold
spieler(gegi).goldmiene=gm
spieler(gegi).krieger=krieger
spieler(gegi).wall=wall
spieler(gegi).angreifen=angreifen
IF spieler(gegi).angreifen<>spieler(nummer).angreifen THEN
IF spieler(nummer).angreifen=1 THEN
angr=nummer
vert=gegi
END IF
IF spieler(gegi).angreifen=1 THEN
angr=gegi
vert=nummer
END IF
IF spieler(angr).krieger>spieler(vert).wall*spieler(vert).krieger THEN
nachricht="Der Angreifer gewann"
spieler(angr).gold=spieler(angr).gold+spieler(vert).gold
spieler(vert).gold=0
spieler(angr).krieger=spieler(angr).krieger-spieler(vert).krieger*spieler(vert).wall
spieler(vert).krieger=0
END IF
IF spieler(angr).krieger<spieler(vert).wall*spieler(vert).krieger THEN
nachricht="Der Verteidiger gewann"
spieler(vert).krieger=CINT((spieler(vert).krieger*spieler(vert).wall-spieler(angr).krieger)/spieler(vert).wall)
spieler(angr).krieger=0
END IF
END IF
IF spieler(gegi).angreifen=1 AND spieler(nummer).angreifen=1 THEN
nachricht="Beide griffen an, waren in der gegnerischen Stadt und plünderten sie"
gold=spieler(gegi).gold
spieler(gegi).gold=spieler(nummer).gold
spieler(nummer).gold=gold
END IF
spieler(1).angreifen=0
spieler(2).angreifen=0
RETURN
bildschirm:
SCREENLOCK
CLS
PRINT spieler(nummer).angreifen
PRINT spieler(gegi).angreifen
PRINT "Gold(1): "+STR$(spieler(1).gold)
PRINT "Goldmiene(1): "+STR$(spieler(1).goldmiene)+" Kosten einer neuen Miene: "+_
STR$(spieler(1).goldmiene*spieler(1).goldmiene)+" Gold"
PRINT "Krieger(1): "+STR$(spieler(1).krieger)
PRINT "Wall(1): "+STR$(spieler(1).wall)
PRINT "Gold(2): "+STR$(spieler(2).gold)
PRINT "Goldmiene(2): "+STR$(spieler(2).goldmiene)+_
" Kosten einer neuen Miene: " + STR$(spieler(2).goldmiene*spieler(2).goldmiene)+" Gold"
PRINT "Krieger(2): "+STR$(spieler(2).krieger)
PRINT "Wall(2): "+STR$(spieler(2).wall) +_
" Kosten eines neuen Walls: " + STR$(spieler(2).wall*spieler(2).wall)+" Gold"
IF spieler(nummer).goldmiene*spieler(nummer).goldmiene<spieler(nummer).gold THEN
PRINT "Goldmiene Bauen=1"
END IF
IF spieler(nummer).gold>10 THEN
PRINT "Söldner anwerben=2"
END IF
IF spieler(nummer).gold>1000 THEN
PRINT "100 Söldner anwerben=3"
END IF
IF spieler(nummer).wall*spieler(nummer).wall<spieler(nummer).gold THEN
PRINT "Wall Bauen=4"
END IF
IF spieler(nummer).krieger>0 AND spieler(nummer).angreifen<>1 THEN
PRINT "Angreifen = 5"
END IF
IF spieler(nummer).angreifen=1 THEN
PRINT "Angriff läuft...."
END IF
PRINT nachricht
SCREENUNLOCK
RETURN
SUB Connect(socket as tcpsocket,nummer)
DIM dummy AS string
IF SDLNet_Init() <> 0 THEN
PRINT "Fehler"
SLEEP
END
END IF
PRINT "1-Server"
PRINT "2-Client"
DO
dummy$=INKEY$
nummer=VAL(dummy$)
IF dummy$=CHR$(27) THEN END
LOOP UNTIL nummer=1 OR nummer=2
DIM sock AS tcpsocket'Socket einstellen
DIM sockclient AS tcpsocket
DIM ip AS ipaddress'Variable IP vom Typ IP Addresse
DIM zahler AS integer
IF nummer=1 THEN
SDLNet_Write32( INADDR_ANY, @ip.host )
SDLNet_Write16( 5678, @ip.port )
sock = SDLNet_TCP_Open( @ip )'TCP Verbindung öffnen, in den Socket schreiben
zahler=1
PRINT "Warte auf Client..."
WHILE sockclient = NULL
IF INKEY$=CHR$(27) THEN END
sockclient = SDLNet_TCP_Accept( sock )
SLEEP 5
WEND
END IF
IF nummer=2 THEN
DIM host AS string
INPUT "IP Addresse des Hostes: ", host$
SDLNet_ResolveHost( @ip, host$, 5678 )
sockclient = SDLNet_TCP_Open( @ip )
END IF
socket=sockclient
END SUB
|
Leider stürzt der Code manchmal ab, wenn man Krieger baut(nicht immer, nur manchmal, und zwar dann, wenn man sehr nah an 0 Gold ist; genau seh ich das nie)
Weiß jemand, woran das liegt, bzw. wie man das beheben kann?
Zuletzt bearbeitet von Progger_X am 20.11.2005, 01:27, insgesamt einmal bearbeitet |
|
Nach oben |
|
|
psygate
Anmeldungsdatum: 05.04.2005 Beiträge: 304 Wohnort: Wien und der Computer
|
Verfasst am: 20.11.2005, 00:57 Titel: |
|
|
ich hab jetzt das ding nciht genau gelesen... aber, ich hätte da was:
1. Hatst du eine sperre eingebaut, dass wenn man nicht genug gold für einen krieger hat, auch keinen mehr bauen kann?
2. Hast du eien Sperre eingebaut, dass die GOld-Werte nicht negativ werden können? |
|
Nach oben |
|
|
Progger_X Mr. Lagg
Anmeldungsdatum: 24.11.2004 Beiträge: 784 Wohnort: Leipzig
|
Verfasst am: 20.11.2005, 01:24 Titel: |
|
|
Jap, habe ich:
Code: | tasten:
IF MULTIKEY(&h02) AND spieler(nummer).goldmiene*spieler(nummer).goldmiene<spieler(nummer).gold THEN
spieler(nummer).gold=spieler(nummer).gold-spieler(nummer).goldmiene*spieler(nummer).goldmiene
spieler(nummer).goldmiene=spieler(nummer).goldmiene+1
END IF
IF MULTIKEY(&H03) AND spieler(nummer).gold>10 THEN
spieler(nummer).gold=spieler(nummer).gold-10
spieler(nummer).krieger=spieler(nummer).krieger+1
END IF
IF MULTIKEY(&H04) AND spieler(nummer).gold>1000 THEN
spieler(nummer).gold=spieler(nummer).gold-1000
spieler(nummer).krieger=spieler(nummer).krieger+100
END IF
IF MULTIKEY(&H05) AND spieler(nummer).wall*spieler(nummer).wall<spieler(nummer).gold THEN
spieler(nummer).gold=spieler(nummer).gold-spieler(nummer).wall*spieler(nummer).wall
spieler(nummer).wall=spieler(nummer).wall+1
END IF
IF MULTIKEY(&H06) AND spieler(nummer).krieger>0 THEN
spieler(nummer).angreifen=1
END IF
IF MULTIKEY(&H01) THEN e=1
dummy$=INKEY$
RETURN |
Dort wird ja bei jeder Schleife geprüft, ob genug Gold da ist. Deshalb kann das Gold ja auch keinem weg negativ werden, da der andere Spieler ja in der Zeit nichts macht(ich hab nur einen Computer als Client reingemacht, damit es sendet; auf dem anderen Computer habe ich nichts gemacht).
/EDIT: was ich gerade gemerkt hab: der Code stürzt immer ab, wenn man eine Taste gedrückt hält und ein wenig das Programm laufen lässt. Bei welchen Tasten es abstürzt, weiß ich aber leider noch nicht. |
|
Nach oben |
|
|
MisterD
Anmeldungsdatum: 10.09.2004 Beiträge: 3071 Wohnort: bei Darmstadt
|
Verfasst am: 20.11.2005, 12:17 Titel: |
|
|
das hatt ich auch mal.. so beim 340sten Inkey mit Inhalt ist mir mein Programm jedes mal einfach weggebrochen ohne das ich die chance hatte, irgendwelche Fehler abzufangen. Da is irgend ein Bug drin den man aber mal wieder nich genau loklisieren kann.. _________________ "It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration."
Edsger W. Dijkstra |
|
Nach oben |
|
|
Progger_X Mr. Lagg
Anmeldungsdatum: 24.11.2004 Beiträge: 784 Wohnort: Leipzig
|
Verfasst am: 20.11.2005, 12:19 Titel: |
|
|
Und wie kann ich das beseitigen?
(außer Maussteuerung) |
|
Nach oben |
|
|
tilli
Anmeldungsdatum: 10.09.2005 Beiträge: 73
|
Verfasst am: 20.11.2005, 20:29 Titel: |
|
|
Moin,
kleiner Tipp: (weis ich auch nur, weil ich es heute gelesen habe):
In der Referenz für Multikey steht:
Zitat: | Sie müssen also den Tastaturpuffer leeren, nachdem Sie MULTIKEY verwendet
haben Code: | 1 WHILE INKEY$ <> "": WEND
|
|
Möglicherweise liegt es daran ...
wenngleich ich das nicht so pralle finde - man sollte den Tastaturpuffer eher Abstellen können... aber man kann sicherlich mit leben.
CU2
Tilli |
|
Nach oben |
|
|
Michael712 aka anfänger, programmierer
Anmeldungsdatum: 26.03.2005 Beiträge: 1593
|
Verfasst am: 20.11.2005, 21:14 Titel: |
|
|
Oder man macht einen thread, in dem dann die ganze zeit inkey$ abgefragt wird. Denn ich bin mir nicht sicher, aber wenn man das in der hauptschleife hat, könnte dadurch das Programm dann nicht stehen bleiben, wenn man eine taste durchdrückt?
Michael _________________
Code: | #include "signatur.bi" |
|
|
Nach oben |
|
|
Progger_X Mr. Lagg
Anmeldungsdatum: 24.11.2004 Beiträge: 784 Wohnort: Leipzig
|
Verfasst am: 20.11.2005, 21:46 Titel: |
|
|
Das mache ich ja, den Tastaturpuffer mit INKEY$ leeren.
Wenn ich den jedoch in nem thread leere, dann hab ich ja nix mehr zum auslesen für MULTIKEY.
Ja, durch den code von Tilli würde das Programm so lange angehalten werden, bis keine Taste gedrückt wird.
Irgendwie muss es da eine andere Möglichkeit geben, den Tastaturpuffer zu leeren(ohne INKEY$) |
|
Nach oben |
|
|
MisterD
Anmeldungsdatum: 10.09.2004 Beiträge: 3071 Wohnort: bei Darmstadt
|
Verfasst am: 21.11.2005, 00:27 Titel: |
|
|
doch, das müsste auch in nem extra thread funktionieren, multikey ist ja eigentlich nicht von inkey abhängig sondern andersrum.. _________________ "It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration."
Edsger W. Dijkstra |
|
Nach oben |
|
|
tilli
Anmeldungsdatum: 10.09.2005 Beiträge: 73
|
Verfasst am: 21.11.2005, 01:18 Titel: |
|
|
Moin,
Ich weis nicht genau, wie die multikeyroutine eingebundenist, aber wenn sie parallel zum Tastaturpuffer arbeitet, was sie eigentlich müsste,wenn sie richtig eingearbeitet ist, wovon ich ausgehe, und das ist wieder so ein Bandwurmsatz ... DMD ...
Also: Wenn es so ist, wie ich vermute, dann ist die Tastaturpufferroutine(inkey$) parallel zu der Tastaturstaturroutine(multikey) angeordnet.
Multikey kann ja nur den aktuellen Status wiedergeben, wohingegen inkey$ wenn nötig 5 Stunden und mehr Zwischenspeichert, aber halt nur soviel wie in den Tastaturpuffer reingeht - könnte 256 Zeichen sein(würde etwa mit den 340 von MrD übereinstimmen, ist aber eine 2er Potenz und damit von Programmierern wahrscheinlicher gewählt).
Möglich auch, dass Windoof das erkennt und den Puffer autokratisch leert.
zudem steht es in der Anleitung (wer auch immer die ursprünglich verfasst hat.)
Ich würde es einfach mal ausprobieren - wenn es das nicht ist, kostet das sicherlich weniger Zeit, als wenn wir weiter diskutieren ... :
CU2
Tilli |
|
Nach oben |
|
|
MisterD
Anmeldungsdatum: 10.09.2004 Beiträge: 3071 Wohnort: bei Darmstadt
|
Verfasst am: 21.11.2005, 14:54 Titel: |
|
|
ne stimmt bestimmt ned überein. Das könnte zwar grob hinkommen, aber ich hab den tastaturpuffer erstens dauernd abgefragt, der lief in ner dauerschleife (Taste=nächtes Bild, 350 oder so gabs und um 340 rum is er immer abgeschissen. Er hat aber auch nicht bei jedem drücken weitergeschaltet sonder manche tasten verschluckt...). Also damit hat das mMn nichts zu tun. _________________ "It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration."
Edsger W. Dijkstra |
|
Nach oben |
|
|
tilli
Anmeldungsdatum: 10.09.2005 Beiträge: 73
|
Verfasst am: 23.11.2005, 23:30 Titel: |
|
|
Moin,
tut mir leid, dass es nicht funktioniert.
Mir kam da noach eine Idee - bezüglich der Verbindungen - die sind hoffentlich geschlossen, nachdem sie geöffnet wurden (ich kann das aus dem Code jetzt nicht so genau herauslesen)... Ich kam drauf, weil auch das eventuell einen Puffer an möglichen geöffneten Verbindungen füllen könnte, der dann überläuft ... allerdings ist das jetzt eher im Bereich Spekulation unterzubringen, da ich mich mit sowas bisher nicht beschäftigt habe.(die "sock = ..." Zeile steht kommentiert als 'TCP-Verbindung öffnen - ein Schließen sehe ich aber nicht)
Was mir am Code Auffällt, ist, dass ide Variablen nicht zwangsläufig zwischengespeichert werden, bzw die Variablenadressen nicht eindeutig sein müssen.(es sei denn da gibt es wieder irgendeien Schalter für)
->
Ich würde mal versuchen die Variablen - speziell jene der sub "connect"- entweder extern shared oder static zu definieren - ansonsten ist es prinzipiell möglich, dass sie sich vom Speicherplatz her überlagern - was dann passieren kann weis sicherlich nicht einmal der big Papa in Rom
Aber bitte nicht böse sein, wenn es das nicht ist ...
CU2
Tilli
------------
never give up |
|
Nach oben |
|
|
Progger_X Mr. Lagg
Anmeldungsdatum: 24.11.2004 Beiträge: 784 Wohnort: Leipzig
|
Verfasst am: 24.11.2005, 17:52 Titel: |
|
|
Das ist es mit sicherheit nicht, denn der Code stürzt auch ohne Netzwerk part ab:
Code: | OPTION EXPLICIT
TYPE spielereigenschaften
gold AS integer
goldmiene AS integer
krieger AS integer
wall AS integer
angreifen AS integer
END TYPE
DIM spieler(5) AS spielereigenschaften
SCREEN 18,8,3,0
COLOR 1,7
CLS
spieler(1).goldmiene=1
DIM zahler AS integer, e AS integer, nummer AS integer
DIM t#
DIM dummy AS string, nachricht AS string
t#=TIMER
nummer=1
WHILE e=0
IF TIMER-t#>1 THEN
spieler(nummer).gold=spieler(nummer).gold+spieler(nummer).goldmiene*5
t#=TIMER
END IF
GOSUB tasten
GOSUB bildschirm
SLEEP 30
WEND
END
tasten:
IF MULTIKEY(&h02) AND spieler(nummer).goldmiene*spieler(nummer).goldmiene<spieler(nummer).gold THEN
spieler(nummer).gold=spieler(nummer).gold-spieler(nummer).goldmiene*spieler(nummer).goldmiene
spieler(nummer).goldmiene=spieler(nummer).goldmiene+1
END IF
IF MULTIKEY(&H03) AND spieler(nummer).gold>10 THEN
spieler(nummer).gold=spieler(nummer).gold-10
spieler(nummer).krieger=spieler(nummer).krieger+1
END IF
IF MULTIKEY(&H04) AND spieler(nummer).gold>1000 THEN
spieler(nummer).gold=spieler(nummer).gold-1000
spieler(nummer).krieger=spieler(nummer).krieger+100
END IF
IF MULTIKEY(&H05) AND spieler(nummer).wall*spieler(nummer).wall<spieler(nummer).gold THEN
spieler(nummer).gold=spieler(nummer).gold-spieler(nummer).wall*spieler(nummer).wall
spieler(nummer).wall=spieler(nummer).wall+1
END IF
IF MULTIKEY(&H06) AND spieler(nummer).krieger>0 THEN
spieler(nummer).angreifen=1
END IF
IF MULTIKEY(&H01) THEN e=1
dummy$=INKEY$
RETURN
bildschirm:
SCREENLOCK
CLS
PRINT "Gold(1): "+STR$(spieler(1).gold)
PRINT "Goldmiene(1): "+STR$(spieler(1).goldmiene)+" Kosten einer neuen Miene: "+_
STR$(spieler(1).goldmiene*spieler(1).goldmiene)+" Gold"
PRINT "Krieger(1): "+STR$(spieler(1).krieger)
PRINT "Wall(1): "+STR$(spieler(1).wall)
IF spieler(nummer).goldmiene*spieler(nummer).goldmiene<spieler(nummer).gold THEN
PRINT "Goldmiene Bauen=1"
END IF
IF spieler(nummer).gold>10 THEN
PRINT "Söldner anwerben=2"
END IF
IF spieler(nummer).gold>1000 THEN
PRINT "100 Söldner anwerben=3"
END IF
IF spieler(nummer).wall*spieler(nummer).wall<spieler(nummer).gold THEN
PRINT "Wall Bauen=4"
END IF
IF spieler(nummer).krieger>0 AND spieler(nummer).angreifen<>1 THEN
PRINT "Angreifen = 5"
END IF
IF spieler(nummer).angreifen=1 THEN
PRINT "Angriff läuft...."
END IF
PRINT nachricht
SCREENUNLOCK
RETURN
|
|
|
Nach oben |
|
|
Eastler_dart
Anmeldungsdatum: 25.09.2005 Beiträge: 177 Wohnort: Baden-Würtemberg + Sachsen
|
Verfasst am: 24.11.2005, 21:13 Titel: |
|
|
Hm. Heißes Thema habt Ihr hier
Auch wenn ich mit den Multikey-Befehl nicht benutze,
- oder vielleicht auch grad deswegen -,
hab ich dein Listing mal an mein FreeBasic 0.14 Win
verfüttert.
hihi, jetzt weiß ich endlich, wie die in "die Stämme" hochzählen.
Hatte mir noch nie Gedanken drüber gemacht.
Aber jetzt mal im Ernst, was mir so auffällt:
paar mal Goldmine gebaut, mich ans Prog gewöhnt,
dann mitgerechnet.
Uaahhhh, der rechnet ja falsch!
hat über 1000 Einheiten Gold, will fünfhundertungrad
um die Miene auszubauen und hat danach nur noch
n paar einzelne Goldeinheiten. Puhh. Eigentlich
sollten so um die 500 noch da sein.
Listing Buchstabe für Buchstabe kontrolliert.
kein Fehler fällt auf.
Logischer Ablauf gecheckt: aha, das könnts sein:
es wird erst die Mine gebaut und danach
das neueste Ergebnis angezeigt.
hm.
Also die beiden Befehle
GOSUB tasten und GOSUB bildschirm in der Reihenfolge
getauscht. Also erst Ergebnis Anzeigen, und wenn das dann
auf dem Monitor steht, nach ner Taste fragen.
Neu Compiliert und wieder testen.
Wieder so n durcheinander, manchmal stimmts einfach
net, wenn man nachrechnet. Geht aber alles auch so
schnell mit dem Weiterzählen des Goldbestandes.
Den Zeitfaktor rausgehauen und durch manuelles
Space-Drücken per Inkey$ ersetzt.
Nun bleibt Goldbestand stehen, bis ich Space drücke.
Dann wars zu erkennen:
Nix Rechenfehler, sondern DOPPELFUNKTION.
Bei zu lang gedrückter "1" (millisekunden) und genügend Goldbestand
hat das Prog gleich 2 mal die Mine erweitert!
So. Weiterdenken.
Diesen Umstand wirst du ja deinen Prog-Nutzern nicht
zumunten wollen. Hm.
Gibt ja dazu 2 Wege.
1) Bleib bei Multikey und fang dahinter per
Code: |
DO
dummy$=INKEY$
LOOP UNTIL INKEY$=""
|
die doppelten Tastenanschläge ab.
Deine Zeile dummy$=INKEY$ holt nur jeweils 1 Tastenanschlag ab!
Wer weiß schon, ob durch das parallele Multikey nicht mehr als
dieser eine im Puffer stehen?
Aber am Ende ist das ja ein Umweg, oder nicht?
Wär es nicht besser, gleich mittels Variable$=INKEY$
die Taste in einer Variable zu speichern und
anhand dieser Variablen dann die Eingabe zu prüfen?
Code: |
tasten:
Eingabe$=INKEY$
REM Goldmine*Goldmine in Var speichern,
REM dann braucht das nur einmal berechnet werden
GoldPreis=spieler(nummer).goldmiene*spieler(nummer).goldmiene
SELECT CASE VARIABLE$
CASE "1" : REM Taste 1 gedrückt, Goldmine ausbauen
IF GoldPreis<spieler(nummer).gold THEN
spieler(nummer).gold=spieler(nummer).gold-GoldPreis
spieler(nummer).goldmiene=spieler(nummer).goldmiene+1
END IF
CASE "2" : REM Taste 2 gedrückt, einen Krieger anheuern
IF spieler(nummer).gold > 10 THEN
spieler(nummer).gold=spieler(nummer).gold-10
spieler(nummer).krieger=spieler(nummer).krieger+1
END IF
'.
'.
'.
END SELECT
REM Tataturpuffer leeren
DO
dummy$=INKEY$
LOOP UNTIL INKEY$=""
RETURN
|
die VIELEN Multikey-Tastaturabfragen für jede erlaubte Taste
würden durch eine einzige Abfrage wie Eingabe$=INKEY$
ersetzt, soviel Zeit verlierst du damit dann doch nicht,
wobei ich sowieso bezweifle, ob in diesem Programm
wirklich der Zeitfaktor bei der Tasteneingabe wichtig ist.
Ach ja, in meiner "Testversion" deines Programmes,
in der ich den Zeitfaktor für die Goldgewinnung per
IF Eingabe$=" " THEN blablabla
geändert hatte, hab ich meinen Taschenrechner
auf die Space-Taste für das Hochzählen gelegt.
Kein Absturz durch Space-Dauerfeuer!
Hoffe, diese Anregungen haben dir geholfen.
Tschüsserling bis denneweng
euer Eastler _________________ Kaum macht mans richtig, schon geht's |
|
Nach oben |
|
|
Progger_X Mr. Lagg
Anmeldungsdatum: 24.11.2004 Beiträge: 784 Wohnort: Leipzig
|
Verfasst am: 25.11.2005, 16:49 Titel: |
|
|
Hi!
Danke, du hast mir schon sehr geholfen. Ich dachte immer, das INKEY$ den Tastaturspeicher vollständig leert.
Problem bei diesem Code
Code: | DO
dummy$=INKEY$
LOOP UNTIL INKEY$="" |
ist, das es dann ja zu enormen Verzögerungen kommen kann, wenn man eine taste länger drückt, so das das senden dann nicht klappen kann.
Hast du eine Idee, wie man dass umgehen kann?
/EDIT:
Meine Idee wäre, das in nem Thread zu machen:
Code: | '$INCLUDE: "SDL/SDL_NET.bi"
DECLARE SUB Connect(socket as tcpsocket,nummer)
DECLARE SUB tastenabfrage(threadcontrol)
OPTION EXPLICIT
TYPE spielereigenschaften
gold AS integer
goldmiene AS integer
krieger AS integer
wall AS integer
angreifen AS integer
END TYPE
DIM SHARED spieler(5) AS spielereigenschaften
SCREEN 18,8,3,0
COLOR 1,7
CLS
DIM sockclient AS tcpsocket
DIM SHARED nummer AS integer, gegi AS integer
Connect(sockclient,nummer)
IF nummer=1 THEN gegi=2 ELSE gegi=1
spieler(1).goldmiene=1
spieler(2).goldmiene=1
spieler(1).krieger=50
spieler(2).krieger=50
spieler(1).wall=2
spieler(2).wall=2
DIM nachricht AS string
DIM t#
t#=TIMER
DIM SHARED e AS integer
DIM SHARED dummy AS string
DIM zahler AS integer
DIM gold AS integer
DIM krieger AS integer
DIM gm AS integer
DIM angr AS integer
DIM vert AS integer
DIM wall AS integer
DIM angreifen AS integer
DIM SHARED AS byte threadcontrol=0
DIM thread_tasten AS integer
thread_tasten = threadcreate(@tastenabfrage, 0)
WHILE e=0
IF TIMER-t#>1 THEN
GOSUB senden
t#=TIMER
END IF
GOSUB bildschirm
SLEEP 30
WEND
threadcontrol=1
THREADWAIT thread_tasten
END
senden:
nachricht=""
zahler=0
spieler(nummer).gold=spieler(nummer).gold+spieler(nummer).goldmiene*5
gold=spieler(nummer).gold
gm=spieler(nummer).goldmiene
krieger=spieler(nummer).krieger
wall=spieler(nummer).wall
angreifen=spieler(nummer).angreifen
SDLNET_TCP_SEND(sockclient, @gold,LEN(gold))
SDLNET_TCP_SEND(sockclient, @gm,LEN(gm))
SDLNET_TCP_SEND(sockclient, @krieger,LEN(krieger))
SDLNET_TCP_SEND(sockclient, @wall,LEN(wall))
SDLNET_TCP_SEND(sockclient, @angreifen,LEN(angreifen))
SDLNET_TCP_RECV(sockclient, @gold,LEN(gold))
SDLNET_TCP_RECV(sockclient, @gm,LEN(gm))
SDLNET_TCP_RECV(sockclient, @krieger,LEN(krieger))
SDLNET_TCP_RECV(sockclient, @wall,LEN(wall))
SDLNET_TCP_RECV(sockclient, @angreifen,LEN(angreifen))
spieler(gegi).gold=gold
spieler(gegi).goldmiene=gm
spieler(gegi).krieger=krieger
spieler(gegi).wall=wall
spieler(gegi).angreifen=angreifen
IF spieler(gegi).angreifen<>spieler(nummer).angreifen THEN
IF spieler(nummer).angreifen=1 THEN
angr=nummer
vert=gegi
END IF
IF spieler(gegi).angreifen=1 THEN
angr=gegi
vert=nummer
END IF
IF spieler(angr).krieger>spieler(vert).wall*spieler(vert).krieger THEN
nachricht="Der Angreifer gewann"
spieler(angr).gold=spieler(angr).gold+spieler(vert).gold
spieler(vert).gold=0
spieler(angr).krieger=spieler(angr).krieger-spieler(vert).krieger*spieler(vert).wall
spieler(vert).krieger=0
END IF
IF spieler(angr).krieger<spieler(vert).wall*spieler(vert).krieger THEN
nachricht="Der Verteidiger gewann"
spieler(vert).krieger=CINT((spieler(vert).krieger*spieler(vert).wall-spieler(angr).krieger)/spieler(vert).wall)
spieler(angr).krieger=0
END IF
END IF
IF spieler(gegi).angreifen=1 AND spieler(nummer).angreifen=1 THEN
nachricht="Beide griffen an, waren in der gegnerischen Stadt und plünderten sie"
gold=spieler(gegi).gold
spieler(gegi).gold=spieler(nummer).gold
spieler(nummer).gold=gold
END IF
spieler(1).angreifen=0
spieler(2).angreifen=0
RETURN
bildschirm:
SCREENLOCK
CLS
PRINT spieler(nummer).angreifen
PRINT spieler(gegi).angreifen
PRINT "Gold(1): "+STR$(spieler(1).gold)
PRINT "Goldmiene(1): "+STR$(spieler(1).goldmiene)+" Kosten einer neuen Miene: "+_
STR$(spieler(1).goldmiene*spieler(1).goldmiene)+" Gold"
PRINT "Krieger(1): "+STR$(spieler(1).krieger)
PRINT "Wall(1): "+STR$(spieler(1).wall)
PRINT "Gold(2): "+STR$(spieler(2).gold)
PRINT "Goldmiene(2): "+STR$(spieler(2).goldmiene)+_
" Kosten einer neuen Miene: " + STR$(spieler(2).goldmiene*spieler(2).goldmiene)+" Gold"
PRINT "Krieger(2): "+STR$(spieler(2).krieger)
PRINT "Wall(2): "+STR$(spieler(2).wall) +_
" Kosten eines neuen Walls: " + STR$(spieler(2).wall*spieler(2).wall)+" Gold"
IF spieler(nummer).goldmiene*spieler(nummer).goldmiene<spieler(nummer).gold THEN
PRINT "Goldmiene Bauen=1"
END IF
IF spieler(nummer).gold>10 THEN
PRINT "Söldner anwerben=2"
END IF
IF spieler(nummer).gold>1000 THEN
PRINT "100 Söldner anwerben=3"
END IF
IF spieler(nummer).wall*spieler(nummer).wall<spieler(nummer).gold THEN
PRINT "Wall Bauen=4"
END IF
IF spieler(nummer).krieger>0 AND spieler(nummer).angreifen<>1 THEN
PRINT "Angreifen = 5"
END IF
IF spieler(nummer).angreifen=1 THEN
PRINT "Angriff läuft...."
END IF
PRINT nachricht
SCREENUNLOCK
RETURN
SUB tastenabfrage(threadcontrol)
WHILE threadcontrol=1
IF MULTIKEY(&h02) AND spieler(nummer).goldmiene*spieler(nummer).goldmiene<spieler(nummer).gold THEN
spieler(nummer).gold=spieler(nummer).gold-spieler(nummer).goldmiene*spieler(nummer).goldmiene
spieler(nummer).goldmiene=spieler(nummer).goldmiene+1
END IF
IF MULTIKEY(&H03) AND spieler(nummer).gold>10 THEN
spieler(nummer).gold=spieler(nummer).gold-10
spieler(nummer).krieger=spieler(nummer).krieger+1
END IF
IF MULTIKEY(&H04) AND spieler(nummer).gold>1000 THEN
spieler(nummer).gold=spieler(nummer).gold-1000
spieler(nummer).krieger=spieler(nummer).krieger+100
END IF
IF MULTIKEY(&H05) AND spieler(nummer).wall*spieler(nummer).wall<spieler(nummer).gold THEN
spieler(nummer).gold=spieler(nummer).gold-spieler(nummer).wall*spieler(nummer).wall
spieler(nummer).wall=spieler(nummer).wall+1
END IF
IF MULTIKEY(&H06) AND spieler(nummer).krieger>0 THEN
spieler(nummer).angreifen=1
END IF
IF MULTIKEY(&H01) THEN e=1
DO
dummy$=INKEY$
LOOP UNTIL INKEY$=""
SLEEP 50
WEND
END SUB
SUB Connect(socket as tcpsocket,nummer)
DIM dummy AS string
IF SDLNet_Init() <> 0 THEN
PRINT "Fehler"
SLEEP
END
END IF
PRINT "1-Server"
PRINT "2-Client"
DO
dummy$=INKEY$
nummer=VAL(dummy$)
IF dummy$=CHR$(27) THEN END
LOOP UNTIL nummer=1 OR nummer=2
DIM sock AS tcpsocket'Socket einstellen
DIM sockclient AS tcpsocket
DIM ip AS ipaddress'Variable IP vom Typ IP Addresse
DIM zahler AS integer
IF nummer=1 THEN
SDLNet_Write32( INADDR_ANY, @ip.host )
SDLNet_Write16( 5678, @ip.port )
sock = SDLNet_TCP_Open( @ip )'TCP Verbindung öffnen, in den Socket schreiben
zahler=1
PRINT "Warte auf Client..."
WHILE sockclient = NULL
IF INKEY$=CHR$(27) THEN END
sockclient = SDLNet_TCP_Accept( sock )
SLEEP 5
WEND
END IF
IF nummer=2 THEN
DIM host AS string
INPUT "IP Addresse des Hostes: ", host$
SDLNet_ResolveHost( @ip, host$, 5678 )
sockclient = SDLNet_TCP_Open( @ip )
END IF
socket=sockclient
END SUB
|
|
|
Nach oben |
|
|
Eastler_dart
Anmeldungsdatum: 25.09.2005 Beiträge: 177 Wohnort: Baden-Würtemberg + Sachsen
|
Verfasst am: 25.11.2005, 21:19 Titel: |
|
|
Hm. Da hab ich mich aber nu wieder weit ausm Fenster gelehnt
wollte schon immer mal wissen, was Ihr mit thread bzw threadcontrol meint, soll heißen, hab keine Ahnung davon.
Aber das ganze erscheint mir dann auch viel zu kompliziert, falls überhaupt eine "simple" Lösung in Threads vorgesehen ist.
Eine Lösung mit wirklich Über-/Durch- blick find ich nur in ner Zählschleife, die nach z.B.500 Tastenanschlägen in einem Stück aus dem Puffer geleert, ne Fehler-/Warn- meldung ausgibt oder aber in dein gewünschtes sicheres Datensenden verzweigt.
Hab die Grundlagen dazu mal mit einem kleinen FreeBasic-Programm getestet:
Code: |
REM Testprogramm für Problem ProggerX vom 25.Nov 05
REM
REM Prüfen, wie schnell ein "Dauerfeuer" auf ner Taste
REM in den Inkey$-Puffer schreibt
LOCATE 10,1
PRINT "Dauerfeuer druecken oder Esc Programmende"
Locate 1,1
PRINT "gezählte Dauerfeueranschläge, ohne die LOOP verlassen zu haben:"
DO:'Hauptschleife, die nur darauf achtet, ob Escape gedrückt wurde
Zaehler%=0
DO:'Diese INNERE Schleife solange durchlaufen, bis Inkey$ ==> in$ leer ist
in$=INKEY$
Zaehler%=Zaehler%+1
LOCATE 1,65: PRINT Str$(Zaehler%);
LOOP WHILE in$<>"" AND in$<>CHR$(27)
LOOP UNTIL IN$=CHR$(27)
REM Ergebnis ist, selbst bei einer ständig gedrückter Taste
REM wird die Innere Schleife trotzdem verlassen,
REM da die Tastatur nicht Soooo schnell in Inkey$ schreibt,
REM wie die Innere Loop Inkey$ ausliest
REM und das auf nem 200MMX-Win98-System!
REM
REM Aber Achtung, sobald auch nur ein einziger Basic-Befehl
REM zusätzlich in die innere Schleife dazu programmiert wird,
REM Sollte das ganze neu getestet werden,
REM da die Abfrage von Inkey$ dann um diesen Befehl
REM langsamer abläuft !
|
Das Programm hat eine solche Zählschleife.
Solange der INKEY$-Buffer NICHT leer wird, wird in der Var Zaehler% weiter gezählt.
Kompiliere mal das Prog bei dir und teste es.
Ich habs auf nem 200MMX (der schwächste anzunehmende PC ?) getestet. Mehr als 2 Anschläge werden nicht aus dem Puffer auf einmal geleert (kurz flackert ab und zu die Anzeige auf 2).
Soll heißen: Selbst mit Dauerfeuer kriegt man diese Tastaturauslese-Zählschleife nicht zum ewig zählen.
Nehme mal an, du hast einen Porsche-Rechner.
Bin ja mal gespannt, was auf deinem PC schneller ist,
die Ausleseroutine oder die Tastatur. Vermute mal,
je schneller der PC, desto schneller wird Inkey$ ausgelesen,
die Tastatur dürfte getimed sein, also überall gleich schnell.
Somit wird es bei schnelleren Rechnern als mein 200MMX
noch unwahrscheinlicher, daß der EndUser sich in dieser
Schleife verbarrikadieren könnte.
P.S: noch auf meinem 1600er getestet. Gleiches Ergebnis.
Somit schätze ich, mit dieser Schleife den Puffer zu leeren versetzt keinen User in die Lage, das Programm zu Stoppen. _________________ Kaum macht mans richtig, schon geht's |
|
Nach oben |
|
|
Eastler_dart
Anmeldungsdatum: 25.09.2005 Beiträge: 177 Wohnort: Baden-Würtemberg + Sachsen
|
Verfasst am: 25.11.2005, 21:28 Titel: |
|
|
Ganz vergessen.
Alles gesagte gilt bei Windows-98SE
Teste das Prog gleich noch unter Linux. Weiß ja nicht, ob du für mehrere Plattformen oder nur für Windows programmierst.
Auch kommt jetzt der Verdacht auf, daß unter WinME oder XP oder NT diese Verhältnisse doch abweichen könnten.
Hallo große weite Welt da draußen! Aufruf
Testet mal alle dieses kleine Programm und gebt eure Erfahrungen hier an. Ist für unzählig viele Fälle bestimmt interessant zu wissen, ob so ein Tastaturpufferleerer (? blödes Wort) überall und immer läuft.
Bis dahin, Euer Eastler _________________ Kaum macht mans richtig, schon geht's |
|
Nach oben |
|
|
Progger_X Mr. Lagg
Anmeldungsdatum: 24.11.2004 Beiträge: 784 Wohnort: Leipzig
|
Verfasst am: 25.11.2005, 21:34 Titel: |
|
|
Also.
Der langsamste Anzunehmende PC hat 100 Mhz und 32 MB-R bzw. 133 Mhz und 16 MB-R. Auf denen sollte es auch funktionieren.
Auf meinem Porsche Rechner kommt immer 1. Aber wenn ich das richtig nachvollzogen hab, hieße das, dass bei mir der Fehler nicht auftreten sollte. Tut er aber, deshalb denk ich eher, das es was mit dem Programm zu tun hat. Ich hab WindowsXP.
Was ich mit threadcontrol mein...MisterD meinte, man bräuchte das irgendwie, damit die Threads beendet werden.
Ich muss jetzt erstmal offline, weil mein Vater ins Internet will. Ich werd das derweil mal auf den langsameren Rechnern testen. |
|
Nach oben |
|
|
tilli
Anmeldungsdatum: 10.09.2005 Beiträge: 73
|
Verfasst am: 25.11.2005, 22:05 Titel: |
|
|
Moin Ihr beides,
zum Thema Tastaturpuffer: der wird von Windoof beliefert(oder Xni-/-ux) - naja zumindest vom BS halt. Das Betriebssystem bekommt von der Tastatur nur gesagt, was gerade gedrückt ist - nicht mehr - und es muss demnach getimed sein.
Im BS ist eine Zeitvariable(einstellbar? War zumindest mal so ... ), die den Anfang von automatischen Widerholen angibt und eine für die Wiederholgeschwindigkeit. Dasgleiche kann man auch im Bios bewundern - ob das BS das dierekt macht oder vom Bios holt, ist nicht definiert(gibt wohl beides). Da von Threads die Rede war und DOS keine hat, gehe ich mal nicht von DOS aus -> BS.
Es dann eine Verzögerung von ca. 100-300 ms und in Folge ein weitere von - nun einstellbar, aber (Szenario) mehr als 80 Zeichen (eine Normzeile) pro Sekund werden es sicher nicht sein. Gehen wir "worst case" von 100 aus. Daraus ergibt sich 10 ms Zeit von Buchstabe zu Buchstabe. bei 200 MHz(ich habe noch`n 33MHzer MIT COPROZESSOR (dx) - der Läuft auch gut - zumindest hat er das vor 2 Jahren getan ) hätte der Rechner etwa mindestens "wieder worst case" 25 MHz für das Programm über(im Schnitt) - das Bedeutet 250 schritte zum Leeren einer Taste - das sollte eigentlich hinkommen.
Wer Spielen will kann ja das System ein wenig auslasten und was im Hintergrund Laufen lassen (z.B. eine DVD in eine MPG4 CD Wandeln oder so ) dann käme man vielleicht auf mehr Tasten.
Eventuell kann man Ihn ein wenig Überlisten und Ihm eine Reihe verschiedener Tasten hintereinander geben (einmal von Q bis Ü auf der Tastatur)
Aber mal im Ernst - ein schnellerer Rechner sollte niemals nie die tastraturgeschwindigkeit Erhöhen (bei 2000MHz dann etwa 10 zeilen pro Sekunde? )
zum Leeren des Tastaturpuffers geht auch ein :
Code: | while inkey$="": wend
|
da kann man dann natürlich nicht abfragen, ob gerde 2 Tasten gleichzeitig gedrückt sind.
Das muss man dann so hinballancieren, dass man eine Abfrage wie:
Code: |
dim keytable(0..255) as integer
if multikey(xy) then
if keytable(xy)=0 then
keytable(xy)=1
Tastenaktivität
end if
else
keytable(xy)=0
end if
|
damit fängt man recht einfach die dopeldrucks ab.
! Achtung ! die interne If ist SEEEEEHR Wichtig, - es geht nciht, dass man die in das erste mit reibringt!!! dann bringt er zwar `NUR`jede 2. Runde eine Tastenaktivität, aber das ist ja nicht erwünscht.
Wenn man einen Timecode reinbringen will kann man es so machen:
Code: |
dim keytable(0..255) as integer
sleep(20) `Abfrage in 50 Hz
if multikey(xy) then
if keytable(xy)<1 then
keytable(xy)=10
Tastenaktivität
else
keytable(xy)-=1
end if
else
keytable(xy)=0
end if
|
so hat man etwa 5 Mal die Sekunde eine Aktivität
eine Erständerung ist natürlich auch drin, wenn man eine 2. If nimmt und es nur is 1 runterlaufen lässt und dann auf z.b. 9 stellt, vorher aber auf z.B. 20.
So nun genug des Textes, wenngleich es ja um Tastaturbetätigung ging .
CU2
Tilli |
|
Nach oben |
|
|
Progger_X Mr. Lagg
Anmeldungsdatum: 24.11.2004 Beiträge: 784 Wohnort: Leipzig
|
Verfasst am: 25.11.2005, 22:13 Titel: |
|
|
Hi.
Tilli:
Das soll also der Code sein, um die Tasten abzufragen, und dann soll man das in nen thread packen?
Ich seh da keine Veränderung zum vorherigen code, wenn schon müsste man den Tastaturpuffer da drin leeren, und das würde ja zum gleichen Problem führen.
eastler:
Ich habe dein programm getestet, aber sowohl auf 2.8 ghz WinXP, 600 Mhz Win98 SE und 133 Mhz Win98 SE kam 1 raus. Welche FB Version hast du? |
|
Nach oben |
|
|
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
|