Skip to content

Instantly share code, notes, and snippets.

@JoernSchoenyan
Created December 24, 2023 20:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoernSchoenyan/cd52e73b25a2feeaa9cd3929164dd4f1 to your computer and use it in GitHub Desktop.
Save JoernSchoenyan/cd52e73b25a2feeaa9cd3929164dd4f1 to your computer and use it in GitHub Desktop.
UE5, base for an interaction system similar to Skyrim
// Fill out your copyright notice in the Description page of Project Settings.
#include "Interfaces/Interactible.h"
// Add default functionality here for any IInteractible functions that are not pure virtual.
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "Interactible.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UInteractible : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class RPG_API IInteractible
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
virtual void Interact() = 0;
virtual void SetHighlight() = 0;
virtual void ClearHighlight() = 0;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "Items/Item.h"
// Sets default values
AItem::AItem()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
void AItem::Interact()
{
}
void AItem::SetHighlight()
{
UStaticMeshComponent* InteractibleMesh = Cast<UStaticMeshComponent>(this->GetComponentByClass(UStaticMeshComponent::StaticClass()));
if (InteractibleMesh)
{
UMaterialInterface* Material = LoadObject<UMaterialInterface>(nullptr, TEXT("/Script/Engine.Material'/Game/_RPG/Materials/MAT_Outline.MAT_Outline'"));
InteractibleMesh->SetOverlayMaterial(Material);
}
}
void AItem::ClearHighlight()
{
UStaticMeshComponent* StaticMeshComponent = Cast<UStaticMeshComponent>(this->GetComponentByClass(UStaticMeshComponent::StaticClass()));
if (StaticMeshComponent)
{
StaticMeshComponent->SetOverlayMaterial(nullptr);
}
}
// Called when the game starts or when spawned
void AItem::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AItem::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Interfaces/Interactible.h"
#include "Item.generated.h"
UCLASS()
class RPG_API AItem : public AActor, public IInteractible
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AItem();
virtual void Interact() override;
virtual void SetHighlight() override;
virtual void ClearHighlight() override;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "Characters/PlayerCharacter.h"
#include "Interfaces/Interactible.h"
#include "Kismet/GameplayStatics.h"
APlayerCharacter::APlayerCharacter()
{
PrimaryActorTick.bCanEverTick = true;
PlayerCameraManager = UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0);
}
void APlayerCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
FVector CameraLocation = PlayerCameraManager->GetCameraLocation();
FVector ForwardVector = PlayerCameraManager->GetActorForwardVector();
FVector LineTraceEnd = CameraLocation + ForwardVector * 600.f;
FHitResult HitResult;
FCollisionQueryParams CollisionParams;
CollisionParams.AddIgnoredActor(this);
GetWorld()->LineTraceSingleByChannel(
HitResult,
CameraLocation,
LineTraceEnd,
ECollisionChannel::ECC_Visibility,
CollisionParams
);
AActor* Actor = HitResult.GetActor();
if (Actor && Cast<IInteractible>(Actor))
{
if (InteractibleActor == Actor)
{
return;
}
if (InteractibleActor)
{
IInteractible* Interactible = Cast<IInteractible>(InteractibleActor);
Interactible->ClearHighlight();
}
InteractibleActor = Actor;
IInteractible* Interactible = Cast<IInteractible>(InteractibleActor);
Interactible->SetHighlight();
HandleCanInteractEvent();
}
else
{
if (InteractibleActor)
{
UStaticMeshComponent* InteractibleMesh = Cast<UStaticMeshComponent>(InteractibleActor->GetComponentByClass(UStaticMeshComponent::StaticClass()));
if (InteractibleMesh)
{
InteractibleMesh->SetOverlayMaterial(nullptr);
}
}
InteractibleActor = nullptr;
HandleCanNotInteractEvent();
}
}
void APlayerCharacter::HandleCanInteractEvent()
{
OnCanInteract.Broadcast();
}
void APlayerCharacter::HandleCanNotInteractEvent()
{
OnCanNotInteract.Broadcast();
}
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Characters/RPGCharacter.h"
#include "Delegates/Delegate.h"
#include "PlayerCharacter.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnCanInteract);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnCanNotInteract);
class APlayerCameraManager;
/**
*
*/
UCLASS()
class RPG_API APlayerCharacter : public ARPGCharacter
{
GENERATED_BODY()
UPROPERTY(VisibleAnywhere)
TObjectPtr<APlayerCameraManager> PlayerCameraManager;
public:
APlayerCharacter();
virtual void Tick(float DeltaTime) override;
UPROPERTY(BlueprintAssignable, Category = "Interaction")
FOnCanInteract OnCanInteract;
UPROPERTY(BlueprintAssignable, Category = "Interaction")
FOnCanNotInteract OnCanNotInteract;
protected:
TObjectPtr<AActor> InteractibleActor;
UFUNCTION()
void HandleCanInteractEvent();
UFUNCTION()
void HandleCanNotInteractEvent();
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment