Creating an RTS in Unity: Part XIII

Update: This can now also be found at stormtek.geek.nz/rts_tutorial/part13.php, where the entire tutorial is now being hosted.

There is one very important aspect of expansion that we still do not have – the ability to construct new buildings. We will fix that this time by creating a worker Unit and using it for construction. We will allow the user to choose where to place the new structure, making sure that it does not collide with any of the existing objects in our world, and then present some simple graphical cues to indicate the progress of the building.

Worker

Let’s kick things off by creating a worker Unit. Inside the Unit folder create a new folder called Worker, with a new C# script called Worker.cs inside that.

using UnityEngine;

public class Worker : Unit {

	public int buildSpeed;

	private Building currentProject;
	private bool building = false;
	private float amountBuilt = 0.0f;

	/*** Game Engine methods, all can be overridden by subclass ***/

	protected override void Start () {
		base.Start();
		actions = new string[] {"Refinery", "WarFactory"};
	}

	protected override void Update () {
		base.Update();
	}

	/*** Public Methods ***/

	public override void SetBuilding (Building project) {
		base.SetBuilding (project);
		currentProject = project;
		StartMove(currentProject.transform.position, currentProject.gameObject);
		building = true;
	}

	public override void PerformAction (string actionToPerform) {
		base.PerformAction (actionToPerform);
		CreateBuilding(actionToPerform);
	}

	protected override void StartMove(Vector3 destination) {
		base.StartMove(destination);
		amountBuilt = 0.0f;
	}

	private void CreateBuilding(string buildingName) {

	}
}

We will use this as a starting point for a Worker’s behaviour. While we are at it we will also change the name of Init() in Unit.cs to SetBuilding(), since this is actually a more sensible name for what that method does. There are a couple of places this is used.

  • In AddUnit() located in Player.cs
  • The override in Harvester.cs

With that out of the way, let us have a quick look at what are wanting our Worker to do. We are defining a public build speed, so that we can play around with how fast production should happen inside Unity. Each Worker then needs a reference to the current Building it is working on, whether it is currently in ‘build’ mode, and how much it has constructed so far.

In the Start() method we define the Buildings that the worker can construct. For now this is all of the Buildings that we have defined so far. Remember that each of these needs to be a prefab object added to GameObjectList, and that each Building needs a BuildImage set as well. This means that we should add a build image to the Refinery we created last time (I have used the image below) and make it into a prefab, which we then need to add to the Buildings list in GameObjectList.

Refinery Build Image

Refinery

We will use SetBuilding() later on to allow us to click on a Building that is under construction and tell the Worker to move to it and start building. This will allow us to have more than one Worker assigned to the construction of each building. The action we wish to perform when a button in the side bar is clicked is to create that Building. We will define the behaviour of CreateBuilding() shortly.

The one thing that we need to do to allow this code to compile is to change the StartMove() method in Unit.cs to virtual so that we can override it.

public virtual void StartMove(Vector3 destination) {
...
}

Now that we have basic behaviour defined, we need to create an actual Worker object. Start by creating an empty object called Worker with Position (0, 0, 0). As usual, any objects currently located around (0, 0, 0) need to be shifted out of the way while we are constructing out Worker (in this case, our Refinery).

Add 5 cubes to the Worker called Body, Cab, ArmL, ArmR, Scoop. Now add 2 cylinders called SmokestackL and SmokeStackR and two capsules called TreadL and TreadR. Set the properties for each object as follows:

  • Body: Position = (0, 0.8, 0), Rotation = (0, 0, 0), Scale = (1.5, 0.2, 2)
  • Cab: Position = (0, 1.5, 0), Rotation = (0, 0, 0), Scale = (1.2, 1, 1.2)
  • ArmL: Position = (-0.7, 0.8, 1), Rotation = (0, 0, 0), Scale = (0.2, 0.2, 0.8)
  • ArmR: Position = (0.7, 0.8, 1), Rotation = (0, 0, 0), Scale = (0.2, 0.2, 0.8)
  • Scoop: Position = (0, 0.6, 1.5), Rotation  = (340, 0, 0), Scale = (1.7, 1, 0.1)
  • SmokestackL: Position = (-0.4, 2.3, -0.4), Rotation = (0, 0, 0), Scale = (0.2, 0.4, 0.2)
  • SmokestackR: Positiion = (0.4, 2.3, -0.4), Rotation = (0, 0, 0), Scale = (0.2, 0.4, 0.2)
  • TreadL: Position = (-0.7, 0.25, 0), Rotation = (0, 90, 90), Scale = (0.5, 0.9, 0.5)
  • TreadR: Position = (0.7, 0.25, 0), Rotation = (0, 90, 90), Scale = (0.5, 0.9, 0.5)

