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 - BssString

256
Hola Peludo

Espero que te encuentres bien, no entendí muy bien lo que intentas hacer, pero te explicaré la lógica que pense:
Debes tener 2 surfaces, una para que dibuje los bloques que se pueden pintar y otra con la pintura, luego debes superponer ambas capas donde el alpha coincide.
Para esto, Crea dos objetos, uno es el controlador que dibujará las surfaces en tu juego, el otro objeto es el bloque que pintarás, debe tener sprite y tener la casilla "Visible" desmarcada.
En el CREATE EVENT del objeto controlador debes declarar las surfaces
sur_tinta = surface_create(room_width,room_height)
sur_bloques = surface_create(room_width,room_height)

Como todo recurso dinámico, debe ser eliminado cuando ya no es necesario.
En el GAME END EVENT del objeto controlador debes eliminar las surfaces
if surface_exists(sur_tinta) surface_free(sur_tinta)
if surface_exists(sur_bloques) surface_free(sur_bloques)

Finalmente, donde ocurre la magia es en el evento de dibujo, colocaré cada línea con comentario para que entiendas su función.
En el DRAW EVENT del objeto controlador debes colocar:
surface_set_target(sur_bloques)           //Comienzas a dibujar en la surface que debe dibujar los bloques
draw_set_colour_write_enable(false,false,false,true)           //Eso hace que los próximos eventos de dibujo no dibujen los canales, rojo, verde, ni azul, sólo dibujará el canal alpha, esto es con el fin de que el color del bloque no interfiera con el color de la tinta
with obj_block draw_self()           //Esto dibuja el bloque en nuestra surface de bloques (sólo el alpha) para crear pixeles de "destino"
draw_set_colour_write_enable(true,true,true,true)             //Esto elimina la configuración anterior para que los próximos dibujos se dibujen con normalidad

draw_set_blend_mode_ext(bm_dest_alpha, bm_src_alpha)
/*El primer valor del blending mode, "bm_dest_alpha", hace que los colores del pixel a dibujar (o sea de la tinta), se multipliquen por
el alpha del destino, entonces si voy a dibujar tinta en un lienzo en blanco, no dibujaré nada, pero en cambio, si existe un bloque ahí, entonces sí dibujaré la tinta encima del bloque.
El segundo valor "bm_src_alpha", hace que los pixeles del destino (el bloque) se multipliquen por el alfa del pixel fuente, entonces sólo dibuja el bloque si hay tinta encima de él, eso evita que el bloque se dibuje como un cuadrado negro*/

draw_surface(sur_tinta,0,0)           //Esta línea superpone la surface "tinta" sobre la surface "bloques", aplicando los efectos "fuente" y "destino" del blending mode.
surface_reset_target()            //Esta línea es obligatoria después de usar el set target, es para hacer que el juego vuelva a dibujar sobre la application surface
draw_set_blend_mode(bm_normal)         //Esto regresa el blending mode a la normalidad
draw_surface(sur_bloques,0,0)         //Esto dibuja los bloques pintados en tu juego


Obviamente no verás ningún efecto si tu surface "Tinta" está vacía, esa la llenas como a ti te plazca...
Para probar si el código funciona, coloca esto en el STEP EVENT del objeto controlador:
draw_set_colour(c_red)
surface_set_target(sur_tinta)
draw_circle(mouse_x,mouse_y,12,false)
surface_reset_target()
draw_set_colour(c_black)

Eso llenará la surface TINTA con un círculo rojo en la ubicación del mouse, sólo es para que pruebes si el código funciona.

Edit: Si estás usando views por tener una room muy grande, tienes que crear las surfaces del tamaño de la view y ajustar las coordenadas finales donde dibujarás la surface a las coordenadas de la view.

Comentanos como te va.
257
Hola Ikaro3d

La versión Gratuita no debería afectar al alpha blending, mándanos tu Draw Event, aunque según yo sólo usando el draw_set_alpha debería bastar
draw_set_alpha(fuerza)
draw_rectangle(0,0,room_width,room_height,false)
draw_set_alpha(1)


Si tienes el código así, probablemente tu problema es la depth o el órden en que se estén dibujando las cosas, que ha cambiado un poco en GMS2 ahora que se crean "capas de dibujo".
Debes dibujar el rectángulo después que las demás cosas se dibujaron en tu juego, la solución más simple que veo es colocar el código que dibuja tu rectángulo en el "Draw GUI Event" o "Draw End" o alguno así.

Saludos
258
Hola somnus

Creo que tu otra consulta sobre grids tenía que ver con esta pregunta inicial, pero te respondo de todas formas...

Existe la función instance_deactivate_region(left, top, width, height, inside, notme);
Los primeros 4 parámetros son para determinar la posición en la room donde quieres desactivar objetos.
El parámetro "inside", si le pones "true" desactivas el interior de la región indicada, con "false" desactivas el exterior.
El parámetro "notme" es para evitar que el objeto que corre el código sea desactivado también.

Piensa que game maker hace un loop a través de todos los objetos para determinar si están o no están en la región dada, si tienes un montón de objeto no puedes abusar de esta función (ej usarla cada step) o podrías disminuir drásticamente el rendimiento de tu juego.

Saludos
259
Hola somnus

Como los objetos fuera de la view siguen ejecutando su draw event (afectando considerablemente el rendimiento cuando tienes miles de objetos), lo mejor es usar un sistema de grid que sólo dibuje los bloques dentro de la view.
El problema de la grid es que al no existir un objeto, no puedes usar las funciones típicas de colisión como el place_free, instance_position, place_meeting, etc...

Como alternativa para realizar la colisión, puedes ver este video de Heart Beast donde enseña una buena lógica de colisión con grids https://youtu.be/fYILA_TWIgs?t=656

Su técnica es utilizar un script para simular la función "place_meeting", pero enfocada en Grids en vez de objetos.
Él mueve el player hacia una posición objetivo, luego detecta si alguna de las 4 esquinas de su máscara de colisión entra en una muralla de la grid, luego devuelve al player a su posición original y retorna si tuvo o no tuvo colisión

El problema de esta técnica es que tu player no puede ser más grande que una celda de la grid.
ej: si tu celda mide 32x32 pixeles, entonces la mascara de colisión de tu player no puede superar ese tamaño o los bloques te pueden atravesar por el centro (ya que la colisión ocurre en las esquinas).

Aquí abajo te redacto mi script llamado "colision", que tiene la misma lógica mostrada por Heart Beast en su video, es el que yo uso para realizar mi colisión y funciona perfecto. Yo uso GMS 1.4, pero no debería ser diferente en GMS 2.
///colision(nueva_x,nueva_y)
var x1,y1,x2,y2,c1,c2,c3,c4
x1 = x //recuerda la x original para después devolverse
y1 = y //Lo mismo
x2 = argument0 //Es la x nueva en la que se detecta la colisión
y2 = argument1 //Lo mismo

//Paso 1, mueve el objeto a la posición objetivo
x = x2
y = y2

