Explore Free Strategy Game Tutorials – GameDev Academy https://gamedevacademy.org Tutorials on Game Development, Unity, Phaser and HTML5 Fri, 07 Apr 2023 06:05:46 +0000 en-US hourly 1 https://wordpress.org/?v=6.1.1 https://gamedevacademy.org/wp-content/uploads/2015/09/cropped-GDA_logofinal_2015-h70-32x32.png Explore Free Strategy Game Tutorials – GameDev Academy https://gamedevacademy.org 32 32 Create Enemy AI for RTS Games – Unreal Engine Tutorial https://gamedevacademy.org/rts-enemy-ai-unreal-tutorial/ Fri, 07 Apr 2023 06:05:46 +0000 https://gamedevacademy.org/?p=19880 Read more]]> RTS games are a fantastic genre, requiring quick-decision making alongside tense action – gaining players’ attention for hours on end. BUT – it wouldn’t be unreasonable to say that RTS games only work if you have good enemy AI to go along with it.

In this tutorial, we’re specifically focusing on creating basic enemy AI units in Unreal Engine. We’re going to work on the ability of the enemy units to attack the player units in the game. The enemy units will, namely, search for the player units in range to set one of them as the current target and get to attack it until it’s destroyed.  We’ll also cover how to update the remaining player units as they are knocked down over time.

Let’s dig in!

Before You Begin & Project Files

Basic skills in Unreal Engine and its Blueprints Visual Scripting system are needed for this tutorial. Notice that you’ll need to already have a player unit blueprint in your project as this is not covered in the present tutorial. Also, we’re using inheritance to make it easier to implement both player and enemy units, which can then use or overwrite functions and values from their parent class.

You can download a copy of the source code files for the project done in the tutorial here.

Note: This tutorial was made with Unreal Engine version 5.0, so if you have a higher version you might see some elements as deprecated although they still work.

BUILD YOUR OWN GAMES

Get 250+ coding courses for

$1

AVAILABLE FOR A LIMITED TIME ONLY

Creating The Variables For The Enemy Unit

We’re going to start by creating the scripts which will set the Target Actors for the Enemy Units. We will do this in the EnemyUnit blueprint’s Event Graph.

To do it, let’s add new variables to the EnemyUnit’s Event Graph. First, we will add a new Float variable ‘DetectRange‘ with the default value of 500:

Setting up a float variable in Unreal Engine

We will use that variable to set the distance at which an Enemy Unit will notice a Player Unit. Then, we will add a new variable called PlayerUnits of type PlayerUnit. We will store all of the Player Units in that variable, so we can find the one we can reach:

Storing all Player Units in a single variable in Unreal Engine

To store all of the Player Units in that variable, we’ll have to turn that variable into an array first. Arrays allow us to store not one but several elements in one variable. Here’s how we will turn the PlayerUnits variable into an array:

  • With the PlayerUnits variable selected, go to the Details panel
  • To the right of the Variable Type selector, you should see one more selector. It should have a head as an icon
  • Click on that selector and select the Array option from the drop-down menu, to turn the PlayerUnits variable into an array of the Player Units

Turning the PlayerUnits variable into an array in Unreal Engine

Filling Up The PlayerUnits Variable

Next, we want to fill the PlayerUnits variable at the start of the game. But first, let’s take a look at the EnemyUnit’s BeginPlay node. It is connected to the Parent: BeginPlay node. That means, that at the start of the game, the EnemyUnit first runs the script the Unit blueprint has at the BeginPlay node:

EnemyUnit's BeginPlay node in Unreal Engine

Now, let’s make our EnemyUnit fill the PlayerUnit variable after running the parent’s code:

  • Connect the Parent: BeginPlay node to a new Get All Actors Of Class node
  • Set the Actor Class pin of that new node to the PlayerUnit class
  • Connect the output control flow and value pins of the Get All Actors Of Class node to a new Set Player Units node

With that script, at the start of the game, the Enemy Unit searches for all of the Player Units and saves them to the PlayerUnits variable:

Filling up the PlayerUnits variable at the start of the game

If you start the game now, you won’t see anything happen, as we don’t actually do anything with those Player Units as of now.

Creating The Target Finder Function

We’ll use the Player Units we found to select one of them that we can use as a Target. Let’s create a new function called Try Find New Target for that:

Creating the Try Find New Target function in Unreal Engine

As the game goes on, some of the Player Units might get destroyed. Let’s filter them out:

  • Connect the Try Find New Target node to a new For Each Loop node
  • Connect the Array pin of the For Each Loop node to a new Get Player Units node
  • Connect the Loop Body control flow pin of the For Each Loop node to a new Is Valid node
  • Connect the Array Element pin of the For Each Loop node to the Input Object pin of the Is Valid node

This way, we loop through each of the Player Units, check which of them still exists, and fire the Is Valid pin for them:

Updating the PlayerUnits variable in Unreal Engine

Then, we’ll find the Player Unit which is close enough to our Enemy Unit:

  • Connect the Is Valid pin of the Is Valid node to a new Branch node
  • Create a new Get Distance To node
  • Connect the Array Element pin of the For Each Loop node to the Other Actor pin of the Get Distance To node
  • Connect the Return Value pin of the Get Distance To node to a new Less Equal node
  • Connect the second input pin of the Less Equal node to a new Get Detect Range node
  • Connect the output pin of the Less Equal node to the Condition pin of the Branch node

This way, we’re checking the valid Player Units on being closer than the Detect Range to our Enemy Unit. For those close Player Units, the Branch node will fire the True pin:

Detecting the closest Player Unit to a given Enemy Unit in Unreal Engine

Next, we will set that close valid Player Unit as a Target:

  • Connect the True pin of the Branch node to a new Set Target node
  • Connect the Array Element pin of the For Each Loop to the second Target pin of the Set Target node

Setting the valid Player Unit as Target

Finally, we will make the Try Find New Target function stop after finding the Target. Otherwise, we’ll do unnecessary computations on the rest of the PlayerUnits array. To stop this function, connect the output control flow pin of the Set Target node to a new Return Node:

Stopping the Try Find New Target function after the Target gets set

Finishing Up The Enemy Unit Blueprint

So far, we’ve created variables and a function required for the Enemy AI. Let’s hook them up now:

  • Open the EnemyUnit’s Event Graph
  • Connect the Parent: Tick node output control flow pin to a new Is Valid node
  • Connect the Input Object pin of the Is Valid node to a new Get Attack Target node
  • Connect the Is Not Valid pin of the Is Valid node to a new Try Find New Target node

This way, when our Enemy Unit doesn’t have a valid Attack Target, it will try to find a new one:

Enemy Unit finding a new Target in Unreal Engine

As our Enemy Unit is inherited from the base Unit, once it has the Attack Target set, it will use the parent’s functions to move to the Target and attack it.

Testing The Enemy AI

Now, let’s get back to the GameLevel level (which we already have made) and test the changes we’ve made:

  • Start the game
  • Select the Player Unit by clicking on it with the left mouse button
  • Go close to the Enemy Unit by clicking on it with the right mouse button
  • The Enemy Unit should run to the Player Unit and attack it until the Player Unit is destroyed

Testing the enemy AI in Unreal Engine

Let’s then create a few more copies of the Enemy and Player Units, put them in different positions, and test how they work together:

Testing the game with more units in Unreal Engine

We see that the units are behaving as expected, the Enemy Units are chasing after the Player Units within range and attacking them until they are destroyed.

Conclusion

Congratulations on reaching the end of this tutorial!

You now have a basic enemy AI ready to go for your Unreal Engine RTS projects. Of course, there are more ways to expand on this concept. For example, you can add more advanced combat strategies, new types of attacks or different sorts of units, and smoother map navigation. There are a bunch of ways for you to keep improving your game here!

Regardless, though, these skills will form a good foundation you can also apply to other genres as well – only your imagination is stopping you with Unreal!

We wish you the best of luck in your future projects!

Want to learn more about strategy games in Unreal Engine? Try our complete Build an RTS Game with Unreal Engine course.

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

]]>
Intro to Strategy Tile Management Systems for Godot Games https://gamedevacademy.org/godot-tile-management-tutorial/ Thu, 06 Apr 2023 10:33:22 +0000 https://gamedevacademy.org/?p=19823 Read more]]> Strategy games are still one of the most popular genres – testing players’ decision-making abilities to achieve goals with limited resources.

However, they can involve some really taxing mechanics for developers as well to create, let alone balance to make a challenging but fun game. That said, with a smaller map and only a handful of different types of buildings or resources, we can already familiarize ourselves with the process of developing city-builders, which are a great start for any skill level!

In this Godot tutorial, you’ll learn how to map all the tiles of your grid in a way to know which ones have buildings on them and which are available to be selected next. We’ll also show you how to highlight tiles that are ready to receive buildings on them in each turn!

That said, let’s get started!

Project Files

Before you begin, note that some basic Godot experience is required, including knowledge of how to set up your project and create your tile map for the game. Aside from that, you can download a copy of the source code files for the project done in this tutorial here.

BUILD YOUR OWN GAMES

Get 250+ coding courses for

$1

AVAILABLE FOR A LIMITED TIME ONLY

Tile Script

To start, go over to the Tile scene and select the root node:

Selecting the Tile root node in Godot

Create a new script on our tile in the inspector:

Creating a new script for the Tile object in Godot

Let’s save the script as “Tile.gd”.

Creating Variables

In this script, we’ll create a boolean called ‘startTile’ using the keyword export. The export keyword allows us to set the value of the variable in the Inspector:

extends Area2D

export var startTile : bool = false

We will select the tile in the middle and set the ‘startTile‘ to be true (ticked):

Checking the startTile box in the Inspector tab in Godot

We need two more boolean variables to check whether or not this tile has a building on it, and also to check if we can place buildings on the selected tile:

extends Area2D

export var startTile : bool = false

var hasBuilding : bool = false
var canPlaceBuilding : bool = false

Functions Set Up

Now, we need to load two sprite components: one for highlighting the tiles, and one for building icons as follows.

extends Area2D

export var startTile : bool = false

var hasBuilding : bool = false
var canPlaceBuilding : bool = false

# components
onready var highlight : Sprite = get_node("Highlight")
onready var buildingIcon : Sprite = get_node("BuildingIcon")

The function below adds the current node to the “Tiles” group as soon as it appears in the scene tree:

func _ready ():
  
  add_to_group("Tiles")

Next, we’re going to create a toggle function that is going to be called whenever we want to enable/disable the Highlight. This will be used to check whether or not we can build on our tile:

func toggle_highlight (toggle):
  
  highlight.visible = toggle
  canPlaceBuilding = toggle

When we click on the tile, we will send over the Sprite to be displayed in our BuildingIcon:

func place_building (buildingTexture):
  
  hasBuilding = true
  buildingIcon.texture = buildingTexture

Detecting Clicks on the Tiles

We need also to add a signal to detect when we have clicked on the tile. With the “Tile” node selected, go to the Inspector and click on the Node panel:

Adding a signal to our Tile node in Godot

Let’s double-click on Input_event, select the “Tile“, and click on “Connect“:

Connecting the Input_event signal to the Tile node in Godot

With this, a new function has been created inside our Tile script:

extends Area2D

export var startTile : bool = false

var hasBuilding : bool = false
var canPlaceBuilding : bool = false

# components
onready var highlight : Sprite = get_node("Highlight")
onready var buildingIcon : Sprite = get_node("BuildingIcon")

func _ready ():
  add_to_group("Tiles")

func toggle_highlight (toggle):
  highlight.visible = toggle
  canPlaceBuilding = toggle
 
func place_building (buildingTexture):
  hasBuilding = true
  buildingIcon.texture = buildingTexture

func _on_Tile_input_event(viewport, event, shape_idx):
  pass # Replace with function body.

Scripting the Map

Our next step is to do the map script. The map script is going to be managing all of the tiles in our scene. It’s going to be managing tile replacement and tile highlighting.

Let’s create a new script on the “Tiles” node:

Selecting the Tiles in the MainScene in Godot

Creating a new script for the Tiles node in Godot

We’ll save the script as “Map.gd“:

Name the script "Map.gd"

First of all, we’re going to have an array for all the tiles, another for those tiles that have the buildings, and a float for the size of each tile:

extends Node

var allTiles : Array
var tilesWithBuildings : Array
var tileSize : float = 64.0

For information about Arrays, visit the documentation: https://docs.godotengine.org/en/stable/classes/class_array.html

Getting Tile at Given Position

We will now create a function to check whether there is a tile at a certain position on the grid and if so, it also checks if there’s no building on that tile. If both conditions are true, it will return that tile to us. Otherwise, we’ll return nothing (null):

extends Node

var allTiles : Array
var tilesWithBuildings : Array
var tileSize : float = 64.0

func get_tile_at_position (position):
  
  for x in range(allTiles.size()):
    if allTiles[x].position == position and allTiles[x].hasBuilding == false:
      return allTiles[x]  
      
  return null

Our next function will be called to disable every tile highlight, as we don’t want to see the highlights anymore once we’ve placed our buildings:

func disable_tile_highlights ():
  
  for x in range(allTiles.size()):
    allTiles[x].toggle_highlight(false)

Highlighting the Tiles

Following, we need to implement the main function for this script, which will be responsible for highlighting all the tiles we can place our building on:

func highlight_available_tiles ():

The function will loop through each of the tiles in the ‘tilesWithBuildings‘ array:

func highlight_available_tiles ():
  
  for x in range(tilesWithBuildings.size()):

…and check to see if the north, south, west, and east tiles can have a building placed on them. For that, we need to get those tiles relative to our selected tile position:

func highlight_available_tiles ():
  
  for x in range(tilesWithBuildings.size()):
    
    var northTile = get_tile_at_position(tilesWithBuildings[x].position + Vector2(0, tileSize))
    var southTile = get_tile_at_position(tilesWithBuildings[x].position + Vector2(0, -tileSize))
    var eastTile = get_tile_at_position(tilesWithBuildings[x].position + Vector2(tileSize, 0))
    var westTile = get_tile_at_position(tilesWithBuildings[x].position + Vector2(-tileSize, 0))

