본문 바로가기

개발/언리얼

언리얼 C++ 펜듈럼 움직임 구현하기

 

https://zerosik00.tistory.com/71

 

언리얼 c++로 움직이는 액터 구현하기

핵심 함수GetActorLocation() : 현재 엑터의 위치 FVector를 가져오는 함수SetActorLocation() : 현재 액터의 위치를 "변경"하는 함수핵심 함수 목표c++클래스를 생성시작지점과 이동거리, 이동속도를 변수로

zerosik00.tistory.com

 

이전에 SetActorLocation, SetActorRotation으로 움직임을 구현하는 시도를 해보았다.

이번엔 이를 조금 응용해서 펜듈럼처럼 움직이는 액터를 구현해볼것이다.

 

이전에 사인파를 이용한다면 두 지점을 왕복하는 애니메이션을 구현할 수 있다는것을 배운적이 있어 이를 응용하였다.

https://zerosik00.tistory.com/39

 

02/10 머티리얼 애니메이션

머티리얼 그래프를 통해 머터리얼에 애니메이션을 추가하는 방법 사인파를 이용해서 반복적인 규칙을 만들 수 있음y = D * sin(C x + a) + b일때a값에 따라 파동 주기의 시작점이 달라지고b값을 올리

zerosik00.tistory.com

 

 

동일하게 Actor를 상속받은 C++클래스를 생성하고, 뼈대가 될 SceneComponent와 StaticMeshComponent를 추가,

펜듈럼 움직임 구현에 사용할 회전각도  MaxAngle과 속도를 정할 SwingSpeed변수를 선언하였다.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "PendulumActor.generated.h"

UCLASS()
class HOMEWORK6_API APendulumActor : public AActor
{
	GENERATED_BODY()
public:	
	APendulumActor();

	UPROPERTY(EditAnywhere, Category = "Components")
	USceneComponent* SceneRoot;
	UPROPERTY(EditAnywhere, Category = "Components")
	UStaticMeshComponent* StaticMeshComp;

	UPROPERTY(EditInstanceOnly, Category = "Pendulum")
	float MaxAngle;
	UPROPERTY(EditInstanceOnly, Category = "Pendulum")
	float SwingSpeed;

	float timeElapsed;

protected:
	virtual void Tick(float DeltaTime) override;
};

 

StaticMesh는 블루프린트 자식에서 지정하도록 한다.

 

구현부를 살펴보자.

#include "PendulumActor.h"

// Sets default values
APendulumActor::APendulumActor()
{
	PrimaryActorTick.bCanEverTick = true;

	SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
	SetRootComponent(SceneRoot);
	StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
	StaticMeshComp->SetupAttachment(RootComponent);

	MaxAngle = 45.f;
	SwingSpeed = 5.f;
	timeElapsed = 0.f;
}

// Called every frame
void APendulumActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	timeElapsed += DeltaTime;
	//사인파를 이용해 반복하는 애니메이션 구현 가능
	//https://zerosik00.tistory.com/39
	float sine = FMath::Sin(timeElapsed * SwingSpeed);

	//Pitch값으로 진자운동
	FRotator newRotate = FRotator(MaxAngle * sine, 0.f, 0.f);
	SetActorRotation(newRotate);
}

생성자에서 컴포넌트 초기화와 기본값설정을 한다.

 

핵심은 Tick함수에 구현한 Sine함수를 통해 1 -> 0 -> -1 -> 0 -> 1로 반복하는 사인파를 이용해 진자운동을 구현하는것이다.

사인파 시각화

timeElapsed에 누적 시간을 더하고 해당값 * Speed로 사인파의 간격을 변경해 속도를 조절한다.

MaxAngle * sine값을 FRotator의 Pitch값으로 지정하고 SetActorRotation 함수로 회전을 구현한다.

 

일단은 예상대로 왕복운동을 하는것을 확인하였다

다만 현재 코드의 문제점이

SetActorRotation호출에 사용한 FRotator값이 Pitch를 제외하고 0이라 한 방향으로만 움직인다.

이를 해결하기 위해 처음에 레벨에 배치된 Yaw값을 저장해놓고, 진자운동에 적용시키도록 개선하였다.

void APendulumActor::BeginPlay()
{
	Super::BeginPlay();
	defaultYaw = GetActorRotation().Yaw;
}

void APendulumActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	timeElapsed += DeltaTime;
	//사인파를 이용해 반복하는 애니메이션 구현 가능
	//https://zerosik00.tistory.com/39
	float sine = FMath::Sin(timeElapsed * SwingSpeed);

	//Pitch값으로 진자운동
	FRotator newRotate = FRotator(MaxAngle * sine, defaultYaw, 0.f);
	SetActorRotation(newRotate);
}

녹음 2026-04-10 211024.gif
1.88MB

 

 

미친티스토리 gif가 안올라간다 아무튼 잘됨