Now attach Worker.cs to the Worker object and add the Worker object to the Units object that your Player object has. For this to interact correctly we also need to set some values for our worker. I have used HitPoints = 100, MaxHitPoints = 100, MoveSpeed = 3, RotateSpeed = 2, and BuildSpeed = 5.

With this in place you should now be able to run your game and order your new Worker to move around the map.

Starting Building Creation

You should see that the Worker has two options showing up in the orders area representing the Buildings that it is able to construct. Clicking on one of these will call the ConstructBuilding() method in Worker.cs, but we have not yet defined what this does. Let’s do so now by adding the following code into that method.

private void CreateBuilding(string buildingName) {
	Vector3 buildPoint = new Vector3(transform.position.x, transform.position.y, transform.position.z + 10);
	if(player) player.createBuilding(buildingName, buildPoint, this, playingArea);
}

We define a point close to the Worker which will be the default place to put the Building. Then we tell the Player to create a Building with the name passed in, at the point specified, and being created by us. It is now up to the Player to decide how to proceed with creating the correct Building. We should add that method to Player.cs now.

public void CreateBuilding(string buildingName, Vector3 buildPoint, Unit creator, Rect playingArea) {
	GameObject newBuilding = (GameObject)Instantiate(ResourceManager.GetBuilding(buildingName), buildPoint, new Quaternion());
	tempBuilding = newBuilding.GetComponent< Building >();
	if (tempBuilding) {
		tempCreator = creator;
		findingPlacement = true;
		tempBuilding.SetTransparentMaterial(notAllowedMaterial, true);
		tempBuilding.SetColliders(false);
		tempBuilding.SetPlayingArea(playingArea);
	} else Destroy(newBuilding);
}

The idea here is to create a temporary version of the desired Building at the point specified and then to use that to find the actual position in the world where the Player wishes to construct that Building. By setting the Building to be transparent we make it obvious to the Player that this is not the final copy of their Building. We are also going to disable all colliders that the Building has to make sure that it does not trigger any interactions with other objects in our world while it is in this temporary state.

Before we can carry on we need to define some more variables at the top of Player.cs.

public Material notAllowedMaterial, allowedMaterial;

private Building tempBuilding;
private Unit tempCreator;
private bool findingPlacement = false;

We also need to define the three methods that are called on the temporary Building. These are all methods that would actually be useful to have on any of the objects that we define, so we will add them to WorldObject.cs. While we are at it we will also define a method to restore the original materials that the object had (even though we will not use it just yet).

public void SetColliders(bool enabled) {
	Collider[] colliders = GetComponentsInChildren< Collider >();
	foreach(Collider collider in colliders) collider.enabled = enabled;
}

public void SetTransparentMaterial(Material material, bool storeExistingMaterial) {
	if(storeExistingMaterial) oldMaterials.Clear();
	Renderer[] renderers = GetComponentsInChildren< Renderers >();
	foreach(Renderer renderer in renderers) {
		if(storeExistingMaterial) oldMaterials.Add(renderer.material);
		renderer.material = material;
	}
}

public void RestoreMaterials() {
	Renderer[] renderers = GetComponentsInChildren< Renderers >();
	if(oldMaterials.Count == renderers.Length) {
		for(int i=0; i<renderers.Length; i++) {
			renderers[i].material = oldMaterials[i];
		}
	}
}

public void SetPlayingArea(Rect playingArea) {
	this.playingArea = playingArea;
}

Notice that we are specifying whether to store the existing materials that the object has set. This will turn out to be very useful shortly. It does mean that we need to declare the list that we are going to store these in at the top of WorldObject.cs

private List< Material > oldMaterials = new List< Material >();

