2022年6月23日木曜日

UE5のTopDownがAndroidでタッチした箇所に移動しない

[UnrealEngine5.0.2][Windows11]で確認

UE5のサンプルTopDownテンプレートが、Androidだとタッチした箇所に移動しなかった。

タッチした方向には移動します。


調査して対応してみました。

C++版で確認しています。プロジェクト名はTopDownTestにしています。


TopDownTestPlayerController.h
FVector HitTouchLocation; を追加。

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Templates/SubclassOf.h"
#include "GameFramework/PlayerController.h"
#include "TopDownTestPlayerController.generated.h"

/** Forward declaration to improve compiling times */
class UNiagaraSystem;

UCLASS()
class ATopDownTestPlayerController : public APlayerController
{
	GENERATED_BODY()

public:
	ATopDownTestPlayerController();

	/** Time Threshold to know if it was a short press */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input)
	float ShortPressThreshold;

	/** FX Class that we will spawn when clicking */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input)
	UNiagaraSystem* FXCursor;

protected:
	/** True if the controlled character should navigate to the mouse cursor. */
	uint32 bMoveToMouseCursor : 1;

	// Begin PlayerController interface
	virtual void PlayerTick(float DeltaTime) override;
	virtual void SetupInputComponent() override;
	// End PlayerController interface

	/** Input handlers for SetDestination action. */
	void OnSetDestinationPressed();
	void OnSetDestinationReleased();
	void OnTouchPressed(const ETouchIndex::Type FingerIndex, const FVector Location);
	void OnTouchReleased(const ETouchIndex::Type FingerIndex, const FVector Location);

private:
	bool bInputPressed; // Input is bring pressed
	bool bIsTouch; // Is it a touch device
	float FollowTime; // For how long it has been pressed

	FVector HitTouchLocation;	// PlayerTickで保存する
};


TopDownTestPlayerController.cpp
PlayerTickに Hit.Location を HitTouchLocation に保存する処理を追加。
OnSetDestinationReleased に HitTouchLocation を 参照する処理を追加。
OnTouchReleasedで bIsTouch = false; を下へずらす。
今回は暫定対応ですが、本格的に対応するなら bIsTouch の代わりにフラグを別に用意する等の対応をしたがほういいかも。

// Copyright Epic Games, Inc. All Rights Reserved.

#include "TopDownTestPlayerController.h"
#include "GameFramework/Pawn.h"
#include "Blueprint/AIBlueprintHelperLibrary.h"
#include "NiagaraSystem.h"
#include "NiagaraFunctionLibrary.h"
#include "TopDownTestCharacter.h"
#include "Engine/World.h"

#include "Kismet/KismetSystemLibrary.h"

ATopDownTestPlayerController::ATopDownTestPlayerController()
{
	bShowMouseCursor = true;
	DefaultMouseCursor = EMouseCursor::Default;
}

void ATopDownTestPlayerController::PlayerTick(float DeltaTime)
{
	Super::PlayerTick(DeltaTime);

	if(bInputPressed)
	{
		FollowTime += DeltaTime;

		// Look for the touch location
		FVector HitLocation = FVector::ZeroVector;
		FHitResult Hit;
		if(bIsTouch)
		{
			GetHitResultUnderFinger(ETouchIndex::Touch1, ECC_Visibility, true, Hit);
#if 0	// FollowTimeやタッチした座標を表示する。
			{
				//	UKismetSystemLibrary::PrintString(this, "C++ Hello World!", true, true, FColor::Cyan, 2.f);
				FString Str = FString::SanitizeFloat(FollowTime);
				UKismetSystemLibrary::PrintString(this, Str, true, true, FColor::Green, 5.f);
				FString Str2 = FString::SanitizeFloat(Hit.Location.X) + FString(" ") + FString::SanitizeFloat(Hit.Location.Y) + FString(" ") + FString::SanitizeFloat(Hit.Location.Z);
				UKismetSystemLibrary::PrintString(this, Str2, true, true, FColor::Green, 5.f);
			}
#endif
			HitTouchLocation = Hit.Location;	// Released時に使うために保存する。
		}
		else
		{
			GetHitResultUnderCursor(ECC_Visibility, true, Hit);
		}
		HitLocation = Hit.Location;

		// Direct the Pawn towards that location
		APawn* const MyPawn = GetPawn();
		if(MyPawn)
		{
			FVector WorldDirection = (HitLocation - MyPawn->GetActorLocation()).GetSafeNormal();
			MyPawn->AddMovementInput(WorldDirection, 1.f, false);
		}
	}
	else
	{
		FollowTime = 0.f;
	}
}

