Construction Timers

👍

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.

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 construction timers?

Popular free-to-play games use construction timers to monetize their game by giving an extra opportunity for players to pay to skip waiting. This feature can be disabled easily in the SO files, instructions below

900

Construction timer, example

What script controls the construction timers?

There's one script to look at, Scripts/Creators/ConstructionSelector.cs which controls the Progress Bar and timing countdown for the buildings under construction

private void ProgressBarUpdate()
	{		
		progCounter += Time.deltaTime*0.5f;
		if(progCounter > progTime)
		{
			progCounter = 0;
			
			ProgressBar.value += Time.deltaTime/buildingTime;				//update progress bars values
			
			ProgressBar.value= Mathf.Clamp(ProgressBar.value,0,1);

			remainingTime = (int)(buildingTime * (1 - ProgressBar.value));

			UpdatePrice (remainingTime);
			UpdateTimeCounter(remainingTime);

			if(ProgressBar.value == 1)				//building finished - the progress bar has reached 1												
			{
				((SoundFX)soundFX).BuildingFinished();

				if(!battleMap)															//if this building is not finished on a battle map
				{				
					//xml order: Forge Generator Vault Barrel Summon Tatami
					((Stats)stats).occupiedDobbits--;									//the dobbit previously assigned becomes available

					if(_structureType=="Toolhouse")										//increases total storage in Stats																	
					{
						((Stats)stats).dobbits += 1;
					}
					else if(_structureType=="Tatami")									//increases total storage in Stats																	
					{
						((Stats)stats).maxHousing += storageAdd;
					}
					else if(_structureType=="Forge")
					{
						isProductionBuilding = true;			//((Stats)stats).maxGold += storageAdd;	
					}
					else if(_structureType=="Generator")
					{
						isProductionBuilding = true;			//((Stats)stats).maxMana += storageAdd;					
					}

					else if(_structureType=="Barrel")									//increases total storage in Stats																	
					{
						((Stats)stats).maxMana += storageAdd;
					}
					else if(_structureType=="Vault")
					{
						((Stats)stats).maxGold += storageAdd;
					}

					((Stats)stats).UpdateUI();
				}

				foreach (Transform child in transform) 									//parenting and destruction of components no longer needed
				{					
					if(child.gameObject.CompareTag("Structure"))//structureType
					{
						child.gameObject.SetActive(true);

						StructureSelector structureSelector = child.gameObject.GetComponent<StructureSelector>();
						structureSelector.inConstruction = false;

						structureSelector.Id = Id;
						structureSelector.Level = Level;
						structureSelector.CategoryType = CategoryType;
						
						if (battleMap)
							structureSelector.battleMap = true;
						else if (isProductionBuilding)
						{
							structureSelector.structureType = _structureType;
							structureSelector.isProductionBuilding = true;

							structureSelector.LateRegisterAsProductionBuilding ();//0.5f

							if (finishedOffLine) 
							{								
								structureSelector.LateCalculateElapsedProduction (elapsedTime);//1.0f
							}



							/*
							MessageNotification m = child.GetComponent<MessageNotification> ();
							m.structureIndex = constructionIndex;
							((ResourceGenerator)resourceGenerator).RegisterMessageNotification (m);
							*/
						}
						foreach (Transform childx in transform) 
						{	
							if(childx.gameObject.CompareTag("Grass"))
							{
								var o = child.gameObject;
								childx.gameObject.transform.parent = o.transform;
								o.transform.parent = ParentGroup.transform;

								break;
							}
						}
						break;
					}
				}

				Destroy(gameObject);
				inConstruction = false;	
			}			
		}			
	}

Can buildings be constructed instantly?

Yes, a good example to look at is the Shop Menu > Ambient Decorations documentation. In the SO (ScriptableObject) AmbientCategory.asset you can set the TimeToBuild element for any structure to 0 like seen in the below example to instantly build it when the player purchases the structure:

369

Can you use In-App Purchase gems to instantly finish construction?

Yes. You want to look at the Shop Menu > In-App Purchase documentation for more details.

900

Gem purchase button. Click to view closer.

As you can see in the above screenshot, there's a button you can push next to every construction project that triggers the Finish() function in Scripts/Creators/ConstructionSelector.cs

This function checks if the player has enough of the rare currency and deducts it before accelerating the ProgressBar to it's full size which triggers ProgressBarUpdate() to finish the construction during the next FixedUpdate() call. FixedUpdate() runs every second.

// Scripts/Creators/ConstructionSelector.cs
// The following Finish() function is triggered by the button push

	public void Finish()									
	{
		//if(!battleMap) //no need to check, the finish button is not visible on the battle map
		//{
		if (!((Relay)relay).pauseInput && !((Relay)relay).delay)  //panels are open / buttons were just pressed 
		{
			((SoundFX)soundFX).Click();
			if (((Stats)stats).crystals >= priceno) 
			{
				((Stats)stats).crystals -= priceno;
				((Stats)stats).UpdateUI();
				ProgressBar.value = 1;
			} 
			else 
			{				
				MessageController.Instance.DisplayMessage("Insufficient crystals");
			}
		}
		//}
	}