Noticias

Importante: ¡Si quieres publicar tu juego no olvides leer este tema!

* Sponsor

Comunidad Game Maker

Bienvenid@ a la comunidad hispana de Game Maker. Nuestro objetivo es crear videojuegos y dar soporte en castellano de GM. Para mejorar nuestro servicio hemos implantado, como adicion al reglamento general, algunas normas especificas en los subforos más comunes. ¡No olvides informarte antes de participar!.

Autor Tema: Optimizar al máximo una generación de terreno MASIVA  (Leído 744 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado kostra

  • Legendario
  • *
  • Puntos: 2559
  • Mensajes: 2.096
  • Agradecido: 111 veces
  • Sexo: Femenino
  • Sé literalmente el sentido de la vida.
    • Ver Perfil
en: Febrero 03, 2021, 12:36:44 am
Buenakas! ando haciendo un plagio genérico de maincra, tengo ya 170 items programados, mecánicas sofisticadas, crafteos, construcción etc... muy muy avanzado. Y actualmente empecé a hacer pruebas para la generación de un mapa muy muy grande. El tamaño que he considerado para la room principal de la superficie, la cual trato de generar un terreno pseudo-aleatorio de tierra y más alante poner bordes de arena simulando playas, es de exactamente 12800x12800px, usando una view de 640x352px

Como la interacción con esta tierra base, es mínima y la puedo detectar de muchas maneras, he decidido usar tiles que es mil veces más eficientes que poner una cantidad muy muy masiva de objetos, aun desactivándolos a fuera de la room, entonces, mi generación consiste en un objeto, con un sprite de 2048x2048 las cuales tiene unos cuantos frames con distintas formas que funcionarán como plantillas de pseudo-aleatoriedad. Uso un objeto con este sprite, con el siguiente código:

create:
///init

//coloco el generador con el sprite plantilla en el centro de la room, snapeado a una grid de 16x16
x = floor( (room_width/2)/16 )*16;
y = floor( (room_height/2)/16 )*16;
image_speed = 0;

//el centro tendrá la plantilla del frame 0 siempre
image_index = 0;
image_angle = irandom(359);

//inicializamos variables de la generacion
procesos = 100; //veces que la plantilla cambiará de forma y se moverá de lugar
tubo = 0; //variable para controlar una barra de carga basada en los procesos

//rellenar la plantilla principal
for (var i=x-1024;i<x+1024;i+=16) {
    for (var j=y-1024;j<y+1024;j+=16) {
        if collision_point(i,j,oterraingen,true,false) {
            tile_add(tdirt,0,0,16,16,i,j,5);
            }
        }
    }

//actualizacion de variables
procesos--;
tubo++;

step:
///generar terreno

if procesos {
    //mover plantilla
    x = floor( irandom_range(2048,room_width-2048)/16 )*16;
    y = floor( irandom_range(2048,room_height-2048)/16 )*16;
   
    //cambiar de forma
    image_index = irandom(image_number-1);
    image_angle = irandom(359);
   
    //rellenar plantilla nueva con tiles
    for (var i=x-1024;i<x+1024;i+=16) {
        for (var j=y-1024;j<y+1024;j+=16) {
            if collision_point(i,j,oterraingen,true,false)
            && !tile_layer_find(5,i,j) {
                tile_add(tdirt,0,0,16,16,i,j,5);
                }
            }
        }

    //actualizacion de variables
    procesos--;
    tubo++;
    }
else {
    //volver al centro, crear al jugador y destruirse para empezar la partida
    x = room_width/2;
    y = room_height/2;
    instance_create(x,y,oplayer);
    view_object[0] = oplayer;
    instance_destroy();
    }

y de extra, irrelevante al problema, el tubo de carga en ev draw:
///draw tubo loading

var _tmaxlengh = 500;
var _tmax = 100;
var _tpos = tubo*_tmaxlengh/_tmax;

var _x = view_xview[0]+view_wview[0]/2-_tmaxlengh/2;
var _y = view_yview[0]+view_hview[0]/2;

draw_set_colour(c_black);
draw_rectangle(0,0,room_width,room_height,false);

draw_set_colour(c_white);
draw_rectangle(_x,_y-2,_x+_tmaxlengh,_y+2,true);
draw_rectangle(_x,_y-2,_x+_tpos,_y+2,false);


Una vez hayan entendido el método que hice, veo que solo con 100 procesos (y no niego que me encantarían más), se me genera un terreno (una especie de gran isla) que me acaba de gustar sin que quede tierra suelta inaccesible y/o formas muy raras que no me convencen... Observo que usar tiles, probablemente sí ayuda, incluso si están activos todos a la vez ( hablamos de +300k tiles ), pero claro, como podrán adivinar... se me tira ~20 mins generando terreno y esto me parece un problema MUY GORDO que hará que el jugador se canse de esperar y cierre el juego...

Alguna sugerencia para mejorar este método. O incluso alguna idea para tener una generación parecida aun que deba de cambiar radicalmente el método?

"ola k ase clickarme o k ase"
la imagen no se quita xD
 


No Tienes Permisos Para Dar Puntos
point 0 Puntos

Este tema no recibió puntos.


Desconectado marco13rpg

  • Visitante
  • *
  • Puntos: 13
  • Mensajes: 7
    • Ver Perfil
Respuesta #1 en: Abril 07, 2021, 10:32:29 pm
Hola! nunca he hecho algo parecido pero podrías tratar de implementar algo que utiliza el mismo minecraft para su generación de terrenos que es Perlin Noise.

Puedo agregar links?   XD

Te dejo información sobre este tema donde todo está hecho en GameMaker (inglés).

https://forum.yoyogames.com/index.php?threads/pure-gml-perlin-noise-function.25534/



 


Desconectado BssString

Respuesta #2 en: Abril 11, 2021, 09:07:57 pm
Hola kostra

Tu código de generación de terreno no es nada eficiente, falla en el Step event, en esta parte específicamente:
if procesos {
    //mover plantilla
    x = floor( irandom_range(2048,room_width-2048)/16 )*16;
    y = floor( irandom_range(2048,room_height-2048)/16 )*16;
Mueves la planitlla a una zona aleatoria del mapa 100 veces y si cae en una zona repetida, la volverá a analizar y perderá tiempo ahí, aunque no modifique las tiles, sí hace los loops y ejecuta los IFs.

Además usas la función:
if collision_point(i,j,oterraingen,true,false)
Esa función es bastante lenta, se debería usar en partes específicas. Tu for loop analiza 2048 pixeles de 16 en 16 (128 cálculos) tanto para X como para Y, lo que da como resultado que usas la función lenta 128 x 128 = 16.384 veces durante los primeros 100 step del juego.

Mi recomendación es que sigas un sistema como el que sugiere marco13rpg que no te haga repetir los cálculos en una zona que ya calculaste previamente o cambies el collision_point por un cálculo más rápido (que no sé la utilidad que cumple esa función en tu juego, no sé qué tan crítica sea para el código porque no lo entendí bien, sorry).

Saludos