Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mensajes - Clamud

1201
¿Es algo parecido a Guitar Hero? Hace poco aroldhtz estaba haciendo un juego como ese y mencionó el uso de time lines, el problema era la dificultad para sincronizarlas y editarlas. He estado pensando en eso y se me ocurren dos formas de simplificar el proceso, una es crear un editor de líneas de tiempo parecido a un "tracker", y la otra es usar un tracker, imitar la melodía o el ritmo y después observar cuántos frames hay entre cada acción. Con "tracker" me refiero a esos primeros programas para escribir música en un ordenador, hay algunos nuevos y fáciles de usar como éste: http://famitracker.com/
1202
Preguntas y respuestas / Re:objeto que gira
Julio 18, 2015, 02:53:21 PM
Lo siento, pero ese archivo no se puede usar. Para exportar el proyecto completo ve al menú File > Export project o pulsa Ctrl+Alt+E.
1203
No. Debe ir en el objeto Goku normal. ¿Como se hace el cambio a ssj?
1204
Preguntas y respuestas / Re:objeto que gira
Julio 18, 2015, 03:11:08 AM
Esto se podría adaptar a tu juego: http://www.comunidadgm.org/preguntas-y-respuestas/unir-dos-objetos/
Menciona cómo funciona tu personaje (códigos de movimiento y controles), trata de explicarlo, así es más fácil ayudar.
1205
En donde se hace el cambio escribe
[gml]
view_object[0] = obj_goku_ssj;
[/gml]
1206
Es necesario redibujar la ventana con cada cambio realizado, si los scripts funcionan con ciclos for (u otros ciclos) no es posible porque sólo se permite dibujar en los eventos Draw (en versiones anteriores a GMS si se podía). Lo mejor es usar una variable para indicar que se está haciendo el proceso de escaneo, durante ese tiempo los objetos no deben reaccionar a la interacción del jugador. Los ciclos deben ser "externos" de modo que se realicen en varios steps y así ejecutar el evento Draw varias veces hasta que se terminen. Por ejemplo, digamos que el controlador inicia el ciclo
[gml]
//Iniciar ciclo
global.ciclo = true;
global.i = 0;
[/gml]
y en el evento Step del controlador se modifica y se comprueba la variable global.i
[gml]
if( global.i < limite ) global.i++;
else global.ciclo = false;
[/gml]
las otras instancias pueden saltar los códigos de interacción con el jugador así
[gml]
if( global.ciclo ) exit;
[/gml]
1208
Antes de profundizar en el código para arrastrar la pieza, es necesario revisar el código para seleccionar; en el evento Left Pressed se tiene lo siguiente
[gml]
///Seleccionar pieza

//solo se puede seleccionar en estado activo
if( ESTADO == ACTIVO )
{
    if( global.seleccion <> noone ) //si hay una pieza seleccionada
    if( global.seleccion.depth < depth ) //y su profundidad de es menor
        exit; //salir
       
    global.seleccion = id; //seleccionar esta pieza
    rx = mouse_x - x; //posicion relativa
    ry = mouse_y - y; // al puntero
}
[/gml]
Primero se revisa que el estado es ACTIVO, después, si ya hay una pieza seleccionada se hace una comparación de profundidades, si la pieza seleccionada tiene una profundidad menor ya no tiene caso continuar y se escribe exit.
Si no se cumplen las condiciones anteriores la pieza actual tiene posibilidades de quedar seleccionada, entonces se guarda el id y se calcula la posición relativa al puntero.

Cuando termina la iteración del código de selección en todas las piezas, la que queda seleccionada se puede arrastrar (en el evento Step)
[gml]
///Arrastrar

if( ESTADO == ACTIVO ) //si esta activa
if( global.seleccion == id ) //y seleccionada
{
    if( depth <> 0 ) //si la profundidad es diferente de cero
    {
        for( i=depth; i>0; i-=1 ) //para las piezas que tienen menor profundidad
        {
            global.lista[|i] = global.lista[|i-1]; //recorrer un lugar
            global.lista[|i].depth += 1; //aumentar la profundidad
        }
        depth = 0; //esta se coloca encima de otras piezas
        global.lista[|0] = id;
    }
    x = mouse_x - rx; //se puede arrastrar
    y = mouse_y - ry;
}
[/gml]
Como en el código previo, se revisa que el estado es ACTIVO, después se revisa que la pieza está seleccionada. Ahora viene la parte complicada, si la pieza tiene profundidad diferente de cero, es posible que esté parcialmente cubierta por otra pieza, pero se necesita que la pieza esté completamente visible, para logar ese objetivo la pieza actual se coloca en profundidad cero y las demás piezas aumentan de profundidad. El siguiente diagrama puede ayudar a entender el algoritmo


  • Las piezas tienen profundidades de 0 a 8, que se asignaron de forma aleatoria.
  • Se selecciona una pieza que no tiene profundidad cero, entonces la sacamos temporalmente de la lista.
  • Las demás piezas se recorren para ocupar el lugar vacío, aumentando su profundidad.
  • La pieza seleccionada se reinserta en la posición cero, y su profundidad se hace cero.

