Das XNA Framework bietet einen extrem leichten Zugriff auf Direct3D und nimmt einem sowohl die ganze Initialisierung inkl. Windows Fenster als auch den eigentlichen Game Loop vollständig ab. Es muss einzig eine Klasse von Microsoft.Xna.Framework.Game abgeleitet werden, danach gilt es ein paar wenige Methoden wie Update() oder Draw() zu überschreiben, fertig! Hier haben die Entwickler von XNA wirklich sehr gute Arbeit geleistet. Ein einfacherer Einstieg in die 3D Spieleprogrammierung ist fast nicht möglich!

Möchte man aber zum Beispiel einen Game Editor programmieren, oder XNA zur Darstellung von 3D Elementen in eigenen Applikationen benutzen, ist es nicht mehr ganz so einfach. Da man dann bereits über Windows Elemente verfügt, in die man die 3D Darstellung einfügen möchte, ist einem die Game Klasse eher im Wege.

Doch wirklich kompliziert ist es nicht. Die einzige Aufgabe besteht nun darin, einen Eratz für die Game Klasse zu schreiben, die folgende Aufgaben hat:

  • GraphicDevice erzeugen und bereitstellen
  • Game Loop abbilden

Ersteres geschieht durch implementieren der Interfaces IGraphicDeviceService und IGraphicsDeviceManager. Für den Game Loop gibt es anschliessend verschiedene Möglichkeiten. So zum Beispiel Timer, Idle Event Handler oder Varianten mit Win32 Unterstützung wie z.B. PeekMessage(). Eingehen möchte ich aber an dieser Stelle vorallem auf das Erstellen des GraphicsDeviceManager's.

Beide Interfaces implementiere ich dabei in einer Klasse RGraphicsDeviceService. IGraphicsDeviceManager beinhaltet BeginDraw(), EndDraw() und CreateDevice(). Im Moment benutze ich allerdings nur CreateDevice(). In ihr wird das Direct3D Device erzeugt. Dazu dient Microsoft.Xna.Framework.Graphics.GraphicsDevice aus dem XNA Framework. Das so erzeugte Device wird in einer Klassenvariablen gespeichert und steht gegen aussen über das Property GraphicsDevice (Implementation des Interfaces IGraphicsDeviceService) zur Verfügung. Das war's dann auch auch fast schon. Jetzt kommt noch der eigentliche Ersatz für Microsoft.Xna.Framework.Game. Ich nenne sie RXNAGameView. Die Klasse wird von Panel abgeleitet und muss zusätzlich noch IServiceProvider implementieren. In einer Initialize() Methode benutzen wir nun die vorbereitete Klasse RGraphicsDeviceService und fertig! WIr haben nuneine von System.Windows.Forms.Panel abgeleitete Klasse, die in jeder WinForms Applikation benutzt werden kann. Alle anderen XNA Bestandteile benutze ich weiterhin auf gleiche Art und Weise. Kapselt man nun noch alle Aktivitäten der Engine in eigenen Klassen, so kann man wahlweise zwischen einem reinen XNA Game und dem RXNAGameView zur Darstellung wählen. Der Code zu obigen Erläuterungen findet sich nachfolgend in einer gekürzten Fassung:

    class RGraphicsDeviceService : IGraphicsDeviceService, IGraphicsDeviceManager
    {
        
private GraphicsDevice m_graphicsDevice;
        private 
Control m_renderControl;

        public 
RGraphicsDeviceService(Control control)
        {
            
this.m_renderControl control;
        
}

        
#region IGraphicsDeviceService Members

        
public event EventHandler DeviceCreated;
        public event 
EventHandler DeviceDisposing;
        public event 
EventHandler DeviceReset;
        public event 
EventHandler DeviceResetting;

        public 
GraphicsDevice GraphicsDevice
        {
            
get return this.m_graphicsDevice}
        }

        
#endregion

        #region
 IGraphicsDeviceManager Members

        
public bool BeginDraw()
        {
            
return false;
        
}

        
public void CreateDevice()
        {
            PresentationParameters pp 
= new PresentationParameters();
            
pp.IsFullScreen = false;
            
pp.BackBufferCount 1;
            
pp.BackBufferHeight = this.m_renderControl.Height;
            
pp.BackBufferWidth = this.m_renderControl.Width;

            this
.m_graphicsDevice = new GraphicsDevice(GraphicsAdapter.Adapters[0], DeviceType.Hardware,
                                                       
this.m_renderControl.Handle, CreateOptions.SoftwareVertexProcessing, pp);
        
}

        
public void EndDraw()
        {
        }

    }


    
public class RGameView : RPanel, IServiceProvider
    {
        
private RGraphicsDeviceService m_graphicsDeviceService;

        public void 
Initialize()
        {
            
this.m_graphicsDeviceService = new RGraphicsDeviceService(this);
            this
.m_graphicsDeviceService.CreateDevice();
            this
.m_contentManager = new ContentManager(this);

            
Timer timer = new Timer();
            
timer.Tick += new EventHandler(TimerHandler);
            
timer.Interval 100;
            
timer.Start();
        
}

        
void TimerHandler(object sender, EventArgs e)
        {
            RenderLoop()
;
        
}


        
#region IServiceProvider Members

        
public new object GetService(Type serviceType)
        {
            
if (serviceType == typeof(Microsoft.Xna.Framework.Graphics.IGraphicsDeviceService))
            {
                
return this.m_graphicsDeviceService;
            
}
            
else
            
{
                
return base.GetService(serviceType);
            
}
        }

        
#endregion

    
}