As games get more and more complex and longer and longer, players will often need to play a game within multiple sessions. However, by default, players will need to start over from scratch. In this recipe, we will be going over how to save a variable and load it at runtime.
Before we start working on this, we need to have a project created and set up. Follow the Setting up your development environment recipe all the way to completion.
To give you an idea of how it works, let's do a simple example of saving a player's position and rotation, which we can return to using keyboard input:
MySaveGame
and click on Create Class and wait for it to finish compiling.#pragma once #include "GameFramework/SaveGame.h" #include "MySaveGame.generated.h" /** * */ UCLASS() class COOKBOOK_CHAPTER9_API UMySaveGame : public USaveGame { GENERATED_BODY() public: UPROPERTY(VisibleAnywhere, Category = Basic) FVector PlayerPosition; UPROPERTY(VisibleAnywhere, Category = Basic) FRotator PlayerRotation; };
The PlayerPosition
variable is of type FVector
, more commonly referred to as a vector. A
vector is a series of three values, X, Y, and Z, which we've been using already for every object's position, and scaled in the appropriate axis. The rotation of an object is stored in a special type called FRotator
.
.cpp
file, but that would be where we would have set any default values. Instead, open up the Cookbook_Chapter9Character.h
file. Under the public
section of the class, add in the following bolded code:// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. #pragma once #include "GameFramework/Character.h" #include "Cookbook_Chapter9Character.generated.h" UCLASS(config=Game) class ACookbook_Chapter9Character : public ACharacter { GENERATED_BODY() /** Camera boom positioning the camera behind the character */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true")) class USpringArmComponent* CameraBoom; /** Follow camera */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true")) class UCameraComponent* FollowCamera; public: ACookbook_Chapter9Character(); /** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera) float BaseTurnRate; /** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera) float BaseLookUpRate; // Saves the game void SaveMyGameFile(); // Loads the game void LoadMyGameFile(); // Called every frame void Tick(float DeltaTime); protected: /** Called for forwards/backward input */ void MoveForward(float Value); // Other declarations below
MySaveGame.cpp
file. At the top, we need to add in some includes, so below the others, add the following:#include "MySaveGame.h" #include "Kismet/GameplayStatics.h" #include "Engine.h" //GEngine
This will allow us to use the MySaveGame
class and GEngine
inside of the file.
Tick
function to be called. To do this, go to the constructor of the Character
class (ACookbook_Chapter9Character
) and add the following bold line:ACookbook_Chapter9Character::ACookbook_Chapter9Character() { PrimaryActorTick.bCanEverTick = true; // Set size for collision capsule GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f); // Other code below
Tick
function:void ACookbook_Chapter9Character::Tick(float DeltaTime) { APlayerController * PController = Cast<APlayerController>(Controller); // Any time we cast, we need to check if the variable is valid if (PController != NULL) { // If Q is pressed, save the game if (PController->WasInputKeyJustPressed(EKeys::Q)) { SaveMyGameFile(); } // Otherwise, if E is pressed we will load else if (PController->WasInputKeyJustPressed(EKeys::E)) { LoadMyGameFile(); } } }
The Tick
function is called in every frame in the game (at 60 FPS, the game is running 60 frames per second), so it'll happen quite often, which is important when it comes to checking input. If the player presses the Q or E key, we will call the Save
and/or Load
functions, respectively.
void ACookbook_Chapter9Character::SaveMyGameFile() { // Create a save object for us to store values UMySaveGame* SaveGameInstance = Cast<UMySaveGame>(UGameplayStatics::CreateSaveGameObject(UMySaveGame::StaticClass())); // Set the player's current location and rotation SaveGameInstance->PlayerPosition = GetActorLocation(); SaveGameInstance->PlayerRotation = GetActorRotation(); //Saves the new save file into the first save slot (0) with // a name of "SaveSlot" UGameplayStatics::SaveGameToSlot(SaveGameInstance, "SaveSlot", 0); if (GEngine) { // Notify the player that we saved GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Yellow, "Game Saved!"); } }
void ACookbook_Chapter9Character::LoadMyGameFile() { // Create a save object for us to store values to load UMySaveGame* LoadGameInstance = Cast<UMySaveGame>(UGameplayStatics::CreateSaveGameObject(UMySaveGame::StaticClass())); // Loads the save slot we created previously LoadGameInstance = Cast<UMySaveGame>(UGameplayStatics::LoadGameFromSlot("SaveSlot", 0)); //Set the player's location and rotation to what we saved SetActorLocationAndRotation(LoadGameInstance->PlayerPosition, LoadGameInstance->PlayerRotation); if (GEngine) { // Notify the player that we loaded GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Yellow, "Loaded!"); } }
Now, whenever you press the Q button, your position and rotation will be saved and if you walk around and then hit the E key, you'll be brought exactly to where you last left it!
If you're interested in taking this to the next level, there is a tutorial on how to do file management, being able to create and modify files on the player's hard drive at https://wiki.unrealengine.com/File_Management,_Create_Folders,_Delete_Files,_and_More.
3.15.3.154