[Workshop] Spieleprogrammierung mit XGL

  • VB.NET

Es gibt 15 Antworten in diesem Thema. Der letzte Beitrag () ist von Gather.

    [Workshop] Spieleprogrammierung mit XGL

    Inhalt:
    1. Projekt erstellen
    2. XGL initialisieren
    3. Gamescenes und unser UFO

    Ressourcen:
    Xemio GameLibrary
    UFO.zip

    1. Projekt erstellen
    Zuerst brauchen wir ein WinForms Projekt bzw. eine Form, die uns als Darstellungsobjekt dient. XGL kann prinzipiell auch in Panels oder andere Controls rendern, allerdings sollte ein Spiel im Normalfall in einer Form laufen, vorausgesetzt man arbeitet nicht gerade an einem Mapeditor.






    Zusätzlich fügen wir die beiden sich im Zip-Ordner befindenen DLLs als Verweis hinzu.





    2. XGL initialisieren
    XGL bietet ab v0.1.9 eine Vereinfachung der Komponenteninitialisierung, auf die ich in diesem Tutorial zurückgreifen werde. Die automatisierte Initialisierung fügt Komponenten wie Grafikausgabe, Maus- und Tastatureingaben und Scene Management hinzu und sofern weitere Komponenten benötigt werden sollten, können diese manuell hinzugefügt werden.

    Um XGL also für unsere Form zu initialisieren, benötigen wir folgende 2 Aufrufe:

    VB.NET-Quellcode

    1. Imports Xemio.GameLibrary
    2. Imports Xemio.GameLibrary.Rendering.GDIPlus
    3. Public Class MainForm
    4. Private Sub MainForm_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    5. XGL.Initialize(New GDIGraphicsInitializer())
    6. XGL.Run(Me.Handle, 400, 300, 60)
    7. End Sub
    8. End Class


    XGL.Initialize nimmt dabei einen IGraphicsInitializer entgegen, der sich um die Initialisierung des GraphicsProviders kümmert. Die Run-Methode nimmt die Größe des Backbuffers (in dem Fall 400x300) und die Framerate entgegen und initialisiert XGL für ein entsprechendes Handle, in unserem Fall die Form.

    Die Größe des Backbuffers muss dabei nicht zwangsläufig der Größe der Form entsprechen, sollte unsere Form z.B. 800x600 sein und der Backbuffer mit 400x300 initialisiert werden, entsteht ein aus Emulatoren bekannter x2-Effekt, der vor allem für auf Pixel Art basierende Indiegames äußerst praktisch ist.

    Beim Starten unseres Projektes sollten wir vorerst einen komplett schwarzen Bildschirm zu Gesicht bekommen, der über GDI auf unsere Form gezeichnet wird.


    3. Gamescenes und unser UFO
    XGL bietet von sich aus direkten Support für Gamescenes, die ähnlich aufgebaut sind wie die aus XNA bekannte Game-Klasse. Um also eine Gamescene zu unserem Spiel hinzuzufügen, erstellen wir eine neue Klasse und beerben die bereitgestellte Xemio.GameLibrary.Game.Scene-Klasse:




    Nachdem mithilfe des Overrides-Keywords die Methoden für LoadContent, Tick und Render überschrieben wurden sollte unsere UfoScene-Klasse folgendermaßen aussehen:

    VB.NET-Quellcode

    1. Imports Xemio.GameLibrary.Game
    2. Public Class UfoScene : Inherits Scene
    3. Public Overrides Sub LoadContent()
    4. End Sub
    5. Public Overrides Sub Tick(elapsed As Single)
    6. End Sub
    7. Public Overrides Sub Render()
    8. End Sub
    9. End Class


    Um unser UFO also darstellen zu können, müssen wir zuerst die bereitgestellte UFO.png Datei laden und in einer Variable speichern. XGL bietet dafür die ITextureFactory-Schnittstelle an, die für das jeweilige Rendering-System Texturen erstellt und verwaltet. Um unsere Grafik zu laden, verwenden wir die CreateTexture-Methode der ITextureFactory:

    VB.NET-Quellcode

    1. Imports Xemio.GameLibrary.Rendering

    VB.NET-Quellcode

    1. Private ufo As ITexture
    2. Public Overrides Sub LoadContent()
    3. Me.ufo = Me.GraphicsDevice.TextureFactory.CreateTexture("UFO.png")
    4. End Sub


    Anschließend implementieren wir noch den Render-Aufruf, der unser UFO an einer bestimmten Position darstellt:

    VB.NET-Quellcode

    1. Imports Xemio.GameLibrary.Math

    VB.NET-Quellcode

    1. Private ufoPosition As New Vector2(10, 10)
    2. Public Overrides Sub Render()
    3. Me.GraphicsDevice.RenderManager.Render(Me.ufo, Me.ufoPosition)
    4. End Sub


    Außerdem wollen wir, dass sich unser UFO langsam diagonal in Bewegung setzt. Die Vector2-Implementierung in XGL unterstützt alle Standard-Operatoren, um also die Position zu erhöhen müssen wir lediglich einen weiteren Vector2 dazuaddieren:

    VB.NET-Quellcode

    1. Public Overrides Sub Tick(elapsed As Single)
    2. Me.ufoPosition += New Vector2(1, 1)
    3. End Sub


    Sollten wir unser Projekt jetzt starten, fällt sicherlich auf, dass sich an unserem schwarzen Bildschirm noch nicht viel verändert hat. Das liegt daran, dass wir unsere Scene zwar implementiert haben, der SceneManager aber noch keine Informationen erhalten hat, dass er unsere Scene überhaupt darstellen und updaten soll. Wir erweitern also unseren Code in der Form1_Load-Methode um eine weitere Zeile:

    VB.NET-Quellcode

    1. Imports Xemio.GameLibrary.Game

    VB.NET-Quellcode

    1. XGL.GetComponent(Of SceneManager)().Add(New UfoScene())


    Starten wir jetzt unser Projekt, sollten wir ein UFO an der Position 10x10 auf unserem Bildschirm sehen, das sich langsam diagonal bewegt.


    Downloads:
    Examples.VisualBasic.zip

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Krissel095“ ()

    tststs verstrichene Zeit übergeben und trotzdem die Bewegung nicht danach richten ...
    Ist in dem Fall auch nicht nötig, da der Gameloop immer mit der selben Geschwindigkeit updated. Die übergebene Zeit ist eher für zeitbasierte Events gedacht, um z.B. nach einer bestimmten verstrichenen Zeit eine Aktion auszuführen ;)

    MfG
    @Trudi
    Genau dafür ist die GameLoop-Logik konzipiert ;) Sollten keine 60fps erreicht werden, wird im nächsten Frame der Render-Aufruf unterdrückt und in Abhängigkeit zur verstrichenen Zeit so oft Tick aufgerufen, bis alle verloren gegangen Frames simuliert worden sind.

    Du kannst dir die Implementierung dazu gerne anschauen:
    github.com/XemioNetwork/GameLi…eLibrary/Game/GameLoop.cs

    Selbst wenn also das Spiel mit 10fps läuft und als Target Framerate 60 eingestellt sind, bewegt sich ein Objekt immer mit der gleichen Geschwindigkeit, mal abgesehen von dem dadurch enstehenden visuellen Lag, da das Spiel ja nur noch mit 10fps läuft :)

    MfG
    @Mangafreak1995
    Du zweifelst den Sinn an? Versuch dich mal etwas genauer auszudrücken, sonst fällt es mir schwer, dir zu folgen :)

    MfG
    Wieso sollte man FPS limitieren? Unlimitiert ist es notwendig die Zeit mit einzubeziehen und limitiert muss man es nicht beachtet, das ist schon richtig.

    VSync ist ok, aber da ist das FPS Limit variabel und IMHO ein Nebeneffekt.
    Eine FPS-Limitation macht meiner Meinung nach definitiv Sinn. Meistens kann dein Monitor sowieso nicht mehr als 60fps darstellen, daher macht es wenig Sinn mehr Frames pro Sekunde darstellen zu lassen.

    Außerdem wäre eine unlimitierte Framerate z.B. für Physics-Engines eher unpraktisch, da so viel mehr Berechnungen ohne visuelle Folgen pro Sekunde bewerkstelligt werden müssen, vorausgesetzt man hält die Tickrate genauso hoch wie die Framerate, in XGL sind beide unabhängig voneinander.

    MfG
    Dein Argument ist kräftig, aber bei MC oder Antichamber oder Portal etc krieg ich wenn ich die eben in den Durchschnitt packe so 110 FPS, also funktioniert das wohl. Dann müssen halt Display und Recalculate unabhängig laufen.

    Mangafreak1995 schrieb:

    Dann müssen halt Display und Recalculate unabhängig laufen.


    Dann würde es noch weniger Sinn machen, mehr Frames pro Sekunde darstellen zu lassen. Wenn das Spiel z.B. 60 mal in der Sekunde geupdated wird, die Framerate aber unbegrenzt ist kann man die Framerate auch gleich limitieren, da sich zwischen 2 Updates nichts an der visuellen Ausgabe ändert.

    Naja, wie dem auch sei, die Implementierung des Gameloops wird sich vorerst nicht ändern :) Es macht meiner Meinung nach keinen Sinn, so ein Feature anzubieten, wenn man berechnen will, wie viele Frames man erreichen würde kann man auch die FrameTime-Property des GameLoops verwenden.

    erreichte Framerate = 1000.0 / FrameTime



    MfG

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Krissel095“ ()

    VSync ist übrigens auf die Monitorframerate begrenzt, also meistens 60 FPS. Und das Prinzip dieser Engine scheint das selbe zu sein wie bei XNA - Weniger Aufwand für den Entwickler, da man von einer festen Framerate ausgehen kann.

    MfG Solaris
    Mit VSync machen mehr FPS als die Bilddarstellungsrate des Monitors keinen Sinn. Aber wenn man VSync nicht verwendet, ist eine noch höhere Framerate doch noch besser, um Tearing zu verhindern. Weil wenn 60 Bilder pro Sekunde nicht mit den 60 Herz des Monitors gesynced sind, bringts ja wenig :P

    Skybird schrieb:

    Das sind ja Ubisoftmethoden hier !

    Glückwunsch, wirklich gelungenes Projekt.
    Exakt was ich brauche: für 2D-Anwendungen nicht so überladen wie Unity3D und gleichzeitig weit angenehmer als 'pures' GDI+.
    Objektorientiert, relativ simpel... Respekt!

    Eine Frage habe ich aber doch:
    Ist es möglich, der GraphicsDevice eine andere Hintergrundfarbe zuzuweisen als das normale Schwarz, ohne gleich mit Texturen zu arbeiten?
    Wieso befindet sich dieses Tutorial eigentlich nicht im Tutorial Bereich?
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!