Zeitliche Verzoegerung in MFC durch Sleep?
-
Hallo Zusammen!
ich versuche gerade in mein Program ein zeitliche Verzoegerung reinzubringen. Es geht um ein einfaches Spiel wo der Computer nach seiner Entscheidung 2 Sekunden warten soll, bevor er das Brett mit seinem entschiedenen Zug wiedermalt. Dadurch schafft man ja der "denkende Gegner" effekt. Das Warten wollte ich mit Sleep realizieren.
void CDreiGewView::OnLButtonDown(UINT nFlags, CPoint point)
{..............
// Benutzer moechte offentsichlich einen Zug machen.
// So es kann nur mit einem X bezeichnet werden.
// Nur klicks auf leere Felder akzeptieren
if( pDoc->m_acBrett[I][J] == ' '){
pDoc->m_acBrett[I][J] = 'X' ;// AnalysiereBrett() sucht nur fuer bevorstehenden Verlust,bevorstehenden
// Gewinn, Verlust oder Gewinn.
pDoc->AnalysiereBrett() ;// Aktualisiere alle Ansichten
pDoc->UpdateAllViews(NULL);// Nach pDoc->AnalysiereBrett das Algorithmus macht
// seinen Zug auch.
if(pDoc->m_cSpielStatus == ' '){
// Dies ist die Stelle wo der Computer seinen Zug macht.
pDoc->m_acBrett[pDoc->m_nBesterI][pDoc->m_nBesterJ] = '0';
// Gewinn,Verlust ?
pDoc->AnalysiereBrett() ;
}// Geh schlafen , der Denkarbeit-Effekt des Computers.
Sleep(2000) ;
// Aktualisere den Ansicht ;
pDoc->UpdateAllViews(NULL) ;
}// Rekursiv aufruf von LeftButtonDown als Event-Handler
CView::OnLButtonDown(nFlags, point);
}Egal an welcher Stelle ich den Sleep(2000) reinbringe, gibt das Spiel nicht das Effekt was ich habe moechte. Ich klicke, das Program wartet 2 Sekunden, und zeigt mir danach mein und sein Zug gleich hintereinander..
Ich denke es ist ein MFC gebundene Kleinigkeit, die ich uebersehe.
Meine Frage ist: Wie kann ich die LButtonDown Funktion dazu beibringen: mein zug anzeigen->2 sekunden warten -> sein zug anzeigen ??
Danke im voraus,
jsbach
-
Vergiss Sleep an solch einer Stelle. Dadurch wird das Spiel unbedienbar in dieser Zeit und reagiert nicht, malt sich nicht mal neu, wenn es verdeckt wurde.
Verwende einen Timer (SetTmer).
-
was martin meint...
während sleep werden keine nachrichten abgearbeitet. also wird das fenster nicht gezeichnet, man kann nichts anklicken, etc...
entweder einen timer oder noch besser einen thread der sowas handelt.
Stefan
PS: schau auch mal den Thread "Unterdialog wir nach 5 sek. weiß......"
-
Tach zusammen,
danke fuer die Antwort. Also, ich habe mit Martin's Variante ausprobiert.
Der SetTimer() zaehlt hoch und dann schickt eine Nachricht was von onTimer() verarbeitet wird.
Mit dieser Logik habe ich SetTimer Aufruf & onTimer() procedure eingebaut. Nun gibt's kaum Unterschied im Vergleich zu dem frueheren Zustand:
void CDreiGewView::OnLButtonDown(UINT nFlags, CPoint point)
{
............
// Benutzer moechte offentsichlich einen Zug machen.
// So es kann nur mit einem X bezeichnet werden.
// Nur klicks auf leere Felder akzeptieren
if( pDoc->m_acBrett[I][J] == ' '){
pDoc->m_acBrett[I][J] = 'X' ;
pDoc->AnalysiereBrett() ;/// BENUTZER'S ZUG WIRD GEMALT
pDoc->UpdateAllViews(NULL);// Nach pDoc->AnalysiereBrett das Algorithmus macht
// seinen Zug auch.
if(pDoc->m_cSpielStatus == ' '){pDoc->m_acBrett[pDoc->m_nBesterI][pDoc->m_nBesterJ] = '0';
pDoc->AnalysiereBrett() ;
}UINT my_timer ;
// Timer has set-up it counts to 2 secs and
// sends WM_ON_TIMER to the OnTimer ;
my_timer = SetTimer(1,2000,NULL) ;}
CView::OnLButtonDown(nFlags, point);
}void CDreiGewView::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call defaultCDreiGewDoc *pDoc = GetDocument() ;
ASSERT_VALID(pDoc) ;//COMPUTER'S ZUG WIRD GEMALT
pDoc->UpdateAllViews(NULL);//VORHANDENER TIMER WIRD GEKILLT
KillTimer(nIDEvent) ;
}@Stefan: ich habe den Mail-Thread angeschaut. Threading ist mir genauso neuland wie der Fragestellender ;).
Sowie SetTimer() definiert ist, muesste sie die Aufgabe leicht erledigen.. Was ist bei SetTimer() Ausfuehrung falsch?
Gruss,
jsbach
-
du hast das prinzip des Timers wohl nich gant verstanden... zudem ist ein timer für diese problemchen nicht unbedingt die beste variante
bau an der stell wo du normalerweise dein slepp machen willst eine
while schleife ein, welche 2 sek durchlaufen wird, zudmen rufst du bei jeder 10ten schleifeniteration die message-queue auf, so das die nachrichten des system immer noch abgearbeitet werden...
Implementiere diese funktion
void SleepWithEvents(){ for(long iter=0; iter< 1000000; iter++){ if(iter%100==0){ MSG dispatch; while (::PeekMessage( &dispatch, NULL, 0, 0, PM_NOREMOVE)){ if (!AfxGetThread()->PumpMessage()); } } } }Die iterationanzahl muss so angepasst werden das die schleife 2 sek. braucht
EDIT: theortisch könntem man noch die zeit messen in der schleife und sie solange duchkaufen bis bis die gewünschte wartezeit erreicht ist
-
Anstatt den Iterationen aber lieber GetTickCount verwenden. Das ist genauer und vor allem unabhängig von der Leistungsfähigkeit des Rechners.
-
Sehe ich auch so. So in etwa alle 100ms nachsehen ob eine Nachricht da ist langt für einfacher UI-Interaktionen vollkommen.
-
jo das meinte ich mit Zeit abfragen