Laden...

Positionsberechnungen von Objekt aus UI-Thread auslagern

Erstellt von BlackArtC# vor 8 Jahren Letzter Beitrag vor 8 Jahren 3.714 Views
B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 8 Jahren
Positionsberechnungen von Objekt aus UI-Thread auslagern

Hallo,

ich programmier momentan ein kleines Minigame als Win Forms Anwendung aber stehe grad vor einem Problem. Ich möchte das Berechnen der Positionen(Spieler, Gegner), das überprüfen auf Kollision und das Zeichnen verlagern, da ich in meinem Programm alles abarbeite wenn ich eine Taste drücke.

Jedoch habe ich keine Erfahrung in sowas. Bis jetzt würde mir nur der Backgroundworker, der Timer und Threading einfallen, aber was ist für sowas am einfachsten umzusetzen?

Hoffe Ihr könnt mir helfen,

Gruß

3.003 Beiträge seit 2006
vor 8 Jahren

Hallo,
Ich möchte das Berechnen der Positionen(Spieler, Gegner), das überprüfen auf Kollision und das Zeichnen verlagern

'tschuldigung, das kommt nicht so genau rüber: wohin möchtest du das verlagern?

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

2.207 Beiträge seit 2011
vor 8 Jahren

Hallo BlackArtC#,

ich hab grad den Thread Titel geändert und es rückgängig gemacht, weil ich selber nicht mehr sicher war. Meine Frage geht aber in LaTinos' Richtung: Willst du es in einen anderen Thread auslagern? Oder willst du es in eine Klasse auslagern? (Separation of Concerns, Single Responsibility etc.?)

Gruss

Coffeebean

B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 8 Jahren

Hi,

also da in einer Win Forms Anwendung an sich keine "Update" Methode vorhanden ist, muss ich ja praktisch das Zeichnen meiner Figur, die Position, die Kollisionserkennung ect. immer aktuell halten.

Momentan mache ich das alles (Zeichnen, Kollisionserkennung, bestimmen der Position)
wenn ich eine Richtungstaste drücke. Wenn ich z.B keine Taste drücke würden sich meine Gegner nicht mehr bewegen, da die ganzen Berechnungen ja erst ab Tastendruck beginnen.

Also brauche ich eine Funktion die im Hintergrund arbeitet und synchron zu meinem eigentlichen Programm läuft. Desweiteren kennt man es ja das die Oberfläche gefriert, wenn ein Prozess "zu lange braucht".

Deswegen würde ich gerne Wissen wie man das am besten realisiert (ich kenne bis jetzt nur Backgroundworker, Threading und Timer).

Gruß

3.003 Beiträge seit 2006
vor 8 Jahren

Die Figur sollte signalisieren, wenn sich ihre Position ändert (bzw geändert hat), und die Oberfläche auf dieses Signal reagieren, indem sie (die Figur) neu zeichnet.

's gibt hier im Forum einen sehr guten Beitrag zum Thema Ereignisse (Events), die dafür am geeignetsten wären. Ich finde ihn nur grad nicht - kann eventuell jemand nachtragen 😮).

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 8 Jahren

