To develop my skills with creating and using a grid system I recreated Fortnite’s building mechanic in Unity. As I had never created a third person character controller before, I followed a tutorial on youtube to set up the movement and camera so that I could focus on the grid system.
I added a button to toggle the building mode. I repurposed code from a previous project to switch build pieces with the scroll wheel, which is called when the player is in the building mode, and added the ability to keep scrolling and wrap around to the other end of the build piece array.
Fortnite displays a model of a build to show where it would go before it is placed. To create this, I spawned a build when the player switches to build mode or scrolls to a different build piece. This is stored in the currentBuildPiece variable, which follows the position of the build point and has its collider set to a trigger so it can’t interact with the environment.
When the player places a build, the collider is changed so it is no longer a trigger, the object stops following the build point and a new object is spawned and put into the currentBuildPiece variable. Spawning new build pieces when scrolling filled the scene as disabled objects, so I destroyed them after scrolling away. I created a string array to store the name of each build piece, and enabled the correct name with a for loop. This displayed the name even when not in build mode, so I changed this to only display when building.
To create the grid snapping I first rounded the x, y and z components of the build point position to the nearest integer, which snapped the build point to a unit grid. I then added euler rotation in increments of 90 so that the build point would only rotate every 90 degrees. This grid was local to the player, so I made it global and scaled the size of the grid up.
I added connection points to each edge of the build pieces. Originally I planned to use these to snap new pieces to existing builds when they were close, and snap to the grid when they weren’t. This was because the build pieces were misaligned to the grid as different pieces need to be placed on different sections on the grid. Walls need to be on the edges of the grid tiles, whereas ramps, cones and floors need to be inside the grid spaces. However, I realised this could be solved in a simpler way by adding a partial grid offset to the pieces to make them line up, and use regular grid snapping as they would all be correctly aligned.
I tried creating the offset by adding a parent object to the prefabs and an offset to the child build pieces but this stopped my existing code from referencing components of the pieces. I decided to instead add the offset with code, using a different offset for each build piece so it was correctly aligned. I added an offset to the wall that is only applied when it is rotated sideways so it is always aligned to the edge of the grid tiles. Cones placed on the ground were too low and partially clipped through it, so I added a separate offset to shift them to the correct height.
I used the connection points I had made previously to only place builds that connected to existing pieces. Each point detects whether it is connected by using its trigger collider, and the build pieces track how many of its points connect. I changed the placing builds function to only place when at least one of the points are connected.
This worked for connecting pieces to existing builds, but placing single builds on the floor did not work as there were no points connected. To fix this I allowed the builds to always place when the player was on the ground. This prevented walls from being placed when the player left the ground and then went back down, so I added an else statement to allow building when on the ground even if the player had gone up beforehand. Sometimes connection points did not successfully detect nearby builds, so I changed their code to detect builds whenever they are in its trigger range, not just when it first enters.
To stop builds placing on existing pieces, I added a script to the build piece that checked if the build piece’s collider is a trigger to know if it has been placed. If it is a trigger, it knows that is the current piece being placed, and runs the trigger detection checks to find whether it is overlapping an existing build piece. However, this stopped builds from being placed next to existing pieces as the trigger zone slightly overlapped. I changed this to check the distance of the build piece to existing builds. If it is inside an existing build, the distance is too close and so is instantly destroyed if the player tries to place it.
To indicate whether the piece could be placed, I changed the material of the build piece to red if it was overlapping, and back to white if it wasn’t. I later changed this to a translucent material if the build could be placed, red if it could not, and solid white once it had been placed to clearly indicate the status of the build piece.
However, the cone and ramp builds were sometimes translucent when they could not be placed. After testing I found that it only occurred when trying to place them on the ground. I changed the code that allowed building on the ground to check whether something was in the build’s collider if it was a cone or ramp, and not allow it to be placed if an object was there.
Fortnite has a mechanic called turbo building which allows a player to hold the mouse button down and instantly build whenever they are aiming at an available tile. To add this I changed the build placing to use GetKey instead of GetKeyDown, but this overrode the build detection and placed multiple builds on top of each other. To fix this I included a small time delay before being able to place the next build, allowing the build detection code to run.