void ATopDownTestPlayerController::SetupInputComponent()
{
	// set up gameplay key bindings
	Super::SetupInputComponent();

	InputComponent->BindAction("SetDestination", IE_Pressed, this, &ATopDownTestPlayerController::OnSetDestinationPressed);
	InputComponent->BindAction("SetDestination", IE_Released, this, &ATopDownTestPlayerController::OnSetDestinationReleased);

	// support touch devices 
	InputComponent->BindTouch(EInputEvent::IE_Pressed, this, &ATopDownTestPlayerController::OnTouchPressed);
	InputComponent->BindTouch(EInputEvent::IE_Released, this, &ATopDownTestPlayerController::OnTouchReleased);

}

void ATopDownTestPlayerController::OnSetDestinationPressed()
{
	// We flag that the input is being pressed
	bInputPressed = true;
	// Just in case the character was moving because of a previous short press we stop it
	StopMovement();
}

void ATopDownTestPlayerController::OnSetDestinationReleased()
{
	// Player is no longer pressing the input
	bInputPressed = false;

	// If it was a short press
	if(FollowTime <= ShortPressThreshold)
	{
		// We look for the location in the world where the player has pressed the input
		FVector HitLocation = FVector::ZeroVector;
		FHitResult Hit;

		if (bIsTouch)
		{
// タッチの場合、Releaseされた後だとHit.Locationは(0.0f, 0.0f, 0.0f)となるので、
			//GetHitResultUnderFinger(ETouchIndex::Touch1, ECC_Visibility, true, Hit);
			//HitLocation = Hit.Location;
// PlayerTickで保存しておいたのものを使う。
			HitLocation = HitTouchLocation;
		}
		else
		{
			GetHitResultUnderCursor(ECC_Visibility, true, Hit);
			HitLocation = Hit.Location;
		}

		// We move there and spawn some particles
		UAIBlueprintHelperLibrary::SimpleMoveToLocation(this, HitLocation);
		UNiagaraFunctionLibrary::SpawnSystemAtLocation(this, FXCursor, HitLocation, FRotator::ZeroRotator, FVector(1.f, 1.f, 1.f), true, true, ENCPoolMethod::None, true);
	}
}

void ATopDownTestPlayerController::OnTouchPressed(const ETouchIndex::Type FingerIndex, const FVector Location)
{
	bIsTouch = true;
	OnSetDestinationPressed();
}

void ATopDownTestPlayerController::OnTouchReleased(const ETouchIndex::Type FingerIndex, const FVector Location)
{
//	bIsTouch = false;
	OnSetDestinationReleased();
	bIsTouch = false;	// OnSetDestinationReleased()でHitTouchLocationを参照させるため、ここへずらす。
	// 今回は暫定対応ですが、本格的に対応するならフラグを別に用意する等の対応をしたがほういいかも。
}

コンソールコマンド「ToggleDebugCamera」デバッグカメラ(フリーカメラ)

  [UnrealEngine5.2.1][Windows11]で確認  コンソールコマンド「ToggleDebugCamera」デバッグカメラ(フリーカメラ)になる。 UE5 大雑把にフリーカメラを使う方法