Actualizado el 03/10/04 a las 19:49.
Proyecto en VC# Express 2005 BetaCitarHerramientas GRATUITAS necesarias para utilizar el motor:
Enlace a VStudio Express
DirectX9 SDK Summer Update 2004
CitarUltimos cambios:
Exportador de MAX.
Se ha simulado los submateriales hasta que se resuelva el ¿bug?
CitarActualmente incluye las siguientes clases:
Creación Device
Fuentes
Texturas
Render
Camara
Mallas
Meshes
Importación de archivos .X
Importación de archivos .haddd + Exportador MAX
Apariencia
Carga XML
Effects
Escena
El motor es capaz de renderizar objetos importados en .X con sus propios efectos.
CitarSiguiente Paso:
Iluminación
CitarSe necesita:
Implementar el selector de resoluciones de vídeo, formato del buffer y demás que aparecen en los ejemplos del SDK.
Mejorar el diseño de las clases.
Paralelamente:
Terrenos
Lighmaps
Colisiones
Física
Exportadores
....
Venga, hay para todos. ¡A ver si os animais!
[Voy a parecer el profesor cabrón o algo así a este paso :P ]
Me ha gustado que uses regiones para agrupar código relacionado
/// <summary>
/// Definimos las variables de acceso a las clases contenidas
/// </summary>
public CInicializar Inicializar;
public CRender Render;
public CFuentes Fuentes;
public CTexturas Texturas;
El comentario ese es comentario de documentación, al generar la documentación (y en el Intellisense (ole) )te saldrá como descripción general de la variable Inicializar O_O, los comentarios que pertenecen al código, no a la documentación que sean comentarios "clásicos": //... o /*....*/
No uses variables miembro ("atributos" en POO clásica) públicos. Si lo necesitas publicar al exterior crea una propiedad, si es para uso interno tampoco, claro está.
Nomenclatura Standard C#:
Clases sin prefijo C. Sólo usar prefijo en interfaces I: Render en vez de CRender por ejemplo.
camelCasing en variables, tanto de clase como parámetros, PascalCasing para Clases y Métodos.
~Video()
{
Console.WriteLine("video");
}
Supongo que el mensaje por Consola es de coña, pero..... :
En código manejado, los destructores sólo se usan en una clase que tiene recursos no manejados, y para liberarlos. Los objetos de clases con destructores se gestionan aparte por el recolector y son más costosos. Deberías usar el diseño de implementar IDisposable y... busca en la ayuda del SDK, en index "destructors, and resources"
float zDepth = 1;
1-->int
1.0-->double
1.0f-->float
(juraría yo :lol: )
/// <summary>
/// Limpia el viewport
/// </summary>
/// <returns>Siempre devuelve true</returns>
public bool Clear()
{
video.Device().Clear(clearFlags, color, zDepth, stencil);
return true;
}
No le veo mucho sentido que un método, que no es virtual, devuelva siempre un valor que no indica nada
public Device Device()
{
return Inicializar.device;
}
Property, plz
El diseño de las clases anidadas, aparte de que mucho mejor una clase por fichero.cs, no lo entiendo. Si quieres agrupar a nivel lógico Inicializar, Render y Video, porqué no un namespace dentro de Hadd?
Lo de CTimer dentro de la clase Entorno es más de lo mismo.
En el diseño yo añadiría varios Manager Singleton para cosas mantener el Device, que supongo que sólo tendrás uno creado y vas guardando referencias en mil sitios, un manager de Texturas para no repetirlas, ordenarlas a la hora de renderizar....
La clase Textura que contiene una referencia a una lista de texturas para poder saber su extensión... :blink:
....
A mi juicio codificas muy rápido pero no diseñas mucho, no es que yo sea Sweeney(me llama más la atención que Carmack :P ), pero mi estilo es más bien al contrario, piénsalo bien antes y aprende del diseño de otros motores como Ogre, Axiom, Purple#...
PD: Ya tienes deberes para un tiempo ;)
Tengo que usar CRender porque quiero que la variable se llame Render. Como ves, las variables dentro de Video, son para encapsular otras clases, y quería que se notara más que variables son subclases.
En realidad la ventaja de esto es que tengo un objeto que se llama video donde se aglutina toda la información. Pero lo que creo que haré será crer una instacia llamado Haddd que tenga todos las clases:
Haddd motor;
Y tendré:
motor.Video
motor.Render
motor.Texturas
¿qué os parece esta nueva visión?
Respecto a lo de Device, tienes razón, no había caido que ser una Property es mucho más cómodo.
Lo de los Singleton, por favor, ponme un ejemplo, porque estoy buscando la forma de hacerlo y no acabo de verlo claro.
La clase textura tiene una referencia a la clase texturas para poder acceder desde una textura a la clase que hace de "colección." Esto lo hago porque en el futuro, la clase texturas tendrá información general que se utilizará en la clase textura:
class Texturas {
public bool soportaDXT1;
....
};
Entonces en la clase textura, al crear una nueva textura, miraré si soporta DXT1 y ya la comprimo.
Singleton en C#, la forma óptima adaptada al entorno .NET, según Microsoft:
LinkCitar
Tengo que usar CRender porque quiero que la variable se llame Render.
Como quieras, con el standard la clase se llamaría Render y la variable render
CitarComo ves, las variables dentro de Video, son para encapsular otras clases, y quería que se notara más que variables son subclases.
Uhm, bienvenido al mundo de como entender un programador a otro cuando no usan la misma terminología :( .Las variables dentro de video encapsulan otras clases :blink: y quería que se notara más que variables son subclases :blink: , supongo que en vez de subclase te refieres a clase anidada.
Tengo la impresión que mezclamos el "aspecto lógico" con el "aspecto físico", evidentemente tendrás una variable de tipo Render dentro de Video(en tu diseño, vamos), lo que ya me disgusta más es una clase pública definida dentro de otra, en el mismo fichero
CitarEn realidad la ventaja de esto es que tengo un objeto que se llama video donde se aglutina toda la información
CitarEn realidad la ventaja de esto es que tengo un objeto que se llama video donde se aglutina toda la información
Uhm, si hablas de objeto, te refieres al código. Para esono tienes porque definir las clases dentro de la implementación de Video.
Tener una clase que englobe toda la aplicación con sus subsistemas es lo lógico, llamarlo Hadd... es egocentrismo (uoh)
Hola,
comparto las opiniones de Grugnorr en todos los puntos. Sobre todo en nomenclatura y lo de una clase por fichero (soy un cuadriculado). Respecto a los códigos que has colgado, veo que algunas cosas son de tutos o de algun otro lado no? Porque encuentro cosas en inglés y en español mezcladas... En general, creo que quizás deberíamos ver quienes somos, y antes de liarnos a tirar codigo organizar un poco las cosas (namespaces, que hace cada uno, clases, nomenclaturas, organizacion del curro,...), vamos, por no hacer cada uno la guerra por su parte. Venga, un saludo!
Vicente
P.D.: unos tutos pa mi gusto muy majos de managed directx con c#
http://www.pluralsight.com/craig/articlevi...irectX/Direct3D
Este mensaje sólo es para indicar que se ha actualizado el motor. Todos los cambios los voy manteniendo en el primer post. Por desgracia, no aparece como mensaje nuevo una modificación de un post, así que debo escribir este mensaje para que la gente se de cuenta <_<
has pensado en darlo de alta en sourceforge para tener un CVS ?
un saludo y suerte
PD:haddd tu cuantas horas codeas al día ? :)
Creo que es un poco pronto todavía. Quiero ver la respuesta de la gente y luego ya se tomará la decisión.
Codeo poco tiempo, lo que ocurre es que ya lo he escrito tantas veces que me lo sé de memoria. :blink:
Citar// probamos con todas las extensiones
for (int c = 0; c < extensiones.Length; c++)
{
if(System.IO.File.Exists(path+nombre+extensiones[c]))
{
pathCompleto=path+nombre+extensiones[c];
return true;
}
}
Si hay dos archivos con mismo nombre y dos extenciones distintas te fracasa.
Es mejor, permitir al usuario cual elegir tambien.
Una manera rapida seria agregar "" a extensiones.
o sea
Citarprivate string[] extensiones={ "", ".png",".jpg",".tga",".bmp",".dds" }; // lista de extensiones que queremos probar para cargar la textura
No por molesto ni metiche son solo ganas de ayudar.
Muy buena Pochaga, no se me había ocurrido lo de "". (ole)
La única pega que le veo es que el programa primero mira si la textura existe, y para comprobarlo utiliza el nombre sin la extensión. No creo que sea mucho pedir que no se utilice el mismo nombre de textura dos veces, pero con extensiones diferentes.
Pero queda dicho y por lo menos lo añadiré al código comentando lo que tu dices.
He vuelto a actualizar el motor. He mejorado las clases un poco y he añadido soporte para carga de archivos .X. Recordad que siempre mantengo el estado actual en el primer mensaje de este post.
C# y Managed DX son la leche. (uoh)
Perdón por offtopic, pero, ¿cómo haces para modificar un post días después de ser publicado? ¿No se supone que hay un límite de 15 minutos para editar? Supongo que serás webmaster o tendrás contacto directo con ellos...
Perdón de nuevo. Si queréis borrar este post para no ensuciar el thread no me parece mal. Ah, ánimo con el proyecto de todas formas :)
Yo no tengo problemas para hacerlo, y no soy administrador.
He vuelto a actualizar el motor. He mejorado las clases un poco, he añadido una clase de carga en XML de Vicente y he incluido la clase Apariencia, que responde al post de atributos que puse en este mismo foro. Recordad que siempre mantengo el estado actual en el primer mensaje de este post.
Hola,
voy a poner aqui el código del cargador de XML a ver si la gente asi se anima a colaborar ;) He corregido un fallo del cargador de XML (si había dos rutas de XML iguales petaba).
Lo que hace el cargador es bien simple. Si tenemos un XML como este:
<Config>
<ProfundidadColor>32</ProfunidadColor>
<Resolucion>
<Ancho>1024</Ancho>
<Alto>768</Alto>
</Resolucion>
</Config>
Se genera una tabla hash como la siguiente (clave - valor, todo son strings):
Config.ProfundidadColor - 32
Config.Resolucion.Ancho - 1024
Config.Resolucion.Alto - 768
El bug era que si teníamos dos rutas iguales, la tabla hash petaba al añadir la segunda (claves repetidas). Ahora si hay dos rutas iguales se agrupan dentro de un arraylist (eso creo, lo tengo que probar un poco más, pero parece que tira ;)).
El código:
using System;
using System.Collections;
using System.Xml;
namespace Utilidades
{
public class ManejadorXml
{
private ManejadorXml()
{
}
public static void VolcarXmlaHash(Hashtable datos, string nombreXml)
{
XmlDocument documento;
//Cargamos el fichero xml
documento = new XmlDocument();
documento.Load(nombreXml);
//Volcamos los valores del xml en la tabla hash
CargarNodos(documento, datos, documento.ChildNodes, string.Empty);
}
private static void CargarNodos(XmlDocument documento, Hashtable datos, XmlNodeList listaNodos, string ruta)
{
string rutaFinal, xPathQuery;
XmlNodeList resultadoQuery;
//Para cada nodo de la lista miramos si es raiz o no.
for (int i=0; i<listaNodos.Count; i++)
{
//Es raiz: llamada recursiva aumentado la ruta que necesitamos para llegar al nodo
if (listaNodos.Item(i).HasChildNodes == true)
CargarNodos(documento, datos, listaNodos.Item(i).ChildNodes, ruta + listaNodos.Item(i).Name + ".");
//Es hoja
else
{
//Realizamos una query de xpath para ver si el nodo está repetido en el documento
rutaFinal = ruta.Substring(0, ruta.Length - 1);
xPathQuery = rutaFinal.Replace('.', '/');
resultadoQuery = documento.SelectNodes(xPathQuery);
//El nodo está repetido, lo guardamos en un arraylist
if (resultadoQuery.Count > 1)
{
//Es el primer nodo repetido, creamos el array de valores
if (datos[rutaFinal] == null)
datos.Add(rutaFinal, new ArrayList());
//Añadimos el valor del nodo a la lista
((ArrayList) datos[rutaFinal]).Add(listaNodos.Item(i).InnerText);
}
//El nodo es único, lo añadimos
else
datos.Add(ruta.Substring(0, ruta.Length - 1), listaNodos.Item(i).InnerText);
}
}
}
}
}
Yo de gráficos cero, pero estas pijadas me encantan ;) Venga, a ver si se anima la gente. Se esperan también críticas al código ;) Un saludo!
Vicente
Falta el manejo de errores. He cargado el archivo que tu mismo has puesto de ejemplo y si te fijas la palabra profundidad está mal escrito, por tanto me ha dado un error.
Pero está realmente bien, y es sencilla de usar. He subido de nuevo el código con la última actualización. También he modificado un poco tu clases. Echale un vistazo y opina!!
Gracias por todo!
Hola,
jejeje, es que el xml lo escribí al vuelo. Es verdad que no puse ni un solo try o catch :rolleyes: Cuando me bajo el proyecto veo el código de la versión anterior, no el nuevo... Ya está actualizado? Un saludo,
Vicente
Sí, ya está actualizado.
Citar public class Vertices : Form
en "vertices.cs"
No deberia llamarse
Aplicación o algo por el estilo, como que parece muy sacado de un ejemplo :P, tambien podrias eliminar ya "tut2_vertices.jpg" y cambiar el nombre al proyecto de "tutorial2".
Una pregunta:
Citarpublic Object objeto;
En "lista.cs", Object es un keyword que vendria a hacer las veces de template?
Por cierto que se necesita para compilarlo?
Alguna modificacion para la clase Camara, a mi me gusta hacer efectos de lentes :D
public class Camara
{
...
public float Fov;
...
public Camara()
{
view=new Matrix();
projection = new Matrix();
Fov=(float)Math.PI / 4.0f;
EstablecerVista(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f));
EstablecerProyeccion(1.0f, 100.0f);
}
...
public void EstablecerProyeccion(float near,float far)
{
projection = Matrix.PerspectiveFovLH(Fov, Haddd.video.aspectRatio, near, far);
}
...
Para compilarlo necesitas Vstudio 2005 express C# beta. Está disponible gratuitamente en la página de MSDN.
Lo del objeto, tienes razón, es simular un template. Si puedes mejorarlo..¡adelante!
Lo de la cámara, tomo nota y lo cambio. Por cierto, ¿porqué no te animas y te curras una clase de cámara como toca? (ole)
He actualizado el proyecto. A ver si le echais un vistazo y comentais. (ole)
CitarLo del objeto, tienes razón, es simular un template. Si puedes mejorarlo..¡adelante!
Tan solo preguntaba por ser ignorante :P
CitarPara compilarlo necesitas Vstudio 2005 express C# beta.
Ya lo tengo, me falta el sdk de DX, pero en eso estoy.
CitarLo de la cámara, tomo nota y lo cambio. Por cierto, ¿porqué no te animas y te curras una clase de cámara como toca?
No se lo suficiente ni de c# ni de dx como para animarme a tanto, pero vere que puedo hacer.
Bueno, pues aquí está mi segunda aportación al motor:
(http://www.arrakis.es/~jonathan01/csharp_imp.jpg)
Como podéis ver es Imp, uno de los modelos de Doom3.
He creado dos clases. Una que es un parser genérico para analizar archivos ASCII y otra que se encarga de cargar los modelos y animaciones de Doom3.
Por otro lado (y esto habrá que ver qué os parece), he creado un nuevo método en la clase FicherosX que es CargarDesdeMD5Mesh (esto de los nombres en castellano...). :lol:
En ese método lo que hago es crear un D3DXMesh y relleno el vertex & index buffer con los datos del modelo MD5. Por ahora sólo cargo la geometría. Luego ya me pondré con la animación, que no tengo ni idea de cómo se rellena todo eso utilizando D3DXMeshes (no los había utilizado en mi vida). :D
Bueno, pues cuando modifique unas cosas que están un poco guarras pongo el código.
Saludos.
la pregunta del cateto :
Lo que hace eso es convertir de md5 a *.x??
Cita de: "donald"la pregunta del cateto :
Lo que hace eso es convertir de md5 a *.x??
No, pero ahora que lo dices, una vez cargado el MD5 en un D3DXMesh, creo que hay un método que guarda el mesh en formato X. Así que en teoría podría hacerse.
Saludos.
Hola,
Haddd, en el todo pones mejorar el diseño de las clases y tal. Si quieres le echo un ojo, pero una cosa: qué clases pueden considerarse más o menos terminadas? (para no ponerme a retocar algo que luego va a cambiar otra persona ;)). Un saludo!
Vicente
Berserker, no hay ningún enlace al importador de MD5. Tampoco sé si has integrado el cargador o has hecho algo por tu cuenta en C#. Desde luego es una gran aportación, pero si lo has hecho aparte, deberías consensuar un poco para poder integrarlo de forma que a ambos nos parezca lo más correcto.
Vicente, prácticamente lo hago yo solito todo, así que cambia bastante. Lo que está realmente mal es lo de las listas, puesto que como verás utilizo una estructura que es la que realmente inserto. Esto debería hacerse con plantillas...
Me queda poco para terminar el importador de mi maxscript. A ver si lo termino esta tarde/noche y ya podemos tener un banco de pruebas mucho más sólido.
Donal, a ver si te animas y nos mandas un objeto .x de esos que tienen miles de polígonos y quedan super chulos con iluminación per pixel!!!
Sí, lo que ves ahí está hecho utilizando el framework que has puesto en el primer mensaje de este hilo. Como he dicho, he creado dos clases (un Parser y el cargador de MD5) y luego he creado un método en FicherosX que es CargarDesdeMD5Mesh que se encarga de crear un D3DXMesh para luego poder renderizar tal y como se hace con el tigre en formato X.
Lo que pasa es que aún no he puesto el código porque se me había olvidado dar soporte para los submeshes, es decir, un md5mesh puede estar compuesto por varios submeshes por lo que tengo que crear varios subsets para el D3DXMesh. El problema lo estoy teniendo ahí precisamente. Estoy creando una AttributeTable con tantas entradas como submeshes y luego asignádosela con Mesh.SetAttributeTable pero no funciona. ¿Tú sabes cómo va eso?.
Bueno, yo sigo probando. En cuanto tenga eso pongo el código.
Saludos.
Me encantaría, Hadd, de veras.
pero el tema es que pese a mis largos posts, tengo un "spool" de cosas que hacer, me refiero a gráficos, a los que ya estoy comprometido y poco a poco voy sacando, pero si me meto en más, ni de coña...
En fin, supongo que si en unos meses estos sigue, igual puedo colaborar entonces :)
Tenía por ahí medio empezado un modelo bastante majo, en alta que pensaba de paso usar para hacer una prueba a nivel personal de normal maps...pero no puede ser, con alta, me pongo tela de perfeccionista, y con todo lo demás que tengo "en cola", no habría manera.
Ya he perdido demasiado el otro día con el cable que le eché a Mars y Ager... ;)
Berserker, para que vaya más rápido, añade lo siguiente en Video.cs, en el constructor de CInicializar:
presentParams.PresentationInterval = PresentInterval.Immediate;
Yo estoy ahora con el mismo problema que tienes tu, los atributos al crear el mesh. Mañana le echaré un vistazo a un libro que tengo en el trabajo donde lo explica.
Lo de los atributos para definir subsets creo que ya se cómo hacerlo. El problema es que me salta una excepción.
Estoy probando con algo sencillo (utilizando el tutorial#3 del SDK de DX para C#). Lo que hago es crear un D3DXMesh y relleno el vertex & index buffer con los vértices e índices de dos quads. Lo que quiero es que esos dos quads sea cada uno un subset. Aquí está el código:
short[] indices = {
0,1,2, // Cara#1
0,2,3,
4,6,5, // Cara#2
4,7,6
};
mesh = new Mesh(4, 8, MeshFlags.Managed,
CustomVertex.PositionTextured.Format, device);
using (VertexBuffer vb = mesh.VertexBuffer)
{
GraphicsStream data = vb.Lock(0, 0, LockFlags.None);
// Vértices para la cara#1
data.Write(new CustomVertex.PositionTextured(-0.2f, 2.0f, 0.0f, 0.0f, 1.0f));
data.Write(new CustomVertex.PositionTextured(-0.2f, 0.0f, 0.0f, 1.0f, 1.0f));
data.Write(new CustomVertex.PositionTextured(-2.0f, 0.0f, 0.0f, 1.0f, 0.0f));
data.Write(new CustomVertex.PositionTextured(-2.0f, 2.0f, 0.0f, 0.0f, 0.0f));
// Vértices para la cara#2
data.Write(new CustomVertex.PositionTextured(0.2f, 2.0f, 0.0f, 0.0f, 1.0f));
data.Write(new CustomVertex.PositionTextured(0.2f, 0.0f, 0.0f, 1.0f, 1.0f));
data.Write(new CustomVertex.PositionTextured(2.0f, 0.0f, 0.0f, 1.0f, 0.0f));
data.Write(new CustomVertex.PositionTextured(2.0f, 2.0f, 0.0f, 0.0f, 0.0f));
vb.Unlock();
}
using (IndexBuffer ib = mesh.IndexBuffer)
{
ib.SetData(indices, 0, LockFlags.None);
ib.Unlock();
}
Una vez rellenados los buffers, intento crear los subsets con:
int[] attr = new int[] { 0, 0, 1, 1 };
GraphicsStream gs = mesh.LockAttributeBuffer(LockFlags.Discard);
gs.Write(attr);
mesh.UnlockAttributeBuffer();
Lo que hace esto es que a cada cara del mesh le asocia un attributeID de forma que en este caso, el primer quad (2 triángulos) es el subset #0 y el otro el subset #1. Pues bien, al hacer el gs.Write, me salta una exceptión de la clase InvalidOperationException que me dice:
CitarOperation is not valid due to the current state of the object.
Y ahí me he quedado parado. Estoy buscando por la red a ver si encuentro una solución pero de momento nada. A ver si tú o alguien más sabe qué es lo que pasa.
Saludos.
Creo que tienes que utilizar SetAttributeTable. Yo también tengo que probarlo, pero ya tendrá que ser esta noche. El primero que lo descubra que ponga el código. ;)
Por lo que he leído se puede hacer tanto con LockAttributeBuffer como con SetAttributeTable. A mí me gusta más LockAttributeBuffer pero peta y con SetAttributeTable probé y aunque no peta, no parece hacer nada. Será que no lo estoy haciendo bien, claro.
Y nada, si es que con LockAttributeBuffer debe ir seguro. De hecho me deja escribir el atributo para la primera cara y efectivamente me separa esa cara de las demas, es decir, crea dos subsets, pero en cuanto intento escribir en la segunda cara pues salta la excepción. He probado a leer el contenido del attribute buffer y está bien. Para el caso este de dos quads hay 4 attributeIDs (al principio todos puestos a cero), como era de esperar.
Bueno, a ver si logro solucionarlo.
Saludos.
Vaya tela, resulta que el attributeID que hay que meter en el buffer al hacer el LockAttributeBuffer es de tipo byte y yo estaba metiendo IDs de tipo int. Ahora parece funcionar:
byte[] attr = new byte[] { 0, 0, 1, 1 };
GraphicsStream gs = mesh.LockAttributeBuffer(LockFlags.Discard);
gs.Write(attr);
mesh.UnlockAttributeBuffer();
Eso quiere decir que el máximo número de subsets es 256...
Saludos.
EDIT: aunque no salta la excepción parece que no funciona del todo. Lo cierto es que me ha creado la attributeTable perfectamente pero cuando hago el DrawSubset no me pinta lo que debería.
Veo que el attributeID del segundo grupo es un nº erróneo. He probado con LockAttributeArray pero parece que tampoco va bien. :(
Pues es muy raro porque estoy probando un un modelo del doom3 que está compuesto por 4 submeshes. He programado el cargador de forma que cree 4 subsets (con LockAttributeBuffer). Si después rellenar el attribute buffer vuelco su contenido en un archivo, la información que imprime es totalmente correcta aunque eso no se plasma en pantalla (sigue renderizando todo en un sólo subset). Y si justo después de rellenar el attribute buffer llamo a Optimize (que es como debería ser ya que se encarga de crear el attribute table), si luego vuelvo a volcar el attribute buffer en un archivo, me lo rellena todo de ceros, es decir, sólo existe el subset #0.
Así que nada, sólo me falta solucionar eso para dar por finalizado la carga de MD5 sin animación. No quiero ni pensar cuando tenga que empezar a meter los bones, weights y demás en las estructuras de D3DXMesh. No creo que salga con vida. :lol:
Saludos.
Bien, he estado haciendo pruebas. En el libro Introduction to Game Programming whith DirectX9, explica la forma de crear tablas de atributos y lo que haces es correcto. Al bloquear el buffer, te devuelve un array de int ( nada de byte !!) y eso es lo que modificas. Por tanto, lo hacemos bien(salvo en el caso tuyo que usas byte para que no aslte la excepción)
Por tanto, he pensado que si funciona con byte y no con int debe ser un problema de espacio de memoria. He subido las caras, multiplicandolas por 4 y entonces al utilizar int y definir los atributos, ¡ha funcionado!
¡Pero tengo 16 caras en lugar de 4! :huh: He intentado luego hacer un compact para ver si me las quitaba pero no ha habido forma. Por tanto, creo que es un bug de DX. (nooo)
Seguiré investigando, a ver si descubro algo más.
No hay forma!! :( Estoy convencido de que es un enorme bug. He puesto un post en las news de DX, pero por ahora nadie ha contestado. ¡Vaya forma de parar un proyecto! (grrr) Los subset eran muy importantes para poder realizar las importaciones y demás que estoy probando. (nooo)
Yo le he preguntado a Robert Dunlop, MVP de DirectX. A ver si me contesta que últimamente está perdido.
Saludos.
Lo que digo yo es que el método Mesh.FromFile tiene, sin más remedio, que crear los subsets porque he probado a cargar el modelo del aeroplano (airplane2.x) y efectivamente crea varios subsets (creo que 2). Pero claro, no tenemos el código de ese método para saber cómo lo hace... :D
Aunque lo raro es que si después de cargar el aeroplano, recojo el attribute buffer y lo vuelco a un archivo, me lo rellena de ceros cuando en realidad deberían ser todo ceros y unos. :lol:
Así que tal vez sí que puede que exista un bug en las runtime DirectX de .NET...
Pero bueno, habrá que esperar a que nos contesten los expertos. O eso o que a alguno se nos encienda la lucecita. :lol:
Saludos.
Bueno, para poder salir del paso voy a crear una lista dentro de la clase mesh. En realidad esa lista sustituye al subset y lo que haré será crear tantos meshes como atributos tenga el mesh. Es la única forma de salir del paso que se me ocurre hasta que se resuelve el problema.
¿Qué te parece?
Intentaré tenerlo listo mañana por la tarde, sin embargo...puede que se demore un poquito hasta el Lunes, porque este fin de semana no voy a poder hacer casi nada.
Ya he hecho una gran parte del cargador( String.Split te resuelve un montón de problemas) de los ficheros Haddd. También tengo una escena enorme que espero que pueda llegar a cargar. Si además Berserker puede terminar su código de MD5, creo que la semana que viene tendremos una buena actualización.
¡A ver si os animais, que hay mucho que hacer! (ole)
Otra cosa, es posible que C# no sea todo lo rápido que quisiéramos, pero os aseguro que es LO MAS PRODUCTIVO QUE HE VISTO EN MI VIDA. Aunque hay cosas que expondré aquí para que me ayudeis a resolver que no sé cómo se pueden resolver sin los punteros de toda la vida.
Por cierto, resulta que para el nuevo Windows Longhorn, los drivers de vídeo(y supongo que todos los demás) tienen que estar en Managed code. ATI ya los ha convertido y NVidia ha dicho que está en ello. Sinceramente, si los drivers que están a bajo nivel TIENEN que estar en Managed, me parece que no permitirán que se hagan cosas sin Managed. Así que es posible que las DX9 sean las últimas que pueden ejecutarse en código no managed...
Argh!
No me digas q el c# no tiene punteros!!!! (grrr)
Cita de: "Haddd"Bueno, para poder salir del paso voy a crear una lista dentro de la clase mesh. En realidad esa lista sustituye al subset y lo que haré será crear tantos meshes como atributos tenga el mesh. Es la única forma de salir del paso que se me ocurre hasta que se resuelve el problema.
¿Qué te parece?
Bueno, está claro que tiene que ser una salida temporal ya que para cada mes crear un vertex & index buffer y eso no es demasiado bueno. pero bueno, para salir del paso está bien.
Cita de: "Haddd"Ya he hecho una gran parte del cargador( String.Split te resuelve un montón de problemas) de los ficheros Haddd. También tengo una escena enorme que espero que pueda llegar a cargar.
Yo he creado un parser genérico (utilizando un singleton) que hace uso de Split para crear los tokens de una línea del archivo y enumerators para recorrer esos tokens. Es lo que he utilizado para analizar los archivos MD5 y la verdad es que funciona muy bien. A lo mejor esta noche pongo el código por si quieres utilizarlo.
Cita de: "Haddd"Si además Berserker puede terminar su código de MD5, creo que la semana que viene tendremos una buena actualización.
Sí, en cuanto hagas lo de los sub-meshes, saca el código y lo adapto al cargador de MD5. Decir que de momento sólo carga los modelos estáticos. La animación tardará algo en llegar, más que nada porque tengo que averiguar cómo rellenar la clase SkinInformation y demás.
Cita de: "Haddd"¡A ver si os animais, que hay mucho que hacer! (ole)
Pues sí, yo la verdad es que estoy haciendo esto porque de esta forma profundizo más en C# y al mismo tiempo aporto cosas a la comunidad.
Cita de: "Haddd"Otra cosa, es posible que C# no sea todo lo rápido que quisiéramos, pero os aseguro que es LO MAS PRODUCTIVO QUE HE VISTO EN MI VIDA.
A mí me encanta. :)
Por cierto, como hemos estado parados en el tema de los subsets, me he puesto a crear una clase cámara decente. He pensado en crear una clase abstracta cámara y después de esa derivar tres clases. Una cámara tipo trackball como la de los paquetes de modelado 3D (MAX, Maya, XSI, etc), otra para manejear una cámara autónoma (por ejemplo una cámara que siga un recorrido exportado del MAX) y otra para manejar cámaras a través de dispositivos de entrada (teclado, ratón, gamepad). Para ello también tendré que programar una clase que envuelva DInput. Y lo que había pensado es, para el tipo de cámara controlada por teclado/ratón/etc, hacer que dicha clase se suscriba a eventos del tipo MouseEventHandler y KeyEventHandler cuyo ofertante podría ser un formulario o incluso un objeto que envuelva dispositivos a través de DInput. De esa forma el control de la cámara se produciría en la propia clase cámara. Por supuesto tendríamos un método a través del cual se rellenaría una estructura (a gusto del usuario) en la que se especificarían las acciones (por ejemplo moverse hacia adelante) y las teclas asociadas a dichas acciones (por ejemplo para cada acción podríamos tener una tecla primaria y una secundaria, como la mayoría de juegos hacen).
Pero bueno, eso es algo que habrá que pensar más y lo menciono para que déis vuestra opinión.
Saludos.
Bueno, pues he creado una pequeña aplicación de consola explicando muy básicamente cómo funciona el parser que he creado (Parser.cs). Lo podéis descargar de
aquí.
También he creado una pequeña prueba de cómo estoy pensando en implementar el manejo de acciones de la cámara para ver qué os parece. He creado una clase cámara (nada que ver con lo que sería en realidad) que se suscribe al evento KeyDown del formulario de forma que si el usuario presiona una tecla con el formulario activo, éste notifica a la cámara que se ha pulsado una tecla y ésta se encargará de reaccionar apropiadamente. También es interesante que os fijéis en la propuesta que hago de cómo manejar las acciones de la cámara y cómo el usuario puede especificar las teclas para dichas acciones. Tened en cuenta que sólo es una prueba de las primeras ideas que me han venido a la cabeza de cómo implementar la cámara (y posiblemente cualquier objeto manejable por el usuario). Podéis descargar el test
aquí.
Una cosa a tener en cuenta. Para que veáis la reacción de la cámara al pulsarse las teclas, saco por la consola información como la acción que se llevó a cabo y la nueva posición de la cámara. Lo que pasa es que la información no sale por consola sino que he redireccionado la salida al archivo de texto "out.txt". Así que ese es el archivo que tenéis que abrir para ver la salida del programa.
Saludos.
Me parece una buena idea. De esta forma la configuración de las teclas es mucho más sencilla. Sin embargo, creo que deberías ligarlo a DInput directamente, puesto que al final es lo que utilizaremos.
Otra cosa, ¿porque no en castellano?
Hola,
Citar
¡A ver si os animais, que hay mucho que hacer! (ole)
he retocado alguna cosa del xml y el gestor de configuracion y como de lo otro no me entero, me he puesto a cacharrear con otro tema que no se si será interesante para el motor: IA. Estoy haciendo clases para manejar automatas finitos (normales y con logica difusa). Cuando los acabe lo postearé todo. Si parece un tema interesante, después seguiré o con búsquedas o con algoritmos genéticos. Que os parece?
Citar
Otra cosa, es posible que C# no sea todo lo rápido que quisiéramos, pero os aseguro que es LO MAS PRODUCTIVO QUE HE VISTO EN MI VIDA. Aunque hay cosas que expondré aquí para que me ayudeis a resolver que no sé cómo se pueden resolver sin los punteros de toda la vida.
A mi me tiene enamorado. Es cómodo, se programa rapidísimo, etc etc. Para mi es una gozada. Venga, un saludo!
Vicente
Hombre, eso ni se pregunta Vicente!! Es realmente interesante todo lo relacionado con juegos, y la IA es algo bastante importante.
¿nadie se anima con los terrenos?
He modificado la estructura del motor para poder "simular" los subsets. Sin embargo NO me funciona, y quizás sea un problema sobre el desconocimiento que tengo a la hora de copiar arrays. :blink:
Bueno, la idea es que cojo el mesh y un array de int[] donde está la información del atributo.
Para cada atributo:
Genero una nueva tabla de indices donde aparecen sólo aquellas caras que utilizan ese atributo.
Copio TODOS los vértices y sólo los índices que he calculado antes.
Lo añado a una lista.
He puesto todo el código por si alguien puede detectar el problema. También he añadido la clase escena. En principio, Berserker tendrías que intentar adecuar tu código a esta nueva estructura, pero verás que los cambios son mínimos mínimos, y espero que convengas conmigo que también son lógicos :D
También he incluido el importador de Haddd que exporta de MAXScript. Pero todavía no lo he terminado puesto que necesito los subsets. El código es bastante feo, pero es código medianamente legible.
Bajarme lasPruebas
No he podido echarle un vistazo aún a lo que dices de los subsets pero he terminado la clase (otro singleton al canto) que encapsula DInput.
Con las pruebas que he hecho parece que funciona bien (teclado y ratón). Lo que no sé es cómo integrarlo en la estructura del motor. He intentado añadir un miembro "input" a la clase Haddd (tal y como tienes el video, texturas, etc) pero no lo he podido hacer funcionar (tampoco le he dedicado mucho tiempo). Así que como es un singleton, allá donde he tenido que utilizarlo, lo he hecho a través de:
Citarif (Input.Instance.KeyPressed(Key.Escape)) ....
if (Input.Instance.MouseButtonPressed(0)) ...
etc
Y así ha funcionado perfectamente. Eso sí, he tenido que modificar (más bien añadir) unas cuantas cosas más para dar cabida a la clase ésta. Por ejemplo, he tenido que añadir un handler al evento Form_Activated para hacer la adquisición (Acquire) tanto del ratón como del teclado. De todas formas, ahí donde he hecho cambios lo he anotado en la parte superior del archivo de código en cuestión.
Lo próximo será crear las clases de cámara y bueno, a ver si le echo un vistazo a lo de los subsets.
Saludos.
Bueno pues ya he desarrollado la clase base de cámara (Camera) con soporte para frustum culling (BBox & BSpheres) y la clase de cámara controlada por el usuario (CameraFirstPerson) a través de teclado y ratón (más adelante habrá que enumerar los dispositivos de entrada para que el usuario escoja uno). Evidentemente esta clase deriva de la clase base que he mencionado antes. Lo siguiente será crear otra clase pero en esta ocasión será otro tipo de cámara (CameraSelfDriven) que se controlará a sí misma a través de paths exportados de MAX. Esta cámara será perfecta para crear secuencias cinemáticas. Finalmente haré la cámara (CameraTrackball) tipo Maya, MAX, etc, que para un juego no tiene mucha utilidad pero para cosas como editores de partículas, visor de modelos, etc, viene perfecta.
Así que de momento llevo el parser, el wrapper de DInput, las cámaras y el cargador de modelos de Doom III. Seguramente sacaré el código cuando termine las cámaras. Aunque el cargador MD5 me gustaría sacarlo ya terminado, pero para eso necesitaríamos tener una respuesta referente al tema de los subsets.
Saludos.
Bien, ya he resuelto el problema del "simulador" de atributos.
He subido la versión en:
Ultima versionCon esto Berserker, podrás simular sin apenas modificar código las tablas de atributos. Echale un vistazo a la clase CMesh, método Prueba() y el que genera los subsets se llama CrearSubMallas()
Bueno, lo que estás haciendo de la clase cámara es genial. Fíjate que en muy poco tiempo tenemos un buen engine, con efects, carga de .X y MD5 y escenas generadas con un script de MAX. Si Vicente se anima con las AI, quizás otros también se animen a colaborar. Creo que el proyecto está funcionando bastante bien (ole)
Deciros a los que querais colaborar que simplemente lo digais, cojais el código y..¡a trabajar! Si quereis discutir lo que haceis, abrid un post que empiece por
CitarMotor común en C#:
¡Animo a todos! (ole)
Otra cosa, este fin de semana no podré hacer nada, pero el domingo creo que le podré pegar un estirón. A ver el Lunes ya puedo tener el importador de escenas.
A ver si montais un proyecto en SourceForge, con su cvs y tal.. :rolleyes:
el .X y MD5 abren la cosa a mucho más que max...
hay muchos grafistas que curran con maya, XSI(yo, y legal :D ), blender(tb yo), character fx(idem), AM,Lightwave, Truespace, Gamespace, etc...
con esos formatos, pueden pasar personajes animados a vuestro engine...
Lástima que tenga yo un spool de cosas más largo que la muralla china...
He probado con los modelos de Doom3 el sistema que has creado para crear los subsets y parece funcionar bien.
Ahora estoy terminando la clase CameraSelfDriven que básicamente funciona ya. He probado a exportar una secuencia de cámara del MAX y la he cargado en el motor y funciona bien. Aunque la verdad es que no sé si la conversión de las rotaciones MAX->D3D estará bien. En las pruebas que he hecho parece que sí. Lo ideal sería probarlo con una escena más compleja. ¿Cómo llevas el cargador de escenas?. Estaría bien probarlo con eso.
Una vez que acabe esta cámara supongo que me pondré con la animación de los MD5 que va a tener tela. Más que nada porque no tengo ni idea de cómo funcionan los D3DXMeshes en temas de animación. Pero bueno, será cuestión de echarles un vistazo.
Saludos.
Juas, manda huevos, entre dos personas hacen un motor de la ostia en ¿cuanto? y se quedan tan anchos, porque no currais en Pyros o algo asi? :S
Un saludo
o mejor, por qué no montais una empresa en vez de que os contrate una. O incluso mejor por qué no os montais una empresa y codeais un juego en vez del enésimo motor?
He subido una nueva versión, está como siempre, en el primer post de este mensaje.
Berserker, necesitaría la clase cámara, porque no veas lo mal que va ver si he importado bien un objeto ¡sin poder rotar la cámara! Ya que tu las tienes desarrolladas, prefiero utilizar las tuyas que ponerme con las mías, así que cuando puedas, por favor, súbelas.
He incluido el exportador en MAXScript. Como podreis ver, me parece que el formato es muy sencillo, y espero que la gente se ánime a crear otros conversores a este formato. (ole)
Por cierto, los comentarios que no estén relacionados con el motor, por favor, abrid otro post para que este no se convierta en lo que todos sabemos. Gracias. ;)
Ya puedes bajar las clases
Parser,
Input,
Camera y
CameraFirstPerson de
aquí.
Tienes que haces algunas cosas para hacer funcionar el cotarro...
Para hacer funciona "Input"La clase "Input" necesita de un handle al formulario para poder crear el dispositivo del teclado y el ratón (en SetCooperativeLevel). Yo lo que he hecho ha sido declarar una propiedad "handle" (es de tipo System.IntPtr) en la clase "Haddd" de forma que luego, en el método "CreateKeyboard" y "CreateMouse" (en "Input.cs") hago:
Citarkeyboard.SetCooperativeLevel(Haddd.handle, ...
Por supuesto, tienes que inicializar la variable handle. Yo lo he hecho en "Formulario.cs", en el método "Main" he puesto:
Citarusing (Formulario frm = new Formulario())
{
Haddd.handle = frm.Handle;
....
}
Otra cosa que tienes que hacer es crear un método para manejar el evento "Activated" y ahí adquirir los dispositivos de entrada:
Citarprivate void Formulario_Activated(object sender, EventArgs e)
{
Input.Instance.Acquire();
}
También, en "Haddd.cs", en el método "Finalizar" liberamos "Input":
Citarpublic static void Finalizar()
{
Input.Instance.Dispose();
....
}
Ahora ya sólo queda actualizar el "Input". Para ello, en "Main.cs", en el método "Render" (esto debería estar mejor en un método "Update"), he puesto:
Citarpublic void Render()
{
if (Haddd.device == null)
return;
// Actualizamos el input
Input.Instance.Update();
// ¿Salimos de la aplicación?
if (Input.Instance.KeyPressed(Key.Escape))
Application.Exit();
....
}
Fíjate que además del "Input.Instance.Update()", también compruebo si se ha pulsado la tecla "ESCAPE". Esto es así porque una vez activado DInput, no se manejará el evento "OnKeyPress" del formulario.
Creo que no se me pasa nada...
Para hacer funciona "Camera"Lo primero que tienes que hacer es declarar el miembro "camaraActiva" - que antes tenías en "Haddd.cs" y en las últimas pruebas en "Escena.cs" - del tipo "Camera" en vez de "Camara".
Ahora tienes que declarar la cámara en "Main.cs":
CitarCameraFirstPerson camara;
En en el método "InitializeGraphics" creas la cámara:
Citarcamara = new CameraFirstPerson(8.0f, 100.0f);
camara.Position = new Vector3(0.0f, 60.0f, -200.0f);
Haddd.camaraActiva = camara;
Como ves, primero se crea la cámara especificando la sensibilidad del ratón y la velocidad de traslación y luego se especifica la posición inicial. También se especifica la nueva cámara como cámara activa. Ten en cuenta que los parámetros velocidad y sensibilidad deberán variar dependiendo de la escala de tu escena. Si la escala es muy pequeña, deberás reducir los valores.
Por último tienes que actualizar la cámara. En el método "Render" (como antes he mencionado, esto debería estar mejor en un método "Update") pones:
CitarHaddd.camaraActiva.Update();
Una última cosa. En la inicialización del dispositivo de render tienes puesto:
CitarpresentParams.BackBufferWidth = 800;
presentParams.BackBufferHeight = 600;
cuando en realidad, las dimensiones de la ventana son 600x600. Lo mejor es que elimines esas dos líneas y Direct3D ya se encargará de crear el backbuffer con el tamaño de la ventana.
Bueno, eso es todo. Si tienes alguna duda, pregunta. :)
Saludos.
He actualizado una cosilla en la clase Input.
Por cierto, si tengo comentado el código con todo el tema de los tags , , etc, ¿cómo se crearía la documentación del proyecto?. ¿Con el propio Visual C# 2005 Express Edition Beta?.
Saludos.
Ya decía yo que se me olvidaba algo. No te olvides de añadir una referencia a la librería de DirectInput.
Esto de no poder editar los mensajes... :rolleyes:
hmmmm...
si yo ayudo con este motor.... podriais ayudarme con el mio?
Se algunas cosillas en el tema de animacion como saber la duracion del track y algo mas.
Boubou he descargado lo que hicistes, y siento decirte que eso no te ayuda en nada. No sé porque se te ocurre, como dices, contactar con sourceforge con lo que tienes. Allá tu, pero cualquiera que vea ese código se da cuenta del nivel de programación que tienes, y te aseguro que a mi me parece irrisorio. No te molestes conmigo, que no te lo digo para cabrearte.
Sobre lo de ayudarnos, ya sabes que cualquier ayuda es buena. Céntrate en un tema, por ejemplo generación de primitivas, o generación de terrenos, o alguna otra cosa, la que quieras, y desarróllala. Seguro que aprendes un montón sobre el tema y encima nos ayudas, así que todo el mundo sale ganando.
Por favor, no hagais comentarios en este post que no sean del motor. Si quereis decir algo abridlo en otro post.
Cita de: "BeRSeRKeR"He actualizado una cosilla en la clase Input.
Por cierto, si tengo comentado el código con todo el tema de los tags , , etc, ¿cómo se crearía la documentación del proyecto?. ¿Con el propio Visual C# 2005 Express Edition Beta?.
Saludos.
Hola,
a menos que las cosas hayan cambiado, el visual con los comentarios genera un documento xml, luego necesitas "algo" que transforme ese xml en documentacion de verdad: yo para ese "algo" uso ndoc (http://ndoc.sourceforge.net/). Es muy fácil de usar (estilo javadoc o doxygen...). Espero que te sirva, un saludo!
Vicente
Acabo de empezar a programarlo Haddd, esta, digamos, a un 1%. Y no estoy cabreado, sera el nuevo talante? xD
De todas formas voy a portar codigo a c++ de mi antiguo motor, el wizLIB. en cuestion de unas semanas estara terminado el port.
He actualizado el código, pero no puedo actualizar el primer mensaje, ya no me deja. :(
He añadido las clases Input y Camera creadas por Berserker.
Por cierto, he tenido que modificar mínimamente la clase Camera para obtener la matriz ViewProjection. Mírate el método Update.
Y tendríamos que standarizar la forma de trabajar. ¿Porqué no lo haces en castellano? Piensa que era una de las premisas y aunque suene raro escribir ciertas palabras, abarcamos el segmento de gente que no sabe inglés.
Después utilizar matView, matProjection. Una de las premisas que leí en C# es que no se deben utilizar los tipos de la variable en los nombres. Es una gran ventaja. Yo usaría View y Projection.
Finalmente decir que tu documentación es muy buena, y me adaptaré a la tuya.
¿Cómo consigues que al escribir /// te quede todo en una línea? A mi me crea una arriba y otra abajo!!
Bien, pues por favor, bájate la última versión y concretamos un poco el camino en común a seguir. (ole)
Cita de: "Haddd"Y tendríamos que standarizar la forma de trabajar. ¿Porqué no lo haces en castellano? Piensa que era una de las premisas y aunque suene raro escribir ciertas palabras, abarcamos el segmento de gente que no sabe inglés.
Ya pero es que me cuesta bastante ponerlo en castellano. Me resulta mucho más natural ponerlo en inglés ya que todo lo que rodea la programación está en inglés. No sé, me parece un sacrilegio. :lol:
Pero vamos que si hay que ponerlo en castellano pues en castellano. Pero yo creo que cualquiera que esté en disposición de utilizar un motor, también tiene que saber algo de inglés. Por muy poco que supiera debería entenderlo. :)
Cita de: "Haddd"Después utilizar matView, matProjection. Una de las premisas que leí en C# es que no se deben utilizar los tipos de la variable en los nombres. Es una gran ventaja. Yo usaría View y Projection.
Lo tendré en cuenta.
Cita de: "Haddd"Finalmente decir que tu documentación es muy buena, y me adaptaré a la tuya.
Gracias. El mérito es de ProD que me reeducó (con látigo en mano) en este sentido. :D
Cita de: "Haddd"¿Cómo consigues que al escribir /// te quede todo en una línea? A mi me crea una arriba y otra abajo!!
La verdad es que no sé si existirá alguna opción del entorno para que quede en una sóla línea. Yo lo hago manualmente ya que el "" siempre se me va a una nueva línea. En las propiedades miembro lo pongo en una sóla línea y en los métodos en varias. Es por cuestión de espacio más que nada.
Cita de: "Haddd"Bien, pues por favor, bájate la última versión y concretamos un poco el camino en común a seguir. (ole)
Voy a echarle un vistazo.
Saludos.
He actualizado las clases Camera y CameraFirstPerson con los cambios que has comentado.
Actualiza con esta nueva versión ya que como el método BuildFrustumPlanes hacía uso de la matriz viewProjection (la calculaba en cada frame), ahora utiliza la matriz viewProjection de la clase. De otra forma estarías calculándola dos veces. :)
Y debido a este cambio, he reubicado el cálculo de dicha matriz. En el método Update de la cámara, hacías el view*projection después de calcular los frustum planes pero tienes que ponerlo antes. Pero bueno, descárgate la actualización y sobreescribe.
Descarga.
Saludos.
No está en castellano. Tendríamos que ponernos deacuerdo en esto. Sé que suena raro en castellano, pero piensa que hay montones de cosas en inglés y muy pocas en castellano. Deberíamos favorecer este idioma, y debemos hacerlo nosotros, ¿no crees?
Por favor, piensa bien esta decisión, hay más gente colaborando en el motor y espero que pronto haya más. Tenemos que estar unidos en el idioma. Sin embargo la decisión final es de cada uno, y si está en inglés, pues bienvenido sea.
Venga, un saludo. (ole)
Hola,
respecto al idioma: lo mismo me da que me da lo mismo, yo lo de genéticos y el xml está en castellano, pero que si hay que traducirlo se traduce (yo he escrito muuuucho menos codigo que vosotros dos ;)). Un saludo,
Vicente
Bueno, se acabó este post, es una pena, porque iba a llegar a ser el post más visto :D ...
Bien, nos han abierto un subforo en Proyectos, al ladito del Anillo. No está mal, que se junte un juego con gráficos y un motor en desarrollo...ehmmm..¿no os sobrarán algunos graficos por ahí? ;)
Nos vemos allí!! (ole)