Flipper The System
Game Project
Description
This is a local multiplayer game in cooperation with the Catholic University of Leuven (KU Leuven), and to be presented to several other universities worldwide, aimed to raise awareness and educate students about the environment, climate change, and more specifically ocean pollution.
You and your three companions are sent to stop the pollution that is ruining the surrounding oceans of the beloved protagonist of the game: “Flipper the Dolphin”. The players will move together as a group along a predetermined path encountering conflicts along the way they will need to solve together through communication in the real world. They each have a set amount of resources that contribute to solving a conflict, but in order to do so, they have to work together.
The players come to face the choice of altruism versus selfishness. Do I benefit the group for the greater good and give them my resources, or do I keep them to myself? Each player has an individual goal to win by being the one with the most unique resources at the end of the game. Does that truly make you a winner though?
My Contributions
- Camera Functionality (custom cinematics, players)
- Conflict/Event Solving (resource management)
- Dialog AI (Unreal Behaviour Trees)
- UI (conflict interface, pollution meter, HUD)
- Real-Time CSV Data Reading
- CPU/GPU Profiling & Optimizations (lower end devices)
The Team
Artist – David Våson
Artist – Mathias Bultynck
Artist – Killian Vermeer
Programmer – Jarne Peire
Programmer – Steve Verhoeven
Programmer – Kobe De Backer
Code Snippets
//Early out
if (CinematicTime > TimeToCinematic)
{
bCanTrack = false;
}
if (!bCanTrack)
{
return;
}
// Add time to use as alpha value later
CinematicTime += DeltaTime;
// We need to determine the position along the spline to move our camera to
const float splineLength = pSplinePath->GetSplineLength();
const float distanceAlongSpline = (CinematicTime / TimeToCinematic) * splineLength;
const FVector locationAlongSpline = pSplinePath->GetLocationAtDistanceAlongSpline(distanceAlongSpline, ESplineCoordinateSpace::World);
// Determine direction from spline point to target point
const FVector targetWorldPos = pTargetPoint->GetRootComponent()->GetComponentLocation();
const FRotator desiredRelativeRot = UKismetMathLibrary::FindLookAtRotation(locationAlongSpline, targetWorldPos);
// Move camera
const FVector delta = locationAlongSpline - pCinematicCamera->GetComponentLocation();
pCinematicCamera->MoveComponent(delta, desiredRelativeRot, false); bool ACSVReader::ReadPlayerCSVFile(const FString& filename, TArray<FPlayerInfo>& outPlayerInfos)
{
//Get file
FString input{};
if (!GetFStringFromFile(filename, input))
{
return false;
}
//Get all data rows
FJsonSerializableArray dataRows = GetRowsFromFStringFile(input);
for (int i = 0; i < dataRows.Num(); ++i)
{
//Skip first row (is to indicate titles of values)
if (i == 0)
{
continue;
}
//Get all values from row into an array
FJsonSerializableArray outValues{};
FString delim = ",";
dataRows[i].ParseIntoArray(outValues, delim.GetCharArray().GetData());
//Parse info to player info
FPlayerInfo playerInfo{};
//The CSV is formatted as following:
// Idx 0 = ID
playerInfo.Role = (ERoleType)FCString::Atoi(outValues[0].GetCharArray().GetData());
// Idx 1 = Name
playerInfo.CharacterName = outValues[1];
// Idx 2-5 = Resource Values
if (!outValues[2].IsNumeric())
return false;
playerInfo.StartResources.SocialCapital = FCString::Atoi(outValues[2].GetCharArray().GetData());
if (!outValues[3].IsNumeric())
return false;
playerInfo.StartResources.Food = FCString::Atoi(outValues[3].GetCharArray().GetData());
if (!outValues[4].IsNumeric())
return false;
playerInfo.StartResources.Power = FCString::Atoi(outValues[4].GetCharArray().GetData());
if (!outValues[5].TrimEnd().IsNumeric())
return false;
playerInfo.StartResources.Money = FCString::Atoi(outValues[5].GetCharArray().GetData());
//Add conflict to array
outPlayerInfos.Add(playerInfo);
}
//Return successfull reading
return true;
} bool ACSVReader::GetFStringFromFile(const FString& filename, FString& input)
{
//Create directory
FString contentDir = FPaths::ProjectContentDir();
FString fileDir = contentDir + "GameData/" + filename;
//Read file
if (!FPaths::FileExists(fileDir))
{
return false;
}
FFileHelper::LoadFileToString(input, fileDir.GetCharArray().GetData());
return true;
}
FJsonSerializableArray ACSVReader::GetRowsFromFStringFile(const FString& stringFile)
{
//Parse file
FJsonSerializableArray rows{};
FString returnChar = "\n";
stringFile.ParseIntoArray(rows, returnChar.GetCharArray().GetData());
return rows;
}