diff --git a/Assets/Scripts/World/ChunkGenManager.cs b/Assets/Scripts/World/ChunkGenManager.cs index cdf6781..97b50ff 100644 --- a/Assets/Scripts/World/ChunkGenManager.cs +++ b/Assets/Scripts/World/ChunkGenManager.cs @@ -28,7 +28,7 @@ namespace Brickcraft.World public void Generate() { ManualResetEvent[] genWait = new ManualResetEvent[threadsNum]; - ThreadPool.SetMaxThreads(threadsNum,threadsNum); + ThreadPool.SetMaxThreads(threadsNum, threadsNum); int totalLoops = (Math.Abs(fromChunkX) + Math.Abs(toChunkX)); int basePartition = totalLoops / threadsNum; diff --git a/Assets/Scripts/World/WorldBehaviour.cs b/Assets/Scripts/World/WorldBehaviour.cs index e2fd77a..0cd5409 100644 --- a/Assets/Scripts/World/WorldBehaviour.cs +++ b/Assets/Scripts/World/WorldBehaviour.cs @@ -68,11 +68,7 @@ namespace Brickcraft.World ChunkGenManager chunkGenManager = new ChunkGenManager(MapMinChunkX, MapMaxChunkX + 1, 6, this, 13284938921, chunkEntries); chunkGenManager.Generate(); - /* - CalculateStartLight(); - - LightAlgorithmRecorder.InitPlayback(); - */ + for(int x = 0; x < ChunksNum; ++x) { chunkEntries[x].Init(); diff --git a/docs/blog-editor.html b/docs/blog-editor.html new file mode 100644 index 0000000..d6f9d6b --- /dev/null +++ b/docs/blog-editor.html @@ -0,0 +1,50 @@ +
Small list of issues that are preventing me from further progress.
+ +Terrain is using a single texture:
+
But i don't now how to set the uvs in order to use it properly.
+If i set all vertices, the entire texture is used, which is not what i'm looking for:
+
+
+With my latest attempt it looks like
+
+Each face has only 1 color => good. But it's not the same color across all faces and also it's always the wrong color => fail.
+ +Here is the code that handles uvs setup: ChunkRenderer.cs#L546 +
+ ++ In order to generate the terrain mesh, i grab the brick model and i use planes to delimitate each face. +
+
+Notice the blue planes "cutting" each face.
+Then i use a small class that iterates over all brick mesh's vertices to know to which face do they belong.
++ After that, when building a mesh slice, i just add the visible brick faces of each case at + ChunkRenderer.cs#L495 +
+ +If top face is properly cut:
+
+
+Then it randomly breaks:
+
+
+If only studs are set as top face:
+
+
+It doesn't break:
+
+
++ Notice how all other faces are also rendering properly now. Yet they haven't been edited. +
+ + How the heck can they "randomly" break?The terrain generation scene is /Scenes/WorldGenerationTest.unity
+ +This is the obj being used: /Models/Bricks/3003/3003.obj +
+ +Well, basic feature not made yet.
+ +
+ Digging takes places at /Scripts/Player/Player.cs#L53.
+
+ And /Scripts/World/WorldBehaviour.cs#L259 has some methods to transform coords to Chunks.
+

Estas navidades quería montar un set de Lego navideño con unos amigos, pero con el tema COVID por en medio no ha sido posible. Así que me ha dado por hacer un juego donde podamos montarlos online.
+
+
+ Pensaba que Lego tendría algo así, pero tras mirarlo sólo he encontrado Lego Worlds, que para nada es la experiencia que busco (minecraft). Aunque también es posible que esté cegato y sí exista.
+
+ Tengo la (mala) costumbre de no terminar lo que empiezo, y no veo por qué este caso vaya a ser una excepción. Aún así, la mayoría de las cosas que hago las publico open source, por lo que siempre hay margen para que otro las continúe de quererlo.

+
+ Para saber qué estructura de datos tendrá cada brick, hay que mirar un poco qué tipos hay, su mínima unidad, el vocabulario, etc..
+
+
No son un fan/AFOL de lego y prueba de ello es que estaba convencido que la mínima unidad era:
+
+
+
+ Pero no, resulta que la unidad más pequeña es:

+
+
+ Mientras que los bloques se llaman bricks, los más pequeños se llaman plates.
+ Con esto ya sabemos que la altura deberá medirse en plates.
+
+
1 brick equivale a 3 plates:
+
+
+
+ Otra parte importante a tener en cuenta es los studs.
+ Los studs son los "conectores", la parte cilíndrica que nos permite conectar unos con otros.
+
+
Los bricks pueden tener studs en múltiples sitios y ángulos:
+
+
+
+ La variedad de colores está (por suerte) limitada a:

+
+
+ Para saber si algo así sería publicable he mirado el tema patente y resulta que esta expiró ya hace tiempo.

+
+ Lo que significa que hay vía libre siempre y cuando no se ponga la marca en ningún sitio.
+ También hay que tener en cuenta que sólo la patente para los bricks ha expirado. La de sus figuras aún está vigente.

https://theconversation.com/how-lego-legally-locked-in-the-iconic-status-of-its-mini-figures-43489
+
+
+
+ Lo único que he tocado para hacer alguna que otra ñapa es Unity, de modo que el engine es fácil.
+ Para la parte multiplayer (si es que llego a hacerla), la librería oficial de Unity está muerta, por lo que optaré por Mirror.
+ Es una librería open source mantenida por gente competente.
+
+
En cuanto a la definición del proyecto, cuanto más acotado lo haga, mayor será la probabilidad de que lo termine.
+ La idea es poder construir en primera persona como en minecraft, pero con bricks. Sín enemigos, ni un mundo procedural.
+ - FPV (First Person View) controller
+ - Sistema de inventario
+ - Sistema de construcción
+ - Multiplayer (si llego a terminar todo lo anterior)
+
+
+
+ Antes que nada, necesito tener los modelos 3d de los bricks. Tras buscar, parece que LLDraw es el repositorio perfecto, pero los ficheros son .dat. Descargué sín éxito LLD View para intentar convertirlos a un formato útil estilo FBX o OBJ. Toca buscar más.....
+ Finalmente encuentro https://www.mecabricks.com/, una web que permite crear lo que quieras usando bricks desde el navegador y... ¡Tiene opción de exportar en DAE o OBJ!
+ Con esto ya tenemos una fuente desde la que ir descargando brick a brick.
+
+
Para empezar sólo he pillado los que he considerado básicos, 1 plate de 1x1, 1 brick de 1x1, 1 brick de 2x2 y un brick con múltiples studs en distintos ángulos.
+
+
+
+
+ Toca definir el modelo con lo aprendido en el primer punto.

+
+
+
+
Ahora se viene la parte chunga, posicionar nuevos bloques.
+
+
En Minecraft colocar un nuevo bloque es muy fácil. Todo el mundo es una gran matriz tridimensional y todos los objetos tienen la misma forma (cubo), con lo que lo único que debes hacer es mirar si el espacio en esa matriz está libre.
+
+
+
+ ¿Pero con los bricks?... Menudo marronazo. Podríamos hacer una matriz usando los plates como unidad, pero tendríamos que calcular los espacios que ocupan bricks como:

+
+
+ Y no me apetece. Así que optaremos por algo más cutre.
+
+
Unity tiene un componente llamado "Collider" que te permite trabajar con las físicas. Es decir, hacer que un objeto ocupe espacio o bien actuar de hitbox, detectar cuando otro objeto esta dentro de él (trigger).
+
+
+
+ En este ejemplo, los cubos con bordes verdes son los colliders.
+
+
Haremos que haya preview de dónde aparecerá el nuevo bloque y a este preview le pondremos un collider en modo trigger.
+ Si el jugador lo pone en un sitio que toca/hay otro brick, lo sabremos y no le dejaremos.
+
+
Pero antes que eso, tenemos que saber exactamente hacia dónde está mirando el jugador. De nuevo en minecraft es fácil, haces raycast y al momento sabes qué bloque y qué cara de este está mirando.
+ Para el que no lo sepa, hacer raycasting es esto:

+
+ Mandar un "haz" hacia una dirección para detectar con qué se encuentra por el camino.
+
+
¿Pero con bricks?... No toda la superfície de un brick es "útil", realmente necesitamos saber si está mirando a un stud.
+ Si hasta ahora me habéis seguido el rollo habréis pensado "pues le metes un collider a cada stud y listo". Pues sí, es una opción:

+
+
+ Sín embargo, va a ser que no. Cada componente consume recursos, hay que ratear en todo.

+
+
+
+ ¡Con esto estás en las mismas, no sabes a cuál de ellos está mirando!
+ Eso me temo, esa parte la tendremos que calcular. Los studs tienen todos la misma superfície, por lo que de si sabemos en qué coordenada ha dado el raycast, podremos saber a qué stud pertenece.

+
+
+ (Imagina que el punto rojo es donde mira el jugador)
+
+
¿No hay una forma más fácil de saberlo? Seguro que sí, pero yo no tengo ni idea.
+
+
+
Ahora ya sabemos dónde colocar el bloque y si está chocando con algo o no.
+ ¿Pues ya lo tenemos no? Caaaaaaasi. Si hago la prueba veréis por qué:

+
+
+ De nuevo falla la colocación, pero porque no sabemos cómo lo quiere el jugador. En Minecraft sólo hay una manera, pero aquí hay múltiples combinaciones posibles.

+
+
+
+ ¿Y cómo arreglamos? Toca hacer un botoncito que permita ir rotando la pieza hasta que quede en la posición deseada.
+ Obviamente podemos intentar hacer el constructor algo "listo". Si el jugador está intentando colocar una pieza de 2x2 encima de otra pieza de 2x2, es probable que quiera que quede así:

+
+
+ De modo que añadimos un check para que en los casos en los que el número de studs coincida, copie la posición cambiando únicamente la altura.

+
+
+
+ El resultado del sistema de rotación me temo es bastante chuchurrio. Se combina el hecho de que no sé que está ocurriendo + me da pereza entenderlo.
+ Supongo que tiene que ver con cómo se realiza la rotación de la pieza. Seguramente se haga en base al centro de la misma y no en base al eje que coincide con el stud. De ser así, no es algo que sepa arreglar, no creo que pueda cambiar el eje de rotación temporalmente, aunque a saber.

+
+
+ En rojo el eje de rotación deseado (tener el stud como base). En negro el punto de rotación actual.
+
+ Con esto ya podemos intentar construir algo:


+
+
+
+
+
+
+ Como de costumbre subestimé la complejidad que conllevaría hacerlo. Pensaba que serían 10 líneas mal contadas y andando, pero no. Resulta que tiene su miga.
+
+
Siempre necesito empezar por la parte visual, no porque sea bueno en ello, sino porque a diferencia de picar código, a poco que hagas ya se aprecia un cambio.
+ Haciendo uso de mi GRAN creatividad, he dispuesto el siguiente diseño:

+
+
+ Ahora toca volver al código.
+
+
Empezaremos con el modelo de datos. ¿Qué vamos a tener que guardar? El id del item, la cantidad y su estado.
+
+
+
+
¡Hecho! ¿Verdad? Pues no.. Nos dejamos el slot en el que se encuentra dentro del inventario. Y esa mierdecilla es la que añade la complicación, porque caaada vez que se añada un item al inventario, tendremos que buscarle un slot disponible (siempre y cuando no lo tengamos ya). Y dentro de lo posible, habrá que priorizar los slots de acceso rápido, los de la barrita inferior vamos.
+
+
+
+ Venga, le añadimos el maldito slot.
+
+
¿Qué tendrá que hacer nuestro inventario?/¿Qué debemos tener en cuenta?
+ - Añadir y quitar items
+ - Cuando se añadan, que siempre de prioridad a llenar la barra inferior
+ - Cuando se añaden o quiten items tiene que actualizarse la UI
+ - En el panel de inventario hay que poder cambiar vía drag & drop los items de slot.
+ - En el panel de inventario, si se arrastra un item fuera de la ventana, tiene que descartarlo.
+ - En la barra inferior siempre tiene que haber un slot seleccionado
+ - Hay que poder cambiar el slot seleccionado de la barra inferior
+ - Cuando se esté en el panel de inventario, hay que congelar la cámara del jugador
+ - Todos los bricks necesitan un icono de preview
+
+
+
Cachís, esto es más largo de lo que creía.
+
+
Sólo con la función de añadir item ya he superado las 10 líneas mal contadas que esperaba escribir xD
+
+
+
+ Como se puede observar, al añadir un item, lo primero que hago es iterar sobre todo el inventario, para hacer 2 cosas:
+ Mirar si ya tengo ese item, de modo que sólo tenga que aumentar la cantidad y apuntarme los slots ocupados.
+
+
En caso de que no encuentre el item, sabré al menos qué slots no puedo llenar. Tras hacer esto, como sé seguro que hay que ocupar un nuevo slot, miro si el inventario está lleno. En caso de que no sea así, continuo, y me dedico a iterar sobre los slots que quedan libres para ver si hay alguno en la barra inferior (el inventario es de 36 slots, así que miro si el slot libre es > 27).
+ Si eso no es posible, pues pillo el primero disponible y que le den. Ah bueno sí, y actualizo la UI.
+
+
A continuación hacemos la parte de mover items entre slots. Para ello nos valdremos del sistema drag&drop que Unity tiene, mediante el uso de IBeginDragHandler, IDragHandler, IEndDragHandler.
+
+
+
+
+ Puede parece que haya movido el icono de sitio pero en realidad no lo estoy haciendo.
+ En vez de generar dinámicamente los slots ocupados, los tengo todos ya generados de forma estático, estén llenos o vacíos.
+ Después de arrastrar, cuando se suelta el icono, lo que hago es mirar qué slot movías y dónde lo has dejado. Vuelvo a dejar el slot que has movido en su sitio y vía código intercambio el contenido de los 2 slots (en caso de que tengan algo).
+
+ Pasamos a lo de tener un slot seleccionado. Esta parte me resulta algo problemática porque estamos acostumbrados a usar la rueda del ratón para movernos entre nuestras armas/inventario. Pero yo he asignado la función de rotar los bricks a la rueda. Me parecía natural y veo que pueda distinguir cuando quieres rotar un cubo a cuando quieres cambiar de slot de modo que los 2 puedan usar la rueda.
+ La única manera sería si el proceso de añadir un brick fuera:
+ 1. Apuntas al stud y haces clic izquierdo.
+ 2. Esto hace que aparezca el preview, pudiendo ahora usar la ruedecita para rotarlo.
+ 3. Haces clic izquierdo para confirmar la construcción.
+
+ Me parece engorroso/más lento. Y como además en el primer paso no tienes el preview, es posible que no entiendas que a diferencia de minecraft, puedes apuntar exactamente en qué stud quieres ponerlo.
+ Aunque por otro lado..
+ 1. Esto me permitiría usar la ruedecita para moverme entre el inventario, pues sólo habría un momento en el que el sistema de construcción lo usa y sabría si está en ese paso o no.
+ 2. También ganaría que podrías ir por el mapa con un brick seleccionado en el inventario sín que el preview te apareciera allá donde miras.
+ 3. No tendría que estar haciendo raycasting en cada frame, sólo en cuanto el jugador hiciera clic izquierdo, porque sabría que quiere construir. [Aunque ahora que lo pienso, esto también puedo evitarlo ahora, mirando si el item que tiene seleccionado es un brick].
+
+ MMMMMMMmmm. Puede que al final haya más cosas a favor que en contra.
+
+ Habrá que rumiarlo bien.

+
+
+
+ De momento esto es todo.
+ Como he dicho al principio, todo lo que hago suele ser open source. Así que dejo el repositorio por aquí con el progreso actual.