Dear Epic,
I’m noticing some strange output from GetTransform() when calling it during OnComponentHit.
Setup
I'm running some checks to see if my character can climb surfaces during the collisions. During these checks I'm trying to use FVectors relating to my actor's location in the world.I cannot use GetActorLocation() because I need to use an FTransform so I can use TransformPosition() and get trace and sweep locations relative to my actor’s current facing direction and location.
However I’m getting bad values from GetTransform().GetLocation().
Code
The Capsule is 96uuI’m using the absolute basic third person c++ code template. Only things changed are:
AWorkshopCharacter.h
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "GameFramework/SpringArmComponent.h"
#include "WorkshopCharacter.generated.h"
UCLASS(config=Game)
class AWorkshopCharacter : public ACharacter
{
GENERATED_UCLASS_BODY()
/** Camera boom positioning the camera behind the character */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
TSubobjectPtr<class USpringArmComponent> CameraBoom;
/** Follow camera */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
TSubobjectPtr<class UCameraComponent> FollowCamera;
/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
float BaseTurnRate;
/** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
float BaseLookUpRate;
/** Called when touching an object */
UFUNCTION()
void OnHit(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);
protected:
/** Called for forwards/backward input */
void MoveForward(float Value);
/** Called for side to side input */
void MoveRight(float Value);
/**
* Called via input to turn at a given rate.
* @param Rate This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
*/
void TurnAtRate(float Rate);
/**
* Called via input to turn look up/down at a given rate.
* @param Rate This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
*/
void LookUpAtRate(float Rate);
/** Handler for when a touch input begins. */
void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);
protected:
// APawn interface
virtual void SetupPlayerInputComponent(class UInputComponent* InputComponent) OVERRIDE;
// End of APawn interface
};
AWorkshopCharacter.cpp
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#include "Workshop.h"
#include "WorkshopCharacter.h"
//////////////////////////////////////////////////////////////////////////
// AWorkshopCharacter
AWorkshopCharacter::AWorkshopCharacter(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
// Set size for collision capsule
CapsuleComponent->InitCapsuleSize(42.f, 96.0f);
CapsuleComponent->OnComponentHit.AddDynamic(this, &AWorkshopCharacter::OnHit);
// set our turn rates for input
BaseTurnRate = 45.f;
BaseLookUpRate = 45.f;
// Don't rotate when the controller rotates. Let that just affect the camera.
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
// Configure character movement
CharacterMovement->bOrientRotationToMovement = true; // Character moves in the direction of input...
CharacterMovement->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate
CharacterMovement->JumpZVelocity = 600.f;
CharacterMovement->AirControl = 0.2f;
// Create a camera boom (pulls in towards the player if there is a collision)
CameraBoom = PCIP.CreateDefaultSubobject<USpringArmComponent>(this, TEXT("CameraBoom"));
CameraBoom->AttachTo(RootComponent);
CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character
CameraBoom->bUseControllerViewRotation = true; // Rotate the arm based on the controller
// Create a follow camera
FollowCamera = PCIP.CreateDefaultSubobject<UCameraComponent>(this, TEXT("FollowCamera"));
FollowCamera->AttachTo(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
FollowCamera->bUseControllerViewRotation = false; // Camera does not rotate relative to arm
// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character)
// are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++)
}
//////////////////////////////////////////////////////////////////////////
// Hit
void AWorkshopCharacter::OnHit(AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::Yellow, GetTransform().GetLocation().ToString());
}
//////////////////////////////////////////////////////////////////////////
// Input
void AWorkshopCharacter::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
// Set up gameplay key bindings
check(InputComponent);
InputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
InputComponent->BindAxis("MoveForward", this, &AWorkshopCharacter::MoveForward);
InputComponent->BindAxis("MoveRight", this, &AWorkshopCharacter::MoveRight);
// We have 2 versions of the rotation bindings to handle different kinds of devices differently
// "turn" handles devices that provide an absolute delta, such as a mouse.
// "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick
InputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
InputComponent->BindAxis("TurnRate", this, &AWorkshopCharacter::TurnAtRate);
InputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
InputComponent->BindAxis("LookUpRate", this, &AWorkshopCharacter::LookUpAtRate);
// handle touch devices
InputComponent->BindTouch(EInputEvent::IE_Pressed, this, &AWorkshopCharacter::TouchStarted);
}
void AWorkshopCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
{
// jump, but only on the first touch
if (FingerIndex == ETouchIndex::Touch1)
{
Jump();
}
}
void AWorkshopCharacter::TurnAtRate(float Rate)
{
// calculate delta for this frame from the rate information
AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}
void AWorkshopCharacter::LookUpAtRate(float Rate)
{
// calculate delta for this frame from the rate information
AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}
void AWorkshopCharacter::MoveForward(float Value)
{
if ((Controller != NULL) && (Value != 0.0f))
{
// find out which way is forward
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// get forward vector
const FVector Direction = FRotationMatrix(Rotation).GetUnitAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
}
void AWorkshopCharacter::MoveRight(float Value)
{
if ( (Controller != NULL) && (Value != 0.0f) )
{
// find out which way is right
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// get right vector
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
// add movement in that direction
AddMovementInput(Direction, Value);
}
}
Results
And my results are:Here we see the results of the above test. I’m getting two different Z values. (Note: 223.150 is the correct Z location)
And here we see the same identical code running in a Tick Override, but here I seem to be getting consistent accurate results.
Anomalies
When using GetActorLocation() in my OnHit function I get consistent Z location results. But I cannot use TransformPosition from an FVector.
I even attempted to create a new FTransform and set the Translation component by:
FTransform( GetActorLocation() )
And I still get the same strange offset results.