[NDS] Ayuda juego coche (Movimiento)

Hola, estoy intentando hacer un juego de coches para la ds.

En principio es en 2d, ya cuando lo tenga quizás lo amplie a 3d.

El caso es que necesito ayuda con algunos temas.

Ya tengo el coche moviendose por la pista, pero yo en principio hice un sprite del coche muy simple con las crucetas básicas y las diagonales, pero claro, la animación queda muy basta, así es que ahora he creado un sprite más completo, donde tengo 3 animaciones entre cada ángulo de 45º.

No se si me estoy explicando bien.

El caso es que yo antes, si iba hacia la derecha movia el sprite poniendo la coordenada (x+1,y), y si cambiaba hacia una diagonal ponía (x+1,y+1), pero ahora tengo un problema, porque al tener tantas animaciones, no se como hacer que avance el coche en la dirección en la que está el sprite apuntando.

Porque, como minimo, se ha de avanzar un pixel, no?

A ver si alguien me puede ayudar a ver como puedo hacer el movimiento más fino para que el coche vaya mejor.

Estoy atascadísimo, cualquier respuesta puede ser buena.

Gracias de antemano
No tiene por que avanzar un pixel. Puedes usar un contador decimal que almacene la posición con decimales y luego castearlo a entero para la representación.

Como la ds no tiene fpu, no es recomendable usar floats si es posible. Intenta usar el ultimo byte de un long para guardar los decimales. De esta manera dividimos cada pixel en 256 partes. Por lo tanto para avanzar 1, añadimos 2^8, es decir, 256; Para sacar las coordenadas reales dividimos entre 256. Dividir es una operación pesada por lo que es recomendable mover bytes. con lXReal = coche->lPosX >>8 se mueven los bits 8 posiciones a la derecha, lo que a terminos prácticos hace que se divida entre 2^8, es decir, 256.

De esta manera puedes usar "decimales", solo que tienes que tener en cuenta que los decimales es en base 256 en vez de 100 (osea que 12.64 es en realidad 12.25), pero si siempre trabajas en la misma unidad no tienes ni que tenerlo en cuenta.

Otra cosa, x+1,y+1 no es mover 1 pixel diagonalmente. La diagonal de un cuadrado es bastante más larga que la arista, y por lo tanto al ir en diagonal irías más rápido de lo que deberías.
Para hacer esto hay que usar trigonometría. hay que multiplicar la velocidad a la que quieres mover (1 pixel/frame) por el seno del angulo que forma la dirección con la horizontal, para la posición Y y por el coseno para la X; Por ejemplo, imaginemos que está a 60 grados sobre la horizontal. Para que se mueva 1 pixel exacto tienes que mover y+(1*sin(60)) e x+(1*cos(60)), que se traduce en y+0.86 x+0.5;

Realmente no está bien ya que los métodos sin() y cos() reciben el parámetro en radianes, por lo que deberías convertir el 60 en radianes.

El cálculo de angulos es bastante pesado, por lo que en lugar de llamar a los métodos sin() y cos() deberías usar una tabla precalculada en memoria. Eso o usar punto flotante pero nunca lo he usado así que no te puedo aconsejar.
Gracias tio, voy a digerir la magistral clase de matemáticas que me has dado y luego te cuento que tal me ha ido.

Es verdad que en las diagonales me iba más rápido, jeje, que paleto soy.
Una cosa más a aportar, no se mucho de DS, pero SEGURO que tiene algo para poder rotar por hardware un sprite, por lo que podrías utilizar esos mismos cálculos para rotar el sprite y ahorrarte los diferentes framss de animaciones.

Hay que reducir costes de diseño :P
Si lo tiene, pero he pasado de ello, te explico.

Yo al pricipio tenía un sprite muy simple, donde solo representaba las posiciones del coche hacia la derecha, luego hacia la izquierda les hacia el hflip, pero resulta que, no se porqué, cuando ponía el coche en alguna de las diagonales izquierdas, tardaba más en representármela, así es que decidí hacer un nuevo sprite con todas las posiciones representadas, de momento voy así, quizás más adelante lo modifique.

Y es que he visto un juego de coches para PC (MRO) cuyos coches son una simple imagen, luego las distintas posiciones supongo que las harán mediante software, rotando el coche, puede que haga eso, pero de momento, tengo un sprite con más de 30 frames.

