How to make lyra starter game first person?

hello i am trying to turn the lyra sample game a first person shooter but I have an issue where the camera seems to move behind the character when you look down

i replaced the mannequin with a metahuman (it messed up the gun holding but oh well) then i hid the face when player controlled and changed the x&y camera offset curves to 0, which kinda works (you have to look down and then up again for some reason tho):


however when you continue to look down it looks like this:

i dont understand why its doing this, i set up a print string on tick for the camera position, and it changes when you just move the mouse, not just rotates. i looked in camera and input blueprints and c++ classes for where the camera position would change but didnt find anything. i thought maybe it was the camera penetration prevention system but disabling that didnt help

any other ideas??

1 Like

Ive been wanting to do the same thing. Did you get this working?

no i gave up

I am progressing on this. I customized the Cosmetic system with a perspective based version where the controller only adds the Subjective cosmetics (Third person) on the server and the remote clients ( And the owning client if in third person ).

Then there is an ObjectiveProxyCosmeticsComponent that lives on the owning client pawn that manage the objective perspective cosmetics (First Person) with their own list of Child Actor Components.

To setup those to use the related character parts for each perspective, i did it through what i called a PerspectiveCharacterPartCosmeticSet that will declare two related Character Part to apply on both perspective.

Its still in the work so if there is someone interested in this i can give you some updates as i work on it.

1 Like

im interested, let me know if you get it working without the issue i had, good luck

3 Days pass :stuck_out_tongue: Curious on anyone’s progress on this

no progress from me, there was a lyra q&a stream yesterday where they talked about making it first person, but as far as i can see (recording skips around a lot tho) they just said update the camera curves and make custom animations but didnt address the looking down issue

I mean, it probably comes down to fundamentally changing how the camera setup is TBH (cause control rotation be weird with this setup currenlty). There are different approaches to make a FPS cam: Have 1st and 3rd person mesh approach, or the TrueFPS route which the camera prolly needs to be attached to the head bone and adjustments that way too.

At the end of the day, A lotta people want to mod it to do different game types (ARPG, FPS, etc.) … but it seems it’s a bit in discovery mode to understand how to approach different funamentals with doing so. It’s a top down approach to visualizing it (starting with each LyraExperienceDefinition and seeing all of the asset stuff from there). Would love to see a more… comprehensive breakdown on the Setup and engineering side more :confused: . But, for starters, I guess one coulllddd make a child of LyraCameraMode to see if they can adjust it to make that work accordingly for the FPS camera

One thing to note is that the way the animation blueprint works is much different than I’m used to (in UE4). There’s a “linked-layer” mechanic that allows the animations to be injected via other blueprints associated with the character (in this case, the weapons happen to contain the character animations). This proved to be a problem because I tried “hiding the mesh from the owner” and doing a split-body style approach (like the original ShooterGame), but I ended up with a permanent T-Pose.

i tried making a child of lyracameramode like you suggested chad but the weird camera movement on rotation doesnt seem to happen there, i logged the location on update. commenting out the penetration prevention and target offset code there didnt help either

To make a “true” first person camera you need to make a c++ child class of LyraCameraMode. I called mine LyraCameraMode_FirstPerson to keep with the naming they had established for third person and top down. I also chose to create it in the ShooterCore game feature similar to what was done with the Top Down Arena camera mode in that game feature plugin. In the new child class, you need to override GetPivotLocation() and in the overridden function you need to get and return the head bone location. I took some code from the ThirdPerson c++ class and modified it as a test.

In my LyraCameraMode_FirstPerson .h

protected:
	virtual FVector GetPivotLocation() const override;

In my LyraCameraMode_FirstPerson .cpp

FVector ULyraCameraMode_FirstPerson::GetPivotLocation() const
{
	const AActor* TargetActor = GetTargetActor();
	check(TargetActor);

	if (const APawn* TargetPawn = Cast<APawn>(TargetActor))
	{
		// Get mesh socket location for head bone
		if (const ACharacter* TargetCharacter = Cast<ACharacter>(TargetPawn))
		{
			return TargetCharacter->GetMesh()->GetSocketLocation("head");
		}

		return TargetPawn->GetPawnViewLocation();
	}

	return TargetActor->GetActorLocation();

}

Make sure you also add 2 includes into your .cpp file:

#include “GameFramework/Pawn.h”
#include “GameFramework/Character.h”

After you have compiled and can see your class in blueprints, you can then create a child blueprint (I called mine CM_FirstPerson).

