Ideating and Initializing the Jam
The introduction of the industry brief was a welcomed surprise to begin the unit. Especially when it came to who was in collaboration (Frontier) and the type of game we would be making. A management sim, with the theme of making the mundane exciting. This immediately jumped out to me for a bit of interesting programming exercises and problems I haven’t encountered in a long while.
I knew that whatever we made, in the brief of management sim, would be data-driven and programmatically heavy in terms of a gameplay loop. Meaning, the gameplay would be enhanced and influenced by the underlying data that the player was tracking, controlling, or working towards.
My first instinct was to dive into some of the games that Frontier makes, especially their larger, more bread and butter type experiences that they are known for. Especially Planet Coaster and Planet Zoo. They offer an immense amount of player customization and their data-driven systems are deep enough for a player with many hours to feel satisfied and engaged for long periods of time. Of course, this 2 week jam would not afford that sort of depth, but the underlying principle of data-driven elements could absolutely be achieved in a short amount of time, if the gameplay loop was engaging enough for the Player to want to proceed.
Our initial team meetings were successful in that most people seemed eager and ready to work. We went over specialties and what everyone was wanting to get out of this experience. I was a little taken aback when finding out I would be the only programmer on the game, with the others indies wanting to focus on art direction and UI design. For a systems heavy game, I knew I would have to tone down what was manageable (pun intended) for this type of game with myself being the only one working on those systems. I was also working under the time constraint of having to fly back home 2 days before the brief ended, so this game had to be done the Wednesday before the brief was due.
With all of that in mind, we settled on a theme (Laundromat manager) and a simple gameplay loop to get started. There was a lot to do, so I tried to parse out my own work in three main areas to tackle:
- ShopManager – The data driven element that the player would track that would handle the shop (Laundromat) Economy and the shop’s Reputation.
- This limitation of two main structures of data kept the scope manageble, but still interesting in terms of how the gameplay would effect both at the same time, and influence the player to balance between the two.
- Gameplay Loop – With the player mainly balancing their time between a Day and Night cycle, they would be washing laundry and fixing broken machines in the day, and purchasing / upgrading store elements in the evening.
- A simple push / pull methodology for gameplay. Make money in the day, spend that money in the evening. Both influencing one another.
- Tools for the design team
- I knew this was a massively important thing to focus on. Being the only developer means that I probably wouldn’t have a ton of time to focus on things like set-dressing and other design work, so I had to make the things I made in the backend, easy and understandable to implement for the front-end users (Asset production, UI designers and Level Designers of the team).
- Off-loading some of this work to them was mutually beneficial in that I could focus on the dev side of things and create a better practice and workflow for myself to enhance my tools skills
Beginning Dev Cycle
Shop Manager Class
The thing I focused on first was how our data-driven elements would interact with the game, as well as what would be possible to really refine in just a week and a half. These elements would have to be tested and I wanted to give us enough time to do so.
One element I dove deep on in the first day was how / what was the best way to store / manage dynamic data elements in Unreal Engine. Something like a data table is perfect for storing and pulling from a large and diverse set of data, but writing to it would be inefficient and otherwise clunky. A data asset (an unreal specific storage of generic data elements) is a very lightweight and custom data element that I really enjoy using for other gameplay experiences, but has a similar issue to data tables when it comes to making more dynamic, written data elements during runtime. In my messing around and experimenting I ran across an Info Actor. It is a base Actor class with literally nothing in it except a empty scene Component. It has no transform and no collision, put simply it is an empty actor in the world meant to store things. Perfect. This meant because it was empty, I could attach any custom data structure I write in C++ to this empty actor to essentially just be a bucket for me to pull from and change whenever I wanted to during runtime. Those custom structures had three main elements. Economy: Cash, the tracked upgrade states of each machine in world, Utilities cost (using machine data), and a Rent variable. Reputation: Tracked Reputation state of the store, Cleanliness, Decor, and overall reputation score to set the state. The third element was the tracked Game states of the shop using all of the data from the custom data structures. This empty actor would live in the world and have helper functions for other actors to interact with it whenever they needed to i.e., rewarded for washing clothes, upgrading a machine, buying a new machine, etc.
// Machine Upgrade states
UENUM(BlueprintType)
enum class EMachineUpgrade : uint8
{
NONE = 0 UMETA(Hidden),
SMALL = 1 UMETA(DisplayName = "Small"),
MEDIUM = 2 UMETA(DisplayName = "Medium"),
LARGE = 3 UMETA(DisplayName = "Large"),
};
// Enum State tracker to influence UI Reviews and Store efficiency/Cleanliness
UENUM(BlueprintType)
enum class EReputationState : uint8
{
NONE = 0 UMETA(Hidden),
NEGATIVE = 1 UMETA(DisplayName = "Negative"),
NEUTRAL = 2 UMETA(DisplayName = "Neutral"),
POSITIVE = 3 UMETA(DisplayName = "Positive"),
EXCELLENT = 4 UMETA(DisplayName = "Excellent"),
};
// Economy will track cash flow in and out
USTRUCT(BlueprintType)
struct FShopEconomy
{
GENERATED_USTRUCT_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Economy")
float Cash;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Economy|Utilities")
TArray<EMachineUpgrade> CurrentMachines;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Economy|Utilities")
float UtilitiesCost;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Economy|Rent")
float Rent;
// Default Values to initiate Store
void init()
{
Cash = 100.f;
UtilitiesCost = 10.f;
Rent = 10.f;
}
};
// Store Reputation influenced by Player's actions in the game
// TODO -- Might have to add an efficiency Variable here
USTRUCT(BlueprintType)
struct FShopReputation
{
GENERATED_USTRUCT_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Reputation")
EReputationState RepState;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Reputation|Variables")
uint8 Cleanliness;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Reputation|Variables")
uint8 Decor;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Reputation")
int32 Reputation;
// Default Values to initiate Store
void init()
{
RepState = EReputationState::NEUTRAL;
Cleanliness = 5;
Decor = 0;
Reputation = (Cleanliness + Decor) * static_cast<int32>(RepState);
}
};
/**
*
*/
UCLASS()
class FRONTIERJAM_API AShopManager : public AInfo
{
GENERATED_BODY()
public:
AShopManager();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Shop")
FShopEconomy Economy;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Shop")
FShopReputation Reputation;
UFUNCTION(BlueprintCallable)
void BuyItem(float cost);
UFUNCTION()
void UpdateUtilitiesCost(EMachineUpgrade MachineState);
UFUNCTION()
void UpdateCleanliness(int8 update);
UFUNCTION()
void UpdateReputation();
};
With this Info actor, I now have a lightweight data asset that I can change during runtime, that is accessible by anything in the world that needs to have access to it.
Initial Dev work
With the core of how data is being handled, I could look ahead to creating the objects in the world that the player would be interacting with. All of these objects would have a purpose and influence in how they effected the ShopManager. My next DevLog will look more into how that interaction is handled, as well as the tools made for the level designer to implement those items in the world without the need of Dev looking over their shoulder…