Autor Beitrag
klaus007
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Sa 09.02.08 23:15 
Hallo

ich versuche ein Kartenspiel zu schreiben. Bin auch fast fertig, nur die Anzeige des Gewinns und Verlustes machen mir gerade das Leben schwer.
Diese sollen nach dem klicken auf eine von 4 Karten in der Mitte des Bildschirms nach einander für ca 2 Sekunden angezeigt werden.

Mein Problem ist nun, dass ich nicht weiß wie ich mehrere Events hintereinander zeitverzögert ausführen kann. Ein Timer ist kein Problem, aber was tun bei mehreren?

Hier ein Auszug des relevanten Codes:
Code:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
        private void KarteA_Click(object sender, EventArgs e)
        {
                    int temp_gain = KarteA_gain[A_Runde];
                    int temp_loss = KarteA_loss[A_Runde];
                    ergebnis = temp_gain - temp_loss;

                    this.KarteA.Enabled = false;
                    this.KarteA.Image = global::IGTmod.Properties.Resources.black;

                    mytimer.Interval = 3000;
                    mytimer.Tick += new EventHandler(Bildwechsel_A);
                    mytimer.Start();
}

 private void Bildwechsel_A(object sender, EventArgs e)
        {
            this.KarteA.Image = global::IGTmod.Properties.Resources.test_back;
            this.KarteA.Enabled = true;
        }

Um nochmal kurz zu erklären wie der Ablauf aussehen soll. Man klickt auf die Karte, diese wird deaktiviert. Dann folgt der Gewinn für 2 Sekunden, dann der Verlust und anschließend wird alles von einem Kontostand abgezogen.
Wie kann ich das über den Timer lösen? Hab schon alles mögliche versucht und auch schon viel gegoogelt, aber irgendwie steh ich aufm Schlauch!
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: So 10.02.08 13:42 
Der exakte Ablauf ist nicht ganz klar geworden, aber so könnte es zum Beispiel aussehen:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
int step;

// Click-Eventhandler:
{
  step = 0;
  gainLabel.Visible = true// Gewinn wird sofort angezeigt
  myTimer.Start(); // Interval und Tick wurden bereits im Designer festgelegt (Interval = 2000)
}


// Tick-Eventhandler:
{
  step++;
  switch (step) {
    case 1// 2 Sekunden vergangen => Gewinn aus-, Verlust einblenden
      gainLabel.Visible = false;
      lossLabel.Visible = true;
    case 1// 4 Sekunden vergangen => Verlust ausblenden, Kontostand anpassen
      lossLabel.Visible = false;
      [...]
  }
}


Du siehst, dass ich nur einen Timer benutze, in den ich quasi die anderen integriert habe.
klaus007 Threadstarter
Hält's aus hier
Beiträge: 7



BeitragVerfasst: So 10.02.08 15:10 
super, danke für die Hilfe. Werde es gleich mal ausprobieren.

Was war unklar bei dem Ablauf? Dann könnte ich es nochmal etwas genauer beschreiben.
klaus007 Threadstarter
Hält's aus hier
Beiträge: 7



BeitragVerfasst: So 10.02.08 16:56 
ES HAT GEKLAPPT!!!!
da wäre ich Leben nicht drauf gekommen! Vielen lieben Dank!!!
klaus007 Threadstarter
Hält's aus hier
Beiträge: 7



BeitragVerfasst: So 10.02.08 17:53 
hmm... klappt leider nur halb. nämlich beim ersten durchgang. aber dann springt er irgendwie sofort durch und landet beim letzten case... was tun?
JüTho
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2021
Erhaltene Danke: 6

Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
BeitragVerfasst: So 10.02.08 18:07 
Hast Du den Code etwa einfach kopiert ohne nachzudenken? Und auch nachdem es nicht klappt, verzichtest Du auf eigene Kontrolle? Khabarakh hat (wie man es natürlich sehr oft macht) den "case 1"-Zweig kopiert und vergessen, die "1" in "2" zu ändern. Jürgen

PS. Sollte das nicht das Problem sein, dann musst Du mehr Informationen geben, z.B. Deinen jetzigen Code.
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: So 10.02.08 19:33 
Mir fällt gerade so auf, dass ein break; am Ende des ersten case-Blocks auch nicht schlecht wäre ^^ . Aber ich gehe davon aus, dass Klaus die beiden Fehler schon selbst beseitigt hat, denn der CSC lässt zwei gleichnamige case-Label erst gar nicht zu *pfuh* . Also wäre es wirklich an der Zeit, Einblick in den Source zu gewähren.
klaus007 Threadstarter
Hält's aus hier
Beiträge: 7



