-
Notifications
You must be signed in to change notification settings - Fork 1
Saving the Character
The objective of this task is to implement a robust saving system that captures and preserves the player's current state during gameplay. This includes the specification of player's health, collected items, and equipped weapons. By serialising this information into a JSON file, the game can easily load and restore player's progress at any point, enhancing the suer's experience by allowing seamless continuation between gaming sessions. This feature is particularly important for integrating pause/unpause functionality and providing save/load mechanism, ensuring that players do not lose progress and can resume gameplay from where they left off.
The saving system is composed of three primary components that work together to capture and store the player's state:
- PlayerConfig: Define the data structure for storing player-related information
-
PlayerConfigGenerator: Extracts the current state of the player from different components of an entity and construct a
PlayerConfig
object. -
SavePlayerGenerator: Manages the process of writing the
PlayerConfig
object to a JSON file using a file loader utility.
These components are designed with modularity and scalability in mind, allowing for easy extension and maintenance as the game's features evolve.
Purpose: This serves as a data model that encapsulates all necessary information about the player's state that needs to be saved. It includes attributes such as health, base attack, collected items and equipped weapons.
Key Attributes:
-
name
: Name of the player -
armour
: The amount of armour -
buff
: The amount of buff -
canCrit
: ability to crit -
critChance
: the amount of critChance -
health
: Represents the player's current health points. -
baseAttack
: Indicates the player's base attack strength. -
items
: An array containing specification of all items collected by the player. -
coins
: The amount of coins player has earned -
difficulty
: the difficult that game was being played in -
timeInvincible
: the amount of invincibility -
speed
: x and y coordinates for speed vector of player -
melee
: Specification of the currently equipped melee weapon. -
maxHealth
: The Mac health a player can have -
pets
: the name of the pets -
textureFilename
: the texture filename -
textureAtlasFilename
: the texture atlas this player uses -
ranged
: Specification of the currently equipped ranged weapon. -
equipped
: Indicates the currently active weapon type (e.g. 'melee' or 'ranged')
Implementation Highlights:
- Default Values: The class initializes certain fields with default values to ensure consistency and prevent null references.
-
Equality and Hashing: Overridden
equals
andhashCode
methods facilitate comparison and usage in collections, ensuring that twoPlayerConfig
instances can be accurately compared based on their state.
Purpose:
The PlayerConfigGenerator
is responsible for extracting the current state from the player's entity components and assembling a PlayerConfig
object that accurately reflects the player's status at the time of saving.
Functionality:
-
State Extraction: Retrieves data from various components attached to the player entity, such as
CombatStatsComponent
andInventoryComponent
. - Data Transformation: Converts complex data structures (e.g., collections of items) into serializable formats suitable for JSON representation.
- Error Handling: Ensures robustness by handling cases where certain components or data might be missing or null, preventing crashes and data corruption.
Implementation Steps:
- Retrieve Components: Accesses the necessary components from the player entity.
- Extract Data: Gathers current values for health, attack, items, and equipped weapons.
- Transform Items: Converts the list of collected items into a string array using a helper method.
- Handle Optional Weapons: Checks for the presence of equipped melee and ranged weapons and retrieves their specifications if available.
-
Assemble Config: Populates a new
PlayerConfig
instance with the extracted data.
Purpose:
SavePlayerService
orchestrates the saving process by utilising the PlayerConfigGenerator
to produce a PlayerConfig
object and then writing this configuration to a JSON file using the FileLoader
utility.
Functionality:
- Initiate Save Process: Provides a simple and straightforward method to trigger the save operation.
-
File Writing: Utilizes the
FileLoader
to serialize thePlayerConfig
object into a JSON format and save it to the specified directory. -
File Path Management: Determines and manages the file path where the player's state will be saved (
configs/player_save.json
).
Implementation Steps:
-
Generate Config: Calls
PlayerConfigGenerator.savePlayerState()
to obtain the current player state. -
Write to File: Uses
FileLoader.writeClass()
to serialize and write thePlayerConfig
to a JSON file. - Handle Exceptions: Includes necessary error handling to manage potential issues during the file writing process.
Implementing and utilizing the saving system in the game involves straightforward steps:
1. Saving the Player's State
To save the player's current state, instantiate the SavePlayerService
and call the savePlayerState
method, passing in the player entity.
Example:
// Assuming 'playerEntity' is your player's Entity instance
SavePlayerService saveService = new SavePlayerService();
saveService.savePlayerState(playerEntity);
This code will create or overwrite the player_save.json
file in the configs
directory with the current state of the player.
2. Loading the Player's State
While loading functionality is not covered in this task, a complementary service can be implemented to read the player_save.json
file and reconstruct the player's state by reversing the process.
Upon saving, the player_save.json
file will contain structured data representing the player's state. An example content of the JSON file might look like:
{
health: 60
name: default
items: [
item:medkit
item:medkit
]
speed: {
x: 3
y: 3
}
difficulty: EASY
maxHealth: 100
pets: []
coins: 55
melee: melee:knife
ranged: ranged:shotgun
textureFilename: images/player/player.png
textureAtlasFilename: images/player/player.atlas
}
(NOTE: as items and weapons are not fully implemented, this is based on initial assumptions formed from Collectible Interface)
This JSON structure is easy to read and parse, facilitating straightforward loading and debugging processes.
1. Modularity and Separation of Concerns
The saving system is designed with clear separation between data modeling (PlayerConfig
), data extraction (PlayerConfigGenerator
), and data persistence (SavePlayerService
). This modular approach enhances maintainability and scalability, allowing each component to be developed and tested independently.
2. Use of JSON for Serialization
JSON is chosen as the serialization format due to its readability, ease of use, and widespread support. It allows for straightforward mapping between Java objects and a text-based format, facilitating easy debugging and potential manual editing if necessary.
3. Handling Optional Data
The system accounts for scenarios where certain data might be absent. For example, if the player has not equipped a melee or ranged weapon, the corresponding fields are set to empty strings. This prevents null references and ensures the integrity of the saved data.
4. Extensibility
Additional player attributes can be easily incorporated into the PlayerConfig
structure as the game evolves. For example, attributes like player level, experience points, or quest progress can be added with minimal adjustments to the existing system.
5. Error Handling and Robustness
The implementation includes checks to handle cases where certain components might be missing from the player entity. This ensures that the save operation does not fail unexpectedly and provides default values where appropriate.
To ensure reliability, comprehensive testing was conducted:
- Unit Tests: JUnit4 testing was used to validate each component individually, ensuring correct data storage.
- Integration Tests: Testing of file writing was unable to be tested in sprint 1 as gds files are not configured properly in test environment and mock testing is not covered yet.
- Edge Cases: Test scenarios with missing data, empty inventories, and maximum capacity inventories were converted to ensure robustness.
To view the comprehensive test plan, please read: Test Plan for Saving Character
For more information and deeper understanding, consider exploring the following resources:
-
LibGDX File Handling:
-
Design Patterns:
The implemented saving system provides a reliable and efficient way to preserve and restore the player's state in the game. Its modular design and use of standard serialization practices ensure that it can be easily integrated and extended as the game develops further. Proper testing and documentation facilitate maintenance and future enhancements, contributing to a robust gaming experience for users.
Note: For implementation assistance or further inquiries, please reach out to @manya-k
Design Choices
Utilities
Animals
Menus/screens
Character
- Character Animations
- Character's Inventory On Display
- Character's Inventory System
- Character's HealthBar
- Character's Interaction with Items
- Character achievements
- Saving Character
- Player-(and-other-NPC)-invincibility-frames
- Player Factory
- Scoring System
- Test Plan for Inventory System
- Test Plan for Player's Interaction with Items
- Test Plan for Player's Inventory Display
- Test Plan for Saving Character State
- Test Plan for Scoring System
Map
Weapon
- Weapon Overview
- Weapon Types
- Weapon Structure
- Weapon Stats Display
- Testing Plan for Weapon Factory
- Testing Plan for Firing Controller Component
- Testing Plan for Position Tracker Component
- Testing Plan for Weapon Animation Controller component
- Testing Plan for Concrete Melee Weapon class
- Testing Plan for Concrete Ranged Weapon class