¿Ya te has pasado el Guitar Hero mil veces? pues ahora puedes hacerte tu propia versión con ayuda del ejemplo que Javier Cantón ha subido a XNACommunity.
Podeis descargar el archivo con el proyecto desde la web de XNACommunity.
Saludetes
Pues eso mismo, aquí os dejo la info sobre el último ejemplo que Alex Urbano ha hecho para XNACommunity.

Este
ejemplo muestra una mezcla de técnicas destinadas a pintar una escena
3D simulando que es un dibujo animado hecho a mano. Se mezclan cosas
tales como cel shading usando una textura para modular la intensidad de
la luz, siluetas mediante geometría y detección de las mismas en un
post-proceso, y una simulación de trazos a lápiz en las zonas
sombreadas.
El ejemplo lo podeis descargar desde XNACommunity en la sección de ejemplos.
Saludetes
Bueno la idea de este tutorial es aprender a crear modelos de terrenos para nuestras demos XNA con 3D Studio Max. La generación de Terrains en los videojuegos se suele hacer mediante código durante el tiempo de carga o de forma dinámica durante el juego. Uno de los últimos videojuegos comerciales que presentan un sistema de terrenos muy avanzado es BattleField Bad Company, en el cual los terrenos se modifican en tiempo de juego a causa de explosiones provocadas por las armas de los jugadores.
Sin embargo muchas veces no se necesitan sistemas de generación de terrenos tan complejos, por lo que podemos precalcular estos y añadirlos en forma de content directamente a nuestros proyectos. Y esto precisamente es lo que vamos a explicar en este tutorial.
Manos a la obra
Bueno lo primero que vamos a necesitar será una textura para nuestro terreno, está podéis crearla ustedes o buscar alguna por internet, yo para este ejemplo voy a usar esta:

Bien lo siguiente que vamos a necesitar es una textura de alturas (heightMap), es decir, una textura con tonalidades que van de blanco a negro y que luego usaremos para establecer las alturas de nuestro terreno. Los pixeles negros estarán a nivel de mar y los pixeles de color blanco serán los picos más altos de nuestro terreno. Posiblemente podáis encontrar también algunos heightMap buscando por internet, pero en mi caso voy a generarlo mediante Photoshop.
Bien nos vamos a Photoshop y creamos un nuevo fichero de dimesiones 512x512, ya que nuestro terreno será cuadrado:

Y luego pintaremos el fondo completamente de negro para que inicialmente todo esté a nivel del mar:

El siguiente paso será usar la brocha para pintar las zonas de nuestro terreno que estarán sobre el nivel del mar. Seleccionamos la herramienta y configuramos algunas propiedades para que la brocha al pintar genere degradados en los bordes y de esa forma el terreno que generemos esté suavizado.

Y por último nos ponemos a pintar las alturas, esto es a gusto del consumidor, según lo que necesitéis para vuestro proyecto. Os recomiendo para la mayoría de los casos dibujar una especie de muralla rodeando toda la imagen pero dejando un margen negro, entonces si colocamos una cámara en el centro del terreno nunca veamos el final de este, sino montañas que no nos dejan ver más allá. Yo he dibujado esto XD:

Bien ya tenemos las texturas que necesitábamos, ahora nos vamos al 3d Studio Max y lo primero que vamos a hacer es crear un plano en el centro del mundo. Para ello dentro de la pestaña Create del menú de la derecha y teniendo seleccionada Geometric podremos ver un botón en el que pone Plane.

Presinamos el botón de plane y manteniendo pulsada la tecla control para que nos salga un plano cuadrado, creamos un plano en el centro del mundo.

Para asegurarnos que está en el centro, haremos click con el botón derecho del ratón sobre el botón mover del toolbar superior y en la ventana que nos aparecerá colocaremos todas las coordenadas a 0.

Ahora nos vamos a la pestaña modify y en un cuadro blanco de debajo aparecerá solo plane. Bien más abajo están las propiedades de creación de este plano, las cuales vamos a modificar para darle mayor número de vértices de forma que luego el terreno tenga un aspecto más suavizado. Para ello modificaremos los parámetros length segs y width segs, yo les voy a poner 40 a cada uno pero este valor difiere según el tamaño del terrain y del suavizado que necesitéis, lo óptimo sería tener un vértice para cada pixel de la textura del heigthMap.

Lo siguiente será irnos a la lista de modificadores y añadirle uno a nuestro plano llamado Displace:

Luego en sus propiedades nos iremos a Map y le aplicaremos el heigthMap que hemos generado con el photoshop.


Y por último para apreciar las alturas de nuestro heightMap sobre el plano le indicaremos mediante el parámetro Strength cuál será la altura de aquellos pixeles que esté en blanco:

Bien ya tenemos nuestro terreno generado, solo falta aplicarle la textura. Para ello abrimos el editor de materiales ( la forma más fácil es presionando la tecla ‘M’). Sobre cualquier material por defecto seleccionamos en la pestaña Maps, y le añadimos una textura al canal diffuse.



Y para aplicar la textura al plano realizamos los siguientes pasos que se muestran en la imagen (debemos tener el plano seleccionado).

Ok, pues aquí termina este tutorial, lo único que nos faltaría sería exportar ya dicho modelo en fbx o en el formato que se quiera.
Created by Javier Cantón Ferrero.
Saludetes
Hola a tod@s, tenemos un nuevo artículo en XNACommunity, en esta ocasión va sobre inteligencia artificial en los videojuegos, se la ha currado Marc García. Podeis también bajaros el código y leerlo en XNACommunity.
Primeros pasos en Inteligencia Artificial:
Modelos de comportamiento usando máquinas de estados
En el mundo de los videojuegos, está muy bien que los enemigos parezca que piensen y actúen en consecuencia a nuestros actos.
Básicamente si no lo hicieran, luchar contra un enemigo o contra una palmera no tendría diferencia alguna (los cocos, quizás).
En este artículo pretendo explicar qué hace decidir a un enemigo actuar de una manera o de otra, y poner un ejemplo práctico.
Mi intención es, que alguien que no sepa nada del tema, después de leer el artículo pueda jugar a un juego y entender porqué ese enemigo viene corriendo hacia mí cuando claramente tengo un bazooka en la mano.
CONTENIDO
- Máquinas de Estados
- Montando el tinglado
- Conclusiones
- Ejemplo
Máquinas de Estados
Me referiré a ellas como autómatas. Hay de muchos tipos, de estados finitos, infinitos, con transiciones lambda/epsilon etc. etc.
La mejor manera de explicar su funcionamiento es con el siguiente diagrama:

Los autómatas cuentan con términos propios (lenguaje, palabra, estado, ...), pero como eso es más complicado, vamos a lo básico.
Simplificando: empezamos en un estado, y cuando se cumple una condición, saltamos a otro estado.
Tanto las condiciones como los estados pueden ser abstracciones de cosas más complejas. De hecho, hasta pueden ser tratados como otros autómatas aparte.

Esto nos puede ayudar a ser organizados y no acabar con tiras y tiras y tiras de papel/hojas de <mi procesador de texto>. Ya sabéis, divide y vencerás.
Sabiendo eso, se puede hacer un esquema parecido al siguiente...

