Section 11: Multiple Weapon Types - Lecture 229

Stop Aiming when exchanging weapons

* Also fixed a case where firing wasn't resumed after reloading when the fire button was still pressed, same for equipping.
This commit is contained in:
charnet3d 2024-01-19 02:12:26 +01:00
parent d16ac0cef1
commit 898f7e60e3
17 changed files with 158 additions and 24 deletions

BIN
Content/_Game/Character/Animations/AimingPose_AR.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/_Game/Curves/SlideDisplacementCurve.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

BIN
Content/_Game/Maps/DefaultMap.umap (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Content/_Game/Materials/PistolMaterials/M_Pistol_Mat.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/_Game/Weapons/BaseWeapon/PistolAnimBP.uasset (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -288,7 +288,7 @@ void AShooterCharacter::LookUp(float Value)
void AShooterCharacter::AimingButtonPressed()
{
bAimingButtonPressed = true;
if (CombatState != ECombatState::ECS_Reloading)
if (CombatState != ECombatState::ECS_Reloading && CombatState != ECombatState::ECS_Equipping)
{
Aim();
}
@ -420,6 +420,11 @@ void AShooterCharacter::ExchangeInventoryItems(int32 CurrentItemIndex, int32 New
|| (CombatState != ECombatState::ECS_Unoccupied && CombatState != ECombatState::ECS_Equipping))
return;
if (bAiming)
{
StopAiming();
}
auto OldEquippedWeapon = EquippedWeapon;
auto NewWeapon = Cast<AWeapon>(Inventory[NewItemIndex]);
@ -572,6 +577,12 @@ void AShooterCharacter::FireWeapon()
EquippedWeapon->DecrementAmmo();
StartCrosshairBulletFire();
StartFireTimer();
if (EquippedWeapon->GetWeaponType() == EWeaponType::EWT_Pistol)
{
// Start moving slide timer
EquippedWeapon->StartSlideTimer();
}
}
void AShooterCharacter::StartFireTimer()
@ -585,10 +596,13 @@ void AShooterCharacter::StartFireTimer()
void AShooterCharacter::AutoFireReset()
{
if (!EquippedWeapon) return;
CombatState = ECombatState::ECS_Unoccupied;
if (WeaponHasAmmo())
{
if (bFireButtonPressed)
if (bFireButtonPressed && EquippedWeapon->GetAutomatic())
{
FireWeapon();
}
@ -1046,15 +1060,10 @@ void AShooterCharacter::ReloadWeapon()
void AShooterCharacter::FinishReloading()
{
CombatState = ECombatState::ECS_Unoccupied;
if (bAimingButtonPressed)
{
Aim();
}
if (!EquippedWeapon) return;
CombatState = ECombatState::ECS_Unoccupied;
if (const auto AmmoType { EquippedWeapon->GetAmmoType() }; AmmoMap.Contains(AmmoType))
{
int32 CarriedAmmo = AmmoMap[AmmoType];
@ -1075,11 +1084,37 @@ void AShooterCharacter::FinishReloading()
AmmoMap.Add(AmmoType, CarriedAmmo);
}
}
if (bAimingButtonPressed)
{
Aim();
}
if (WeaponHasAmmo())
{
if (bFireButtonPressed && EquippedWeapon->GetAutomatic())
{
FireWeapon();
}
}
}
void AShooterCharacter::FinishEquipping()
{
CombatState = ECombatState::ECS_Unoccupied;
if (bAimingButtonPressed)
{
Aim();
}
if (WeaponHasAmmo())
{
if (bFireButtonPressed && EquippedWeapon->GetAutomatic())
{
FireWeapon();
}
}
}
bool AShooterCharacter::CarryingAmmo()
@ -1123,6 +1158,7 @@ void AShooterCharacter::CrouchButtonPressed()
{
bCrouching = !bCrouching;
}
if (bCrouching)
{
GetCharacterMovement()->MaxWalkSpeed = CrouchMovementSpeed;

View File

@ -11,7 +11,13 @@ AWeapon::AWeapon() :
WeaponType(EWeaponType::EWT_SubmachineGun),
AmmoType(EAmmoType::EAT_9mm),
ReloadMontageSection(FName(TEXT("Reload SMG"))),
ClipBoneName(TEXT("smg_clip"))
ClipBoneName(TEXT("smg_clip")),
SlideDisplacement(0.f),
SlideDisplacementTime(0.2f),
bMovingSlide(false),
MaxSlideDisplacement(4.f),
MaxRecoilRotation(20.f),
bAutomatic(true)
{
PrimaryActorTick.bCanEverTick = true;
}
@ -27,6 +33,9 @@ void AWeapon::Tick(float DeltaTime)
GetItemMesh()->SetWorldRotation(MeshRotation, false,
nullptr, ETeleportType::TeleportPhysics);
}
// Update slide on pistol
UpdateSlideDisplacement();
}
void AWeapon::ThrowWeapon()
@ -61,6 +70,12 @@ void AWeapon::DecrementAmmo()
--Ammo;
}
void AWeapon::StartSlideTimer()
{
bMovingSlide = true;
GetWorldTimerManager().SetTimer(SlideTimer, this, &AWeapon::FinishMovingSlide, SlideDisplacementTime);
}
void AWeapon::ReloadAmmo(int32 Amount)
{
checkf(Ammo + Amount <= MagazineCapacity, TEXT("Attempted to reload with more than the magazine capacity!"))
@ -139,6 +154,8 @@ void AWeapon::OnConstruction(const FTransform& Transform)
{
GetItemMesh()->HideBoneByName(BoneToHide, EPhysBodyOp::PBO_None);
}
bAutomatic = WeaponDataRow->bAutomatic;
}
if (GetMaterialInstance())
@ -161,3 +178,19 @@ void AWeapon::BeginPlay()
GetItemMesh()->HideBoneByName(BoneToHide, EPhysBodyOp::PBO_None);
}
}
void AWeapon::FinishMovingSlide()
{
bMovingSlide = false;
}
void AWeapon::UpdateSlideDisplacement()
{
if (!SlideDisplacementCurve && !bMovingSlide) return;
const float ElapsedTime{ GetWorldTimerManager().GetTimerElapsed(SlideTimer) };
const float CurveValue{ SlideDisplacementCurve->GetFloatValue(ElapsedTime) };
SlideDisplacement = CurveValue * MaxSlideDisplacement;
RecoilRotation = CurveValue * MaxRecoilRotation;
}