Next, open the HeroData_ShooterGame file and change the Camera-> Default Camera Mode to the new CM_FirstPerson.

Press play and you’ll have a first person camera attached to the head bone of the skeleton.

To adjust the aim down sights, you’ll need to create another child blueprint of the LyraCameraMode (I called mine CM_FirstPersonADS) and adjust the FOV to something slightly smaller for mild zoom effect.

Then you will need to edit the GA_ADS blueprint in ShooterCore Content->Input>Abilities and have the ADS ability call the CM_FirstPersonADS file you just created. Compile, save and play.

There is additional work needed if you want to use offsets, curves, etc., this is just the most basic setup to get a “true” FPS camera that I was playing around with.

Major props to LFA on YouTube for the inspiration I got after watching their video on first person for Lyra.

6 Likes

it works! thank you so much!

2 Likes

Hi Kromtak,

Thanks for the details it works! Im trying to set up the ADS similar to most first person shooters i think they do it by fixing the camera to a weapon socket. Do you have any ideas around this. Thanks

Hi can you post the code how you have got it layed out for both .h and .cpp files for the First-person. Mine keeps crashing. Thanks

there are probably useless lines in this code but heres what i have that worked for me

LyraCameraMode_FirstPerson.h:

#pragma once

#include "CoreMinimal.h"
#include "LyraCameraMode.h"
#include "Curves/CurveFloat.h"
#include "LyraPenetrationAvoidanceFeeler.h"
#include "DrawDebugHelpers.h"
#include "LyraCameraMode_FirstPerson.generated.h"

class UCurveVector;

UCLASS(Abstract, Blueprintable)
class ULyraCameraMode_FirstPerson : public ULyraCameraMode
{
	GENERATED_BODY()

public:

	ULyraCameraMode_FirstPerson();

protected:

	virtual FVector GetPivotLocation() const override;

	virtual void UpdateView(float DeltaTime) override;

	void UpdateForTarget(float DeltaTime);
	void UpdatePreventPenetration(float DeltaTime);
	void PreventCameraPenetration(class AActor const& ViewTarget, FVector const& SafeLoc, FVector& CameraLoc, float const& DeltaTime, float& DistBlockedPct, bool bSingleRayOnly);

	virtual void DrawDebug(UCanvas* Canvas) const override;

protected:

	UPROPERTY(EditDefaultsOnly, Category = "First Person", Meta = (EditCondition = "!bUseRuntimeFloatCurves"))
	const UCurveVector* TargetOffsetCurve;

	UPROPERTY(EditDefaultsOnly, Category = "First Person")
	bool bUseRuntimeFloatCurves;

	UPROPERTY(EditDefaultsOnly, Category = "First Person", Meta = (EditCondition = "bUseRuntimeFloatCurves"))
	FRuntimeFloatCurve TargetOffsetX;

	UPROPERTY(EditDefaultsOnly, Category = "First Person", Meta = (EditCondition = "bUseRuntimeFloatCurves"))
	FRuntimeFloatCurve TargetOffsetY;

	UPROPERTY(EditDefaultsOnly, Category = "First Person", Meta = (EditCondition = "bUseRuntimeFloatCurves"))
	FRuntimeFloatCurve TargetOffsetZ;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "First Person")
	float CrouchOffsetBlendMultiplier = 5.0f;

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Collision")
	float PenetrationBlendInTime = 0.1f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Collision")
	float PenetrationBlendOutTime = 0.15f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Collision")
	bool bPreventPenetration = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Collision")
	bool bDoPredictiveAvoidance = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Collision")
	float CollisionPushOutDistance = 2.f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Collision")
	float ReportPenetrationPercent = 0.f;

	UPROPERTY(EditDefaultsOnly, Category = "Collision")
	TArray<FLyraPenetrationAvoidanceFeeler> PenetrationAvoidanceFeelers;

	UPROPERTY(Transient)
	float AimLineToDesiredPosBlockedPct;

	UPROPERTY(Transient)
	TArray<TObjectPtr<const AActor>> DebugActorsHitDuringCameraPenetration;

#if ENABLE_DRAW_DEBUG
	mutable float LastDrawDebugTime = -MAX_FLT;
#endif

protected:
	
	void SetTargetCrouchOffset(FVector NewTargetOffset);
	void UpdateCrouchOffset(float DeltaTime);

	FVector InitialCrouchOffset = FVector::ZeroVector;
	FVector TargetCrouchOffset = FVector::ZeroVector;
	float CrouchOffsetBlendPct = 1.0f;
	FVector CurrentCrouchOffset = FVector::ZeroVector;
	
};