... en el que dejamos externa la parte de inicio/fin. Si además lo llamamos, por ejemplo, 'soldado'... pues supongo que ya se empieza a ver por dónde van los tiros.
Y hasta aquí la parte teórica, que no quiere decir ni por asomo que no exista nada más que explicar (je). Simplemente he contado lo básico que creo que es necesario para entenderlo.
De todos modos, si alguien siente curiosidad, wikipedia es tu amiga ->
http://en.wikipedia.org/wiki/Automata_theory http://en.wikipedia.org/wiki/Finite_state_machine Pasemos al ejemplo práctico
Montando el tinglado
Para nuestro ejemplo contamos con un par de modelos, a los que asignaremos diferentes comportamientos.
Ya que el comportamiento puede variar, creamos una clase base, de la que heredarán el resto.
public class CBehaviourModel
{
public CBehaviourModel() { }
public virtual void Update(GameTime gameTime, ref Vector3 position, ref Vector3 direction, ref Vector3 rotation) { }
}
El método importante es el
Update (bueno, estando sólo el constructor y un método tampoco queda mucho más).
Como alguno de los comportamientos modificará la posición, etc. de su modelo, lo pasamos por referencia en el
Update.
Teniendo ya la clase base, podemos crear el resto.
El planning es que uno de los modelos estará en modo patrulla, y el otro estará buscándolo. Cuando lo vea, lo seguirá.
Hacemos 3 clases entonces:
CPatroller,
CStraightSearcher y
CFollower.
Además, hacemos una cuarta
CStandStiller, que no hace nada. Realmente es como la clase base, pero con el nombre adecuado a lo que hace, quedarse quieto.
Para las explicaciones me centraré en los métodos "importantes", básicamente los
Update. Ya que en los métodos
Draw,
Load, etc. no hay nada excesivamente raro, no los comentaré.
Patrullar
Se trata de una clase muy simple.
Contiene un array de
N posiciones, que le indican la ruta a seguir. El punto
N conecta con el primero, de manera que hace un recorrido cerrado.
En el Update, va guardando el tiempo pasado entre frame y frame (
cumul_time) para determinar la distancia que avanza.
Hace un Lerp entre 2 vectores: pilla vector1, pilla vector2, y con un factor alpha [0..1] devuelve un nuevo vector. Si alpha = 0.5f, devuelve el vector medio entre v1 y v2. Como va de 0 a 1, usamos el tiempo para determinar alpha.
Una vez llegado al destino (
cumul_time = 1), se avanzan los corners (si es el final se vuelve al principio).
public override void Update(GameTime gameTime, ref Vector3 position, ref Vector3 direction, ref Vector3 rotation)
{
// update time: takes X seconds to go from corner to corner
cumul_time += (float)gameTime.ElapsedGameTime.TotalSeconds / corner_to_corner_time;
if (cumul_time > 1f) // reached max?
{
cumul_time = 0f;
// Change corners
++actual_corner;
rotation.Y -= 90f;
if (actual_corner >= corner_points.Length)
{
actual_corner = 0;
rotation.Y = 0f;
}
}
// patrolling
int next_corner = actual_corner + 1;
if (next_corner >= corner_points.Length)
next_corner = 0;
Vector3 from = corner_points[actual_corner];
Vector3 to = corner_points[next_corner];
position = Vector3.Lerp(from, to, cumul_time);
}
Apunte: siempre suelo decir que a la hora de calcular cualquier cosa en videojuegos hay que tener en cuenta tanto los números como los gráficos.
Es decir, que hay que cuadrar los valores de los elementos con los de las meshes que se van a pintar.
Por eso cuando se cambia de esquina se actualiza la rotación del modelo. Si no, iría pululando por el escenario sin más (ver el caso de
CFollower).
Buscar
Esta clase está hecha a modo de alarma típica de láser infrarrojo. Tenemos el modelo quieto, que "emite" un rayo; si alguien cruza ese rayo se cambia de comportamiento a
CFollower.
Para simular el rayo usaremos dos planos. El segundo se usa para limitar la "altura" del primero, ya que un plano es infinito y por tanto cualquier cosa que estuviera por detrás del modelo se detectaría también.
Aunque no se vea, en la escena tenemos

las rayas de colores son los dos planos.
En el
Update se hace la comprobación que el objeto esté por delante del plano rojo, y que intersecte con el plano amarillo.
public bool Intersects(BoundingSphere sphere)
{
intersection_front = false;
intersection_straight = false;
// check0: front of plane
if (Front.Intersects(sphere) != PlaneIntersectionType.Front)
{
return false;
}
intersection_front = true;
// check1: straight plane
if (Straight.Intersects(sphere) == PlaneIntersectionType.Intersecting)
{
intersection_straight = true;
}
return (intersection_front && intersection_straight);
}
Seguir
Finalmente, esta clase se encarga de seguir una posición con una distancia de seguridad (para no montar un modelo con otro).
Cada
Update se ha de actualizar la posición a seguir, por lo que se hace desde el
Update del juego principal.
if (dino.Behaviour is CFollower)
{
((CFollower)dino.Behaviour).TargetPosition = sword.Position;
}
dino.Update(gameTime);
sword.Update(gameTime);
y en el update correspondiente, se calcula la nueva posición
public override void Update(GameTime gameTime, ref Vector3 position, ref Vector3 direction, ref Vector3 rotation)
{
Vector3 dir = target_position - position;
dir = dir - dir / 10; // security distance = 1/10;
position += dir * (float)gameTime.ElapsedGameTime.TotalSeconds;
dir.Normalize();
direction = dir;
}
En este modelo no se actualiza la rotación del modelo, por lo que se ve "mal" cuando se mueve. Este es el ejemplo que comentaba en la clase
CPatroller.
Conclusiones
Con todo lo anterior se puede conseguir lo que se ve en el ejemplo, que es muy básico.
Con algo más de complejidad, se podría hacer, por ejemplo, que si un elemento se escapa a más de una distancia X, el otro elemento cambia a CSearcher.
También CStraightSearcher se podría convertir en CSearcher, haciendo no sólo una línea recta, si no que vaya rotando en un arco para ampliar la búsqueda, añadir un cono de visión, etc.
Los controles básicos son WASDZX + mouse para la cámara, espacio para iniciar el comportamiento de patrulla, R para resetear y ESC para salir.
Finalmente, espero que este artículo haya ayudado a alguien a entender, o entender mejor, como funcionan algunas de las Inteligencias Artificiales en los videojuegos.
Hay que tener en cuenta que las máquinas de estados se usaban hace mil millones de años, y que los juegos next-gen usan algoritmos muchos más complejos.
Pero bueno, que de algún lado ha venido todo.
Lo dicho, que espero que haya sido útil.
Saludetes
Tenemos nuevos recursos en esta nuestra comunidad de XNA.
Concretamente es un componente de menú para añadir a nuestros videojuegos y además un artículo en el que se explica como se ha hecho.
Por poner algo más el autor es César Reneses que por una vez se ha dejado la vaguería en el cajón y se ha puesto a escribir 
La dirección del componente es esta, y la dirección del artículo aquí.
Saludetes
Pues eso, que Alex Urbano ha actualizado su componente que permite añadir un skydome con efecto de atmospheric scattering y transición día/noche. En esta actualización se han añadido sencillas nubes generadas con Perlin Noise en la GPU.
El enlace aquí
Saludetes
Ya tenemos un nuevo tutorial en XNACommunity gentileza de Javier Cantón
.
En
este tutorial aprenderemos a crear aplicaciones Windows Forms que usen
XNA a las que podríamos catalogar como aplicaciones “híbridas”. Este
tipo de aplicaciones se están volviendo cada vez más y más común en el
mundo de la informática.
Empezaremos comentando que el framework de
XNA no viene preparado para que se pueda usar junto con Windows Forms,
ya que el graphicsDeviceManager que es el que se encarga de crear la
ventana sobre la que pinta XNA y de inicializar el device no nos
permite especificar el handle de la superficie sobre la que queremos
pintar. Tenemos la opción inicializar nosotros a mano nuestro device,
pero estaríamos perdiendo gran parte de la funcionalidad que nos aporta
el graphicsDeviceManager, como puede ser el ContentManager. En la
página de ejemplos de Microsoft http://creators.xna.com podemos
encontrar dos ejemplos en los que utilizan Windows Forms junto con XNA.
En el primero llamado WindowsForms Series 1: Graphics Device podemos
aprender a crear el device a mano y a poder usarlo para pintar un
triangulo:

El
problema que nos encontramos con este ejemplo es que hemos perdido con
ContentManager (no podemos cargar contenido como texturas, modelos,
sonidos, etc usando los contentloaders de XNA) y por lo tanto tenemos
que crear ese triangulo a mano. Esto nos llevaría a desaprovechar gran
parte del Framework de XNA. Sin embargo en el siguiente ejemplo
WinForms Serie 2: Content Loading que proponen en dicha web podemos ver
como cargan un FBX con textura:

Y
si nos vemos el código de dicho ejemplo es mucho más extenso que el del
anterior ya que han creado se crean sus propias clases encargadas de
hacer unos de ContentBuilder. ¿Y esto en qué consiste?, pues en coger
todos los ficheros de content que hay en nuestro proyecto, usar el
loader adecuado para compilarlo y generar los ficheros xnb en el
directorio de trabajo de nuestra solución.
Personalmente tras
ver estas dos propuestas no me convenció ninguna de las dos, ya que en
la primera desperdicias el framework y para eso usas directamente
DirectX, y en la segunda en la implementación que haces uso del
ContentBuilder me parece muy engorroso. Tras investigar un poco
encontré una solución parcialmente buena, su principal característica
es que es bastante sencilla de implementar y puedes seguir usando el
ContentManager por defecto.
Pongámonos manos a la obra para
explicar cómo sería este nuevo método, bien lo primero que tenemos que
hacer es crear un nuevo proyecto XNA, el cual si lo ejecutamos pues ya
nos creará una ventana en donde pintará con XNA. Pero nosotros no
queremos pintar en esa ventana, nosotros queremos crear por ejemplo un
editor en donde lo que necesitamos es que XNA pinte sobre un panel de
nuestra ventana. Por ello lo primero que vamos a hacer es añadir un
formulario a nuestra solución y como una imagen vale más que mil
palabras:


Y
ahora le añadiremos el aspecto de un pequeño editor con un menuStrip,
un propertyGrid a la izq y un panel a la derecha separados por un
splitter para luego poder redimensionar el espacio, todo esto quedaría
de la siguiente forma:

Una
vez que tenemos esto ahora tenemos que hacer que XNA pinte sobre
nuestro panel. Para ello primero nos dirigiremos al código de nuestro
formulario y le añadiremos la siguiente propiedad:
public Control Panel
{
get { return splitContainer.Panel; }
}
Después de hacer esto lo único que nos hace falta saber
es que existe una forma de cambiar el handle de la superficie sobre la
que pinta el device de XNA, y esta es:
GraphicsDeviceInformation.PresentationParameters.DeviceWindowHandle
Propiedad que intersectaremos justo cuando la cuando el
Graphics esté preparando los parámetros para crear el device. Los
cambios que vamos a realizar a continuación serán sobre el fichero
program.cs y sobre el game.cs.
Empecemos por el program:
static class Program
{
static Game1 game;
[STAThread]
static void Main(string[] args)
{
Main form = new Main();
form.Disposed += new EventHandler(form_Disposed);
using (game = new Game1(form))
{
form.Show();
form.TopMost = true;
game.Run();
}
}
static void form_Disposed(object sender, EventArgs e)
{
game.Exit();
}
}
Como se puede ver hemos creado una variable static de
tipo Game1, y luego dentro del Main hemos inicializado nuestro
formulario. Hemos suscrito un método al enveto Disposed de nuestro
formulario ya que vamos a dejar que Game lleve el thread de nuestra
aplicación mediante el Game.Run () y por lo tanto tendremos que
avisarle de que queremos salir de esta cuando el usuario cierre el
formulario.
Luego hemos creado una instancia de nuestra clase
Game1 a la que como véis se le pasa el formulario como parámetro, hemos
mostrado el formulario, activado la opción TopMost de este y llamado a
Game.Run(). La pregunta que todos os podréis hacer aquí es porque hemos
activado la opción TopMost, vayamos a explicar esto antes de continuar.
El graphicsDeviceManager creará una ventana por defecto al arrancar
pero no es esta sobre la que queremos que pinte pero sin embargo dicha
ventana se creará y podrán verse las dos ventanas abiertas en nuestra
pantalla, para disimular esto vamos a hacer un pequeño truco que
consistirá en decirle a nuestro formulario que se cree en pantalla por
encima de todas las ventanas de forma que la ventana por defecto
quedará escondida detrás de la nuestra, en ese momento ya le habremos
cambiado a XNA el handle sobre el que debe pintar y por lo tanto
pintará sobre el panel de nuestro formulario. Y como no existe forma de
decirle a el graphicsDeviceManager que no cree su ventana por defecto
pues una vez que esta reciba el foco del sistema la pondremos invisible
mediante mediante la propiedad Visible y restauraremos la propiedad
TopMost de nuestro formulario a false.
Si no hacéis este
pequeño truco se notará un pequeño parpadeo al arrancar la aplicación
que consistirá en la ventana de XNA que se crea y desaparece
rápidamente, por este motivo cuando hable de esta solución la califiqué
como parcialmente buena pero es la única pega.
Bueno pues una
vez que lo tenemos todo claro solo queda escribir código en Game. Para
empezar necesitamos un atributo del tipo de nuestro formulario, que
inicializaremos en nuestro constructor:
Main form;
public Game1(Main form)
{
this.form = form;
Una vez que tenemos esto tenemos que realizar tres tareas importantes:
- Cambiar el handle sobre el que pintará XNA.
- Cuando la ventana por defecto reciba el foco hacerla invisible y cambiar la propiedad TopMost de nuestro formulario.
-
Y adaptar el device y el aspectRatio de la cámara cada vez que el
tamaño del panel del formulario cambia, para no perder las proporciones.
Cambiar el handle sobre el que pintará XNA
La constructor de Game la añadimos la siguiente línea para suscribirnos al evento de preparación de parámetros del device:
graphics.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(graphics_PreparingDeviceSettings);
Luego dentro del método cambiamos el handle sobre el que el device pintará:
void graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
{
e.GraphicsDeviceInformation.PresentationParameters.DeviceWindowHandle = form.Panel.Handle;
}
Cuando la ventana por defecto reciba el foco hacerla invisible y cambiar la propiedad TopMost de nuestro formulario
En el constructor escribiremos lo siguiente para obtener el puntero a la ventana que XNA crea por defecto:
Form xnaWindow = (Form)Control.FromHandle((this.Window.Handle));
Y después nos suscribiremos al método GotFocus un
método que se encargará de poner la ventana invisible y de volver a
cambiar la propidad TopMost de nuestro formulario:
xnaWindow.GotFocus += new EventHandler(xnaWindow_GotFocus);
void xnaWindow_GotFocus(object sender, EventArgs e)
{
((Form)sender).Visible = false;
form.TopMost = false;
}
Y adaptar el device y el aspectRatio de la cámara
cada vez que el tamaño del panel del formulario cambia, para no perder
las proporciones
En el constructor añadimos también la
suscripción al evento Resize del panel, para después cambiar las
propiedades de tamaño del device y las del aspectRatio de la cámara:
form.Panel.Resize += new EventHandler(Panel_Resize);
void Panel_Resize(object sender, EventArgs e)
{
graphics.PreferredBackBufferWidth = form.Panel.Width;
graphics.PreferredBackBufferHeight = form.Panel.Height;
aspectRatio = (float)form.Panel.Width / form.Panel.Height;
graphics.ApplyChanges();
}
Bien pues ya está todo implementado para hacer uso de
XNA y su ContentManager para crear aplicaciones hibridas junto con
Windows Forms, aquí os dejo un pequeño ejemplo en donde se pone en
práctica todo lo explicado.

El código de ejemplo lo podeis descargar de aquí.
Saludetes 
Aquí tenemos un nuevo componente que permite añadir en tu juego un skydome
con efecto de atmospheric scattering y transición día/noche.
Verdaderamente esta muy trabajado y lo mejor que podéis hacer es bajarlo y
probarlo, Aunque como siempre aquí tenéis unas capturas y un vídeo:
Pulsa aquí para ver el video.
El componente está hecho por Alex Urbano y podéis encontrar aquí.
Saludetes
Bueno la idea de escribir este artículo surgió del foro de XNACommunity, donde se preguntó cómo se podría hacer en XNA una situación parecida a la de las luchas que aparecen en Blue Dragon, donde aparecen los luchadores y a la izquierda una pequeña pantalla que enfoca en primer plano a alguno de estos. Aquí podéis ver una imagen en donde veréis mejor a que me refiero:
Manos a la obra
Bien lo primero será tener claro que es lo que queremos hacer, simplemente haremos dos renders de la escena, uno desde una posición cercana a alguno de los luchadores y otra desde un punto de vista más global. Por lo que necesitaremos dos cámaras y dos superficies sobre las que pintar, empezaremos hablando sobre las superficies.
Sobre un renderTarget pintaremos la imagen desde cámara zoom, que será la que recoja un primer plano de alguno de los luchadores, para ello nos creamos un atributo de tipo RenderTarget:
RenderTarget2D RT;
Inicializamos el renderTarget dentro de método Initialize, con unos parámetros habituales y con un tamaño de 512 pixeles.
protected override void Initialize()
{
base.Initialize();
RT = new RenderTarget2D(GraphicsDevice, 512, 512, 1, SurfaceFormat.Color);
}Ahora para la otra superficie usaremos directamente el target buffer, por lo que no hace falta nada más.
Ahora necesitamos crear dos cámaras que capten la escena desde cada uno de los puntos de vista que queremos. Para ello crearemos una clase camera dentro de un nuevo fichero camera.cs, este será una cámara muy simple con unos atributos habituales. Para más información mirar directamente el fichero en el ejemplo, nosotros ahora solo le echaremos un vistazo al constructor para conocer sus parámetros:
public Camera(Vector3 position, Vector3 lookat, float nearPlane, float farPlane, float aspectRatio, float fieldOfView)
Bien una vez que tenemos esto ya podemos crear las dos cámaras que necesitábamos, e inicializarlas con los parámetros correctos:
Camera camera;
Camera cameraZoom;
protected override void Initialize()
{
base.Initialize();
RT = new RenderTarget2D(GraphicsDevice, 512, 512, 1, SurfaceFormat.Color);
camera = new Camera(new Vector3(0, 20, 50), Vector3.Zero, 1, 10000,
GraphicsDevice.Viewport.Width / GraphicsDevice.Viewport.Height, MathHelper.PiOver4);
cameraZoom = new Camera(new Vector3(0, 10, 1), new Vector3(5, 10, 0), 1, 10000, 1, MathHelper.PiOver4);
}Ok, el siguiente paso será usar la cámara normal para renderizar la escena:
protected override void Draw(GameTime gameTime)
{
RenderScene();
base.Draw(gameTime);
}
private void RenderScene()
{
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1, 0);
DrawTerrain(camera);
DrawMD3();
DrawText();
}
El resultado de nuestra escena en estos momentos es:
Bien el siguiente paso será renderizar sobre el rendertarget la escena desde el punto de vista de camerazoom. Para ello crearemos un método llamado DrawCameraZoom, que se encargará de hacer esto:
protected override void Draw(GameTime gameTime)
{
DrawCameraZoom();
RenderScene();
base.Draw(gameTime);
}
private void DrawCameraZoom()
{
GraphicsDevice.SetRenderTarget(0, RT);
GraphicsDevice.Clear(Color.CornflowerBlue);
DrawTerrain(cameraZoom);
models[0].render(GraphicsDevice,
getLocalWorld(new Vector3(40, 70, 0), new Vector3(-MathHelper.PiOver2, -MathHelper.PiOver2, 0), 0.1f),
cameraZoom.View,
cameraZoom.Projection);
GraphicsDevice.SetRenderTarget(0, null);
}
Como se puede ver en el código, lo primero que hacemos es configurar el GraphicsDevice para que renderize sobre nuestro renderTarget, después limpiamos la escena y renderizamos esta. Como solo va a aparecer un modelo en pantalla será este el único que dibujemos y por último configuramos otra vez el device para que pinte sobre el target por defecto.
Bien en este momento ya tenemos dentro de RT.GetTexture() almacenada la siguiente imagen:
Que es precisamente con la que vamos a texturizar el plano que vamos a colocar en la escena con forma de pantalla. Por lo que añadiremos un nuevo método DrawPlane() al método RenderScene():
private void RenderScene()
{
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1, 0);
DrawPlane();
DrawTerrain(camera);
DrawMD3();
DrawText();
}En este método renderizaremos el plano y utilizando basicEffect le aplicaremos la textura de nuestro renderTarget:
private void DrawPlane()
{
foreach (ModelMesh mesh in plane.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.Texture = RT.GetTexture();
effect.TextureEnabled = true;
effect.World = getLocalWorld(new Vector3(-100, 140, 50), new Vector3(MathHelper.PiOver2, MathHelper.Pi / 2.5f, 0), 0.12f);
effect.View = camera.View;
effect.Projection = camera.Projection;
}
mesh.Draw();
}
}
Ahora ya tenemos la escena terminada:
En el juego BlueDragon esta pantalla aparece y desaparece durante las luchas, pero eso ya lo dejo en vuestras manos XD. Espero que os haya ayudado este artículo y el ejemplo en donde se aplica todo lo explicado.
Bueno, todo este artículo y el código correspondiente lo podéis encontrar en XNACommunity. Todo gentileza de Javier Cantón.
Saludetes
Este ejemplo muestra un efecto de metaballs (también conocidas como blobs o isosuperficies) generado como un postproceso. Se pierde algo de sensación de tridimiensionalidad, pero el efecto es muy rápido.
By Alex Urbano, lo podeis encontrar todo aquí
Saludetes
Este artículo me propuse hacerlo debido a que mucha gente me preguntaba cómo hacer algunos tipos de cámara muy usados, entre ellos una cámara en 3ª persona y una cámara típica de un juego de lucha.
Con este artículo aprenderás a crear estos dos tipos de cámara:
Cámara 3ª Persona
Lo primero es saber a qué tipo de cámara me refiero, con esta cámara nos referimos a la típica cámara de un juego de vehículos (Need For Speed) o juegos en los que puedes ver la espalda del protagonista (Tomb Raider).
Vamos a explicar ahora teóricamente como se ha hecho. Lo primero es tener la posición de tu personaje y hacia dónde está mirando. Esta información la podéis sacar directamente de la matriz LocalWorld de dicho modelo.
Vector3 position = new Vector3(localWorld.M41, localWorld.M42, localWorld.M43);
Vector3 lookAt = new Vector3(localWorld.M31, localWorld.M32, localWorld.M33);
Con estos datos podríamos calcular un punto que se encuentra detrás del modelo, ya que podríamos restarle a la posición el vector lookAt normalizado y multiplicado por un valor. Para normalizar un vector tenemos el método Vector3.Normalize.