BeitragVerfasst: So 10.02.08 21:23 
ich bin auch echt ne pappnase, sorry das ich vergessen habe den Source zu posten!


ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
private void KarteA_Click(object sender, EventArgs e)
        {
                if (A_Runde <= 40)
                {
                    step = 0;
                    temp_gain = KarteA_gain[A_Runde];
                    temp_loss = KarteA_loss[A_Runde];
                    ergebnis = temp_gain - temp_loss;
         
                    this.KarteA.Enabled = false;
                    this.KarteA.Image = global::IGTmod.Properties.Resources.black;

                    fb = "Gewinn: " + temp_gain;
                    this.pictureBox2.Invalidate();

                    mytimer.Interval = 2000;
                    mytimer.Tick += new EventHandler(Bildwechsel_A);
                    mytimer.Start();
                    

                    A_Runde++;
                    runde++;
                    
                    
                        string sLines = "" + runde + "\t" + "A'\t" + temp_gain + "\t" +                     temp_loss + "\t" + konto + "\r\n";
                        StreamWriter myFile = new StreamWriter(filename, true);
                        myFile.Write(sLines);
                        myFile.Close();
                        durch = false;
                    


                }
                else
                {
                    this.KarteA.Image = global::IGTmod.Properties.Resources.black;
                }
                  
               }


