Meteorit 011

Aclaracion importante sobre metodos abstract/virtual.
Usando la clase Proyectil me he dado cuenta de la diferencia entre metodos abstract y virtual.
Aqui dos formas identicas de declarar Metodo():
public abstract void Metodo(); <- Asi se escribiria si es abstracto
public virtual void Metodo() {} <- Asi se escribiria si es virtual
Por tanto abstract solo es un prototipo de la funcion, no admite implementacion {}. Pero equivale a un metodo virtual con implementacion vacia.

Aclaracion importante para el uso de sonidos.
No tuve ni que mirar en google (mas que nada xk no tenia internet), era facilisimo e intuitivo.
1 – Añadir el sonido en si (yo he usado el laser1.wav de alberto) al content.
2 – Declarar y cargar el efecto de sonido en el gestor de contenidos. SoundEffect laser = GestorContenidos.contenido.Load(«laser 1»);
3 – Reproducirlo cuando se quiera, por ejemplo en el metodo que dispara balas. void dispararBalas(){ laser.Play(); }
Esto es un SoundEffect, no es una cancion. Tambien esta la clase SoundEffectInstance, Song, SongCollection y no se si hay mas relacionadas con el audio… pero para efectos lo mas seguro es que se necesite esta, SoundEffect.

Meteorit 010

Declaracion de la plantilla de las balas (todas tienen los mismos apartados pero diferente comportamiento)

Atributos:
– Sprite bala; Sprite de la bala (habra mas si hay mas balas)
– Rectangle colision; Rectangulo de colision de la bala (habra mas si hay mas balas)

Constructores:
– Bala() Donde TIPO = {Simple, 2Diagonal, 2Trasera, 2EjeY} por ahora. Este constructor carga la imagen de la bala en su sprite y asigna las posiciones iniciales de la bala y de su rectangulo de colision.

Metodos:
– Update(int velocidad) Mueve n = velocidad pixels la bala
– Draw() Dibuja la bala en pantalla

Comportamientos:
Lo unico que variara en los distintos tipos de balas seran las posiciones iniciales y el comportamiento en update.
Simple -> Se carga en el extremo derecho de la nave, justo al medio de su altura. Su comportamiento sera rectilineo hacia la derecha.
2Diagonal -> 2 Balas que se cargan en el mismo sitio que la simple. Su comportamiento sera en diagonal 45º hacia delante, una hacia arriba y otra hacia abajo.
2Trasera -> 2 Balas que se cargan en la parte trasera de la nave, a 1/3 y 2/3 de la altura de la nave respectivamente. Su comportamiento es como la simple pero hacia la izquierda.
2EjeY -> 2 Balas que se cargan en el medio de la nave, en los extremos de arriba y abajo. Su comportamiento es rectilineo sobre el eje Y, una arriba y otra abajo.

Para usar la clase:
Lo logico es que no se quiera solo instanciar 1 bala, por eso explicare como instanciar un conjunto de balas.
Usaremos una lista de balas, mas concretamente de proyectiles. List balas = new List();
Para una prueba de todos los tipos de balas crearemos varios metodos que carguen varios tipos de balas, aqui un ejemplo de balasimple. void dispararBala(){ BalaSimple bala = new BalaSimple(); balas.Add(bala); }
El metodo lanzador de balas deberia estar ya hecho, sera un boton al ser pulsado, el cual llamara a dispararBala() y eso creara la instancia y la añadira a la lista.
Una vez añadidas las balas creamos la logica de movimiento en Update, en este ejemplo se mueven 8 pixels cada 1 segundo. if(gameTime.TotalGameTime.Seconds % 1 == 0) { for(int i = 0; i < balas.Count; i++) { if(balas[i].estoyVivo) balas[i].Update(8); else balas.Remove(balas[i]); } } Esto actualizaria la posicion de la bala si esta viva (sigue en la pantalla), en caso contrario se elimina de la lista y posteriormente el garbage collector de c# eliminaria la instancia de la bala ya que no se ha referenciado otra vez.
En el metodo Draw simplemente haremos un foreach de la lista para dibujar todas las balas. foreach(Proyectil bala in balas) bala.Draw();

