MakeUseOf logo

How to Save and Load Game Data in Arcade

game screen with high score and health
No attribution required: Unsplash
Imran is a writer at MUO with 3 years of experience in writing technical content. He has also worked with many startups as a full-stack developer. He is passionate about writing and helping others learn about technology. In his free time, he enjoys exploring new programming languages.
Sign in to your MakeUseOf account

Adding a save and load system to your game can greatly enhance the player experience. It allows players to persist their progress, resume gameplay sessions, and experiment with different strategies without losing hard-earned achievements.

You'll be pleasantly surprised by how straightforward it is to add this feature to your game using Python’s Arcade library.

Create a Simple Game

Start by creating a simple game where the player can move left and right.

The code used in this article is available in this GitHub repository and is free for you to use under the MIT license.

Create a new file named simple-game.py and add the below code:

import arcade
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
PLAYER_SPEED = 5
blue = arcade.color.BLUE
class GameWindow(arcade.Window):
 def __init__(self, width, height):
 super().__init__(width, height)
 self.player_x = width // 2
 def on_draw(self):
 arcade.start_render()
 arcade.draw_rectangle_filled(self.game_state.player_x, 
 50, 50, 50, blue)
 def update(self, delta_time):
 pass
 def on_key_press(self, key, modifiers):
 if key == arcade.key.LEFT:
 self.player_x -= PLAYER_SPEED
 elif key == arcade.key.RIGHT:
 self.player_x += PLAYER_SPEED
def main():
 window = GameWindow(SCREEN_WIDTH, SCREEN_HEIGHT)
 arcade.run()
if __name__ == '__main__':
 main()

The code creates a window with a blue rectangle representing the player. The player can move left and right using the left and right arrow keys.

[画像:simple game in arcade with a player object]
No attribution required: Screenshot by Imran

Managing Game States

To implement a save and load system, you need to manage different game states. A game state represents the current state of the game, including the positions of objects, scores, and other relevant data. For this example, focus on only the player's x-coordinate.

To manage game states, introduce a GameState class that encapsulates the game's data and provides methods to save and load it. Here's the code:

class GameState:
 def __init__(self):
 self.player_x = 0

Saving the Game Data

To save the game data, extend the GameWindow class and add a method to save the game state whenever necessary. Use the JSON format for simplicity. Here's the code:

In the save_game method, create a Python dictionary containing the relevant game data. Then serialize it into a JSON file called save.json.

import json
class GameWindow(arcade.Window):
 def __init__(self, width, height):
 super().__init__(width, height)
 self.game_state = GameState()
 def save_game(self):
 data = {
 'player_x': self.game_state.player_x
 }
 with open('save.json', 'w') as file:
 json.dump(data, file)
 print(data)
 def on_draw(self):
 arcade.start_render()
 arcade.draw_rectangle_filled(self.game_state.player_x, 
 50, 50, 50, blue)
 def update(self, delta_time):
 pass
 def on_key_press(self, key, modifiers):
 if key == arcade.key.LEFT:
 self.game_state.player_x -= PLAYER_SPEED
 elif key == arcade.key.RIGHT:
 self.game_state.player_x += PLAYER_SPEED
 elif key == arcade.key.S:
 self.save_game()

Loading the Game Data

To load the game data, extend the GameWindow class further and add a method to load the game state. Create a new file named load-game.py and add the code with the below updates:

class GameWindow(arcade.Window):
 def __init__(self, width, height):
 super().__init__(width, height)
 self.game_state = GameState()
 self.load_game()
 def load_game(self):
 try:
 with open('save.json', 'r') as file:
 data = json.load(file)
 self.game_state.player_x = data['player_x']
 except FileNotFoundError:
 pass
 def on_key_press(self, key, modifiers):
 if key == arcade.key.L:
 self.load_game()

The load_game method attempts to open the save.json file and retrieve the game data. It then updates the game state with the loaded data. If the file doesn't exist, you can just ignore the exception, leaving the default game state.

[画像:arcade game with player object and loaded game data]
No attribution required: Screenshot by Imran

Including Additional Features

You can add more features to enhance the game’s save and load system.

Saving High Scores

Saving high scores alongside the game state is a common feature in many games. You can manage the scores and save the high score using this system. Create a new file named high-score.py and add the code with the below updates:

class GameWindow(arcade.Window):
 def __init__(self, width, height):
 super().__init__(width, height)
 self.high_score = 0
 def load_game(self):
 try:
 with open('save.json', 'r') as file:
 data = json.load(file)
 print(data)
 self.player_x = data.get('player_x', self.player_x)
 self.high_score = data.get('high_score', self.high_score)
 except FileNotFoundError:
 pass
 def save_game(self):
 data = {
 'player_x': self.player_x,
 'high_score': self.high_score
 }
 with open('save.json', 'w') as file:
 json.dump(data, file)
 print(data)
 def on_key_press(self, key, modifiers):
 if key == arcade.key.LEFT:
 self.player_x -= PLAYER_SPEED
 elif key == arcade.key.RIGHT:
 self.player_x += PLAYER_SPEED
 self.high_score += 1

Autosave Feature

To provide players with peace of mind and prevent loss of progress, you can automatically save the game state at regular intervals. Create a new file named auto-save.py and add the code with the below updates:

import time
class GameWindow(arcade.Window):
 def __init__(self, width, height):
 super().__init__(width, height)
 self.game_state = GameState()
 # Save every 6 seconds
 self.autosave_interval = 6
 self.last_save_time = time.time()
 def update(self, delta_time):
 current_time = time.time()
 time_diff = current_time - self.last_save_time
 if time_diff >= self.autosave_interval:
 self.save_game()
 print("Saved")
 self.last_save_time = current_time

In this code snippet, the update method checks if the specified time interval has passed since the last save. If so, it triggers the save_game method of the GameWindow class to automatically save the game state. Adjust the autosave_interval value according to your game's requirements.

Validating Game Data

Validating the loaded game data is essential to ensure its integrity and consistency. You can easily incorporate data validation into our save and load system:

class GameState:
 def __init__(self):
 self.player_x = 0
 def save_state(self):
 if self.is_valid_state():
 data = {
 'player_x': self.player_x
 }
 with open('save.json', 'w') as file:
 json.dump(data, file)
 def load_state(self):
 with open('save.json', 'r') as file:
 data = json.load(file)
 if self.validate_loaded_data(data):
 self.player_x = data['player_x']
 else:
 print("Error!")
 def is_valid_state(self):
 # Perform validation logic here
 # Return True if the state is valid, False otherwise
 pass
 def validate_loaded_data(self, data):
 # Perform validation on the loaded data
 # Return True if the data is valid, False otherwise
 pass

By incorporating these additional features into the save and load system, you can create a more versatile and robust gameplay experience, offering players the ability to save multiple game states, track high scores, enable autosave, and ensure data integrity.

Best Practices for the Save and Load System

Implementing a save and load system is an important aspect of game development. To ensure a robust and reliable system, it's essential to follow best practices. Here are some key practices to consider:

Encrypt Sensitive Data

If your game includes sensitive information such as passwords, personal data, or in-app purchases, it's crucial to encrypt the saved game state. Encryption adds an extra layer of security, protecting the player's privacy and preventing unauthorized access to their data. Utilize encryption algorithms and libraries to safeguard sensitive information.

Validate Loaded Data

Before loading the game data, it's essential to validate it to ensure its integrity and consistency. Verify that the loaded data adheres to the expected format, structure, and constraints of your game.

Perform validation checks on critical data fields to avoid crashes or cheating. Implement robust data validation mechanisms to handle potential errors or unexpected data.

Handle Errors Gracefully

When dealing with file I/O operations, errors can occur. It's crucial to handle these errors gracefully and provide informative error messages to the player. Catch and handle exceptions, such as FileNotFoundError or PermissionError, during save and load operations.

Display user-friendly error messages to guide players and prevent frustration. Additionally, consider implementing error logging to help diagnose and fix issues.

Test Save and Load Functionality

Thoroughly test the save and load functionality of your game to ensure its reliability and correctness. Create test cases that cover various scenarios, such as saving in different game states, loading from valid and invalid save files, and testing edge cases.

Validate that the game state is properly saved and loaded and that the expected behavior occurs. Automated testing frameworks can assist in creating comprehensive test suites.

Make Games More Fun With Save and Load System

Adding a save and load system can make games more engaging by providing players with a sense of continuity and progress. Players can experiment freely, try different approaches, and return to the game later without losing their accomplishments.

This feature also allows players to compete with friends or challenge themselves to beat their previous high scores, adding replayability and long-term engagement to your game.

AltStyle によって変換されたページ (->オリジナル) /