private void Bildwechsel_A(object sender, EventArgs e)
        {
                step++;

                switch (step)
                {
                    case 1:
                        fb = "Verlust: " + temp_loss;
                        this.pictureBox2.Invalidate();
                        break;
                    case 2:
                        fb = "Bitte warten";
                        this.pictureBox2.Invalidate();
                        KontostandBox.Invalidate();
                        break;
                    case 3:
                        int latenz;
                        latenz = m_Config.Latenz * 1000;
                        System.Threading.Thread.Sleep(latenz);
                        break;
                    case 4:
                        fb = "Bitte Karte auswählen";
                        this.pictureBox2.Invalidate();
                        this.KarteA.Enabled = true;
                        this.KarteA.Image = global::IGTmod.Properties.Resources.test_back;
                        break;

                
            }
JüTho
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2021
Erhaltene Danke: 6

Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
BeitragVerfasst: Mo 11.02.08 10:27 
Hallo Klaus,

danke für den Code. Aber nun verstehe ich wieder weniger, was Du erreichen willst: Wozu gibt es den String fb, und wird er irgendwo für die Anzeige verwendet? Wenn Du den aktuellen Thread schlafen lässt, bringst Du doch den Timer vollständig durcheinander; was soll das denn?

Vielleicht formulierst Du unter Berücksichtigung des aktuellen Codes nochmals Deine Anforderungen und Erwartungen. Schöner Pseudo-Code im Sinne von "wenn ... dann ... andernfalls" ist sicher hilfreich. (Vielleicht fällt Dir dabei bereits ein Gedankenfehler auf - mir bisher nicht, aber ich rechne mit so etwas.)

Gruß Jürgen

@Khabarakh
Auf die Aufmerksamkeit des CSC hätte ich auch gehofft, hatte es aber noch nicht bewusst probiert.
klaus007 Threadstarter
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Mo 11.02.08 11:12 
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
private void KarteA_Click(object sender, EventArgs e)
        {
                if (A_Runde <= 40//Es soll nur 40 Karten pro Deck geben. Insgesamt gibt es 4 Decks A,B,C,D mit jeweils 40 Karten. Jedes Spiel dauert 100 Durchgänge
                {
                    
                    temp_gain = KarteA_gain[A_Runde]; //Gewinn aus Array
                    temp_loss = KarteA_loss[A_Runde]; //Verlust aus Array
                    ergebnis = temp_gain - temp_loss;
         
                    this.backblackA.Visible = true//soll aussehen als sei Karte umgedreht
                    this.GewinnBox.Visible = true//Gewinn anzeigen
                    this.smilyGewinnBox.Visible = true//lachender Smily bei Gewinn
                    this.pictureBox2.Visible = false//Anzeige "Bitte Karte auswählen" ausblenden
                    Utility.playSoundFromResource("winsound2"); //Sound bei Gewinn abspielen
                    step = 0;
                    mytimer.Interval = 3000;
                    mytimer.Tick += new EventHandler(Bildwechsel_A);
                    mytimer.Start();
                    
                    

                    A_Runde++;
                    runde++;

                    //Ergebnisse in Datei schreiben
                        string sLines = "" + runde + "\t" + "A'\t" + temp_gain + "\t" + temp_loss + "\t" + konto + "\r\n";
                        StreamWriter myFile = new StreamWriter(filename, true);
                        myFile.Write(sLines);
                        myFile.Close();
                }
                else
                {
                    this.KarteA.Image = global::IGTmod.Properties.Resources.blackback;
                }
                
}

       private void Bildwechsel_A(object sender, EventArgs e)
        {

            step++;

                switch (step)
                {
                    case 1:
                        this.smilyGewinnBox.Visible = false//Gewinn Smily wird ausgeblendet
                        this.SmilyVerlustBox.Visible = true//damit Verlust Smily angezeigt werden kann
                        this.GewinnBox.Visible = false//Gewinn ausblenden
                        this.VerlustBox.Visible = true//Verlust anzeigen
                        Utility.playSoundFromResource("losesound1"); //Verlustsound abspielen
                    
                        break;
                    case 2:
                        this.VerlustBox.Visible = false
                        this.SmilyVerlustBox.Visible = false;
                        this.pictureBox2.Visible = true// vorher über fb=Bitte Karte auswählen angezeigt
                        fb = "Bitte warten"//jetzt soll bitte warten angezeigt werden
                        this.pictureBox2.Invalidate();
                        this.KontostandBox.Invalidate(); //und die Kontostandanzeige über Balken aktualisieren
                        break;
                    case 3:
                        int latenz; //Hier soll eine gewisse Zeit gewartet werden, die man in einem Einstellungsmenü festlegen kann
                        latenz = m_Config.Latenz * 1000;
                        System.Threading.Thread.Sleep(latenz);
                        break;
                    case 4//hier nach soll alles wieder so aussehen wie zuvor
                        fb = "Bitte Karte auswählen"
                        this.pictureBox2.Invalidate();
                        this.backblackA.Visible = false;
                        break;     
            }
            
            
            
        }



Mein großes Problem ist - und ansonsten bin ich fertig mit dem kleinen Spiel - diese zeitliche Abfolge von Ereignissen.
1. Karte auswählen
2. Karte wird schwarz
3. Gewinn wird 2 Sekunden angezeigt wo vorher "Bitte Karte auswählen" stand, Sound wird abgespielt, lachender Smiley angezeigt
4. Verlust wird 2 Sekunden angezeigt wo voher "Gewinn" stand, Sound wird abgespielt, trauriger Smiley wird angezeigt
5. Kontostand wird aktuallisiert
6. es wird "Bitte warten" angezeigt wo vorher "Verlust" stand und eine gewisse Latenz gewartet die vorher in Einstellungen angegeben werden kann
7. Kartenrücken wieder normal, "Bitte Karte auswählen" wo vorher "Bitte warten" stand

Ich bin echt verzweigelt weil ich wirklich nicht weiß wie ich das lösen soll. Habe schon wirklich überall danach gesucht, aber komme einfach auf keine Lösung.

@JüTho
mit dem Sleep hatte ich schon gedacht das es nicht so elegant ist. Aber auch wenn ich es rausnehme besteht immer noch das Problem, dass es beim ersten Mal wunderbar klappt, aber wenn ich die Karte das zweite Mal wähle er sofort in den letzten case springt.
JüTho
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2021
Erhaltene Danke: 6

Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
BeitragVerfasst: Mo 11.02.08 13:07 
Hmmm... Mir fällt in der Tat auch nichts Gravierendes auf. Aber probier mal Folgendes aus:
  1. Die Festlegung von Timer.Interval und vor allem Timer.Tick gehört nicht zu KarteA_Click, sondern in den Konstruktor des Formulars.
  2. Bei KarteA_Click zuerst Timer.Stop() aufrufen; das bringt möglicherweise alles durcheinander.
  3. Thread.Sleep solltest Du vielleicht durch einen weiteren Zähler latenz ersetzen:
    ausblenden C#-Quelltext
    1:
    2:
    3:
    4:
    5:
    6:
    7:
    8:
    9:
    10:
    11:
    12:
    private void Bildwechsel_A(object sender, EventArgs e)
    {
        if (latenz <= 0) {
            step++;
            switch(step) {
                case 3:
                    latenz = m_Config.Latenz;
                    break;
            }
        } else
            latenz--;
    }

  4. Füge in jeden case-Fall von switch ein Debug.WriteLine() ein, um jeden Aufruf des Timers zu protokollieren.

Mir bleibt unklar, wofür fb verwendet wird.

Ich habe den Verdacht, dass der Timer korrekt arbeitet, aber die Abfolge der Anzeigen nicht dem entspricht, was Du Dir vorstellst. Jürgen
klaus007 Threadstarter
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Mi 13.02.08 18:46 
Du hattest Recht, es lag am Konstruktor!

Vielen Dank für die viele Hilfe und die vielen nützlichen Tipps!

LG,
Klaus