LyraCameraMode_FirstPerson.cpp:

#include "LyraCameraMode_FirstPerson.h"
#include "Curves/CurveVector.h"
#include "Engine/Canvas.h"
#include "GameFramework/CameraBlockingVolume.h"
#include "LyraCameraAssistInterface.h"
#include "GameFramework/Controller.h"
#include "GameFramework/Character.h"
#include "GameFramework/Pawn.h"

namespace LyraCameraMode_FirstPerson_Statics
{
	static const FName NAME_IgnoreCameraCollision = TEXT("IgnoreCameraCollision");
}

ULyraCameraMode_FirstPerson::ULyraCameraMode_FirstPerson()
{
	TargetOffsetCurve = nullptr;
}

void ULyraCameraMode_FirstPerson::UpdateView(float DeltaTime)
{
	UpdateForTarget(DeltaTime);
	UpdateCrouchOffset(DeltaTime);

	FVector PivotLocation = GetPivotLocation() + CurrentCrouchOffset;
	FRotator PivotRotation = GetPivotRotation();

	PivotRotation.Pitch = FMath::ClampAngle(PivotRotation.Pitch, ViewPitchMin, ViewPitchMax);

	View.Location = PivotLocation;
	View.Rotation = PivotRotation;
	View.ControlRotation = View.Rotation;
	View.FieldOfView = FieldOfView;
}

void ULyraCameraMode_FirstPerson::UpdateForTarget(float DeltaTime)
{

	if (const ACharacter* TargetCharacter = Cast<ACharacter>(GetTargetActor()))
	{
		if (TargetCharacter->bIsCrouched)
		{
			const ACharacter* TargetCharacterCDO = TargetCharacter->GetClass()->GetDefaultObject<ACharacter>();
			const float CrouchedHeightAdjustment = TargetCharacterCDO->CrouchedEyeHeight - TargetCharacterCDO->BaseEyeHeight;

			SetTargetCrouchOffset(FVector(0.f, 0.f, CrouchedHeightAdjustment));

			return;
		}
	}

	SetTargetCrouchOffset(FVector::ZeroVector);
}

void ULyraCameraMode_FirstPerson::DrawDebug(UCanvas* Canvas) const
{
	Super::DrawDebug(Canvas);

#if ENABLE_DRAW_DEBUG
	FDisplayDebugManager& DisplayDebugManager = Canvas->DisplayDebugManager;
	for (int i = 0; i < DebugActorsHitDuringCameraPenetration.Num(); i++)
	{
		DisplayDebugManager.DrawString(
			FString::Printf(TEXT("HitActorDuringPenetration[%d]: %s")
				, i
				, *DebugActorsHitDuringCameraPenetration[i]->GetName()));
	}

	LastDrawDebugTime = GetWorld()->GetTimeSeconds();
#endif
}

void ULyraCameraMode_FirstPerson::UpdatePreventPenetration(float DeltaTime)
{
}

void ULyraCameraMode_FirstPerson::PreventCameraPenetration(class AActor const& ViewTarget, FVector const& SafeLoc, FVector& CameraLoc, float const& DeltaTime, float& DistBlockedPct, bool bSingleRayOnly)
{
}

void ULyraCameraMode_FirstPerson::SetTargetCrouchOffset(FVector NewTargetOffset)
{
}


void ULyraCameraMode_FirstPerson::UpdateCrouchOffset(float DeltaTime)
{
}

FVector ULyraCameraMode_FirstPerson::GetPivotLocation() const
{
	const AActor* TargetActor = GetTargetActor();
	check(TargetActor);

	if (const APawn* TargetPawn = Cast<APawn>(TargetActor))
	{
		// Get mesh socket location for head bone
		if (const ACharacter* TargetCharacter = Cast<ACharacter>(TargetPawn))
		{
			return TargetCharacter->GetMesh()->GetSocketLocation("head");
		}

		return TargetPawn->GetPawnViewLocation();
	}

	return TargetActor->GetActorLocation();

}
1 Like

Thanks for the speedy reply i have been on it all day i will give that ago. In regards to making the child of ‘LyracameraMode’ did you do this from inside unreal engine then move to visal or copy the files in visal code.

1 Like

i made those files in visual studio, and then i reopened ue and right clicked an empty space in the content browser and clicked add blueprint and selected lyracameramode_firstperson

Thanks. It strange i still get the crash when i enter a game