導入:世界を「壊せる」ようにするということ
ゲームの没入感を高める最大の要素の一つは、プレイヤーの行動に対する「世界の反応」です。特にアクションゲームにおいて、置かれている木箱を壊せるか、ただの背景かという違いは、プレイ体験の密度に直結します。 今回は、UE5 の新世代物理エンジン「Chaos」を活用し、単に消えるだけではない、物理的にリアリティのある破壊表現の実装に挑戦しました。

Chaos 破砕:Geometry Collection の活用
破壊可能なオブジェクト(ADestructibleCrate)の実装では、UE5 の Geometry Collection を使用しました。 ヘルスが 0 になった瞬間に Static Mesh を非表示にし、事前に破砕設定を施した Geometry Collection をシミュレート物理として出現させます。ここで重要なのは、単に物理を ON にするだけでなく、「確実に粉々にする」ための力(Impulse)を加えることです。
// ダメージを受けて破壊される際の処理(C++)
void ADestructibleCrate::DestroyCrate() {
if (bIsDestroyed) return;
bIsDestroyed = true;
// 通常のメッシュを隠し、破砕用コンポーネントを表示
CrateMesh->SetVisibility(false);
GeometryCollection->SetVisibility(true, true);
GeometryCollection->SetSimulatePhysics(true);
// 指定した半径内に巨大なダメージを与え、意図的に粉砕を「誘発」させる
UGameplayStatics::ApplyRadialDamage(
GetWorld(), 1000000.0f, GetActorLocation(), 50.0f, nullptr, {}, this
);
// さらに上方へ突き上げるようなインパルスを加え、飛び散り方を演出
GeometryCollection->AddImpulse(FVector(0, 0, 500.0f), NAME_None, true);
}動的なギミック:移動プラットフォームの制御
一方で、ピラミッド探索を奥深くするために「移動リフト」も実装しました。 これは単純な `Tick` による座標更新ですが、工夫したのは「誤差の蓄積への対策」です。単に速度を掛けて進ませるだけでは、浮動小数点の計算誤差で数時間後には位置がズレてしまいます。周期ごとに計算上の「開始地点」をリセットすることで、安定した往復運動を実現しました。
// Tick内での移動制御
void AMovingPlatform::Tick(float DeltaTime) {
FVector CurrentLocation = GetActorLocation();
CurrentLocation += (MoveVelocity * DeltaTime);
SetActorLocation(CurrentLocation);
float DistanceMoved = FVector::Dist(StartLocation, CurrentLocation);
if (DistanceMoved >= MoveDistance) {
// 境界を越えたら、基準点を正確に移動させて誤差をリセット
FVector MoveDirection = MoveVelocity.GetSafeNormal();
StartLocation = StartLocation + (MoveDirection * MoveDistance);
SetActorLocation(StartLocation);
// 進行方向を反転
MoveVelocity = -MoveVelocity;
}
}今後の展望:ゲームプレイと演出の融合
今回の実装により、世界に対する攻撃(破壊)と、世界の中での移動(リフト)という二つの基本要素が揃いました。 今後はこれらを組み合わせ、特定のスイッチを押すと扉が開く、あるいは特定のオブジェクトを破壊すると道が拓けるといった、よりパズル要素の強いゲームプレイへと拡張していく予定です。UE5 の C++ 開発は、エンジンの深層まで手が届くため、独自のロジックを組む楽しさを再認識しています。

