Hello! In our last lesson, we covered loops, which are essential for repeating actions in your code. You learned how to use for and while loops to iterate over data and repeat tasks, a skill that's fundamental to making games interactive and dynamic.
As our programs grow, we risk our code becoming long, repetitive, and hard to manage. Imagine if every time a monster attacked, you had to copy and paste the same ten lines of code for calculating damage. It would be a nightmare to update!
This is where functions come in. A function is a named, reusable block of code that performs a specific task. Your goal for this lesson is to learn how to define and call functions with parameters and return values.
In game development, functions are the building blocks of your entire project. You'll write functions for everything:
attack(attacker, target)use_item(player, item)open_door(door_id)play_sound(sound_file)
By mastering functions, you'll be able to write cleaner, more organized, and more powerful code, bringing you one big step closer to creating your RPG.
What is a Function?
At its core, a function is a way to package up a piece of code, give it a name, and then run it whenever you want just by calling that name. This follows the "Don't Repeat Yourself" (DRY) principle, one of the most important ideas in programming.
Let's start with a video that gives a quick and clear introduction to the concept.
Functions in Python are easy 📞
The video 'Functions in Python are easy' from the Bro Code channel provides a great starting point. We'll begin with the first part, which explains what a function is and how to define and call a simple one.
Watch from the beginning to 01:47. The video uses the example of singing 'Happy Birthday' to demonstrate how functions help you avoid repeating code.
As the video showed, the basic syntax to define a function uses the def keyword, followed by the function's name and a pair of parentheses:
# Defining the function
def show_title_screen():
print("==========================")
print(" THE LEGEND OF PYTHONIA ")
print("==========================")
print("\n (Press Enter)")
# Calling the function to execute its code
show_title_screen()
Every time you call show_title_screen(), it will execute the three print statements inside it. This is already useful, but the real power comes when we give functions information to work with.
Passing Data to Functions: Parameters and Arguments
What if you want a function to be more flexible? For instance, a function that greets a player by name. You don't want to write a separate function for every possible name. Instead, you want one function that can accept any name you give it.
This is done using parameters and arguments.
- Parameters are the variables you list inside the parentheses in the function definition. They act as placeholders for the data the function expects to receive.
- Arguments are the actual values you pass to the function when you call it.

