Skip to content

Commit

Permalink
Added flinch effect on shot (#276)
Browse files Browse the repository at this point in the history
* #250 Implemented flinch

* #250 Removed flinch and decal effect when character under shield effect

* Fixed effect on init
  • Loading branch information
xthebat authored May 5, 2024
1 parent 36f8822 commit 3a4b098
Show file tree
Hide file tree
Showing 32 changed files with 345 additions and 90 deletions.
Binary file modified Content/Characters/Blueprints/BP_Cloud9CharacterBot.uasset
Binary file not shown.
Binary file modified Content/Characters/Effects/BP_ShieldEffectBot.uasset
Binary file not shown.
Binary file modified Content/Game/BP_Cloud9Console.uasset
Binary file not shown.
Binary file modified Content/Maps/de_shortdust.umap
Binary file not shown.
Binary file modified Content/Maps/warmup.umap
Binary file not shown.
Binary file modified Content/Weapons/FirearmWeaponsTable.uasset
Binary file not shown.
61 changes: 60 additions & 1 deletion Source/Cloud9/Character/Cloud9AIController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,66 @@

#include "Cloud9AIController.h"

#include "Cloud9/Tools/Extensions/UWorld.h"
#include "Cloud9/Tools/Macro/Common.h"
#include "Cloud9/Tools/Macro/Logging.h"

ACloud9AIController::ACloud9AIController()
{
bWantsPlayerState = true;
BaseLocation = FVector::ZeroVector;
MovingOffset = FVector::ZeroVector;
ChangeDirectionDelay = 0.5f;
}

void ACloud9AIController::SetMovingOffset(FVector Value)
{
GetWorld() | EUWorld::ClearTimer{TimerHandle};
SetMovingOffsetEx(Value);
}

void ACloud9AIController::SetMovingOffsetEx(FVector Value)
{
MovingOffset = Value;
Move(BaseLocation + MovingOffset);
}

void ACloud9AIController::SetChangeDirectionDelay(float Value)
{
ChangeDirectionDelay = Value;
}

void ACloud9AIController::OnMoveCompleted(FAIRequestID RequestID, const FPathFollowingResult& Result)
{
Super::OnMoveCompleted(RequestID, Result);
if (not MovingOffset.IsZero())
{
TimerHandle = GetWorld() | EUWorld::AsyncAfter{
[this] { SetMovingOffsetEx(-MovingOffset); },
ChangeDirectionDelay
};
}
}

void ACloud9AIController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
CheckIsValid(InPawn, Error, "Pawn is invalid")
BaseLocation = InPawn->GetActorLocation();
}

void ACloud9AIController::OnUnPossess()
{
Super::OnUnPossess();
Destroy();
}

void ACloud9AIController::Move(FVector Destination)
{
MoveToLocation(
Destination,
-1,
false,
false,
false,
true);
}
31 changes: 31 additions & 0 deletions Source/Cloud9/Character/Cloud9AIController.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,42 @@
#include "AIController.h"
#include "Cloud9AIController.generated.h"

class ACloud9Character;

UCLASS()
class CLOUD9_API ACloud9AIController : public AAIController
{
GENERATED_BODY()

public:
ACloud9AIController();

UFUNCTION(BlueprintCallable)
void SetMovingOffset(FVector Value);

UFUNCTION(BlueprintCallable)
void SetChangeDirectionDelay(float Value);

virtual void OnMoveCompleted(FAIRequestID RequestID, const FPathFollowingResult& Result) override;

protected:
virtual void OnPossess(APawn* InPawn) override;

virtual void OnUnPossess() override;

void SetMovingOffsetEx(FVector Value);

void Move(FVector Destination);

UPROPERTY()
FVector BaseLocation;

UPROPERTY()
FTimerHandle TimerHandle;

UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category=Testing)
FVector MovingOffset;

UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category=Testing)
float ChangeDirectionDelay;
};
47 changes: 38 additions & 9 deletions Source/Cloud9/Character/Cloud9Character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "Cloud9/Modes/Cloud9GameMode.h"
#include "Cloud9/Game/Cloud9GameInstance.h"
#include "Cloud9/Tools/Extensions/ACharacter.h"
#include "Cloud9/Weapon/Classes/Cloud9WeaponGrenade.h"
#include "Components/Cloud9InventoryComponent.h"
#include "Components/Cloud9CharacterMovement.h"
#include "Components/Cloud9SpringArmComponent.h"
Expand All @@ -69,6 +70,7 @@ ACloud9Character::ACloud9Character(const FObjectInitializer& ObjectInitializer)
.SetDefaultSubobjectClass<UCloud9SkeletalMeshComponent>(MeshComponentName))
{
AIControllerClass = ACloud9AIController::StaticClass();
AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;

bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
Expand Down Expand Up @@ -305,6 +307,11 @@ bool ACloud9Character::RemoveCharacterEffect(UCloud9CharacterEffectTrait* Effect
return EffectsComponent->RemoveEffect(Effect);
}

void ACloud9Character::RemoveAllCharacterEffects() const
{
EffectsComponent->RemoveAllEffects();
}

void ACloud9Character::AddScore() const
{
if (let MyPlayerState = GetPlayerState())
Expand All @@ -313,10 +320,6 @@ void ACloud9Character::AddScore() const
MyPlayerState->SetScore(NewScore);
OnScoreChanged.Broadcast(NewScore);
}
else
{
log(Error, "[Character='%s'] Can't add score cus no valid player state")
}
}

void ACloud9Character::UseObject()
Expand Down Expand Up @@ -348,14 +351,24 @@ float ACloud9Character::InternalTakePointDamage(
AController* EventInstigator,
AActor* DamageCauser)
{
if (GetHealthComponent()->IsInvulnerable())
{
return 0.0f;
}

static let Settings = UCloud9DeveloperSettings::Get();

Damage = Super::InternalTakePointDamage(Damage, PointDamageEvent, EventInstigator, DamageCauser);

if (let Weapon = Cast<ACloud9WeaponFirearm>(DamageCauser))
// TODO: Scale will be used when implement grenade damage
float Scale = 1.0f;
float FlinchModLarge = 0.0f;
float FlinchModSmall = 0.0f;

if (let WeaponFirearm = Cast<ACloud9WeaponFirearm>(DamageCauser))
{
let BoneName = PointDamageEvent.HitInfo.BoneName;
let WeaponInfo = Weapon->GetWeaponInfo();
let WeaponInfo = WeaponFirearm->GetWeaponInfo();

bool HitInArmor = false;

Expand Down Expand Up @@ -414,6 +427,24 @@ float ACloud9Character::InternalTakePointDamage(
DamageToHealth,
DamageToArmor);
}

FlinchModLarge = WeaponInfo->GetFlinchVelocityModifierLarge();
FlinchModSmall = WeaponInfo->GetFlinchVelocityModifierSmall();
}
else if (let WeaponGrenade = Cast<ACloud9WeaponGrenade>(DamageCauser))
{
let WeaponInfo = WeaponGrenade->GetWeaponInfo();
FlinchModLarge = WeaponInfo->GetFlinchVelocityModifierLarge();
FlinchModSmall = WeaponInfo->GetFlinchVelocityModifierSmall();

Scale = 1.0f - Damage / 40.0f;
FlinchModLarge += Scale * 1.05;
FlinchModLarge = FMath::Min(1.5f, FlinchModLarge);
}

if (Damage > 0.0f)
{
GetCloud9CharacterMovement()->UpdateFlinchVelocityModifier(FlinchModSmall, FlinchModLarge);
}

