Duck Typing
2025/12/27
- Type
- Learning Resource
- Format
- Glossary Article
- Version
- General
- Subject Tags
- Created
- Updated
- 2026/02/16
- 2025/12/27
In languages with strong types, you can discriminate between different elements based on their type. For example, in Java, you can have a method that receives an object of type Animal, and then you can check if the object is an instance of Dog or Cat to perform different actions.
In GDScript, you can also do that. If you have an Animal class, and two sub-classes Dog and Cat, you could write the below:
extends Node
func determine_animal_type(animal: Animal):
if animal is Dog:
print("It's a dog!")
elif animal is Cat:
print("It's a cat!")
else:
print("It's an animal, but we don't know which")However, this system only works if the elements have a common parent. If you have two classes that don't share a common parent, you can't use this method. This is where duck typing comes in.
Duck typing is the process of guessing what a variable is based on its methods or properties: "If it walks like a duck and quacks like a duck, it's a duck".
This is commonly used in Godot to apply damage to enemies. For example, in a game, the Player class and the various enemies might all descend from different classes. However, if they all have a take_damage() method, you can call that method without knowing the exact type of the object. For example, here's a BirdEnemy class with a take_damage() method:
class_name BirdEnemy extends Area3D
var health := 100
func take_damage(damage: int) -> void:
health -= damage
if health <= 0:
queue_free()And this bullet will check if an object has a take_damage() method:
func on_area_entered(target: Area3D) -> void:
if target.has_method("take_damage"):
target.take_damage(10)This assumes you respect a contract where all objects that have a take_damage() method use the same function signature. In this example above, take_damage() receives an int or a float as a parameter.
Another way to check for an object type is to add a special property. Let's assume you have a bird enemy, based on Area3D, and a bull enemy, based on CharacterBody3D. You may add an is_enemy property to both classes:
class_name BirdEnemy extends Area3D
var is_enemy := true
var health := 5
func take_damage(damage: int) -> void:
health -= damageclass_name BullEnemy extends CharacterBody3D
var is_enemy := true
var health := 15
func take_damage(damage: int) -> void:
health -= damageThen, you can check if an object is an enemy by checking if it has the is_enemy property:
func on_area_or_body_entered(target: Node) -> void:
if target.is_enemy:
target.take_damage(10)That's a different contract, more complicated: you're making a contract that if you add the is_enemy property, you will also always add the take_damage() method.
As you can see, while duck typing is practical, it is also error-prone. For that reason, at GDQuest we prefer to use composition when possible. For example, we could have a HitBox class that handles damage. This hitbox could be added to any object that needs to take damage. When its health reaches 0, it deletes its parent:
class_name HitBox extends Area3D
@export var health := 10
func take_damage(damage: int) -> void:
health -= damage
if health <= 0:
get_parent().queue_free()Then, you can add a HitBox to any object that needs to take damage. This simplifies your code and you can avoid duck typing:
extends Node
func on_area_entered(target: Area3D):
if target is HitBox:
target.take_damage(10)Don't stop here. Step-by-step tutorials are fun but they only take you so far.
Try one of our proven study programs to become an independent Gamedev truly capable of realizing the games you’ve always wanted to make.
Get help from peers and pros on GDQuest's Discord server!
20,000 membersJoin ServerThere are multiple ways you can join our effort to create free and open source gamedev resources that are accessible to everyone!
Sponsor this library by learning gamedev with us onGDSchool
Learn MoreImprove and build on assets or suggest edits onGithub
Contributeshare this page and talk about GDQUest onRedditYoutubeTwitter…