Χρήση XNA σε εφαρμογές WPF

Σελίδα ενημέρωση :
Ημερομηνία δημιουργίας σελίδας :

περίληψη

Περιγράφει τον τρόπο χρήσης του XNA Framework σε εφαρμογές WPF.

WPF アプリケーションで XNA を使用する

Περιβάλλον λειτουργίας

Προϋποθέσεις

Υποστηριζόμενες εκδόσεις XNA
  • 2.0
  • 3.0
Υποστηριζόμενες πλατφόρμες
  • Windows (XP SP2 ή νεότερη έκδοση, Vista)
Windows Απαιτούμενη έκδοση σκίασης Vertex 1.1
Απαιτούμενη έκδοση Pixel Shader των Windows 1.1

Περιβάλλον λειτουργίας

πλατφόρμα

ουσία

Για να κάνετε απόδοση σε ένα συγκεκριμένο στοιχείο ελέγχου χρησιμοποιώντας το DirectX, πρέπει να λάβετε τη λαβή παραθύρου για αυτό το στοιχείο ελέγχου. Ωστόσο, σε αντίθεση με τα στοιχεία ελέγχου φόρμας των Windows, τα στοιχεία ελέγχου WPF δεν διαθέτουν λαβές παραθύρων (στο WPF απλώς "σχεδιάζουν" το στοιχείο ελέγχου).

Ωστόσο, το WPF παρέχει ένα στοιχείο ελέγχου που ονομάζεται "WindowsFormsHost" που σας επιτρέπει να χρησιμοποιείτε στοιχεία ελέγχου Windows Forms.

Σε αυτό το άρθρο, θα δημιουργήσουμε ένα δείγμα σχεδίασης ενός πολυγώνου καθώς περιστρέφεται όπως φαίνεται παραπάνω, αλλά θα παραλείψω τις λεπτομέρειες του ίδιου του XNA γιατί θα ήταν πολύ μεγάλο για να το εξηγήσω. Θα μιλήσω μόνο για τη σχέση μεταξύ WPF και XNA.

Πρώτα, ανοίξτε ένα παράθυρο WPF (σε αυτήν την περίπτωση, Window1.xaml) και τοποθετήστε ένα στοιχείο ελέγχου WindowsFormHost από τη γραμμή εργαλείων. Το ρυθμιστικό στα δεξιά είναι ένα μπόνους.

WPF ウインドウデザイン

Πρέπει πραγματικά να κάνω λίγο περισσότερη δουλειά στο XAML, αλλά θα το αφήσω για αργότερα, επειδή πρέπει πρώτα να δημιουργήσω τα χειριστήρια για να χρησιμοποιήσω το XNA.

Προσθέστε ένα "Προσαρμοσμένες φόρμες των Windows" "Προσαρμοσμένο στοιχείο ελέγχου" στο έργο σας. Αφήστε το όνομα GraphicsDeviceControl.

Windows Forms のカスタムコントロールを追加

Μην ξεχάσετε να προσθέσετε εκ των προτέρων την αναφορά "Microsoft.Xna.Framework". Υπάρχει επίσης το "Microsoft.Xna.Framework.Game", αλλά αυτό χρησιμοποιείται σε ένα έργο μόνο για παιχνίδι, επομένως δεν χρειάζεται να το συμπεριλάβετε.

Managed DirectX の参照

Για να διατηρήσετε το δείγμα κώδικα σύντομο, όλα τα προγράμματα που σχετίζονται με το XNA συνοψίζονται σε GraphicsDeviceControl.cs. Δεν είναι ένα πολύ ευέλικτο στυλ γραφής, οπότε εφαρμόστε το και ξαναγράψτε το.

