XNA lección 2 Detectar si el mouse choca con un objeto 3d PDF Imprimir E-mail
1
Escrito por Fernando   
Viernes, 29 de Mayo de 2009 04:19

XNA Game Studio 3.0 lección 2

En esta lección vamos ha realizar un ejercicio que consiste en detectar si el mouse choca con un objeto 3d

1-1 Primero vamos ha crear un proyecto llamado ClicObj luego importamos en nuestro contenedor un modelo 3d en nuestro caso un cubo, si a veis seguido la lección primera esto no sera difícil Xd



1-2 Una ves que tengamos nuestro modelo en el Explorador seleccionamos el archivo Game1.cs ,definimos todas las variables ha utilizar


Código : C#
 
 
GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        /// <summary>
        /// Bloque de variables a utilizar
        /// </summary>
        Model cubo3d;
        MouseState ratonEs;
        Matrix proyector;
        Matrix vista;
        Matrix mundo;
        Vector3 vistaCam;
        Vector3 vistaTar;
        Vector3 trasladar;
        Color prueva;
        float rotY;
        float rotX;
        float rotZ;
 
Analizado en 0.071 segundos ha 6.29 KB/s, GeSHi 1.0.8.2-- CFX.GHCode Programado Por Crea-Flash.com



1-3 Cagamnos nuestro modelo y ubicamos el zoom de la cámara ha una distancia considerable del objeto para poder verlo mejor.


Código : C#
 
 protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
 
            //cagamos el modelo a presentar 
            cubo3d=Content.Load<Model>("Modelos\\cubo");
            //colocamos la cámara 
            vistaCam.Z = 200.0f;
 
        }
 
Analizado en 0.028 segundos ha 11.00 KB/s, GeSHi 1.0.8.2-- CFX.GHCode Programado Por Crea-Flash.com



1-4 A partir de ahora empezaremos ha ir organizando el código, con la construcción de funciones de momento son simples pero según se avance se irán convirtiendo en clases.
Primero creamos una función para cargar los modelos eso ya lo hemos visto en la lección 1


Código : C#
 
 
void MuestraModelo(Model m, Matrix proyector,Matrix vista ,Matrix mundo)
        {
            foreach (ModelMesh mesh in m.Meshes)
            {
                Matrix[] boneTransforms = new Matrix[m.Bones.Count];
                m.CopyAbsoluteBoneTransformsTo(boneTransforms);
                foreach (BasicEffect effect in mesh.Effects)
                {
 
                    effect.Projection = proyector;
                    effect.View = vista;
                    effect.World = boneTransforms[mesh.ParentBone.Index]*mundo;
 
                }
                mesh.Draw();
            }
        }
 
Analizado en 0.037 segundos ha 17.56 KB/s, GeSHi 1.0.8.2-- CFX.GHCode Programado Por Crea-Flash.com



La segunda función que vamos a crear se llama PuntoL lo que hace básicamente es detectar si un punto en la pantalla choca con el área de un objeto utilizando la clase Ray, esta clase es muy buena porque también permite combinar el sistema de choque tridimensional con el de bidimensional aunque la función PuntoL no esta preparada para ello XD

 

Código : C#
 
 Ray PuntoL(Vector2 punto, Matrix proyector, Matrix vista, Matrix mundo)
        {
            Vector3 nearsource = new Vector3((float)punto.Y, (float)punto.Y, 0f);
            Vector3 farsource = new Vector3((float)punto.X, (float)punto.Y, 1f);
            Vector3 nearPoint = graphics.GraphicsDevice.Viewport.Unproject(nearsource, proyector, vista, mundo);
            Vector3 farPoint = graphics.GraphicsDevice.Viewport.Unproject(farsource, proyector, vista, mundo);
            Vector3 direction = farPoint - nearPoint;
            direction.Normalize();
            return  new Ray(nearPoint, direction);
        }
 
Analizado en 0.031 segundos ha 19.87 KB/s, GeSHi 1.0.8.2-- CFX.GHCode Programado Por Crea-Flash.com


