ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 무기 버리는 물리효과 추가
    Game Programming/언리얼 2023. 10. 18. 17:24

    Weapon.h

    private:
    	FTimerHandle ThrowWeaponTimer;
    	float ThrowWeaponTime;
    	bool bFalling;

    무기 버리기 종료 타이머, 무기가 땅에 떨어졌는데 확인하는 boolean 변수를 추가했다.

    	FRotator MeshRotation{ 0.f, GetItemMesh()->GetComponentRotation().Yaw, 0.f };
    	GetItemMesh()->SetWorldRotation(MeshRotation, true, nullptr, ETeleportType::TeleportPhysics);

    무기의 Y축 회전량을 가져와서, 무기 메시를 Y축 방향으로 월드에서 회전시킨다. (손에 있을 때는 회전이 안된 상태인가보다.)


    언리얼 도큐먼트 SetWorldRotation


    SetWorldRotation 함수에 대해 찾아보니, bSweep 변수는 목표 지점에서 무기가 쓸고 지나갈지 결정하는 변수이고 SweepHitResult는 무기가 땅에 닿았는지 여부를 알려주는 변수로 확인했다.

    bSweep  목표 지점에서 무기가 쓸고 지나갈지 결정하
    SweepHitResult 무기가 땅에 닿았는지 여부를 알려주는 변수
    ETeleportType 물리 효과, 충돌을 어떻게 설정할지 여부
    UENUM()
    enum class ETeleportType : uint8
    {
    	/** Do not teleport physics body. This means velocity will reflect the movement between initial and final position, and collisions along the way will occur */
    	None,
    
    	/** Teleport physics body so that velocity remains the same and no collision occurs */
    	TeleportPhysics,
    
    	/** Teleport physics body and reset physics state completely */
    	ResetPhysics,
    };

    ETeleportType 내부를 보니 위와 같이 코드가 되어있다.

    None 물리체를 이동시키않고, 속도는 유지하는데 처음 위치와 마지막 위치의 이동을 반영한다. 충돌은 발생한다.
    TeleportPhysics 물리체를 이동 시키고, 등속도로 유지하되 충돌은 발생하지 않는다.
    ResetPhysics 물리체를 이동시키고 물리체를 완전하게 리셋시킨다.

    ResetPhysics으로 설정하면 BarrelSocket이 손에있고, TeleportPhysics로 설정하면 BarrelSocket이 무기에 있었다.


    	const FVector MeshForward{ GetItemMesh()->GetForwardVector() };
    	const FVector MeshRight{ GetItemMesh()->GetRightVector() };
    	// Direction in which we throw the Weapon
    	FVector ImpulseDirection = MeshRight.RotateAngleAxis(-20.f, MeshForward);
    	float RandomRotation{ 30.f };
    	ImpulseDirection = ImpulseDirection.RotateAngleAxis(RandomRotation, FVector(0.f, 0.f, 1.f));

    무기의 진행 방향으로 Y축 기준 20도 아래로 던지도록 하고, Z축으로 30도 회전하도록 코드를 짰다.

    무기 펄스 진행 방향


    	ImpulseDirection *= 20'000.f;
    	GetItemMesh()->AddImpulse(ImpulseDirection);

     그리고 펄스의 세기로 20'000f을 주었다.

     

    void AWeapon::ThrowWeapon()
    {
    	FRotator MeshRotation{ 0.f, GetItemMesh()->GetComponentRotation().Yaw, 0.f };
    	GetItemMesh()->SetWorldRotation(MeshRotation, true, nullptr, ETeleportType::None);
    	
    	const FVector MeshForward{ GetItemMesh()->GetForwardVector() };
    	const FVector MeshRight{ GetItemMesh()->GetRightVector() };
    	// Direction in which we throw the Weapon
    	FVector ImpulseDirection = MeshRight.RotateAngleAxis(-20.f, MeshForward);
    	float RandomRotation{ 30.f };
    	ImpulseDirection = ImpulseDirection.RotateAngleAxis(RandomRotation, FVector(0.f, 0.f, 1.f));
    	ImpulseDirection *= 20'000.f;
    	GetItemMesh()->AddImpulse(ImpulseDirection);
    
    	bFalling = true;
    
    	GetWorldTimerManager().SetTimer(
    		ThrowWeaponTimer, 
    		this, 
    		&AWeapon::StopFalling, 
    		ThrowWeaponTime);
    }

    떨어지는 중이면 Tick에서 메시를 계속해서 회전 시켰다. (y축의 회전량 만큼 계속 회전을 시키는 것으로 파악된다)

    void AWeapon::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    
    	if (GetItemState() == EItemState::EIS_Falling && bFalling)
    	{
    		const FRotator MeshRotation{ 0.f, GetItemMesh()->GetComponentRotation().Yaw, 0.f };
    		GetItemMesh()->SetWorldRotation(MeshRotation, false, nullptr, ETeleportType::TeleportPhysics);
    	}
    }

     

    타이머가 호출되면 떨어지는 상태를 종료 시키고, 무기의 물리 상태를 EIS_Pickup상태로 만들었다.

    void AWeapon::StopFalling()
    {
    	bFalling = false;
    	SetItemState(EItemState::EIS_Pickup);
    }

     


    	FRotator MeshRotation{ 0.f, GetItemMesh()->GetComponentRotation().Yaw, 0.f };
    	GetItemMesh()->SetWorldRotation(MeshRotation, false, &WeaponeHitResult, ETeleportType::ResetPhysics);
    	
    	const FVector MeshForward{ GetItemMesh()->GetForwardVector() };
    	const FVector MeshRight{ GetItemMesh()->GetRightVector() };
    	// Direction in which we throw the Weapon
    	FVector ImpulseDirection = MeshRight.RotateAngleAxis(-20.f, MeshForward);
    	float RandomRotation{ 10.f };
    	ImpulseDirection = ImpulseDirection.RotateAngleAxis(RandomRotation, FVector(0.f, 0.f, 1.f));
    	ImpulseDirection.X *= 100.f;
    	ImpulseDirection.Y *= 20'000.f;
    	ImpulseDirection.Z *= 100.f;
    	GetItemMesh()->AddImpulse(ImpulseDirection);

     

    void AWeapon::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    
    	if (GetItemState() == EItemState::EIS_Falling && bFalling)
    	{
    		if (WeaponeHitResult.bBlockingHit)
    		{
    			SetItemState(EItemState::EIS_Pickup);
    		}
    		else
    		{
    			const FRotator MeshRotation{ 0.f, GetItemMesh()->GetComponentRotation().Yaw + 10.f, 0.f };
    			GetItemMesh()->SetWorldRotation(MeshRotation, false, nullptr, ETeleportType::TeleportPhysics);
    		}
    	}
    }

    수정한 무기 회전 값, Tick 함수 ThrowWeaponTime = 0.3f로 수정했다. 무기가 땅에 닿으면 물리 효과를 껏다.

    void AWeapon::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    
    	if (GetItemState() == EItemState::EIS_Falling && bFalling)
    	{
    		const FRotator MeshRotation{ 0.f, GetItemMesh()->GetComponentRotation().Yaw + 10.f, 0.f };
    		GetItemMesh()->SetWorldRotation(MeshRotation, false, nullptr, ETeleportType::TeleportPhysics);
    	}
    }

    Tick함수 수정, bBlockgingHit이면 물리효과를 끄도록 했는데 제대로 동작은 안했다.

    'Game Programming > 언리얼' 카테고리의 다른 글

    문 물리 작용 업데이트  (0) 2023.10.19
    무기 교체  (0) 2023.10.18
    Item Falling State  (0) 2023.10.17
    무기 버리기  (1) 2023.10.17
    아이템 Enum값 추가  (0) 2023.10.17
Designed by Tistory.