I’m trying to extend the unreal learn shooter project, and I’m trying to add a teleport function to Character.h/.cpp and CharacterMovementComponent.h/.cpp .
I’ve replicated the functions used for jumping and adapted them to my purpose, but even declaring and implementing everything it still results in multiple unresolved symbol errors.
Here what I copied and modified in Character.h and .cpp. The jump related stuff is the original, and the teleport related stuff is my work.
character.h:
class ENGINE_API ACharacter : public APawn
{
...
UPROPERTY(BlueprintReadOnly, Category=Character)
uint32 bPressedJump:1;
UPROPERTY(BlueprintReadOnly, Category=Character)
uint32 bPressedTeleport:1;
...
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Transient, Category=Character)
uint32 bWasJumping : 1;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Transient, Category=Character)
uint32 bWasTeleporting : 1;
UPROPERTY(Transient, BlueprintReadOnly, VisibleInstanceOnly, Category=Character)
float JumpKeyHoldTime;
UPROPERTY(Transient, BlueprintReadOnly, VisibleInstanceOnly, Category=Character)
float JumpForceTimeRemaining;
UPROPERTY(Transient, BlueprintReadOnly, VisibleInstanceOnly, Category=Character)
float TeleportSinceActivationTime;
...
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category=Character, Meta=(ClampMin=0.0, UIMin=0.0))
float JumpMaxHoldTime;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category=Character, Meta=(ClampMin=0.0, UIMin=0.0))
float TeleportCooldown;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category=Character)
int32 JumpMaxCount;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category=Character)
int32 JumpCurrentCount;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = Character)
int32 JumpCurrentCountPreJump;
...
UFUNCTION(BlueprintCallable, Category=Character)
virtual void Jump();
UFUNCTION(BlueprintCallable, Category=Character)
virtual void Teleport();
...
UFUNCTION(BlueprintCallable, Category=Character)
virtual void StopJumping();
UFUNCTION(BlueprintCallable, Category=Character)
virtual void StopTeleporting();
...
UFUNCTION(BlueprintCallable, Category=Character)
bool CanJump() const;
UFUNCTION(BlueprintCallable, Category=Character)
bool CanTeleport() const;
...
UFUNCTION(BlueprintNativeEvent, Category=Character, meta=(DisplayName="CanJump"))
bool CanJumpInternal() const;
UFUNCTION(BlueprintNativeEvent, Category=Character, meta=(DisplayName="CanTeleport"))
bool CanTeleportInternal() const;
virtual bool CanJumpInternal_Implementation() const;
virtual bool CanTeleportInternal_Implementation() const;
...
virtual void ResetJumpState();
virtual void ResetTeleportState();
...
UFUNCTION(BlueprintNativeEvent, Category=Character)
void OnJumped();
virtual void OnJumped_Implementation();
and character.cpp
bool ACharacter::CanJump() const
{
return CanJumpInternal();
}
bool ACharacter::CanTeleport() const
{
return CanTeleportInternal();
}
bool ACharacter::CanJumpInternal_Implementation() const
{
// Ensure the character isn't currently crouched.
bool bCanJump = !bIsCrouched;
// Ensure that the CharacterMovement state is valid
bCanJump &= CharacterMovement->CanAttemptJump();
if (bCanJump)
{
// Ensure JumpHoldTime and JumpCount are valid.
if (!bWasJumping || GetJumpMaxHoldTime() <= 0.0f)
{
if (JumpCurrentCount == 0 && CharacterMovement->IsFalling())
{
bCanJump = JumpCurrentCount + 1 < JumpMaxCount;
}
else
{
bCanJump = JumpCurrentCount < JumpMaxCount;
}
}
else
{
// Only consider JumpKeyHoldTime as long as:
// A) The jump limit hasn't been met OR
// B) The jump limit has been met AND we were already jumping
const bool bJumpKeyHeld = (bPressedJump && JumpKeyHoldTime < GetJumpMaxHoldTime());
bCanJump = bJumpKeyHeld &&
((JumpCurrentCount < JumpMaxCount) || (bWasJumping && JumpCurrentCount == JumpMaxCount));
}
}
return bCanJump;
}
bool ACharacter::CanTeleportInternal_Implementation() const
{
// Ensure the character isn't currently crouched.
bool bCanTeleport = !bIsCrouched;
// Ensure that the CharacterMovement state is valid
bCanTeleport &= CharacterMovement->CanAttemptTeleport();
bCanTeleport &= !bWasTeleporting && TeleportSinceActivationTime >= GetTeleportCooldown();
return bCanTeleport;
}
void ACharacter::ResetJumpState()
{
bPressedJump = false;
bWasJumping = false;
JumpKeyHoldTime = 0.0f;
JumpForceTimeRemaining = 0.0f;
if (CharacterMovement && !CharacterMovement->IsFalling())
{
JumpCurrentCount = 0;
JumpCurrentCountPreJump = 0;
}
}
void ACharacter::ResetTeleportState()
{
bPressedTeleport = false;
bWasTeleporting = false;
}
void ACharacter::OnJumped_Implementation()
{
}
...
void ACharacter::Jump()
{
bPressedJump = true;
JumpKeyHoldTime = 0.0f;
}
void ACharacter::Teleport()
{
bPressedTeleport = true;
TeleportSinceActivationTime = 0.0f;
}
void ACharacter::StopJumping()
{
bPressedJump = false;
ResetJumpState();
}
void ACharacter::StopTeleporting()
{
bPressedTeleport = false;
ResetTeleportState();
}
void ACharacter::CheckJumpInput(float DeltaTime)
{
JumpCurrentCountPreJump = JumpCurrentCount;
if (CharacterMovement)
{
if (bPressedJump)
{
// If this is the first jump and we're already falling,
// then increment the JumpCount to compensate.
const bool bFirstJump = JumpCurrentCount == 0;
if (bFirstJump && CharacterMovement->IsFalling())
{
JumpCurrentCount++;
}
const bool bDidJump = CanJump() && CharacterMovement->DoJump(bClientUpdating);
if (bDidJump)
{
// Transition from not (actively) jumping to jumping.
if (!bWasJumping)
{
JumpCurrentCount++;
JumpForceTimeRemaining = GetJumpMaxHoldTime();
OnJumped();
}
}
bWasJumping = bDidJump;
}
}
}
void ACharacter::CheckTeleportInput(float DeltaTime)
{
JumpCurrentCountPreJump = JumpCurrentCount;
if (CharacterMovement)
{
if (bPressedTeleport)
{
const bool bDidTeleport = CanTeleport() && CharacterMovement->DoTeleport(bClientUpdating);
bWasTeleporting = bDidTeleport;
}
}
}
void ACharacter::ClearJumpInput(float DeltaTime)
{
if (bPressedJump)
{
JumpKeyHoldTime += DeltaTime;
// Don't disable bPressedJump right away if it's still held.
// Don't modify JumpForceTimeRemaining because a frame of update may be remaining.
if (JumpKeyHoldTime >= GetJumpMaxHoldTime())
{
bPressedJump = false;
}
}
else
{
JumpForceTimeRemaining = 0.0f;
bWasJumping = false;
}
}
void ACharacter::ClearTeleportInput(float DeltaTime)
{
TeleportSinceActivationTime+=DeltaTime;
if(TeleportSinceActivationTime>=GetTeleportCooldown() && !bPressedTeleport)
{
bWasTeleporting = false;
}
}
float ACharacter::GetJumpMaxHoldTime() const
{
return JumpMaxHoldTime;
}
float ACharacter::GetTeleportCooldown() const
{
return TeleportCooldown;
}