Last active
December 24, 2023 17:19
-
-
Save josimard/c69b87dc88882e6f5286d9d69a5b6e85 to your computer and use it in GitHub Desktop.
UE4 - Rotate an actor around another in Unreal Engine using FVector::RotateAngleAxis() to create an orbital rotation (Not using transforms or attachments)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "RotateAroundActor.h" | |
#include "GameFramework/Actor.h" | |
// Sets default values for this component's properties | |
URotateAroundActor::URotateAroundActor() | |
{ | |
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features | |
// off to improve performance if you don't need them. | |
PrimaryComponentTick.bCanEverTick = true; | |
bAutoActivate = true; | |
} | |
// Called when the game starts | |
void URotateAroundActor::BeginPlay() | |
{ | |
Super::BeginPlay(); | |
Reset(); | |
} | |
// Called every frame | |
void URotateAroundActor::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) | |
{ | |
Super::TickComponent(DeltaTime, TickType, ThisTickFunction); | |
if (IsActive() && RotateAroundActor != nullptr) | |
{ | |
CurrentAngle += RotationSpeed * DeltaTime; | |
// Wrap angles around: Only good for this use case, otherwise use Math::UnwindDegrees() | |
if (CurrentAngle > 360.f) CurrentAngle -= 360.f; | |
// Get this actor location from rotating it's | |
const FVector NewLocation = RotateAroundActor->GetActorLocation() + RotationRadius.RotateAngleAxis(CurrentAngle, RotationAxis); | |
GetOwner()->SetActorLocationAndRotation(NewLocation, FRotator(0, CurrentAngle, 0)); | |
} | |
} | |
void URotateAroundActor::Reset() | |
{ | |
CurrentAngle = InitialRotationAngle; | |
if (RotateAroundActor == nullptr) | |
{ | |
UE_LOG(LogTemp, Error, TEXT("RotateAroundActor is not set on %s"), *GetReadableName()); | |
return; | |
} | |
if (RotationRadius.IsZero()) | |
{ | |
RotationRadius = GetOwner()->GetActorLocation() - RotateAroundActor->GetActorLocation();//FVector::Dist(GetOwner()->GetActorLocation(), RotateAroundActor->GetActorLocation()); | |
} | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "CoreMinimal.h" | |
#include "Components/ActorComponent.h" | |
#include "RotateAroundActor.generated.h" | |
/** | |
* Rotate an actor around another. | |
* | |
* Notes: | |
* - ONLY USEFUL WHEN you cannot attach actors to each other for some reason. | |
* - Also demonstrates the use of FVector::RotateAngleAxis() in a reusable UActorComponent architecture | |
* The gist of it: WorldLocation = WorldLocation + RadiusVector.RotateAngleAxis(Angle, FVector::UpVector); | |
* | |
* If you can re-attach your actor's root component: | |
* - A simpler method consists of attaching a SceneComponent and using it's relative location and rotation to create an orbital movement | |
* | |
* @see USceneComponent::AttachToComponent | |
* https://api.unrealengine.com/INT/API/Runtime/Engine/Components/USceneComponent/AttachToComponent/index.html | |
**/ | |
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) | |
class URotateAroundActor : public UActorComponent | |
{ | |
GENERATED_BODY() | |
public: | |
// The target actor to rotate around | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RotateAround") | |
AActor* RotateAroundActor; | |
// The speed: Angles per second in degrees | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RotateAround") | |
float RotationSpeed = 50.f; | |
// The distance to rotate around the actor in CM | |
// ZERO: will take the initial distance of the two actors as the radius | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RotateAround") | |
FVector RotationRadius = FVector::ZeroVector; | |
// The 3D Axis around which the object will rotate, default horizontal (FVector::UpVector) | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RotateAround") | |
FVector RotationAxis = FVector::UpVector; | |
// The current angle for FVector::RotateAngleAxis() | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RotateAround", meta = (ClampMin = "0.0", ClampMax = "360.0", UIMin = "0.0", UIMax = "360.0")) | |
float InitialRotationAngle = 0.f; | |
protected: | |
float CurrentAngle = 0.f; | |
public: | |
// Sets default values for this component's properties | |
URotateAroundActor(); | |
protected: | |
// Called when the game starts | |
virtual void BeginPlay() override; | |
public: | |
// Called every frame | |
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; | |
// Will reset current angle axis and | |
UFUNCTION(BlueprintCallable) | |
void Reset(); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment