Hi. I have a problem. I was working on my silly little overwatch-like project and sudenlly my character is not walking nor falling. However I can look around, shoot etc. That’s why I think it have something to do with Character Movement Component.
I did some tests.
My ABomberCharacter class inherits from APlayerCharacter. When I Play as Blueprint based on APlayerCharacter everything works fine, problem is only when I use blueprint based on ABomberCharacter.
Input works correctly, When I print AxisValue I can see -1, 0, 1, while trying to move.
Also when I use AddActorLocalOffset() it works fine.
PlayerCharacter.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "PlayerCharacter.generated.h"
UCLASS()
class FPSPROTOTYPE_API APlayerCharacter : public ACharacter
{
GENERATED_BODY()
public:
APlayerCharacter();
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
UPROPERTY(EditAnywhere, meta = (AllowPrivateAccess = "true"))
class UCameraComponent* Camera;
UPROPERTY(EditAnywhere, meta = (AllowPrivateAccess = "true"))
class USkeletalMeshComponent* WeaponMesh;
UPROPERTY(EditAnywhere, meta = (AllowPrivateAccess = "true"))
USceneComponent* ProjectileSpawnPoint;
USkeletalMeshComponent* GetWeapon();
void MoveForward(float AxisValue);
void MoveRight(float AxisValue);
void LookUp(float AxisValue);
void LookRight(float AxisValue);
virtual void MainAttack();
virtual void FirstAbility();
virtual void SecondAbility();
virtual void UltimateAbility();
virtual void CustomAction();
virtual void Jump() override;
UPROPERTY(VisibleAnywhere, meta = (AllowPrivateAccess = "true"))
class UHealthComponent* HealthComp;
//Cooldown
UPROPERTY(EditDefaultsOnly, Category="Combat|Cooldown")
float MainAttackCooldownTime = 0;
UPROPERTY(EditDefaultsOnly, Category="Combat|Cooldown")
float FirstAbilityCooldownTime = 0;
UPROPERTY(EditDefaultsOnly, Category="Combat|Cooldown")
float SecondAbilityCooldownTime = 0;
UPROPERTY(EditDefaultsOnly, Category="Combat|Cooldown")
float UltimateAbilityCooldownTime = 0;
bool IsMACooled = true;
bool IsFACooled = true;
bool IsSACooled = true;
bool IsUACooled = true;
void MACooldown();
void FACooldown();
void SACooldown();
void UACooldown();
FTimerHandle MATimerHandle;
FTimerHandle FATimerHandle;
FTimerHandle SATimerHandle;
FTimerHandle UATimerHandle;
UFUNCTION(BlueprintPure)
float GetMACT();
UFUNCTION(BlueprintPure)
float GetFACT();
UFUNCTION(BlueprintPure)
float GetSACT();
UFUNCTION(BlueprintPure)
float GetUACT();
UPROPERTY(EditDefaultsOnly, Category="Combat|Cooldown", meta=(AllowPrivateAccess = "true"))
USoundBase* CooldownSound;
void AbilityFailed();
};
PlayerCharacter.cpp
#include "PlayerCharacter.h"
#include "Camera/CameraComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "HealthComponent.h"
#include "Kismet/GameplayStatics.h"
#include "GameFramework/CharacterMovementComponent.h"
// Sets default values
APlayerCharacter::APlayerCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
Camera->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
WeaponMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("WeaponMesh"));
WeaponMesh->AttachToComponent(Camera, FAttachmentTransformRules::KeepRelativeTransform);
ProjectileSpawnPoint = CreateDefaultSubobject<USceneComponent>(TEXT("ProjectileSpawnPoint"));
ProjectileSpawnPoint->AttachToComponent(WeaponMesh, FAttachmentTransformRules::KeepRelativeTransform);
HealthComp = CreateDefaultSubobject<UHealthComponent>(TEXT("HealthComp"));
}
// Called when the game starts or when spawned
void APlayerCharacter::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void APlayerCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAxis(TEXT("MoveForward"), this, &APlayerCharacter::MoveForward);
PlayerInputComponent->BindAxis(TEXT("MoveRight"), this, &APlayerCharacter::MoveRight);
PlayerInputComponent->BindAxis(TEXT("LookUp"), this, &APlayerCharacter::LookUp);
PlayerInputComponent->BindAxis(TEXT("LookRight"), this, &APlayerCharacter::LookRight);
PlayerInputComponent->BindAction(TEXT("MainAttack"), IE_Pressed, this, &APlayerCharacter::MainAttack);
PlayerInputComponent->BindAction(TEXT("FirstAbility"), IE_Pressed, this, &APlayerCharacter::FirstAbility);
PlayerInputComponent->BindAction(TEXT("SecondAbility"), IE_Pressed, this, &APlayerCharacter::SecondAbility);
PlayerInputComponent->BindAction(TEXT("Jump"), IE_Pressed, this, &APlayerCharacter::Jump);
PlayerInputComponent->BindAction(TEXT("UltimateAbility"), IE_Pressed, this, &APlayerCharacter::UltimateAbility);
PlayerInputComponent->BindAction(TEXT("CustomAction"), IE_Pressed, this, &APlayerCharacter::CustomAction);
}
USkeletalMeshComponent* APlayerCharacter::GetWeapon()
{
return WeaponMesh;
}
void APlayerCharacter::MoveForward(float AxisValue)
{
AddMovementInput(GetActorForwardVector() * AxisValue);
UE_LOG(LogTemp, Warning, TEXT("IsFalling: %s"), GetCharacterMovement()->IsFalling() ? TEXT("True") : TEXT("False"));
UE_LOG(LogTemp, Warning, TEXT("Input Value: %f"), AxisValue);
}
void APlayerCharacter::MoveRight(float AxisValue)
{
AddMovementInput(GetActorRightVector() * AxisValue);
}
void APlayerCharacter::LookUp(float AxisValue)
{
AddControllerPitchInput(AxisValue);
}
void APlayerCharacter::LookRight(float AxisValue)
{
AddControllerYawInput(AxisValue);
}
void APlayerCharacter::MainAttack()
{
UE_LOG(LogTemp, Warning, TEXT("Main Attack..."));
}
void APlayerCharacter::FirstAbility()
{
UE_LOG(LogTemp, Warning, TEXT("First Ability..."));
}
void APlayerCharacter::SecondAbility()
{
UE_LOG(LogTemp, Warning, TEXT("Second Ability..."));
}
void APlayerCharacter::UltimateAbility()
{
UE_LOG(LogTemp, Warning, TEXT("Ultimate Ability..."));
}
void APlayerCharacter::CustomAction()
{
UE_LOG(LogTemp, Warning, TEXT("Custom Action..."));
}
void APlayerCharacter::Jump()
{
Super::Jump();
}
void APlayerCharacter::MACooldown()
{
IsMACooled = true;
}
void APlayerCharacter::FACooldown()
{
IsFACooled = true;
}
void APlayerCharacter::SACooldown()
{
IsSACooled = true;
}
void APlayerCharacter::UACooldown()
{
IsUACooled = true;
}
void APlayerCharacter::AbilityFailed()
{
UGameplayStatics::PlaySoundAtLocation(GetWorld(), CooldownSound, GetActorLocation());
}
float APlayerCharacter::GetMACT()
{
return MainAttackCooldownTime;
}
float APlayerCharacter::GetFACT()
{
return FirstAbilityCooldownTime;
}
float APlayerCharacter::GetSACT()
{
return SecondAbilityCooldownTime;
}
float APlayerCharacter::GetUACT()
{
return UltimateAbilityCooldownTime;
}
BomberCharacter.h
#pragma once
#include "CoreMinimal.h"
#include "PlayerCharacter.h"
#include "BomberCharacter.generated.h"
/**
*
*/
UCLASS()
class FPSPROTOTYPE_API ABomberCharacter : public APlayerCharacter
{
GENERATED_BODY()
protected:
virtual void BeginPlay() override;
public:
ABomberCharacter();
virtual void Tick(float DeltaTime) override;
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
class UCharacterMovementComponent* CharMoveComp;
UPROPERTY(EditAnywhere, Category="Combat")
class UParticleSystem* WeaponFire;
class AMyPlayerController* Controller;
bool CanPerform();
bool IsAttacking = false;
//Input
virtual void MainAttack() override;
virtual void FirstAbility() override;
virtual void SecondAbility() override;
virtual void CustomAction() override;
virtual void Jump() override;
//Bomb
UPROPERTY(EditAnywhere, meta = (AllowPrivateAccess = "true"), Category = "Combat|Bomb")
TSubclassOf<class ABomb> BombClass;
void SpawnBomb();
UPROPERTY(EditDefaultsOnly, Category="Combat|Bomb")
USoundBase* LauncherSound;
//RocketJump
void RocketJump();
bool RocketJumpCheck(AActor* Actor);
UPROPERTY(EditAnywhere, Category="Combat|Rocket Jump")
float MaxDistanceZ;
UPROPERTY(EditAnywhere, Category="Combat|Rocket Jump")
float MaxDistanceXandY;
UPROPERTY(EditAnywhere, Category="Combat|Rocket Jump")
float UpVelocity;
//Jump
FTimerHandle BurstTimerHanlde;
UPROPERTY(EditDefaultsOnly, Category="Combat|Burst")
float BurstRate = 1;
int BurstCounter = 0;
void Burst();
//Mine
UPROPERTY(EditAnywhere, meta = (AllowPrivateAccess = "true"), Category = "Combat|Mine")
TSubclassOf<class AMine> MineClass;
bool IsPlacingMine = false;
void StartPlacingMine();
void StopPlacingMine(bool Commit);
class AMine* CurrentMine;
float MineZ = 0;
bool PlaceMineTrace(FHitResult& HitResult);
UPROPERTY(EditDefaultsOnly, Category="Combat|Mine")
float MaxMinePlacingRange;
int MineCounter();
void ExplodeAllMines();
};
BomberCharacter.cpp
#include "BomberCharacter.h"
#include "Bomb.h"
#include "TimerManager.h"
#include "Math/UnrealMathUtility.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Mine.h"
#include "Kismet/GameplayStatics.h"
#include "MyPlayerController.h"
ABomberCharacter::ABomberCharacter()
{
CharMoveComp = GetCharacterMovement();
}
void ABomberCharacter::BeginPlay()
{
Controller = Cast<AMyPlayerController>(GetController());
}
void ABomberCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
void ABomberCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if(IsPlacingMine && CurrentMine)
{
FHitResult Hit;
bool bSuccess = PlaceMineTrace(Hit);
if(bSuccess)
{
CurrentMine->SetActorLocation(Hit.Location);
}
else
{
FVector MineNewLocation = GetActorLocation() + GetActorForwardVector() * MaxMinePlacingRange;
MineNewLocation.Z = MineZ;
CurrentMine->SetActorLocation(MineNewLocation);
}
}
}
bool ABomberCharacter::CanPerform()
{
return IsAttacking;
}
void ABomberCharacter::MainAttack()
{
if(IsPlacingMine)
{
StopPlacingMine(true);
return;
}
if(IsMACooled)
{
Super::MainAttack();
SpawnBomb();
IsMACooled = false;
if(Controller) Controller->CooldownEvent(1);
GetWorldTimerManager().SetTimer(MATimerHandle, this, &APlayerCharacter::MACooldown, MainAttackCooldownTime, false);
}
else
{
AbilityFailed();
UE_LOG(LogTemp, Warning, TEXT("Main Attack Is Colling Down..."));
}
}
void ABomberCharacter::FirstAbility()
{
if(IsPlacingMine)
{
StopPlacingMine(false);
return;
}
if(IsFACooled)
{
Super::FirstAbility();
GetWorldTimerManager().SetTimer(BurstTimerHanlde, this, &ABomberCharacter::Burst, BurstRate, true, 0);
}
else
{
AbilityFailed();
UE_LOG(LogTemp, Warning, TEXT("Main Attack Is Colling Down..."));
}
}
void ABomberCharacter::SecondAbility()
{
if(MineCounter()<3 && !CharMoveComp->IsFalling())
{
if(!IsPlacingMine)
{
Super::SecondAbility();
StartPlacingMine();
}
}
else
{
AbilityFailed();
}
}
void ABomberCharacter::CustomAction()
{
ExplodeAllMines();
ExplodeAllMines();
}
void ABomberCharacter::Jump()
{
UE_LOG(LogTemp, Warning, TEXT("Jumping..."));
if(IsPlacingMine)
{
StopPlacingMine(false);
}
Super::Jump();
}
void ABomberCharacter::SpawnBomb()
{
FVector Location = ProjectileSpawnPoint->GetComponentLocation();
FRotator Rotation = GetActorRotation();
auto Bomb = GetWorld()->SpawnActor<ABomb>(BombClass, Location, Rotation);
Bomb->SetOwner(this);
UGameplayStatics::PlaySoundAtLocation(GetWorld(), LauncherSound, GetActorLocation());
}
void ABomberCharacter::RocketJump()
{
UE_LOG(LogTemp, Warning, TEXT("Rocket Jump!"));
FVector Velocity(0, 0, UpVelocity);
LaunchCharacter(Velocity, false, false);
}
bool ABomberCharacter::RocketJumpCheck(AActor* Actor)
{
FVector PlayerLocation = this->GetActorLocation();
FVector ActorLocation = Actor->GetActorLocation();
float DistanceZ = PlayerLocation.Z-ActorLocation.Z;
float DistanceXY = FMath::Sqrt(FMath::Square(PlayerLocation.X-ActorLocation.X)+FMath::Square(PlayerLocation.Y-ActorLocation.Y));
if(DistanceZ>0 && DistanceZ<MaxDistanceZ && DistanceXY<MaxDistanceXandY && CharMoveComp->IsFalling())
{
UE_LOG(LogTemp, Warning, TEXT("DistanceZ: %f"), DistanceZ);
UE_LOG(LogTemp, Warning, TEXT("DistanceXY: %f"), DistanceXY);
return true;
}
return false;
}
void ABomberCharacter::Burst()
{
if(BurstCounter<=2)
{
SpawnBomb();
BurstCounter++;
}
else
{
BurstCounter = 0;
IsFACooled = false;
if(Controller) Controller->CooldownEvent(2);
GetWorldTimerManager().SetTimer(FATimerHandle, this, &APlayerCharacter::FACooldown, FirstAbilityCooldownTime, false);
GetWorldTimerManager().PauseTimer(BurstTimerHanlde);
}
}
void ABomberCharacter::StartPlacingMine()
{
UE_LOG(LogTemp, Warning, TEXT("Starting Placing Mine..."));
FHitResult Hit;
bool bSuccess = PlaceMineTrace(Hit);
if(bSuccess)
{
UE_LOG(LogTemp, Warning, TEXT("Spawning Mine..."));
CurrentMine = GetWorld()->SpawnActor<AMine>(MineClass, Hit.Location, FRotator(0, 0, 0));
if(CurrentMine != nullptr) IsPlacingMine = true;
MineZ = Hit.Location.Z;
}
}
void ABomberCharacter::StopPlacingMine(bool Commit)
{
if(Commit)
{
UE_LOG(LogTemp, Warning, TEXT("Mine Placed..."));
CurrentMine->Arm();
}
else
{
CurrentMine->Destroy();
}
IsPlacingMine = false;
}
bool ABomberCharacter::PlaceMineTrace(FHitResult& HitResult)
{
AController* PlayerController = GetController();
if(!Controller) return false;
FVector Location;
FRotator Rotation;
Controller->GetPlayerViewPoint(Location, Rotation);
FVector End = Location + Rotation.Vector() * MaxMinePlacingRange;
FCollisionQueryParams Params;
return GetWorld()->LineTraceSingleByChannel(HitResult, Location, End, ECC_GameTraceChannel1);
}
int ABomberCharacter::MineCounter()
{
TArray<AActor*> Mines;
UGameplayStatics::GetAllActorsOfClass(GetWorld(), MineClass, Mines);
return Mines.Num();
}
void ABomberCharacter::ExplodeAllMines()
{
if(MineCounter()>0)
{
TArray<AActor*> Mines;
UGameplayStatics::GetAllActorsOfClass(GetWorld(), MineClass, Mines);
UE_LOG(LogTemp, Warning, TEXT("Mines Placed: %i"), MineCounter());
for(int i = 0; i<MineCounter(); i++)
{
TArray<AActor*> MinesTwo;
UGameplayStatics::GetAllActorsOfClass(GetWorld(), MineClass, MinesTwo);
AMine* Mine = Cast<AMine>(MinesTwo.Top());
if(Mine!=nullptr)
{
Mine->Explode();
}
}
}
}
I spent few hours trying to solve this problem on my own but I couldn’t.
PS. I know my code might not be the highest quality but i’m still learning.