Download

Unreal Tutorial: No power decrease?

I’m trying to follow the “3rd Person Power-Up Game with C++” tutorial (https://wiki.unrealengine.com/Videos/Player?series=PLZlv_N0_O1gYup-gvJtMsgJqnEB_dGiM4&video=FsKMVvtK5oA) and my character’s power is not decreasing, but I don’t know why. It was working before, but now I started my project and it became quite strange.

Symptoms: (Are the first 2 important at all?)
-When I started the project and pressed play, not the third person character came up, just a floating bodyless camera that bumps into walls.
-I changed the gamemode to GameMode_BP, changed the pawn to “ThirdPersonCharacter”, then the body came back without decreasing, same with “BatteryCollectorCharacter”.
-Then changed back the gamemode to the “BatteryCollectorGameMode”, now it works the same.
-The game mode should decrease the power. The Tick override should work. The casting should work. Then why it isn’t happening?

Here is the Tick function:



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

	//Check that we are using the battery collector character
	ABatteryCollectorCharacter* MyCharacter = Cast<ABatteryCollectorCharacter>(UGameplayStatics::GetPlayerPawn(this, 0));
	if (MyCharacter)
	{
		//If the character's power is greater than needed to win, set the game's state to Won
		if (MyCharacter->GetCurrentPower() > PowerToWin)
		{
			SetCurrentState(EBatteryPlayState::EWon);
		}

		//If the character's power is positive
		if (MyCharacter->GetCurrentPower() > 0)
		{
			//Decrease the character's power using the decay rate
			MyCharacter->UpdatePower(-DeltaTime*DecayRate*(MyCharacter->GetInitialPower()));
		}

		else
		{
			SetCurrentState(EBatteryPlayState::EGameOver);
		}
	}
}

The character still can collect the batteries, and the play state can change to “EWon”, so this must be working, but something happens between the 2 “if”?

Put



UE_LOG(LogClass, Warning, TEXT("msg x"));


on different lines and see the log in views->developer tools IIRC, to see the log.

My UpdatePower function looks like this with it:



void ABatteryCollectorCharacter::UpdatePower(float PowerChange)
{
	//Change power
	CurrentPower += PowerChange;

	//Change speed based on power
	GetCharacterMovement()->MaxWalkSpeed = BaseSpeed + SpeedFactor * CurrentPower;

	//Call visual effect
	PowerChangeEffect();

	UE_LOG(LogClass, Warning, TEXT("UpdatePower - done"));
}

And I get that “UpdatePower - done” after every Tick. I watch the powerlevel from the progressbar, the character speed, and the character’s color, and they all change when I collect a battery, but still no decrease.
DecayRate shouldn’t be a problem either, since it’s value is set in the GameMode’s contructor to 0.075f. (and it IS a float variable)

you can debug it and put a breakpoint there.

Or save and print the value of the operation

Maybe it always return the same value, so “no power decrease” even if it is called.

That will be for the UI… if your movement is decreasing at the end before die, and you are not seeing the update on the UI, maybe you havent setup correctly the UI event and update, so you dont see it.

Tried with this UE_LOG to localize why it doesn’t change. The reason: The DecayRate IS 0. But there is no reason to be that.

I have this contructor:



ABatteryCollectorGameMode::ABatteryCollectorGameMode()
{
	// set default pawn class to our Blueprinted character
	static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter"));
	if (PlayerPawnBPClass.Class != NULL)
	{
		DefaultPawnClass = PlayerPawnBPClass.Class;
	}


	UE_LOG(LogClass, Warning, TEXT("GameMode Contructor 1"));
	//Base decay rate
	DecayRate = 0.075f;
	UE_LOG(LogClass, Warning, TEXT("GameMode Contructor 2"));
}

And I get:
LogClass:Warning: GameMode Contructor 1: 0.000000
LogClass:Warning: GameMode Contructor 2: 0.075000, as it should be.
But it still becomes 0 in the Tick function. (“LogClass:Warning: UpdatePower DecayRate? 0.000000”
And idea why?

Btw thanks for the helpful fast replies!

The only way to know why it gets reset to 0 would be to searhc in all the project for the variable, and set breakpoints to see where it gets reset to cero.

To be able to catch breakpoints, you should attach vs to the UE4 process or, hit run from VS, this will launch another instance of the editor if you launched it from the epic launcher, ad it will break on the brakpoints you have setup.

Good idea, but sadly this is the only place where the DecayRate is used. It’s only purpose is to decrease the power.


Find all "DecayRate", Match case, Whole word, Subfolders, Find Results 1, Entire Solution, ""
  E:\Unreal\BatteryCollector\Source\BatteryCollector\BatteryCollectorGameMode.cpp(19):	UE_LOG(LogClass, Warning, TEXT("GameMode Contructor 1: %f"), DecayRate);
  E:\Unreal\BatteryCollector\Source\BatteryCollector\BatteryCollectorGameMode.cpp(21):	DecayRate = 0.075f;
  E:\Unreal\BatteryCollector\Source\BatteryCollector\BatteryCollectorGameMode.cpp(22):	UE_LOG(LogClass, Warning, TEXT("GameMode Contructor 2: %f"), DecayRate);
  E:\Unreal\BatteryCollector\Source\BatteryCollector\BatteryCollectorGameMode.cpp(59):			UE_LOG(LogClass, Warning, TEXT("UpdatePower DecayRate? %f"), DecayRate);
  E:\Unreal\BatteryCollector\Source\BatteryCollector\BatteryCollectorGameMode.cpp(60):			MyCharacter->UpdatePower(-DeltaTime*DecayRate*(MyCharacter->GetInitialPower()));
  E:\Unreal\BatteryCollector\Source\BatteryCollector\BatteryCollectorGameMode.h(43):	float DecayRate;
  Matching lines: 6    Matching files: 2    Total files searched: 12727

Might it be something like that the game uses a 2nd, unconstructed GameMode?

probably… in any case, for the moment, you can setup directly with a hardcoded constant or inside the update ask if the value is zero set it to the correct value xD… (and see if it doesnt get reset to zero each tick… which would be strange).

It could be a second game mode, dont know, but I guess if you print “this” and you get different hex values for the address, it could be a different game mode…

in any case here is my code for that tut game mode




#include "BatteryCollector.h"
#include "BatteryCollectorGameMode.h"
#include "BatteryCollectorCharacter.h"

#include "Kismet/GameplayStatics.h"
#include "Blueprint/UserWidget.h"
#include "SpawnVolume.h"

void ABatteryCollectorGameMode::PrepareSpawnVolumes()
{
    // find all spawn volume actors
    TArray<AActor*> FoundActors;
    UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASpawnVolume::StaticClass(), FoundActors);

    for (auto Actor : FoundActors)
    {
        ASpawnVolume* SpawnVolumeActor = Cast<ASpawnVolume>(Actor);
        if (SpawnVolumeActor)
        {
            SpawnVolumeActors.AddUnique(SpawnVolumeActor);
        }
    }
}

