[박치영] 충돌 및 히트판정 작업 중

main
PCYPC\pcy35 2023-08-02 21:37:10 +09:00
parent 4a9c04e1ca
commit bb659ad091
18 changed files with 224 additions and 27 deletions

View File

@ -31,6 +31,14 @@ void ABaseEquippable::AttachActor(const FName SocketName)
}
}
UPrimitiveComponent* ABaseEquippable::GetItemMesh()
{
if (IsValid(ItemStaticMesh->GetStaticMesh()))
return ItemStaticMesh;
else
return ItemSkeletalMesh;
}
void ABaseEquippable::OnEquipped()
{
SetIsEquipped(true);

View File

@ -18,6 +18,7 @@ public:
public:
UFUNCTION(BlueprintCallable)
virtual void AttachActor(const FName SocketName);
UPrimitiveComponent* GetItemMesh();
virtual void OnEquipped();
virtual void OnUnequipped();
virtual void SetIsEquipped(bool IsEquipped);

View File

@ -4,11 +4,22 @@
#include "Actor/BaseWeapon.h"
#include "Components/CombatComponent.h"
#include "GameFramework/Character.h"
#include "Components/CollisionComponent.h"
#include "Interface/CombatInterface.h"
#include "Kismet/GameplayStatics.h"
ABaseWeapon::ABaseWeapon()
{
CollisionComponent = CreateDefaultSubobject<UCollisionComponent>(TEXT("CollisionComponent"));
CollisionComponent->OnHitDelegate.BindUObject(this, &ABaseWeapon::OnHit);
CollisionComponent->SetTraceRaius(20.f);
CollisionComponent->SetStartSocketName(TEXT("WeaponStart"));
CollisionComponent->SetEndSocketName(TEXT("WeaponEnd"));
TArray<TEnumAsByte<EObjectTypeQuery>> InputCollisionObjectTypes;
InputCollisionObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECollisionChannel::ECC_Pawn));
CollisionComponent->SetCollisionObjectTypes(InputCollisionObjectTypes);
CollisionComponent->SetDrawDebugType(EDrawDebugTrace::None);
}
void ABaseWeapon::OnEquipped()
@ -30,17 +41,23 @@ void ABaseWeapon::OnEquipped()
UCombatAnimInstance* animInstance = Cast<UCombatAnimInstance>(character->GetMesh()->GetAnimInstance());
animInstance->UpdateCombatType(CombatType);
}
CollisionComponent->SetCollisionMeshComponent(GetItemMesh());
CollisionComponent->AddActorToIgnore(GetOwner());
}
void ABaseWeapon::OnHit(FHitResult hitResult)
{
//float UGameplayStatics::ApplyPointDamage(
// AActor * DamagedActor, float BaseDamage, FVector const& HitFromDirection,
// FHitResult const& HitInfo, AController * EventInstigator, AActor * DamageCauser,
// TSubclassOf<UDamageType> DamageTypeClass)
if (true) // TODO : Interface CanReceiveDamage
ICombatInterface* pActor = Cast<ICombatInterface>(hitResult.GetActor());
if (pActor)
{
UGameplayStatics::ApplyPointDamage(hitResult.GetActor(), Damage, GetOwner()->GetActorForwardVector(), hitResult, GetInstigatorController(), this, TSubclassOf<UDamageType>(UDamageType::StaticClass()));
if (pActor->Execute_CanReceiveDamage(hitResult.GetActor()))
UGameplayStatics::ApplyPointDamage(hitResult.GetActor(), Damage, GetOwner()->GetActorForwardVector(), hitResult, GetInstigatorController(), this, TSubclassOf<UDamageType>(UDamageType::StaticClass()));
}
}
void ABaseWeapon::SimulateWeaponPhysics()
{
GetItemMesh()->SetCollisionProfileName(TEXT("PhysicsActor"), true);
GetItemMesh()->SetSimulatePhysics(true);
}

View File

@ -22,11 +22,15 @@ public:
ABaseWeapon();
public:
//override
void OnEquipped() override;
public:
//Delegate
void OnHit(FHitResult hitResult);
public:
//Normal
void SimulateWeaponPhysics();
public:
FORCEINLINE UAnimMontage* GetEnterCombat() const { return EnterCombat; }
FORCEINLINE UAnimMontage* GetExitCombat() const { return ExitCombat; }
@ -42,6 +46,9 @@ protected:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components")
TObjectPtr<class UCombatComponent> CombatComponent;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components")
TObjectPtr<class UCollisionComponent> CollisionComponent;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Montages")
TObjectPtr<UAnimMontage> EnterCombat;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Montages")