Meteorit 009

Declaracion de la clase Proyectil

Atributos:
– bool estoyVivo; Cuando nace esta a true, cuando se sale de la pantalla esta a false y se elimina de la lista de balas
– const int RESOLUCION_HORIZONTAL = 800; Ancho de la pantalla del dispositivo
– const int RESOLUCION_VERTICAL = 480; Alto de la pantalla del dispositivo

Constructores:
– Proyectil() Simplemente establece a true estoyVivo

Metodos:
– abstract Update(int velocidad); Sin implementacion (porque cada subclase tendra su propio comportamiento). Mueve la bala n = velocidad pixels
– abstract Draw(); Sin implementacion. Dibuja la/s bala/s en pantalla

Puesto que la clase es abstracta no se puede usar directamente, es solo una pseudointerfaz para sus clases derivadas.

Meteorit 008

Aclaracion importante del foreach y el for:
Si en el foreach se borran elementos de ese mismo vector recorrido petara porque se altera la cantidad de elementos en el vector, es obligado usar for
Ejemplo:
foreach(Proyectil bala in balas) balas.Remove(bala) <- Peta
for(int i = 0; i < balas.Count; i++) balas.Remove(balas[i]); <- No peta

Aclaracion importante del rectangulo de colisiones:
Cada vez que movemos algo que queramos que colisione tenemos que mover tambien su rectangulo, para ello cada metodo que mueva (Update para npcs y Mover para nave) reestablecera la localizacion del rectangulo, dejando su anchura y altura igual que en la declaracion.
Ejemplo:
colision2.Location = new Point((int)bala2.Posicion.X, (int)bala2.Posicion.Y);

Aclaracion importante de la posicion de objetos:
El vector de posicion de sprite es Vector2 con X e Y float, por eso hay que castearlo a int cuando queramos dibujar en pantalla, porque no existe el pixel 1’5. Pero acordaos siempre de castear a int al final, cuando se haya calculado ya el nuevo valor de la variable, sino puede pasar lo siguiente…
Ejemplo (teniendo a=1’5, b=2):
c = (int)a*b; //Esto quedaria 1*2 => c = 2
c = (int)(a*b) //Esto quedaria (int)1’5*2 => c = 3
Esta tonteria si se hace mal podria hacer por ejemplo que si mueves algo pixel a pixel con una pendiente X veas que realmente adopte un comportamiento rectilineo…

Meteorit 007

Declaracion de la clase Background

Atributos:
– const RESOLUCION_HORIZONTAL = 800; Esto deberia ser lo tipico de precompilador #define y tal, pero c# no permite hacer esto, asi que la pongo dentro de la clase. Es la constante que recoge el ancho de la pantalla, que se supone k siempre sera 800…
– bool reproduciendo; True -> Fondo scrolleando. False -> Fondo pausado.
– int numeroFondoActual; Es un entero k va incrementandose conforme cargamos fondos, para saber cuando parar de cargar.
– string resourceName; Contiene el nombre exacto de la parte comun del nombre de los fondos que se quiere cargar. Es decir si los fondos son «Fondo1.1, Fondo1.2» esta variable sera «Fondo1.»
– int numeroFondos; Numero total de fondos a cargar.
– Sprite fondoA; Sprite que contiene el primer fondo a cargar.
– Sprite fondoB; Sprite que contiene el segundo fondo a cargar.
//Esta preparado para cargar siempre 2 fondos, pero tambien funciona si quieres scrollear solo 1 fondo, pasandole por parametro al constructor numeroFondos = 1, aunque se cargara un fondo NULL a su derecha

Constructores:
– Background(string resourceName, int numeroFondos) Pasarle por parametro la cadena k identifica a los fondos y el numero de fondos a cargar

Metodos:
– Reproducir() Pone a true el bool reproduciendo
– Pausar() Pone a false el bool reproduciendo
– DibujarImagen(Sprite fondo) Muestra en pantalla el Sprite pasado por parametro (necesita acceso a un spriteBatch, k nosotros tenemos global en la clase estatica GestorContenidos)
– Draw() Metodo draw que llama a DibujarImagen con fondoA y con fondoB
– Update(int velocidad) Logica del background scrolling, por parametro se le pasa el numero de pixels que se movera cada vez que se llame a este metodo.