De todos modos gracias
marioqn escribió:Si lo tiene, pero he pasado de ello, te explico.
Yo al pricipio tenía un sprite muy simple, donde solo representaba las posiciones del coche hacia la derecha, luego hacia la izquierda les hacia el hflip, pero resulta que, no se porqué, cuando ponía el coche en alguna de las diagonales izquierdas, tardaba más en representármela, así es que decidí hacer un nuevo sprite con todas las posiciones representadas, de momento voy así, quizás más adelante lo modifique.

Eso es casi seguro porque cuango girabas en diagonal izquierda hacías un flip a la imagen cada vez que pulsabas la tecla. Lo que tienes que hacer es -en memoria- hacer el flip una vez, guardarlo y luego reutilizar ese sprite que has creado y existe únicamente en memoria.
Sin embargo es raro, porque seguro que también la DS permite rotaciones por software

Y es que he visto un juego de coches para PC (MRO) cuyos coches son una simple imagen, luego las distintas posiciones supongo que las harán mediante software, rotando el coche, puede que haga eso, pero de momento, tengo un sprite con más de 30 frames.

Yo lo decía porque en DS por lo que tengo entendido la memoria es bastante escasa, así que si te ahorras 29 frames y además obtienes una representación mejor según el ángulo del coche... yo no me lo pensaría la verdad. Siempre que no tengas el mismo problema que al hacer el hflip de antes, que no creo ya que no tendría mucho sentido si no tener una rotación por hardware.
Al final seguí tu consejo y he dejado el sprite de una sola imagen, pero ahora me estoy peleando con los ángulos para avanzar y tal.

Ufff, en 2 días he cambiado 3 veces la forma de mover el coche, que cacao, jejeje.

Pero vamos, que es normal, es mi primer juego, tendré que cometer muchos errores.

Una pregunta (siempre estoy aprovechándome):

Para hacer bots, ¿Como los haríais? Todavía no los he empezado porque quiero tener primero acabado el coche del jugador, pero sería crear una clase que heredase de la clase Coche y donde redefiniese algunas funciones, no?

Me gustaría que me dieseis algunos consejos / ideas.

Gracias
Puedes hacer un simple if.

si el coche es controlado por el jugador, que lo mueva, si es controlado por la ai, que se mueva solo.
Ya pero el tema es como hacer que se mueva solo, ir avanzando hasta que se encuentre pared y luego empezar a girar a la izquierda, o tener una array con los valores de las posiciones por donde tiene que pasar?

Ahí está el tema...
Inteligencia articifial.

Básicamente tienes que pasar a código lo que tu harías al estar donde él.

Por ejemplo, en una recta acelerarías, al avistar una curva frenarías hasta tener una velocidad que haga que no te salgas de la carretera y girarías al entrar en la curva.

Hay dos formas de hacer esto : la basta y la fina.

La basta es hacer un precalculo de todas las posibilidades y tomar la mejor. Eso en este juego es un poco inviable porque la cantidad de posibilidades son enormes.

La fina es decirle en el momento exacto como debe actuar. así, el objeto estará en una acción a la espera de que otra orden cambie su coportamiento. El problema es como decirle "oye, hay una curva cerrada, tienes que frenar ya"). Para eso se pueden usar muchos métodos. Yo soy fiel a usar sensores. Por ejemplo, el punto de visión. Ponemos el punto a 100 píxeles en al dirección que esté mirando el coche, en el momento en el que el punto se salga de la carretera indica que hay una curva, es en ese momento en el que debes muirar si es hacia la derecha o la izquierda. También puedes poner el punto más lejos o más cerca dependiendo de la velocidad de giro del coche y de la velocidad que tenga, así si va despacio, puedes ponerlo a 32, y si va muy rápido a 150, así se simularía el tiempo de reacción. Eso sí, tendrás que hacer muchos cálculos para que no se salga.

De hecho el hecho de que el punto sea dinámico y se acerque al coche haría que este reduzca su velocidad cuanto más cerrada sea la curva. Así si es una curva poco pronunciada, al frenar un poco y girar minimamente elp unto volverá a estar en carretera, y el coche volverá a acelerar, mientras que si es cerrada, al girar un poco seguirá fuera de la carretera porque irá muy rápido y el punto estará lejos, tendría uqe estar mirando en dirección al nuevo tramo de carretera para que acelere, pero al reducir la velocidad al mínimo, llega un momento en que el punto se sitúa dentro de la carretera y el coche vuelve a acelerar siguiendo la curva.
Vale, entiendo, intentaré sacarle jugo por ahí.

