This Christmas I wanted to assemble a Christmas Lego set with some friends, but with the COVID issue in the middle it has not been possible. So I decided to make a game where we can mount them online.
I thought Lego would have something like that, but after looking at it I only found Lego Worlds, which is not the experience I am looking for (minecraft). Although it is also possible that i'm blind and it does already exist.
I have the (bad) habit of not finishing what I start, and I don't see why this case is going to be an exception. Even so, most of the things I do, I publish them open source, so there is always room for someone else to continue it if they want to.
I hope you have as much fun as me during this adventure! And keep in mind that i have no idea of what I'm doing ;)
1. Studying the bricks
To know what data structure each brick will have, we have to look a little at what types there are, their minimum unit, the vocabulary, etc.
For example, i was convinced that the smallest unit was:
But no, it turns out that the smallest unit is:
While the blocks are called bricks, the smaller ones are called plates.
With this we already know that the height must be measured in plates.
1 brick equals 3 plates:
Another important part to keep in mind is the studs.
The studs are the "connectors", the cylindrical part that allows us to connect bricks with each other.
Bricks can be studded at multiple locations and angles:
The variety of colors is (luckily) limited to:
To know if something like this would be publishable, I looked at the patent issue and it turns out that it expired a long time ago.
Which means that there is a free pass as long as the LEGO trademark is not placed anywhere.
It should also be noted that only the patent for bricks has expired. The figures one is still valid.
2. Technology and project definition
The only engine I have touched to try things is Unity, so that's an easy choice.
For the multiplayer part (if I ever do it), the official Unity library is dead, so I'll go for Mirror.
It is an open source library maintained by competent people.
Regarding the definition of the project, the more limited you do it, the greater the probability that you will finish it.
The idea is to be able to build in the first person as in minecraft, but with bricks. No enemies and stuff like that for now.
- FPV (First Person View) controller
- Inventory system
- Construction system
- Multiplayer (if I finish all of the above)
3. First steps
First of all, I need to have the 3d models of the bricks. After searching, it seems that LLDraw is the perfect repository, but the files are .dat. I unsuccessfully downloaded LLD View to try to convert them to a useful FBX or OBJ style format. Time to keep researching....
I find Mecabricks.com, a website that allows you to create whatever you want using bricks from the browser and... You have the option of exporting them in DAE or OBJ!
With this, we already have a source to download brick models.
To begin with, I have only taken what I have considered basic: 1 plate of 1x1, 1 brick of 1x1, 1 brick of 2x2 and a brick with multiple studs at different angles.
It is time to define the model with what was learned in the first point.
Now comes the dodgy part, positioning new blocks.
In Minecraft placing a new block is "very easy". The world is a big three-dimensional matrix and all objects have the same shape (cube), so all you have to do, is look to see if the space in that matrix is free.
But with bricks? ... What a brownie. We could make a matrix using plates as a unit, but we would have to calculate the space that bricks like this occupy:
And I don't feel like it. So we will go for something more crappy.
Unity has a component called "Collider" that allows you to work with physics. That is, make an object take up space or act as a hitbox, detect when another object is inside it (trigger).
In this example, the cubes with green edges are the colliders.
We will make a preview of where the new block will appear and to this preview we will put a collider in trigger mode.
If the player puts it in a place that touches / there is another brick, we will know it and we will not let it happen.
But before that, we have to know exactly where the player is looking. Again in minecraft it's easy, you do raycast and instantly you know which block and which side of it is looking.
For those who do not know, raycasting is this:
Send a "ray" in a direction to detect what is on the way.
But with bricks?... Not all brick surface is "useful", we really need to know if you are looking at a stud.
If you have followed the roll until now, you will have thought "well, you put a collider on each stud and that's it". Well yes, it is an option:
However, it will not be case. Each component consumes resources, you have to save on everything.
With this you are in the same case, you do not know which of them is looking!
Yep, we will have to calculate it. All studs have the same surface, so if we know in which coordinate the raycast has collided, we will be able to know which stud it belongs to.
(Imagine the red dot is where player is looking at)
Isn't there an easier way to find it out? Sure it is, but I have no idea how.
Now we know where to place the block and if it is hitting something or not.
Well, we already have it, right? Aaaaaaaallllmost. If I do the test you will see why:
Again the placement fails, but because we do not know how the player wants it. In Minecraft there is only one way, but here there are multiple possible combinations.
And how do we fix? It is time to make a button that rotates the brick until it is in the desired position.
We can obviously try to make the constructor slightly "smart". If the player is trying to place a 2x2 piece on top of another 2x2 piece, he probably expects this:
So we add a check so in cases where the number of studs matches, it copies the position changing only the height.
The result of the rotation system I am afraid is quite meh. It combines the fact that I do not know what is happening + I am lazy to understand it.
I guess it has to do with how the part is rotated. Surely it is done based on the center of it and not based on the axis that coincides with the stud. If so, it's not something I know how to fix, I don't think I can change the axis of rotation temporarily, but who knows.
In red, the desired axis of rotation (have the stud as a base). In black, the current rotation point.
With this we can already try to build something:
4. The damn inventory system
As usual I underestimated the complexity of doing it. I thought it would be 10 lines at max and done, but no. Turns out it has its crumb.
I always need to start with the visual part, not because I'm good at it, but because unlike coding, the smallest change can be appreciated.
Using my GREAT creativity, I have arranged the following design:
Now it's time to go back to coding.
We will start with the data model. What are we going to have to save? The id of the item, the quantity and its status.
Done! Right? Well no... We forgot the slot in which it is inside the inventory. And that little shit is the one that adds the complication, because each time an item is added to the inventory, we will have to find an available slot for it (as long as we don't already have it). And if possible, we will have to prioritize the fast access slots (those at lower bar).
I've added the damn slot.
What will our inventory have to do? / What should we take into account?
- Add and remove items
- When they are added, always give priority to fill the bottom bar
- When items are added or removed, the UI has to be updated
- In the inventory panel you must be able to change slot items via drag & drop.
- In the inventory panel, if you drag an item out of the window, you have to discard it.
- In the lower bar there must always be a selected slot
- Player mut be able to change the selected slot on bottom bar
- When in the inventory panel, player's camera must be freezed
- All bricks need a preview icon
Huh, this will take longer than I thought.
Only with the add item function I have already exceeded the 10 wrongly counted lines that I expected to write xD
As you can see, when adding an item, the first thing I do is iterate over the entire inventory, to do 2 things:
See if I already have that item, so that I only have to increase the quantity and list the occupied slots.
In case I can't find the item, I'll at least know which slots I can't fill. After doing this, since I know for sure that a new slot has to be occupied, I check to see if the inventory is full. If that's not the case, I continue, and I iterate over the slots that are free to see if there are any in the bottom bar (the inventory has 36 slots, so I check if the free slot is> 27).
If that's not possible, then I'll get the first one available and screw it. Oh, well, yeah, and I update the UI.
Next we do the moving items between slots part. For this, we will use the drag & drop system that Unity has, by using IBeginDragHandler, IDragHandler, IEndDragHandler.
It may look like I have moved the icon but actually, I'm not doing that.
Instead of dynamically generating the occupied slots, I have them all already generated statically, whether they are full or empty.
After dragging, when the icon is released, what I do is check which slot you moved and where you left it. Via code i just exchange the content of the 2 slots (in case they have something).
Time to move on to having a selected slot.
This part is somewhat problematic for me because we are used to using the mouse wheel to move between our weapons / inventory. But I have assigned the function of rotating the bricks to the wheel.
A workaround could be:
1. You aim at the stud and left click.
2. This makes the preview appear, and you can now use the wheel to rotate it.
3. You left click to confirm the construction.
I find it cumbersome/slower. And since you don't have the preview in the first step, you may not understand that unlike minecraft, you can point out exactly at which stud you want to put it on.
Although on the other hand..
1. This would allow me to use the wheel to move between the inventory, since there would only be a moment in which the construction system uses it and it would know if it is in that step or not.
2. Another gain would be that you could go around the map with a brick selected in the inventory without the preview appearing wherever you look.
3. I wouldn't have to be raycasting every frame. Just as soon as the player left-clicked, because i know what you want to build. [Now that I think about it, I can also avoid this now, looking to see if the item you have selected is a brick].
MMMMMMMmmm. I will have to ruminate it well.
This is all for now.
As I said at the beginning, everything I do is usually open source. So I leave the repository over here with the current progress.