And then it is going to toggle/highlight the tiles:

func highlight_available_tiles ():
  
  for x in range(tilesWithBuildings.size()):
    
    var northTile = get_tile_at_position(tilesWithBuildings[x].position + Vector2(0, tileSize))
    var southTile = get_tile_at_position(tilesWithBuildings[x].position + Vector2(0, -tileSize))
    var eastTile = get_tile_at_position(tilesWithBuildings[x].position + Vector2(tileSize, 0))
    var westTile = get_tile_at_position(tilesWithBuildings[x].position + Vector2(-tileSize, 0))
    
    if northTile != null:
      northTile.toggle_highlight(true)
    if southTile != null:
      southTile.toggle_highlight(true)
    if eastTile != null:
      eastTile.toggle_highlight(true)
    if westTile != null:
      westTile.toggle_highlight(true)

And that is our map script all set:

extends Node

var allTiles : Array
var tilesWithBuildings : Array
var tileSize : float = 64.0

func get_tile_at_position (position):
  
  for x in range(allTiles.size()):
    if allTiles[x].position == position and allTiles[x].hasBuilding == false:
      return allTiles[x]  
      
  return null

func disable_tile_highlights ():
  
  for x in range(allTiles.size()):
    allTiles[x].toggle_highlight(false)
    
    
func highlight_available_tiles ():
  
  for x in range(tilesWithBuildings.size()):
    
    var northTile = get_tile_at_position(tilesWithBuildings[x].position + Vector2(0, tileSize))
    var southTile = get_tile_at_position(tilesWithBuildings[x].position + Vector2(0, -tileSize))
    var eastTile = get_tile_at_position(tilesWithBuildings[x].position + Vector2(tileSize, 0))
    var westTile = get_tile_at_position(tilesWithBuildings[x].position + Vector2(-tileSize, 0))
    
    if northTile != null:
      northTile.toggle_highlight(true)
    if southTile != null:
      southTile.toggle_highlight(true)
    if eastTile != null:
      eastTile.toggle_highlight(true)
    if westTile != null:
      westTile.toggle_highlight(true)

Now you’re ready to start placing the buildings of your game on top of the available tiles as you like!

Conclusion

Congratulations on finishing up the tutorial!

You’ve learned a lot about using a tile-based strategy system in Godot, including how to know which ones already have buildings, and how to highlight empty neighbor tiles. With the tile management implementation covered in this tutorial, we’ve tackled key components for many other sorts of strategy games as well!

From here, you can continue on developing different types of buildings you want to have for your game and customize each’s impact on resource generation. You can even move to bigger maps or create personalized ones! Make sure to use all your creativity moving forward and best of luck with your future Godot games!

Want to learn more about strategy games? Try our complete Construct a Strategy Game with Godot 3 course.

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

]]>
Best Tower Defense Tutorials – Making Strategy Games https://gamedevacademy.org/best-tower-defense-tutorials/ Mon, 23 Jan 2023 09:45:57 +0000 https://gamedevacademy.org/?p=15574 Read more]]> Tower defense games are one of the most popular subgenres of strategy gaming, tasking players with repelling waves of enemies by placing weapons and defensive units around a maze-like map. They offer a fun challenge with plenty of replayability thanks to the variety of different playstyles and strategies that players can deploy.

As such, we’ve compiled a list of some of the best tower defense tutorials currently available online. By following these tutorials, you’ll be well on your way to crafting imaginative and challenging tower defense games for players to enjoy playing again and again!

Why Learn To Create A Tower Defense Game?

Tower defense games offer a fun challenge for both players and developers. Players have to work out the optimal strategy for holding back enemies, and developers have to design genuinely challenging levels without making the game unfair.

Because of their replayability and their relative simplicity compared to other strategy games like real-time strategy games, tower defense games can be highly appealing as an entry point into strategy game design. However, they still require aspiring game developers to master a range of different mechanics before they can start to build their own tower defense games.

Tower defense games are therefore an excellent genre for testing your level design and game balancing skills as a developer. Make a map too easy, and your players won’t be impressed by the lack of challenge – but make it unreasonably hard and they’ll simply give up instead of trying to find the right strategy. 

Learning to find the ideal middle ground between these extremes is a key test of your skills as a game developer, and tower defense games give you a great opportunity to master this art.

Tower defense character

Tower defense games also give you the chance to practice with various different game mechanics like enemy design, currency systems, technology trees, and more. You can also blend in elements of other genres like RPGs to give your tower defense game a fun twist. As such, tower defense games are an adaptable and rewardable genre for learning new skills and practicing your existing ones.

To help you on your way to creating your first tower defense game, we’ve put together a list of some of the best online tutorials for learning essential skills and mechanics in the tower defense genre. Most of these tutorials are designed to be accessible even for those with limited experience in coding and game development, so if you’re only just getting started making games, don’t worry – you’ll quickly find your feet with these tutorials! 

There’s also plenty to learn here for more experienced game developers, so whatever your skill level, you’re sure to find a tutorial that works for you from the selection below.

Create A Tower Defense Game 

If you’re new to the tower defense genre and need a comprehensive introduction to the essential skills and mechanics you need to make your own tower defense game, this tutorial from Zenva Academy has you covered. The Create A Tower Defense Game tutorial provides a detailed guide to creating your first tower defense game in Unity.

Through this tutorial, you’ll learn various core mechanics of the genre such as tower placement, enemy wave spawning, currency systems, and more. You’ll also master some fundamental programming skills for the Unity engine such as scriptable objects and game managers.

All you’ll need to get started is a basic understanding of Unity and C#, so it’s a perfect place to start even if you’re only just beginning your game development journey. It’s not just for beginners, though – more experienced coders will have the opportunity to practice their existing skills, learn new ones and add an impressive new project to their portfolio.

Key Topics Covered: 

  • Creating paths for enemies to follow
  • Spawning enemies in customizable waves
  • Placing towers with UI indicators
  • Tracking health and money for gameplay control
  • Implementing different towers and attack types
  • Setting up win and defeat/game over conditions

Duration: Just under 3 hours of video tutorials guiding you through the whole process of creating your first tower defense game.

How To Make A Tower Defense Game

Another option for aspiring game developers looking to make their first tower defense game in Unity is the How to make a Tower Defense Game series from Brackeys. This series explores how to use Unity to create a 3D tower defense game.

These tutorials will walk you through the entire process of creating your first 3D tower defense game in Unity, from the initial setup of the project to core tower defense mechanics like tower placement, enemy wave spawns, upgrades, and more. The series is split into 28 separate tutorials, each covering a different gameplay element, so even if you’re just looking to learn specific mechanics then it’s easy to jump in and out wherever you please.

Key Topics Covered:

  • Creating enemies, coding their AI, and setting up wave-based spawns
  • Creating, placing, and upgrading towers
  • Programming tower attacks and behaviors
  • Camera movement and control
  • Creating a currency system and tower/upgrade shop
  • Creating different tower classes
  • Implementing base health/lives and win/lose conditions
  • Adding non-damage effects like slowing and freezing enemies
  • Creating new levels and setting unlock requirements

Duration: A longer series lasting roughly 10 hours, 35 minutes – although you can jump between episodes if you only want to learn specific mechanics.

Develop A Technology Tree For Strategy Games

Tower defense games aren’t just about placing towers and leaving them be – most games in the genre also offer the opportunity to upgrade them with new abilities as you progress through each level. Tower upgrades and other unlockable abilities help to add another layer of depth and complexity to your game, giving players more options in how they’ll approach things.

If you’d like to build an upgrade system for your tower defense game, then one of the best places to start is with the Develop a Technology Tree for Strategy Games tutorial. This series of bite-sized video tutorials provide you with step-by-step instructions to build a technology tree for strategy games, adding deeper gameplay potential to your tower defense game.

Throughout the tutorial, you’ll learn to implement an upgrade system with distinct prerequisites and costs for each new upgrade. You’ll also learn to construct a UI system for your upgrades that can also be applied to other projects. The best part is that you’ll only need a basic familiarity with C# and Unity to get started, making it a rewarding course for beginners as well as more experienced devs.

Key Topics Covered: 

  • Creating hierarchical systems that lock and unlock technologies available for research
  • Deducting resources or currency when technologies are researched
  • Setting up event systems that detect a technology’s state and relay it to other game elements
  • Building a UI with nodes and connectors instantiated through C#
  • Adding UI mechanics such as tooltips and panel toggling
  • Modifying game mechanics based on technologies researched

Duration: Roughly 2 hours, 45 minutes of video tutorials explaining the process of creating a technology tree for your tower defense game.

Tower Defense In Godot

Unity isn’t the only engine you can use to create tower defense games – there are plenty of other options such as Godot, an open-source platform designed with indie developers in mind. If you’re interested in creating a tower defense game with Godot rather than Unity, then the Tower Defense in Godot series from the Game Development Center is a great place to start.

This tutorial series provides detailed instructions for creating a tower defense game using Godot, providing guides for everything from the initial project setup to adding finishing touches like muzzle flashes and impact animations.

By following this tutorial, you’ll learn various essential skills like map creation, tower scripting, enemy spawning, and more. By the end, you’ll have created a fun and challenging tower defense game to add to your portfolio, and you’ll have the necessary skills to create more complex and innovative tower defense games with Godot in the future.

Key Topics Covered:

  • Setting up a tower defense project in Godot
  • Creating maps
  • Setting up towers and script inheritance
  • Creating menus
  • Scene switching
  • Setting up tower attacks 
  • Adding essential UI elements including tower range, health bars, money, and info bars
  • Adding final details like muzzle flashes and impact animations

Duration: Just under 4 hours of video tutorials exploring different stages of setting up a tower defense game in Godot.

1 Hour Programming: A Tower Defense Game In Unity 3D

If you’re looking for a slightly shorter tutorial that still covers everything you need to know to start making tower defense games, then quill18creates has you covered with the 1 Hour Programming: A Tower Defense game in Unity 3D tutorial.

The tutorial is designed to help you quickly build out the shell of a 3D tower defense game which you can then further develop and build out with your own ideas. The complete project’s files are all freely available to download, making it even easier to follow the tutorial at each step and build the project yourself. 

Since it’s a shorter and more fast-paced tutorial, it might be easier for slightly more experienced coders to follow than for absolute beginners. However, it’s definitely worth trying out, as it’s a quick way to learn the basics of the genre and build a basic tower defense game that you can then flesh out and add to your portfolio.

Key Topics Covered:

  • Enemy scripting and pathfinding 
  • Tower scripting, targeting, and attacks
  • Damage and health systems
  • Enemy death behavior
  • Currency and life systems
  • Different tower classes

Duration: Roughly 1 hour, 15 minutes, with the bulk of the tutorial carried out as real-time coding in just one hour.

2D Procedural Maps For Beginners

One way to make your tower defense games stand out from the crowd and add endless replayability is to implement randomized maps that change each time the game is played. If you’d like to add a random map option to your tower defense game, then the 2D Procedural Maps For Beginners tutorial will be perfect for you.

The tutorial provides a series of bite-sized explainer videos that provide step-by-step instructions for creating procedurally generated maps for your games using expandable programming logic. In doing so, you’ll also learn some useful new C# skills and gain valuable practice using Unity.

You’ll need to have some prior experience with C# and Unity to get the most out of this tutorial, but the step-by-step format makes it highly accessible and simple to follow.

Key Topics Covered:

  • Generating noise maps in Unity
  • Understanding noise settings for different effects
  • Calculating biomes based on noise map data
  • Organizing biome data with Scriptable Objects
  • Instantiating 2D tiles based on biome data
  • Implementing a player controller

Duration: 1 hour, 30 minutes of bite-sized video tutorials explaining the process of creating procedurally generated maps in Unity.

Roblox Tower Defense Tutorial

If you’re not familiar with Unity or C#, then an alternative starting point for your first tower defense game is Roblox’s creation engine. Roblox uses the beginner-friendly Lua programming language to power its game creation engine, and GnomeCode provides an excellent guide to using this engine to create your very own tower defense game within Roblox. 

By following the Roblox Tower Defense Tutorial series, you’ll learn various core elements of the tower defense genre, such as path navigation, wave-based enemy spawns, tower placement, and more. If you’ve used Roblox to create games before, then this is an ideal series for learning more about the underlying mechanics that make tower defense games work.

Key Topics Covered:

  • Map creation and path navigation
  • Programming wave-based attacks
  • Creating and animating different enemy types
  • Creating and placing different tower types
  • Tower vs enemy combat 
  • Implementing a base health system and currency system
  • Creating an upgrade system and corresponding graphical UI 
  • Selling/destroying towers 
  • Programming different targeting behaviors for towers

Duration: Roughly 6 hours, 50 minutes of tutorials on different elements of a Roblox tower defense game.

Conclusion

Tower defense games are a staple of the strategy genre, and making your own is a great place to start if you’re looking to master essential strategy mechanics. Their relative simplicity also makes them an ideal project for those just getting started with game design; you’ll quickly learn and master various key skills that will help you tackle a variety of other projects and genres in the future.

Using the tutorials above, you’ll be able to add some simple tower defense games to your portfolio and begin fleshing them out with new features to enhance their gameplay potential. Before long, you’ll be a tower defense master! Of course, there are plenty of tutorials out there, so don’t be afraid to continue exploring this fascinating genre.

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

]]>
Learn Unit Movement for RTS Games with Unreal Engine https://gamedevacademy.org/unreal-rts-movement-tutorial/ Fri, 06 Jan 2023 01:00:38 +0000 https://gamedevacademy.org/?p=19599 Read more]]>

You can access the full course here: BUILD AN RTS GAME WITH UNREAL ENGINE

Unit Movement – Part 1

In this lesson, we will start creating our Units.

Creating The Unit Blueprint

First of all, let’s create the Unit blueprint:

  • Go to the Content folder in the Content Browser
  • Create a new Blueprint Class in the Content folder
  • Select the Character as the Parent Class for that blueprint
  • Name that blueprint Unit

