Hola quisiera saber como crear una cámara 3d que sea como la versión 3d del juego de Yume niki , se que es parecida a una cámara de fps pero no se como hacer el movimiento que tiene la cámara al mover el personaje
(https://vignette4.wikia.nocookie.net/yumenikkifg/images/a/a9/Yume_Nikki_3d_v_0.02_gameplay_video/revision/latest/scale-to-width-down/335?cb=20131005173347)
hola tal vez esto te sirva, esperando que alguien te de mejor respuesta
http://www.comunidadgm.org/preguntas-y-respuestas/como-hacer-camara-en-tercera-persona-para-un-juego-estilo-mario-kart/msg93574/#msg93574
Crea dos objetos: el personaje y la cámara. El personaje es el punto de rotación y la cámara lo sigue. La cámara debe tener más profundidad (depth) que los otros objetos, para que la proyección 3D sea establecida antes de que los demás objetos comiencen a dibujar.
En el evento Create de la cámara inicia el modo 3D, coloca el mouse en el centro de la pantalla y define sus coordenadas esféricas relativas al personaje
https://es.wikipedia.org/wiki/Coordenadas_esf%C3%A9ricas
[gml]
// Iniciar 3D
d3d_start();
d3d_set_culling( true );
draw_set_color( c_white );
// Mouse en el centro de la pantalla
centro_h = display_get_width() / 2;
centro_v = display_get_height() / 2;
display_mouse_set( centro_h, centro_v );
// Coordenadas esfericas
direction = point_direction( obJugador.x,obJugador.y, x,y );
elevacion = 45;
distancia = 128;
[/gml]
En el evento Draw de la cámara calcula las coordenadas cartesianas a partir de las coordenadas esféricas y establece la proyección 3D
[gml]
// Coordenadas cartesianas
x = lengthdir_x(distancia,elevacion) * lengthdir_x(1,direction) + obJugador.x;
y = lengthdir_x(distancia,elevacion) * lengthdir_y(1,direction) + obJugador.y;
z = -lengthdir_y(distancia,elevacion) + 16;
// Proyeccion
d3d_set_projection( x,y,z, obJugador.x,obJugador.y,16, 0,0,1 );
[/gml]
En el evento Step de la cámara controla la posición de la cámara con el ratón
[gml]
// Controlar con raton
direction += (centro_h - display_mouse_get_x()) / 10;
elevacion += (display_mouse_get_y() - centro_v) / 10;
elevacion = median( 0, 89, elevacion );
// volver a colocar el mouse en el centro de la pantalla
display_mouse_set( centro_h, centro_v );
[/gml]
En Yume Nikki 3D la cámara detecta colisiones para que no pueda ver a través de las paredes. El sistema de colisión depende de cómo están definidas las paredes.
El personaje se mueve tomando en cuenta la posición de la cámara, después mostraré un método.
Hola gracias por responder la cámara funciona bastante bien , pero como hago para que el personaje rote lo tenia programado para que solo se moviera con las teclas de direccion
sin rotar y ahora cuando muevo la cámara con el mouse pierdo de vista al personaje, el personaje lo dibujo con draw_wall
Cita de: Clamud en Septiembre 01, 2017, 04:16:44 PM
Crea dos objetos: el personaje y la cámara. El personaje es el punto de rotación y la cámara lo sigue. La cámara debe tener más profundidad (depth) que los otros objetos, para que la proyección 3D sea establecida antes de que los demás objetos comiencen a dibujar.
En el evento Create de la cámara inicia el modo 3D, coloca el mouse en el centro de la pantalla y define sus coordenadas esféricas relativas al personaje
https://es.wikipedia.org/wiki/Coordenadas_esf%C3%A9ricas
[gml]
// Iniciar 3D
d3d_start();
d3d_set_culling( true );
draw_set_color( c_white );
// Mouse en el centro de la pantalla
centro_h = display_get_width() / 2;
centro_v = display_get_height() / 2;
display_mouse_set( centro_h, centro_v );
// Coordenadas esfericas
direction = point_direction( obJugador.x,obJugador.y, x,y );
elevacion = 45;
distancia = 128;
[/gml]
En el evento Draw de la cámara calcula las coordenadas cartesianas a partir de las coordenadas esféricas y establece la proyección 3D
[gml]
// Coordenadas cartesianas
x = lengthdir_x(distancia,elevacion) * lengthdir_x(1,direction) + obJugador.x;
y = lengthdir_x(distancia,elevacion) * lengthdir_y(1,direction) + obJugador.y;
z = -lengthdir_y(distancia,elevacion) + 16;
// Proyeccion
d3d_set_projection( x,y,z, obJugador.x,obJugador.y,16, 0,0,1 );
[/gml]
En el evento Step de la cámara controla la posición de la cámara con el ratón
[gml]
// Controlar con raton
direction += (centro_h - display_mouse_get_x()) / 10;
elevacion += (display_mouse_get_y() - centro_v) / 10;
elevacion = median( 0, 89, elevacion );
// volver a colocar el mouse en el centro de la pantalla
display_mouse_set( centro_h, centro_v );
[/gml]
En Yume Nikki 3D la cámara detecta colisiones para que no pueda ver a través de las paredes. El sistema de colisión depende de cómo están definidas las paredes.
El personaje se mueve tomando en cuenta la posición de la cámara, después mostraré un método.
alguien sabe hacer lo que dice Ares074 creo que nos ayudarian a muchos...una vez encontre una engine 3d muy buena cuyo unico defecto era que no seguia al personaje por la espalda, habia que estar acomodando la camara manualmente lo que era engoroso y poco practico..
Para dibujar el personaje se pueden usar varios métodos. Uno es dibujar con d3d_draw_wall:
[gml]
// calcular extremos
x1 = x + lengthdir_x(8, obCamara.direction + 90);
y1 = y + lengthdir_y(8, obCamara.direction + 90);
x2 = x + lengthdir_x(8, obCamara.direction - 90);
y2 = y + lengthdir_y(8, obCamara.direction - 90);
z1 = 0;
z2 = 16;
// dibujar plano
d3d_draw_wall( x1,y1,z1, x2,y2,z2, tex,1,1 );
[/gml]
Otro es usar un modelo y transformaciones:
[gml]
// Evento Create
// Modelo
mdl = d3d_model_create();
d3d_model_wall( mdl, 0,-8,0, 0,8,16, 1,1 );
[/gml]
[gml]
// Evento Draw
d3d_transform_set_rotation_z( obCamara.direction );
d3d_transform_add_translation( x,y,0 );
d3d_model_draw( mdl, 0,0,0, tex );
d3d_transform_set_identity();
[/gml]
Dejo un ejemplo adjunto. Camina con WASD, y con M se cambia entre los dos métodos.
Gracias creo que ya quedo solo me faltaría lo de las colisiones de las paredes con la cámara esperare el método :)
Dejo una captura
(http://oi67.tinypic.com/15eb6ae.jpg)
Cita de: Clamud en Septiembre 02, 2017, 08:30:42 PM
Para dibujar el personaje se pueden usar varios métodos. Uno es dibujar con d3d_draw_wall:
[gml]
// calcular extremos
x1 = x + lengthdir_x(8, obCamara.direction + 90);
y1 = y + lengthdir_y(8, obCamara.direction + 90);
x2 = x + lengthdir_x(8, obCamara.direction - 90);
y2 = y + lengthdir_y(8, obCamara.direction - 90);
z1 = 0;
z2 = 16;
// dibujar plano
d3d_draw_wall( x1,y1,z1, x2,y2,z2, tex,1,1 );
[/gml]
Otro es usar un modelo y transformaciones:
[gml]
// Evento Create
// Modelo
mdl = d3d_model_create();
d3d_model_wall( mdl, 0,-8,0, 0,8,16, 1,1 );
[/gml]
[gml]
// Evento Draw
d3d_transform_set_rotation_z( obCamara.direction );
d3d_transform_add_translation( x,y,0 );
d3d_model_draw( mdl, 0,0,0, tex );
d3d_transform_set_identity();
[/gml]
Dejo un ejemplo adjunto. Camina con WASD, y con M se cambia entre los dos métodos.
Esa imagen se ve muy bien, tengo ganas de probar el juego.
Supongo que los muros son bloques en el editor de rooms. Lo más fácil que se me ocurre es usar la función collsion_line para ver si hay un muro entre el jugador y la cámara, si es así, la distancia se reduce hasta que ya no hay colisión. Se pueden usar métodos más optimizados, pero más complicados, creo que esto debe funcionar bien. Hay que eliminar la parte que calcula las coordenadas cartesianas en el ejemplo anterior y sustituirla por esto:
[gml]
// longitudes del vector unitario que
// apunta del jugador a la camara
uw = lengthdir_x(1 ,elevacion);
ux = lengthdir_x(uw,direction);
uy = lengthdir_y(uw,direction);
uz = lengthdir_y(1 ,elevacion);
r = distancia;
c = true; //condicion
// repetir hasta que la linea que va de la camara al jugador este libre de
// colision, o se alcance la distancia minima entre la camara y el jugador
while( true ){
//calcular posicion
x = r*ux + obJugador.x;
y = r*uy + obJugador.y;
if( r <= 10 )break; //si se alcanza la distancia minima, terminar bucle
c = collision_line(x,y, obJugador.x,obJugador.y, obMuro,false,true);
if( c == false )break; //si no hay colision, terminar bucle
else r -= 10; //si hay colision, disminuir la distancia
}
z = r*uz + obJugador.z; //calcuar posicion faltante
if( z > 50 )z = 50; //no colisionar con el techo
[/gml]
Hola ya lo hice pero me sale error en Variable obj_player2.<unknown variable>(100010, -2147483648) not set before reading it.
at gml_Object_obCamara_DrawEvent_1 (line 34) - z = r*uz + obj_player2.z; //calcuar posicion faltante, obj_player2 es el nombre de mi personaje
uw = lengthdir_x(1 ,elevacion);
ux = lengthdir_x(uw,direction);
uy = lengthdir_y(uw,direction);
uz = lengthdir_y(1 ,elevacion);
r = distancia;
c = true; //condicion
// repetir hasta que la linea que va de la camara al jugador este libre de
// colision, o se alcance la distancia minima entre la camara y el jugador
while( true ){
//calcular posicion
x = r*ux + obj_player2.x;
y = r*uy + obj_player2.y;
if( r <= 10 )break; //si se alcanza la distancia minima, terminar bucle
c = collision_line(x,y, obj_player2.x,obj_player2.y, obj_pared,false,true);
if( c == false )break; //si no hay colision, terminar bucle
else r -= 10; //si hay colision, disminuir la distancia
}
z = r*uz + obj_player2.z; //calcuar posicion faltante
if( z > 50 )z = 50; //no colisionar con el techo
// Establecer proyeccion
d3d_set_projection( x,y,z, obj_player2.x,obj_player2.y,16, 0,0,1 );
draw_set_color( c_white );
dark_purple = make_colour_rgb(27,3,59);
d3d_set_fog(true,dark_purple,228,512)
Es por esto: obj_player2.z. El objeto no tiene definida la variable z, simplemente cambia esa parte por 16 (es el valor que usé en otros lugares del código), o define la variable z en obj_player2 (si después quieres hacer que el personaje salte vas a necesitar esa variable).
Hola gracias por ayudarme, tuve que cambiar la variable r <= 10 por 80 por que el personaje se mira muy cerca de la pantalla , no se si por eso no funciona bien la colisión con las paredes
Adjunte el archivo gmz para que lo veas mejor ,igual también le sirve a alguien de ejemplo
Pensé que collision_line devolvía true o false, pero devuelve el id de una instancia encontrada en la colisión. Modifiqué dos líneas
[gml]
c = collision_line(x,y, obj_player2.x,obj_player2.y, obj_colision,false,true);
if( c == noone )break; //si no hay colision, terminar bucle
[/gml]
Modifiqué otros detalles: La colisión de la cámara ahora se revisa en End Step, el personaje se dibuja con un modelo, se cambiaron dos signos de la función que dibuja el piso para poder usar d3d_set_culling(true) sin problemas, el background del que se obtiene la textura del personaje ya no está invertido. Archivo gmz adjunto.
Me di cuenta de que este método de reducir la distancia no se ve muy bien, el cambio de distancia se hace escalonado. Para mejorarlo se puede usar un script que devuelva el punto de colisión con el muro de un rayo imaginario que va del personaje a la cámara. Se pueden usar dos métodos:
https://yal.cc/gamemaker-collision-line-point/
http://gmc.yoyogames.com/index.php?showtopic=479678
Hola la cámara funciona bien pero tienes razón se ve escalonado así que puse el script de la pagina https://yal.cc/gamemaker-collision-line-point/ (https://yal.cc/gamemaker-collision-line-point/)
Asy lo puse en el evento end step de la cámara
var r = collision_line_point(x, y, obj_player2.x, obj_player2.y, obj_colision, false, true);
//draw_line(x, y, r[1], r[2]);
if (r[0] == noone) break;
else a -=1; //holds the nearest (hit) instance.
Cambie la variable r de distancia por a , la variable a para disminuir la distancia estaba en -10 la cambie a -1 el movimiento de la cámara se va mas suave por que disminuye mas lento lo que ase que al girar se mire algo lento no se si estoy implementando bien el script o se puede mejorar , segun la versiones de GMS de 1.4.1760 tienen la opción de fast collision system intente buscar una versión actualizada a ver si mejoraba pero no la encontré.
De esa forma no se está aprovechando la utilidad del script. Cuando se detecta colisión la cámara se debe mover justo al punto donde el rayo colisiona con el muro, ese punto lo calcula el script.
Quise ver cómo funcionaba y cambié todo el ciclo while en obj_camara por esto
[gml]
c = collision_line_point(obj_player2.x,obj_player2.y, x,y, obj_colision,false,true);
if( c[0] <> noone ){
x = c[1];
y = c[2];
d = point_distance(obj_player2.x,obj_player2.y, x,y) / uw;
}
z = d*uz + obj_player2.z + 35; //volver a calcular z
[/gml]
Pero después no me gustó el movimiento de la cámara al colisionar con el piso y el techo, entonces cambié todo el código de colisión
[gml]
/// Colisiones de la camara v0.2
// longitudes del vector unitario que apunta del jugador a la camara
uw = lengthdir_x( 1,elevacion);
ux = lengthdir_x(uw,direction);
uy = lengthdir_y(uw,direction);
uz = lengthdir_y(-1,elevacion);
d = distancia; //d se va a reducir si hay colisiones
z = d*uz + obj_player2.z + 35; //calcular z
if( z > 55 ){
z = 55; //no colisionar con el techo
d = (z - obj_player2.z - 35) / uz; //reducir d
}
if( z < 5 ){
z = 5; //no colisionar con el piso
d = (z - obj_player2.z - 35) / uz; //reducir d
}
// coordenadas en el plano horizontal
x = d*ux + obj_player2.x;
y = d*uy + obj_player2.y;
// detectar colision con los muros
c = collision_line_point(obj_player2.x,obj_player2.y, x,y, obj_colision,false,true);
if( c[0] <> noone ){ //si se detecta colision
x = c[1]; //mover la camara al punto de colision
y = c[2];
d = point_distance(obj_player2.x,obj_player2.y, x,y) / uw; //reducir d
}
z = d*uz + obj_player2.z + 35; //volver a calcular z
[/gml]
Me gustaría explicar el código, pero hoy no tengo mucho tiempo. Todo se explica con triángulos semejantes y trigonometría.
Hola gracias ya quedo bastante bien ahora tengo una duda se puede animar el personaje si esta dibujado como modelo , daré el tema como solucionado gracias :)
En vez de usar un background como textura usa un sprite con varias sub-imágenes.
En algún lugar del código asigna el sprite y la velocidad de animación
[gml]
sprite_index = spr_caminar;
image_speed = 0.3;
[/gml]
En el evento Draw obtén la textura de la sub-imagen actual
[gml]
tx = sprite_get_texture(sprite_index, image_index);
d3d_transform_set_rotation_z( obCamara.direction );
d3d_transform_add_translation( x,y,z );
d3d_model_draw(mdl, 0,0,0, tx);
[/gml]
Ok, gracias con eso ya puedo continuar con el juego