as well as including

using System.Collections.Generic;

so that we can use the List.

Finally we need to add the transparent material we are going to use to the Player. We will actually create two transparent materials at once, one for allowed and one for not allowed, and place them in our Materials folder. Set the shaders for both of these materials to be Transparent/Diffuse. We want the colour for Allowed to be (R=60, G=175, B=255, A=100) and the colour for NotAllowed to be (R=130, G=0, B=0, A=200). Now add these materials to the appropriate variables in the Player object.

Play the game now and you should see a temporary Building being placed in front of your Worker.

Building Placement

Now that we have the beginning of the creation process for a Building defined it is time to allow the Player to choose where to put that Building. This involves updating the behaviour of UserInput.cs slightly. The first thing we want to change is MouseHover().

private void MouseHover() {
	if(player.hud.MouseInBounds()) {
		if(player.IsFindingBuildingLocation()) {
			player.FindBuildingLocation();
		} else {
			// existing behaviour here ...
		}
	}
}

The idea here is that if the Player is currently trying to place a Building then do that, otherwise we want to do perform the existing hover behaviour. This requires the definition of those two methods inside Player.cs.

public bool IsFindingBuildingLocation() {
	return findingPlacement;
}

public void FindBuildingLocation() {
	Vector3 newLocation = WorkManager.FindHitPoint();
	newLocation.y = 0;
	tempBuilding.transform.position = newLocation;
}

With this code we are also deciding that we want to shift FindHitPoint() and FindHitObject() from UserInput.cs into WorkManager.cs. We also want them to take a start position, rather than always using the mouse position. They need to become

public static GameObject FindHitObject(Vector3 origin) {
	Ray ray = Camera.main.ScreenPointToRay(origin);
	RaycastHit hit;
	if(Physics.Raycast(ray, out hit)) return hit.collider.gameObject;
	return null;
}

and

public static Vector3 FindHitPoint(Vector3 origin) {
	Ray ray = Camera.main.ScreenPointToRay(origin);
	RaycastHit hit;
	if(Physics.Raycast(ray, out hit)) return hit.point;
	return ResourceManager.InvalidPosition;
}

Each reference to either of these methods in UserInput.cs now needs to reference WorkManager too, as well as passing

Input.mousePosition

as the parameter. This method is going to have the temporary Building perfectly centred on the mouse cursor in the world, so we want to hide the cursor if the Player is placing a Building. This can be done simply by adding another check into DrawMouseCursor() in HUD.cs.

if(mouseOverHud) {
	Screen.showCursor = true;
} else {
	Screen.showCursor = false;
	if(!player.IsFindingBuildingLocation()) {
		// existing draw cursor code ...
	}
}

Run your game now and you should see the temporary Building following the mouse cursor around the world. It jumps slightly when we the mouse is over other objects since we are getting the position of the object, rather than the ground underneath / behind it, but that is a problem I will leave you to solve. For now, it is enough that we can move the Building around, thus allowing the Player to choose a location that suits them.

Legal Build Position

Now that we can move the temporary Building around we need to determine whether the current position is legal – we don’t want to allow the Player to construct a new Building in the middle of an existing Building, for example. Start by adding the following code to Update() in Player.cs.

if(findingPlacement) {
	tempBuilding.CalculateBounds();
	if(CanPlaceBuilding()) tempBuilding.SetTransparentMaterial(allowedMaterial, false);
	else tempBuilding.SetTransparentMaterial(notAllowedMaterial, false);
}

We want to change the transparent material if the Player is allowed to place the Building at it’s current location. This provides a simple visual cue to them as to what they are allowed to do. We also need to make sure that we recalculate the bounds for the Building, since we will use these to determine if the location is already occupied. Now it is time to create the method CanPlaceBuilding() in Player.cs.

