Skip to content
octubre 12, 2010 / 100xna

[Intermedio] Menus en XNA


¿Que es un juego sin menú? Incluso los juegos más simples tienen un menú. Una pantalla de inicio, que da paso a la ventana de opciones, los créditos, donde elegir si vamos a jugar solos o multijugador…etc

Aprovechando el tutorial de gestión de estados, vamos a ver como implementar un menú para nuestro juego. Sigue leyendo después del salto para ver como lo hacemos.

Al igual que hicimos con el ejemplo de gestión de estados, vamos a empezar con el diagrama.Main

 

State es la clase que creamos en el ejemplo anterior. Como podéis ver, el menú es en realidad un nuevo estado. Lo que pasa es que es un estado “especial”. Este estado contiene un atributo de tipo Menu, que controlará la lógica de seleccionar ítems del menú. MenuItem es cada uno de los ítems que contendrá el menú, esto es : Opciones, créditos, un jugador, multijugador, salir, etc.…

Por ultimo llegamos a MainMenu, que es en realidad el estado que contiene nuestro menú. En el ejemplo, este estado contiene 3 ítems: Un jugador, Opciones y Salir.

MenuItem

El ítem, elemento básico de nuestro sistema de menús. Representa una opción del menú. Por ejemplo: “Salir”, “Jugar”, “Opciones”, etc…

 

  1         public string Name; //Nombre del item
  2         public event EventHandler Activate;
  3         public bool IsDisabled = false;
  4
  5
  6         public MenuItem(string name)
  7         {
  8             Name = name;
  9         }
10
11
12         public void PerformActivate()
13         {
14             if (Activate != null)
15                 Activate(this, null);
16         }

 

Menu

Esta clase controla toda la lógica interna del comportamiento del menú. Tiene dos atributos: una lista de ítems y una variable que indica cual es el ítem seleccionado actualmente.

  1         public List<MenuItem> Items = new List<MenuItem>(); //Lista de opciones disponibles en el menu
  2         private int itemActual = 0

 

En el método Draw, calculamos las posiciones de los ítems para que más o menos salgan centrados en pantalla.

  1         public void Draw(SpriteBatch spritebatch, SpriteFont fuente)
  2         {
  3             spritebatch.Begin();
  4
  5             for (int i = 0; i < Items.Count; i++)
  6             {
  7                 MenuItem item = Items[i];
  8                 Vector2 tam = fuente.MeasureString(item.Name);
  9
10                 Vector2 pos = new Vector2(
11                     spritebatch.GraphicsDevice.Viewport.Width / 2,
12                     spritebatch.GraphicsDevice.Viewport.Height / 2);
13
14                 pos -= tam * 0.5f;
15                 pos.Y += i * (tam.Y * 1.1f);
16
17                 Color color = Color.White;
18                 if (item == SelectedItem)
19                     color = Color.Yellow;
20                 else if (item.IsDisabled)
21                     color = Color.DarkGray;
22
23                 spritebatch.DrawString(fuente, item.Name, pos, color);
24             }
25
26             spritebatch.End();
27         }

 