This Unit blueprint will be used as the base for both the Player and Enemy Units.

Player and Enemy Units

Next, let’s add some visuals to our Unit:

  • Open the Unit blueprint by double-clicking on it
  • Drag the Bishop model from the Content > Models folder to the Unit component in the Components panel

Components panel

Now our Unit has the Bishop model.

Bishop model

Then, let’s drag the Bishop model down so it fits nicely into the Capsule Collider our Unit has.

Capsule Collider

Or you can just set the Bishop’s Location in the Details panel to (0, 0, -88).

Location Details panel

Next, we’ll give our bishop the Unit_1 material in the Details > Material dropdown.

Material dropdown

This will make our Bishop blue.

Bishop blue

Setting Up The Unit’s Target Position

Now, let’s go to the Unit’s Event Graph tab. This is where we will create all of the logic for moving, attacking, and taking damage.

Event Graph

First of all, we need to create a variable to store the target movement position:

  • Go to the Variables dropdown in the My Blueprint panel
  • Create a new variable called TargetPosition

variable TargetPosition

Then, let’s change the type of the TargetPosition variable to the Vector:

  • Go to the Details panel
  • Set the Variable Type property to the Vector type
  • Compile the blueprint so those changes would be applied to the blueprint

Vector type

By default, the TargetPosition is (0, 0, 0), which means, our Units will go to the (0, 0, 0) position at the start of the game. As we don’t want this to happen, we will initialize the TargetPosition variable with the Unit’s position instead:

  • In the EventGraph, connect the BeginPlay event node to a new Set Target Position node
  • Connect the Set Target Position node’s Target Position pin to a new Get Nav Agent Location node

This way, we will get the Unit’s start position from the Nav Mesh and set it to the TargetPosition variable.

Unit start position

Moving To The Target Position

Next, we want to move our Unit towards the TargetPosition:

  • Connect the Tick event node control flow pin to a new AI MoveTo node. This node uses the Nav Mesh to move Actors
  • Connect the Pawn pin of the MoveTo node to a new Self node. This way, we’re telling the MoveTo node to move the Actor which calls it
  • Connect the Destination pin of the MoveTo node to a new Get Target Position node, so this node will know where to move our Unit
  • Compile the Unit blueprint so the changes would take place

Compile Unit blueprint

Let’s go back to the GameLevel level, add the Unit to the level, and start the game to see what happens.

GameLevel level

The only thing which should actually happen is the Unit Actor positioning itself to be on the Ground. As we set the TargetPosition to the Unit’s position at the start of the game and haven’t implemented any input, our Unit has no reason to move now.

Actor positioning

Just to test the Nav Mesh, let’s disconnect the BeginPlay node from the Set node in the Unit’s Event Graph. This way, the Target Position would have the default (0, 0, 0) value at the start of the game.

Unit Event Graph

If you start the game now, you should see the Unit go to the (0, 0, 0) location. The Unit will even go around the obstacles we set earlier.

start game

Unit location obstacles

You may think that our Unit moves too fast. Let’s change the Unit’s speed now:

  • Open the Unit blueprint
  • In the Components panel, select the Character Movement component
  • In the Details panel, in the Character Movement: Walking dropdown set the Max Walk Speed property to 300

Max Walk Speed property

If you start the game now, you should notice that our Unit moves slower. You can test out different speeds and pick the one you like.

Don’t forget to reconnect the BeginPlay event node to the Set node before going to the next lesson.

reconnect BeginPlay event node

In this lesson, we created the Unit blueprint and made it go to the Target Position using the Nav Mesh. In the next lesson, we’ll add input handling, so we would be able to actually tell our Unit where to go.

Unit Movement – Part 2

In this lesson, we will make our Units moveable by Player.

Creating The Player Unit

First of all, let’s remove the Unit Actor from the level. Only the Cube obstacles and Nav Mesh should remain.

remove Unit Actor

We’re not actually going to use the Unit blueprint instances in the level. Instead, we will use it as the base for the Player and Enemy Unit blueprints.

Let’s create the PlayerUnit blueprint now:

  • Create a new Blueprint Class in the Content folder
  • In the Pick Parent Class window, go to the All Classes dropdown
  • In that dropdown, find and select the Unit class, to use the Unit as the parent class
  • Click on the Select button to create that blueprint
  • Name that blueprint PlayerUnit

Blueprint Class

blueprint PlayerUnit

If you open PlayerUnit’s Event Graph, you will see that its event nodes are connected to the Parent event nodes. The Parent event nodes are the ones we’ve defined in the Unit’s Event Graph. This means, PlayerUnit’s Event Graph runs the code defined in its parent – the Unit blueprint.

Event Graph

Selecting The Player Unit

Now, let’s implement the Unit selection with our Player Controller:

  • Open the RTSPlayerController blueprint
  • Go to the Event Graph tab
  • In the My Blueprint panel, add a new variable called SelectedUnit.

Blueprint panel

Next, in the Details panel, we’ll set the SelectedUnit’s Variable Type property to the Player Unit.

Details panel Variable Type

As we want to select our Units with our mouse, let’s enable the Mouse Cursor first:

  • Connect the BeginPlay event to a new Set Show Mouse Cursor node
  • Enable the Show Mouse Cursor property in that Set node

Show Mouse Cursor node

Then, we’ll add the Left Mouse Button event node, to get notified on when the left mouse button is pressed.

Left Mouse Button event node

Next, we will send a raycast to check if there is any object under our cursor:

  • Add a new Get Hit Result Under Cursor by Channel node to the Event Graph
  • Connect the Hit Result pin of that node to a new Break Hit Result node

The Get Hit Result Under Cursor node sends the raycast from the cursor position and returns the result of that raycast. A raycast shoots through space like a laser beam and returns the objects which got in its way.

Get Hit Result Under Cursor by Channel

Then, we will check if we hit the Player Unit Actor:

  • Expand the Break Hit Result node to see all of its output pins
  • Connect the Hit Actor pin of the Break Hit Result node to a new Cast To PlayerUnit node
  • You can collapse the Break Hit Result node now, as the used pins will remain visible

Now we have the Cast To PlayerUnit node which can tell us if we hit the PlayerUnit Actor by passing the control flow to its first pin.

Cast To PlayerUnit node

Finally, we can set the Selected Unit variable:

  • Connect the Pressed pin of the Left Mouse Button node to the input control flow pin of the Cast To PlayerUnit node
  • Connect the first output control flow pin of the Cast To PlayerUnit node to a new Set Selected Unit node
  • Connect the As Player Unit pin of the Cast To PlayerUnit node to the Selected Unit pin of that new Set node

Now, once we press the left mouse button, we check the object under our cursor, and if it happens to be the Player Unit, we’re saving it in the Selected Unit variable.

Selected Unit variable

Setting Up The Player Unit Movement

Next, we’ll make the Units move with the right mouse button click. Let’s add the Right Mouse Button event node to the Event Graph first.

Right Mouse Button event node

Then, let’s copy the raycast nodes we created earlier:

  • Select the Get Hit Result Under Cursor by Channel and Break Hit Result nodes we created earlier
  • Press Ctrl+C to copy and Ctrl+V to paste those nodes
  • Move the copy of those nodes to be below the RightMouseButton event node
  • The connection between those nodes must remain

copy raycast nodes

We also need to check if we actually have a Unit selected:

  • Connect the Pressed pin of the Right Mouse Button node to a new Is Valid node
  • Connect the Input Object pin of the Is Valid node to a new Get Selected Unit node

This way, on the right mouse button click, we’ll check if we selected a Unit first.

Is Valid node

Creating The Unit’s MoveTo Function

Then, we need to return back to the Unit blueprint to set up a way to set the Target Position variable from outside. We will make changes to the base Unit blueprint, as both the Player and Enemy Units will need to get their Target Positions from outside.

Let’s do the following now:

  • Open the Unit’s Event Graph
  • In the My Blueprint panel add a new function called MoveTo

MoveTo function

Next, in the MoveTo function Details panel, add a new input of the Vector type called ToPosition.

Vector type ToPosition

Finally, let’s make the Move To function set the TargetPosition variable:

  • In the Move To function graph, connect the control flow pin of the Move To node to a new Set Target Position node
  • Connect the To Position pin of the Move To node to the Target Position pin of the Set node
  • Compile the Unit blueprint to apply those changes

Now we can set the Unit’s Target Position with the Move To function.

Unit Target Position

Back To The Player Controller

Let’s return to the Event Graph of the RTSPlayerController blueprint now. We can finally connect the script we started earlier to the Unit’s MoveTo function:

  • Connect the Get Selected Unit node to a new Move To node. You need to make that connection first, as only the node of the Unit type can be connected to the Unit’s Move To function Target pin
  • Connect the Is Valid pin of the Is Valid node to the input control flow pin of the Move To node
  • Connect the Impact Point pin of the Break Hit Result node to the To Position pin of the Move To node

Now, when we click the right mouse button and we have a PlayerUnit selected, we will call the MoveTo function on it with the click position as the target position.

Player Controller

Testing The Movement

Let’s get back to the GameLevel level and test how our new input works. First, let’s add two PlayerUnits to the level to make sure that our selection works as it should.

Testing Movement

If you start the game now, you should be able to select a PlayerUnit by clicking it with the left mouse button and move it by clicking the right mouse button somewhere on the Ground. Though the selection itself is not displayed at the moment, we will work on it in one of the following lessons.

start game

In this lesson, we implemented the ability to move the PlayerUnits. In the next lesson, we will start working on the Combat system.

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

Transcript – Unit Movement – Part 1

Welcome back everyone in this lesson we are gonna begin creating our units.

So first of all, we want to go down to our content draw and we wanna go to our content folder where we have our level and our other blueprints that have already been created.

And what we want to do is right-click go blueprint class and we want to select the character blueprint. Okay. And I am gonna call this one Unit.

Now this is gonna be the base blueprint for all of our different units, both the player and the enemy. And then from here what we’re gonna do is we are gonna extend from that for the player units and extend for that for the enemy unit.

Okay. So if you do want certain logics such as AI for our enemies cause our enemies are going to be able to attack on their own when a player gets within range but we don’t want our players to do that.

So we are going to basically have a separate player and a separate enemy blueprint. Okay. But this unit blueprint is basically going to be the parent class for both of those.

So all of the similar logics, such as being able to move to a location, move to a target is gonna be shared between them inside of this blueprint here. And we’re getting better understanding of how that works later on.

Once we start setting up the others, but for now let’s just open up this unit blueprint by double-clicking on it and we can then dock it like so. just to make it a bit neater.

Now, the first thing we want to do is give ourselves a 3-D model because right now we have no visual. So what I’m gonna do is I’m gonna open up the content draw.

I’m gonna go to our models folder and I’m just gonna drag in the Bishop 3-D model under the unit here, we can select that model.

And what we want to do is we basically wanna drag it down so that it is sitting at the bottom of this capsule right here. And this capsule is basically defining the bounds of our unit. Now let’s actually disable the grid snapping here so we can move it up a tiny bit, just so it fits correctly. There we go.

And let’s also give it a material now to give it a material we can go over to our details panel, go down to the materials and let’s give this one unit I’ll give it ‘unit_1’, which is just a blue one like so. And then we go, so that is our 3-D model. Pretty much all set up.

Now what we need to do is go over to the event graph where we are going to be spending most of our time, setting up the various different pieces of logic for our unit.

Now inside of this unit blueprint, we are gonna be making a bunch of different things. First of all, we’re gonna have it so that this unit can move to a target. It can also move to a position in the world.

For example, when we right-click on the ground our player’s gonna move to that position. When we right-click on an enemy, we want it to move and attack that enemy.

We’re also gonna have logic that works for attacking a target when we get within range and also for taking damage. So let’s start simple and just get our unit moving.

So first things first, we need to create a variable here which is actually going to determine the position we want to move to. So I’m gonna create a new variable down here.

I’m gonna call this one target position over in the details panel. We can change the variable type from a boolean over to a vector, which has an X, Y and Z coordinate that we are going to move towards.

We can click compile to save all those changes. And then over inside of begin play. What we want to do is initially we want to set our target position to be our current location. And that is because we don’t want our target.

We don’t want our unit I mean to start moving over to 0, 0, 0 at the start of the game, we want them to stand still. So we’re gonna set their target position to basically be their existing one.

So from begin play I’m gonna drag out and go set target position. And the target position is basically just going to be Get Nav Agent Location. Okay. So that’s gonna get the location of our AI agent.

And an agent is basically an entity that utilizes a nav mesh. So it’s basically gonna get our current location on the nav mesh. Now the active begin overlap node which detects collisions. We don’t really need that.

So we can actually go ahead and delete it like so. but the event tick we definitely will need. Now with event tick what we want to do is we basically want to be moving towards our target position at all times for now though. Okay.

So I’m gonna do is I’m gonna drag out from event tick here with the control and I’m gonna drag this into a node called AI move to, okay this one right here, AI move to, and this node right here basically we give it some information and it is gonna automatically calculate a path and move us towards our target location.

So what information do we need to give it give? Well, first of all, we need to give it the pawn or the object that we want to move, which is gonna be ourself.

So we can just right-click and look for the self node right here, get a reference to self and drag that into the pawn. Now we also need a destination and of course that destination is gonna be our target position.

So we can drag in target position, go get target position and connect that up like so. Okay. And pretty much that is all we need to do.

So now if we compile this, if we go back to our game level we can actually go to our content draw, go back to content drag in a unit here, there we go. They’re on the ground.

And if we press play, you’ll see that nothing happens because we initially set their target position to be their existing one. But what happens if we don’t do that? What if we go to unit? What if we right-click on the begin play node and just go over to where it says break node links.

That will disconnect it. If we click compile, if we go back to game level and we move our player over here, for example and we press play.

What you’ll see is our character now moves over or it’s trying to move over to the (0,0) coordinate which is pretty much inside of this cube right here. okay. So we can move it over, down below here.

So there is an obstacle in the way, and as you can see it moves around this obstacle towards the target. Now you may think it is moving a bit fast and it kind of is.

