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 XML, 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

// Scripts/Creators/ConstructionSelector.cs
// ProgressBarUpdate() is called by FixedUpdate() once per second
// to update the progress bar for building constructions
//
private void ProgressBarUpdate()
{		
  // sets the time by half a second
	progCounter += Time.deltaTime*0.5f;
	if(progCounter > progTime)
	{
		progCounter = 0;
		
    //update progress bars values
		((UISlider)ProgressBar.GetComponent("UISlider")).value += (float)(Time.deltaTime/buildingTime);				
		
		((UISlider)ProgressBar.GetComponent("UISlider")).value=
		Mathf.Clamp(((UISlider)ProgressBar.GetComponent("UISlider")).value,0,1);

    // Calculates remaining time
		remainingTime = (int)(buildingTime * (1 - ((UISlider)ProgressBar.GetComponent("UISlider")).value));

    // Updates the price for finishing the construction now
    // (Read more about the UpdatePrice function in the 
    // Shop Menu > In-App Purchase page at the bottom of that page...
		UpdatePrice (remainingTime);
    
    // Updates the remaining time counter
		UpdateTimeCounter(remainingTime);
    
		//building finished - the progress bar has reached 1
		if(((UISlider)ProgressBar.GetComponent("UISlider")).value == 1)																
		{
      // Construction finished sound
			((SoundFX)soundFX).BuildingFinished();

      // if this building is not finished on a battle map
      // only works if this is the player's home abse
			if(!battleMap)															
			{				
				//the dobbit previously assigned becomes available
				((Stats)stats).occupiedDobbits--;									

        // Assign the special settings depending on what type of building it
        // is that we just finished
        // Normal buildings don't need any of this...
        
				if(structureType=="Toolhouse")										
				{
          //increases total builders in Stats for the toolhouse									
					((Stats)stats).dobbits += 1;
				}
				else if(structureType=="Tatami")									
				{
          //increases total unit housing storage in Stats								
					((Stats)stats).maxHousing += storageAdd;
				}
				else if(structureType=="Forge")
				{
          // adds a notification above the building when the harvest is ready
					isProductionBuilding = true;			
				}
				else if(structureType=="Generator")
				{
          // adds a notification above the building when the harvest is ready
					isProductionBuilding = true;		
				}

				else if(structureType=="Barrel")									
				{  
          //increases total storage in Stats											
					((Stats)stats).maxMana += storageAdd;
				}
				else if(structureType=="Vault")
				{
          //increases total storage in Stats				
					((Stats)stats).maxGold += storageAdd;
				}
        
				// Because some of these buildings change UI stats
        // Update the UI 
				((Stats)stats).UpdateUI();
			}

      
      // parenting and destruction of components no longer needed
			foreach (Transform child in transform) 				
			{					
				if(child.gameObject.tag == "Structure")//structureType
				{
          // Actiavte the game object for the structure
					child.gameObject.SetActive(true);

          // Find the game object
					StructureSelector structureSelector = ((StructureSelector)child.gameObject.GetComponent ("StructureSelector"));
          // Disable the construction
					structureSelector.inConstruction = false;

          // Depending if this is a battle map
					if (battleMap)
            // Set the battleMap boolean for the structureSelector
						structureSelector.battleMap = true;
					else if (isProductionBuilding){						
						
            // If this is a production building as defined above
            // Here's where we attach the harvest message notification
            // above the building
						structureSelector.isProductionBuilding = true;
						RegisterAsProductionBuilding ();
						MessageNotification m = child.GetComponent<MessageNotification> ();
						m.structureIndex = constructionIndex;
						((ResourceGenerator)resourceGenerator).RegisterMessageNotification (m);
					}
          
          // Now we'll attach the grass to the building
					foreach (Transform childx in transform) 
					{	
						if(childx.gameObject.tag == "Grass")
						{									
							childx.gameObject.transform.parent = child.gameObject.transform;
							child.gameObject.transform.parent = ParentGroup.transform;

							break;
						}
					}
					break;
				}
			}

      // Lastly, we'll destroy the under construction object
			Destroy(this.gameObject);
			inConstruction = false;	
		}			
	}			
}

Can buildings be constructed instantly?

Yes, a good example to look at is the Shop Menu > Ambient Decorations documentation. In the XML 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:

<TimeToBuild>0</TimeToBuild>

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()									
{
	//panels are open / buttons were just pressed 
	if (!((Relay)relay).pauseInput && !((Relay)relay).delay)  
	{
    // play the click sound effect
		((SoundFX)soundFX).Click();
    
    // Check if the player has enough crystals compared to the price shown
		if (((Stats)stats).crystals >= priceno) 
		{
      // Deduct the crystals
			((Stats)stats).crystals -= priceno;
      // Update the crystals UI with the new value
			((Stats)stats).UpdateUI();
      // Set the Progress Bar equal to 1
      // the ProgressBarUpdate() function will take over
      // during the next FixedUpdate() call in a second
			((UISlider)ProgressBar.GetComponent ("UISlider")).value = 1;
		} 
		else 
		{				
      // Show an error, that they don't have enough crystals
			((Messenger)statusMsg).DisplayMessage("Insufficient crystals");
		}
	}
}