Let's continue with the video, which explains this concept very clearly.
Functions in Python are easy 📞
The next segment of the 'Functions in Python are easy' video demonstrates how to pass data (arguments) to a function and receive it with parameters.
Watch from 01:47 to 06:08. Pay close attention to how the number and order of arguments you pass must match the parameters in the function definition.
To see this in a game context, imagine a function that describes an attack. It needs to know who is attacking and what attack they are using.
# 'character_name' and 'attack_name' are parameters
def perform_attack(character_name, attack_name):
print(f"{character_name} uses {attack_name}!")
# "Hero" and "Slash" are arguments passed to the function
perform_attack("Hero", "Slash")
# "Slime" and "Goo Spit" are different arguments for the same function
perform_attack("Slime", "Goo Spit")
Output:
Hero uses Slash!
Slime uses Goo Spit!
The same function perform_attack behaves differently based on the arguments we provide.
To get a deeper, visual understanding of what Python does "under the hood" when you call a function, the following video is incredibly helpful.
Python Functions - Visually Explained
The video 'Python Functions - Visually Explained' traces the execution of a function step-by-step. This will help solidify your understanding of how arguments are assigned to parameters.
Watch from 00:12 to 04:27. This covers the function header, the body, and most importantly, visually traces how Python executes a function call, assigning the argument values (like 14 and 10) to the function's parameters (length and width).
Getting Data Back from Functions: The return Statement
So far, our functions have only printed text to the screen. But what if a function needs to calculate something and give the result back to the main program? For example, a function to determine combat damage shouldn't just print the damage; it needs to return the numeric value so we can subtract it from the enemy's health.
This is done with the return statement. When a return statement is executed, the function stops immediately and sends the specified value back to where it was called.
Let's see the final part of the "Bro Code" video.
Functions in Python are easy 📞
This last segment of 'Functions in Python are easy' explains how the return statement works and how you can capture the returned value in a variable.
Watch from 06:08 to 10:26. Notice how the result of a function like add(1, 2) can be assigned to a variable, like z = add(1, 2).
A crucial concept related to return is scope. Variables created inside a function (like the damage variable in the example below) are local to that function. They are destroyed once the function finishes. The only way to get information out is with return.
The "Visually Explained" video has an excellent segment on this.
Python Functions - Visually Explained
Let's revisit 'Python Functions - Visually Explained' to understand why the return statement is so essential. It introduces the concept of a 'local namespace' (or scope).
Watch from 08:03 to 10:29. This is a key concept. It explains that variables created inside a function are temporary and disappear when the function ends. The return statement is how you save a value from being lost.
Here is a complete RPG combat example showing the whole flow:
# Define a function to calculate damage. It takes two parameters.
def calculate_damage(attack_power, defense):
# Calculate damage. The 'damage' variable is local to this function.
damage = attack_power - defense
# If damage is negative, it should be 0 (you can't heal by attacking!)
if damage < 0:
damage = 0
# Return the final calculated value.
return damage
# --- Main part of our program ---
player_attack = 15
enemy_defense = 8
enemy_hp = 50
print(f"The enemy has {enemy_hp} HP.")
# Call the function and store its return value in a new variable.
damage_dealt = calculate_damage(player_attack, enemy_defense)
print(f"The player attacks and deals {damage_dealt} damage!")
# Use the returned value to update the game state.
enemy_hp = enemy_hp - damage_dealt
print(f"The enemy now has {enemy_hp} HP.")
Test your understanding!
You're designing the character creation screen for your RPG. Write a function named get_initial_stats.
- The function should accept two parameters:
base_strengthandbase_vitality. - Inside the function, calculate two derived stats:
healthshould be10 + (base_vitality * 5)attack_powershould be5 + base_strength
- The function should
returnbothhealthandattack_power. Hint: you can return multiple values by separating them with a comma, likereturn value1, value2.
After defining the function, call it with a base_strength of 8 and a base_vitality of 5. Store the two returned values in variables named player_health and player_attack, and then print them out.
Show answer
Here's a solution. Notice how we can assign the two returned values to two variables in a single line.
def get_initial_stats(base_strength, base_vitality):
health = 10 + (base_vitality * 5)
attack_power = 5 + base_strength
return health, attack_power
# Call the function with arguments 8 and 5
# The first returned value (health) goes into player_health
# The second returned value (attack_power) goes into player_attack
player_health, player_attack = get_initial_stats(8, 5)
print(f"Your new character has {player_health} health and {player_attack} attack power.")
# Expected output:
# Your new character has 35 health and 13 attack power.
Functions in a Real Project
Let's look at how these concepts are applied in a practical scenario. The following resource is a discussion from a programmer trying to build a simple RPG combat system. It's a perfect example because it shows common mistakes and how to fix them by correctly using function arguments and return values.
random - Basic Python RPG combat
This Stack Overflow page 'Basic Python RPG combat' shows a beginner's attempt at creating combat logic and the corrections provided by an experienced programmer. It's a great real-world case study.
Read the answer provided (you can ignore the user's initial incorrect code). Focus on the corrected functions (roll_to_hit, roll_4_dmg) and the final while loop. See how the loop calls roll_to_hit and checks its True/False return value, and how it calls roll_4_dmg to get a number that it then uses to update the current_hp.
This example is key because it shows the most common mistake beginners make: calling a function but not doing anything with its return value. Calling roll_4_dmg(strength) on its own does nothing useful in the main loop; you must capture the result with damage_done = roll_4_dmg(strength).
As a final look ahead, the structure of a real game project relies heavily on functions. In the Roguelike tutorial (a resource we will use more in the future), the attack function doesn't just return a single number. It returns a list of "results" (like a message to display and whether the target died), which the main game loop then processes.
# A simplified example based on the roguelike tutorial
def attack(self, target):
results = [] # A list to hold outcomes
damage = self.power - target.fighter.defense
if damage > 0:
# The function doesn't print! It just adds a dictionary to the results.
results.append({'message': f'{self.name} attacks {target.name} for {damage} damage.'})
# It also calls another function and adds its results
results.extend(target.fighter.take_damage(damage))
else:
results.append({'message': f'{self.name} attacks {target.name} but does no damage.'})
return results # Returns the whole list of outcomes
You don't need to understand every detail here. The key takeaway is that professional code organizes logic into functions that take in data (parameters) and send back results (return), separating the calculation from the action.
Conclusion
Great work! You've just learned one of the most important concepts in programming. Functions are essential for writing code that is readable, manageable, and reusable.
Here are the key points from this lesson:
- Functions are named, reusable blocks of code defined with the
defkeyword. - They help you follow the DRY (Don't Repeat Yourself) principle.
- You pass data into a function using arguments, which are received by the function's parameters.
- You get data out of a function using the
returnstatement. - Variables created inside a function are local and disappear when the function ends;
returnis the only way to get their values out. - It's crucial to capture and use the return value of a function in your main program.
In our next lesson, we'll dive into lists and dictionaries. Now that you know how to create reusable blocks of logic with functions, you'll need more powerful ways to store and manage collections of data—like a player's inventory, a character's stats, or all the monsters on a level. Lists and dictionaries are the perfect tools for the job.