So what we can do is go over to our unit here and select our character movement component. And what we want to do here is just change the move speed. So if we go down to where it says, max walk speed.

We can change that to let’s just say 300. So now if we compile that, go to our game level, press play you’ll see that we move at a much slower speed and we can see the AI navigation a bit easier. But yeah, that is basically how we can navigate around obstacles using the AI move to node.

Now I’m gonna reconnect the begin play to that set target position because we do want to actually have our target position set to wherever we are right now by default.

And in the next lesson we are going to be looking at making it so that we can actually tell our player where to move. Okay.

We’re gonna be able to select our player with left mouse and right-click on the ground to move to a position. okay. So we’re gonna get that RTS movement and interaction set up. So Thank you for watching! and I’ll see all then in the next lesson.

Transcript – Unit Movement – Part 2

Welcome back, everyone. In this lesson, we are gonna get our player controller set up and working so we can actually start selecting our units and moving them around.

And we are first of all going to actually create another unit blueprint. And that is going to be our player unit. Because this unit right here, this unit blueprint, we aren’t going to ever be using it.

So, let’s go ahead and delete our unit that exists in our world right now, because we’re never gonna drag this unit blueprint into our world.

Rather, we are gonna create two other blueprints, a player unit, and an enemy blueprint. And those are both going to inherit, or they’re both gonna be a child class of this unit blueprint.

So it’s basically, we want the enemy and the player to both have the same characteristics and the same logic as each other, but they’re gonna differ in certain ways that we do want to give themselves different behaviors, such as the enemy is gonna have automatic AI, and the player is going to have the ability to be selected.

So, I’m gonna right-click. I’m gonna create a new blueprint class. And we need to pick a parent class. Now, we wanna go All Classes, because we want to search for our unit right here.

And this unit is gonna be our parent class. And I’m gonna call this one PlayerUnit. Now what happens, if I open this up, you’ll see that we have the player bishop right here. We have everything set up just as it is over in Unit.

Yet, if we go to Event Graph, you’ll see that our BeginPlay connects to this thing called Parent BeginPlay. And Parent BeginPlay is basically what this code here, or this logic over in Unit, that we are setting up here.

Because everything inside of PlayerUnit is sort of overriding or inheriting from Unit. That stuff already exists. And any changes we make to the Unit blueprint, those changes get applied to our PlayerUnit as well.

And then what we can do is just attach on extra logic, extra gameplay behaviors, to our player unit here that are more player-centric. And if we create the enemy blueprint, that’s gonna be more enemy-centric with the AI.

And of course we’ll get into this a bit later on on the specifics, but for now just know that PlayerUnit is basically inheriting everything from this unit blueprint right here, with the ability to add on its own extra unique properties.

So, now what we want to do is open up our RTSPlayerController blueprint right here. And this is going to be where we are detecting all of our mouse clicks, and keeping track of which units we have currently selected.

So inside of the player controller, what we want to do is go over to our Event Graph here, and we want to create ourselves a new variable. And this variable is going to be called SelectedUnit.

And the variable type is not gonna be boolean or vector, rather it is gonna be of type player unit. Like so. We can compile that to save those settings.

And now what we need to do is we need a way of basically determining when we click on a player unit. So, first things first, in BeginPlay, we’re going to connect this over into a Show Mouse Cursor node and enable that, because we do want our mouse cursor enabled by default.

We then want to delete Event Tick, since we won’t be needing that. And instead we want to create a Left Mouse Button node. And this Left Mouse Button node is gonna basically execute once the left mouse button is pressed or released.

Now, what we want to do is we want to basically determine if we are clicking on a player unit when we select it with the left mouse buttons. How do we do that? Well, we need to use a raycast, or a hit result.

So, for this what I’m gonna do is I’m gonna create a node called Get Hit Results Under Cursor by Channel. And this node right here, basically, it is going to shoot a laser beam from my mouse cursor to whatever we are pointing.

And it is then gonna return to us that information whenever it hits something. Now from Hit Result, we wanna bring this over into a Break Hit Result node right here.

You can then pop that open to see all of the different outputs we can choose from. Now, the thing we ought to check to see is the Hit Actor. And we to know if whatever actor we hit with our mouse cursor is a player unit.

So, we can drag that out like so. And we are going to put this into a Cast to Player Unit node. Now, a Cast To node, it basically takes in an object as an input, and it basically determines if this object is of type player unit.

If it is, this Control Flow executes. Otherwise, Cast Failed executes. So, basically this is only going to be true if the object we are clicking on is a player unit. So, let’s connect this up with the pressed input like so.

And then from Cast, if it is indeed a player unit, then what we want to do is we want to basically go Set Selected Unit, and go As Player Unit. And like so. So, now when we left-click on a player unit, it is going to set it as our selected unit.

Now, how do we get that unit to actually begin moving around once we have it selected? Well, for that, we are gonna create another event node called Right Mouse Button.

And Right Mouse Button, this gets executed when, of course, we click on our right mouse button. And what we want to do with this is we basically to start off with, want to see, first of all, do we have a selected unit?

And if we do have a selected unit, then we want to move it to whatever location we have hit. So, what we can do here is actually just to save some typing,

I’m gonna select our Get Hit Result under cursor, hold down Control, and select the other node here. I’m gonna copy that and paste it down here, just ’cause we don’t have to worry about creating those nodes again.

And instead of the Hit Actor, we want to get the Location. But we don’t wanna get that just yet. Instead, what we want to do is we want to go out from Pressed, and we want to check to see if we have a selected unit.

Because we don’t wanna try and move somewhere if we don’t have a selected unit. So out from Pressed, what we want to do is we want to check to see the Is Valid. Is Valid right here, a little question mark icon.

Basically, we give it a object and it determines if it exists or not. So, right now our selected unit if we get it like so, plug it in. If it has not been set, it is equal to what’s known as null.

Null basically means empty. And if it’s empty, that means it is not valid. Otherwise, if we have set the selected unit, it will be valid. Now, if it is valid, then we want to basically set its target position.

And to do that, we are gonna go over to our PlayerUnit right here. And actually not our PlayerUnit. We’re gonna go over to our Unit, so our base unit, because this could also be given to an enemy.

And we are going to create a new function down here called MoveTo. And the MoveTo function is going to contain a input. So, we can add an input right here. And it is gonna be called ToPosition. We wanna make that of type vector.

And basically what we want to do is set our target position to be this ToPosition. So, we just wanna plug it in like so and there we go. So, basically when this Move To function is called, we send over a position and it is gonna set our unit’s target position.

Now we wanna click Compile, go back to our RTSPlayerController. And then what we want to do is we want to drag in our selected unit here, go Get Selected Unit, drag that out, and we want to call the Move To function like so.

And we wanna connect that to the Is Valid of the Is Valid node. And the ToPosition is going to be the Impact Point, the point at which our mouse cursor has impacted, probably the ground that we wanna move to.

So, that is what we need to do in order to basically set it up for our unit to be selected initially. And then when we right-click, we want to check to see if we have a unit selected.

And if we do, we want to move it to wherever our mouse cursor has clicked on the ground. So, now we can click Compile. We can go back to our game level. We can then drag in a player unit here.

Let’s actually drag in another one as well just to basically see if the selecting works. Click Play. Okay, and now what we can do is we can click on our unit.

So, if I click on the left one right here, nothing really happens so far, but we will have a selection visual appear. And if I right-click, you’ll see that our unit is now moving to whatever position I am giving it, which is pretty cool.

Now, if I select this other unit with left mouse, as you can see, I am now controlling it, and the other one is staying still.

So, we can switch between our units here and move them around wherever we wish by clicking on them and then right-clicking on the ground to basically navigate over to that location.

So, that’s all working nicely right there. All right, so we got that all set up and ready to go. Now in the next lesson, I reckon we look at setting up some sort of enemy.

Because we need a way to actually begin attacking other units, and then later on, them having the ability to attack us. So, thanks for watching. And I’ll see you all then in the next lesson.

Interested in continuing?  Check out our all-access plan which includes 250+ courses, guided curriculums, new courses monthly, access to expert course mentors, and more!

]]>
Create a City Building Game in Unity – Strategy Tutorial https://gamedevacademy.org/unity-city-building-game-tutorial/ Mon, 19 Dec 2022 01:00:17 +0000 https://coding.degree/?p=670 Read more]]> Do your players long for the exhilarating sensation of controlling a whole city?

From popular games like Sim City to lesser-known indie games like Banished, city-building games are an immensely popular sub-genre of strategy. Not only are they beloved by players, but they also present developers with a special challenge in terms of game design. Despite all the under-the-hood math involved, though, they can also be a great first choice of game for a beginner to create on their own!

In this tutorial, we’ll be creating the foundations of a city-building game in Unity. This project will feature a versatile camera controller, different buildings that can be placed, population/job/food simulations, and even a UI to tie it all together. By the end, you’ll be able to easily add in new buildings since we’re going to be using scriptable objects. So if you’re ready to develop your own city-building game from scratch, let’s get started.

the complete city builder game

Project Files & Prerequisites

In this tutorial, we’ll be needing some assets such as 3D models and textures.

  • Download the required assets here.
  • Download the complete project here.

Before jumping in, do note that this tutorial does assume you know the basics of Unity. Just starting out? Try out some of our other Unity tutorials first. You can also find online courses on the topic as well – with expansive content on many different genres.

Additionally, if you’re a teacher looking to bring Unity to the classroom, you can try out the Zenva Schools classroom for K12-appropriate teaching material.

BUILD YOUR OWN GAMES

Get 250+ coding courses for

$1

AVAILABLE FOR A LIMITED TIME ONLY

Creating the Project

First, let’s begin by creating a new Unity project with the 3D template. In our new project, let’s start by creating some folders.

  • Building Presets
  • Icons
  • Materials
  • Models
  • Prefabs
  • Scripts
  • Textures

unity project browser

Now let’s start importing the required assets such as 3D models and textures. Download the ZIP file from the start of the tutorial and extract the contents to somewhere on your computer. You’ll see three folders with assets. Let’s start with the icons. Inside of the Icons Folder Contents drag the 4 icons into the Unity project’s Icons folder.

  1. Select all the icons
  2. In the Inspector, set the Texture Type to Sprite (2D and UI)
  3. Click Apply

importing the icon sprites

Then inside of our Models folder, drag in the assets from the Models Folder Contents.

Models folder contents

For each of the materials in this folder:

  1. Select it
  2. In the Inspector, set the Albedo Texture to the relative texture PNG in the folder

3D model material texture setting

Finally, inside of the Textures folder, drag in the single image from the Textures Folder Contents folder.

Textures folder contents

Creating the Environment

To begin, let’s create our base from where we’ll be placing buildings. First, create a new 3D plane object and rename it to Ground. Then set the Scale to 5, 5, 5.

creating the ground plane

In the Materials folder, create a new material called Ground and apply it to the ground plane.

  • Set the Albedo Texture to be the ground texture
  • Set the Albedo Color to be a light green
  • Set the Tiling to 50, 50
  • Set the Offset to 0.5, 0.5

Ground material texture

You may notice that the lighting is a bit off. To fix this, go to the bottom right corner of the screen and click on the Auto Generate Lighting button. This will open up the Lighting window where at the bottom, you can enable Auto Generate.

Auto generate lighting

final result of the ground plane with material and texture

Camera Controller

In this game, we’re going to have a camera which can move around, look and zoom in and out. To begin, let’s create a new empty object called CameraAnchor.

  • Set the Position to 0, 0, 0
  • Set the Rotation to -50, 45, 0

Then we can drag the Main Camera in as a child.

  • Set the Position to 0, 20, 0
  • Set the Rotation to 90, 0, 0

Camera anchor and main camera setup

Also on the Main Camera, let’s change our Field of View to 20.

changing the field of view

Here’s what it should look like in the Game view:

what the game view should look like

Scripting the Camera Controller

Create a new C# script called CameraController and attach it to the CameraAnchor object. Open the script up in Visual Studio so we can begin to create it.

Let’s start with our variables.

public float moveSpeed;

public float minXRot;
public float maxXRot;

private float curXRot;

public float minZoom;
public float maxZoom;

public float zoomSpeed;
public float rotateSpeed;

private float curZoom;
private Camera cam;

In the Start function, we can setup some initial values and get the camera.

void Start ()
{
    cam = Camera.main;
    curZoom = cam.transform.localPosition.y;
    curXRot = -50;
}

From here on, we’ll be working inside of the Update function. First, we have the code for zooming in and out with the scroll wheel.

curZoom += Input.GetAxis("Mouse ScrollWheel") * -zoomSpeed;
curZoom = Mathf.Clamp(curZoom, minZoom, maxZoom);

cam.transform.localPosition = Vector3.up * curZoom;

Then if we’re holding down the right mouse button, we want to rotate the camera around.

if(Input.GetMouseButton(1))
{
    float x = Input.GetAxis("Mouse X");
    float y = Input.GetAxis("Mouse Y");

    curXRot += -y * rotateSpeed;
    curXRot = Mathf.Clamp(curXRot, minXRot, maxXRot);

    transform.eulerAngles = new Vector3(curXRot, transform.eulerAngles.y + (x * rotateSpeed), 0.0f);
}

Finally, we want to implement the movement. We can move forwards, back, left and right relative to where we’re facing.

Vector3 forward = cam.transform.forward;
forward.y = 0.0f;
forward.Normalize();
Vector3 right = cam.transform.right.normalized;

float moveX = Input.GetAxisRaw("Horizontal");
float moveZ = Input.GetAxisRaw("Vertical");

Vector3 dir = forward * moveZ + right * moveX;
dir.Normalize();

dir *= moveSpeed * Time.deltaTime;

transform.position += dir;

Save that and return to the editor. We can select the camera anchor and fill in the properties:

Camera controller script in the Unity Inspector

Press play and test it out!

Creating the UI

