Entwickler-Ecke

Alle Sprachen - Alle Plattformen - SFML.Net RenderWindow.DispatchEvents asynchron ausführen


Kasko - Fr 14.12.18 01:47
Titel: SFML.Net RenderWindow.DispatchEvents asynchron ausführen
Ich versuche mich gerade an SFML.Net. Aber schon bei den Basics scheitert es. Der grundlegendste MainLoop sieht wie folgt aus


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
using SFML.Graphics;
using SFML.Window;

public class Program {
    RenderWindow window;

    public static void Main() {
        window = new RenderWindow(new VideoMode(7681024), "Program");
        window.Closed += Window_Closed;

        while (window.isOpen) {
            window.DispatchEvents();
            window.Clear();
            window.Display();
        }
    }

    private void Window_Closed(object sender, System.EventArgs e) {
        window.Close();
    }
}


Das Problem ist die Methode window.DispatchEvents(). Sie ist nämlich solange aktiv, wie Events beim Fenster ankommen. Das Bewegen des Fensters ist aber ein Event, dass über mehrere Frames oder Sekunden hinausgeht. Wenn also das Fenster bewegt wird, wird währenddessen nicht gerendert und die frameTime steigt ins "Unermessliche". Danach rattern die DrawCalls nur so durch egal auf welche FrameRate man abzielt.

Bei meiner Recherche hab ich nur die Idee gefunden, die Methode in einen anderen Thread auszulagern, aber wenn ich das versuche werden gar keine Events mehr erkannt.


Th69 - Fr 14.12.18 11:37

Hast du denn auch das Erzeugen des Fensters in dem neuen Thread durchgeführt (s.a. SFML Thread does not works for window [https://stackoverflow.com/questions/33024988/sfml-thread-does-not-works-for-window])?


Kasko - Fr 14.12.18 12:19

Ja das Problem ist, dass die dort mit sf::threads und nicht mit std::threads arbeiten. Daher glaub ich kaum, dass ich mit System.Threading.Threads arbeiten kann. Wenn ich nur die Methode auslager wird nichts erkannt. Wenn ich alles auslager funktioniert es genau wie vorher --> DispatchEvents blockiert das Rendering.

Allerdings finde ich keine Dokumentation über eine Thread-Klasse aus SFML.Net.


Kasko - Fr 14.12.18 18:16

Okay hab es jetzt mit folgendem Code geschafft. WICHTIG Zeile 15-20 und Run-Methode


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:
namespace GLib {
    public class Game {
        public readonly StateMachine stateMachine;
        public readonly RenderWindow window;

        private Clock clock;

        public Game(uint width, uint height, string title) {
            window = new RenderWindow(new VideoMode(width, height), title);
            window.Closed += Window_Closed;

            stateMachine = new StateMachine();
            stateMachine.AddState(new SplashState(window), false);

            window.SetActive(false);

            Thread thread = new Thread(() => Run());
            thread.Start();
            while (window.isOpen)
                window.DispatchEvents();
        }

        private void Window_Closed(object sender, System.EventArgs e) {
            window.Close();
        }

        private void Run() {
            clock = new Clock();
            float time = 0.0f;
            float fixedTime = 0.0f;

            

            while (window.IsOpen) {
                time = GetFrameTime();
                Time.unscaledDeltaTime = time;
                fixedTime += time;
                stateMachine.GetActiveState().Update();

                if (fixedTime > 1.0f / 60) {
                    stateMachine.GetActiveState().FixedUpdate();

                    window.Clear();
                    stateMachine.GetActiveState().Render(window);
                    window.Display();

                    Time.fixedDeltaTime = fixedTime;
                    fixedTime -= 1.0f / 60;
                }
            }
        }

        private float GetFrameTime() { return clock.Restart().AsSeconds(); }
    }
}


Es bleibt aber ein Problem. Jetzt hat die Methode RenderWindow.Close() keinen Einfluss auf das Vorhandensein des Fensters und damit auf den MainLoop solange ich das Fenster bewege. Wenn ich loslasse dauert es ca. eine Sekunde und dann wird es erst geschlossen. Zudem wirft der Code eine System.AccessViolationException aus wenn ich versuche es zu schließen während kein Event ankommt.