Siguiente función es un auxiliar lo que hace es actualizar las variables alteradas, esto normalmente lo pueden programar sin que tengan que estar construyendo funciones de este tipo, personalmente me ayudan ha ordenar mejor que el código para ubicar mejor un posible fallo

 

Código : C#
 
 void actualiza()
        {
            proyector = Matrix.CreatePerspectiveFieldOfView(
                      MathHelper.ToRadians(45.0f),
                      graphics.GraphicsDevice.Viewport.Width / graphics.GraphicsDevice.Viewport.Height,
                      1.0f, 10000.0f);
            vista = Matrix.CreateLookAt(vistaCam, vistaTar, Vector3.Up);
            mundo = Matrix.CreateRotationY(rotY)*
                    Matrix.CreateRotationX(rotX)*
                    Matrix.CreateRotationZ(rotZ)*
                    Matrix.CreateTranslation(trasladar);
        }
 
Analizado en 0.034 segundos ha 16.68 KB/s, GeSHi 1.0.8.2-- CFX.GHCode Programado Por Crea-Flash.com


Por ultimo construimos la funciona que detecta la posición del ratón con respecto al objeto

 

Código : C#
 
 void cambiaColor()
        {
            // Crear un estado del mouse para detectar su posición o si se hace clics en alguno de sus botones
            ratonEs = Mouse.GetState();
            // Crea una clase Ray con las coordenadas del mouse y las que utiliza el modelo 
            Ray puntoL = PuntoL(new Vector2(ratonEs.X, ratonEs.Y), proyector, vista, mundo);
            // define la distancia limite entre el muse y el objeto con respecto al eje de Z 
            // también se puede colocar float.MaxValue para alcanzar el máximo de distancia   
            float distancia = 1000;
            //BoundingSphere crea un objeto esférico que sirve como detector de choque 
            //si un modelo es cubico este sistema no reconocerá las esquinas 
            BoundingSphere esferaDeChoque = cubo3d.Meshes[0].BoundingSphere;
            //.Center utiliza el mismo vector que el del target de la cámara 
            esferaDeChoque.Center = vistaTar;
            //.Radius amplia el radio de la esfera 
            esferaDeChoque.Radius = (esferaDeChoque.Radius * 3) / 2;
            //recogemos el valor entregado por .Intersects
            Nullable<float> resultato = puntoL.Intersects(esferaDeChoque);
            //si el valor entregado por .Intersects es positivo 
            if (resultato.HasValue)
            {
                // si el Value es menor que la distancia Cambia de color
                if (resultato.Value < distancia)
                {
 
                    prueva = Color.CornflowerBlue;
                }
            }
            else
            {
                prueva = Color.DarkOliveGreen;
            }
 
 
        }
 
Analizado en 0.035 segundos ha 47.60 KB/s, GeSHi 1.0.8.2-- CFX.GHCode Programado Por Crea-Flash.com

1-5 Aquí dejo el código completo
Código : C#
 
 
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
 
