Creating the interactions between the world objects

Finally, we have created the game world for BountyDash! Now, it is time to make it all interact with one another. We have already done this somewhat by having the coin adjust height when it is spawned on top of an obstacle object. We must scrutinize how we are going to interact with the player when it runs into the objects around him. First, let's detail how the player is going to be colliding with the obstacles.

Pushing the Character

When the player runs into a rock, we want the player avatar to be pushed back into the game world down the x-axis. This will be quite simple to implement; we can introduce the same offset backwards to the player that we do for all the other objects if he is currently colliding with a rock obstacle! This is very easily done. Navigate to the BountyDashCharacter.cpp in code; we are going to be defining the collision function.

ABountyDashCharacter Collision functions

The first collision function we will be defining is MyOnComponentOverlap(). The purpose of this function is to detect if the player has collided with an obstacle from a reasonably head on approach. We do this so that when the player is skipping between lanes there is a margin of allowance for moving over the back of an obstacle. If so, we are going to be enacting on the collision. Add the following code to ABountyDashCharacter::myOnComponentOverlap:

if (OtherActor->GetClass()->IsChildOf(AObstacle::StaticClass()))
{
FVector vecBetween = OtherActor->GetActorLocation() - GetActorLocation();

float AngleBetween = FMath::Acos(FVector::DotProduct(vecBetween.GetSafeNormal(), GetActorForwardVector().GetSafeNormal()));

    AngleBetween *= (180 / PI);

    if (AngleBetween < 60.0f)
    {
        bBeingPushed = true;
    }
}

We check that the offending actor is either of type AObstacle or a child of the class. If so, we get a vector between the character and the obstacle. We determine if the character is heading toward the obstacle within a margin by checking the angle between the direction of the vector between the two objects and the forward vector of the character. We do this by obtaining a dot product between the two vectors via the FVector::DotProduct function.

We then plug the result of this calculation into FMath::Acos. We do this as the dot product will return a ratio value that when parsed through an arccos function will return the angle between the two vectors in radians. To change this value to degrees, we multiply it by (180 / PI) as PI radians = 180 degrees. If the angle between vectors is less than 60.0f, we can assume that the collision is fairly direct, so we then inform the character of a collision with the obstacle by setting the bBeingPushed Boolean to true. As we just referenced the AObstacle type, ensure you add #include "Obstacle.h" to the include list of this .cpp.

Next, we define the MyOnActorEndOverlap() function. This one is much less complicated, we will simply check that the leaving actor is of type AObstacle; and if so, we will enact on the end of the overlap, add the following code to ABountyDashCharacter::myOnComponentEndOverlap:

if (OtherActor->GetClass()->IsChildOf(AObstacle::StaticClass() ))
{
bBeingPushed = false; 
}

As you can see, we set the bBeingPushed value to false when the obstacle leaves the bounds of the character f capsule component collider. Now, we must add some code to the Tick() function to ensure the character's position updates when he is being pushed by an obstacle.

Pushing the character back

In ABountyDashCharacter::Tick(), we are going to be checking if the bBeingPushed value is set to true; if so, we will be offsetting the character's location down the x-axis at the same speed as the obstacles. Add the following code to ABountyDashCharacter::Tick():

if (bBeingPushed)
{
    float moveSpeed = GetCustomGameMode<ABountyDashGameMode> (GetWorld())->GetInvGameSpeed();
    AddActorLocalOffset(FVector(moveSpeed, 0.0f, 0.0f));
}

As you can see, if the character is currently being pushed we will add an offset to the character's position down the x-axis. The effect this will create is the player will feel as though the character has stopped moving! The idea is to then convince that a wall of death has caught up with them and it is game over. But, we will be programming the wall of invisible death in the next chapter.

Picking up coins

The next thing we have to implement is the collecting of coins! The collision functionality for this is much simpler than that defined for the obstacle collision. We will simply detect if the player has overlapped with a coin. If so, we will inform the player to score up. We will also have to properly define that function, so the player score increases and the game mode is informed of the new score!

Coin collision

Let's start with the coin collision functionality. Add the following code to ACoin::MyOnActorOverlap() found in Coin.cpp:

if (otherActor->GetClass()->IsChildOf(ABountyDashCharacter::StaticClass()))
{
ABountyDashCharacter* myChar = Cast<ABountyDashCharacter>(otherActor);

myChar->ScoreUp();

GetWorld()->DestroyActor(this);
}

We are simply going to check if the offending actor is of type ABountyDashCharacter. If so, we are going to inform the character to score up. We then inform the game world to destroy the coin actor. Next, we have to define the functionality for ABountyDashCharacter::ScoreUp(). The purpose of this function is to increment the player's internal score count as well as informing the Game Mode of that increment. Add the following to code to ABountyDashCharacter::ScoreUp():

Score++;
GetCustomGameMode<ABountyDashGameMode>(GetWorld())->CharScoreUp(Score);

This will increment the score then inform the game mode to score up thus invoking the functionality we previously implemented.

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

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