[17. Intro to Collision #1]
복합 콜리전을 이용하면 연산량이 많아서 느려지게 된다.
FBX 파일에 기본적으로 콜리전 처리가 되어있지 않으면 단순 콜리전을 선택해도 아무런 변화가 없다. (콜리전이 없어서 표시가 안됨)
콜리전 메뉴에서 박스 단순화 콜리전 추가를 한 후에 해당 메시를 포함하고 있는 Floater_BP의 디테일 탭에서 피직스 카테고리에 접근한다.
Simulate Physics : 물체의 피직스를 시뮬레이션 함
MassInKg : 물체의 기본 질량을 무시하고 재정의
Linear Damping : 평행 이동 느리게
Angular Damping : 회전 동작 느리게
오브젝트의 모빌리티가 무버블, 심플 콜리전이 있는 경우 시뮬레이트 피직스(Simulate Physics) 옵션을 체크하면 에디터에서 시뮬레이트나 에디터에서 플레이를 클릭했을 때 오브젝트에 피직스가 적용된다.
해당 블루프린트 클래스를 월드에 배치해서 적당한 높이에 둔 후에 실행을 누르면 중력을 받아 떨어지다가 땅에 닿으면 튀어오르게 된다.
다만, 박스 단순 콜리전이 적용된 상태라서 실제 메쉬와는 일치하지 않고 박스의 충돌처리가 이루어져서 조금 어색하다.
[18. Collision]
Floater_BP에서 해당 메소드를 선택하면 경고가 뜬다. C++에서 블루프린트에 관련된 속성을 넣어주지 않았기 때문이다.
// Floater.h
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "ActorMeshComponents")
UStaticMeshComponent* StaticMesh;
BlueprintReadWrite 속성을 추가해주면 경고가 사라진다.
콜리전이 존재한다면 충돌처리 자체는 다 되지만, Sunulate Physics가 체크된 물체들은 물리학까지 적용받게 된다.
Floater_BP의 AddForce를 X값 2천만 정도로 설정하고 위치를 테이블과 의자쪽으로 옮기고 실행하면 충돌처리가 잘 일어난다.
기본적으로 존재하던 테이블이나 의자 등의 오브젝트의 Simulate Physics를 체크해주면 마찬가지로 물리학이 적용된다.
피직스의 Enable Gravity 옵션을 비활성화하면 중력이 적용되지 않아서 오브젝트가 절대 떨어지지 않는다.
플레이 도중 ` 키를 눌러서 콘솔창을 열고 show collision을 입력하면 오브젝트마다 콜리전 영역이 표시된다.
[19. Sweeping]
Shape_Cube를 하나 생성해서 크기를 적당히 늘리고 Floater_BP를 뒤쪽에 배치한다.
Floater_BP의 이벤트그래프에서 AddForce 메소드를 지우고 월드 디테일에서 값을 위와같이 설정해준다. Simulate Physics도 체크 해제해준다.
실행해보면 Floater_BP가 메시를 뚫고 이동하는것을 볼 수 있다.
Simulate Physics를 다시 체크해주면 중력을 받아서 떨어진 후에 벽에 박히게 된다.
이전에 Floater의 Tick에서 작성했던 AddActorLocalOffset의 두 번째 인자가 sweep인데, true로 설정하면 Simulate Physics를 켜두지 않았을 때 관통하던것이 이제는 벽에 가로막히게 된다.
추가로, FHitResult는 구조체로써 다양한 정보를 담을 수 있다.
AddActorLocalOffset에 매개변수로 들어가는데, 주소값을 넘겨주므로 충돌이 발생했을 때 다양한 정보를 담게 된다.
그 중에 Location은 충돌이 발생한 지점을 FVector로 저장한다.
// Floater.cpp
void AFloater::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (bShouldFloat)
{
FHitResult HitResult;
AddActorLocalOffset(InitialDirection, true, &HitResult);
FVector HitLocation = HitResult.Location;
UE_LOG(LogTemp, Warning, TEXT("Hit Location: x = %f, y = %f, z = %f"), HitLocation.X, HitLocation.Y, HitLocation.Z);
}
}
위와 같이 작성하고 실행하면 출력 로그에 0으로만 찍히던 것이 벽과 충돌이 발생한 시점부터 좌표가 찍히게 된다.
별개로, 충돌하는 두 오브젝트가 있을 때, 둘 중 한쪽만 콜리전 반응을 겹침, 또는 무시로 설정하면 충돌이 발생하지 않게 된다.
sweep과는 상관 없이 발생하지 않게 된다.
[20. Local vs World Offset]
매개변수 : FVector(좌표), bSweep(스윕여부), FHitResult(충돌체 정보)
AddActorLocalOffset : 로컬 좌표계 기준으로 좌표를 더한다.
AddActorWorldOffset : 월드 좌표계 기준으로 좌표를 더한다.
매개변수 : FRotator(좌표)
AddActorLocalRotation : 로컬 좌표계 기준으로 회전한다.
AddActorWorldRotation : 월드 좌표계 기준으로 회전한다.
pitch - y / yaw - z / roll - x 이다.
뷰포트에서 Ctrl+`를 눌러서 월드/로컬 기준 좌표계를 변경할 수 있다.
[21. Force and Torque]
회전하는 힘: Torque
AddForce와 AddTorque를 통해 물체에 힘을 가할 수 있다.
참고) AddTorqueInRadians 사용을 권장한다. AddTorque를 사용해도 어차피 AddTorqueInRadians를 호출한다.
// Floater.h
UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Category = "Floater Variables")
FVector InitialForce;
UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Category = "Floater Variables")
FVector InitialTorque;
// Floater.cpp
AFloater::AFloater()
{
// .. 생략
InitialForce = FVector(2000000.f, 0.f, 0.f);
InitialTorque = FVector(2000000.f, 0.f, 0.f);
}
// Called when the game starts or when spawned
void AFloater::BeginPlay()
{
// .. 생략
StaticMesh->AddForce(InitialForce);
StaticMesh->AddTorqueInRadians(InitialTorque);
}
위의 함수를 사용하려면 Simulate Physics가 켜져있어야 한다.
[22. Random Numbers]
FMath::FRand()는 0~1사이의 float를 반환해준다.
FMath::FRandRange()는 2개의 float를 인자로 받아서 해당 값의 범위를 반환해준다.
이 외에도 다양한 랜덤 반환값을 돌려주는 함수들이 있다.
[23. The Sin Function]
위아래로 움직이는것과 같은 진동 동작을 모델링하는데 좋다.
종종 연산량이 많아져서 초당 프레임이 떨어질 때, 게임이 정말 느려지는 것처럼 고르지 못하게 된다.
이 때, DeltaTime과 Tick함수를 사용하면 프레임에 상관 없이 잘 동작하게 된다.
예를 들어서 120 프레임을 기준으로 초당 120cm씩 움직인다면 60 프레임인 경우 초당 60cm, 120 프레임인 경우 초당 120cm로 서로 다르게 움직이게 된다. 하지만 여기에 DeltaTime을 곱해준다면 프레임에 상관없이 항상 초당 120cm를 움직이게 된다.
// Floater.h
private:
float RunningTime;
float BaseZLocation;
// Floater.cpp
AFloater::AFloater()
{
// .. 생략
RunningTime = 0.f;
}
void AFloater::BeginPlay()
{
// .. 생략
BaseZLocation = PlacedLocation.Z;
}
void AFloater::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (bShouldFloat)
{
FVector NewLocation = GetActorLocation();
NewLocation.Z = BaseZLocation + FMath::Sin(RunningTime) * 100.f;
SetActorLocation(NewLocation);
RunningTime += DeltaTime;
UE_LOG(LogTemp, Warning, TEXT("%f"), RunningTime);
}
}
Floater_BP에서 체크박스를 모두 꺼준다.
실행 시켜보면 Z축 ±100으로 움직인다.
// Floater.h
public:
// Amplitude : how much we oscillate up and down
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Floater Variables")
float A;
// Period : 2 * PI / abs(B)
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Floater Variables")
float B;
// Phase Shift : C / B
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Floater Variables")
float C;
// Vertical Shift : D
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Floater Variables")
float D;
//
void AFloater::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (bShouldFloat)
{
FVector NewLocation = GetActorLocation();
// 중요!
NewLocation.Z = BaseZLocation + A * FMath::Sin(B * RunningTime - C) + D;
SetActorLocation(NewLocation);
RunningTime += DeltaTime;
}
}
X축이 시간(RunningTime)일 때, 진폭은 사인 그래프에 곱한 상수 값(A), 주기는 시간에 곱한 상수 값(B), 위상 변화는 시간에서 뺀 상수 값(C), 수직 이동은 결과에 더한 상수 값(D)이다.
Sin그래프는 기본적으로 -1 ~ 1 의 값을 가진다.
진폭(A) : 그래프의 빨간 곡선을 위 아래로 늘린 것 ([-1 ~ 1] * A)
주기(B) : 실제 주기 계산은 (2 * PI) / ABS(B) 이지만 해당 식도 주기와 관련이 있다. X축(Running Time)의 증가량을 늘리기 때문에 그래프가 좀더 빨리 그려지므로 주기가 짧아지는듯한 효과가 있다 (RunningTime * B)
위상 변화(C) : 그래프의 파란 곡선과 같다. 그래프의 시작이 0이 아닌 다른 값부터 시작하게 한다 (RunningTime - C)
수직 이동(D) : 그래프의 곡선을 위, 아래로 옮긴 것. 수직인 경우에 위상 변화와 유사하다 (Sin - D)
[24. Deleting Classes]
C++ 클래스는 에디터에서 삭제할 수 없다.
언리얼 엔진과 IDE를 모두 끄고 해당 폴더에서 직접 삭제를 해주어야 한다.
C++ 클래스가 있는 폴더에 접근해서 삭제하고 싶은 클래스를 삭제하고, Binaries 폴더까지 삭제한다.
uproject 확장자 파일을 우클릭해서 Generate Visual Studio project files를 누르고 다시 uproject를 실행해주면 된다.
팝업창은 예를 눌러주도록 하자.
'언리얼 엔진 > UE4 C++' 카테고리의 다른 글
[UE C++] The Pawn Class #2 (0) | 2022.09.05 |
---|---|
[UE C++] The Pawn Class #1 (0) | 2022.09.04 |
[UE C++] The Actor Class #1 (0) | 2022.09.03 |
[UE C++] Intro to Unreal Engine C++ (0) | 2022.09.03 |
[UE C++] Download UE4, and Intro to the Engine (0) | 2022.09.03 |