Pero existe una forma más rápida de hacer esto mediante el método Vector3.TransformNormal, en la que sólo tenemos que configurarnos un vector con el offset que le queremos aplicar a la posición y nos devolverá el vector que restado a la posición del modelo será la posición deseada detrás del modelo.
Vector3 offsetPlayer1 = new Vector3(0, -5, 20);
offsetPlayer1 = Vector3.TransformNormal(offsetPlayer1, player1.localWorld);
Vector3 pivotPlayer1 = player1.position - offsetPlayer1;
Con esto ya tendríamos la posición en la que debe estar la cámara, y como lookAt a la cámara le pasaríamos la dirección del modelo, por ejemplo. ¿Cuál es el problema que tiene esto tal y como está? Que los movimientos de cámara serían muy “rígidos” y nosotros queremos que parezca que la cámara y nuestro protagonista no están “anclados” uno al otro. Para ello vamos a añadir una simple interpolación entre la posición actual de la cámara y la posición en la que debería estar. De esta forma la cámara se moverá con suavidad e irá adquiriendo poco a poco la posición en la que debe estar.
Position -= (Position - pivotPlayer1) / 10;
View = Matrix.CreateLookAt(Position, player1.position, Vector3.Up);

Como se puede ver hemos dividido la distancia entre el pivot que sería donde debería estar la cámara y la posición del modelo entre 10, y lo que hacemos es avanzar la posición de la cámara hacia la del pivot una décima parte de la distancia que hay actualmente. Esto provocará un efecto muy curioso ya que si esta distancia es grande la décima parte será grande, y conforme la distancia va disminuyendo la décima parte también. Con ello conseguimos una sensación de aceleración y desaceleración en los movimientos de nuestra cámara.
Cámara lucha
Veamos ahora como haríamos para crear una cámara de un juego de lucha. Este tipo de cámaras tipo Tekken o budokay se caracterizan porque los dos jugadores siempre aparecen en pantalla por lo que la cámara se acerca y aleja dependiendo de la distancia entre los jugadores.
¿Cómo podemos hacer esto? Lo primero será calcular hacia dónde debe mirar la cámara, que debe ser el punto medio entre los dos modelos. ¿Cómo podemos calcular el punto medio entre dos modelos en el espacio? . Pues es tan fácil como sumar los vectores de posición de los modelos y dividir el resultado entre 2.
Vector3 middle = (player1.position + player2.position) / 2;