return Damage;
Expand Down Expand Up @@ -441,7 +472,7 @@ void ACloud9Character::OnConstruction(const FTransform& Transform)
if (not CameraTargetBoneName.IsNone())
{
let HeadBoneLocation = MyMesh->GetBoneLocation(CameraTargetBoneName, EBoneSpaces::WorldSpace);
log(Display, "Setup CameraBoom = %s", *HeadBoneLocation.ToString());
log(Verbose, "Setup CameraBoom = %s", *HeadBoneLocation.ToString());
CameraBoom->SetWorldLocation(HeadBoneLocation);
}

Expand Down Expand Up @@ -490,8 +521,6 @@ void ACloud9Character::BeginPlay()
CameraBoom->Deactivate();
}

log(Display, "[Character='%s'] IsPlayer=%d", *GetName(), IsPlayerControlled());

// Load all characters (even it's a bot) because LoadCharacter also handle GameMode initialization
if (let GameMode = GetWorld() | EUWorld::GetGameMode<ACloud9GameMode>{})
{
Expand Down
2 changes: 2 additions & 0 deletions Source/Cloud9/Character/Cloud9Character.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ class ACloud9Character : public ACharacter

bool RemoveCharacterEffect(UCloud9CharacterEffectTrait* Effect);

void RemoveAllCharacterEffects() const;

void AddScore() const;

void UseObject();
Expand Down
57 changes: 57 additions & 0 deletions Source/Cloud9/Character/Components/Cloud9CharacterMovement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include "Cloud9CharacterMovement.h"

#include "Cloud9InventoryComponent.h"

#include "Cloud9/Tools/Math.h"
#include "Cloud9/Tools/Macro/Common.h"
#include "Cloud9/Tools/Macro/Logging.h"
#include "Cloud9/Character/Cloud9Character.h"
Expand All @@ -44,8 +46,11 @@ UCloud9CharacterMovement::UCloud9CharacterMovement()
SpeedWalkModifier = 0.52f;
SpeedClimbModifier = 0.34f;

FlinchVelocityModifier = 1.0f;

MaxWalkSpeed = SpeedRun;
MaxWalkSpeedCrouched = MaxWalkSpeed * SpeedDuckModifier;
MaxAcceleration = GetMovementValue(AccelerationWalkScaleCoefficient, AccelerationDuckScaleCoefficient);

var& NavAgentProperties = GetNavAgentPropertiesRef();
NavAgentProperties.bCanCrouch = true;
Expand Down Expand Up @@ -131,13 +136,65 @@ float UCloud9CharacterMovement::GetMovementValue(float WalkScale, float DuckScal
return IsSneaking() ? MaxSpeed * SpeedWalkModifier : MaxSpeed;
}

void UCloud9CharacterMovement::UpdateFlinchVelocityModifier(float FlinchModSmall, float FlinchModLarge)
{
static let Settings = UCloud9DeveloperSettings::Get();

// logic and coefficients from cstrike15

// apply the minimum large flinch amount on the first hit and on subsequent hits,
// apply a portion of the small amount - less as we apply more
let NewFlinchModeLarge = FlinchModLarge - (1.0f - FlinchVelocityModifier) * FlinchModSmall;
FlinchVelocityModifier = FMath::Min(FlinchVelocityModifier, FMath::Min(FlinchModLarge, NewFlinchModeLarge));

var FlinchModifier = FlinchVelocityModifier;

// scale this by a global convar value
FlinchModifier *= Settings->TaggingScale;

// get the player's current max speed based on their weapon
let InventoryComponent = GetCloud9CharacterOwner()->GetInventoryComponent();
let SelectedWeapon = InventoryComponent->GetSelectedWeapon();
let WeaponMaxSpeed = IsValid(SelectedWeapon)
? SelectedWeapon->GetWeaponInfo()->MaxPlayerSpeed
: ACloud9WeaponBase::KnifeMaxPlayerSpeed;

// this is the value we use to scale the above fFlinchModifier -
// knives receive less; AKs receive a bit more, etc.
constexpr let WeaponScaleMin = 0.15f;
let WeaponScaleMax = (WeaponMaxSpeed - 120.0f) / (ACloud9WeaponBase::KnifeMaxPlayerSpeed - 120.0f);
let LocalWeaponScale = FMath::Max(WeaponScaleMin, WeaponScaleMax) * 0.8f + 0.08f;
FlinchModifier = FlinchModifier * LocalWeaponScale;

// the held weapon also determines what the tagging cap should be
// since it's accumulative; we want to be able to cap it, so we don't keep getting more
// tagged the more someone shoots us
constexpr let RatioMin = 1.0f;
let RatioMax = (WeaponMaxSpeed - 80.0f) / (ACloud9WeaponBase::KnifeMaxPlayerSpeed - 80.0f);
let Ratio = FMath::Min(RatioMin, RatioMax) * 1.2f - 0.08f;
let ClampMin = FMath::Max(0.2f, Ratio / 4.0f);
let ClampMax = FlinchModLarge > 0.65f ? FlinchModLarge : 0.65f;
FlinchModifier = FMath::Clamp(FlinchModifier, ClampMin, ClampMax);

// this function only allows more flinch (smaller values) to be applied, not less
FlinchVelocityModifier = FMath::Min(FlinchVelocityModifier, FlinchModifier);
}

void UCloud9CharacterMovement::TickComponent(
float DeltaTime,
ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

// lerp decay a flinch modifier too slowly, so use the original cstrike15 method
if (FlinchVelocityModifier < 1.0f)
{
FlinchVelocityModifier = Math::Approach(1.0, FlinchVelocityModifier, DeltaTime * 0.35);
}

FlinchVelocityModifier = FMath::Clamp(FlinchVelocityModifier, 0.1f, 1.0f);

if (let Owner = GetCloud9CharacterOwner(); IsValid(Owner))
{
var NewRotation = TargetRotator;
Expand Down
21 changes: 15 additions & 6 deletions Source/Cloud9/Character/Components/Cloud9CharacterMovement.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ class CLOUD9_API UCloud9CharacterMovement : public UCharacterMovementComponent

static constexpr let AccelerationDuckScaleCoefficient = 4.0f;

public:
UCloud9CharacterMovement();

ACloud9Character* GetCloud9CharacterOwner() const;
Expand Down Expand Up @@ -114,10 +113,18 @@ class CLOUD9_API UCloud9CharacterMovement : public UCharacterMovementComponent
UPROPERTY(Category="Character Movement: Modifier", EditAnywhere, BlueprintReadWrite, meta=(ClampMin="0", UIMin="1"))
float SpeedClimbModifier;

public:
void UpdateFlinchVelocityModifier(float FlinchModSmall, float FlinchModLarge);

virtual float GetMaxSpeed() const override
{
return GetMovementValue(SpeedScaleCoefficient, SpeedScaleCoefficient);
var MaxCharacterSpeed = GetMovementValue(SpeedScaleCoefficient, SpeedScaleCoefficient);

if (IsWalking())
{
MaxCharacterSpeed *= FlinchVelocityModifier;
}

return MaxCharacterSpeed;
}

virtual float GetMaxAcceleration() const override
Expand All @@ -137,13 +144,15 @@ class CLOUD9_API UCloud9CharacterMovement : public UCharacterMovementComponent
protected:
float GetMovementValue(float WalkScale, float DuckScale) const;

protected:
/** Target rotator of character*/
UPROPERTY(Category="Character Movement: Modifier", BlueprintReadOnly)
float FlinchVelocityModifier;

/** Target rotator of character */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=State)
FRotator TargetRotator;

private:
/** Character rotation lag*/
/** Character rotation lag */
UPROPERTY(EditDefaultsOnly, Category=Config)
float RotationLag;
};
Loading

0 comments on commit 3a4b098

Please sign in to comment.