Saving or loading games and keyboard input with C++

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.

Getting ready

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.

How to do it…

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:

  1. Navigate to File | New C++ Class, and you should see the Choose Parent Class window pop up. Check the Show All Classes option, select SaveGame, and click on Next.
    How to do it…
  2. Next, it'll ask you for the name of your save class. In this instance, I'm going to leave it as MySaveGame and click on Create Class and wait for it to finish compiling.
  3. In the header file for the object, we'll need to add any variables that we want to save. In this case, I want to save my player's position and rotation, so I'm going to do the following:
    #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.

  4. We aren't doing anything special inside the .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
  5. Next, we need to implement the functionality in the 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.

  6. After that we need to enable the ability for the 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
  7. Now we can implement the 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.

  8. After that, let's implement the function that will save the game:
    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!");
      }
    }
  9. Finally, we need to implement the way to load the game:
    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!");
      }
    }
  10. With all that done, save all of the files, go back into the Unreal Editor and then hit the Compile button.
  11. Once the compilation finishes, start up the game by using the Play button.
    How to do it…

    Starting the game with Play button

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!

Note

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.3.154