Ο πλήρης κώδικας για το GraphicsDeviceControl εμφανίζεται παρακάτω (εκτός από το τμήμα σχεδιαστή). Εάν έχετε χρησιμοποιήσει ποτέ XNA, θα ξέρετε ότι δεν κάνει τίποτα ασυνήθιστο. Χρησιμοποιώ ένα στοιχείο χρονοδιακόπτη για να κάνω το πολύγωνο να φαίνεται ότι περιστρέφεται συνεχώς.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace XNAOnWPF
{
    /// <summary>
    /// グラフィックデバイスコントロール
    /// </summary>
    public partial class GraphicsDeviceControl : Control
    {
        /// <summary>
        /// グラフィックデバイス
        /// </summary>
        private GraphicsDevice device = null;

        /// <summary>
        /// エフェクト
        /// </summary>
        private BasicEffect effect = null;

        /// <summary>
        /// 頂点データ
        /// </summary>
        private VertexPositionColor[] vertices = new VertexPositionColor[3];
        /// <summary>
        /// 頂点データ
        /// </summary>
        public VertexPositionColor[] Vertices
        {
            get { return this.vertices; }
        }


        /// <summary>
        /// コンストラクタ
        /// </summary>
        public GraphicsDeviceControl()
        {
            InitializeComponent();
        }

        /// <summary>
        /// コントロールが作成されるとき
        /// </summary>
        protected override void OnCreateControl()
        {
            if (this.DesignMode == false)
            {
                try
                {
                    // デバイス作成
                    PresentationParameters pp = new PresentationParameters();
                    pp.SwapEffect = SwapEffect.Discard;
                    pp.BackBufferWidth = 300;
                    pp.BackBufferHeight = 300;
                    pp.EnableAutoDepthStencil = true;
                    pp.AutoDepthStencilFormat = DepthFormat.Depth16;
                    this.device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter,
                        DeviceType.Hardware, this.Handle, pp);

                    // 頂点データの設定
                    this.vertices[0] = new VertexPositionColor(
                        new Vector3(0.0f, -2.0f + (float)Math.Sqrt(3) * 3.0f, 0.0f),
                        new Microsoft.Xna.Framework.Graphics.Color(255, 0, 0));
                    this.vertices[1] = new VertexPositionColor(
                        new Vector3(3.0f, -2.0f, 0.0f),
                        new Microsoft.Xna.Framework.Graphics.Color(0, 255, 0));
                    this.vertices[2] = new VertexPositionColor(
                        new Vector3(-3.0f, -2.0f, 0.0f),
                        new Microsoft.Xna.Framework.Graphics.Color(0, 0, 255));

                    // 頂点定義
                    this.device.VertexDeclaration =
                        new VertexDeclaration(this.device, VertexPositionColor.VertexElements);

                    // エフェクト
                    this.effect = new BasicEffect(this.device, null);
                    this.effect.VertexColorEnabled = true;

                    // ビュー変換行列を設定
                    this.effect.View = Matrix.CreateLookAt(
                        new Vector3(0.0f, 0.0f, -10.0f),
                        new Vector3(0.0f, 0.0f, 0.0f),
                        Vector3.Up);

                    // 射影変換を設定
                    this.effect.Projection = Matrix.CreatePerspectiveFieldOfView(
                        MathHelper.ToRadians(45.0f), 1.0f, 1.0f, 100.0f);

                    // レンダリングステート設定
                    this.device.RenderState.CullMode = CullMode.None;
                    this.device.RenderState.AlphaBlendEnable = true;
                    this.device.RenderState.SourceBlend = Blend.SourceAlpha;
                    this.device.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex.ToString());
                }
            }

            base.OnCreateControl();
        }

        /// <summary>
        /// 使用中のリソースをすべてクリーンアップします。
        /// </summary>
        /// <param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }

            if (disposing)
            {
                if (this.device != null)
                {
                    this.device.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        /// <summary>
        /// 描画イベント
        /// </summary>
        /// <param name="pe"></param>
        protected override void OnPaint(PaintEventArgs pe)
        {
            this.Draw();

            base.OnPaint(pe);
        }

        /// <summary>
        /// 描画
        /// </summary>
        private void Draw()
        {
            if (this.device == null)
            {
                return;
            }

            this.device.Clear(Microsoft.Xna.Framework.Graphics.Color.DarkBlue);

            // ポリゴンを描画する
            this.effect.Begin();
            this.effect.Techniques[0].Passes[0].Begin();

            this.effect.World = Matrix.CreateRotationY((float)Environment.TickCount / 1000.0f);
            this.device.DrawUserPrimitives<VertexPositionColor>(
                PrimitiveType.TriangleList, vertices, 0, 1);

            this.effect.Techniques[0].Passes[0].End();
            this.effect.End();

            this.device.Present();
        }

        /// <summary>
        /// タイマーイベント
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer_Tick(object sender, EventArgs e)
        {
            this.Draw();
        }
    }
}

Τώρα που δημιουργήσατε το στοιχείο ελέγχου, ας δούμε την XAML. Εφόσον πρόκειται να τοποθετήσουμε το στοιχείο ελέγχου που δημιουργήσαμε, θα προσθέσουμε έναν χώρο ονομάτων στην ετικέτα root. Εδώ, ορίζεται ως "xw".

<Window&nbsp;x:Class="ManagedDirectXOnWPF.Window1"
&nbsp;&nbsp;&nbsp;&nbsp;xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
&nbsp;&nbsp;&nbsp;&nbsp;xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
&nbsp;&nbsp;&nbsp;&nbsp;Title="WPFウインドウ上でManaged DirectXを使用してポリゴン描画"
&nbsp;&nbsp;&nbsp;&nbsp;Height="338"&nbsp;Width="422"
&nbsp;&nbsp;&nbsp;&nbsp;xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
&nbsp;&nbsp;&nbsp;&nbsp;xmlns:xw="clr-namespace:ManagedDirectXOnWPF">
    <!-- 省略 -->
</Window>

Στη συνέχεια, αναπτύξτε την ετικέτα για το στοιχείο ελέγχου WindowsFormsHost που μόλις τοποθετήσατε και προσθέστε ένα GraphicsDeviceControl, όπως φαίνεται παρακάτω.

<my:WindowsFormsHost&nbsp;Name="windowsFormsHostManagedDirectX"&nbsp;Width="300"&nbsp;Height="300"
                    HorizontalAlignment="Left"&nbsp;VerticalAlignment="Top">
  <xw:GraphicsDeviceControl&nbsp;x:Name="GraphicsDeviceControl"&nbsp;/>
</my:WindowsFormsHost>

Δεν χρειάζεται να έχετε ένα "x:Name", αλλά το δείγμα το χρησιμοποιεί για πρόσβαση σε δεδομένα κορυφής με ένα ρυθμιστικό.

Εάν το κάνετε αυτό, μπορείτε να εκτελέσετε μια σκηνή στο WPF όπου τα πολύγωνα σχεδιάζονται με ένα περιστρεφόμενο πολύγωνο, όπως φαίνεται στο δείγμα. Η πρόσβαση μέσω ρυθμιστικού είναι ένα μπόνους, οπότε κατεβάστε το δείγμα δεδομένων και ελέγξτε το.

Το πρόγραμμα απαιτεί το .NET Framework 3.0, τον πιο πρόσφατο χρόνο εκτέλεσης του DirectX και το Microsoft XNA Framework Redistributable 2.0. Επιπλέον, ως απαίτηση υλικού, απαιτείται "μια κάρτα γραφικών που υποστηρίζει Pixel Shader 1.1 ή νεότερη έκδοση".

Επιπλέον, το έργο δημιουργήθηκε στο "Visual Studio 2008 Professional Edition". Προετοιμάστε ένα περιβάλλον για το Visual Studio 2008.