Vamos a observar qué sucede al soltar la pieza, en el Evento Left Released
[gml]
///Soltar pieza

if( ESTADO = ACTIVO ) //si esta activa
if( global.seleccion = id ) //y esta seleccionada
{
    global.seleccion = noone; //seleccionar nada
   
    //si esta cerca de la posicion correcta
    if( point_distance(x,y,xstart,ystart) < 64 )
    {
        x = xstart; //plop
        y = ystart;
        ESTADO = CALZA; //cambiar estado
        global.calzadas += 1; //incrementar contador
    }
}
[/gml]
Se reutilizan las 2 primeras líneas, después se indica que no hay nada seleccionado. Abajo se hace el efecto "snap"; se han agregado 2 líneas, una incrementa el contador de piezas calzadas y otra cambia el estado de la pieza. Entre esas líneas se puede reproducir el sonido "plop" que mencionado.

Sólo falta ver el código que determina que el rompecabezas se ha completado. Se encuentra en obControl, en el evento Begin Step
[gml]
///Nivel completado!

if( global.calzadas == 9 )
{
    show_message( "Nivel completado!" );
    global.calzadas = 0; //no mostrar el mensaje otra vez
}
[/gml]
Es bastante sencillo, se comprueba que el número de piezas calzadas es igual al número total de piezas, se muestra un mensaje y la variable global.calzadas se reinicia para no mostrar el mensaje constantemente. En esta demo no ocurre nada mas, bueno, se puede mezclar otra vez. Vale la pena mencionar que la función show_message() sólo se recomienda en Windows.

Esto ha quedado bastante extenso, y eso que es la parte fácil, aún quedan un montón de detalles por agregar y muchas pruebas por hacer. Intentaré ayudar en lo posible, hasta pronto.
1209
Ahora sí, comenzaré a explicar el funcionamiento de del proyecto. He procurado hacerlo lo más sencillo posible, aún así, su nivel de complejidad ha aumentado bastante.

También he subido una nueva versión, en la que se soluciona el comportamiento extraño de las piezas. El problema era suponer que al cambiar la depth también se cambia el orden de los eventos de las instancias, como sucede en GM8, sin embargo, en GMS sólo se cambia el orden de los eventos Draw. Al hacer click en una pieza no se seleccionaba la de menor profundidad, en cambio, se seleccionaba la última que fue creada. Al soltar la pieza seleccionada no quedaba encima, y a veces la profundidad cambiaba de forma extraña. El nuevo método de selección evalúa la depth y usa una lista para guardar los ids en orden de profundidad.

El nuevo comportamiento de la variable depth en GMS ha complicado un poco las cosas. Se han empleado algunos recursos que por lo general son difíciles de dominar por los que inician. Esta forma de seleccionar se podría evitar si se diseña un sistema que no permita la superposición de muchas piezas a la vez, no obstante, el diseño de ese sistema es más complicado.
Aunque en GM8 el sistema funciona bien, no es a prueba de errores. El nuevo sistema es más robusto en lo 2 casos.



Primero se han agregado las siguientes variables al controlador
[gml]
btn_mezclar = false; //estado del boton mezclar
global.calzadas = 0; //numero de piezas calzadas
global.lista = ds_list_create(); //para guardar los ids
[/gml]
para entender la última linea, leer Data Structures en el manual.
Cuando se crean las piezas (con el doble ciclo for) también se guardan los ids
[gml]
...
ds_list_add( global.lista, id ); //guardar id
...
[/gml]

Pasemos al objeto pieza. Según la descripción que diste en mensajes anteriores, se pueden identificar 3 estados:
Al iniciar el nivel el rompecabezas está armado, las piezas inmóviles y no pueden ser arrastradas, llamemos CALZA a este estado.
Al presionar el botón "mezclar" las piezas se dispersan, en este estado, que llamaremos MEZCLA, las piezas no pueden ser desplazadas manualmente.
Una vez dispersas, el usuario puede arrastrar las piezas y armar el rompecabezas, el estado se llama ACTIVO.
Cuando el usuario suelta una pieza cerca o en la posición correcta la pieza se bloquea y no puede ser arrastrada, por lo tanto regresa al estado CALZA.
(Siento que los nombres de los estados y las variables no son muy buenos, tal vez puedas mejoralos XD.)

En el evento Create de obPieza se definen los estados
[gml]
///Estados