//Paso 2, convertimos las coordenadas de las 4 esquinas de la bounding box a coordenadas en la grid y trae el valor de la grid.
var cell_size = 32 //Supongamos que tu grid es de 32x32
c1 = grid[# floor(bbox_right/cell_size),floor(bbox_top/cell_size)] //Esquina superior derecha
c2 = grid[# floor(bbox_left/cell_size),floor(bbox_top/cell_size)] //Esquina superior izquierda
c3 = grid[# floor(bbox_left/cell_size),floor(bbox_bottom/cell_size)] //Esquina inferior izquierda
c4 = grid[# floor(bbox_right/cell_size),floor(bbox_bottom/cell_size)] //Esquina inferior derecha

//Paso 3, devuelve al player a su posición original
x = x1
y = y1

//Paso 4, retorna un valor como resultado del script
var muralla = 2 //Supongamos que en tu grid el valor 2 significa que hay una muralla (en mi caso 0 es vacío, 1 es suelo, 2 es muralla, así que sólo detecto colisión con las celdas de valor 2)
return (c1==muralla) || (c2==muralla) || (c3==muralla) || (c4==muralla) //Si cualquiera de las esquinas toma el valor muralla, el script detecta colisión y devuelve "true", si ninguna de las 4 esquinas tiene valor muralla, devolverá "false"


Luego usas el script en tu código de detección de la colisión de la misma forma que usarías el place_meeting.
if !colision(x+xdir,y) { x += xdir }

Saludos
260
Hola somnus

Todo depende de cómo esté diseñado tu juego. Pero un sistema de GRID es más fácil de optimizar.
Cuando tienes 5000 o 15000 objetos en tu room, usar alguna función en esos objetos hace al juego extremadamente lento, incluso abusar del uso constante de un instance_deactivate, se te hará lento.
Caso contrario ocurre con las Grid, ya que puedes trabajar sólo en el sector donde está la cámara y ejecutar una menor cantidad de cálculos por step.

Saludos
261
Preguntas y respuestas / Re:ayuda con ventajas
Julio 24, 2018, 01:36:00 AM
Hola Sr.Mojon
Para este tipo de códigos me gusta usar una ds_list que guarde el número único o nombre de la "ventaja" que ya hayas comprado.
Create event
list = ds_list_create()
En tu script de compra debes checkear si la ventaja ya fue comprada, en caso contrario se debe comprar y debes añadir la variable a la lista para indicarle al juego que es mejora ya fue comprada
if ds_list_find_index(list,ventaja) != noone {
//aquí ejecutas el código de compra
Ds_list_add(list,ventaja)
}


Cuando mueres, puedes limpiar la lista para poder volver a comprar las ventajas
ds_list_clear(list)

Como todo recurso dinámico, las ds_list son almacenadas como cache en el dispositivo y deben eliminarse cuando ya no son más necesarias para liberar la memoria.
if ds_exists(list,ds_type_list) ds_list_destroy(list)

La explicación es genérica, debes adaptarla a tu código, espero que te sirva.

Saludos
262
Hola EMiner11

Al parecer lo que causa el consumo de memoria es la creación dinámica del sprite mediante la función "sprite_create_from_surface".

Te recomiendo usar sprite_delete(spr_temp) después de haber dibujado tu sprite en el draw event.

Saludos
263
Hola Pejota.

Ahora entiendo mejor tu código, perdón...
En ese caso te sugiero duplicar todo el código para una segunda DS QUEUE.
Ej:
queue1 = ds_queue_create()
queue2 = ds_queue_create()


Crear una segunda ds_queue que guarde la vida del segundo jugador (global.vida2), duplicas el código del Create para que te llene ambas queue, duplicas el step para que se aplique también en la segunda barra de vida y duplicas el código en draw para que se dibuje la segunda barra de vida y duplicas el código de limpieza para que se eliminen las dos DS.

Como dato, no debería afectar que el número sea negativo o positivo, ya que copia el dato tal cual como lo tienes en la variable global.vida, lo importante es que dspués lo dibujes con el signo bien.

Nos comentas si funciona

Saludos
264
Hola Pejota
No entiendo tu draw event ni porqué usas -global.vida como valor en la xscale... Pero bueno, te diré la lógica que pensé y tu ves si te sirve, si la aplicas y cómo la dibujas.
Puedes crear una queue en el evento Create del personaje que guarde la vida que él tenía 1 seg atrás.
queue = ds_queue_create()
repeat (room_speed) ds_queue_enqueue(queue,global.vida)

En el STEP EVENT vas añadiendo tu vida actual a esta cola.
ds_queue_dequeue(queue)
ds_queue_enqueue(queue,global.vida)

Finalmente, en el evento draw añades una línea más que dibuje la vida que tenías 1 segundo atrás.
draw_sprite_ext (spr_vida, 0,30, 95,25,1,image_angle,c_black,1);
draw_sprite_ext (spr_vida2, 0,30, 95,-ds_queue_head(queue),1,image_angle,c_red,1); //esta línea dibujará el primer valor de la cola y le hará un color blend a c_red.
draw_sprite_ext (spr_vida2, 0,30, 95,-global.vida,1,image_angle,c_white,1);


Entonces cuando recibas por ejemplo, dos golpes seguido, tu vida bajará normalmente, pero se quedará el sprite dibujado en rojo entre medio indicando la vida que tenías 1 segundo atrás y al cabo de 1 segundo se reducirá hasta llegar a tu vida actual.

No olvides eliminar la cola con ds_queue_destroy una vez que ya no sea necesaria.
if ds_exists(queue,ds_type_queue) ds_queue_destroy(queue)

Saludos
265
Hola Hezz
Es bastante enrredado tu código, pero leyendo e interpretando lo que has escrito, me doy cuenta que el error es que estás enviando una información, pero estás leyendo otra diferente.

Antes de intentar dar con una solución, quiero comentarte que no es necesario crear un nuevo buffer cada vez que necesites uno, basta con crear uno y reutilizarlo, o si no quieres reutilizar, lo eliminas cuando ya no es útil. Los buffers son recursos dinámicos tal como los DS LIST, por lo que reservarán una parte de la memoria que tu computador le asigna a Game Maker, si creas muchos corres el riesgo de quedarte sin memoria mientras el juego está funcionando.

Ahora, detecté dos errores críticos, uno es que tu cliente, le manda al server un buffer con 3 datos de tipo "boolean"
Pero el server, lee 4!. Esto es lo que pusiste en el script "scr_received_packet" del server. Primero lees un u8
var pack = buffer_read(buffer, buffer_u8);
Y luego lees 3 boolean, pero los booleans los lees dentro de un evento "with" y los asignas como variables locales (las que se borran xD)
var key_left = buffer_read(buffer, buffer_bool);
var key_right = buffer_read(buffer, buffer_bool);
var key_jump = buffer_read(buffer, buffer_bool);


Para solucionarlo, antes que el cliente mande los 3 booleans, hace que escriba un u8 con su socket ID.
buffer_write(package, buffer_u8, global.client_id); //Esto añade mi socket ID
    buffer_write(package, buffer_bool, key_left);
    buffer_write(package, buffer_bool, key_right);
    buffer_write(package, buffer_bool, key_jump);
    network_send_packet(socket_type, package, buffer_tell(package));
    buffer_delete(package) //esto eliminará el buffer que ya ha sido utilizado y no es necesario.
}

Y en el código de lectura del cliente, debes crear las variables como "instance variables" (sin la palabra var adelante) para que se asignen al objeto del with.
key_left = buffer_read(buffer, buffer_bool);
key_right = buffer_read(buffer, buffer_bool);
key_jump = buffer_read(buffer, buffer_bool);

Eso hará que en el lado del server se le asigne las tres variables a la instance que encontró en la DS LIST.

Es complicado de explicar, espero que se haya entendido.
Nos comentas si se soluciona o si el problema persiste.

Saludos
266
Hola Hezz

A simple vista tu código se ve bien, qué información está enviando el cliente?
Puedes pegar la parte del código donde el cliente llena el buffer que le envía al server? Quizás estás pasando mal un dato o una variable.

Saludos
267
Hola Hezz
Asegúrate que la aplicación que ejecuta el código del servidor esté leyendo los packetes enviados por los clientes en el evento NETWORKING.
Si el cliente le manda un packete de datos al server, hace que el tipo de evento que genera la DS MAP del server sea la constante "network_type_data".

Saludos
268
Preguntas y respuestas / Re:balas y disparo
Julio 14, 2018, 06:14:09 PM
Muéstranos tu código, sin el código es difícil hacer un diagnóstico para detectar cuál es el problema exacto
269
Preguntas y respuestas / Re:balas y disparo
Julio 13, 2018, 06:41:16 PM
Hola Sr.Mojon.

Tal como dice 3dgeminis, tu error es sólo un problema de órden y falta de llaves.
Tu problema: A tu línea 16 le falta el signo "&&", además el código que debería ir dentro de ese IF lo pusiste en la línea 31. y en la línea 29 debería ir una llave de cierre "}"
Para solucionarlo, borra de la línea 16 a la 33 y déjalo así:
if (mouse_check_pressed(mb_left) && cargador > 0 { //verifica que hagas click y que tengas más de cero balas
instance_create(x, y, obj_bala); //dispara
sprite_index=primera_skin_disparando //cambia el sprite a disparando
cargador-- //te resta una bala de la pistola
}

if (keyboard_check_pressed(ord("R"))) {
//Si tiene 14 o más balas de respuesto
if (municion >= cargador_max {
municion -= cargador_max - cargador; //Se hace esto por si todavía quedan balas en el cargador
cargador = cargador_max;
}
//Si tiene menos de 14 balas de repuesto
else if (municion < cargador_max) {
cargador = municion;
municion = 0;
}
}


Eso debería ordenar el código y corregir el error

Saludos
270
Interesante consulta elmmertonw.
Puedes predecir la dirección y velocidad justo antes de hacer el rebote según si colisiona de forma horizontal o vertical.
digamos que tienes las variable speed y direction y te topas una muralla para hacer colisión. Intenta este código en el evento step.
var h_length = lengthdir_x(speed, direction)
var v_length = lengthdir_y(speed, direction)
if place_meeting(x+hspeed,y,obj_muralla) { h_length = -h_length  } //Calcula un rebote horizontal
if place_meeting(x,y+vspeed,obj_muralla) { v_length = -v_length  } //Calcula un rebote vertical
new_direction = point_direction(0,0,h_length,v_length) //Esta es la dirección después del rebote


Comenta si te funciona, saludos!