void ABatteryCollectorGameMode::BeginPlay()
{
    Super::BeginPlay();
    PrepareSpawnVolumes();
    SetCurrentState(EBatteryPlayState::EPlaying);

    // set the score to beat
    ABatteryCollectorCharacter* MyCharacter = Cast<ABatteryCollectorCharacter>(UGameplayStatics::GetPlayerPawn(this, 0));
    if (MyCharacter)
    {
        PowerToWin = (MyCharacter->GetInitialPower())*1.54f;
    }

    if (HUDWidgetClass != nullptr)
    {
        CurrentWidget = CreateWidget<UUserWidget>(GetWorld(), HUDWidgetClass);
        if (CurrentWidget != nullptr)
        {
            CurrentWidget->AddToViewport();
        }
    }

}

ABatteryCollectorGameMode::ABatteryCollectorGameMode()
{
    // set default pawn class to our Blueprinted character
    static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter"));
    if (PlayerPawnBPClass.Class != NULL)
    {
        DefaultPawnClass = PlayerPawnBPClass.Class;
    }

    // base decay rate
    DecayRate = 0.01f;
}

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

    ABatteryCollectorCharacter* MyCharacter = Cast<ABatteryCollectorCharacter>(UGameplayStatics::GetPlayerPawn(this, 0));

    if (MyCharacter)
    {
        if (MyCharacter->GetCurrentPower() > PowerToWin) {
            SetCurrentState(EBatteryPlayState::EWon);
        }
        if (MyCharacter->GetCurrentPower() > 0) {
            MyCharacter->UpdatePower(-DeltaTime*DecayRate*(MyCharacter->GetInitialPower()));
        }
        else {
            SetCurrentState(EBatteryPlayState::EGameOver);
        }
    }
}



float ABatteryCollectorGameMode::GetPowerToWin()
{
    return PowerToWin;
}


EBatteryPlayState ABatteryCollectorGameMode::GetCurrentState() const
{
    return CurrentState;
}

void ABatteryCollectorGameMode::SetCurrentState(EBatteryPlayState NewState)
{
    CurrentState = NewState;
    HandleNewState(CurrentState);
}

void ABatteryCollectorGameMode::HandleNewState(EBatteryPlayState NewState)
{
    UE_LOG(LogClass, Warning, TEXT("handling new state"));
    switch (NewState) {
    case EBatteryPlayState::EPlaying:
        UE_LOG(LogClass, Warning, TEXT("handling playing state!"));
        // spawn volumes active
        for (ASpawnVolume* Volume : SpawnVolumeActors)
        {
            Volume->SetSpawningActive(true);
        }
        break;
    case EBatteryPlayState::EWon:
        UE_LOG(LogClass, Warning, TEXT("handling won state!"));
        // spawn volumes inacive
        for (ASpawnVolume* Volume : SpawnVolumeActors)
        {
            Volume->SetSpawningActive(false);
        }
        break;
    case EBatteryPlayState::EGameOver:
    {
        UE_LOG(LogClass, Warning, TEXT("handling game over state!"));
        // spawn volumes inactive
        for (ASpawnVolume* Volume : SpawnVolumeActors)
        {
            Volume->SetSpawningActive(false);
        }
        // block player input
        APlayerController* PlayerController = UGameplayStatics::GetPlayerController(this, 0);
        if (PlayerController)
        {
            PlayerController->SetCinematicMode(true, false, true);
        }
        // ragdoll the character
        ACharacter* MyCharacter = Cast<ACharacter>(UGameplayStatics::GetPlayerCharacter(this, 0));
        if (MyCharacter)
        {
            MyCharacter->GetMesh()->SetSimulatePhysics(true);
            MyCharacter->GetMovementComponent()->MovementState.bCanJump = false;
        }
    }
        break;
    default:
    case EBatteryPlayState::EUnknow:
        UE_LOG(LogClass, Warning, TEXT("     game state is unknow!"));
        break;
    }
}

Oh, god. I found the problem, but still don’t know how it could have happened. There was a Blueprint made from the BatteryCollectorGameMode, called GameMode_BP, and this was used. And in Its blueprint was the DecayRate set to 0 manually. Goddamit… So I put it back to Default Value, now it works as it should. Thank you for your patience, and I can’t belive how dumb problem it was…:mad:

Well, Im still not found on the make logic in C and assign values i BP xD… so… it passed my head a couple of times, but I didnt take the hint… xD GL && HF.