namespace ClicObj
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        /// <summary>
        /// Bloque de variables a utilizar
        /// </summary>
        Model cubo3d;
        MouseState ratonEs;
        Matrix proyector;
        Matrix vista;
        Matrix mundo;
        Vector3 vistaCam;
        Vector3 vistaTar;
        Vector3 trasladar;
        Color prueva;
        float rotY;
        float rotX;
        float rotZ;
 
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
 
        }
        protected override void Initialize()
        {
            IsMouseVisible = true;
            base.Initialize();
        }
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
 
            //cagamos el modelo a presentar 
            cubo3d=Content.Load<Model>("Modelos\\cubo");
            //colocamos la carmara 
            vistaCam.Z = 200.0f;
 
        }
        protected override void UnloadContent()
        {
        }
        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            // con la variable teclado bamos ha detectar que boton del teclado se esta precionando
            KeyboardState teclado = Keyboard.GetState();
            if (teclado.IsKeyDown(Keys.W))
            {
                trasladar.Y += 1.0f;
            }else if (teclado.IsKeyDown(Keys.S))
            {
                trasladar.Y -= 1.0f;
            }
 
            if (teclado.IsKeyDown(Keys.A))
            {
                trasladar.X += 1.0f;
            }else if (teclado.IsKeyDown(Keys.D))
            {
                trasladar.X -= 1.0f;
            }
            if (teclado.IsKeyDown(Keys.Z))
            {
                trasladar.Z += 10.0f;
            }
            else if (teclado.IsKeyDown(Keys.X))
            {
                trasladar.Z -= 10.0f;
            }
            rotY -= 0.02f;
            rotX += 0.02f;
            rotZ -= 0.02f;
 
            cambiaColor();
            actualiza();
            base.Update(gameTime);
        }
        /// <summary>
        /// funcion que detecta si el mouse se atraviesa con el modelo cubo3d
        /// </summary>
        void cambiaColor()
        {
 
            ratonEs = Mouse.GetState();
            Ray puntoL = PuntoL(new Vector2(ratonEs.X, ratonEs.Y), proyector, vista, mundo);
            float distancia = 1000;
            BoundingSphere esferaDeChoque = cubo3d.Meshes[0].BoundingSphere;
            esferaDeChoque.Center = vistaTar;
            esferaDeChoque.Radius = (esferaDeChoque.Radius * 3) / 2;
            Nullable<float> resultato = puntoL.Intersects(esferaDeChoque);
            if (resultato.HasValue)
            {
                if (resultato.Value < distancia)
                {
 
                    prueva = Color.CornflowerBlue;
                }
            }
            else
            {
                prueva = Color.DarkOliveGreen;
            }
 
 
        }
        /// <summary>
        /// Función de simple para actualizar algunas variables 
        /// </summary>
        void actualiza()
        {
            proyector = Matrix.CreatePerspectiveFieldOfView(
                      MathHelper.ToRadians(45.0f),
                      graphics.GraphicsDevice.Viewport.Width / graphics.GraphicsDevice.Viewport.Height,
                      1.0f, 10000.0f);
            vista = Matrix.CreateLookAt(vistaCam, vistaTar, Vector3.Up);
            mundo = Matrix.CreateRotationY(rotY)*
                    Matrix.CreateRotationX(rotX)*
                    Matrix.CreateRotationZ(rotZ)*
                    Matrix.CreateTranslation(trasladar);
        }
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(prueva);
            MuestraModelo(cubo3d, this.proyector, this.vista, this.mundo);
            base.Draw(gameTime );
        }
 
        /// <summary>
        /// Créanos una función Ray la cual detecta un punto en el espacio 3d 
        /// el cual nos sirve de guía para saber donde esta un objeto
        /// </summary>
        Ray PuntoL(Vector2 punto, Matrix proyector, Matrix vista, Matrix mundo)
        {
            Vector3 nearsource = new Vector3((float)punto.Y, (float)punto.Y, 0f);
            Vector3 farsource = new Vector3((float)punto.X, (float)punto.Y, 1f);
            Vector3 nearPoint = graphics.GraphicsDevice.Viewport.Unproject(nearsource, proyector, vista, mundo);
            Vector3 farPoint = graphics.GraphicsDevice.Viewport.Unproject(farsource, proyector, vista, mundo);
            Vector3 direction = farPoint - nearPoint;
            direction.Normalize();
            return  new Ray(nearPoint, direction);
        }
        /// <summary>
        /// Función que sirve para la presentación de los objetos 3d en el escenario
        /// </summary>
        void MuestraModelo(Model m, Matrix proyector,Matrix vista ,Matrix mundo)
        {
            foreach (ModelMesh mesh in m.Meshes)
            {
                Matrix[] boneTransforms = new Matrix[m.Bones.Count];
                m.CopyAbsoluteBoneTransformsTo(boneTransforms);
                foreach (BasicEffect effect in mesh.Effects)
                {
 
                    effect.Projection = proyector;
                    effect.View = vista;
                    effect.World = boneTransforms[mesh.ParentBone.Index]*mundo;
 
                }
                mesh.Draw();
            }
        }
    }
}
 
Analizado en 0.081 segundos ha 78.19 KB/s, GeSHi 1.0.8.2-- CFX.GHCode Programado Por Crea-Flash.com

Última actualización el Martes, 02 de Junio de 2009 00:01
 

Articulos Relacionados XNA