Making a RTS game #39: Boosting our game scene (Unity/C#)

Let’s continue working on our RTS: today, we’ll improve our game scene!

This article is also available on Medium.

The last articles have been pretty dense, and we’ve refactored big systems. So, what if we calmed down a bit and focused on some quick-win features this time? 🙂

Today, we’ll work on various little improvements for our game scene: we’ll add spawn points to precisely determine where the initial buildings will be placed, we’ll add some minimap icons for player units and we’ll even see how to take a screenshot of the current minimap to get a “snapshot” of the level!

Adding spawn points

So far in the series, we’ve been spawning just one building for our current player, in the middle of the screen (depending on where the camera was pointing initially). This is, of course, not very usable in a real RTS game!

Usually, those games have a system of spawn points: the map contains some reference anchors for each player in the session that are assigned at the beginning of the game.

There are various ways to assign those waypoints: at random, according to a pre-determined order… Here, I’ll simply take the order of the child game objects in the spawn points parent as reference – so the first player will be assigned to the spawn point that is the first child in the list, the second player will get the second child, and so on.

To implement this new spawn points system, let’s first jump in our scene and add the necessary objects. We will create a bunch of empty game objects and have a basic hierarchy, like this:

The spawn points themselves are placed on your terrain – they depend on the shape of your map, so it’s up to you to place them properly! 😉

To make those items easier to spot in your 3D scene, you can give them special gizmos renders in scene mode by clicking on the game object icon dropdown and picking one of the built-in icon types.

Which gives the following result in the scene:

Now, we can reference and use these objects in our scripts.

First, in the BuildingPlacer script, we’ll iterate through our session players and, for each of them, spawn the initial building at the matching spawn point. We will assume that there are enough spawn points for all players.

If the player I am assigning a spawn point to is myself, then I also need to recenter the camera on this specific part of the map. To do this, I’ll simply take the spawn point position and add some offset. But then, as you can see, we need to compute the minimap indicator after we’ve placed the camera – so, we also need to add this new public method, SetPosition(), to the CameraManager script to handle camera positioning and minimap indicator recomputing:

By the way, I’ll also take this opportunity to make the “altitude fix” optional: because I plan on having flatter maps than in my initial tests, I shouldn’t need the camera to auto-adapt its altitude according to the terrain. So I’ll just add a boolean flag to easily enable or disable this feature and, by default, leave it to false.

This way, now, the camera will simply move around the map at a fixed altitude that is determined by its initial position 😉

Important note: you might be experiencing some issues with the “click and drag” on the minimap to reposition the camera – we will be working on this next time when we handle different terrain sizes!

Showing the player units on the minimap

Next thing on my list today is to add some info on our minimap. For now, we are simply showing the terrain and the currently explored/unexplored areas. Although this is already a valuable piece of info, there are lots of other interesting things to show.

For example, we could have unique markers for the trees, the rocks, some special locations…

Today, let’s start by adding markers for our units. The idea is to have a little square on the minimap of the player’s colour at the position of each visible unit for this player. Something like this:

Here, I am the red player. And, of course, I only show the blue dots because I had one unit scout and explore this zone.

The overall process is pretty simple. Remember our “Minimap” layer? Well, we just need to put some additional quads on it, above our units, and those squares will automatically show on the minimap and follow the unit if it moves! 🙂

First, here is the “MinimapIcon” prefab – it is a simple quad, rotated to face upwards, with an unlit material on it. The scale sort of depends on how big you want the object to appear on the minimap – I’ve found that, for me, a 4×4 quad renders quite nicely, but you should try it out and adapt it to your own UI…

Now, let’s use this prefab inside of our unit prefabs!

What I’m going to do is modify the FogRendererToggler script a little to show and hide the “Mesh” sub-game object, instead of just this render; then, by making the “MinimapIcon” a child of this “Mesh” object, it will automatically be togged on and off at the same time.

