How to Make a Strategy Game in Godot – Part 2

Introduction

Welcome back to Part 2 of creating a strategy game in the Godot game engine!

In Part 1, we began showing you how to build your first strategy game in Godot by setting up highlight-able tiles, buildings, and the basic UI which will tell the players crucial information about their resource management.Ā  All in all, we have a great foundation to work with so we can finish our project and add it to our portfolio!

Of course, with this being Part 2, there is still more go.Ā  We need to finish up our map system, set up our UI properly, give ourselves the ability to place buildings, and even implement the overall turn-based gameplay flow.Ā  So, if you’re prepared, and let’s finish this resource management game and become master Godot developers!

Project Files

In this tutorial, we’ll be using some sprites from the kenney.nl website (an open domain game asset website) and fonts from Google Fonts. You can of course choose to use your own assets, but we’ll be designing the game around these:

  • Download the sprite and font assets we’ll be using for this tutorial here.
  • Download the complete strategy game Godot project here.

ON SALE – FINAL DAYS
BUILD GAMES
BUILD GAMES WITH GODOT

āœ“ 250+ coding courses

āœ“ Interactive lessons

āœ“ Guided learning paths

āœ“ Help from expert mentors

GET IT ALL FOR JUST
$1

Finishing the Map Script

To begin, let’s go back to ourĀ Map script. TheĀ place_building function gets called when we want to place down a building on a tile.

# places down a building on the map
func place_building (tile, texture):

    tilesWithBuildings.append(tile)
    tile.place_building(texture)

    disable_tile_highlights()

Finally, theĀ _readyĀ function gets called when the node is initialized. Here, we want to get all of the tiles in the “Tiles” group and setup the initial base building.
func _ready ():

    # when we're initialized, get all of the tiles
    allTiles = get_tree().get_nodes_in_group("Tiles")

    # find the start tile and place the Base building
    for x in range(allTiles.size()):
        if allTiles[x].startTile == true:
            place_building(allTiles[x], BuildingData.base.iconTexture)

Back in theĀ MainScene, let’s select the center tile and enableĀ Start Tile.

Selecting the center tile and making it the starting tile.

Now if we press play, you should see that the center tile has a Base building on it.

The start tile now displays the Base building.

GameManager Script

TheĀ GameManager script is what’s going to manage our resources and states. Go to theĀ MainScene and select theĀ MainScene node. Create a new script attached to it calledĀ GameManager. We can start with our variables.

# current amount of each resource we have
var curFood : int = 0
var curMetal : int = 0
var curOxygen : int = 0
var curEnergy : int = 0

# amount of each resource we get each turn
var foodPerTurn : int = 0
var metalPerTurn : int = 0
var oxygenPerTurn : int = 0
var energyPerTurn : int = 0

var curTurn : int = 1

# are we currently placing down a building?
var currentlyPlacingBuilding : bool = false

# type of building we're currently placing
var buildingToPlace : int

# components
onready var ui : Node = get_node("UI")
onready var map : Node = get_node("Tiles")

TheĀ on_select_building function gets called when we press one of the three building UI buttons. This will be hooked up later on when we create theĀ UI script.
# called when we've selected a building to place
func on_select_building (buildingType):

    currentlyPlacingBuilding = true
    buildingToPlace = buildingType

    # highlight the tiles we can place a building on
    map.highlight_available_tiles()

TheĀ add_to_resource_per_turn function adds the givenĀ amount to the givenĀ resource per turn.
# adds an amount to a certain resource per turn
func add_to_resource_per_turn (resource, amount):

    # resource 0 means none, so return
    if resource == 0:
        return
    elif resource == 1:
        foodPerTurn += amount
    elif resource == 2:
        metalPerTurn += amount
    elif resource == 3:
        oxygenPerTurn += amount
    elif resource == 4:
        energyPerTurn += amount

TheĀ place_building function will be called when we place down a tile on the grid.
# called when we place a building down on the grid
func place_building (tileToPlaceOn):

    currentlyPlacingBuilding = false

    var texture : Texture

    # are we placing down a Mine?
    if buildingToPlace == 1:
        texture = BuildingData.mine.iconTexture

        add_to_resource_per_turn(BuildingData.mine.prodResource, BuildingData.mine.prodResourceAmount)
        add_to_resource_per_turn(BuildingData.mine.upkeepResource, -BuildingData.mine.upkeepResourceAmount)

    # are we placing down a Greenhouse?
    if buildingToPlace == 2:
        texture = BuildingData.greenhouse.iconTexture

        add_to_resource_per_turn(BuildingData.greenhouse.prodResource, BuildingData.greenhouse.prodResourceAmount)
        add_to_resource_per_turn(BuildingData.greenhouse.upkeepResource, -BuildingData.greenhouse.upkeepResourceAmount)

    # are we placing down a Solar Panel?
    if buildingToPlace == 3:
        texture = BuildingData.solarpanel.iconTexture

        add_to_resource_per_turn(BuildingData.solarpanel.prodResource, BuildingData.solarpanel.prodResourceAmount)
        add_to_resource_per_turn(BuildingData.solarpanel.upkeepResource, -BuildingData.solarpanel.upkeepResourceAmount)

    # place the building on the map
    map.place_building(tileToPlaceOn, texture)