También tenemos métodos para trabajar con los ítems, sabiendo cual es el ítem seleccionado actualmente y pudiendo seleccionar el anterior o el siguiente. Fijaros que el menú es cíclico, esto es: cuando llegamos a la ultima opción del menú y le damos a siguiente, vuelve al principio.

  1         public MenuItem SelectedItem
  2         {
  3             get
  4             {
  5                 if (Items.Count > 0)
  6                     return Items[itemActual];
  7                 else
  8                     return null;
  9             }
10         }
11 
12         public void SelectNext()
13         {
14             if (Items.Count > 0)
15             {
16                 do 
17                 { 
18                     itemActual = (itemActual + 1) % Items.Count; 
19                 } while (SelectedItem.IsDisabled);
20             }
21         }
22 
23 
24         public void SelectPrevious()
25         {
26             if (Items.Count > 0
27             { 
28                 do 
29                 {
30                     itemActual–;
31                     if (itemActual < 0)
32                         itemActual = Items.Count – 1;
33                 } while (SelectedItem.IsDisabled);
34             }
35         }

 

MenuState

Una vez tenemos montado el menú, tenemos que definir los estados que van a contener menús. Para ello, primero definimos una clase base llamada “MenuState” con los siguientes atributos:

  1         protected SpriteBatch spriteBatch;
  2         protected SpriteFont fuente;
  3         protected KeyboardState tecladoAnterior;
  4         protected KeyboardState tecladoActual;
  5         protected Menu menu;

 

En el constructor hacemos lo siguiente:

  1         public MenuState(Game game) : base(game)
  2         {
  3             spriteBatch = new SpriteBatch(GraphicsDevice);
  4             fuente = Content.Load<SpriteFont>("menu");
  5             menu = new Menu();
  6
  7             tecladoActual = tecladoAnterior = Keyboard.GetState();
  8         }

 

En el Update debemos comprobar si el usuario pulsa alguna tecla para cambiar de ítem. Y si pulsa Enter, entonces ejecutamos el ítem seleccionado:

  1         public override void Update(GameTime gameTime)
  2         {
  3             tecladoActual = Keyboard.GetState();
  4
  5             if (tecladoActual.IsKeyDown(Keys.Enter) && !tecladoAnterior.IsKeyDown(Keys.Enter))
  6             {
  7                 if (menu.SelectedItem != null)
  8                     menu.SelectedItem.PerformActivate();
  9             }
10
11             if (tecladoActual.IsKeyDown(Keys.Up) && !tecladoAnterior.IsKeyDown(Keys.U))
12             {
13                 menu.SelectPrevious();
14             }
15
16             if (tecladoActual.IsKeyDown(Keys.Down) && !tecladoAnterior.IsKeyDown(Keys.Down))
17             {
18                 menu.SelectNext();
19             }
20
21             tecladoAnterior = tecladoActual;
22         }

 

Para pintar el estado, llamamos al Draw del menú:

  1         public override void Draw(GameTime gameTime)
  2         {
  3             menu.Draw(spriteBatch, fuente);
  4         }

 

 

MainMenu

Llegamos por fin a lo que nos interesa realmente: nuestro menú. Una vez tenemos todas las clases anteriores, es muy fácil hacer un nuevo menú. Tan sólo hay que añadir ítems y definir que acción quieres que se ejecute cuando el usuario seleccione el ítem.

En el constructor definimos los ítems que queremos añadir. En este caso, “Un jugador”, “Opciones” y “Salir”.

  1         public MainMenu(Game game)
  2             : base(game)
  3         {
  4             MenuItem item;
  5
  6             //Añadimos las posibles opciones del menu
  7             item = new MenuItem("Un jugador");
  8             item.Activate += UnJugadorActivated;
  9             menu.Items.Add(item);
10
11             item = new MenuItem("Opciones");
12             item.Activate += OptionsActivated;
13             menu.Items.Add(item);
14
15             item = new MenuItem("Salir");
16             item.Activate += QuitActivated;
17             menu.Items.Add(item);
18
19             tecladoActual = tecladoAnterior = Keyboard.GetState();
20         }

 

Ahora tenemos que programar los controladores de eventos de cada ítem. Para el caso de “un jugador”, es algo así:

  1         public void UnJugadorActivated(object sender, EventArgs args)
  2         {
  3             //Ahora vamos a cargar los recursos del estados. Como supuestamente va
  4             //a tardar un poco en cargar todo, pasamos al estado que muestra
  5             //la pantalla de "cargando"
  6             (Manager.Estados[GameStates.PlayingState] as PlayingState).Initialize(); 
  7             Manager.EstadoActual = GameStates.Loading;
  8         }

Como podéis ver, lo que hacemos cuando el usuario selecciona “Un jugador” es cargar el estado de “Loading”. Este estado, como vimos en el ejemplo anterior, espera 2 segundos y luego cambia al estado “Jugando”

Por ejemplo, en el caso de “Salir” el código seria el siguiente:

  1         public void QuitActivated(object sender, EventArgs args)
  2         {
  3             Game.Exit();
  4         }

Y por ultimo, no os olvides del “Update

  1         public override void Update(GameTime gameTime)
  2         {
  3             base.Update(gameTime);
  4         }

 

——————————————————————————————————————————–

 

Download Código Fuente

Ahora os toca a vosotros mirar el código y trastear con él para ir haciendo cosas.

PD: Este tutorial esta basado en un ejemplo de Nick Gravelyn

Anuncios

One Comment

  1. Carlos / Oct 27 2010 10:39 pm

    Desde luego muy interesante, creo que te voy a meter en mis RSS Feed 😉
    Por cierto, podrias incluir todos estos utiles tutoriales en http://www.creagamers.es

    😉

    un saludo

Los comentarios están cerrados.

A %d blogueros les gusta esto: