Auf das Thema antworten  [ 2 Beiträge ] 
Menü-Button für XNA 
Autor Nachricht
Administrator
Benutzeravatar

Registriert: Sa 15. Dez 2012, 19:15
Beiträge: 137
Wohnort: Karlsruhe
Mit Zitat antworten
Hallo Leute!

Nachdem ich als Feedback zurückbekommen habe dass meine MouseEvents "zu komplex" sei, möchte ich hier ein einfaches Beispiel anbieten, wie man diese Klasse anwenden könnte. Dazu werden wir einen vollwertigen Menü-Button mit allen Events erstellen. Das Visual-Studio-Projekt kann am Ende des Tutorials heruntergeladen werden. Ich benutze noch Visual Studio 2010.


Neues Projekt starten
Über "Datei", "Neu..", "Projekt..." kommen zum Auswahlfenster für Vorlagen. Unter "Visual C#", "XNA Game Studio 4.0" wählen wir "Windows Game (4.0)" aus, geben ein Projektnamen ein und bestätigen dies mit einem Klick auf "OK".


Hinzufügen der MouseEvents-Klasse
Hier könnt ihr die Klasse komplett downloaden. Kopiert die Visual C# Source file "MouseEvents.cs" aus dem gepackten Verzeichnis in euer Projekt. Ihr könnt das z.B. dadurch tun, dass ihr die Datei per Drag & Drop auf euren "Game1"-Eintrag in eurem Projektmappen-Explorer zieht, oder ihr klickt auf "Projekt" (Oben in der Menüleiste) und wählt "Vorhandenes Element hinzufügen...". Im folgenden Fenster könnt ihr dann die entpackte Visual C# Source file "MouseEvents.cs" auswählen und hinzufügen.

Ändert noch den namespace der KeyEvents-Klasse in Game1 - oder wie auch immer euer Standard-Namespace lautet.


Hinzufügen des GameState-Interface
Ein Interface bestimmt Properties, Methoden usw. die eine Klasse, die dieses Interface implementiert, besitzen muss. So kann man die Klasse in das Interface umwandeln und auf alle Properties, Methoden usw. zugreifen, die im Interface deklariert wurden.

Über "Projekt" (Oben in der Menüleiste), "Neues Element hinzufügen..." kommt ihr wieder zum Fenster für das Hinzufügen einer Vorlage. Wählt "Schnittstelle" aus - das deutsche Wort für "Interface" und wählt die Datei "IGameState". Kopiert dann folgenden Inhalt in das Interface:
Code:
 
internal interface IGameState
{
        string GameStateName { get; }
        void Update(GameTime time);
        void Draw(GameTime time, GraphicsDevice grapic, SpriteBatch sprite);
        bool ContentLoaded { get; set; }
        void LoadContent();
        void UnloadContent();
}
 


Dieses Interface könnt ihr für eurer GameStateManagement nutzen.


Hinzufügen der MenuButton-Klasse
Der Code für den MenuButton ist etwas länger, aber lasst euch davon nicht abschrecken. Fügt einfach den Code als neue Klasse in euer Projekt ein ("Projekt", "Neues Element hinzufügen...", "Klasse"), die Erklärungen dazu gibt es in den Kommentaren.
Code:
 
// Implementieren des Interface IGameState
internal class MenuButton : IGameState
{
 
        internal static Texture2D Hintergrund;  // Der Hintergrund für den Button
        internal static SpriteFont myFont;      // Die Standard-SpriteFont, mit der wir den Text zeichnen
        private static int ButtonCounter = 1;   // Ein Counter für den Buttonnamen (siehe Konstruktor)
 
        public string Name { get; set; }        // Name des Buttons
        public string Text { get; set; }        // Text des Buttons
        public Vector2 TextStart { get; set; }  // Position, an der der Text im Button gezeichnet werden soll
        public SpriteFont Font { get; set; }    // Die SpriteFont, mit der wir den Text zeichnen
        public Color BackColor { get; set; }    // Die Farbe des Hintergrunds
        public Color ForeColor { get; set; }    // Die Farbe des Textes
       
        private float _left = 0;                // Bei Änderung des Wertes müssen die Events.Bounds neu gesetzt werden
        private float _top = 0;                 // Deshalb sind _left, _top, _width und _height private
        public float Left                       // Die X-Koordinate des Buttons
        {
                get { return _left; }
                set { _left = value; Events.Bounds = Bounds; }
        }                  
        public float Top                        // Die Y-Koordinate des Buttons
        {
                get { return _top; }
                set { _top = value; Events.Bounds = Bounds; }
        }                  
        public Vector2 Location                 // Die Koordinaten des Buttons
        {
                get { return new Vector2(Left, Top); }
                set { Left = value.X; Top = value.Y; }
        }
 
        private float _width = 153;
        private float _height = 41;
 
        public float Width                      // Die Breite des Buttons
        {
                get { return _width; }
                set { _width = value; Events.Bounds = Bounds; }
        }
        public float Height                     // Die Höhe des Buttons
        {
                get { return _height; }
                set { _height = value; Events.Bounds = Bounds; }
        }
 
        public Vector2 Size                     // Die Größe des Buttons
        {
                get { return new Vector2(_width, _height); }
                set { Width = value.X; Height = value.Y; }
        }
 
        public Vector4 Bounds                   // Die Grenzen des Buttons
        {
                get { return new Vector4(_left, _top, _left + _width, _top + _height); }
                set { Left = value.X; Top = value.Y; Width = value.Z - value.X; Height = value.W - value.Y; }
        }
 
        private MouseEvents.Entry Events;       // Die Events für MouseEvents
        public bool Visible                     // Ob der Button angezeigt und die Events ausgelöst werden sollen
        {
                get { return Events.Active; }
                set { Events.Active = value; }
        }
 
        /// <summary>
        /// Instanziert einen neuen MenuButton
        /// </summary>
        /// <param name="text">Der Text des Buttons</param>
        /// <param name="textStart">Die Position des Textes im Button</param>
        /// <param name="foreColor">Die Farbe des Textes</param>
        /// <param name="visible">Ob der Button angezeigt und Events ausgelöst werden sollen</param>
        internal MenuButton(string text, Vector2 textStart, Color foreColor, bool visible)
        {
                Name = "Button" + (ButtonCounter++).ToString().PadLeft(2, '0'); // Ergibt "Button01", "Button02", usw.
                Text = text; TextStart = textStart; Font = myFont; ForeColor = foreColor; // Zuweisung der Properties
                BackColor = Color.White; // Standard-Hintergrundfarbe
 
                // Hinzufügen der Events
                Events = new MouseEvents.Entry(
                        _left, _top, _left + _width, _top + _height,
                        new MouseEvents.OnHandler(OnEnter),
                        new MouseEvents.OnHandler(OnOver),
                        new MouseEvents.OnHandler(OnLeave),
                        new MouseEvents.OnHandler(OnOut),
                        new MouseEvents.OnHandler(OnClick),
                        this, visible); // das this überträgt diese Instanz als UserState. So können wir im Ereignis auf diese Instanz zugreifen
 
                // Events der Überwachung hinzufügen
                MouseEvents.Entries.Add(Events);
        }
 
        // Es folgen die Events und die Methoden für die Events
        public event MouseEvents.OnHandler MouseClick = null;
        private void OnClick(MouseEvents.Entry mouseEvents)
        {
                if (MouseClick != null) MouseClick(mouseEvents);
        }
        public event MouseEvents.OnHandler MouseEnter = null;
        private void OnEnter(MouseEvents.Entry mouseEvents)
        {
                if (MouseEnter != null) MouseEnter(mouseEvents);
        }
        public event MouseEvents.OnHandler MouseOver = null;
        private void OnOver(MouseEvents.Entry mouseEvents)
        {
                if (MouseOver != null) MouseOver(mouseEvents);
        }
        public event MouseEvents.OnHandler MouseLeave = null;
        private void OnLeave(MouseEvents.Entry mouseEvents)
        {
                if (MouseLeave != null) MouseLeave(mouseEvents);
        }
        public event MouseEvents.OnHandler MouseOut = null;
        private void OnOut(MouseEvents.Entry mouseEvents)
        {
                if (MouseOut != null) MouseOut(mouseEvents);
        }
 
        // Es folgt die Implementierung des Interfaces IGameState
        string IGameState.GameStateName
        {
                get { return Name; }
        }
 
        void IGameState.Update(GameTime time)
        {
                return;
        }
 
        void IGameState.Draw(GameTime time, GraphicsDevice grapic, SpriteBatch sprite)
        {
                if (!Visible) { return; }
                sprite.Draw(Hintergrund, new Rectangle((int)_left, (int)_top, (int)_width, (int)_height), BackColor);
                sprite.DrawString(Font, Text, new Vector2(_left + TextStart.X, _top + TextStart.Y), ForeColor);
        }
 
        bool IGameState.ContentLoaded { get; set; }
        void IGameState.LoadContent()
        {
                ((IGameState)this).ContentLoaded = true;
        }
        void IGameState.UnloadContent()
        {
                ((IGameState)this).ContentLoaded = false;
        }
}
 



Alles zum Laufen bringen
Jetzt wo wir alle Klassen haben, müssen wir noch die Game1 etwas bearbeiten. Als erstes müssen folgende drei Variablen noch hinzugefügt werden:
Code:
 
GraphicsDeviceManager graphics; // Existiert bereits
SpriteBatch spriteBatch; // Existiert bereits
GraphicsDevice device;
 
MenuButton NeuesSpiel;
Texture2D Maus;
 

Dann muss die Methode LoadContent() modifiziert werden:
Code:
 
protected override void LoadContent()
{
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);
        device = this.GraphicsDevice;
 
        MenuButton.Hintergrund = this.Content.Load<Texture2D>("XNA_MenuButton");
        Maus = this.Content.Load<Texture2D>("Target");
        MenuButton.myFont = this.Content.Load<SpriteFont>("Cranberry Gin 12");
 
        NeuesSpiel = new MenuButton("Neues Spiel", new Vector2(15, 8), Color.Black, true);
        NeuesSpiel.BackColor = Color.Firebrick;
        NeuesSpiel.Location = new Vector2(100, 100);
        NeuesSpiel.MouseEnter += new MagonyOrg.MouseEvents.OnHandler(NeuesSpiel_MouseEnter);
        NeuesSpiel.MouseLeave += new MagonyOrg.MouseEvents.OnHandler(NeuesSpiel_MouseLeave);
 
        // TODO: use this.Content to load your game content here
}
 
// Die Methoden die bei den Events aufgerufen werden
void NeuesSpiel_MouseLeave(MagonyOrg.MouseEvents.Entry mouseEvents)
{
        // Weil wir die Instanz des MenuButton als UserState übergeben haben
        // (im Konstruktor von MenuButton), können wir nun auf die Instanz im
        // Event zugreifen. Ähnlich wie das object "sender" aus dem System.EventHandler.
        MenuButton b = (MenuButton)mouseEvents.UserState;
        b.ForeColor = Color.Black;
}
 
void NeuesSpiel_MouseEnter(MagonyOrg.MouseEvents.Entry mouseEvents)
{
        MenuButton b = (MenuButton)mouseEvents.UserState;
        b.ForeColor = Color.White;
}
 


Zusammen mit den zwei abonnierten Events für MouseEnter und MouseLeave erzeugen wir einen Rollover-Effekt.

Jetzt fehlt noch Update und Draw:
Code:
 
protected override void Update(GameTime gameTime)
{
        // Allows the game to exit
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
 
        // TODO: Add your update logic here
        MouseEvents.Update(); // Notwendig, damit die Events geprüft werden
        ((IGameState)NeuesSpiel).Update(gameTime); // Eigentlich unnötig...
 
        base.Update(gameTime);
}
 
protected override void Draw(GameTime gameTime)
{
        GraphicsDevice.Clear(Color.CornflowerBlue);
 
        MouseState m = Mouse.GetState();
 
        // TODO: Add your drawing code here
        spriteBatch.Begin();
        ((IGameState)NeuesSpiel).Draw(gameTime, device, spriteBatch); // Zeichnen des Buttons
        spriteBatch.Draw(Maus, new Rectangle(m.X - 10, m.Y - 10, 20, 20), Color.Violet); // Zeichnen der Maus
        spriteBatch.End();
 
        base.Draw(gameTime);
}
 



Wer das ganze Projekt als Visual-Studio-Solution haben möchte, kann das Projekt nun hier downloaden.


Wenn es Fragen oder Anmerkungen gibt: Immer her damit!

Schöne Grüße,
Magony

_________________
Bei Fragen, Lob, Kritik, Vorschläge, hilfreiche Hinweise oder Alternativvorschläge: Beitrag, neues Thema oder PN.
Für Dinge die diskutiert werden sollten, bitte neues Thema im jeweiligen Forum.
Wenn du nicht weißt wohin: Forum Unsortiert.


Do 28. Mär 2013, 18:19
Diesen Beitrag melden
Profil Website besuchen
Administrator
Benutzeravatar

Registriert: Sa 15. Dez 2012, 19:15
Beiträge: 137
Wohnort: Karlsruhe
Mit Zitat antworten
Hallo Leute!

In diesem Thread biete ich euch die Bibliothek magonyORG.Input als OpenSource mit einer kleinem Testumgebung und einem Beispiel an. Sie beinhaltet sowohl die MouseEvents als auch die KeyEvents und den Button. Außerdem bietet sie weitere Verbesserungen und wird auch in Zukunft weiterentwickelt.

Schöne Grüße,
Magony

_________________
Bei Fragen, Lob, Kritik, Vorschläge, hilfreiche Hinweise oder Alternativvorschläge: Beitrag, neues Thema oder PN.
Für Dinge die diskutiert werden sollten, bitte neues Thema im jeweiligen Forum.
Wenn du nicht weißt wohin: Forum Unsortiert.


Sa 28. Sep 2013, 14:39
Diesen Beitrag melden
Profil Website besuchen
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Auf das Thema antworten   [ 2 Beiträge ] 

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast


Du darfst neue Themen in diesem Forum erstellen.
Du darfst Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
cron
Powered by phpBB® Forum Software © phpBB Group
Designed by ST Software
Deutsche Übersetzung durch phpBB.de

Impressum