Resource Generators
Reminder - Keep Daily Backups
When working on a strategy game with a kit as big as the Complete Kit - always keep a working daily backup! Save yourself the trouble of rolling-back changes and losing work.
What are resource generators?
Your game can include buildings that create in-game resources like gold. These are called resource generators and the city building kit comes with two in-game resource examples (gold and mana) plus one rare currency example. In the store you'll see the two generator examples, gold mine forge (example currency #1) and the mana generator (example currency #2)
Resource #1 Generator (Gold)
Like many free-to-play strategy games, the first resource generator produces gold as you can see in the below example.
Resource #2 Generator (Liquid Mana)
The second type of resource generator in the city building kit is liquid mana, as seen in the below screenshot.
Can I change these currencies to others, like wood or stone?
Yes, you can change everything inside the city building kit. All the source code is included. The easiest way to change one of the existing currency examples like gold to wood without adding more currencies is to update the gold sprite images. The source code can remain the same.
Can I add more currencies to my game?
Yes, you can add more to your game by copying the existing source code for the first two currencies examples - gold and liquid mana. Or to have more than one purchase currency, you'll want to work with the rare crystal gem example included in the kit.
Adding more currencies to your game will take some time to fully understand. We'd hope you'd become comfortable with the kit source code first and editing the existing two currency examples before attempting more difficult customizations like additional currencies.
Resource BuildingsCategory.asset Example
Here's an example of how to do a resource generator, in this case a gold mine, in the ScriptableObject (SO). For resource generators, the single difference most noticeable is that ProdType (production type) is set to either Gold or Mana, instead of None.
For a closer look at the SO for resource generators and storage units, you want to open the Shops Menu > Resource Generators section of the documentation.
Updating the ConstructionSelector.cs
If you're adding a new resource building to your game and not working from one of the existing examples (we highly recommend you work from the examples first!) then you'll want to edit the list seen in Scripts/Creators/ConstructionSelector.cs ProgressBarUpdate() function which runs when the construction has completed.
The following is an excerpt from that function -- you'll see the two examples for resource buildings have the line isProductionBuilding = true marked. Make sure you do this for your own resource buildings too since later in the function it sets up the notifications for harvesting above the resource buildings.
// ProgressBarUpdate() excerpt
// from Scripts/Creators/ConstructionSelector.cs
//
// The following part of the function updates the player stats depending
// on what sort of special features the building they create
//the builder previously assigned becomes available
((Stats)stats).occupiedDobbits--;
// What type of building is it?
// Any special building attributes are added to the player stats
if(structureType=="Toolhouse")
{
//increases total builders since they built a builder house
((Stats)stats).dobbits += 1;
}
else if(structureType=="Tatami")
{
// increases total unit storage in Stats because they built
// the Tatami example which has unit storage
((Stats)stats).maxHousing += storageAdd;
}
else if(structureType=="Forge")
{
// if it's a production building
// later in this fuction we'll register it for
// notifictions above the building using
// RegisterAsProductionBuilding
isProductionBuilding = true;
}
else if(structureType=="Generator")
{
// if it's a production building
// later in this fuction we'll register it for
// notifictions above the building using
// RegisterAsProductionBuilding
isProductionBuilding = true;
}
else if(structureType=="Barrel")
{
//increases total mana (currenct #2) storage in Stats
((Stats)stats).maxMana += storageAdd;
}
else if(structureType=="Vault")
{
//increases total gold (currency #1 storage in Stats
((Stats)stats).maxGold += storageAdd;
}
// since we've probably changed values seen in the UI
// (e.g. extra storage with a vault) then update the stats UI
((Stats)stats).UpdateUI();
// .........
How resource generators work
Resource generators work by producing a certain amount of resources per hour (specified in BuildingsCategory.asset ). In the case of the gold mine forge example above, you can see it's 100 gold per hour which roughly translates to approximately 0.28 gold per second.
The function RunEconomy() in the Scripts/Creators/ResourceGenerator.cs script is what manages the resource generation each second. It's invoked on start in this script to repeat each second - calculating the new resource generation total. See the following excerpt:
private void RunEconomy()
{
RunProduction (1);
}
public void FastPaceEconomyAll(int minutesPass) //called by save/load games for already finished/functional buildings
{
RunProduction (60 * minutesPass);
}
public void InitializeEconomy()
{
InvokeRepeating ("RunEconomy", 1, 1);
}
private void RunProduction(int timefactor)//timefactor seconds=1 minutes=60
{
for (int i = 0; i < ExistingEconomyBuildings.Count; i++)
{
GameResourceType prodType = ExistingEconomyBuildings [i].ProdType;
if (prodType != GameResourceType.None)
{
float produce = ((float)ExistingEconomyBuildings [i].ProdPerHour / 3600)*timefactor;
bool displayNotification = false;
switch (prodType) {
case GameResourceType.Gold:
if (ExistingEconomyBuildings [i].storedGold + produce < ExistingEconomyBuildings [i].StoreCap)
{
ExistingEconomyBuildings [i].ModifyGoldAmount (produce);
//if((float)existingEconomyBuildings [i].storedGold/existingEconomyBuildings [i].StoreCap>0.1f)//to display when 10% full
if(ExistingEconomyBuildings [i].storedGold>1)
displayNotification = true;
}
else //fill storage
{
ExistingEconomyBuildings [i].ModifyGoldAmount
(ExistingEconomyBuildings [i].StoreCap-
ExistingEconomyBuildings [i].storedGold);
displayNotification = true;
}
if(displayNotification)
DisplayHarvestNotification (ExistingEconomyBuildings [i].structureIndex, ExistingEconomyBuildings [i].storedGold);//i
break;
case GameResourceType.Mana:
if (ExistingEconomyBuildings [i].storedMana + produce < ExistingEconomyBuildings [i].StoreCap)
{
ExistingEconomyBuildings [i].ModifyManaAmount (produce);
//if((float)existingEconomyBuildings [i].storedMana/existingEconomyBuildings [i].StoreCap>0.1f)//to display when 10% full
if(ExistingEconomyBuildings [i].storedMana>1)
displayNotification = true;
}
else //fill storage
{
ExistingEconomyBuildings [i].ModifyManaAmount
(ExistingEconomyBuildings [i].StoreCap-
ExistingEconomyBuildings [i].storedMana);
displayNotification = true;
}
if(displayNotification)
DisplayHarvestNotification (ExistingEconomyBuildings [i].structureIndex, ExistingEconomyBuildings [i].storedMana);
break;
}
}
}
}
The below screenshot shows what a harvest notification looks like above buildings, and as you can read in the source excerpt above, this notification shows when greater than 1 is ready for collection (tap or click to collect). This can be changed to show when a certain percent of the internal storage is reached for that structure, like 10% as seen in the commented out line in the function above.
After a certain amount is reached, the value of the resource yet to be collected appears above the resource structure. This continues accumulating until you reach the resource cap. In the case of the above example
EconomyBuilding.cs
How to get the "gameObject" of each EconomyBuilding (from the script "script/Creators/EconomyBuilding"):
The EconomyBuilding script acts like a production account (as opposed to a bank account). Each building that produces something is registered in the ResourceGenerator along with its index for unique identification. This script is not attached to the building so you can recover it.
If you need to register/retrieve the building position, you can record this information with the StructureSelector script that all buildings have. Buildings based on grid position already register the grid col/row to calculate the position. Modify the behaviour of this class for structures to be aware of its position on the map.
What is internal storage?
To keep the player engaged with your game they collect resources from their resource generators by tapping or clicking on the generator to add the total resources generated since last harvest collection to the player's stats.
Waiting too long means they miss out on resources that are generated because each building has a maximum storage cap defined in the BuildingsCategory.asset as seen above. This StoreCap item is used in the RunEconomy() function to throw away resources gained per second if the storage cap has been reached.
// Excerpt from RunEconomy() function in
// Scripts/Creators/ResourceGenerator.cs
// this function runs once per second
// The following checks if the stored gold plus the resources
// generated in the last second exceed the storage cap
// If exceeded, resources are discared until the player collects
// the stored resources.
if (ExistingEconomyBuildings [i].storedGold + produce < ExistingEconomyBuildings [i].StoreCap)
{
ExistingEconomyBuildings [i].ModifyGoldAmount (produce);
//if((float)existingEconomyBuildings [i].storedGold/existingEconomyBuildings [i].StoreCap>0.1f)//to display when 10% full
if(ExistingEconomyBuildings [i].storedGold>1)
displayNotification = true;
}
Can I remove the storage cap from buildings?
Yes. If you still want the resource structures to collect resources until they've been tapped, but not allow the resources to generate automatically without the need to collect - then change the StoreCap variable to an incredibly high value, such as the below example:
Can I make resource generate automatically without collection?
Yes, if you change the StoreType from Internal to Distributed then the resource are automatically added to the player stats rather than being stored in the resource collectors until the structure's StoreCap is reached.
What happens when you tap the structure to harvest?
First, you should understand that every building has a unique structureIndex ID (for example, 1, 2, 3, etc.) this allows us to know which resource building we are collecting resources from. This structureIndex is set on the PlaceStructure() function triggered when you are placing a structure purchased in the store. See the excerpt below:
// Excerpt from Scripts/Creators/BaseCreator.cs
// when placing a structure, it adds a unique number
// to the existing structure index so we can identify this structure
// when tapping on it
public void PlaceStructure()
{
Vector3
grassPos = selectedGrass.transform.position,
structurePos = selectedStructure.transform.position;
// Only runs the following on first place, not when reselecting a building
if(!isReselect)
{
// Increments the structureIndex
((Stats)stats).structureIndex++;
//unique number for harvesting, the structureIndex we just incremented
structureIndex = ((Stats)stats).structureIndex;
//.....
With a structureIndex variable attached to every building, we can then call the Harvest() function in ResourceGenerator.cs.
But first, we need to detect when the player clicks on the structure. The ReSelect() function in Scripts/Creators/StructureSelector.cs does just that.
When a building is selected, this function is called. In the checks - pointed out at the end of this excerpt below we can call the Harvest function with the proper structure index.
// Excerpt from Scripts/Creators/StructureSelector.cs
// ReSelect() function is triggered when selecting a building
public void ReSelect()
{
// ........
if(!battleMap)
{
if(!((StructureCreator)structureCreator).isReselect &&
!((Relay)relay).pauseInput)
{
if (messageNotification != null&&messageNotification.isReady)
{
messageNotification.FadeOut ();
ResourceGenerator.Harvest (structureIndex);
messageNotification.isReady = false;
return;
}
((BaseCreator)structureCreator).isReselect = true;
int childrenNo = gameObject.transform.childCount;//grass was parented last
((BaseCreator)structureCreator).OnReselect(gameObject, gameObject.transform.GetChild (childrenNo-1).gameObject, structureType);
}
}
// ........
The Harvest() function in Scripts/Creators/ResourceGenerator.cs called from ReSelect() in Scripts/Creators/StructureSelector.cs does the total resource addition to the stats.
It's actually quite simple. Since ReSelect told us the structureIndex, all we need to do is loop through the economy buildings until we found the structure that matches the structureIndex value. Then determine its type of resource and add this resource to the player's total. See the excerpt below:
public void Harvest(int index)
{
for (int i = 0; i < ExistingEconomyBuildings.Count; i++)
{
if (ExistingEconomyBuildings [i].structureIndex == index)
{
switch (ExistingEconomyBuildings [i].ProdType)
{
case GameResourceType.Gold:
((Stats)stats).AddResources ((int)ExistingEconomyBuildings [i].storedGold, 0, 0);
ExistingEconomyBuildings [i].storedGold -= (int)ExistingEconomyBuildings [i].storedGold;
break;
case GameResourceType.Mana:
((Stats)stats).AddResources (0, (int)ExistingEconomyBuildings [i].storedMana, 0);
ExistingEconomyBuildings [i].storedMana -= (int)ExistingEconomyBuildings [i].storedMana;
break;
}
ResetHarvestNotification(i);
((Stats)stats).UpdateUI ();
break;
}
}
}
Resetting the harvest notification
At the end of the function above this line resets the gather resource notification so it no longer appears until the RunEconomy() described above triggers the notification again.
ResetHarvestNotification(i);
Below is an example of what the resource building looks like after resources have been gathered.
How are player stats updated?
Seen in the above Harvest() function excerpt, the last line calls a UI update which then reflects the changes from 99900 to after 99916 with the 16 gold collected from the gold mine forge in the below screenshots.
((Stats)stats).UpdateUI ();
Where are the prefabs?
All of the game object prefabs are set in the ScriptableObjects at the path Assets/CityBuildingKit/Resources/Assets/
For example take a look at the BuildingsCategory.asset file below :
In addition, you will want to look at GameManager > Creators > BuildingCreator (prefabs are also there) This is discussed in the Buildings > Part 2: Customize Menus section of the documentation. Prefabs are used by the creator for construction and by SaveLoadBattle for loading during battle.
GameManager > Creators > BuildingCreator
In the GameManager > Creators > BuildingCreator we have the list of game object prefabs used by the creator in addition to certain build settings used by the Scripts/Creators/BaseCreator.cs script. Let's describe these below. But first, here's how to open the BuildingCreator Inspector
In the Inspector you'll notice a few arrays, here's a description of each one. It's the same for every type of game object you can build in the game except for the RemovableCreator (removables are not for players to construct but rather remove -- see Player Removable Objects doc for details)
Array Title | Description |
---|---|
Structure Pf | The structure prefab. |
Grass Pf | 1x1 to 5x5 dark green grass collider grid prefabs list. These you don't have to edit, they are shared by all structures in the game based on their grid size. |
Construction Pf | Under construction prefab list. There's 3 different sizes of this for 1x1 to 3x3 grid size construction projects. |
Grass Types | Size of this array matches the the Structure Pf array size. We tell which Grass Pf element to use with each structure. Depends on structure size whether they take 1x1 (Grass Pf element 0) like a wall segment or 3x3 (Grass Pf element 2) like the large gold vault. Tatami is the only object that takes grass collider 5x5 ( Grass Pf Element 4). |
Construction Types | Array size matches Structure Pf. Like grass types, we match the construction prefab grid size too. Since there's 3 different sizes of construction prefabs, this ranges from values 0 to 2. By default, we set most structures to use the 3x size. |
Pivot Corrections | Array size matches Structure Pf. Odd size grid structures (1x1 and 3x3) need a pivot correction so they don't appear accidentally off-center, taking more grid space than necessary. Pivot Correction does this. |
Is Array | Array size matches Structure Pf. If set to 1, uses the row making field builder for construction instead of the usual construction. The only objects that use this are the wall segments that let you pick a start and end point and automatically constructs a repeating row of the structure between the points. |
Is Instant | Array size matches Structure Pf. For items you set TimeToBuild to 0 (instant build) in the SO, you also want to set the elements Is Instant boolean to 1 in this array. The only objects that use this in the demo are the wall segments. |
What about resource storage structures?
Locate the Resource Storage section of the documentation on the right for details about the resource storage building examples included with the kit.
Updated less than a minute ago