Uff con esto de los exámenes no puedo pasarme todo lo que quiero pero bueno he conseguido terminar este post y así aportar algo esta semana.

En todos los juegos o por lo menos en la inmensa mayoría
de ellos llega un momento en el que tenemos que detectar cuando dos objetos del
juego consiguen colisionar.

En XNA, la verdad es que lo tenemos bastante fácil. Están
implementadas unas estructuras que permiten a través de llamadas a métodos
saber si dos objetos colisionan en un determinado momento y de esta forma
podemos avanzar más rápidamente en el desarrollo de nuestros juegos.

XNA nos proporciona tres tipos de volúmenes, bounding box,
bounding sphere y bounding frustrum.

 

El bounding box
lo que hace es encerrar un modelo dentro de una caja que está alineada con los
ejes x,y,z. Este tipo de volumen es el indicado sobre todo para objetos que se
adapten bien a formas rectangulares, ya que si por ejemplo metemos una pelota
dentro de una caja nos quedan partes del volumen sin ocupar y cuando veamos el
choque quedará mal porque veremos un espacio entre la pelota y la otra figura
con la que este colisionando. También hay que tener en cuenta que si rotamos la
figura también hay que rotar la caja porqué si no este método no funciona.

 

El bounding sphere
como su nombre indica es una esfera y al contrario que en la estructura anterior
lo que puede ocurrir es que existan partes del modelo que se salgan de la
esfera. Una ventaja que tenemos con esta estructura es que no tenemos la
necesidad de rotarla nunca por lo que resulta más rápida que la estructura
anterior.

 

Por último también tenemos la estructura bounding frustrum que controla el
espacio que visiona la cámara. Esta estructura no controla colisiones, sino que
sirve para determinar si se ve el objeto o no y de esta forma no tenerlos que
dibujar.

 

Voy a dejar un ejemplillo de cómo comprobar si se chocan
dos cajas en 2D, aunque el bounding box está pensado para objetos 3D si al
constructor le damos los valores correspondientes a la X y a la Y, y cero a la
Z, ya lo tenemos adaptado al 2D.

El ejemplillo es un poco «cutre-rapidillo» pero cualquier duda dejar un comentario e intentare explicarlo un poco mejor. 

 

 #region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion

namespace pong
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        ContentManager content;
        Texture2D ttirador;
        Texture2D tbola;
        SpriteBatch spritebach;

        BoundingBox bfigura;
        BoundingBox bfigura2;
        public Rectangle figura;
        public Rectangle figura2;
        public Vector2 posicion_tirador;
        public int velocidad_tirador;

        BoundingBox bbola;
        public int velocidad_x, velocidad_y;
        public Rectangle bola;
        public Vector2 posicion_bola;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            content = new ContentManager(Services);
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            spritebach = new SpriteBatch(graphics.GraphicsDevice);
            graphics.PreferredBackBufferWidth = 640;
            graphics.PreferredBackBufferHeight = 480;
            graphics.ApplyChanges();

            Random valor = new Random();

            velocidad_x = valor.Next(19);
            velocidad_y = valor.Next(19);

            velocidad_tirador = 6;

            posicion_bola = new Vector2(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2);

            base.Initialize();
        }

        /// <summary>
        /// Load your graphics content.  If loadAllContent is true, you should
        /// load content from both ResourceManagementMode pools.  Otherwise, just
        /// load ResourceManagementMode.Manual content.
        /// </summary>
        /// <param name=»loadAllContent»>Which type of content to load.</param>
        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            if (loadAllContent)
            {
                ttirador = content.Load<Texture2D>(«media\tirador»);
                tbola = content.Load<Texture2D>(«media\bola»);
            }

            // TODO: Load any ResourceManagementMode.Manual content
        }

        /// <summary>
        /// Unload your graphics content.  If unloadAllContent is true, you should
        /// unload content from both ResourceManagementMode pools.  Otherwise, just
        /// unload ResourceManagementMode.Manual content.  Manual content will get
        /// Disposed by the GraphicsDevice during a Reset.
        /// </summary>
        /// <param name=»unloadAllContent»>Which type of content to unload.</param>
        protected override void UnloadGraphicsContent(bool unloadAllContent)
        {
            if (unloadAllContent == true)
            {
                content.Unload();
            }
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input and playing audio.
        /// </summary>
        /// <param name=»gameTime»>Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the default game to exit on Xbox 360 and Windows
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here
            posicion_bola.X += velocidad_x;
            posicion_bola.Y += velocidad_y;

            bola = new Rectangle((int)posicion_bola.X, (int)posicion_bola.Y, tbola.Width, tbola.Height);
            bbola = new BoundingBox(new Vector3(posicion_bola, 0), new Vector3(posicion_bola.X + tbola.Width, posicion_bola.Y + tbola.Height, 0));
            figura = new Rectangle((int)posicion_tirador.X, (int)posicion_tirador.Y, ttirador.Width, ttirador.Height);
            bfigura = new BoundingBox(new Vector3(posicion_tirador, 0), new Vector3(posicion_tirador.X + ttirador.Width, posicion_tirador.Y+ttirador.Height, 0));
            figura2=new Rectangle(640 – ttirador.Width, (int)posicion_tirador.Y, ttirador.Width, ttirador.Height);
            bfigura2 = new BoundingBox(new Vector3(640 – ttirador.Width, posicion_tirador.Y, 0), new Vector3(figura2.X + ttirador.Width, figura2.Y + ttirador.Height, 0));
            elteclado();

            //Cuando el tirador golpea golpea las paredes debe rebotar
            //ABAJO
            if (posicion_tirador.Y > (480 – ttirador.Height))
            {
                posicion_tirador.Y = (480 – ttirador.Height);
            }
            //ARRIBA
            if (posicion_tirador.Y < 1)
            {
                posicion_tirador.Y = 1;
            }

            //Cuando la bola golpea golpea las paredes debe rebotar
            //ABAJO
            if (posicion_bola.Y > (480 – tbola.Height))
            {
                velocidad_y *= -1;
            }
            //ARRIBA
            if (posicion_bola.Y < 1)
            {
                velocidad_y *= -1;
            }

            if (bfigura2.Intersects(bbola))
            {
                velocidad_x *= -1;
            }

            if (bfigura.Intersects(bbola))
            {
                velocidad_x *= -1;
            }

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name=»gameTime»>Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

            spritebach.Begin(SpriteBlendMode.AlphaBlend);
            spritebach.Draw(ttirador, figura, Color.White);
            spritebach.Draw(ttirador, figura2, Color.White);
            spritebach.Draw(tbola, bola, Color.White);
            spritebach.End();

            base.Draw(gameTime);
        }

        KeyboardState estadoteclado;
        void elteclado()
        {
            estadoteclado = Keyboard.GetState();
            Keys[] teclaspulsada = estadoteclado.GetPressedKeys();
            foreach (Keys ekey in teclaspulsada)
            {
                if (ekey == Keys.Up)
                    posicion_tirador.Y -= velocidad_tirador;
                if (ekey == Keys.Down)
                    posicion_tirador.Y += velocidad_tirador;
                if (ekey == Keys.Space)
                    posicion_bola = new Vector2(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2);
                if (ekey == Keys.Escape)
                    this.Exit();

            }
        }
    }
}

 

Un saludete [H]