Although we don’t have the game’s systems running yet, let’s begin by creating the UI. First, create a new canvas object which is the container for our UI. As a child of the canvas, create a new UI image and call it Toolbar.

  • Set the Anchoring to be bottom-stretch
  • Set the Left and Right to 0
  • *Set the Pos Y to 50
  • Set the Height to 100
  • Set the Color to be dark grey

ui toolbar canvas

Then as a child of the toolbar, create a new UI image and call it HouseButton.

  • Set the Anchoring to middle-left
  • Set the Position to 50, 0, 0
  • Set the Width and Height to 80
  • Set the Source Image to Building_House.png
  • Add a Button component

house button ui

Next to this button, create three more for the Factory, Farm and Road buildings.

all the building buttons created

After this, as a child of the toolbar, create a new UI > Button – TextMeshPro. Import the TMP essentials when it asks.

  • Set the Anchoring to middle-right
  • Set the Position to -135, 0, 0
  • Set the Width to 250
  • Set the Height to 80
  • Set the Source Image to none
  • Set the child text to display: End Turn

end turn button

Finally, we want to create a new Text Mesh Pro text object and call it StatsText.

  • Set the Position to 50, 0, 0
  • Set the Width to 1120
  • Set the Height to 100
  • Set the text to display what’s in the image below as a template:

stats text

Building Presets

In this game, we’ll be using scriptable objects to create our buildings. This will allow us to easily add new ones with a pre-existing system that’s already in place whenever we want. To begin, let’s create a new script called BuildingPreset and open it up.

At the top of the class, we need to first add in the UnityEditor namespace, the CreateAssetMenu attribute and make the class extend from ScriptableObject.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CreateAssetMenu(fileName = "Building Preset", menuName = "New Building Preset")]
public class BuildingPreset : ScriptableObject
{
...

Then inside of the class, we can create our variables.

public string displayName;
public int cost;
public int costPerTurn;
public GameObject prefab;

public int population;
public int jobs;
public int food;

Scriptable objects allow us to create an instance of an asset with custom properties and functions. We’ll be creating one for each of our buildings. In the Building Presets folder, create 4 new building presets (right click and select Create > New Building Preset).

  • House
  • Farm
  • Factory
  • Road

Building Presets as Scriptable Objects in Unity

Next, we need to create the building objects. For each building, do the following:

  • Create an empty GameObject called Building_[building type]
  • Drag in the 3D model as a child
  • Set the Scale to 0.045, 0.045, 0.045
  • Set the Rotation to 0, 180, 0
  • Apply the respective material
  • Save it to the Prefabs folder

When it came to the road, I just used a 3D plane with a new material.

creating the building prefabs

From here, we can go back to our 4 building presets and fill in their information. This part is really up to you in order to test out which values are best, but here are mine:

factory preset

farm preset

house preset

road preset

City Management Script

Now we can create the C# City script and attach it to an empty GameObject called _GameManager. This script is going to manage our population, money, jobs, food and overall processes.

First, let’s add the text mesh pro namespace to our script.

using TMPro;

Then we can create our variables as well as a singleton so we can access this script from anywhere in the project.

public int money;
public int day;
public int curPopulation;
public int curJobs;
public int curFood;
public int maxPopulation;
public int maxJobs;
public int incomePerJob;

public TextMeshProUGUI statsText;

private List<BuildingPreset> buildings = new List<BuildingPreset>();

public static City inst;

void Awake()
{
    inst = this;
}

When we place down a building, the OnPlaceBuilding function will be called.

public void OnPlaceBuilding (BuildingPreset building)
{
    maxPopulation += building.population;
    maxJobs += building.jobs;
    buildings.Add(building);
}

At the end of every turn, we’ll need to calculate our population, money, jobs, food, etc. Let’s start with the CalculateMoney function.

void CalculateMoney ()
{
    money += curJobs * incomePerJob;

    foreach(BuildingPreset building in buildings)
        money -= building.costPerTurn;
}

Then the CalculatePopulation function which will figure out how many people are in the city.

void CalculatePopulation ()
{
    maxPopulation = 0;

    foreach(BuildingPreset building in buildings)
        maxPopulation += building.population;

    if(curFood >= curPopulation && curPopulation < maxPopulation)
    {
        curFood -= curPopulation / 4;
        curPopulation = Mathf.Min(curPopulation + (curFood / 4), maxPopulation);
    }
    else if(curFood < curPopulation)
    {
        curPopulation = curFood;
    }
}

The CalculateJobs function figures out how many jobs are being worked.

void CalculateJobs ()
{
    curJobs = 0;
    maxJobs = 0;

    foreach(BuildingPreset building in buildings)
        maxJobs += building.jobs;

    curJobs = Mathf.Min(curPopulation, maxJobs);
}

And finally, the CalculateFood function.

void CalculateFood ()
{
    curFood = 0;

    foreach(BuildingPreset building in buildings)
        curFood += building.food;
}

Now what’s going to call of this? The EndTurn function which gets called when we click on the End Turn button. The long line is where we’re setting the stats text to display all of our new information. You can of course change this to how you like (if you prefer separate text elements).

public void EndTurn ()
{
    day++;
    CalculateMoney();
    CalculatePopulation();
    CalculateJobs();
    CalculateFood();

    statsText.text = string.Format("Day: {0}   Money: ${1}   Pop: {2} / {3}   Jobs: {4} / {5}   Food: {6}", new object[7] { day, money, curPopulation, maxPopulation, curJobs, maxJobs, curFood });
}

Back in the editor, here’s what my _GameManager object looks like:

game manager script object

Also, select the EndTurnButton and add a new listener to the OnClick event which links to the EndTurn function.

button onclick event listener city end turn

So now if you press play, you should be able to click on the end turn button and see the stat text update.

Placing Buildings

Create a new C# script called Selector and attach it to the _GameManager object. This script will manage detecting our mouse in world coordinates.

First, we want to add this namespace so we can see if we’re clicking on UI.

using UnityEngine.EventSystems;

Then we can create our variables as well as singleton .

private Camera cam;
public static Selector inst;

void Awake ()
{
    inst = this;
}

In the Start function, we’ll get the camera.

void Start ()
{
    cam = Camera.main;
}

Then the main function, GetCurTilePosition. This will return the position of the tile we’re currently hovering over.

public Vector3 GetCurTilePosition ()
{
    if(EventSystem.current.IsPointerOverGameObject())
        return new Vector3(0, -99, 0);

    Plane plane = new Plane(Vector3.up, Vector3.zero);
    Ray ray = cam.ScreenPointToRay(Input.mousePosition);
    float rayOut = 0.0f;

    if(plane.Raycast(cam.ScreenPointToRay(Input.mousePosition), out rayOut))
    {
        Vector3 newPos = ray.GetPoint(rayOut) - new Vector3(0.5f, 0.0f, 0.5f);
        return new Vector3(Mathf.CeilToInt(newPos.x), 0, Mathf.CeilToInt(newPos.z));
    }

    return new Vector3(0, -99, 0);
}

Next, let’s return to the editor and create a new empty GameObject called PlacementIndicator. This object will appear when we click on a building to place and will show where we’re going to be placing it. As a child of this object, create a new cube and move it up so it’s sitting on the surface. Create a new material and assign it to the cube.

  • Set the Rendering Mode to Fade
  • Set the Albedo Color to blue

placement indicator

Then we can go ahead and disable the object so it’s not visible. Next, create a new C# script called BuildingPlacer. We’ll start with varaibles and singleton.

private bool currentlyPlacing;
private BuildingPreset curBuildingPreset;

private float placementIndicatorUpdateRate = 0.05f;
private float lastUpdateTime;
private Vector3 curPlacementPos;

public GameObject placementIndicator;
public static BuildingPlacer inst;

void Awake ()
{
    inst = this;
}

The way the placement indicator will work, is that if currentlyPlacing is true – the placement indicator object will snap to the current grid position that the mouse is over every 0.05 seconds. 0.05 seconds because doing it every frame may cause performance issues.

The BeginNewBuildingPlacement function will be called once we click on a building in the UI toolbar.

public void BeginNewBuildingPlacement (BuildingPreset buildingPreset)
{
    if(City.inst.money < buildingPreset.cost)
        return;

    currentlyPlacing = true;
    curBuildingPreset = buildingPreset;
    placementIndicator.SetActive(true);
}

The CancelBuildingPlacement function gets called if we press the escape key when placing and once we place down a building.

public void CancelBuildingPlacement ()
{
    currentlyPlacing = false;
    placementIndicator.SetActive(false);
}

PlaceBuilding gets called when we click on the grid to place the building down.

void PlaceBuilding ()
{
    GameObject buildingObj = Instantiate(curBuildingPreset.prefab, curPlacementPos, Quaternion.identity);
    City.inst.OnPlaceBuilding(curBuildingPreset);

    CancelBuildingPlacement();
}

Finally, in the Update function we’ll do a few things. First, if we press escape – cancel the building placement. If we are placing a building down, make it follow the cursor and when we press left mouse button – place it down.

void Update ()
{
    if(Input.GetKeyDown(KeyCode.Escape))
        CancelBuildingPlacement();

    if(Time.time - lastUpdateTime > placementIndicatorUpdateRate && currentlyPlacing)
    {
        lastUpdateTime = Time.time;

        curPlacementPos = Selector.inst.GetCurTilePosition();
        placementIndicator.transform.position = curPlacementPos;
    }

    if(currentlyPlacing && Input.GetMouseButtonDown(0))
    {
        PlaceBuilding();
    }
}

Back in the editor, select the _GameManager object and drag in the placement indicator object.

placement indicator property

Now we need to do the following for each of the 4 building buttons:

  1. Add a new listener to the button’s OnClick event.
  2. Set that to be the building placer’s BeginNewBuildingPlacement function
  3. Set the parameter to be the respective Building Preset asset

building placement button

Once all the buttons are linked up you can press play and test it out!

The various different building stats will need to be tweaked in order to get the gameplay you desire.

Conclusion

Congrats on finishing the tutorial! As promised, we just created the foundations for a city building game in Unity.

With this project, we’ve explored a lot of fundamental mechanics you’ll find in most city-building games, such as moving and rotating the camera, using buildings to calculate resources, and more. From here, you can expand upon the game in a ton of different ways, such as: adding in more buildings, implementing new resources or calculation mechanics, and even updating the visuals. Tools like the selector can be used for other things too, like selecting buildings and even upgrading them once placed down.

Don’t forget to also explore other genres as well – as they can be a great boost to your Unity skills. Online courses for individuals and platforms like Zenva Schools for teachers are perfect solutions for diving into additional Unity topics.

Whatever you decide, I hope these foundations help inspire your next game project! Thanks for following along, and I wish you the best of luck with your future games.

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

]]>
A Guide to Adding Towers for Tower Defense Games in Unity https://gamedevacademy.org/tower-defense-tower-unity-tutorial/ Tue, 09 Aug 2022 10:59:55 +0000 https://gamedevacademy.org/?p=18514 Read more]]> There’s no question tower defense games are insanely popular – whether we’re talking about the PC market, console market, or mobile game market. Defending a territory and stopping enemies is a true classic for games, as it involves tense action and strategy at the same time. But, how do the towers of tower defense games function?

In this Unity tutorial, we’ll go through the specifics of the tower creation process and how to have them shoot projectiles at the enemies in your game. No matter what kind of tower defense game you’re building, these basics will ensure you’re up and running with the most fundamental aspect of them.

Let’s get started!

Before You Begin & Project Files

Before you begin, note that some basic Unity experience is required, including knowledge of how to set up your project and create enemies for the game.

Regardless of experience level, though, you can download a copy of the assets (and scripts) used in this tutorial here

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

Creating the Tower GameObject

Let’s create a new empty object called “CastleTower“. The tower is going to be shooting projectiles at the first enemy that it sees.

The 3D model for the tower should be added to the Assets > Models > Towers folder. You can use any model you want, or use the one we provided with the project files.

Tower 3D model

Make sure that the model sits under the parent “CastleTower” object, and add the following components:

  • Sphere Collider (Trigger) for the tower’s attack range
  • “Tower” C# script 

The model should be under the "CastleTower" object parent

Adding a Sphere Collider and a Script to the model

We also need to create an empty child object to set the Transform at which we are spawning the projectiles. (e.g. at the top of the tower)

Creating a child object for the spawning of the projectiles

Scripting the Tower

Inside the script we created a moment ago, we’re going to define an enum for the tower’s target priority as such:

  • First: The tower is going to target the first enemy that enters its range
  • Close: The tower is going to target the closest enemy within the range
  • Strong: The tower is going to target the enemy with the most health
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Tower : MonoBehaviour
{
    public enum TowerTargetPriority
    {
        First,
        Close,
        Strong
    }
}

We also need to declare the following variables for the target information and the tower’s attack settings:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Tower : MonoBehaviour
{
    public enum TowerTargetPriority
    {
        First,
        Close,
        Strong
    }

    [Header("Info")]
    public float range;
    private List<Enemy> curEnemiesInRange = new List<Enemy>();
    private Enemy curEnemy;

    public TowerTargetPriority targetPriority;
    public bool rotateTowardsTarget;

    [Header("Attacking")]
    public float attackRate;
    private float lastAttackTime;
    public GameObject projectilePrefab;
    public Transform projectileSpawnPos;

    public int projectileDamage;
    public float projectileSpeed;
}

When an enemy enters the trigger (OnTriggerEnter), we’re going to add it to our curEnemiesInRange list. And when it leaves (OnTriggerExit), if it’s in the list, we’re going to remove it:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Tower : MonoBehaviour
{
    public enum TowerTargetPriority
    {
        First,
        Close,
        Strong
    }

    [Header("Info")]
    public float range;
    private List<Enemy> curEnemiesInRange = new List<Enemy>();
    private Enemy curEnemy;

    public TowerTargetPriority targetPriority;
    public bool rotateTowardsTarget;

    [Header("Attacking")]
    public float attackRate;
    private float lastAttackTime;
    public GameObject projectilePrefab;
    public Transform projectileSpawnPos;

    public int projectileDamage;
    public float projectileSpeed;

    private void OnTriggerEnter (Collider other)
    {
        if(other.CompareTag("Enemy"))
        {
            curEnemiesInRange.Add(other.GetComponent<Enemy>());
        }
    }

    private void OnTriggerExit (Collider other)
    {
        if(other.CompareTag("Enemy"))
        {
            curEnemiesInRange.Remove(other.GetComponent<Enemy>());
        }
    }
}