View File

@ -9,11 +9,13 @@
#include "GameFramework/SpringArmComponent.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet/KismetMathLibrary.h"
#include "Interface/Interact.h"
#include "Actor/BaseWeapon.h"
#include "Components/CombatComponent.h"
#include "Engine/DamageEvents.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet/KismetMathLibrary.h"
#include "Kismet/GameplayStatics.h"
//////////////////////////////////////////////////////////////////////////
// ACombatCharacter
@ -60,6 +62,16 @@ ACombatCharacter::ACombatCharacter()
CombatEnabled = false;
IsTogglingCombat = false;
IsDodge = false;
IsDisabled = false;
IsDead = false;
Health = 100.f;
PelvisBoneName = TEXT("pelvis");
//³ªÁß¿¡ ¼öÁ¤ÇÒ ¼ö ÀÖÀ½
static ConstructorHelpers::FObjectFinder<UAnimMontage> findHitMontage(TEXT("/Script/Engine.AnimMontage'/Game/CombatSystem/CourseFiles/Animations/HitReactions/Standing_React_Large_Front_Montage.Standing_React_Large_Front_Montage'"));
if (findHitMontage.Succeeded())
HitMontage = findHitMontage.Object;
}
void ACombatCharacter::BeginPlay()
@ -85,6 +97,29 @@ void ACombatCharacter::BeginPlay()
SpawnItem->OnEquipped();
}
float ACombatCharacter::TakeDamage(float Damage, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
float fDamage = Super::TakeDamage(Damage, DamageEvent, EventInstigator, DamageCauser);
if (DamageEvent.IsOfType(FPointDamageEvent::ClassID))
{
const FPointDamageEvent* PointDamageEvent = static_cast<const FPointDamageEvent*>(&DamageEvent);
CharacterTakeDamage(fDamage);
//TODO : Sound, Effect Emitter, Play anim montage
//static void PlaySoundAtLocation(
// const UObject * WorldContextObject, USoundBase * Sound, FVector Location,
// float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, float StartTime = 0.f,
// class USoundAttenuation* AttenuationSettings = nullptr, USoundConcurrency * ConcurrencySettings = nullptr,
// const UInitialActiveSoundParams * InitialParams = nullptr)
//UGameplayStatics::PlaySoundAtLocation(this, HitSound, PointDamageEvent->HitInfo.Location);
PlayAnimMontage(HitMontage);
IsDisabled = true;
}
return fDamage;
}
void ACombatCharacter::ContinueAttack_Implementation()
{
CombatComponent->SetIsAttacking(false);
@ -116,6 +151,11 @@ FRotator ACombatCharacter::GetDesiredRotation_Implementation()
return UKismetMathLibrary::MakeRotFromX(GetLastMovementInputVector());
}
bool ACombatCharacter::CanReceiveDamage_Implementation()
{
return !IsDead;
}
//////////////////////////////////////////////////////////////////////////
// Input
@ -249,6 +289,36 @@ void ACombatCharacter::AttackEvent()
ToggleCombatEvent();
}
void ACombatCharacter::CharacterTakeDamage(float InDamage)
{
float tmp = Health - InDamage;
Health = UKismetMathLibrary::Clamp(tmp, 0, Health);
if (Health <= 0)
PerformDeath();
}
void ACombatCharacter::ApplyHitReactionPhysicsVelocity(float InitialSpeed)
{
if (!GetMesh())
return;
GetMesh()->SetPhysicsLinearVelocity(GetActorForwardVector() * -InitialSpeed, false, PelvisBoneName);
}
void ACombatCharacter::EnableRagdoll()
{
GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_None, 0);
GetCapsuleComponent()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Ignore);
GetCapsuleComponent()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Camera, ECollisionResponse::ECR_Ignore);
FAttachmentTransformRules rules(EAttachmentRule::KeepWorld, EAttachmentRule::KeepWorld, EAttachmentRule::KeepWorld, true);
GetCameraBoom()->AttachToComponent(GetMesh(), rules, PelvisBoneName);
GetCameraBoom()->bDoCollisionTest = false;
GetMesh()->SetCollisionProfileName(TEXT("ragdoll"), true);
GetMesh()->SetAllBodiesBelowSimulatePhysics(PelvisBoneName, true, true);
GetMesh()->SetAllBodiesBelowPhysicsBlendWeight(PelvisBoneName, 1.f);
}
void ACombatCharacter::PerformAttack(int32 attackIndex)
{
ABaseWeapon* CurrentWeapon = CombatComponent->GetMainWeapon();
@ -296,19 +366,70 @@ void ACombatCharacter::PerformDodge()
}
}
void ACombatCharacter::PerformDeath()
{
IsDead = true;
EnableRagdoll();
ApplyHitReactionPhysicsVelocity(2000.f);
if (IsValid(CombatComponent->GetMainWeapon()))
CombatComponent->GetMainWeapon()->SimulateWeaponPhysics();
FTimerHandle deathTimer;
GetWorld()->GetTimerManager().SetTimer(deathTimer, FTimerDelegate::CreateLambda([&]()
{
if (IsValid(CombatComponent->GetMainWeapon()))
CombatComponent->GetMainWeapon()->Destroy();
this->Destroy();
}), 4.f, false);
}
bool ACombatCharacter::CanPerformToggleCombat()
{
return (!CombatComponent->GetIsAttacking() && !IsTogglingCombat);
bool ReturnValue = true;
ReturnValue &= !CombatComponent->GetIsAttacking();
ReturnValue &= !IsTogglingCombat;
ReturnValue &= !IsDodge;
ReturnValue &= !IsDisabled;
ReturnValue &= !IsDead;
ReturnValue &= !GetCharacterMovement()->IsFalling();
return ReturnValue;
}
bool ACombatCharacter::CanPerformAttack()
{
return (!CombatComponent->GetIsAttacking() && !IsTogglingCombat);
bool ReturnValue = true;
ReturnValue &= !CombatComponent->GetIsAttacking();
ReturnValue &= !IsTogglingCombat;
ReturnValue &= !IsDodge;
ReturnValue &= !IsDisabled;
ReturnValue &= !IsDead;
ReturnValue &= !GetCharacterMovement()->IsFalling();
return ReturnValue;
}
bool ACombatCharacter::CanPerformDodge()
{
return (!CombatComponent->GetIsAttacking() && !IsTogglingCombat && !IsDodge);
bool ReturnValue = true;
ReturnValue &= !CombatComponent->GetIsAttacking();
ReturnValue &= !IsTogglingCombat;
ReturnValue &= !IsDodge;
ReturnValue &= !IsDisabled;
ReturnValue &= !IsDead;
ReturnValue &= !GetCharacterMovement()->IsFalling();
return ReturnValue;
}
bool ACombatCharacter::CanJumping()
{
bool ReturnValue = true;
ReturnValue &= !CombatComponent->GetIsAttacking();
ReturnValue &= !IsTogglingCombat;
ReturnValue &= !IsDodge;
ReturnValue &= !IsDisabled;
ReturnValue &= !IsDead;
ReturnValue &= !GetCharacterMovement()->IsFalling();
return ReturnValue;
}

