前回は、装備している武器を下にただ落とすだけでしたが、今回は、装備している武器をランダムな角度で前方向に投げ捨て、地面に落下している武器、もしくは、完全に落下せずに空中浮遊している状態の武器を再び装備できるようにします。ランダム角度なので、例えば、投げ捨て角度が0度の場合と30度の場合では1秒間に落下できる距離に差が生じます。
一度投げ捨てた武器を再装備する
Weapon.hのpublicエリアにThrowWeapon関数を宣言します。
void ThrowWeapon();
Weapon.hのprotectedセクションにStopFalling関数を宣言します。
void StopFalling();
Weapon.hのprivateエリアに変数を宣言します。
FTimerHandle ThrowWeaponTimer; float ThrowWeaponTime; bool bFalling;
Weapon.cppにThrowWeapon関数の定義を記述します。
oid AWeapon::ThrowWeapon() { FRotator MeshRotation{ GetItemMesh()->GetComponentRotation().Pitch, GetItemMesh()->GetComponentRotation().Yaw, GetItemMesh()->GetComponentRotation().Roll }; GetItemMesh()->SetWorldRotation(MeshRotation, false, nullptr); const FVector MeshForward{ GetItemMesh()->GetForwardVector() }; const FVector MeshRight{ GetItemMesh()->GetRightVector() }; // Direction in which we throw the Weapon FVector ImpulseDirection = MeshRight.RotateAngleAxis(60.f, MeshForward); float RandomRotation{ 30.f }; ImpulseDirection = ImpulseDirection.RotateAngleAxis(RandomRotation, FVector(0.f, 1.f, 1.f)); ImpulseDirection *= 4000.f; GetItemMesh()->AddImpulse(ImpulseDirection); bFalling = true; GetWorldTimerManager().SetTimer( ThrowWeaponTimer, this, &AWeapon::StopFalling, ThrowWeaponTime); }
Weapon.cppにStopFalling関数の定義を記述します。
void AWeapon::StopFalling() { bFalling = false; SetWeaponState(EWeaponState::EWS_PickUp); }
Weapon.cppのTick関数にコードを追加します。
void AWeapon::Tick(float DeltaTime) { Super::Tick(DeltaTime); if (WeaponState == EWeaponState::EWS_Falling && bFalling) { const FRotator MeshRotation{ GetItemMesh()->GetComponentRotation().Pitch, GetItemMesh()->GetComponentRotation().Yaw, GetItemMesh()->GetComponentRotation().Roll }; GetItemMesh()->SetWorldRotation(MeshRotation, false, nullptr); } }
これで一度投げ捨てた武器を再装備できるようになりました。
DropWeapon関数の修正
Yボタンで装着している武器を投げ捨てた後で再びYボタンを押すと、投げ捨てたはずの武器(pickupステート)が何故か勝手にfallingステートになって動いてしまいます。このバグを修正するには、投げ捨てる武器がequippedステートであることをチェックする必要があります。Weapon.cppのDropWeapon関数に武器ステートのチェックを入れることでこのバグを回避することができます。
void AMyCharacter::DropWeapon() { if (EquippedWeapon->GetWeaponState()==EWeaponState::EWS_Equipped) { FDetachmentTransformRules DetachmentTransformRules(EDetachmentRule::KeepWorld, true); EquippedWeapon->GetItemMesh()->DetachFromComponent(DetachmentTransformRules); EquippedWeapon->SetWeaponState(EWeaponState::EWS_Falling); EquippedWeapon->ThrowWeapon(); } }
テレポートフラグを追加する
装備した武器の捨てる→再装備を繰り返していると「完全にシミュレートされたスケルタルメッシュ ItemMesh を移動しようとしています。テレポートフラグを使用してください」というエラーメッセージが出てきます。このバグを修正するには、Weapon.cppのThrowWeapon関数にTeleportフラグを追加する必要があります。
GetItemMesh()->SetWorldRotation(MeshRotation, false, nullptr, ETeleportType::TeleportPhysics);
Tick関数を以下のように書き換える必要があります。
void AWeapon::Tick(float DeltaTime) { Super::Tick(DeltaTime); if (WeaponState == EWeaponState::EWS_Falling && bFalling) { const FRotator MeshRotation{ GetItemMesh()->GetComponentRotation().Pitch, GetItemMesh()->GetComponentRotation().Yaw, GetItemMesh()->GetComponentRotation().Roll }; GetItemMesh()->SetWorldRotation(MeshRotation, false, nullptr, ETeleportType::TeleportPhysics); } }
コメント