Punch Mechanic - Part 2

No punching while running
Enemy can fight back
Punch reaction animation
This commit is contained in:
charnet3d 2024-01-28 21:48:11 +01:00
parent dc7333b3a2
commit 549d4e590a
17 changed files with 114 additions and 60 deletions

View File

@ -355,23 +355,23 @@ bEnableDomStorage=False
-Profiles=(Name="UI",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Block),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
+Profiles=(Name="NoCollision",CollisionEnabled=NoCollision,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="No collision")
+Profiles=(Name="BlockAll",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=,HelpMessage="WorldStatic object that blocks all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAll",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAll",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="BlockAllDynamic",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=,HelpMessage="WorldDynamic object that blocks all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAllDynamic",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAllDynamic",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="IgnoreOnlyPawn",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that ignores Pawn and Vehicle. All other channels will be set to default.")
+Profiles=(Name="OverlapOnlyPawn",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that overlaps Pawn, Camera, and Vehicle. All other channels will be set to default. ")
+Profiles=(Name="OverlapOnlyPawn",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that overlaps Pawn, Camera, and Vehicle. All other channels will be set to default. ")
+Profiles=(Name="Pawn",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object. Can be used for capsule of any playerable character or AI. ")
+Profiles=(Name="Spectator",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="WorldStatic"),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Pawn object that ignores all other actors except WorldStatic.")
+Profiles=(Name="CharacterMesh",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object that is used for Character Mesh. All other channels will be set to default.")
+Profiles=(Name="Spectator",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Pawn object that ignores all other actors except WorldStatic.")
+Profiles=(Name="CharacterMesh",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore)),HelpMessage="Pawn object that is used for Character Mesh. All other channels will be set to default.")
+Profiles=(Name="PhysicsActor",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="PhysicsBody",CustomResponses=,HelpMessage="Simulating actors")
+Profiles=(Name="Destructible",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Destructible",CustomResponses=,HelpMessage="Destructible actors")
+Profiles=(Name="InvisibleWall",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldStatic object that is invisible.")
+Profiles=(Name="InvisibleWallDynamic",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that is invisible.")
+Profiles=(Name="Trigger",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that is used for trigger. All other channels will be set to default.")
+Profiles=(Name="Trigger",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that is used for trigger. All other channels will be set to default.")
+Profiles=(Name="Ragdoll",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="PhysicsBody",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Simulating Skeletal Mesh Component. All other channels will be set to default.")
+Profiles=(Name="Vehicle",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Vehicle",CustomResponses=,HelpMessage="Vehicle object that blocks Vehicle, WorldStatic, and WorldDynamic. All other channels will be set to default.")
+Profiles=(Name="UI",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility"),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="Enemy")
+Profiles=(Name="UI",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Block,bTraceType=True,bStaticObject=False,Name="Fighting")
-ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall")
-ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn")
-ProfileRedirects=(OldName="StaticMeshComponent",NewName="BlockAllDynamic")
@ -390,4 +390,5 @@ bEnableDomStorage=False
+CollisionChannelRedirects=(OldName="Dynamic",NewName="WorldDynamic")
+CollisionChannelRedirects=(OldName="VehicleMovement",NewName="Vehicle")
+CollisionChannelRedirects=(OldName="PawnMovement",NewName="Pawn")
+CollisionChannelRedirects=(OldName="Enemy",NewName="Fighting")

Binary file not shown.

BIN
Content/SideScroller/Animations/Combat/PunchReaction1.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -2,6 +2,7 @@
#include "EnemyCharacter.h"
#include "EnhancedInputComponent.h"
AEnemyCharacter::AEnemyCharacter(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
@ -10,18 +11,19 @@ AEnemyCharacter::AEnemyCharacter(const FObjectInitializer& ObjectInitializer)
void AEnemyCharacter::BeginPlay()
{
/*GetWorldTimerManager().SetTimer(AutoPunch, this, &AEnemyCharacter::StartPunch,
1.f);*/
// Call the base class
Super::BeginPlay();
GetWorldTimerManager().SetTimer(AutoPunch, this, &AEnemyCharacter::StartPunch,
1.f);
}
void AEnemyCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AEnemyCharacter::StartPunch()
{
if (CanAttack)
UE_LOG(LogTemp, Warning, TEXT("Enemy StartPunch()"));
Super::StartPunch();
GetWorldTimerManager().SetTimer(AutoPunch, this, &AEnemyCharacter::StartPunch,
1.f);

View File

@ -20,7 +20,6 @@ class FUNNYPRINCE_API AEnemyCharacter : public AFunnyPrinceCharacter
public:
AEnemyCharacter(const FObjectInitializer& ObjectInitializer);
protected:
// To add mapping context
virtual void BeginPlay() override;

View File

@ -3,10 +3,9 @@
#include "FunnyPrinceCharacter.h"
#include "SSTCharacterMovementComponent.h"
#include "Components/InputComponent.h"
#include "EnhancedInputComponent.h"
#include "Components/ArrowComponent.h"
#include "EnhancedInputComponent.h"
#include "InputActionValue.h"
#include "Engine/DamageEvents.h"
#include "EnemyCharacter.h"
@ -17,7 +16,17 @@ DEFINE_LOG_CATEGORY(LogTemplateFunnyPrinceCharacter);
// AFunnyPrinceCharacter
AFunnyPrinceCharacter::AFunnyPrinceCharacter(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
: Super(ObjectInitializer),
MoveAction2(nullptr),
PunchAction(nullptr),
PunchMontage(nullptr),
StartAttack(nullptr),
EndAttack(nullptr),
CanAttack(true),
MaxHealth(100),
Health(100),
PunchDamage(10),
CanMove(true)
{
StartAttack = CreateDefaultSubobject<UArrowComponent>("StartAttack");
StartAttack->SetupAttachment(RootComponent);
@ -50,6 +59,9 @@ void AFunnyPrinceCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInp
// Set up action bindings
if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent)) {
//Moving
EnhancedInputComponent->BindAction(MoveAction2, ETriggerEvent::Triggered, this, &AFunnyPrinceCharacter::Move);
// Punching
EnhancedInputComponent->BindAction(PunchAction, ETriggerEvent::Started, this, &AFunnyPrinceCharacter::StartPunch);
}
@ -117,11 +129,8 @@ void AFunnyPrinceCharacter::StartPunch()
if (AnimInstance && PunchMontage)
{
UE_LOG(LogTemp, Warning, TEXT("StartPunch()"));
//CanAttack = false;
if (Enemy && Enemy->GetMesh()->GetAnimInstance())
{
Enemy->GetMesh()->GetAnimInstance()->Montage_Play(Enemy->PunchMontage);
}
CanAttack = false;
CanMove = false;
AnimInstance->Montage_Play(PunchMontage);
//AnimInstance->Montage_JumpToSection(FName("StartFire"));
}
@ -130,6 +139,7 @@ void AFunnyPrinceCharacter::StartPunch()
void AFunnyPrinceCharacter::FinishPunching()
{
CanMove = true;
CanAttack = true;
}
@ -142,16 +152,25 @@ void AFunnyPrinceCharacter::PunchHitTrace()
FVector start = StartAttack->GetSocketLocation(FName());
FVector end = EndAttack->GetSocketLocation(FName());
FCollisionQueryParams Params;
Params.AddIgnoredActor(this);
bool bSuccess = GetWorld()->LineTraceSingleByChannel(PunchTraceHit, start, end, ECollisionChannel::ECC_GameTraceChannel1, Params);
/*FCollisionQueryParams Params;
Params.AddIgnoredActor(this);*/
bool bSuccess = GetWorld()->LineTraceSingleByChannel(PunchTraceHit, start, end, ECollisionChannel::ECC_GameTraceChannel1);
if (bSuccess)
{
AActor* HitActor = PunchTraceHit.GetActor();
if (HitActor)
AFunnyPrinceCharacter* HitEnemy = Cast<AFunnyPrinceCharacter>(PunchTraceHit.GetActor());
if (HitEnemy)
{
FPointDamageEvent DamageEvent(PunchDamage, PunchTraceHit, end - start, nullptr);
HitActor->TakeDamage(PunchDamage, DamageEvent, GetController(), this);
HitEnemy->TakeDamage(PunchDamage, DamageEvent, GetController(), this);
UAnimInstance* AnimInstance = HitEnemy->GetMesh()->GetAnimInstance();
if (AnimInstance && PunchReactionMontage)
{
UE_LOG(LogTemp, Warning, TEXT("Punch Reaction"));
HitEnemy->CanAttack = false;
HitEnemy->CanMove = false;
AnimInstance->Montage_Play(PunchReactionMontage);
}
}
}
/*UE_LOG(LogTemp, Warning, TEXT("TraceHit from %f %f %f to %f %f %f"),
@ -163,6 +182,20 @@ void AFunnyPrinceCharacter::PunchHitTrace()
end.Z);*/
// (World, Start, End, Color, Persistent Lines, Life Time, Depth Priority, Thickness)
DrawDebugLine(GetWorld(), start, end, FColor(255, 0, 0), false, 1, 0, 5);
//DrawDebugLine(GetWorld(), start, end, FColor(255, 0, 0), false, 1, 0, 5);
}
}
void AFunnyPrinceCharacter::FinishPunchReaction()
{
CanMove = true;
CanAttack = true;
}
void AFunnyPrinceCharacter::Move(const FInputActionValue& Value)
{
if (CanMove)
{
Super::Move(Value);
}
}

View File

@ -44,6 +44,8 @@ protected:
virtual bool CanJumpInternal_Implementation() const override;
void Move(const struct FInputActionValue& Value);
virtual void StartPunch();
UFUNCTION(BlueprintCallable)
@ -52,41 +54,52 @@ protected:
UFUNCTION(BlueprintCallable)
void PunchHitTrace();
UFUNCTION(BlueprintCallable)
void FinishPunchReaction();
/** Move Input Action */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = true))
TObjectPtr<class UInputAction> MoveAction2;
/** Punch Input Action */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = true))
TObjectPtr<class UInputAction> PunchAction = nullptr;
TObjectPtr<class UInputAction> PunchAction;
/** Punch Montage */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
UAnimMontage* PunchMontage = nullptr;
UAnimMontage* PunchMontage;
/** Punch Reaction Montage */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
UAnimMontage* PunchReactionMontage;
/** Punch Start Position */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
UArrowComponent* StartAttack = nullptr;
UArrowComponent* StartAttack;
/** Punch End Position */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
UArrowComponent* EndAttack = nullptr;
UArrowComponent* EndAttack;
/** Punch Input Action */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Combat, meta = (AllowPrivateAccess = true))
bool CanAttack = true;
bool CanAttack;
UPROPERTY(EditDefaultsOnly)
float MaxHealth = 100;
UPROPERTY(EditAnywhere)
float MaxHealth;
/** Current Health */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Combat, meta = (AllowPrivateAccess = true))
float Health = 100;
float Health;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
float PunchDamage = 10;
/** Punch End Position */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
TSoftObjectPtr<AEnemyCharacter> Enemy = nullptr;
float PunchDamage;
/** Whether the player can move */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Combat, meta = (AllowPrivateAccess = true))
bool CanMove;
private:
public:
};