Para usar la clase se creara un fondo -> Background fondo;
Luego se instanciara con los identificadores y el numero de fondos -> fondo = new Background(«Fondo1.», 6);
Y luego se llamara a update para moverlo (en este ejemplo se mueve 16 pixels cada 1 segundos) -> if(gameTime.TotalGameTime.Seconds % 1 == 0) fondo.Update(16);

PD: NO es recomendable pasar mas de 1 por parametro en la velocidad, porque si se mueve de 3 en 3 por ejemplo y el ancho de la imagen no es multipo de 3, entonces se pintara en pantalla pixels k se salen de la imagen. Lo mejor es variar los segundos k transcurren hasta volver a llamar al metodo, y llamarlo con 1, para k vaya pixel a pixel. Lo he implementado asi para hacer pruebas, aunque es totalmente funcional siempre que se usen cantidades potencia de 2 -> 1, 2, 4, 8, 16, 32, 64, etc.

Meteorit 006

Descripcion de la clase Sprite
Sprite contiene 3 atributos privados: Texture2D imagen; Vector2 Posicion; y string source;
– imagen es el contenedor de la imagen
– posicion es la posicion en coordenadas X e Y de la esquina superior izquierda del rectangulo en el que esta inscrita la imagen
– source es el nombre sin extension del resource a cargar (en caso del sprite sera una imagen)

Sprite contiene 2 constructores: Sin parametros y con 2 parametros (Vector2, string)
– El primero sirve para hacer pruebas, por si no quieres inicializar los atributos para instanciarlos luego con las propiedades
– El segundo inicializa los 3 atributos privados, la imagen se carga con el gestor de contenidos el resource pasado por el parametro string

Sprite contiene 3 Propiedades: 1 para cada atributo privado
– set y get para imagen. Setea o devuelve el contenedor Texture2D de la imagen.
– set y get para posicion. Setea o devuelve la posicion en formato Vector2 (para setear coordenadas X e Y individualmente seguir leyendo)
– set y get para source. Setea o devuelve el nombre del source string.

Sprite contiene 3 Metodos: los dos para setear las coordenadas X e Y de la posicion y el de cargar imagen en el contenedor
– setPosX(int) Establece la coordenada X de la posicion
– setPosY(int) Establece la coordenada Y de la posicion
– CargarImagen(source) Carga en el atributo imagen un resource identificado por el parametro string source

Ejemplos de uso:
/*Constructor sin parametros y coordenadas X e Y separadas
Sprite sprite = new Sprite();
sprite.setPosX(0);
sprite.setPosY(0);
sprite.Source = «nave»;
sprite.CargarImagen(sprite.Source);
*/
/*Constuctor con parametros y posicion encapsulada en Vector2
Sprite sprite = new Sprite(new Vector2(0, 0), «nave»);
*/

Asumiendo que sprite tiene acceso a un gestor de contenidos estatico, el metodo CargarImagen sera asi:
CargarImagen(string source) { imagen = GestorContenidos.contenido.Load<Texture2D>(source); }

Meteorit 005

Intentando implementar un ContentManager me doy cuenta de que no es tan facil… hay que declarar servicios y cosas que desconozco por ahora.
He probado a hacer una clase estatica global con un parametro que recoge el Content creado por defecto y funciona, asi ya es visible globalmente ^^
Se me habia ocurrido tambien usar un puntero a Content y pasarlo a la clase estatica, asi cuando se solicite alguna operacion sobre la variable de mi clase estatica se estara haciendo sobre el Content. Para usar punteros se escribe «unsafe» delante del metodo/declaracion. ContentManager no permite que punteros apunten a el… asi que idea descartada.

Implementacion completa de la clase GestorContenidos:
using Microsoft.Xna.Framework.Content;