Para el cálculo de la posición de la cámara tendremos que calcular el plano en el que se encuentran los dos modelos y luego colocaremos la cámara siguiendo la normal a dicho plano.
Bien, lo primero será calcula el vector que va desde un player:
Vector3 playersVector = player1.position - player2.position;
Después calcularemos el producto vectorial entre este vector y el Vector3.Up para calcular el vector normal al plano formado por estos dos vectores:
Vector3 normal = Vector3.Cross(playersVector, Vector3.Up);
normal = Vector3.Normalize(normal);
Y por último sólo queda calcular un factor que multiplicaremos por dicha normal según la distancia a la que se encuentren nuestros jugadores:
float offsetFactor = playersVector.Length() + 50;
Position = middle - (normal * offsetFactor);

Y ya tenemos todo lo necesario para actualizar la matriz View de nuestra cámara:
View = Matrix.CreateLookAt(Position, middle, Vector3.Up);
Podéis descargar el código para probar todo esto desde aquí y también tenéis un pequeño vídeo que demuestra lo explicado anteriormente.
By Javier Cantón Ferrero.
Esta demo muestra la técnica mostrada en un artículo del libro ShaderX5 para animar vegetación de forma sencilla en la GPU. El resultado no es físicamente realista, pero da una sensación de realismo suficiente para muchas aplicaciones.
Por otro lado, se permite hacer uso de hardware instancing para renderizar gran cantidad de hierba de forma óptima.
El hardware instancing es básicamente hacer que la GPU trabaje en vez de que lo haga la CPU.
Un pequeño vídeo que demuestra el efecto:
Todo esto cortesía de Alex Urbano que se está portando con nosotros este veranito.
Saludetes
Hola a todos!! XNACommunity no cierra por vacaciones y va avanzando y creando nuevos contenidos.
Se acaba de inaugurar una nueva sección donde podremos encontrar contenidos para el Zune con XNA 3.0.
Así que ya sabéis a animarse que no es nada complicado, para empezar hay subido un ejemplo realizado en un taller durante el GameLab. El código es muy sencillo y aprenderéis cosas como:crear GameStates, añadir música, creación de menú, manejo de un personaje animado, scroll 2D sobre el fondo y algúnas cosillas más.
Saludetes 
Rubén López ha actualizado la herramienta que permite añadir modelos de Quake 3 a nuestros proyectos.
Ahora a parte de cargar este tipo de modelos nos trae soporte para cajas contenedoras, tag del arma soportado y niveles de detalle.

El que quiera modelos en este formato puede pasarse por panebianco3d.com en donde podéis encontrar varios modelos libres para descarga.
Como siempre esta utilidad la podéis encontrar en XNACommunity.
Saludetes
Menudo ejemplo más chulo que se ha currado Alex Urbano en XNACommunity. Lo podemos encontrar en la sección de ejemplos de XNACommunity.
Podemos ver como se podría implementar una simulación de fluidos en 2D. Si queréis una explicación en profundidad podéis pasaros por cowboyprogramming donde Mick West explica como conseguir este efecto de fluido.
El vídeo y la fotejo que nunca nos falten 
Saludetes 