Finally, we have theĀ end_turn function which gets called when we press the end turn button.
# called when the player ends the turn
func end_turn ():

    # update our current resource amounts
    curFood += foodPerTurn
    curMetal += metalPerTurn
    curOxygen += oxygenPerTurn
    curEnergy += energyPerTurn

    # increase current turn
    curTurn += 1

Okay so we’ve got our GameManager class all setup but there’s no real way for it to function. In order to connect everything together, we need to create aĀ UI script.

UI Script

In theĀ UI scene, select the UI node and create a new script calledĀ UI. Let’s start with our variables.

# container holding the building buttons
onready var buildingButtons : Node = get_node("BuildingButtons")

# text displaying the food and metal resources
onready var foodMetalText : Label = get_node("FoodMetalText")

# text displaying the oxygen and energy resources
onready var oxygenEnergyText : Label = get_node("OxygenEnergyText")

# text showing our current turn
onready var curTurnText : Label = get_node("TurnText")

# game manager object in order to access those functions and values
onready var gameManager : Node = get_node("/root/MainScene")

First, we have theĀ on_end_turn function. This gets called when a turn is over, so we’re going to reset the UI.
# called when a turn is over - resets the UI
func on_end_turn ():

    # updates the cur turn text and enable the building buttons
    curTurnText.text = "Turn: " + str(gameManager.curTurn)
    buildingButtons.visible = true

The we have theĀ update_resource_text function which updates the two resource labels to show the player’s current resource values.
# updates the resource text to show the current values
func update_resource_text ():

    # set the food and metal text
    var foodMetal = ""
    
    # sets the text, e.g. "13 (+5)"
    foodMetal += str(gameManager.curFood) + " (" + ("+" if gameManager.foodPerTurn >= 0 else "") + str(gameManager.foodPerTurn) + ")"
    foodMetal += "\n"
    foodMetal += str(gameManager.curMetal) + " (" + ("+" if gameManager.metalPerTurn >= 0 else "") + str(gameManager.metalPerTurn) + ")"	
    
    foodMetalText.text = foodMetal

    # set the oxygen and energy text
    var oxygenEnergy = ""
    
    # set the text, e.g. "13 (+5)"
    oxygenEnergy += str(gameManager.curOxygen) + " (" + ("+" if gameManager.oxygenPerTurn >= 0 else "") + str(gameManager.oxygenPerTurn) + ")"
    oxygenEnergy += "\n"
    oxygenEnergy += str(gameManager.curEnergy) + " (" + ("+" if gameManager.energyPerTurn >= 0 else "") + str(gameManager.energyPerTurn) + ")"
	
    oxygenEnergyText.text = oxygenEnergy

Now we need to connect the buttons. In theĀ UI scene, do the following for the EndTurnButton, MineButton, GreenhouseButton and SolarPanelButton…

  1. Select the button node
  2. Double click theĀ pressed signal (called when we press the button)
  3. Connect that to the UI script

Connecting the buttons to our UI script using signals.

So back in our script, we’ll have 4 new functions. Let’s start with the three building buttons.

# called when the Mine building button is pressed
func _on_MineButton_pressed ():

    buildingButtons.visible = false
    gameManager.on_select_building(1)

# called when the Greenhouse building button is pressed
func _on_GreenhouseButton_pressed ():

    buildingbuttons.visible = false
    gameManager.on_select_building(2)

# called when the Solar Panel building button is pressed
func _on_SolarPanelButton_pressed

    buildingButtons.visible = false
    gameManager.on_select_building(3)

Then we have the end turn button function.
# called when the "End Turn" button is pressed
func _on_EndTurnButton_pressed ():

    gameManager.end_turn()

Connecting Everything Together

Now that we have our UI script, let’s go back to theĀ TileĀ script and fill in theĀ _on_Tile_input_event function.

# called when an input event takes place on the tile
func _on_Tile_input_event (viewport, event, shape_idx):

    # did we click on this tile with our mouse?
    if event is InputEventMouseButton and event.pressed:
        var gameManager = get_node("/root/MainScene")

        # if we can place a building down on this tile, then do so
        if gameManager.currentlyPlacingBuilding and canPlaceBuilding:
            gameManager.place_building(self)

Next, let’s hop into theĀ GameManager script and create theĀ _ready function. Here, we’re going to initialize the UI.
func _ready ():

    # updates the UI when the game starts
    ui.update_resource_text()
    ui.on_end_turn()

At the end of the end_turn function, let’s also update the UI.
# update the UI
ui.update_resource_text()
ui.on_end_turn()

Finally, at the bottom of theĀ place_building function, we can update the resource text UI.
# update the UI to show changes immediately
ui.update_resource_text()

Now we can press play and test out the game!

Conclusion

Congratulations on completing the tutorial!

You just created a 2D, turn-based strategy game in Godot.Ā  Through this journey, we’ve covered a wide array of topics, from setting up objects that give and take resources, to creating a tile-based map that provides visual clues about where buildings can be placed.Ā  Further, with turn-based gameplay mechanics also introduced, we’ve tackled a key component for many other sorts of strategy games as well!

From here, you can expand upon what you’ve learned to add more systems, work on existing ones we touched on here, or even start a new strategy game project with Godot. Regardless, thank you very much for following along with the tutorial, and we wish you the best of luck with your future Godot games.