This is more than is expected for a Project at NCEA Level 2 and 3
Storing high scores locally is a classic game dev Milestone, and SQLite is a fantastic choice for Godot – it’s lightweight, self-contained, and much more robust than just dumping text into a JSON file.
Since Godot doesn’t have SQLite built-in by default, we will use the highly popular Godot-SQLite plugin.
Here is your step-by-step Guide to setting up and using SQLite3 in Godot 4.
1. Setup & Installation
Before writing code, you Need to add the SQLite extension to your Project.
- Open your Godot Project.
- Click on the AssetLib tab at the top of the editor.
- Search for “Godot-SQLite” (by 2shady4u) and download it.
- In the installation window, Ensure it installs into your
addons/folder. - Go to Project -> Project Settings -> Plugins and check the Enable box next to Godot-SQLite.
2. Creating the Database Manager (Autoload)
To make sure your database is accessible from any scene (MainMenu, GameOver, etc.), it’s best to create a singleton (Autoload).
- Create a new script named
DatabaseManager.gd. - Go to Project -> Project Settings -> Autoload, add this script, and name it
DatabaseManager.
Here is the foundational code to initialize your database and create a highscores table:
extends Node
const SQLite = preload("res://addons/godot-sqlite/bin/gdsqlite.gd")
var db: SQLite
var db_path: String = "user://game_data.db" # 'user://' ensures it saves correctly on all platforms
func _ready() -> void:
# Initialize the database
db = SQLite.new()
db.path = db_path
db.open_db()
# Create the high scores table if it doesn't exist
create_highscore_table()
func create_highscore_table() -> void:
var table_structure: Dictionary = {
"id": {"Data_type": "int", "primary_key": true, "not_null": true, "auto_increment": true},
"player_name": {"Data_type": "text", "not_null": true},
"score": {"Data_type": "int", "not_null": true},
"date": {"Data_type": "text"}
}
db.create_table("highscores", table_structure)
We use
user://for the database path. If you useres://, your game won’t be able to save Data once it’s exported into a finished executable!
3. Saving a New High Score
When a player dies or finishes a round, you’ll want to insert their name and score into the database. Add this Function to your DatabaseManager.gd:
func save_score(player_name: String, score: int) -> void:
# Get current date/time to log when the score happened
var current_time: String = Time.get_datetime_String_from_System(false, true)
var Row_Data: Dictionary = {
"player_name": player_name,
"score": score,
"date": current_time
}
# Insert into the 'highscores' table
db.insert_Row("highscores", Row_Data)
print("Score saved successfully!")
4. Retrieving the Top Scores
To display a Leaderboard, you Need to Query the database, sort the scores from highest to lowest, and limit the results (e.g., Top 10). Add this to DatabaseManager.gd:
func get_top_scores(limit: int = 10) -> Array:
# Construct a Query to get top scores sorted descending
# SQLite plugin allows custom queries via text
var Query: String = "SELECT player_name, score, date FROM highscores ORDER BY score DESC LIMIT %d;" % limit
db.Query(query)
# db.Query_result holds an Array of Dictionaries representing the rows
return db.Query_result
5. Putting It All Together (Example Usage)
Now that your manager is setup, using it anywhere else in your game is incredibly straightforward.
Saving a score from a “Game Over” screen:
extends Control
func _on_submit_score_button_pressed() -> void:
var name_entered = $LineEdit.text
var final_score = 15200 # Grab this from your global game manager
if name_entered != "":
DatabaseManager.save_score(name_entered, final_score)
Displaying the leaderboard on a “Main Menu” screen:
extends Control
@onready var score_list = $ItemList # An ItemList UI node to display rows
func _ready() -> void:
display_leaderboard()
func display_leaderboard() -> void:
score_list.clear()
# Fetch top 5 scores
var top_scores: Array = DatabaseManager.get_top_scores(5)
# Loop through rows and add them to the UI
var rank = 1
for row in top_scores:
var entry_text = "%d. %s - %d pts (%s)" % [rank, row["player_name"], row["score"], row["date"].split("T")[0]]
score_list.add_item(entry_text)
rank += 1
Staying Safe
Sanitization: The Godot-SQLite plugin handles Basic dictionary-to-Query conversions safely, but if you write raw SQL strings with user input, always be careful of SQL injection.
Closing the DB: It’s good practice to close the database connection when the game exits. You can add a func _exit_tree() -> void: db.close_db() into your DatabaseManager.gd.