View File

@ -63,8 +63,9 @@ public:
protected:
// APawn interface
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
virtual void BeginPlay();
virtual void BeginPlay() override;
virtual float TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) override;
public:
// Inherited via ICombatInterface
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
@ -79,27 +80,34 @@ public:
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
FRotator GetDesiredRotation();
virtual FRotator GetDesiredRotation_Implementation() override;
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
bool CanReceiveDamage();
virtual bool CanReceiveDamage_Implementation() override;
protected:
/** Called for movement input */
//Input Funcs
void Move(const FInputActionValue& Value);
/** Called for looking input */
void Look(const FInputActionValue& Value);
void Interact(const FInputActionValue& Value);
void ToggleCombat(const FInputActionValue& Value);
void LightAttack(const FInputActionValue& Value);
void Dodge(const FInputActionValue& Value);
private:
void ToggleCombatEvent();
void AttackEvent();
void CharacterTakeDamage(float InDamage);
void ApplyHitReactionPhysicsVelocity(float InitialSpeed);
void EnableRagdoll();
void PerformAttack(int32 attackIndex);
void PerformDodge();
void PerformDeath();
bool CanPerformToggleCombat();
bool CanPerformAttack();
bool CanPerformDodge();
bool CanJumping();
public:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components", meta=(AllowPrivateAccess="true"))
TObjectPtr<class UCombatComponent> CombatComponent;
@ -107,9 +115,19 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon", meta = (AllowPrivateAccess = "true"))
TSubclassOf<class ABaseEquippable> Weapon;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
FName PelvisBoneName;
private:
//TODO : particle, sound Ãß°¡
//class USoundWave* HitSound;
TObjectPtr<UAnimMontage> HitMontage;
private:
bool CombatEnabled;
bool IsTogglingCombat;
bool IsDodge;
bool IsDisabled;
bool IsDead;
float Health;
};