View File

@ -87,6 +87,9 @@ struct FWeaponDataTable : public FTableRowBase
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FName BoneToHide;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool bAutomatic;
};
/**
@ -109,6 +112,9 @@ protected:
virtual void BeginPlay() override;
void FinishMovingSlide();
void UpdateSlideDisplacement();
private:
FTimerHandle ThrowWeaponTimer;
float ThrowWeaponTime;
@ -180,6 +186,41 @@ private:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = DataTable, meta = (AllowPrivateAccess = "true"))
FName BoneToHide;
/** Amount that the slide is pushed back during pistol fire */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Pistol, meta = (AllowPrivateAccess = "true"))
float SlideDisplacement;
/** Curve for the slide displacement */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Pistol, meta = (AllowPrivateAccess = "true"))
UCurveFloat* SlideDisplacementCurve;
/** Timer handle for updating SlideDisplacement */
FTimerHandle SlideTimer;
/** Time for displacing the slide during pistol fire */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Pistol, meta = (AllowPrivateAccess = "true"))
float SlideDisplacementTime;
/** True when moving the pistol slide */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Pistol, meta = (AllowPrivateAccess = "true"))
bool bMovingSlide;
/** Max distance for the slide on the pistol */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Pistol, meta = (AllowPrivateAccess = "true"))
float MaxSlideDisplacement;
/** Max rotation for pistol recoil */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Pistol, meta = (AllowPrivateAccess = "true"))
float MaxRecoilRotation;
/** Amount that the pistol will rotate during pistol fire */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Pistol, meta = (AllowPrivateAccess = "true"))
float RecoilRotation;
/** True for auto gunfire */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Weapon Properties", meta = (AllowPrivateAccess = "true"))
bool bAutomatic;
public:
/** Adds an impulse to the weapon */
void ThrowWeapon();
@ -197,6 +238,9 @@ public:
FORCEINLINE float GetAutoFireRate() const { return AutoFireRate; }
FORCEINLINE UParticleSystem* GetMuzzleFlash() const { return MuzzleFlash; }
FORCEINLINE USoundCue* GetFireSound() const { return FireSound; }
FORCEINLINE bool GetAutomatic() const { return bAutomatic; }
void StartSlideTimer();
void ReloadAmmo(int32 Amount);