CALZA  = 0; //en posicion correcta
MEZCLA = 1; //al oprimir el boton mezclar
ACTIVO = 2; //se puede arrastrar

ESTADO = CALZA;
[/gml]
El uso de una variable estado es muy útil en la programación porque evitamos tener que usar muchos objetos y el código queda bien organizado.

El objeto controlador se encarga de dibujar el botón "mezclar", usando el script scTextoBoton, si lo deseas, el siguiente código se puede usar un un objeto aparte que actúe como botón.
[gml]
///Mezclar piezas

//si se presiona el boton mezclar
if( btn_mezclar )
{
    ds_list_shuffle( global.lista ); //desordenar lista
    global.calzadas = 0; //cero piezas calzadas
    //
    with( obPieza ) //con todos los objetos pieza
    {
        ESTADO = MEZCLA; //cambiar estado
        xfinal = irandom_range( 480,768 ); //posicion final
        yfinal = irandom_range( 64, 448 );
        depth = ds_list_find_index( global.lista, id ); //profundidad aleatoria
    }
}
[/gml]
Aquí se emplea la lista para asignar la profundidad, las piezas quedan con una profundidad aleatoria (de 0 a 8 ) sin repetirse. El estado cambia al apropiado. Y las variables xfinal,yfinal se definen aleatoriamente entre los límites de un rectángulo imaginario en la parte derecha de la ventana.

Como las piezas se encuentran en el estado MEZCLA, ejecutan el sig. código en Step
[gml]
///Mezclar

if( ESTADO = MEZCLA ) //mezclando
{
    if mp_linear_step( xfinal,yfinal,32, false ) //mover linealmente
        ESTADO = ACTIVO; //cambiar estado al llegar a la pos. final
}
[/gml]
(revisa el manual por información adicional)
Cuando la pieza llega a su posición final el estado cambia a ACTIVO y se puede arrastrar
[gml]
///Arrastrar

if( ESTADO == ACTIVO ) //si esta activa
if( global.seleccion == id ) //y seleccionada
{
    if( depth <> 0 ) //si la profundidad es diferente de cero
    {
        for( i=depth; i>0; i-=1 ) //para las piezas que tienen menor profundidad
        {
            global.lista[|i] = global.lista[|i-1]; //recorrer un lugar
            global.lista[|i].depth += 1; //aumentar la profundidad
        }
        depth = 0; //esta se coloca encima de otras piezas
        global.lista[|0] = id;
    }
    x = mouse_x - rx; //se puede arrastrar
    y = mouse_y - ry;
}
[/gml]
Aquí se emplea nuevamente la lista y se usa una sintaxis que se explica en la sección Accesors del manual.

Mas tarde continuaré la explicación.  ;)
1210
El error debe estar en el evento Create del controlador, ¿se borró la línea de declara la variable?

Acabo de hacer una actualización al motor, hoy no me va a dar tiempo de dar una explicación, funciona bien en :GM8:, pero hay algunos comportamientos extraños en :GMS: (nada grave). Hasta luego.
1211
Aparece cuando se dibujan muchas cosas a la vez dentro de GMS, por ejemplo, muchas ventanas abiertas al mismo tiempo o editando una room muy grande. No es peligroso y se soluciona temporalmente reiniciando GMS. Dicen que el error estará arreglado en la próxima actualización.
http://gmc.yoyogames.com/index.php?showtopic=628178
http://bugs.yoyogames.com/view.php?id=15818
1212
Falta declarar la variable en el evento Create
[gml]contacto = false;[/gml]
1213
Escribe esto en el evento de colisión de uno de los objetos:
[gml]
if( image_index == other.image_index )
{
     //Acciones
}
[/gml]
Con ese código las acciones se repetirán mientras los dos objetos estén en contacto, para ejecutar las acciones sólo una vez, cuando colisionen por primera vez, debes agregar otra variable en el evento Create, por ejemplo contacto = false y cambiar el código anterior por el siguiente:
[gml]
if( image_index == other.image_index and contacto == false )
{
    contacto = true;
    //Acciones
}
[/gml]
1214
Todo lo que comentas es posible con GM. Los menús, los sonidos y las animaciones son relativamente fáciles de hacer, lo que es más complicado es recortar la imagen dentro del juego (sobre todo para ti que estás empezando), aunque a veces las cosas complicadas resultan sencillas al final, de todos modos necesitas estudiar un poco sobre primitivas y surfaces. Voy a pensar en un algoritmo sencillo que distribuya las piezas de forma vistosa.
1215
Se puede hacer como mencionó 3dgeminis o también con un solo sprite a la vez, lo importante es que las 2 animaciones tengan el mismo número de subimágenes. Si se hace con un sprite a la vez, sólo se necesita cambiar la variable sprite_index, la varible image_index mantiene su valor por eso las animaciones quedan sincronizadas.