Ygg – Downtree Madness is a 3D Fun Racer developed in Unreal Engine 4 and programmed in C++. In the game you build your own soapboxes to engage in Physics-based races on one of five tracks set in the world of Nordic mythology. Only those who master the laws of physics can beat their friends and make it to the goal. Additionally, the game features five playable characters, including an unlockable one.
Ygg – Downtree Madness was my fourth and final project at Games Academy and my first game developed in Unreal Engine 4. The team decided to use the engine mainly for learning purposes. As with all new engines, there were a lot of technical difficulties and bugs to overcome, especially in the starting phase. I was responsible for implementing the core gameplay features and most of the workshop features. While the game was received quite well at both milestones, an overlooked bug in the final build overshadowed the game itself at Goldmaster. The bug was later fixed and the game was showcased at Gamescom 2014.
If there is one lesson we all learned from this project it’s not to start the debugging phase too late, especially when using a brand new engine.
The team:
Melli Gottschalk – Team Lead, Game Design, Art
Josua Hagedorn – Visionkeeper, Game Design, Programming, Audio
Daria Varfolomeeva – Game Design, Art
Eric Vetter – Art
Emily Schuhmann – Art
Stella Behrendt – Art
Michael Beck – Programming
Max Giller – Programming
Markus Wall – Programming
Gallery:
Code Snippet:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
///////////////////////////////////////// //Ygg - Downtree Madness - Code Snippet// ///////////////////////////////////////// // Serialize a complete vehicle into a FSerializedVehicle so it can be duplicated or saved to file void UVehicleSpawnerLibrary::SerializeVehicle(FSerializedVehicle& outSerializedVehicle, AVehicleBodyBase* vehicle) { if (vehicle == nullptr) return; // Get body class outSerializedVehicle.bodyClass = vehicle->GetClass(); UVehicleSpawnerLibrary::AddClassToRootList(outSerializedVehicle.bodyClass); FMatrix bodyMatrix = vehicle->Body->GetComponenTransform().ToMatrixNoScale(); for (TArray<AVehicleWheelBase*>::TIterator wheelIter(vehicle->attachedWheels); wheelIter; ++wheelIter) { // Get current wheel class and relative transform AVehicleWheelBase* currentWheel = *wheelIter; FMatrix wheelMatrix = currentWheel->WheelConstraint->GetComponenTransform().ToMatrixNoScale(); FMatrix relativeMatrix = wheelMatrix * bodyMatrix.InverseSafe(); outSerializedVehicle.wheelClasses.Add(FWheelClass(currentWheel->GetClass(), currentWheel->bIsSteerable, currentWheel->bHasBrake, relativeMatrix)); UVehicleSpawnerLibrary::AddClassToRootList(currentWheel->GetClass()); } for (TArray<AVehicleWeightBase*>::TIterator weightIter(vehicle->attachedWeights); weightIter; ++weightIter) { // Get current weight class and relative transform AVehicleWeightBase* currentWeight = *weightIter; FMatrix weightMatrix = currentWeight->PhysicsConstraint->GetComponenTransform().ToMatrixNoScale(); FMatrix relativeMatrix = weightMatrix * bodyMatrix.InverseSafe(); outSerializedVehicle.weightClasses.Add(FWeightClass(currentWeight->GetClass(), relativeMatrix)); UVehicleSpawnerLibrary::AddClassToRootList(currentWeight->GetClass()); } // Get steering class if (vehicle->attachedSteering != nullptr) { outSerializedVehicle.steeringClass = vehicle->attachedSteering->GetClass(); UVehicleSpawnerLibrary::AddClassToRootList(vehicle->attachedSteering->GetClass()); } // Get brake class if (vehicle->attachedBrake != nullptr) { outSerializedVehicle.brakeClass = vehicle->attachedBrake->GetClass(); UVehicleSpawnerLibrary::AddClassToRootList(vehicle->attachedBrake->GetClass()); } } //////////////////////////////////////////////////////////////////// // Spawn a vehicle from a FSerializedVehicle AVehicleBodyBase* UVehicleSpawnerLibrary::SpawnVehicle(UObject* WorldContextObject, const FSerializedVehicle& inSerializedVehicle, FVector spawnLocation, FRotator spawnRotation) { if (WorldContextObject == nullptr) return nullptr; UWorld* currentWorld = WorldContextObject->GetWorld(); if (inSerializedVehicle.bodyClass != nullptr) { FActorSpawnParameters spawnParameters; if (currentWorld) { // Spawn body actor AVehicleBodyBase* vehicleBody = (AVehicleBodyBase*)(currentWorld->SpawnActor(inSerializedVehicle.bodyClass, &spawnLocation, &spawnRotation, spawnParameters)); if (vehicleBody != nullptr) { FMatrix bodyMatrix = FRotationTranslationMatrix(spawnRotation, spawnLocation); for (TArray<FWheelClass>::TConstIterator wheelIter(inSerializedVehicle.wheelClasses); wheelIter; ++wheelIter) { // Get wheel world transform FWheelClass currentWheel = *wheelIter; FMatrix wheelMatrix = currentWheel.relativeWheelMatrix * bodyMatrix; FVector wheelSpawnPos = wheelMatrix.GetOrigin(); FRotator wheelSpawnRotation = wheelMatrix.Rotator(); // Spawn wheel actor AVehicleWheelBase* vehicleWheel = (AVehicleWheelBase*)(currentWorld->SpawnActor(currentWheel.classInstance, &wheelSpawnPos, &wheelSpawnRotation, spawnParameters)); if (currentWheel.isSteerable != 0) vehicleWheel->bIsSteerable = true; else vehicleWheel->bIsSteerable = false; if (currentWheel.hasBrake != 0) vehicleWheel->bHasBrake = true; else vehicleWheel->bHasBrake = false; vehicleBody->AttachWheel(vehicleWheel); } for (TArray<FWeightClass>::TConstIterator weightIter(inSerializedVehicle.weightClasses); weightIter; ++weightIter) { // Get weight world transform FWeightClass currentWeight = *weightIter; FMatrix weightMatrix = currentWeight.relativeWeightMatrix * bodyMatrix; FVector weightSpawnPos = weightMatrix.GetOrigin(); FRotator weightSpawnRotation = weightMatrix.Rotator(); // Spawn weight actor AVehicleWeightBase* vehicleWeight = (AVehicleWeightBase*)(currentWorld->SpawnActor(currentWeight.classInstance, &weightSpawnPos, &weightSpawnRotation, spawnParameters)); vehicleBody->AttachWeight(vehicleWeight); } // Spawn steering actor if (inSerializedVehicle.steeringClass != nullptr) { AVehicleSteeringBase* vehicleSteering = (AVehicleSteeringBase*)(currentWorld->SpawnActor(inSerializedVehicle.steeringClass, &spawnLocation, &spawnRotation, spawnParameters)); vehicleBody->AttachSteering(vehicleSteering); } // Spawn brake actor if (inSerializedVehicle.brakeClass != nullptr) { AVehicleBrakeBase* vehicleBrake = (AVehicleBrakeBase*)(currentWorld->SpawnActor(inSerializedVehicle.brakeClass, &spawnLocation, &spawnRotation, spawnParameters)); vehicleBody->AttachBrake(vehicleBrake); } return vehicleBody; } } } return nullptr; } |