Inside the Update function, we want to make sure that the tower is attacking at a set attackRate. To do this, we need to check how much time has elapsed from the last attack (Time.time – lastAttackTime).

If it is bigger than attackRate, the tower is ready to attack again. This is where we should reset the lastAttackTime and attack our current target (enemy) if it is not null.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Tower : MonoBehaviour
{
    public enum TowerTargetPriority
    {
        First,
        Close,
        Strong
    }

    [Header("Info")]
    public float range;
    private List<Enemy> curEnemiesInRange = new List<Enemy>();
    private Enemy curEnemy;

    public TowerTargetPriority targetPriority;
    public bool rotateTowardsTarget;

    [Header("Attacking")]
    public float attackRate;
    private float lastAttackTime;
    public GameObject projectilePrefab;
    public Transform projectileSpawnPos;

    public int projectileDamage;
    public float projectileSpeed;

    void Update ()
    {
        // attack every "attackRate" seconds
        if(Time.time - lastAttackTime > attackRate)
        {
            lastAttackTime = Time.time;
            curEnemy = GetEnemy();

            if(curEnemy != null)
                Attack();
        }
    }

    private void OnTriggerEnter (Collider other)
    {
        if(other.CompareTag("Enemy"))
        {
            curEnemiesInRange.Add(other.GetComponent<Enemy>());
        }
    }

    private void OnTriggerExit (Collider other)
    {
        if(other.CompareTag("Enemy"))
        {
            curEnemiesInRange.Remove(other.GetComponent<Enemy>());
        }
    }
}

Let’s now define the GetEnemy function and the Attack function:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Tower : MonoBehaviour
{
    public enum TowerTargetPriority
    {
        First,
        Close,
        Strong
    }

    [Header("Info")]
    public float range;
    private List<Enemy> curEnemiesInRange = new List<Enemy>();
    private Enemy curEnemy;

    public TowerTargetPriority targetPriority;
    public bool rotateTowardsTarget;

    [Header("Attacking")]
    public float attackRate;
    private float lastAttackTime;
    public GameObject projectilePrefab;
    public Transform projectileSpawnPos;

    public int projectileDamage;
    public float projectileSpeed;

    void Update ()
    {
        // attack every "attackRate" seconds
        if(Time.time - lastAttackTime > attackRate)
        {
            lastAttackTime = Time.time;
            curEnemy = GetEnemy();

            if(curEnemy != null)
                Attack();
        }
    }

    // returns the current enemy for the tower to attack
    Enemy GetEnemy ()
    {
       
    }

    // attacks the curEnemy
    void Attack ()
    {
    }

    private void OnTriggerEnter (Collider other)
    {
        if(other.CompareTag("Enemy"))
        {
            curEnemiesInRange.Add(other.GetComponent<Enemy>());
        }
    }

    private void OnTriggerExit (Collider other)
    {
        if(other.CompareTag("Enemy"))
        {
            curEnemiesInRange.Remove(other.GetComponent<Enemy>());
        }
    }
}

The GetEnemy function should return the current enemy for the tower to attack. But first, we need to check if the current enemy exists.

Chances are that the enemy is within the tower’s attack range (= exists in the curEnemiesInRange list) but has been already destroyed by another tower. In that case, the list will contain a null element, which we need to avoid as this is going to cause a null reference exception error.

Let’s remove any null element inside the curEnemiesInRange list by using the RemoveAll method:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Tower : MonoBehaviour
{
    public enum TowerTargetPriority
    {
        First,
        Close,
        Strong
    }

    [Header("Info")]
    public float range;
    private List<Enemy> curEnemiesInRange = new List<Enemy>();
    private Enemy curEnemy;

    public TowerTargetPriority targetPriority;
    public bool rotateTowardsTarget;

    [Header("Attacking")]
    public float attackRate;
    private float lastAttackTime;
    public GameObject projectilePrefab;
    public Transform projectileSpawnPos;

    public int projectileDamage;
    public float projectileSpeed;

    void Update ()
    {
        // attack every "attackRate" seconds
        if(Time.time - lastAttackTime > attackRate)
        {
            lastAttackTime = Time.time;
            curEnemy = GetEnemy();

            if(curEnemy != null)
                Attack();
        }
    }

    // returns the current enemy for the tower to attack
    Enemy GetEnemy ()
    {
        curEnemiesInRange.RemoveAll(x => x == null);
    }

    // attacks the curEnemy
    void Attack ()
    {

        GameObject proj = Instantiate(projectilePrefab, projectileSpawnPos.position, Quaternion.identity);
        proj.GetComponent<Projectile>().Initialize(curEnemy, projectileDamage, projectileSpeed);
    }

    private void OnTriggerEnter (Collider other)
    {
        if(other.CompareTag("Enemy"))
        {
            curEnemiesInRange.Add(other.GetComponent<Enemy>());
        }
    }

    private void OnTriggerExit (Collider other)
    {
        if(other.CompareTag("Enemy"))
        {
            curEnemiesInRange.Remove(other.GetComponent<Enemy>());
        }
    }
}

Note the use of a lambda expression (x => x == null) to create a Predicate, which defines the condition to remove. The List<T>.RemoveAll(Predicate<T>) method can traverse the list from the beginning, and remove any element ‘x‘ which meets the criteria (in this case, the criteria is that x is null).

Check out the C# List.RemoveAll method for more information: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.removeall?view=net-6.0

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Tower : MonoBehaviour
{
    public enum TowerTargetPriority
    {
        First,
        Close,
        Strong
    }

    [Header("Info")]
    public float range;
    private List<Enemy> curEnemiesInRange = new List<Enemy>();
    private Enemy curEnemy;

    public TowerTargetPriority targetPriority;
    public bool rotateTowardsTarget;

    [Header("Attacking")]
    public float attackRate;
    private float lastAttackTime;
    public GameObject projectilePrefab;
    public Transform projectileSpawnPos;

    public int projectileDamage;
    public float projectileSpeed;

    void Update ()
    {
        // attack every "attackRate" seconds
        if(Time.time - lastAttackTime > attackRate)
        {
            lastAttackTime = Time.time;
            curEnemy = GetEnemy();

            if(curEnemy != null)
                Attack();
        }
    }

    // returns the current enemy for the tower to attack
    Enemy GetEnemy ()
    {
        curEnemiesInRange.RemoveAll(x => x == null);

        if(curEnemiesInRange.Count == 0)
            return null;

        if(curEnemiesInRange.Count == 1)
            return curEnemiesInRange[0];       
    }

    // attacks the curEnemy
    void Attack ()
    {
       
    }

    private void OnTriggerEnter (Collider other)
    {
        if(other.CompareTag("Enemy"))
        {
            curEnemiesInRange.Add(other.GetComponent<Enemy>());
        }
    }

    private void OnTriggerExit (Collider other)
    {
        if(other.CompareTag("Enemy"))
        {
            curEnemiesInRange.Remove(other.GetComponent<Enemy>());
        }
    }
}

Then we can return any remaining enemy in the list, or null if there is none. If we’re returning an enemy, remember to return the right enemy based on the TowerTargetPriority:

  • If it is TowerTargetPriority.First, the enemy to return is simply the first element in the list (curEnemiesInRange[0]).
  • If it is TowerTargetPriority.Close, we need to find the enemy to return by looping through each enemy in the list and checking the distance between the tower and each enemy’s position.

When comparing the distance, we need to find the vector between the two points (e.g. TowerPosition –  EnemyPosition) and then find its magnitude.

Distance from Enemy to Tower

However, the Sqrt ( √ ) calculation is quite complicated and takes longer to execute than the normal arithmetic operations. So if you’re simply comparing distances, Unity recommends using Vector3.sqrMagnitude instead of using the magnitude property.