namespace Prueba
{
static class GestorContenidos
{
public static ContentManager contenido;
public static SpriteBatch spriteBatch;
}
}
Ejemplo de uso:
GestorContenidos.contenido = Content; //Esto se hara en el metodo Initialize de game, lo que hace es pasarle el Content a nuestra clase para k sea visible en todo el namespace (lo malo es que asi tenemos dos ContentManager)
fondo1a.Imagen = GestorContenidos.contenido.Load<Texture2D>(fondo.Source); //Esto se hara desde cualquier otra clase que quiera hacer algo en ese content

Actualizacion 2/04/2011:
He añadido un atributo estatico spriteBatch a la clase, modificando ligeramente tambien Game1. Game1 corresponde a un nivel/pantalla, nos viene muy bien que en ese nivel sea global el spritebatch y el contentmanager. En el siguiente nivel se volveria a instanciar spritebatch, por tanto se borraria todo rastro del anterior y se cargaria el nuevo content de ese nivel (cambiando tambien la carpeta fisica que almacena todos los datos del nivel con el atributo contenido.RootDirectory = «Content2»;)

Meteorit 004

Vector2 posicion es una estructura con int X e int Y. Su propiedad solo permite modificar elementos de tipo Vector2, pero no deja accesible X e Y. He encontrado 3 formas de hacer propiedades:
public Vector2 Posicion { get { return posicion; } set { posicion = value; } }
public Vector2 Posicion { get; set; }
public Vector2 Posicion { get { return posicion; } set { posicion = new Vector2(value.X, value.Y); } }

La primera seria la normal, la que enseñan en los manuales y todos deben saber.
La segunda parece que es una forma abreviada. No se si hace exactamente lo de arriba pero funciona igualmente, el problema es que sale warning porque «posicion» no se ha usado.
La tercera se parece a lo que buscamos pero no es, la he visto en codigos de ejemplo pero no la he testeado, en algun contexto podria ser util.

Me decanto por hacer un metodo set para X y para Y como toda la vida. Puede resultar un poco engorroso al usarlo pero la otra solucion seria hacerlo public…
public void setPosX(int X) { posicion.X = X; }
public void setPosY(int Y) { posicion.Y = Y; }
Y ejemplo de llamada: bala.setPosX(180); en lugar de bala.Posicion.X = 180; que NO funcionaria.

Meteorit 003

Hola mundo xna

Me ha costado 1 hora o asi pero ya he conseguido un hola mundo xD, aqui detallo los pasos
1. Crear un proyecto tipo Windows Phone Game (Framework 4.0)
2. Abrir el archivo Game1.cs y añadir la libreria Microsoft.Xna.Framework.Graphics; (con el using delante en el inicio del codigo) (esto es para poder llamar a SpriteBatch)
3. Ir a WindowsPhoneGame1Content y boton derecho, Add, New Item. Seleccionar Sprite Font y Add. (Es obligatorio cargar fuentes para todo lo que hagamos, por eso cargamos la default)
4. Ir al metodo draw en Game1.cs y crear un SpriteBatch con esta linea. SpriteBatch spriteBatch = new SpriteBatch(GraphicsDevice);
5. Iniciar el SpriteBatch con spriteBatch.Begin();
6. Mostrar la string por pantalla con spriteBatch.DrawString(Content.Load(«SpriteFont1»), «Hola mundo», new Vector2(0, 0), Color.White);
7. Finalizar el SpriteBatch con spriteBatch.End();

Explicacion de los parametros de DrawString
1. Fuente. No puede ser null ni hay fuentes ya cargadas, se tienen que cargar de los resources del proyecto, por eso se usa Content.Load(nombre) para cargar esa fuente.
2. String. La string que se mostrara.
3. Posicion. Posicion en pantalla desde donde empezara el texto, yo he creado un Vector2(0, 0) que posiciona el texto en la coordenada (0,0) empezando por la esquina superior izquierda.
4. Color. He puesto color de texto blanco; al poner Color os saldra la lista de los que podeis poner.

PD: Al final no estamos usando layouts en xml, aunque la descripcion de la fuente, por ejemplo, si que es con xml; asi que es probable que se pueda portar facilmente a xbox/win.
PD2: No es lo mismo phone game que phone app, en phone app se usan los layouts y en phone game no.

