【UEFN】 DiabloライクのTop-DownViewカメラを作る Part.2(Verseの学習④)
カメラ方向と操作方向が一致したTop-Down Viewカメラを作る
前回紹介したTop-Down View カメラはカメラ方向と操作方向が一致していない場合に、非常に操作が行いづらいという欠点がありました。
そこで、前回のものを改修して、プレイヤーの向きにカメラが追従するように変更します。
イメージとしてはこのような形になります。
改修方針
- 親となっているオブジェクト(図のNullProp)の位置をプレイヤーの位置と一致させるように動かします。(A)
- カメラのオフセットは親からの相対座標として与えておきます。(B)
- プレイヤーの視点移動に合わせて、親となっているオブジェクトのYaw角を動かします。(A)
- ジャンプした際に、カメラ方向と操作方向を一致させるようにします。(常に一致させることも可能ですが、ゲーム性としてジャンプした際のみに一致させる方針で進めます)
シーン準備
前回と同一のものを使用し、カメラオフセット(上記図のB)は変更しておきます。
Verse Code
改修したコードは以下のようになります。
using { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } using { /Fortnite.com/Characters } using { /UnrealEngine.com/Temporary/SpatialMath } using { /Fortnite.com/Characters } # A Verse-authored creative device that can be placed in a level track_player_manager := class(creative_device): @editable _CameraRoot: creative_prop = creative_prop{} @editable _OtherRoot: creative_prop = creative_prop{} @editable _OffsetX : float = 0.0 @editable _OffsetY : float = 0.0 @editable _OffsetZ : float = 0.0 var _CurrentRotation : rotation = rotation{} ### OnBegin OnBegin<override>()<suspends>:void= Offset:vector3 = vector3{X:=_OffsetX, Y:=_OffsetY, Z:=_OffsetZ} ## add jumped event Players : []player = GetPlayspace().GetPlayers() if(Player : player = Players[0]): if(FortniteCharacter : fort_character = Player.GetFortCharacter[]): FortniteCharacter.JumpedEvent().Subscribe(OnPlayerJumped) UpdateRotationValue() ## start update loop spawn{UpdateTargetPosition(Offset)} ### process for jump OnPlayerJumped(the_player:fort_character):true= UpdateRotationValue() ### update rotation value UpdateRotationValue():void= Players : []player = GetPlayspace().GetPlayers() if(Player : player = Players[0]): if(FortniteCharacter : fort_character = Player.GetFortCharacter[]): ### Not Good #var playerRotation : rotation = FortniteCharacter.GetTransform().Rotation ### Good var viewRotation : rotation = FortniteCharacter.GetViewRotation() var angles :[]float = viewRotation.GetYawPitchRollDegrees() if(angleYaw := angles[0]): anglePitch := 0.0 angleRoll := 0.0 targetRotation := MakeRotationFromYawPitchRollDegrees(angleYaw, anglePitch, angleRoll) set _CurrentRotation = _CurrentRotation.RotateBy(MakeShortestRotationBetween(_CurrentRotation, targetRotation)) ### Loop Process UpdateTargetPosition(Offset:vector3)<suspends>:void= loop: ## get player and player position Players : []player = GetPlayspace().GetPlayers() if(Player : player = Players[0]): if(FortniteCharacter : fort_character = Player.GetFortCharacter[]): PlayerPosition : vector3 = FortniteCharacter.GetTransform().Translation ## add rotation PlayerRotation : rotation = FortniteCharacter.GetTransform().Rotation ## first rotation TargetPositionX : float = PlayerPosition.X TargetPositionY : float = PlayerPosition.Y TargetPositionZ : float = PlayerPosition.Z TargetPosition:vector3 = vector3{X:=TargetPositionX, Y:=TargetPositionY, Z:=TargetPositionZ} + Offset ## move target to player position _CameraRoot.MoveTo(TargetPosition, _CurrentRotation, 0.5) _OtherRoot.MoveTo(TargetPosition, IdentityRotation(), 0.5) # Not Good # if(_CameraRoot.TeleportTo[TargetPosition, IdentityRotation()]): # void Sleep(0.5) # Not Good # Sleep(0.0)
コード解説します。 CameraRootは上記図で言うNullPropをセットする場所です。 OtherRootを今回追加しています。これは、回転を適用せずにプレイヤーに追従してほしいものを入れるために用意しました。 自分の作例では、ライトを入れています。(ライトは回転させたくないため)
@editable _CameraRoot: creative_prop = creative_prop{} @editable _OtherRoot: creative_prop = creative_prop{}
_CurrentRotationに計算した回転量を保持していきます。
var _CurrentRotation : rotation = rotation{}
プレイヤーがジャンプした際に、回転量計算が発生するようにしています。
FortniteCharacter.JumpedEvent().Subscribe(OnPlayerJumped) ... OnPlayerJumped(the_player:fort_character):true= UpdateRotationValue()
UpdateRotationValueが回転量計算の部分になります。
今回の一番のポイントはここです。
### Not Good #var playerRotation : rotation = FortniteCharacter.GetTransform().Rotation ### Good var viewRotation : rotation = FortniteCharacter.GetViewRotation()
プレイヤーに追従させたいのでプレイヤーの回転をとってしまいそうなところですが、それではうまくいきません。実際の操作は視点の方向と一致する必要があるため、視点の回転情報を取得する必要があります。
Fortniteは3人称ゲームのため、キャラクターの方向と視点の方向が一致していません。
Yaw角だけを取り出して回転情報を作ります。現在の回転との差分を出し、時計回りと半時計回りで近い方向に回るようにしています。
var angles :[]float = viewRotation.GetYawPitchRollDegrees() if(angleYaw := angles[0]): anglePitch := 0.0 angleRoll := 0.0 targetRotation := MakeRotationFromYawPitchRollDegrees(angleYaw, anglePitch, angleRoll) set _CurrentRotation = _CurrentRotation.RotateBy(MakeShortestRotationBetween(_CurrentRotation, targetRotation))
ここで出来た回転情報を使用してMoveTo関数を利用します。
_CameraRoot.MoveTo(TargetPosition, _CurrentRotation, 0.5)
_OtherRootは回転はせず位置だけ追従させるので前回と同様です。
デバイス設定
デバイス設定は以下のようになります。 _OtherRootはここではセットしていませんが、実際はライトのためのRootオブジェクトをセットしています。
まとめ
今回の結果はこのような形になります。
視点方向とカメラ方向が一致したため、感覚的に操作が行えるようになりました。
また、ジャンプで回転というゲーム性も出たため、なかなかいいように思います。
EpicのDevCommunityで今回のコードをSnippetとして投稿しておきました。
https://dev.epicgames.com/community/snippets/xve/fortnite-top-down-view-support-device
この情報が皆さんの参考になれば幸いです。
今後もさまざまな情報を発信していきますので、Twitterフォローしていただけると嬉しいです。 twitter.com
UEFN楽しい:)