#300 Ahh vale! Unity tiene también algo muy similar (Rule Tile)
#300 Vale, sí, lo del bitmask y los autotiles la había estado viendo en otras ocasiones/videos para aprender a utilizarlo, pero no veo como usar esto con algo que no sea "pintar a mano" el mapa.
Pensando como hacer un mapa aleatorio a través de código, mirando las funciones/métodos que ofrece Godot para los TileMaps (documentación) y basándome en algún tutorial que encontré en youtube, me quedé con el método "set_cell", de tal forma que genero el perímetro (de momento es un cuadrado, en un futuro quiero generar una isla gigante) y luego genero el interior que no deja de ser hierba como fondo y árboles y arbustos colocados de forma aleatoria.
Me da vergüencita ponerlo, pero mi idea es esta, mejorada y a gran escala:
#302 No te puedo decir en Godot, pero en Unity lo que creas es una tile especial que ya tiene ese comportamiento, quiero decir que ya comprueba automáticamente las tiles adyacentes y se pinta de un modo u otro. Que la pongas de forma procedural o a mano no importa.
Si el método set_cell de Godot es similar al de Unity será algo parecido, en Unity sería:
tileMap.SetTile("Vector de posicion", "Tile a poner");
Pues si "Tile a poner" es del tipo ese que comento ya se pinta como toca dependiendo de las rules que le hayas puesto. No se si me explico o te estoy liando más xD
#303 en unity existe eso? debe ser reciente no? yo me lo pique a manubrio cuando lo usaba con unity 2017
#304 Si, es un package que está en preview (https://github.com/Unity-Technologies/2d-extras) que da funcionalidades extra a los tilemaps, como lo del Rule Tile o Animated Tile entre otras.
Perdón por llenar el devlog de godorogue con Unitadas xD
#28AikonCWD:El tema del balanceo lo iremos mejorando entre todos.
Para el tema del balanceo está muy bien esta herramienta, simula miles de partidas y detecta fallos de balanceo, detecta si el juego "está roto".
https://machinations.io/
#302 No exactamente. El bitmask sirve para "pintar" el mapa y también para generarlo en runtime con set_cell. Una vez has generado el mapa y tras la última llamada a set_cell(), llamas a la función update_bitmask_area()
para actualizar el bitmask y hacer que cada sprite cambie acorde a las celdas de su alrededor.
Luego con set_cell tienes un parámetro para indicar el ID del autotile en caso de utilizar un mapa de Atlas en los sprites:
void set_cell(x: int, y: int, tile: int, flip_x: bool = false, flip_y: bool = false, transpose: bool = false, autotile_coord: Vector2 = Vector2( 0, 0 ))
(es el último de sus parámetros).
Te voy a seguir en twitter para estar atento a tus updates
En cuanto tenga el ejemplo hecho en mi juego lo posteo aquí con el código para que se entienda mejor.
#306 Gracias! ahora lo miro
#303 Sí, sé lo que dices, sólo que no me cuadra/ba con hacerlo por código, ya que todos los tutoriales que he encontrado te enseñaban a hacer el bitmask y luego pintaban a mano. No he visto ninguno que lo haga con código ni para Unity, ni para Godot, de ahí mi lío.
#307 Creo que el problema está en que yo cuando leí la frase "The autotile coordinate refers to the column and row of the subtile.", lo entendí como que dentro del autotile le indicabas a mano la celda que querías usar, así que para era el caso era el mismo resultado, que necesitabas decirle el autotile y luego, por ejemplo, posición (3,4) que es donde está el tile que quiero para la esquina.
Pongo un ejemplo más concreto y más adecuado a mi caso:
https://www.davidepesce.com/2019/10/18/godot-tutorial-7-using-tile-maps-to-create-game-map/
En esta imagen se ve que sólo utiliza autotile para la zona de arena:
Para el caso del autotile de la arena que crea, puedo llegar a entender que Godot sepa corregir los errores, pero si quieres poner árboles, piedras, etc que no van dentro de un autotile no queda más remedio que decirle al juego que pinte el tile que tú quieres. O eso pienso yo :S
Le veo utilidad para generar mazmorras, que el autotile te generará muros y suelos y luego ya le pones decoración aleatoria por encima de otro tileset a sabiendas de lo que pones.
#308 En realidad en ese ejemplo tienes 2 tiles:
hierba = id 0
arena = id 1
Para hacer tu mapa, solo escribes tiles con id 0 y 1, y el bitmask se encargará de usar el sprite de la arena con esquina según corresponda en función de sus vecinos. Luego los obstáculos yo no los haría tiles, si no objetos instanciable. Y los instanciarás de forma random sobre el grupo de tiles que tengan id=0 (hierba), evitando que aparezcan árboles sobre la arena.
edit: @Thanat0s a parte si pones los árboles como tiles.... no puedes hacer que el personaje vaya por detrás del sprite del arbol, verdad? Para eso deberías meterlos como un nodo a parte y usar el nodo Ysort:
#309 Vale, ahí tengo yo toda la confusión, con los obstáculos.
Una de mis primeras aproximaciones ha sido hacer los obstáculos como objetos instanciables y funcionaba genial (es lo que se ve en el vídeo de twitter que puse).
El problema me surge cuando quiero usar el navigation de los tilemaps para que los enemigos usen pathfinding y no sean enemigos tontos que persiguen a tu personaje en línea recta, sin necesidad de rellenar yo un grid y montar mi propio pathfinding (que lo tenía hecho en Unity).
En ese momento es cuando empecé a liar las cosas y a meter los obstáculos con su navigation dentro del mismo tileset que el suelo y los bordes xD
Hablando con vosotros estoy viendo una forma mejor de hacerlo y solucionar lo del pathfinding con el navigation de forma elegante.
Ya os contaré
Gracias por todos los comentarios/ayuda.
Edit: justo ese tutorial lo estuve viendo y claro, si los meto en el mismo tilemap efectivamente pasa lo que dices, por eso creo un tilemap que llamo "tilemap_front" que meto junto al "player" en un ysort.
Además en consumo me parece que instanciar 10000 objetos me parece una burrada, por eso quería usar también los tilemaps, aunque quizás estoy equivocado y apenas consume recursos el instanciar tantas cosas.
#310 Claro, ahora te toca probar y decidir que opción te sirve a ti. Aquí no hay una forma única de hacer las cosas, y siempre que el resultado te guste, estará bien hecho.
Yo no he usado el nodo de Navigation2D para hacer el pathfinding, he usado el módulo AStar (A*) y he montado el grid a mano. Usé este tutorial: https://www.youtube.com/watch?v=Rf9GZKfALAo
Pero deberías poder hacerlo con Navigation2D, prueba ambos métodos a ver cual te resulta mejor.
edit: Instanciar 10000 objetos es una burrada, deberás usar CameraCulling.
#311 Pues sí, al final esto no deja de ser un aprendizaje y además es divertido ir probando varias formas y quedarte con la que más te gusta o mejor funciona.
Tengo en mente echarle un vistazo al A* que has utilizado, ya que el Navigation2D no funciona muy bien del todo.
Cada semana cambio alguna cosa que tenía "fija" la semana pasada.
Ahora mismo estoy pensando cambiar la forma de mover el personaje, ahora uso wasd + teclas de ataque y magias y estoy pensando en pasar a ratón + teclas de ataque y magias.
¡Soy un caos!
Pues voy a meterle un update al juego añadiendo el tileset gráfico. Es algo que tenía pendiente y lo he ido dejando atrasado porque la verdad no he tenido mucho tiempo.
He empezado por los monstruos, en la foto se ve a un Emu en su formato ascii y tileset. Ahora voy a ver si puedo actualizar el resto de símbolos.
´Por hoy lo dejo aquí. Ya tengo todos los items/monstruos en modo gráfico y ahora estoy trabajando con la generación del layout de la mazmorra. Se pueden ver unos tiles rojos que tengo que sustituir. Me falta añadir esquemas de colores, tipos de terreno, etc... supongo que esta noche o mañana lo terminaré.
PD: Tengo que meter outline a los bichos porque con el fondo de colores no se aprecian nada xd
#318 He dibujado pocas cositas, no se me da bien. El mapa es un tileset de Oryx y los bichos los saqué de opengameart, luego he ido añadiendo y quitando cosillas yo mismo.
Aquí tenemos el mismo mapa, en versión ascii y en versión tileset. Se puede alternar el modo y de momento no está petando nada xd.
Voy a definir diferentes layouts de colores y ya podré shippear la versión final de GodoRogue
Edit: Bendito Aseprite que te permite hacer outline con un click.
#319 Gana mucho con los sprites, buen trabajo!
pondría los tiles negros de un gris, para que concuerde un poco con el recho de los muros
#320 Gracias!!
Ya tengo terminados los 5 layouts.
El de Jardín solo puede aparecer a partir de la profundidad 10, ya que visualmente lo convierte en un laberinto complicado de recorrer, aumentando un poco su dificultad.
Cual os gusta más? El resto de layouts son random y cada piso se genera usando uno de ellos.
Solo me falta arreglar un par de sprites (proyectiles, lanzar armas, etc...), arreglar algún efecto de sonido y balancear un poco el juego. Ya lo dejo para mañana.
Bueno pues aquí dejo subida la versión actual:
Recordad que, pese a que podéis jugar desde el navegador, la versión ejecutable funciona mil veces mejor y permite escalar la pantalla usando los números del 1 al 9.
El juego empieza automáticamente en modo tileset, pero se puede alternar la vista pulsando G
(Shift+G) o F7
. Recordad leer la ayuda F1
. Todos los items tienen su descripción correspondiente y hay un bestiario F6
que permite leer la entrada de cada monstruo que hayas eliminado.
La dificultad del juego la he retocado un poco y ahora no refleja la realidad de los valores que hay en #1 (ya lo editaré), pero digamos que es todo un pelín más fácil. Yo he hecho una partida rápida y me he quedado en un nivel avanzado con Dragones, creo que profundidad 20 o así.
Spoiler: El dragón me ha reventado la cara.
Espero feedback!
Una consulta que tengo...
Actualmente cada partida se genera de forma random, pero me resulta muy sencillo especificar una seed y hacer que siempre se genere la misma partida (mismo layout, monstruos, items, etc...), permitiendo que alguien pueda jugar X veces la misma partida o compartir una seed en la que sabes que empiezas con buenos items, etc... Para hacer pruebas puede ir genial.
El tema es que no sé como implementarlo en el juego... actualmente al empezar te pregunta el nombre. Si no escribes nada te asigna el nombre de Rodney.
Cómo veis si, la seed del generador de números aleatorios se calcule a partir del nombre? Siendo Rodney una palabra clave que hará que sea RNG puro, pero cualquier otro nombre siempre genere la misma partida. A mí la idea me gusta, pero es muy probable que la gente no lo sepa y pongan su mismo nick/nombre, generando siempre la misma partida y pensando que el juego está bug xd.
Que haríais? Se os ocurre alguna forma mejor de implementar el seed?
#324 Yo seguramente me pondría el mismo nombre, así que me pasaría lo que tú dices. Lo que sí puedes hacer es que además te pregunte el nombre del mundo, o de la mazmorra. Y entonces, si es siempre el mismo tiene sentido que sea el mismo lugar. También puedes por defecto sacar un nombre aleatorio distinto cada vez, para que la gente no tenga que pensarlo a no ser que de verdad quiera.
#324 Lo del nombre parece una mala idea.
Yo haría algo como en Minecraft, que al darle a empezar una partida te salga un número generado (el jugador ve el número escrito, vamos) aleatoriamente que sea la semilla.
Y que además de esto, haya un botoncito para generar otro número aleatorio y que esté la posibilidad de escribir a mano el número, por si quieres probar la misma semilla de otra persona, o de una partida que ya has jugado por ejemplo.
Vale, se viene momento
Voy a descartar el tema de las seeds porque como soy retromonguer y no tengo una buena base con la programación, he cometido un error de diseño que me impide implementar un sistema de seeds funcional. Me explico:
Yo uso la función randf() que devuelve un float entre 0 y 1, para hacer todos los cálculos (generar el terreno, tiradas de dados de combate, generación de loot, etc...). El generador de números aleatorios es una especie de array infinito por el cual cada vez que llamas a randf() hace pop de dicho array y te saca un número random.
Cual ha sido mi cagada? Que no sabía que puedes tener N generadores aleatorios e independientes, cada uno con su propia seed. Yo esto no lo sabía xd, y solo tengo un único generador de números... Imaginemos que mi generador con la seed "123" genera el siguiente array de números:
2, 4, 6, 8, 10, 12, 14, ...
Al generar el nivel 1, se usa el primer número random (2) para generar el layout, luego el siguiente número (4) para generar los monstruos, luego el 6 para los items y finalmente el 8 es usado para calcular el combate contra un monstruo... paso al siguiente nivel y utilizo el número 10 para generarlo.
Qué pasa si repito la run pero decido ir al siguiente nivel sin luchar? Que el segundo nivel será generado usando el número 8 y tendré una partida diferente.
Esto lo podría haber solucionado teniendo diferentes generadores de números, y usar uno de ellos únicamente para calcular los niveles, así los otros eventos random del juego (como los combates) no consumen números aleatorios y no rompen la serie.
Lo puedo arreglar? Sí
Lo voy a arreglar? No xd. Me da mucho palo ahora recorrerme TODO el código fijándome línea por línea donde uso un randf() y cambiarlo por generador1.randf()... me da muchísimo palo.
No sé si se me entiende porque a veces me explico como un libro cerrado pero bueno. Me quedo con la parte buena de haber aprendido algo nuevo hoy.
#329 noooo jajaja.
En verdad esto de las seeds jamás fue algo planeado, así que si no sale pues nada pasa nada
Si el editor de Godot tuviera refactorizar, quizás lo implemente, pero no tiene. Creo que se puede conectar el Code como editor y de ahí usar el refactorizar, pero ni idea... no quiero liarme a tocar algo del proyecto y romperlo.