Although sqrMagnitude doesn’t give you a usable distance in terms of units per second, it is much faster and is useful when we’re comparing it with another distance. It is a more performance-friendly way to compare distances. (Note that you should only compare it against the squares of distances. For more information, check https://docs.unity3d.com/ScriptReference/Vector3-sqrMagnitude.html).

We can use the above calculation to find the closest enemy in range.

Finally, if the TowerTargetPriority is set to Strong, we will use a foreach loop and find the enemy with the highest health points:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Tower : MonoBehaviour
{
    public enum TowerTargetPriority
    {
        First,
        Close,
        Strong
    }

    [Header("Info")]
    public float range;
    private List<Enemy> curEnemiesInRange = new List<Enemy>();
    private Enemy curEnemy;

    public TowerTargetPriority targetPriority;
    public bool rotateTowardsTarget;

    [Header("Attacking")]
    public float attackRate;
    private float lastAttackTime;
    public GameObject projectilePrefab;
    public Transform projectileSpawnPos;

    public int projectileDamage;
    public float projectileSpeed;

    void Update ()
    {
        // attack every "attackRate" seconds
        if(Time.time - lastAttackTime > attackRate)
        {
            lastAttackTime = Time.time;
            curEnemy = GetEnemy();

            if(curEnemy != null)
                Attack();
        }
    }

    // returns the current enemy for the tower to attack
    Enemy GetEnemy ()
    {
        curEnemiesInRange.RemoveAll(x => x == null);

        if(curEnemiesInRange.Count == 0)
            return null;

        if(curEnemiesInRange.Count == 1)
            return curEnemiesInRange[0];

        switch(targetPriority)
        {
            case TowerTargetPriority.First:
            {
                return curEnemiesInRange[0];
            }
            case TowerTargetPriority.Close:
            {
                Enemy closest = null;
                float dist = 99;

                for(int x = 0; x < curEnemiesInRange.Count; x++)
                {
                    float d = (transform.position - curEnemiesInRange[x].transform.position).sqrMagnitude;

                    if(d < dist)
                    {
                        closest = curEnemiesInRange[x];
                        dist = d;
                    }
                }

                return closest;
            }
            case TowerTargetPriority.Strong:
            {
                Enemy strongest = null;
                int strongestHealth = 0;

                foreach(Enemy enemy in curEnemiesInRange)
                {
                    if(enemy.health > strongestHealth)
                    {
                        strongest = enemy;
                        strongestHealth = enemy.health;
                    }
                }

                return strongest;
            }
        }

        return null;
    }

    // attacks the curEnemy
    void Attack ()
    {
    }

    private void OnTriggerEnter (Collider other)
    {
        if(other.CompareTag("Enemy"))
        {
            curEnemiesInRange.Add(other.GetComponent<Enemy>());
        }
    }

    private void OnTriggerExit (Collider other)
    {
        if(other.CompareTag("Enemy"))
        {
            curEnemiesInRange.Remove(other.GetComponent<Enemy>());
        }
    }
}

Scripting the Projectiles

In this last part of the tutorial, we’re going to be setting up the Tower Projectiles in order to attack the enemies.

Let’s begin by creating an empty GameObject called “CastleProjectile”, and adding a new C# script called “Projectile”:

Creating the "CastleProjectile" GameObject

We will also add a basic Cube as a child to visualize the projectile.

Using a basic Cube to visualize the projectile

Let’s save it as a Prefab and remove the instance from the scene.

Deleting the "CastleProjectile" from the scene

Saving the "CastleProjectile" as a Prefab

Let’s open up the script and declare the following variables:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Projectile : MonoBehaviour
{
    private Enemy target;
    private int damage;
    private float moveSpeed;

    public GameObject hitSpawnPrefab;

}

First of all, we will define the Initialize function so that the projectile moves at the given speed to damage the given target by the given damage amount. This Initialize function should be called whenever a new projectile instance is created by the Tower script.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Projectile : MonoBehaviour
{
    private Enemy target;
    private int damage;
    private float moveSpeed;

    public GameObject hitSpawnPrefab;

    public void Initialize (Enemy target, int damage, float moveSpeed)
    {
        this.target = target;
        this.damage = damage;
        this.moveSpeed = moveSpeed;
    }
}

Inside the Update function, we’re going to update the projectile’s position if the target exists. If the target is null, then we will destroy the projectile:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Projectile : MonoBehaviour
{
    private Enemy target;
    private int damage;
    private float moveSpeed;

    public GameObject hitSpawnPrefab;

    public void Initialize (Enemy target, int damage, float moveSpeed)
    {
        this.target = target;
        this.damage = damage;
        this.moveSpeed = moveSpeed;
    }

    void Update ()
    {
        if(target != null)
        {
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

To move the projectile towards the target, we will use Vector3.MoveTowards to update the transform.position. The projectile should also look at the target, and damage the target once it reaches the target.

After damaging the target, the projectile instance should be destroyed, and a new instance should be created:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Projectile : MonoBehaviour
{
    private Enemy target;
    private int damage;
    private float moveSpeed;

    public GameObject hitSpawnPrefab;

    public void Initialize (Enemy target, int damage, float moveSpeed)
    {
        this.target = target;
        this.damage = damage;
        this.moveSpeed = moveSpeed;
    }

    void Update ()
    {
        if(target != null)
        {
            transform.position = Vector3.MoveTowards(transform.position, target.transform.position, moveSpeed * Time.deltaTime);

            transform.LookAt(target.transform);

            if(Vector3.Distance(transform.position, target.transform.position) < 0.2f)
            {
                target.TakeDamage(damage);

                if(hitSpawnPrefab != null)
                    Instantiate(hitSpawnPrefab, transform.position, Quaternion.identity);

                Destroy(gameObject);
            }
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

Let’s save the script and go over to the Tower script to define the Attack function. Here, we will create a new projectile instance and initialize it with the pre-defined variables. We will also make it rotate along the Y-axis to look at the current target:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Tower : MonoBehaviour
{
    public enum TowerTargetPriority
    {
        First,
        Close,
        Strong
    }

    [Header("Info")]
    public float range;
    private List<Enemy> curEnemiesInRange = new List<Enemy>();
    private Enemy curEnemy;

    public TowerTargetPriority targetPriority;
    public bool rotateTowardsTarget;

    [Header("Attacking")]
    public float attackRate;
    private float lastAttackTime;
    public GameObject projectilePrefab;
    public Transform projectileSpawnPos;

    public int projectileDamage;
    public float projectileSpeed;

    void Update ()
    {
        // attack every "attackRate" seconds
        if(Time.time - lastAttackTime > attackRate)
        {
            lastAttackTime = Time.time;
            curEnemy = GetEnemy();

            if(curEnemy != null)
                Attack();
        }
    }

    // returns the current enemy for the tower to attack
    Enemy GetEnemy ()
    {
        curEnemiesInRange.RemoveAll(x => x == null);

        if(curEnemiesInRange.Count == 0)
            return null;

        if(curEnemiesInRange.Count == 1)
            return curEnemiesInRange[0];

        switch(targetPriority)
        {
            case TowerTargetPriority.First:
            {
                return curEnemiesInRange[0];
            }
            case TowerTargetPriority.Close:
            {
                Enemy closest = null;
                float dist = 99;

                for(int x = 0; x < curEnemiesInRange.Count; x++)
                {
                    float d = (transform.position - curEnemiesInRange[x].transform.position).sqrMagnitude;

                    if(d < dist)
                    {
                        closest = curEnemiesInRange[x];
                        dist = d;
                    }
                }

                return closest;
            }
            case TowerTargetPriority.Strong:
            {
                Enemy strongest = null;
                int strongestHealth = 0;

                foreach(Enemy enemy in curEnemiesInRange)
                {
                    if(enemy.health > strongestHealth)
                    {
                        strongest = enemy;
                        strongestHealth = enemy.health;
                    }
                }

                return strongest;
            }
        }

        return null;
    }

    // attacks the curEnemy
    void Attack ()
    {
        if(rotateTowardsTarget)
        {
            transform.LookAt(curEnemy.transform);
            transform.eulerAngles = new Vector3(0, transform.eulerAngles.y, 0);
        }

        GameObject proj = Instantiate(projectilePrefab, projectileSpawnPos.position, Quaternion.identity);
        proj.GetComponent<Projectile>().Initialize(curEnemy, projectileDamage, projectileSpeed);
    }

    private void OnTriggerEnter (Collider other)
    {
        if(other.CompareTag("Enemy"))
        {
            curEnemiesInRange.Add(other.GetComponent<Enemy>());
        }
    }

    private void OnTriggerExit (Collider other)
    {
        if(other.CompareTag("Enemy"))
        {
            curEnemiesInRange.Remove(other.GetComponent<Enemy>());
        }
    }
}

Now we can assign the public variables in the Inspector and hit Play to test it out (though you’ll of course need to set up enemies on your end to see it function):

  • Range: 2
  • Target Priority: First
  • Attack Rate: 0.5
  • Projectile Damage: 1
  • Projectile Speed: 6

Setting up the public variables in the Inspector

Testing it out in Play mode

Conclusion

And that is our tutorial complete! Well done on creating the towers for your tower defense game!

Tower defense games are excellent for you to test your level design skills by placing the towers in the best strategic spots possible for each level. You’ll also learn a lot about balancing the game difficulty to be challenging while not too cumbersome at the same time.

Now you’re ready to keep pushing your project forward, as you still need to generate the spawning of the enemy waves and make them move along custom waypoints. You’ll also need to assess when the enemy units take damage to calculate their remaining health. However, these are topics for another tutorial – for now setting up your towers is a great first step!

We hope you have enjoyed learning with us and wish you all the best of luck in your future projects!

Want to learn more about farming sims? Try our complete Create a Tower Defense Game course.

]]>
Free eBook – Godot Game Development for Beginners https://gamedevacademy.org/free-ebook-godot-game-development/ Wed, 01 Jul 2020 08:09:57 +0000 https://godottutorials.pro/?p=3566 Read more]]> We’re overjoyed to bring you our latest eBook: Godot Game Development for Beginners.

With tutorials created by experienced game developer Daniel Buckley, this eBook will set you on an exciting path of 2D and 3D game development with the open-source Godot game engine.  You’ll learn to create platformers, RPGs, first-person shooters, and more as you dive into various mechanics and the engine’s personal scripting language, GDScript.

By the end, you will have gained in-demand skills for shooting mechanics, raycasting, level set up, player controllers, and more – all of which can be expanded and applied to your own game projects!

Download the eBook here

 

]]>
Create a Puzzle Game in the Unreal Engine https://gamedevacademy.org/unreal-puzzle-game-tutorial/ Wed, 24 Jun 2020 01:00:32 +0000 https://gamedevacademy.org/?p=12212 Read more]]> Introduction

Ready to challenge your players to unique, brain-busting puzzles?

Puzzle games are a fairly unique genre in game development, requiring even more work than many other genres in its level design phase.  However, they can also be a rewarding experience in terms of development, as they offer unique challenges and systems that can be used across many different game projects.

In this tutorial, we’re going to be creating a puzzle game inside of Unreal Engine. This game will feature a player who can move around on a grid and whose goal is to collect a number of followers, evade traps, and reach the end goal.  Over the course of this tutorial, not only will you learn to use blueprints in Unreal for this purpose, but also gain a fundamental understanding of how to design puzzles and challenges for your games.

Before we continue, do know that this is not an introductory tutorial. If this is your first time using Unreal Engine, then we recommend you check out our Intro to Unreal Engine course here.

gif of the puzzle game

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

Project Files

For this project, there are a few 3D models we’ll be needing. You can use your own, although the tutorial will be made using these. The complete project can also be downloaded.

Creating the Project

To begin, let’s create a new Unreal Engine project. When creating the project, make sure to include the starter content as we’ll be using a few of the materials. To begin, let’s create three new folders.

  • Blueprints
  • Levels
  • Models

Then, create a new level and save it to the Levels folder as MainLevel.

unreal engine editor

Let’s then download the required assets (linked at the top of the tutorial). There is a folder called Models Folder Content. Inside of that, drag the contents into our Content Browser‘s Models folder.

importing models

Next, let’s setup some key bindings. We need to know which buttons we’re going to use for player movement. Open the Project Settings window (Edit > Project Settings…). Click on the Input tab and create 4 new action mappings.

  • MoveUp = W
  • MoveDown = S
  • MoveLeft = A
  • MoveRight = D

setting up player controls

Creating the Player

Now that we’ve got our controls sorted out, let’s create the player. In the Blueprints folder, create a new blueprint with a parent class of Pawn. Call it Player.

creating the player blueprint

Open it up and we can begin to create the player. First, create a static mesh component.

  • Set the Static Mesh to Player_Cylinder_003
  • Set the Material to M_Metal_Brushed_Nickel
  • Set the Scale to 0.8, 0.8, 0.8
  • Enable Simulation Generates Hit Events
  • Set the Collision Presets to OverlapAllDynamic

creating the player model

Then as a child of the static mesh, create a Point Light component.

  • Set the Location to 0, 0, 137
  • Set the Intensity to 4500
  • Set the Light Color to Green
  • Set the Attenuation Radius to 300
  • Set the Source Radius to 20
  • Disable Cast Shadows

adding a light to the player

The final component will be a Box Collision, and this is used to know if we’re going to run into a wall.

  • Set the Location to 100, 0, 50
  • Enable Simulation Generates Hit Events
  • Set the Collision Presets to Custom…

Custom collision presets means that we can choose what we want to detect with this collider. Since we’re looking for walls, they fall under WorldStatic. So under Object Responses, set everything to Ignore except WorldStatic.

overlapping wall detection collider

Now that we’ve got our player setup component-wise, let’s place them into the level. Back in the level editor, create a new blueprint of type GameMode Base and call it MyGameMode. Open it up and all we want to do here is set the Default Pawn Class to our Player.

game mode blueprint

Save, compile then go back to the level editor. In the World Settings panel, set the GameMode Override to MyGameMode. Now when we press play, our player should spawn.

Unreal Engine World Settings window

The default camera position is pretty bad, so let’s search for Camera in the Modes panel and drag that in.

  • Set the Location to -1130, -400, 210
  • Set the Rotation to 0, -60,  380
  • Set the Field of View to 40

creating the camera

Now let’s setup the level bounds. Create a new cube and position it to the corner of the platform.

  • Set the Material to M_CobbleStone_Smooth

creating a cube

Copy and past that cube so we have something that looks like this. Also, select all the walls and in the details panel, enable Simulation Generates Hit Events and Generate Overlap Events.

level layout

Since this puzzle game is in the dark with lights, let’s select the Light Source and set the Light Color to Black.

changing the light color

To make the sky night, we can select the Sky Sphere.

  • Disable Colors Determined by Sun Position
  • Set the Sun Brightness to 0.5
  • Set the Cloud Opacity and Stars Brightness to 0
  • Set the 4 colors to Black

After this, we need to click on the down arrow next to the Build button (in the toolbar) and select Build Lighting Only.

setting the sky color

It’s pretty dark, so a way we can see is by disabling the lighting when working on the level. In the viewport, click on Lit and select Unlit.

changing the scene view

Drag in the Player blueprint. Set the Auto Possess Player to Player 0 so when we press play, we have control of the player.

adding the player

Moving the Player

We’ll begin by adding in the ability for the player to move. First, we’ll create the variables.

  • TargetPositon (Vector)
  • CanMove (Boolean)

Compile, then set the CanMove default value to true.

player variables

Whenever we want to move the player, we need to see if we’re going to move into a wall. If we are, then don’t move. This will be calculated in a new function called HasWallAhead.

  • Create a vector input called PositionCheck
  • Create a boolean output called CanMoveAhead (different from image)

creating a new function

This function will change the position of the checker box, then see if it’s colliding with anything, outputting whether or not we can move ahead.

creating the function

Back in the main Event Graph, we can begin to setup the movement inputs. Here’s how the movement will work:

  1. Detect movement key input (WASD)
  2. Check if we can move to that location
  3. Set the target position to that new position
  4. Overtime move towards the target position

player movement input

Using the tick node, we can move towards the target position every frame by plugging that into a Move Component To node.

moving component to

If you press play, you’ll be able to move forward with the W key. Now let’s go ahead and setup the other three movement inputs.

4 different movement inputs

You may notice that we can move again even though we’re not at the target position yet. To fix this, create a Sequence node (we’ll be adding more to this is the future). Have the input connect to each of the set target position node outputs. What we want to do here is disable can move, wait half a second, then re-enable can move.

sequence disable can move

Creating the Progressor

This is going to be a game where everything moves only when the player moves. The followers, obstacles, etc. So to make it a nice system, we’ll create a base blueprint which all others will inherit from.

In the Blueprints folder, create a new blueprint of type Actor called Progressor. The only thing we want to do inside of this blueprint, is create a new function called OnProgress.

progressor event

Now that we have the base of all progressors (followers, blades, etc), we can call the OnProgress function when the player moves.

In the Player blueprint, create the GetAllActorsOfClass node and connect that to the sequence node.

  • Set the Actor Class to Progressor
  • Connect that to a for each loop
    • This will loop through every progressor in the level
  • We then want to call each progressor’s OnProgress function

calling the on progress function

Creating the Followers

Now that we’ve got the progressor system in place, let’s create our follower blueprint. This is going to be what the player can collect and then have follow them. Create a new blueprint with the parent class of Progressor. Call it Follower.

  • Create a static mesh component
    • Set the Static Mesh to Follower
    • Set the Materials to M_Brick_Clay_New and M_StatueGlass
    • Enable Simulation Generates Hit Events
    • Set the Collision Presets to OverlapAllDynamic
  • Create a point light with blue light

follower blueprint

We then want to create three variables.

  • CanMove (Boolean)
  • TargetPosition (Vector)
  • Target (Actor)

follower variables

In the event graph, we first want to set the initial target position when the game starts.

set target position

Using the Event Tick node, we want to make the follower move towards the target position every frame (only if they can move though).

move towards the target position

When the player moves, we’re calling all progressor’s OnProgress function. Well in the follower, we can detect when that’s being called and do something. Create the Event OnProgress node. We then need to get that parent event call, so right click on the red node and select Add call to parent function.

detecting parent function call

Finally for the follower, we need to create the SetTarget function. This will be called when the player collects them, allowing them to follow. Make sure to add an actor input for the target to be set to.

set target function

In the Player blueprint, we can setup the ability to collect these followers. First, we need some variables.

  • Create a variable of type Follower called Followers
    • We want this to be an array, so in the Details panel, click on the icon left of the variable type and choose Array
  • Create a variable of type Integer called FollowersToCollect
    • Set this to Instance Editable

follower variables

Let’s begin by creating an Event ActorBeginOverlap node to detect when we’ve overlapped an object. Then we can cast that to a follower.

follower cast

We then need to check if we’ve already collected the follower. If not, then we need to check if this is the first follower we’re collecting.

follower conditions

If this is the first follower, then set its target to us. Otherwise, set its target to the last follower in the line.

setting the follower's target

Finally, we want to add the follower, to the followers array.

adding it to the array

Back in the level editor, drag in a follower and press play!

adding the follower to the level

You can now also add in multiple followers and begin a chain!

Creating the Blade

As an obstacle, we can create a blade which will reset the player if they touch it. Create a new blueprint with the parent class of Progressor. Call it Blade.

  • Create a static mesh component called Base
    • Set the Location to 250, 0, 0
    • Set the Scale to 5.0, 0.1, 0.05
    • Set the mesh to Cube
  • Create a static mesh component called Blade
    • Set the mesh to Blade
  • As a child of the blade, create a point light component

blade components

In the event graph, let’s start with some variables.

  • MoveTicks (Integer)
  • CurrentMoveTicks (Integer)
  • StartPosition (Vector)
  • MovingForward (Boolean)

Compile, and set the MoveTicks default value to 5.

blade variables

First, we’ll have to set the start position.

setting the start position

Overtime we want the blade to rotate.

rotate over time

Continuing from that node, we’ll make it so the blade moves based on the current move ticks variable.

moving the blade

The next set of nodes will increase or decrease the current move ticks whenever the On Progress event is triggered. This will make the blade move back and forth.

moving the blade each on progress

Coming from the second sequence execution output, let’s check if the blade has collided with anything. If so, restart the level.

check blade collisions

Now we should be able to play the game and reset the scene when colliding with the blade.

End Goal

Finally, we have the end goal. This will take us to other levels.

Create a new blueprint of type Actor called EndGoal. Create a cube static mesh with a light like so:

end goal blueprint

Then, create a new variable called LevelToGoTo. Make it of type Name and enable Instance Editable.

end goal variable

All we’re going to do here, is check for collisions. If it’s the player, we’ll check to see if they have all the followers in the level and if so, open the next requested level.

end goal blueprint graph

Back in the level editor, place down the end goal and if you have a level to go to, enter the name in the detail panel.

adding the end goal to the level

Conclusion

Congratulations on completing the tutorial!

You now have the basis for a semi-turn based puzzle game.  As stated at the beginning, our game features a player who needs to collect a number of followers.  Once collected, the player needs to reach the end goal – all while avoiding a blade haunting their every step.  Our game features all of this and more, most of which we accomplished with Unreal Engine’s built-in features and blueprinting system.

From here, you can expand upon the game, adding in more levels, mechanics, etc. Or you could create an entirely new project with your newfound knowledge.

Whatever you decide, good luck with your future games and we hope you enjoyed developing a puzzle game with Unreal Engine!

Unreal Puzzle game in action

]]>
Make a Puzzle Game with Unity – Part 1 https://gamedevacademy.org/unity-puzzle-game-tutorial/ Wed, 29 Apr 2020 01:00:56 +0000 https://gamedevacademy.org/?p=11664 Read more]]> Introduction

One of the most incredible things about game design is the ability to do things that are impossible in reality. A chief example of this is the idea of the orthographic view.

Unity orthographic view demonstration

Computers have the ability to construct a perspective that does not even exist in real life. This has some fascinating consequences when it comes to creating video games. Exploring ways to utilize this unique perspective will generate a quite intriguing game.  Not only will it be unique, but it also adds another dimension of design possibilities. This look is also quite similar to certain popular video games on the mobile app stores.

In this tutorial, we will learn how to use orthographic view to create a puzzle game in Unity. From generating an orthographic projection, to creating a character, we will explore all aspects of this novel perspective for game development. Simultaneously, we will also be learning about Unity’s Navigation component system and how we can manipulate that to work in this multi-faceted view.

So, without further ado, let’s get started and create an illusion game!

Want to jump ahead?  Check out Part 2 instead!

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

Assets and Project files

You can download the completed project files for this tutorial here: source code.

We will also be using the Navigation Component system which can be obtained for free from Unity’s Github (https://github.com/Unity-Technologies/NavMeshComponents). Download it to your computer and save it in a file near your Unity projects. We are going to be accessing this later.

Creating the Illusion

Select your camera and change the perspective to “Orthographic.”

Switching the Camera to Orthographic in Unity

The way this view works is it takes all depth information and flattens it. This way, the size of objects in the scene is their “true size,” meaning that far away objects do not look smaller and closer objects do not look larger. This, you can imagine, is essential when it comes to creating this illusion.

We can create this illusion using only cubes, so go ahead and add one in.

Adding in a cube to the scene

Our camera isn’t in the right position; we need to fix that. The position isn’t as important as the rotation. We want it to be rotated around the X and Y axis so that we can essentially see three faces of the cube at the same time. Here are the final position and rotation I landed at:

The transform of the Camera in Unity

It is super important to never change the transform of the camera! Once you have a value, lock it in, do not change it. Do not write scripts moving the camera. Do not make animations moving the camera. In order for the illusion to work, we need the camera to always stay in one single position.

Once the camera is set up, we need to create an illusion we can work with. Scale the cube so that it is fairly long on one axis

A scaled cube and its transform

Next, you’re going to want to duplicate the cube and rotate the duplicate 90 degrees on the Y-axis. Position it so that it looks like this:

The cube duplicated and rotated

Bring it up above the original cube a good distance for reasons we will see later.

Repositioning the top cube

Reposition everything so that the final result looks like this:

View size on Orthographic camera

You may have to either change the position of both cubes or change the “Size” on our orthographic camera. Also, disable shadows on the directional light. This is another important part of creating the illusion.

Framing the objects in the scene

Cleaning Up The Environment

I have a couple of complaints with our current setup. First, everything is so bright! 

A material-less scene requiring sunglasses to avoid blindness

Let’s add in some materials. Create a new folder called “Materials” and create a new material called “Blue.” Change the Albedo value to blue and drag this material onto both of our cubes.

Adding a material to our cubes

That looks much better! The second thing we need to change is our hierarchy.

A disorganized and inefficient hierarchy

It looks so un-organized. Plus, the scale of our cubes will present problems later on if we try and animate them. So first, let’s create an empty game object called “Environment” and place our cubes in that.

The Environment object parenting all the cubes

Next, let’s further parent our cubes into empty game objects called “PlatformTop” and “PlatformOccluded” so that they’ll each have a uniform scale of 1.

The Cubes parented to newly created Gameobjects

The scale of each cube's parent

There we are! A nicely setup scene that we can work with. As a very final step, create a capsule called “Character” and place it on our cubes.

A capsule which will serve as our character

Since this is going to be our character, you might consider changing the size of the environment (change the scale of the children, not the parents which must stay at 1). The character should easily fit under both of these cubes

Properly placing objects to make space for the character

Setting Up Navigation

Agents and Nav-Meshes

In your project files, create a new folder called “Navigation Components.” Navigate to where you stored your downloaded Navigation Components from Github and drop the “NavMeshComponents” folder into your project tab (this is located in “NavMeshComponents-master -> Assets”). There are some examples in the entire folder that are worth checking out in a separate, dedicated Unity project. When the folder is done importing, you’ll notice the presence of a few more scripts in the “Navigation” category of the components.

Newly imported navigation scripts

If you’d like a more in-depth look at what exactly these components do, check out the tutorial on the Game Dev Academy about Unity’s native navigation tools (https://gamedevacademy.org/learn-unitys-navmesh-by-creating-a-click-to-move-game/). For now, assign a “Nav Mesh Agent” to our character capsule.

The navigation Agent component

A “Nav Mesh Agent” is a game object which traverses a nav mesh. Basically, this is the game object that’s going to be doing the path-finding. Most of the settings in the agent component are fairly intuitive. I suggest, in order to better understand what each of these settings do, fiddle with these values when we’ve got the character on a working nav mesh. What I mainly want to highlight here is the cylinder shape surrounding the capsule.

The Collider on our character

In addition to the capsule collider (which should be set to “trigger” by the way), we’ve got an extra boundary being created. The size and radius of this cylinder is the size and radius that Unity will think the navigation agent is. This isn’t a value we can’t edit this value on the Nav Mesh Agent, rather, when we get to it, we will actually be editing this on the nav-mesh itself.

But what is a Nav Mesh exactly? A nav-mesh is an actual mesh generated by Unity which allows the agent to make paths on its geometry. Any place where there is a nav-mesh is a place where the nav-mesh agent can generate a path. Having said that, we’re going to want a nav-mesh on both our cubes. Select the parent of each cube and add a “Nav Mesh Surface” component to each.

A Nav-Mesh Surface component added to each cube

The settings for this component are worth looking at. First, you’ll notice that there is an “Agent Type” field. This is set to “Humanoid” by default. The idea behind this value is that you could set different types of nav-mesh agents (things like animals, enemies, etc.) if you wanted them to path-find differently. Since “Humanoid” is what our character is, we’re going to leave this at the default value.

“Collect Objects” determines which surfaces are going to have a nav-mesh baked onto them. In our case, we want this set to “children” since that is where are cubes are. “Includes Layers” allows you to determine what render layers you want to be involved in the nav-mesh calculation. And “Use Geometry” allows you to set whether you want the geometry or the physics colliders belonging to the game object to be considered viable nav-mesh surfaces. Finally, there is a “Bake” and “Clear” button at the end of the component. Hit “Bake” for each of the components we created. Unity will then generate the nav-meshes and your viewport will look like this:

Our scene with baked nav-meshes

That little blue sliver is our nav-mesh. Let’s test to see if it’s working! Create a new folder called “Scripts” and create a new script called “PlayerController.”

A newly created script in a newly created folder

In that script, we’re going to write out a simple bit of code that sends out a ray-cast, checks to see if it’s on a nav-mesh, and sets the clicked position to be the destination of the agent if the click was indeed on a nav-mesh.

using System.Collections;
using System.Collections.Generic;
using UnityEngine.AI;
using UnityEngine;

[RequireComponent(typeof(NavMeshAgent))]
public class PlayerController : MonoBehaviour
{
    private NavMeshAgent agent;
    private RaycastHit clickInfo = new RaycastHit();

    // Start is called before the first frame update
    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray.origin, ray.direction, out clickInfo))
                agent.destination = clickInfo.point;
        }
    }
}