public bool CanPlaceBuilding() {
	bool canPlace = true;

	Bounds placeBounds = tempBuilding.GetSelectionBounds();
	//shorthand for the coordinates of the center of the selection bounds
	float cx = placeBounds.center.x;
	float cy = placeBounds.center.y;
	float cz = placeBounds.center.z;
	//shorthand for the coordinates of the extents of the selection box
	float ex = placeBounds.extents.x;
	float ey = placeBounds.extents.y;
	float ez = placeBounds.extents.z;

	//Determine the screen coordinates for the corners of the selection bounds
	List< Vector3 > corners = new List< Vector3 >();
	corners.Add(Camera.mainCamera.WorldToScreenPoint(new Vector3(cx+ex,cy+ey,cz+ez)));
	corners.Add(Camera.mainCamera.WorldToScreenPoint(new Vector3(cx+ex,cy+ey,cz-ez)));
	corners.Add(Camera.mainCamera.WorldToScreenPoint(new Vector3(cx+ex,cy-ey,cz+ez)));
	corners.Add(Camera.mainCamera.WorldToScreenPoint(new Vector3(cx-ex,cy+ey,cz+ez)));
	corners.Add(Camera.mainCamera.WorldToScreenPoint(new Vector3(cx+ex,cy-ey,cz-ez)));
	corners.Add(Camera.mainCamera.WorldToScreenPoint(new Vector3(cx-ex,cy-ey,cz+ez)));
	corners.Add(Camera.mainCamera.WorldToScreenPoint(new Vector3(cx-ex,cy+ey,cz-ez)));
	corners.Add(Camera.mainCamera.WorldToScreenPoint(new Vector3(cx-ex,cy-ey,cz-ez)));

	foreach(Vector3 corner in corners) {
		GameObject hitObject = WorkManager.FindHitObject(corner);
		if(hitObject && hitObject.name != "Ground") {
			WorldObject worldObject = hitObject.transform.parent.GetComponent< WorldObject >();
			if(worldObject && placeBounds.Intersects(worldObject.GetSelectionBounds())) canPlace = false;
		}
	}
	return canPlace;
}

This large method is finding the screen coordinate for each corner of the bounding box. We then fire a ray into the world to find the first object we would hit. If this object’s bounding box intersects the bounding box for the Building then the space is already occupied and so it cannot be built in.

Building Construction

With the ability to select a valid build location now defined we need to allow the Player to actually start construction. We will start this with a left mouse click, so we need to initiate that in UserInput.cs.

private void LeftMouseClick() {
	if(player.hud.MouseInBounds()) {
		if(player.IsFindingBuildingLocation()) {
			if(player.CanPlaceBuilding()) player.StartConstruction();
		} else {
			// existing left click logic ...
		}
	}
}

Now we can define StartConstruction() in Player.cs to handle the beginning of construction.

public void StartConstruction() {
	findingPlacement = false;
	Buildings buildings = GetComponentInChildren< Buildings >();
	if(buildings) tempBuilding.transform.parent = buildings.transform;
	tempBuilding.SetPlayer();
	tempBuilding.SetColliders(true);
	tempCreator.SetBuilding(tempBuilding);
	tempBuilding.StartConstruction();
}

It is here that we assign the new Building to the Player (since they are actually building it now), reinitialize any colliders the Building has, tell the worker that initiated the construction that it is assigned to the new Building, and tell the Building that it is now under construction. We want to initialize the Player for the Building at this point too, so we will take the current initialization found in Start() in WorldObject.cs and put it in a new method. This gives us

protected virtual void Start () {
	SetPlayer();
}

and

public void SetPlayer() {
	player = transform.root.GetComponentInChildren< Player >();
}

in WorldObject.cs. We already defined the basic behaviour for our Worker, but we still need to define StartConstruction() in Building.cs.

public void StartConstruction() {
	CalculateBounds();
	needsBuilding = true;
	hitPoints = 0;
}

The call to CalculateBounds() makes sure that the bounds for the Building are correct once construction has started. We will make use of hitPoints to track build progress, so we need to set hitPoints to 0 to indicate no initial progress. We also need to define

private bool needsBuilding = false;

at the top of Building.cs. Now add

if(needsBuilding) DrawBuildProgress();

to OnGUI() and define the method DrawBuildProgress()

private void DrawBuildProgress() {
	GUI.skin = ResourceManager.SelectBoxSkin;
	Rect selectBox = WorkManager.CalculateSelectionBox(selectionBounds, playingArea);
	//Draw the selection box around the currently selected object, within the bounds of the main draw area
	GUI.BeginGroup(playingArea);
	CalculateCurrentHealth(0.5f, 0.99f);
	DrawHealthBar(selectBox, "Building ...");
	GUI.EndGroup();
}

so that we can display the current build progress to the player. I have chosen to show this at all times the Building is under construction, but we could also choose to only display this if the Building is currently selected. We actually want to rewrite DrawSelectionBox() and CalculateCurrentHealth() in WorldObject.cs, as well as adding in DrawHealthBar(). Replace the existing code in WorldObject.cs with the code below.

protected virtual void DrawSelectionBox(Rect selectBox) {
	GUI.Box(selectBox, "");
	CalculateCurrentHealth(0.35f, 0.65f);
	DrawHealthBar(selectBox, "");
}

protected virtual void CalculateCurrentHealth(float lowSplit, float highSplit) {
	healthPercentage = (float)hitPoints / (float)maxHitPoints;
	if(healthPercentage > highSplit) healthStyle.normal.background = ResourceManager.HealthyTexture;
	else if(healthPercentage > lowSplit) healthStyle.normal.background = ResourceManager.DamagedTexture;
	else healthStyle.normal.background = ResourceManager.CriticalTexture;
}

protected void DrawHealthBar(Rect selectBox, string label) {
	healthStyle.padding.top = -20;
	healthStyle.fontStyle = FontStyle.Bold;
	GUI.Label(new Rect(selectBox.x, selectBox.y - 7, selectBox.width * healthPercentage, 5), label, healthStyle);
}

The negative padding on healthStyle in DrawHealthBar() makes sure that the text is drawn above the health bar. We then need to add the parameters to CalculateCurrentHealth() in Resource.cs, even though we are not using them.

protected override void CalculateCurrentHealth (float lowSplit, float highSplit) {
	// existing code ...
}

Now we need to make it so that our Worker can actually complete construction of the Building. Add the following code to Update() in Worker.cs.

if(!moving && !rotating) {
	if(building && currentProject && currentProject.UnderConstruction()) {
		amountBuilt += buildSpeed * Time.deltaTime;
		int amount = Mathf.FloorToInt(amountBuilt);
		if(amount > 0) {
			amountBuilt -= amount;
			currentProject.Construct(amount);
			if(!currentProject.UnderConstruction()) building = false;
		}
	}
}

If the Worker has been told to construct a certain Building, and that Building is still under construction, then we need it to add the amount of work done since last update to the Building. This requires that we add two new methods to Building.

public bool UnderConstruction() {
	return needsBuilding;
}

public void Construct(int amount) {
	hitPoints += amount;
	if(hitPoints >= maxHitPoints) {
		hitPoints = maxHitPoints;
		needsBuilding = false;
		RestoreMaterials();
	}
}

Run your game now and you will see that your worker is now able to construct new Buildings, and that these take time to complete.

Tidy Up

Things are working well, but there are still a couple of things that we need to tidy up before the Player can interact with their Worker properly.

  • We want to stop construction if the Worker is told to move away from the Building they are working on
  • We want to start construction on a specified Building if we click on it while a Worker is selected (reallocate which Building it is working on)
  • We want to allow the Player to cancel the process of finding a location for a new Building by right-clicking the mouse

The first case is actually really easy to fix. Add

building = false;

to the end of the overridden version of StartMove() in Worker.cs. This is now telling our Worker that if we start a move towards a location on the map, rather than to a Building, it is no longer constructing something.

To implement the second case we need to override MouseClick() in Worker.cs.

public override void MouseClick (GameObject hitObject, Vector3 hitPoint, Player controller) {
	bool doBase = true;
	//only handle input if owned by a human player and currently selected
	if(player && player.human && currentlySelected && hitObject && hitObject.name!="Ground") {
		Building building = hitObject.transform.parent.GetComponent< Building >();
		if(building) {
			if(building.UnderConstruction()) {
				SetBuilding(building);
				doBase = false;
			}
		}
	}
	if(doBase) base.MouseClick(hitObject, hitPoint, controller);
}

Notice that we are only executing the base behaviour for MouseClick() if we do not click on a Building under construction.

Implementing the final case requires adding an extra check into RightMouseClick() in UserInput.cs to give the following code.