View File

@ -30,7 +30,7 @@ void UCollisionComponent::TickComponent(float DeltaTime, ELevelTick TickType, FA
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if (IsCollisionEnabled)
if (bCollisionEnabled)
CollisionTrace();
}
@ -56,12 +56,14 @@ void UCollisionComponent::CollisionTrace()
{
HitActor = LastHit.GetActor();
AlreadyHitActors.Add(HitActor);
OnHit.ExecuteIfBound(LastHit);
OnHitDelegate.ExecuteIfBound(LastHit); //Multi면 변경해야됨
}
}
}
void UCollisionComponent::EnableCollision()
{
ClearHitActors();
bCollisionEnabled = true;
}

View File

@ -7,7 +7,8 @@
#include "Kismet/KismetSystemLibrary.h"
#include "CollisionComponent.generated.h"
DECLARE_DELEGATE_OneParam(FOnHit, FHitResult hitResult);
//DECLARE_MULTICAST_DELEGATE_OneParam ·Î º¯°æ ÇÊ¿ä
DECLARE_DELEGATE_OneParam(FOnHit, FHitResult);
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class D1_API UCollisionComponent : public UActorComponent
@ -29,11 +30,30 @@ public:
public:
void CollisionTrace();
public:
FORCEINLINE void SetCollisionMesh(UPrimitiveComponent* InputComponent) { CollisionMeshComponent = InputComponent; }
FORCEINLINE void EnableCollision();
FORCEINLINE void DisableCollision() { IsCollisionEnabled = false; }
TArray<AActor*> GetAlreadyHitActors() { return AlreadyHitActors; }
FORCEINLINE void ClearHitActors() { AlreadyHitActors.Empty(); }
FHitResult GetLastHit() { return LastHit; }
UPrimitiveComponent* GetCollisionMeshComponent() { return CollisionMeshComponent; }
FORCEINLINE void SetCollisionMeshComponent(UPrimitiveComponent* InputComponent) { CollisionMeshComponent = InputComponent; }
FORCEINLINE void AddActorToIgnore(AActor* inputActor) { ActorsToIgnore.Add(inputActor); }
void RemoveActorToIgnore(AActor* inputActor) { ActorsToIgnore.Remove(inputActor); }
TArray<AActor*> GetActorToIgnore() { return ActorsToIgnore; }
//Initialize
FORCEINLINE void SetTraceRaius(float inputTrace) { TraceRadius = inputTrace; }
FORCEINLINE void SetStartSocketName(FName InputStartSocketName) { StartSocketName = InputStartSocketName; }
FORCEINLINE void SetEndSocketName(FName InpuEndSocketName) { EndSocketName = InpuEndSocketName; }
FORCEINLINE void SetCollisionObjectTypes(TArray<TEnumAsByte<EObjectTypeQuery>> InputCollisionObjectTypes) { CollisionObjectTypes = InputCollisionObjectTypes; }
FORCEINLINE void SetDrawDebugType(TEnumAsByte<EDrawDebugTrace::Type> InputDrawDebugType) { DrawDebugType = InputDrawDebugType; }
public:
UFUNCTION(BlueprintCallable)
FORCEINLINE void EnableCollision();
UFUNCTION(BlueprintCallable)
FORCEINLINE void DisableCollision() { bCollisionEnabled = false; }
bool IsCollisionEnabled() { return bCollisionEnabled; }
private:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Initialization", meta=(AllowPrivateAccess="true"))
float TraceRadius;
@ -53,11 +73,12 @@ private:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components", meta = (AllowPrivateAccess = "true"))
TObjectPtr<UPrimitiveComponent> CollisionMeshComponent;
bool IsCollisionEnabled;
bool bCollisionEnabled;
TArray<TObjectPtr<AActor>> AlreadyHitActors;
TArray<TObjectPtr<AActor>> ActorsToIgnore;
FHitResult LastHit;
TObjectPtr<AActor> HitActor;
FOnHit OnHit;
public:
FOnHit OnHitDelegate;
};

View File

@ -30,4 +30,6 @@ public:
void ResetCombat();
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
FRotator GetDesiredRotation();
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
bool CanReceiveDamage();
};