Otra pregunta más (siento ser pesado).

Yo tenía hecha una función llamada ModificarMapaColisiones, que cambiaba los valores de un vector donde, por otro lado, consulto para saber si me he chocado.

Esto funcionaba bien con los Sprites de varias imágenes, pero ahora no se como hacerlo, necesito poder ver la matriz de los colores del coche, para generar los valores de colisión.

El problema es que no lo puedo hacer como hasta ahora porque solo tengo una imagen y la roto, ¿Como puedo conseguir la matriz de la imagen rotada?

Es vital para las colisiones.

Gracias por todo, sin vosotros no podría avanzar tanto y tan rápido
A modo chapuza puedes dibujar la imagen rotada en un bitmap auxiliar y usar ese bitmap para detectar colisiones.
No lo veo, porque si ahora he conseguido tener solo una imagen para representar el coche y no necesitar 30 distintas en un sprite, el cargar las posiciones solo para las colisiones me parece un engorro.

He estado leyendo otro post que tienes aquí sobre las colisiones y es interesante, según este se que tengo el método de la caja para la detección de colisiones (la verdad es que este método me lo pasaron).

Pero para que este método funcione tengo que tener el mapa de colisiones del coche, claro está, y ahí reside mi problema.
Este método lo que hace es poner un 0 o un 1 en un vector dependiendo si hay o no píxeles en un cuadrado, para ser un poco más fino obligué a que hubiese, al menos 10 pixeles para que se pusiera a 1 el valor en el vector, pero esto quedaba un poco feo porque se paraba el coche donde no debía.

No puedo hacer lo de la imagen rotada, ya que tendría 360 imágenes, porque voy girando grado a grado, necesitaría otro método más simple y efectivo, pero no se me ocurre nada.
No, no, me refería a guardar la actual en un auxiliar, no las 360. DS tiene problemas de capacidad de memoria, por lo que tener 360 es un suicidio. Solo tienes que tener una, que sea un bmp auxiliar en memoria, un buffer. En ese buffer dibujas el coche rotado y luego dibujas ese buffer en pantalla. Usando ese buffer detectas las colisiones.

Cuando vuelvas a pasar por el bucle, sobreescribes el buffer con el coche rotado de en su nuevo ángulo y listo. Solo tienes que tener dos imagenes por coche: buffer y sprite.


Otra opción es tener un mapa de bordes y usar el método vectorial. Te haces una caja con 4 vértices, y mediante aceleración rotas los vértices según el ángulo del coche. Ahora tendrás los vectores que definen el coche rotado, pero claro, eso implica tener un mapa de vectores que definan el borde de la carretera, o en su defecto ingeniartelas para detectar la colisión de un sprite con un vector.


Si quieres agrégame al msn para discutirlo allí personalmente.
Al margen de teoría de IA, que no tengo tiempo para entrar en ello, para definir si un coche está controlado por la IA o por un jugador, no hagas ifs, que es una chapuza.

La idea es que la clase coche tenga ciertas operaciones (girar, acelerar, frenar, etc) y un estado ( velocidad, dirección...). Eso es el único cometido de la clase coche.

Es otra clase externa la que tiene que operar sobre esas acciones, y ahí es donde entra la posibilidad de usar un controlador humano (mapeas el control de la consola a las acciones de la clase coche) o una IA (mapeas las decisiones de la IA a las acciones de la clase coche)

Respecto a colisiones, tienes varias opciones, dependiendo del grado de control que quieras. Puedes, por ejemplo, utilizar una caja alineada con el mundo que contenga al sprite (supongo que eso lo podrás calcular aunque sea girado). El problema es que al poner el coche en diagonal, la caja contendrá mucho espacio vacío y lo detectará como una falsa colisión. Aunque si puedes usar las colisiones entre cajas para para afinar y luego realizar una colisión por pixel. En ese caso te recomendaría usar circunferencias para la colisión inicial en vez de cajas, que es mucho más sencillo de calcular.
14 respuestas