There's only need for one forum for now. Discuss development. No advertising or thinly veiled attempts at advertising. Create a single thread for your project and be prepared to show and tell.
A tower defense mixed with real-time strategy where you repel attacking sentient AI robots until they give up.
You'll have an object to defend just like most other tower defense games and there will be a secondary objects to defend, landing zones. If you lose a landing zone, you won't necessarily lose the game, but they're important because they give you $upplies! $upplies will be used to purchase defenses, units, upgrades, repairs, and call in off map strikes such as air strike, artillery strike, and tactical nukes.
$0 Budget Terrain Textures
Making textures for terrain is pretty straight forward work, but I found that getting pictures of the ground on an overcast day is best. The overcast allows for the ground to be lit and have no shadows. Next part is the guess and check work, find the best photos and make them square while keeping an eye out for anything that stands out which would make textures look repetitive. Whatever photo you take, you'll always have seams when you put them side by side; I found a nice online tool that will make your textures seamless here.
An Easy RTS Pathfinding System
This easy pathfinding system I've put in the game is very similar to Dijstra's algorithm. The unit will move on a grid. The unit will test for a collision with a block before moving to the next grid point. The unit can only rotate to 1 of 8 directions that lead to neighboring points.
The whole path is mapped out in a single frame within a loop. With this method you can see the path without traversing it and see the distance of that path made. Next I added four different rotation patterns to plug into the pathfinding method: Always clockwise, Always counterclockwise, starting with counterclockwise and alternating, and starting with clockwise and alternating.
Of the four paths made, the one with the least points is chosen. And finally, before the unit begins it's journey, the path is refined by getting rid of junk points. This way, only key points without a block between them exist.
If you would like to follow me on my game dev journey, don't forget to subscribe or follow on social media!
Facebook - https://www.facebook.com/DeterrenceGame/
Twitter - https://twitter.com/DeterrenceGame
Instagram - https://www.instagram.com/deterrencegame/
Discord Server - https://discord.gg/tH3qRhMau7
IndieDB - https://www.indiedb.com/games/deterrence
Last edited by PiscesStudios on Sun Jan 15, 2023 4:20 am, edited 33 times in total.
I opted not to use Unity's terrain trees for this game because the terrain tree colliders didn't work with my units pathfinding system. Instead, I just used game objects for trees which also gave me more freedom to do what I want with them.
To make the trees destructible, the trees have a reference to a destroyed tree prefab which inherit the transform of the tree that instantiated it. The destroyed tree prefab has a rigid body for physics and a script with an explosive force scenario to play out.
It is also a good idea to put trees on they're own layer and disable the trees from interacting with the block layer in the physics settings. This way you don't get trees that collide with the invisible block layer.
Easy Bump Mapping
To get the desired look for my landing zone tent, I went with a solid color and a height map. A height map is a gray scaled texture where white represents bumps. I use the brush free handed and then soften what's been drawn to make the bump more smooth. This texture can be imported into Unity and converted to a normal texture through gray scale.
Now that the LZ model is complete, I import the LZ model into unity to see how it looks. After adjusting all the materials, you can now see an awesome looking tent in Unity.
Modeling the CH-47
The most important part to modeling the chinook was reference images. Without them, the model would be have incorrect proportions and I wouldn't have gotten very far.
To texture the chinook, I tried the high resolution model method since I didn't have an actual chinook to capture pictures of. The high resolution model method will have all the finer details of the model created with geometry, then I would render an image of that model to paint on the lower resolution game ready model.
Making the propeller blades a separate object was important for the spinning effect I would add later in Unity.
To finish up the chinook, I took the color texture and began to change the RGBA channels for metal, smoothness, and a gray scaled normal map to be interpreted by Unity.
Modeling the Soldier
This was my first character model ever, I learned quite a bit and actually impressed myself with this one. I thought texturing the soldier would be incredibly difficult, but the method I used was simple and powerful. I would create the shapes I wanted to paint on the model with an image editor. I used those images to paint the color and height textures. They turned out pretty good in Unity.
As this was my first rig in my life and in Blender, I had to a bit of trouble getting the bones to work. If your character is built with one half and mirrored, then you should know that the bones on each side should have the same name (case sensitive) and end with .L or .R for their side. Also, it's a good idea to add a few more loop cuts to your limbs to prevent them from folding completely flat.
Unit Select Ring
The unit select ring is bascially a projector. If you've ever tried this, you'd know that Unity has a standard asset package that comes with projector shaders, and you'd know that those shaders aren't for opaque images. In order to get the projector opaque, I took the light projector shader and changed the blend to "SrcAlpha OneMinusSrcAlpha" and commented out all the fog related code. The trick to using this shader is to know that opaque black is transparency and all color data to be drawn is completely transparent.
RTS Drag Select
You're probably thinking drag selection is as simple as just testing if the unit is between the Xs and Ys of the rectangle, which would work if the rectangle is not on an angle. In this game, the camera can rotate 360 degrees and tilt 180 degrees making the drag select programming a real drag. With the help of an online search I was able to get it working with a very awesome math technique you can find here.
It works like this: you find the area of the rectangle using an uncommon formula that works for any rectangle at any angle.
Rectangle Area = 0.5 * Abs|(yA−yC)⋅(xD−xB)+(yB−yD)⋅(xA−xC)|
Next you use the unit coordinate to make four triangles with the rectangle. If the sum of all the triangle areas are equal to the the rectangle area, then the unit is inside the rectangle.
Triangle Area = 0.5 * Abs|(x1(y2−y3)+x2(y3−y1)+x3(y1−y2))|
If the unit was outside the rectangle, then the sum of all the triangle areas would be greater than the area of the rectangle.
Interesting idea! I'll have to try the game out when it is ready.
Thanks for documenting the Blender work, it is helpful to a 3D modeling novice like me.
This is my first time implementing RTS unit movement and I am no expert, but I have learned the basics that hold true in many AAA RTS games. Most of the information I go over in this devlog can be found [url=
https://www.gamedeveloper.com/programmi ... t-movement]here[/url] and here.
The RTS unit pathfinding method can destroy a games frame rate if not used wisely. Having a large group of units and having each unit in that group use their own pathfinding method to go to the same place is a performance killer. Also there may be units that find an alternate route making the group split, which may not be what the player wants. This problem is simply solved by designating a leader. The leader would find the path and all other units will use the leaders path.
One factor that can adjust the pathfinding work load is the spacing of grid nodes that units move on. By increasing the spacing, you are effectively reducing the amount of processing power to find a path between the unit and the destination; by doing this, you also sacrifice pathfinding in tight spaces. The RTS map and pathfinding grid should be made with each other in mind for the best performance.
Unit to Unit Collisions
The pathfinding method will only take into account the terrain and structures the unit must move around, but since units are constantly moving and changing positions, their collisions are calculated as they move along their path. In this game I implement a collision prevention check to stop units from walking on top of each other. To make it work, each unit has a priority based on their distance to their goal. The unit closest to it's goal will be given the right of way.
There are also instances where I would allow units to pass through one another when getting into formation. I also tried resolving collisions that were not prevented, but that would result in a huge chain reaction of collision resolving in a tightly packed group. From the research, the best way to handle unit to unit collision is to have a grid that all the units shared to predict and resolve collisions with one another.
I'm just settling with my single collision prevention method for now since this game is a tower defense at it's core and this is my first time implementing RTS style movement.
Formations are important to allow units to flow in a group and prevent units from having the same destination point. A well thought out formation should take into consideration the terrain and structures by forming around them without splitting the group.
Handling Enemy Units
The easiest and most optimal way in my opinion for player units to check for enemy units in their surroundings is for player units to have a static list of enemy units to check distances with. When an enemy is created, it will add itself to the list and vice versa. If the enemy is in range for a unit, then the enemy is added to the units local 'enemies in range' list. Further layers will be added to prioritize what enemies to attack first.
Player unit movement will take in an additonal variable storing the command given by the player. With attack move, the unit should pause it's path to engage enemies in range before finishing the path. And with a regular move command, the unit should finish it's path before engaging any enemies in range.
Heads Up Display and User Interface
I've decided to go with the old fashioned bottom heads up display that most RTS games use. The tricky part about using this with Unity's canvas was the scaling. Using the expand with screen option would work for the heads up display, but the drag select would be thrown off.
So I opted to just keep the canvas at a constant pixel size and wrote my own scaling script that also keeps the aspect ratio of the canvas elements.
The A* pathfinding tutorial by Sebastian Lague can be found on YouTube. There were a few modifications I've made to the script to fix some issues I've found with A* pathfinding. I noticed how the A* pathfinding would fail if the target node was an unwalkable node, so I made a quick method to search for a nearby walkable node to find a path to. This way if a player commands units to move towards an unwalkable cliff, the units will still move to the general area.
Another problem with the A* pathfinding is islands. If the start or end points are surrounded by unwalkable nodes, then the path will fail. Determining if either one is on an island using a flood fill method can be expensive on the CPU depending on how large the island is.
One can simply try to solve this problem by finding islands when the grid is created at the start of the game, but that still won't find islands created by the player building walls. If anyone has any solutions, let me know!
Adjusting Paths for Unexpected Obstructions
To finish the pathfinding for units, units needed to find their way around buildings. Not just at the moment the path is created, but also during the path's execution to account for buildings created by the player after the path was made.To make buildings work with the pathfinding system, the buildings had to be grid snapped to the pathfinding nodes, and buildings width and length will be measured in whole nodes. For instance, this small bunker is one by one.
The pathfinding system was expanded to include a second buildable layer for units to find paths around. As buildings are built, the pathfinding grid will be updated and vice versa.
Units were then programmed to look for buildings between themselves and their next path node. If their path was in fact being obstructed by a building, the best way around it would be to find a new path which was expensive on the CPU. To limit pathfinding calls, buildings were listed for having already been accounted for and if the unit was in a group, the unit would notify the leader who will find a new path for the whole group.
In the case that an area is completely walled off and the pathfinding fails, a second pathfind will be made ignoring buildings and that path will be truncated where buildings are found. This way, units will still have a path towards the walled off area; solving the issue of islands with an extra pathfind instead of other more CPU intensive methods.
I found a really simple tutorial on how to make an RTS minimap in Unity by Alessandro Valcepina. At first glance, I thought that using a second camera for the minimap was a lazy and CPU intensive way to do it. But it turns out with the correct settings, this was a simple and light weight way to build a minimap.
I expanded on the minimap to register clicks and convert the minimap coordinates into game world coordinates by simply using proportions. With this, I was able to make the minimap move the camera anywhere on the map with a simple click.
The landing zones are now selectable and have the ability to collect supplies and units from chinooks. The landing zone UI will show two groups of items. The left group shows the items currently on the chinook and the right group shows what items the chinook will pickup upon return. When the player wants units, the units will be added to the pickup list. Any blank space will be converted to supplies when the chinook returns for pickup. Players can also cancel units by simply left clicking on their icon in the pickup list.
Unit Selecting UI
Unit selecting UI will be work like traditional RTS games. Selecting a single unit will give an in depth look at the unit and selecting multiple units will show icons with healthbars for each unit selected. When multiple units are selected, you can select a single unit by clicking on its icon in the UI. At this time, the UI can only fit 20 unit icons, so the limit of units that can be selected at once is 20.
The RTS user interface uses a lot of components including drag select, heads up display, minimap, and command menus. Having all these components work correctly in any resolution while keeping their aspect ratio was challenging in Unity. Having the canvas scaler do the scaling would interfere with the drag select working with the mouse position and the aspect ratio couldn't be kept.
So I wrote a custom scaling script to attach to each component. The proportional scaling was as simple as multiplying the original dimensions by the new resolution divided by the native resolution. To maintain aspect ratio, the orginial dimensions are multipled by one resolution axis and then adjusted towards their anchor. This script works for all the common resolutions, but for 21:9 and 32:9, the script will simply use proportional scaling.
To make the minimap, I used this tutorial by Alessadro Valcepina
To expand on the minimap to register clicks, I simply checked if the mouse was hovering over it by checking if the mouse was within its rectangle and if the mouse button was pressed. I did not use Unity's event system for the user interface because only one component can use the event system at a time.
At the current moment I am not using sprites for the progress bars and health bars, so I don't have the option to use a fill method. Instead, for the fill bar I set the pivot to 0 (left) and use the width to increment. Later, I will definitely give them sprites for good looks and make the coding much easier.
Last edited by PiscesStudios on Fri May 13, 2022 11:10 pm, edited 1 time in total.
Sandbag walls will be basic early game defenses that can be built by all soldier units. They will have the ability to garrison 2 soldiers. I'm also thinking about adding the ability to upgrade the sandbag walls with a mounted machine gun to buff attack and double layered bags to buff defense or hit points.
Building construction will be done by soldiers. Basic buildings like the sandbag walls can be built by any soldier, but more advanced buildings like bunkers and towers will only be built by engineer soldiers. Buildings can have more than one unit constructing it to speed up production and units can stop building at anytime the player chooses.
Buildings will have the same stats as units shown. Buildings will inheret the attack and range of the units that occupy it or the building could have an upgrade that buffs a stat(s). For instance, if a building has two general infrantry units occupying it, then the building would have their range and attack x2; defense and hit points are not inhereted. Buildings will have a garrisoned units section where you can see the icon of units currently garrisoned in the building, and the player can left click on those icons to ungarrison the units. The building command menu currently has 'ungarrison all' and 'attack' buttons. The building attack button will command all garrisoned units to target a specfic enemy unit as long as the enemy is in range.
Making Units Construct Buildings
The build command works like the move command. The placement object will give the selected unit(s) the build target. Once the path is complete, the unit will switch to the build animation instead of the idle animation. Each unit will call the build target's build method making it possible to have multiple units to speed up construction. The build method will simply progress using Time.deltatime. Once the time reaches the buildings build time, the building is complete.
Making Buildings Garrison Units
Buildings have a capacity variable that determines how many units can be garrisoned at once in the building, if the capacity is larger than zero, the UI will display the garrisoned units section. Buildings will have a list of units it holds and assign each unit a position for each slot. Garrisoned units will have their colliders disabled to prevent selecting; and while garrisoned, all code except the enemies in range check is disabled and the unit follows specific instructions for being garrisoned.