Danke (: Ich denke mal Delegates sind dann die Events welche ich brauche, oder?

P
1.090 Beiträge seit 2011
vor 8 Jahren

Events sind eine spezial Form der Delegates. Also alle Events sind Delegates, aber nicht alle Delegates Event.

Grundlegend wir du wohl eine Game Loop brauchen.
Ist jetzt der 1. Beitrag dazu den ich bei google gefunden habe:
Game Programming Patterns:Game Loop

Zum neu Zeichnen solltest du mal nach Game Loop und Rendern googlen (Events sind da nicht unbedingt die Optimale Lösung).

Sollte man mal gelesen haben:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 8 Jahren

Vielen Dank,
hab mir ein paar Videos angeschaut. Sieht echt knackig aus 😕

2.207 Beiträge seit 2011
vor 8 Jahren

Hallo zusammen,

vielleicht auch hilfreich: [FAQ] Warum blockiert mein GUI?

Gruss

Coffeebean

B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 8 Jahren

Danke für die Antwort (:.

In Anbetracht der Spielgröße, werde ich das wohl mit dem Timer Event machen. Ne Game Loop in C# Forms zu Implementieren ist mir dann doch zuuuu extrem. Da greif ich dann später lieber gleich zu XNA/Mono 😛

B
88 Beiträge seit 2016
vor 8 Jahren

Hallo BlackArtC#,

so mache ich das in meinem kleinem Weltraumshooter auch.
Ich habe einen Timer (tmrRefreshGUI, Intervall 1 ms.) und der ruft .Invalidate() auf meinem (DoubleBuffered)Zeichenpanel auf.

In dem _Paint Ereignis des Panels zeichne ich dann alles und reagiere auf Tasteneingaben.

Ist bestimmt nicht so StateOfTheArt aber es funktioniert auf jeden Fall schonmal und es war mein erstes Spiel.

Ich wollte das Projekt schon vor Ewigkeiten mal im CodeReview Bereich vorstellen und nach Feedback fragen, aber ich hab einfach keine Lust mehr die letzten 10% zu coden 😉 Da kann man bestimmt noch vieles viel viel besser machen MVC und so zb.

B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 8 Jahren

Hehe danke für den Tipp mit dem doppelten Puffer, wusste gar nicht das es sowas gibt(Das flackern hat mich schon verrückt gemacht).

Space Shooter sind immer gut, würde ich mir falls du es irgendwann posten solltest gerne durchlesen 😄

B
88 Beiträge seit 2016
vor 8 Jahren

Auf einem Panel funktioniert dass mit dem DoubleBuffered leider nicht ganz so leicht wie auf der Form, ich hab damals diesen Codeschnipsel dafür gefunden:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace EscapeTheAsteroids
{
    public class DoubleBufferPanel : Panel
    {
        public DoubleBufferPanel()
        {
            // Set the value of the double-buffering style bits to true.
            this.SetStyle(ControlStyles.DoubleBuffer |
            ControlStyles.UserPaint |
            ControlStyles.AllPaintingInWmPaint,
            true);

            this.UpdateStyles();
        }
    }
}

Und nein, normalerweise arbeite ich nicht mit Copy&Paste falls es jetzt wem in den Fingern juckt 😉

PS: Irgendwann poste ich das Spiel bestimmt. Notfalls halt auch unfertig, ich hatte die Sache von Anfang an so geplant möglichst viel dazu zu lernen 😃

B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 8 Jahren

Hey super danke (:

Hast du dein Spiel auch in Abhängigkeit der Zeit gemacht? Also das es immer konstant läuft?

B
88 Beiträge seit 2016
vor 8 Jahren

Hast du dein Spiel auch in Abhängigkeit der Zeit gemacht? Also das es immer konstant läuft?

Wie meinst du das? 😃

Ich "bitte" Windows durch panel.Invalidate() quasi ständig (-> 1 ms timer) mein panel neu zu zeichen, sprich: das Paint Ereignis des Panels auszulösen.
(100%ig erzwingen kann man den Zeichenvorgang durch Invalidate() glaube ich nicht nicht, aber das klappt trotzdem ganz gut)

Jetzt kann ich in diesem Paint Ereignis mein Zeug schreiben, das jede Millisekunde auf dem Bildschirm dargestellt werden soll z.B.


            // Raumschiff zeichnen          
            if (mySpaceship.IsAlive)
                mySpaceship.Draw(sender, e, this);

            // Auf Tastatureingaben reagieren
            CheckForKeysPressed();

            // Hindernisse zeichnen
            foreach (IDrawable obstacle in myAlienObstacleLst)
            {
                obstacle.Draw(sender, e, this);
            }

Mir hat am Anfang dieser Artikel sehr geholfen:
[Tutorial] Zeichnen in Windows-Forms-Programmen (Paint/OnPaint, PictureBox)

Genieße aber meine Beiträge ab jetzt bitte trotzdem mit Vorsicht, ich weiß selbst noch nicht wie sinnvoll sie gerade wirklich sind 😉

16.835 Beiträge seit 2008
vor 8 Jahren

Eine Auflösung auf 1ms gibt es nicht; der Timer wird nicht genauer als 15ms sein. Eher 25-35ms.
Technisch in .NET nicht anders möglich.

In Spielen ist es eher üblich mit while(true) zu arbeiten und bei jedem Schleifendurchlauf neu zu zeichnen.

B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 8 Jahren

Ich habe grad gemerkt das ich das auf die genannte While Schleife bezogen habe.

Da ist ja das Problem das die Schleife theoretisch von nem leistungsstarken CPU schneller durchlaufen wird als von nem schwachen, also muss man das ja irgendwie im Spiel selbst ausgleichen das es überall ne konstante >Frame Rate hat.

Und da arbeitet man ja dann mit der DeltaTime welche am Ende mit den Positionen ect verrechnet wird. Bin aber extrem neu auf diesem Gebiet xD

16.835 Beiträge seit 2008
vor 8 Jahren

Zeichengeschwindigkeit hat nichts direktes mit Spielgeschwindigkeit zutun.
Ersteres kannst Du nicht garantieren, zweiteres musst Du (insbesondere bei Multiplayer) garantieren.

Schau Dir mal Videos von Tom Wendel (Microsoft MVP C#, Erfinder von AntMe! und Ex Microsoft Evangelist) an.
Der hat ein eigenen Videokanal zum Thema Spieleentwicklung und dessen Basics.

P
1.090 Beiträge seit 2011
vor 8 Jahren

Der Punkt wird auch in dem von mir Verlinkten Beitrag angesprochen und wird da so gelöst.

while (true)
{
  double start = getCurrentTime();
  processInput();
  update();
  render();

  sleep(start + MS_PER_FRAME - getCurrentTime());
} 

Sollte man mal gelesen haben:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 8 Jahren

Hi,

ich weiß und kenne auch viele andere Ansätze aber das Prinzip ist für mich grad ein wenig schwer zu begreifen.

Der Wert den Sleep bekommt(start + MS_PER_FRAME - getCurrentTime()) ist er dafür da konstante Sleep Aufrufe zu erreichen also z.B brauch die Schleife im ersten Durchlauf 2 Sek und im Dritten nur eine, dass die Schleife beim nächsten mal eine Sekunde "länger" braucht oder wie?

Gruß