Drag and drop this script on to our capsule character. Hit play and watch the magic!

The character navigating the occluded cube

Our character now moves where we click! Note this, because we have the nav-mesh as a component, it exists on that game object meaning we can move the game object and our nav-mesh follows. This will be handy when it comes to animating the platforms.

Off Mesh Links

The entire purpose of this illusion was to make it so that surfaces that seem connected can be navigated by the player. As such, we want these two surfaces to be connected somehow.

An apparent surface connection

This is where Off-Mesh Links come in. Just like their name implies, they are a way to link two nav-mesh surfaces. Create a new empty game object called  “Link1” and place it in the Environment.

Link in the hierarchy

Add a “NavMeshLink” component (not an “Off-Mesh Link”) to this game object.

Off-mesh link component

As you can see, we get two transforms. These are, intuitively, the start and end positions of our link. We need to place each transform on the occluded cube and another on the top cube. You will see a circle form when the transform is over a viable nav-mesh surface.

A viable off-mesh link

Now here is where the uniqueness of the illusion comes in. We need to strategically place these off-mesh links in such a way so that they align in the game view. This causes a disconnect in world space but an apparent connection in orthographic space.

The illusion preserved in the game view

If you don’t see any of this in the game view, enable “Gizmos” in the top right corner. Our player now has the ability to navigate both cubes!

Navigation with links

Cleaning things up

Right now, the mechanic works. Our player can navigate two disconnected surfaces. However, it looks all wrong. There is too much of a translational delay. We need it to be as seamless as possible. Now, we realize that it won’t look 100% seamless simply because we’re using a navigation system that wasn’t really built for what we’re using it for. This link system was designed for things like ladders or teleportations, not necessarily illusion upholding linkage. Nevertheless, we can make an exponential improvement to this atrocious way of crossing platforms. As soon as the player is on a link, we don’t want it to interpolate between the positions (causing a delay). Instead, we can make it instantaneously teleport through the link. To do this, we’re actually going to write a bit of code with our own method of crossing links. In the “PlayerController” script, we need to add this if-statement to our update function,

void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray.origin, ray.direction, out clickInfo))
                agent.destination = clickInfo.point;
        }

        if (agent.isOnOffMeshLink) //New logic statement
        {
            agent.CompleteOffMeshLink();
        }


    }

“CompleteOffMeshLink” is a method we call on the navigation agent. It will instantaneously move the character through the off-mesh link whenever it is called. In our case, we’re calling this method whenever we’re on an off-mesh link.

To test it out, make sure that “Auto Traverse Off Mesh Link” is disabled.

Nav-Mesh Agent with "auto traverse" disabled

Hit play and let’s have a look!

An improved interpolation between platforms for the illusion

This actually is only a slight improvement. It’s much too sudden. It looks weird because the character just appears right in the middle of the platform. This is because our navigation mesh is right in the center of our platform.

A nav-mesh surface only covering part of the cube

We can fix this by changing the agent size of the nav-mesh agent. Go to the Navigation tab and change the radius of the character to be a very small value.

Agent radius in Unity

Go over our nav-mesh surfaces and rebake each of them. This will make the navigation surface cover the top of most of the cubes.

A rebake of the nav-mesh so that it covers everything

Notice, however, we have an error message.

A warning message on the nav-mesh surface component

Basically, it’s saying that the navigation surface may not be accurate for such a small agent radius. To fix this, open “Advanced Settings,” check “Override Voxel Size.” Set it to the recommended size of 0.022. We need to do this on each surface component and then bake it as well. The error will be cleared when each surface has finished baking.

We need this navigation surface to cover as much of the platform as possible. To increase the precision of our linkage system, we can scale the top cube ever so slightly to be underneath all of the navigation surface.

The navigation surface covering all of the top of the cube

And now, it’s just a matter of strategically placing the links so that one of them is on the edge of the top cube.

Repositioning the link on the edge

Now, hit play and test it!

Our final interpolation system

As you can see, this isn’t 100% seamless but it is an improvement to the previous look. To improve the “seamlessness” of the link, try repositioning the start and end points. It’s just a matter of fiddling with values. Even though it doesn’t completely uphold the illusion, it will certainly suffice for prototyping and level testing.

Conclusion

Whew!  We’ve covered a lot of ground here and learned quite a bit about using Unity’s Navigation component system and orthographic views to create a game.  Not only did we get our systems set up for our illusion game, but we also got our character moving!

However, while, we’ve got the ability to navigate disconnected platforms, it isn’t as seamless we can get.

In the next tutorial, we’re going to write a custom algorithm for interpolating between points. We’re also going to be animating platforms and giving the player the ability to trigger these animations from in-scene actuators. This might all sound a bit complicated, but worry not as we will walk you through each step to get it done!

Let’s continue this exploration of perspective as we…

Keep making great games!

]]>
How to Make a Strategy Game in Godot – Part 2 https://gamedevacademy.org/godot-strategy-game-tutorial-part-2/ Tue, 03 Mar 2020 01:00:44 +0000 https://godottutorials.pro/?p=3393 Read more]]> 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.

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

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.

]]>