private void RightMouseClick() {
	if(player.hud.MouseInBounds() && !Input.GetKey(KeyCode.LeftAlt) && player.SelectedObject) {
		if(player.IsFindingBuildingLocation()) {
			player.CancelBuildingPlacement();
		} else {
			player.SelectedObject.SetSelection(false, player.hud.GetPlayingArea());
			player.SelectedObject = null;
		}
	}
}

We also need to add CancelBuildingPlacement() to Player.cs.

public void CancelBuildingPlacement() {
	findingPlacement = false;
	Destroy(tempBuilding.gameObject);
	tempBuilding = null;
	tempCreator = null;
}

Awesome. I do believe that wraps things up for this time. We have successfully added a Worker that can create Buildings in the location specified by the Player. The sourcecode for this part can be found on github under the commit for Part 13.

Advertisements

18 thoughts on “Creating an RTS in Unity: Part XIII

  1. Steve says:

    Elgar – thank you so much for this tutorial. I am currently learning Unity/Coding and, thanks to this tutorial, it has been a very entertaining and rewarding ride so far! The game I hope to make is very RTS- based, so you are covering so many important topics for me to see!

    I feel bad asking for anything more given how much I’ve already benefited from the blog, but figured it’s worth a shot:

    1) Are you planning on converting the mouse control scheme to fit something like Starcraft’s in the future? In particular, Right Click = Action, not Left Click. If not, do you mind pointing me in a direction of how you’d recommend going about making the tweak?

    2) Have you thought about how much further you are going to go and what topics/features you are going to cover before you wrap it up? I hope you finish the game!

    3) I was surprised to see you use the built-in GUI and not use NGUI. Any reason you didn’t go that direction with the user interface?

    • Steve,

      That is no problem. It is great to hear that you are enjoying things 🙂 To answer your questions.

      1) Not at this stage. Reality is that both models have been used quite a lot, and this is the one that I prefer. I have thought a later post that could be useful would be to implement the other control scheme and then have a user option where they can choose which model they would like to use. But that will not be for quite a while at the very least. To implement it yourself you will need to start by changing behaviour in UserInput.cs – in particular LeftMouseClick() and RightMouseClick() – since this is where we start handling the mouse input from the user.

      2) Further plans include basic combat. Once that is done I will add in a basic menu system. This will lead to starting the game from a menu, complete with player selection. I will also cover saving the game (as JSON for ease of use) followed by loading from that saved game. This process will also include how to use an external library within your project too. I think some basic user configurable options (inside Settings menu) would also be a good thing.

      3) The built-in GUI was quick and easy at the time (when I was first mucking round with Unity and wrote the original version of most of this code). Also, I have not heard of NGUI. That is the only reason.

      • Thanks for the reply Elgar!

        1) Completely understand – I’m starting to get used to the left click-action myself 🙂

        2) That all sounds great- looking forward to it all!

        3) I have very little experience with NGUI (just with other tutorials) but it seems like a pretty great resource. If you continue to develop for Unity, I’d recommend taking a look (although it looks like the NGUI creator may be working on Unity’s next GUI in house now…)

        Thanks again- Looking forward to the rest of the blog!

  2. Before I talk about my issue, I just have to say what an amazing tutorial this is.
    I will admit that there are a few parts that I didn’t understand, but that’s just me. This tutorial has really helped me up to now, and at least I have a minimum knowledge to be able to continue with my project alone… more or less.

    So, here’s my main issue (and two others):
    In my project, I would like to allow the player to buy buildings ‘Addons’ or ‘Upgrades’. The latter will not only upgrade the buildings statistics and abilities, but will also modify them visually.
    And that’s where my problem is. I cannot seem to manage to create an ‘Addon’ class like the Building or Unit class.
    I’ve tried coding it myself, as well as copying the Unit code and modifying it -as well as other scripts- a tad to not allow these addons to either be selected or moved, and spawn at a pre-determined point on the building.
    Yet, I can’t get the addon icon to appear in my buildings actions.
    I thought that copying the Unit class code and removing the methods that rendered it mobile would work, but it would seem that that is not the case.
    How would I proceed to doing this, then? I have a feeling it’s extremely simple and my limited knowledge with CSharp isn’t allow me to see the solution.

    Second, how would i proceed to create units within a building and have them animate out?
    I’m wanting to have my ‘Recon’ units created by one of my buildings to be spawned within one of it’s garages, roll out of it, rotate to the buildings gate and drive through it to then end up at the rally point.

    I’m not sure if what I’m asking is complicated or not, and I may find my answers later on with some thorough searching throughout the interwebs.
    Anyway, thanks in advance, even though you might be too busy to answer me. 😉

    • The short answer to your first query is, I don’t know. I would have to play around with things quite a bit first. This would involve trying to replicate what you have done and see if I could get things working. And at the moment that is just not viable sorry.

      For your second query, a lot of things are already in place to support that. We have already set up a creation point that is different to a spawn point. So in theory you could create your building in such a way that there is a path ‘inside’ the building that your newly created unit could travel down (ending at the gates / doors of the building). If you then set the creation point to be at the start of this path you would be halfway there. All you would need to do then is to write some code that tells the newly created unit to move down this path, out the gates, and then head to the spawn point. Of course, this will probably be the hardest part of the entire procedure. Having said that, one of the things I have been toying with is adding in the concept of ways points – so you can tell your unit go to point A, then point B, point C, and so on until you reach a destination point. Initially I would have the unit move in a straight line between each point (rotating as needed in between), much like the basic unit movement is already. Each time you reach a way point you would then check the list of way points to see if there is a new point to head for. This would be useful for the player to be able to micro-manage unit movement a bit more – which could be important in certain combat scenarios, etc. If a system like this was in place then it would be really easy to adapt for your unit creation scenario – each of the way points would be a key part of the path heading from ‘inside’ the building to the door. In fact, now that you mention it (and now that I have put some thoughts down in response) that would be an intersting post to work out and write up. However, it is likely to be several months before I get to that. In the mean time, feel free to take the ideas I sketched out here and see what you can come up with. 🙂

  3. Dude – very nice tutorial – been playing around with Unity for quite a while – and this is definitely one of the best tutorials i have seen for scripting and stuff like that in general. Also for making an RTS one of the only and by far the best tutorials regarding Unity. Easy and understandable to follow. I would say though – that the code you’ve posted the last 5-6 posts in the tutorial all have some issues with GetComponentInChildren / GetComponent – you almost never fill in the part – e.g. GetComponent(): – but its pretty easy to understand and fix if u have basic knowledge of Unity programming.

    I was also kind of wondering if you are going to post additional tutorials to the series seeing as its been 3 months or so since the last update 🙂 – no pressure or hassle – just wondering – i learned alot along the ride 🙂

    Thank you very much!

    • Wow – typing in this comment i now see that WordPress apparently removes the “” lines… and so you probably did type them in – but the themes “disapears them” – hmm interesting – most likely because of the ability to use HTML in the comments lets try Bold
      Thanks again dude

    • Sebastian,

      I am definitely planning on further updates. It is just a matter of finding time … Things should be settling down in the next month, allowing me some time to focus on this again.

  4. Elgar,

    Great set of tutorials , thanks a lot. Have you thought of hosting this somewhere , so that people who are trying to learn can quickly get a feeling of what is being tried to achieve . I think that would really bump up interest among folks who are landing here , trying to learn RTS in unity.
    Let me know what you think.

  5. Joseph says:

    Hello Again, I am having a problem with the spawn point after creating a building, the original building is fine but when I use the Worker to build another building its spawn point is set in the center (0,0,0) instead of in front of the building like the original, I have no clue where to fix this issue hopefully you can point me in the right direction?

  6. anon says:

    Collider[] colliders = GetComponentsInChildren();

    missing after GetComponentsInChildren

    Renderer[] renderers = GetComponentsInChildren();

    Should be (2 places)?

    List corners = new List();

    Think it should be List?

    Hope it helps.

    • anon says:

      Ugh, HTML tags. Replace \ with open tag, / with close tag:

      Collider[] colliders = GetComponentsInChildren();

      \Collider/ missing after GetComponentsInChildren

      Renderer[] renderers = GetComponentsInChildren\Renderers/();

      Should be \Renderer/ (2 places)?

      List corners = new List();

      Think it should be List\Vector3/?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s