So, let’s add the new prefab in the hierarchy, like this:

(You should do it for all of your unit prefab, in my case that’s: the House, the Tower, the Worker and the Soldier)

Then, let’s update the fog script:

Don’t forget to assign the mesh variable properly in the Inspector! 🙂

And finally, let’s make sure that the icon has the proper colour: we’ll initialise the renderer material colour when we first create the unit, depending on its owner variable:

If you run the game again, you’ll see that there are now minimap icons above the units, and because they are parented to the object itself, they’ll move along with the characters. Also, as soon as a unit enters the “in-view area”, its mesh and minimap icon are toggled on; and as soon as it leaves it, they’re both toggled back off.

As you can see, it’s pretty straight-forward… you could easily do the same for other objects on the terrain: just create some minimap icon, assign it to the “Minimap” layer and it will show on the map!

If you want to have a little drawing instead of a simple block of colour, you can use 2D sprites, or material textures, on the minimap icon. For example, this adds a “house” minimap icon to the spawn point:

Note: make sure to place it at a high enough Y position for the icon to be above the initial building minimap icon 😉

Taking a screenshot of the map!

Finally, let’s work on a very useful tool: a “snapshot” utility for our maps 🙂

Why is that interesting?

In the upcoming tutorials, we’ll want to display the list of available maps in a menu: to help the player see what these maps look like, it would be nice to show them a little preview of the terrain. There are, obviously, plenty of other things we could want to show on this preview but for now, we’ll just focus on the terrain and the spawn points.

This basically means that we want to take a screenshot of the minimap before the game starts, without any fog of war. This should give us a valid (although basic) overview of the map!

This feature requires two things:

  • a “capture script“: some C# code that can take in a camera, a destination image size and a file name, and that will render the current camera view as a JPG image
  • an “editor tool“: an additional tool to easily call our capture script! We’ll want to have a little button somewhere in the editor’s interface to quickly get a screenshot of our map in its current state.

The “capture script” is pretty easy: we simply need to take the camera’s render texture, read its pixels and copy them to the screenshot image, before saving the image as a JPG file. Here, the ReadPixels() method is key to getting and copying the pixels.

I’ll put all this C# logic in a MinimapCapture class:

At that point, any script can call MinimapCapture.TakeScreenshot(), which is quite cool! But… we want to run it in edit mode, and not only at runtime.

The solution is to create a custom editor tool with some input variables and a button to call the function in the editor: MinimapCaptureWindow.

Important note: just like any editor script, this script has to be saved in an “Editor” folder. Check out the Github project to see my file organisation 🚀 😉

If you want a more in-depth intro to writing custom editors in Unity, you can take a look at this other article I wrote a while ago about async process in Unity in edit mode; or even this previous tutorial from the RTS series.

Here, I’ll make a simple custom window that displays input fields for the file name, the image size, the map size, and also some slots for the camera and camera anchors to use for the render. We’ll need these references to properly center the minimap camera on the terrain while taking the screenshot. At the bottom, I’ll also have a button to actually take the screenshot that is only active when the camera and its anchor are filled.

This can be done with the following script that defines the MinimapCaptureWindow class:

The window will be accessible from the top-bar menu of your Unity editor, in the Tools > Minimap Capture menu:

Here, I’ve hardcoded the output path to be in a “MapCaptures” folder at the root of my assets folder, but you can of course “variabilise” this more if you want 🙂

After clicking the button, I get images like this one:

What’s really nice is that TakeScreenshot() can of course still be called from our runtime code, too – for example, we could make a “snapshot” of the level when we save… which will be very useful in the next tutorials, when we start to work on our main menu, and the save/load system!

Conclusion

In this episode, we’ve gone back to quick-win features and worked on simpler systems. We did however implement really useful things: the spawn points, the minimap icons and the map screenshots.

Next time, we’ll fix our minimap indicator to make it more efficient and more accurate!

Leave a Reply

Your email address will not be published.