En este
comentario, me jacté de haber escrito un programa que creó un bosque "decente" en doscientas líneas de código. Desafortunadamente, la realidad resultó ser un poco más grande: las fuentes excavadas contienen alrededor de 2100 líneas de código, de las cuales alrededor de 700 son comentarios, pensamientos en voz alta, código viejo descartado e intentos de documentar métodos. Sin embargo, el tamaño del ejecutable SWF resultó ser 13112 bytes.
Todo comenzó con el hecho de que en el foro Kongregate.com, donde estaba pasando el rato activamente en ese momento, uno de los participantes sugirió competir en la generación procesal de algo, el primer tema fue
"Bosque" .

Naturalmente, todos tenían su propia idea de lo que debería ser el bosque que cultivarían. En ese momento leí libros sobre todo tipo de magia, como resultado, quería cultivar un bosque. El bosque está formado por árboles: escribimos la clase Árbol {...}. Un árbol consta de ramas y hojas: escribimos la clase Rama {...} y pensamos, ¿realmente necesitamos tener en cuenta cada hoja del árbol? Como resultado, la "rama" adquirió el parámetro "con hojas", y el árbol adquirió un par de texturas, una para las ramas y un tronco, una para las hojas. La textura "debajo del árbol" era relativamente simple de hacer: hay un ruido de perlin, puedes estirarlo, envolverlo, pintarlo, considerarlo listo, pero tenías que jugar con las hojas.
Sin embargo, no estaba contento con solo el ruido de la guinda de la textura de un árbol; en su lugar, se me ocurrió un mapa de relieve, es decir Creó un mapa de altura, lo ajustó debajo del semicírculo de la rama visible desde el lado, luego rellenó la textura principal con marrón y superpuso un mapa de altura con la iluminación ajustada al chirrido lateral. El código resultante es el siguiente:
private function generateBranch():void { branchBitmap = new BitmapData(512, 512, true, 0xff8080ff);
"Basis" es una clase auxiliar para vectores a la Vector3D, pero como el código fue escrito en Flash 10.1, todavía no existían tales vectores, o preferí hacer mi propia bicicleta. La textura debajo de la rama con hojas se dibujó de la siguiente manera: al principio se hizo una hoja, luego se determinó si las ramas tenían una hoja central, esto determinó la longitud de la pieza de la rama a la que se unieron las hojas, luego se unieron (calculado sobre la textura) en un ángulo a la rama por el ancho calculado de la hoja . La forma de la hoja se estableció como un círculo distorsionado con varios puntos de referencia desplazados del círculo por un radio de media hoja, y la longitud de los esquejes se estableció por separado, todo esto se dibujó en la textura de la hoja en blanco y negro y se guardó para el futuro. (Más precisamente, había dos texturas de "rama con hojas", una para los extremos, es decir, ramas para las que nada crece desde el "extremo", pero con hojas, se dibujó una hoja al final de la rama, la segunda para "medio "Sin hoja final.)
Entonces la parte más difícil es ¿cómo se verá el árbol? Aquí pensé y experimenté durante mucho tiempo. Decidí hacer que el árbol realmente creciera: las ramas se extienden en longitud (en realidad crecen desde el extremo), a veces generan ramas a un lado, las ramas se extienden hacia el sol (hacia arriba) y un par de condiciones más. Resultó un hash terrible, la mejor opción que pudimos compartir se veía así:
(Curiosamente, diary.ru es un excelente servicio de alojamiento de fotos, ¡hasta ahora nada ha salido mal!)Llegué a la conclusión de que necesitamos reducir de alguna manera la densidad de las ramas. Inicialmente, la idea era limitarlos gravitacionalmente, es decir, ramas demasiado "pesadas" simplemente se rompen y caen. Comencé a contar el momento de fuerza en la flexión, comparándolo con la fuerza del árbol (arrastré los valores desde algún lugar, lo califiqué como constantes y comencé a probar): resultó mal, a veces el tronco se rompió, aunque no debería haber sucedido, y el árbol se dobló con seguridad , a veces una rama grande se rompió al principio, el resultado condujo a un tronco desequilibrado y se rompió nuevamente, esta vez debido a una pérdida de equilibrio vertical, y a veces una rama que era bastante normal en estructura, creciendo en grosor, inicialmente doblada bajo su peso, luego quiebra, ventas si no hay nada en ella ya no se creció. Marcó porque el desafío era una fecha límite.
El segundo intento fue limitar tanto el crecimiento de nuevas ramas como la supervivencia de las antiguas / anteriores utilizando iluminación. Desde el tercer intento de implementación (los dos primeros permanecieron en forma de funciones comentadas) resultó así: construí una red de vóxeles tridimensional con un lado de 0.5 metros (sí, todos los valores que había en metros y kilogramos; realmente quería física real para un bosque real en ese momento), que estaba lleno al principio ceros, luego, al rodear el árbol, cada rama contribuía al relleno de la red en forma de volumen dividido por uno o dos vóxeles. El hecho es que todas las ramas (en cualquier caso, casi todas) como piezas separadas del marco calculado eran más cortas que 0.5m, lo que nos permitió usar una aproximación aproximada. Además del relleno, cada rama "proyecta una sombra" en los vóxeles subyacentes en forma de relleno adicional de los vóxeles debajo y ligeramente alrededor del vóxel con una rama (la forma final es una pirámide cuadrada, pero jugar con un círculo se rompía y, por lo tanto, no se iluminaba de todos modos). Este enrejado se usó como un limitador, si una de las ramas comienza a crecer en el medio del árbol: tendrá menos luz allí, será más corta y es posible que no crezca en absoluto o muera por falta de iluminación. Las ramas muertas se cayeron.
Esta opción hizo posible obtener árboles que eran relativamente transparentes cuando se veían y relativamente compactos en términos de alcance, la primera versión de trabajo se veía así:

En esta versión, todavía depuré el mecanismo de crecimiento del árbol, y el árbol se podía ver desde todos los lados. Se dibujó un árbol una rama a la vez, la matriz de ramas se ordenó primero por distancia del observador, ya que en el viejo curso VMX sobre gráficos tridimensionales de 1996, seleccioné colores con fines cosméticos del rango HSB para cada llamada "dibujame un árbol" para que el bosque no sea monótono, el esqueleto del árbol también se gira al azar para dibujar. En total, había de seis a ocho modelos de árboles para dibujar, cada uno creciendo bajo su propia influencia de RNG, el paisaje de la tierra produjo otro ruido de guinda, y el lugar donde cultivar el árbol se seleccionó al azar usando un conjunto de rangos de puntos permitidos para el crecimiento al moverse hacia un lado observador a distancia. Si el árbol se plantó en el punto A, y el radio del árbol R seleccionado para "crecer", entonces los valores (AR, A + R) quedaron prohibidos para el crecimiento a la distancia actual, al pasar al siguiente (-0.05) este intervalo disminuyó en 0.1, y se eliminó cuando se redujo a cero.
El último (y de hecho el primer e inmediatamente considerado) matiz de todo el algoritmo es que es MUY LARGO. Para recorrer el árbol "adulto", se necesitan unos segundos para dibujar, unos pocos más para dibujar las texturas de un árbol, se tarda de medio segundo a dos, y Adobe Flash no está diseñado para intervalos de cálculo tan largos sin actualizar la pantalla (más precisamente, sin devolver el control al motor) . Por lo tanto, necesitábamos un algoritmo que supiera cómo mantener el estado entre llamadas, continuar trabajando desde el lugar donde fue interrumpido y controlar su tiempo de ejecución, y al mismo tiempo no entrar en pánico y no asustar al motor flash. Guardar el estado se implementó como un par de propiedades de la clase Principal, dividiéndose en etapas: seleccionando las funciones "cultivar un árbol una vez", "dibujar un árbol terminado" y "dibujar un pedazo de tierra" y medir el tiempo dedicado, respectivamente, tan pronto como la próxima "una vez" Le tomó más de unos segundos para un árbol, el árbol fue considerado "listo" y puesto a un lado. Resultó tres grandes fases: crear texturas, "cultivar" árboles, colocar árboles terminados en la pantalla.
El resultado se ve así:

Puedes jugar
aquí . Optimizado (más precisamente, escrito) para Flash 10.1, tener en cuenta un montón de actualizaciones flash en términos de seguridad puede ser terriblemente lento; en este caso, le aconsejo que descargue la versión de depuración de Adobe Flash Player 11.5 y la abra sin conexión. Todo el dibujo toma de 5 a 6 minutos, después de los dos primeros en la pantalla comienza a producirse algún movimiento, lo que puede ser interesante de observar. Después de dibujar, puede presionar Ctrl + clic para guardar el resultado como un archivo PNG cuádruple en comparación con el tamaño de la ventana.