TKGame Jam 2016 – Grand Theft Taxi

I’m after TKGameJam 2016 and I have another proof that you can do a lot in Unreal Engine 4 in small amount of time.  Game was created by me, @smallshake and @ogniok with special thanks to @politko! We haven’t had any graphics artist in the team.

Dive into madness in this fast paced taxi simulator. You have ten seconds to get your clients to the destination or else they won’t pay you!

12719290_1150169308341291_8542629117904010224_o 12747539_1150169248341297_2545138683569032275_o 12771499_1150169445007944_7563220202408499445_o

Game can be downloaded at GameJolt.

I would like to show you guys couple of pipeline decisions we did. Maybe it will be helpful for you.

Graphics / Rendering

We haven’t had any graphics artist in the team so we decided to go with simple box graphics which can be easily manipulated in Maya. Basically the game have only one material with base color as parameter. Always create master materials as you can do global changes without need to click on each material. Thanks to really basic shader we avoided lightmaps which can be pain during jams as they are calculating some time. To reduce static shader cost you can disable Static Lighting in Project Settings.

Static shadows was emulated as post process AO.

ShadowsUsingPPAO

With PP AO

ShadowsWithoutAO

Without PP AO

Rest of the shadowing comes from one Directional Light. Only Directional Light cause shadows.

Another advantage of fully dynamic lighting was day/night manipulation.

It was super easy with Blueprints. It was only one Timeline

daynight

Driving all of the data:

  • Directional Light Rotation,
  • Light intensity (to drive Sky Light and Directional Light intensity),
  • Fog Intensity,
  • Sun Rotation for AtmosphericFog which have different rotations than Directional Light,
  • Sun Colors which is changing Sky Light and Directional Light colors,

Easy as that. It was separated Blueprint so it could be added to any level. (eg. main menu)

To avoid over burned lighting we have added simple cube map to Sky Light.

WithoutCubeMap

Without Cube Map

CubeMap

With Cube Map

Cube maps was updated with day/night cycle as well.

To avoid light overhead AI car lights was added as particle system which is super fast.

carlights

Lamps lights can be created exactly like this. Only player car need to have spot light.

Level Design

We knew that we would need to create really big map and we haven’t any level designer. Thanks to UE4 tools we have scaled down the work needed.

Props / Buildings randomly chosen:

Small districts as blueprints as well:

To do such thing you need to make sure your props/roads/buildings are using the same grid. Thanks to that we were able to create whole level in couple of hours. Another thing is that each gameplay element was added to those Blueprints as well. (roads, lamps, target points etc) so we haven’t “hard placed” anything in the level. It was easy to iterate later on.

Physics

We wanted to create something more casual/arcade than default UE4 car physics so we have taken simple 2d physics described here (java script implementation here) and implement it quickly in Blueprints (yes, blueprints as it was faster to just check how it will work)

When implementing your own physics you need to make sure it’s updating with UE4 physics. We have added FloatingPawnMovement component and update theirs physics state depending on the custom 2d state. For movement we have used FloatingPawnMovement.MoveUpdatedComponent() with Sweep option to check if we are colliding with something. Easy as that!

To have more arcade movement:

  • “smooth steering” and “safe steering” was ignored as we wanted to have more arcade movement,
  • max steer was changed depending on the car speed, player need to have more control in slower speed,
  • we haven’t used hand break instead we used opposite velocity,

As you can see you can implement your own car physics using Blueprints in no time!

City Simulation

We want to have a feeling that the City is alive and we only had 48 hours to do so.

Again we used Unreal Engine 4 tools to make living city. Whole car / human movement was done using Splines. It isn’t using our player car physics. Instead we implemented simple driving model calculating acceleration, deacceleration, maximum speed and driver reaction time. We wanted to have some variation in AI cars.

Cars are always checking if they will collide with something so they can drive through crossings as well.

Here’s car Tick you can follow:

void AAICar::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);

UpdateMovement(DeltaTime);
UpdateLocation(DeltaTime);
UpdateVelocity(DeltaTime);
UpdateForwardCollision();
UpdateFailure(DeltaTime);
}
void AAICar::UpdateMovement(float DeltaTime)
{
if (!FollowedPath)
{
return;
}

float ActualAcceleration = Acceleration;

// If we need to deaccelerate
if (HasForwardCollision)
{
ActualAcceleration = -ActualAcceleration * DeaccelerationFactor;
}

//Update speed
Speed = FMath::Clamp(Speed + ActualAcceleration * DeltaTime, 0.0f, MaxSpeed);

//Update position
SplinePosition += Speed * DeltaTime;

if (SplinePosition -> FollowedPath->GetSpline()->GetSplineLength())
{
SplinePosition -= FollowedPath->GetSpline()->GetSplineLength();
}
}
void AAICar::UpdateLocation(float DeltaTime)
{
if (!FollowedPath)
{
return;
}

SetActorLocation(FollowedPath->GetSpline()->GetWorldLocationAtDistanceAlongSpline(SplinePosition), true);
SetActorRotation(FMath::RInterpConstantTo(GetActorRotation(), SimulatedVelocity.Rotation(), DeltaTime, GetLifeTime() -> 1.0f ? RotationInterpSpeed : 360.0f));
}
void AAICar::UpdateVelocity(float DeltaTime)
{
const FVector ActorLocation = GetActorLocation();

if (ActorLocation != PreviousPosition)
{
SimulatedVelocity = (ActorLocation - PreviousPosition) / DeltaTime;
PreviousPosition = ActorLocation;
}
}
void AAICar::UpdateForwardCollision()
{
const float BaseTraceLength = 500.0f;
FVector ActorLocation = GetActorLocation() + FVector(0.0f, 0.0f, ForwardCollisionTraceUpOffset);

FHitResult Hit;
FCollisionObjectQueryParams CollisionObjectQueryParams(ECC_TO_BITFIELD(ECC_WorldStatic) | ECC_TO_BITFIELD(ECC_WorldDynamic) | ECC_TO_BITFIELD(ECC_Vehicle));
FCollisionQueryParams CollisionQueryParams(TEXT("AAICar::UpdateForwardCollision"), false, this);

CollisionQueryParams.AddIgnoredActor(IgnoredActor);

HasForwardCollision = GetWorld()->LineTraceSingleByObjectType(Hit, ActorLocation, ActorLocation + GetActorForwardVector() * BaseTraceLength * TraceLengthFactor, CollisionObjectQueryParams, CollisionQueryParams);

if (HasForwardCollision && Hit.GetActor() && Hit.GetActor()->ActorHasTag("IgnoreAICar"))
{
HasForwardCollision = false;
}

#ifdef DM_DRAW_TRACES
DrawDebugLine(GetWorld(), ActorLocation, ActorLocation + GetActorForwardVector() * BaseTraceLength * TraceLengthFactor, HasForwardCollision ? FColor::Red : FColor::Green, false, -1.0f, 0, 5.0f);
#endif
}

To be sure cars won’t stuck we are resetting whole thing when player is outside the view.

Humans was created with less movement detail but the same way – using splines. We have added some noise to spline movement so each human is moving different than other. Also he is checking if car is near, if yes – try to run 🙂 When hit just enable ragdoll. Simple as that. As for optimisation humans tick 2-3 per frame when not in viewport.

And basically that’s it.

Game scope was big but when using Unreal Engine 4 tooset we were able to create such game in 48 hours.

4 thoughts on “TKGame Jam 2016 – Grand Theft Taxi

Leave a Reply