Meteorit 002

Ya he acabado de leer los pdfs, estas son las cosas mas importantes que he encontrado y difieren de lo que ya sabiamos:

– convert para castings (tambien funciona (int))
Ejemplo: double angulo = Convert.ToDouble(entero); //siendo int entero;
Ejemplo: Button buttonEmisor = (Button)emisor; //siendo Object emisor;

– foreach
Ejemplo: foreach(string disco in discosLogicos) { } //siendo discosLogicos un vector de strings
Ejemplo: int[10] vector; foreach(int a in vector) { } //recorrido del vector de principio a fin sin iteradores

– setters y getters (propiedades)
Ejemplo: public string Nombre { get{return nombre;} set{nombre = value;} } //siendo string nombre; un atributo privado, explicacion de value abajo
Ejemplo: a.Nombre = «yo»; string b = a.Nombre; //ejemplos de llamadas a set y get respectivamente. «yo» seria el objeto «value» asignado en el set

– herencia con :
Ejemplo: public class MiClase : ClaseBase { } //siendo public class ClaseBase { } la superclase

– interface con :
Ejemplo: public class MiClase : Interfaz { } //siendo interface Interfaz { } una clase interface

– namespaces (package en java). Se usa para acceder si se empaqueta en un .dll
Ejemplo: namespace Proyecto1{ public class Hola { } }
Ejemplo: using Proyecto1; Proyecto1.Hola a = new Proyecto1.Hola(); //ejemplos de carga del namespace y llamada al constructor (si no se ha cargado) respectivamente

– Console.WriteLine(«{0}», parametro); para salida estandar, similar a c; tambien funciona Console.WriteLine(cadena) siendo string cadena; tambien existe Console.Write, el cual no hace salto de linea
Ejemplo: Console.WriteLine(«Me llamo {0} y soy {1}», nombre, caracteristica); //siendo {0} el primer parametro (nombre) y {1} el segundo (caracteristica)
Ejemplo: «Me llamo Cerb y soy osom» //ejemplo de ejecucion con nombre = «Cerb» y caracteristica = «osom»

– para sobreescribir metodos si a priori no se sabe k se van a redefinir -> usar «new» entre public y el tipo en la cabecera de la funcion (clase derivada)
Ejemplo: public new metodo () { } //siendo metodo() un metodo heredado que se definio normal en su clase

– si se sabe entonces -> declarar metodos como «virtual» para marcar k seran redefinidos (clase base), al sobreescribir se pondra «override», siempre entre public y el tipo en la cabecera
Ejemplo: public virtual metodo() { } //implementacion del metodo metodo() en la clase base
Ejemplo: public override metodo() { } //sobreescritura del metodo metodo() heredado de la clase base, el cual se sabia que se podia sobreescribir

– palabra reservada «base» para hacer referencia a la clase base (como el this hace referencia a la clase en uso) (equivalente a super en java)
Ejemplo: public class ClaseBase { string atrib; } //estructura de la clase base
Ejemplo: public class MiClase : ClaseBase { MiClase() { string a = base.atrib; } } //llamada al atributo atrib de la clase base

– eventos: cada componente(button, textbox, etc) tendra una propiedad para asignarle un manejador de eventos
Ejemplo: buttonAceptar.Click += new EventHandler(ButtonAceptarClick); //siendo Button buttonAceptar; se le asigna un manejador al evento click

– eventos: en la misma clase habra un metodo que maneje el evento generado
Ejemplo: static void ButtonAceptarClick(object sender, EventArgs e) { } //implementacion del evento click, puede llamarse desde varios componentes

– palabra reservada «partial» en la cabecera de la clase para implementar la clase en varios archivos, se usa para dividir diseño de componentes de la logica
Ejemplo: public partial class MiClase { MiClase() { Button a = new Button(); } } //parte que genera componentes y propiedades (como los layouts en xml)
Ejemplo: public partial class MiClase { } //parte que implementa la logica de dichos componentes y otras funciones