From 3e842336d0208fbde3c062e5bf0e0496c4fc8c39 Mon Sep 17 00:00:00 2001 From: Kingsmedia Date: Tue, 10 May 2022 22:34:28 +0200 Subject: [PATCH] reorg --- .../GameModes/BP_BlasterGameMode.uasset | Bin 20388 -> 20243 bytes .../Blueprints/HUD/WBP_Announcement.uasset | Bin 30917 -> 30875 bytes Content/Maps/BlasterMap.umap | Bin 1331237 -> 1332404 bytes Source/Blaster/Character/BlasterCharacter.cpp | 448 +++++++-------- Source/Blaster/Character/BlasterCharacter.h | 4 +- Source/Blaster/Components/CombatComponent.cpp | 543 +++++++++--------- Source/Blaster/GameMode/BlasterGameMode.cpp | 43 +- Source/Blaster/GameMode/BlasterGameMode.h | 6 +- Source/Blaster/GameMode/LobbyGameMode.cpp | 2 +- Source/Blaster/HUD/Announcement.h | 11 +- Source/Blaster/HUD/BlasterHUD.cpp | 12 +- Source/Blaster/HUD/BlasterHUD.h | 4 +- ...pp => InteractWithCrosshairsInterface.cpp} | 2 +- ...ce.h => InteractWithCrosshairsInterface.h} | 6 +- .../BlasterPlayerController.cpp | 417 +++++++------- .../BlasterPlayerController.h | 4 +- .../PlayerState/BlasterPlayerState.cpp | 66 +-- .../Blaster/PlayerState/BlasterPlayerState.h | 7 +- Source/Blaster/Types/CombatState.h | 4 +- 19 files changed, 770 insertions(+), 809 deletions(-) rename Source/Blaster/Interfaces/{InteractWithCrosshairInterface.cpp => InteractWithCrosshairsInterface.cpp} (81%) rename Source/Blaster/Interfaces/{InteractWithCrosshairInterface.h => InteractWithCrosshairsInterface.h} (70%) diff --git a/Content/Blueprints/GameModes/BP_BlasterGameMode.uasset b/Content/Blueprints/GameModes/BP_BlasterGameMode.uasset index 15b9ff2e66c2aa7ad19d81e89617e08a6e4e5702..fa9c0d0fe22a2548dc6a81fb7b0c3111af397c97 100644 GIT binary patch delta 4367 zcmb_fdr*{B6u%#$vWfw+EG#d12m&I)!Y+RM0=|6!0t>#N$W$@~M8OAYq%)+JnS({% zY$i=DGxd)&341tWA)^FRfXRq%UDAS4mAPRhv@bBn}0oxP~Ysmsol3=XFx ziK0`=D>B%10CCGGQ2Nn?#De|-jIKyRfP+|~2ysBEgR-^bP@jFfSa~RH&5}D8Hk>{n18G3_&%=U- zboZ*F1KVdZ@v{SQ?)eW~6GE`#=LQ00%NwrD58Nf-Yx9a@`Cq|;sA{|d z-A*O$2|sbQzHof~5%Z)kAd8`z=_l?fKX7vYJgwf=SUKa_eh?yLju%`HECF-NYQEbD zAtRyU7~-}vMS5P!phrh%M%24KL5b(cKU>yaJ8<5UPwrrV;@ zhnB*l5=C!nqv^${=&%`J#lmxff=LOdefbgH$=cQ+o1RF-LF`aOk_UA?{N@uISjA9` zP`48u{E1K#;m-gV1IdAC9?6BcKt|Do*y8TQB(ti(2~HaT^PrIvKze|PP|pQ=haA(% z0OA4G1J4$1aUPuVY0Z znKXNRO82^n7gef4oHB@owurGp4$U^JzKiv4Q#K)!Ky`R;|E1KQ8`2t=ow>-ws;UC zl-bpQNK=(CYaA^!sT28d2D8HFiY#u{EvAr%Va?*KQy2?RlP80CF^uOyNVXx2PnHjM z0#3HJ;@}5IFT@|Wy;rv{`IzZg87Ic3K9@%c{F|K}Od}sj6uo8^`ya^P6~_y?gGanT zdcl{01_)aLxvr$fl`WFJ{nVaG{sRQk{epKPsG7*5RIsX5Jm(e~Z;cfysL7h1q3o=b zqnY+}^cQfM=qpy-czdi_+Dr!Unp5Mc6Sm&^-jjtdj%qd>za2R3A-Zty?V5rN-(Bc$ zzHxW;(Jk}JHzhUn+-R*$P;TxRi;gx9w$cBakLT9}wL zhFM8Wb65hiNg`cSXi`mLW(AG6H)z>4N4zE}%y|0j2~l`rDL05{io?8 z_sw#CShX1=I>9BpDjP&lQgK6X z4j)UyiXB>f?NRt{^Rert`|f)Ffy49VdkgCVXw|{OZI1UpQSFP1+io(`kdnxh!#k_( z0T)gtB^%&N?%jq`!~?{rl6sJltzW#)4|@d^3l8l z>~(tM+$InA#PUmtJgA1Ct)+Px3~O#{V@q?ww7E+g7q@z_vntkR761k%5z2%9$)~}t z7|+9rjg&bFM+b<7mbhZ$`E%nrQJ4w-#8uL@F1>b!4Da6=JSsnc)_2EUtXe;Hk!$OZ z^^RM?fic+(eb0>uUv9D}$KqrkBi72aXg(5ovGC(k%Nkhd^OfpQWwT@JGIsnAuHc0D delta 4617 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 diff --git a/Content/Maps/BlasterMap.umap b/Content/Maps/BlasterMap.umap index fe90ccdf07514656414e98b2db847d68bbec2f0d..8b77609f8b889963c9ebd6a4af9814fd5f82403b 100644 GIT binary patch delta 22425 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 Fe*rkUjxhiL delta 22148 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 K52&=a^8W!qsaKx> diff --git a/Source/Blaster/Character/BlasterCharacter.cpp b/Source/Blaster/Character/BlasterCharacter.cpp index 4d07751..88f645e 100644 --- a/Source/Blaster/Character/BlasterCharacter.cpp +++ b/Source/Blaster/Character/BlasterCharacter.cpp @@ -27,7 +27,7 @@ ABlasterCharacter::ABlasterCharacter() SpawnCollisionHandlingMethod = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn; CameraBoom = CreateDefaultSubobject(TEXT("CameraBoom")); CameraBoom->SetupAttachment(GetMesh()); - CameraBoom->TargetArmLength = 350.f; + CameraBoom->TargetArmLength = 600.f; CameraBoom->bUsePawnControlRotation = true; FollowCamera = CreateDefaultSubobject(TEXT("FollowCamera")); @@ -44,11 +44,12 @@ ABlasterCharacter::ABlasterCharacter() Combat->SetIsReplicated(true); GetCharacterMovement()->NavAgentProps.bCanCrouch = true; - GetCapsuleComponent()->SetCollisionResponseToChannel(ECC_Camera, ECR_Ignore); + GetCapsuleComponent()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Camera, ECollisionResponse::ECR_Ignore); GetMesh()->SetCollisionObjectType(ECC_SkeletalMesh); - GetMesh()->SetCollisionResponseToChannel(ECC_Camera, ECR_Ignore); - GetMesh()->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block); - GetCharacterMovement()->RotationRate = FRotator(0.f, 850.f, 0.f); + GetMesh()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Camera, ECollisionResponse::ECR_Ignore); + GetMesh()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Visibility, ECollisionResponse::ECR_Block); + GetCharacterMovement()->RotationRate = FRotator(0.f, 0.f, 850.f); + TurningInPlace = ETurningInPlace::ETIP_NotTurning; NetUpdateFrequency = 66.f; MinNetUpdateFrequency = 33.f; @@ -56,17 +57,6 @@ ABlasterCharacter::ABlasterCharacter() DissolveTimeline = CreateDefaultSubobject(TEXT("DissolveTimelineComponent")); } -void ABlasterCharacter::BeginPlay() -{ - Super::BeginPlay(); - - UpdateHUDHealth(); - if (HasAuthority()) - { - OnTakeAnyDamage.AddDynamic(this, &ABlasterCharacter::ReceiveDamage); - } -} - void ABlasterCharacter::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); @@ -79,76 +69,10 @@ void ABlasterCharacter::GetLifetimeReplicatedProps(TArray& Ou void ABlasterCharacter::OnRep_ReplicatedMovement() { Super::OnRep_ReplicatedMovement(); - SimProxiesTurn(); TimeSinceLastMovementReplication = 0.f; } -void ABlasterCharacter::Destroyed() -{ - Super::Destroyed(); - - if (EliminationBotComponent) - { - EliminationBotComponent->DestroyComponent(); - } - if (Combat && Combat->EquippedWeapon) - { - Combat->EquippedWeapon->Destroy(); - } -} - -void ABlasterCharacter::PostInitializeComponents() -{ - Super::PostInitializeComponents(); - - if (Combat) - { - Combat->Character = this; - } -} - -void ABlasterCharacter::PlayFireMontage(bool bAiming) -{ - if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return; - - UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance(); - if (AnimInstance && FireWeaponMontage) - { - AnimInstance->Montage_Play(FireWeaponMontage); - const FName SectionName = bAiming ? FName("RifleADS") : FName("RifleHip"); - AnimInstance->Montage_JumpToSection(SectionName); - } -} - -void ABlasterCharacter::PlayReloadMontage() -{ - if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return; - - UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance(); - if (AnimInstance && ReloadMontage) - { - AnimInstance->Montage_Play(ReloadMontage); - FName SectionName; - switch (Combat->EquippedWeapon->GetWeaponType()) - { - case EWeaponType::EWT_AssaultRifle: - SectionName = FName("Rifle"); - break; - } - AnimInstance->Montage_JumpToSection(SectionName); - } -} - -void ABlasterCharacter::PlayEliminatedMontage() -{ - UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance(); - if (AnimInstance && EliminatedMontage) - { - AnimInstance->Montage_Play(EliminatedMontage); - } -} - void ABlasterCharacter::Eliminated() { if (Combat && Combat->EquippedWeapon) @@ -156,7 +80,12 @@ void ABlasterCharacter::Eliminated() Combat->EquippedWeapon->Dropped(); } MulticastEliminated(); - GetWorldTimerManager().SetTimer(EliminationTimer, this, &ABlasterCharacter::EliminationTimerFinished, EliminationDelay); + GetWorldTimerManager().SetTimer( + EliminationTimer, + this, + &ABlasterCharacter::EliminationTimerFinished, + EliminationDelay + ); } void ABlasterCharacter::MulticastEliminated_Implementation() @@ -182,7 +111,6 @@ void ABlasterCharacter::MulticastEliminated_Implementation() GetCharacterMovement()->DisableMovement(); GetCharacterMovement()->StopMovementImmediately(); bDisableGameplay = true; - // Disable collision GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision); GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision); @@ -190,13 +118,21 @@ void ABlasterCharacter::MulticastEliminated_Implementation() // Elimination bot if (EliminationBotEffect) { - const FVector EliminationBotSpawnPoint(GetActorLocation().X, GetActorLocation().Y, GetActorLocation().Z + 200.f); - EliminationBotComponent = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), EliminationBotEffect, EliminationBotSpawnPoint, GetActorRotation()); - + FVector EliminationBotSpawnPoint(GetActorLocation().X, GetActorLocation().Y, GetActorLocation().Z + 200.f); + EliminationBotComponent = UGameplayStatics::SpawnEmitterAtLocation( + GetWorld(), + EliminationBotEffect, + EliminationBotSpawnPoint, + GetActorRotation() + ); } if (EliminationBotSound) { - UGameplayStatics::SpawnSoundAtLocation(this, EliminationBotSound, GetActorLocation()); + UGameplayStatics::SpawnSoundAtLocation( + this, + EliminationBotSound, + GetActorLocation() + ); } } @@ -209,40 +145,38 @@ void ABlasterCharacter::EliminationTimerFinished() } } -void ABlasterCharacter::PlayHitReactMontage() +void ABlasterCharacter::Destroyed() { - if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return; + Super::Destroyed(); - UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance(); - if (AnimInstance && HitReactMontage) + if (EliminationBotComponent) { - AnimInstance->Montage_Play(HitReactMontage); - const FName SectionName = FName("FromFront"); - AnimInstance->Montage_JumpToSection(SectionName); + EliminationBotComponent->DestroyComponent(); + } + if (Combat && Combat->EquippedWeapon) + { + Combat->EquippedWeapon->Destroy(); } } -void ABlasterCharacter::ReceiveDamage(AActor* DamagedActor, float Damage, const UDamageType* DamageType, AController* InstigatorController, - AActor* DamageCauser) +void ABlasterCharacter::BeginPlay() { - Health = FMath::Clamp(Health - Damage, 0.f, MaxHealth); + Super::BeginPlay(); UpdateHUDHealth(); - if (Health > 0.f) + if (HasAuthority()) { - PlayHitReactMontage(); + OnTakeAnyDamage.AddDynamic(this, &ABlasterCharacter::ReceiveDamage); } +} - if (Health == 0.f) - { - ABlasterGameMode* GameMode = GetWorld()->GetAuthGameMode(); - if (GameMode) - { - BlasterPlayerController = BlasterPlayerController == nullptr ? Cast(Controller) : BlasterPlayerController; - ABlasterPlayerController* AttackerController = Cast(InstigatorController); - GameMode->PlayerEliminated(this, BlasterPlayerController, AttackerController); - } - } +void ABlasterCharacter::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); + + RotateInPlace(DeltaTime); + HideCameraIfCharacterClose(); + PollInit(); } void ABlasterCharacter::RotateInPlace(float DeltaTime) @@ -253,7 +187,7 @@ void ABlasterCharacter::RotateInPlace(float DeltaTime) TurningInPlace = ETurningInPlace::ETIP_NotTurning; return; } - if (GetLocalRole() > ROLE_SimulatedProxy && IsLocallyControlled()) + if (GetLocalRole() > ENetRole::ROLE_SimulatedProxy && IsLocallyControlled()) { AimOffset(DeltaTime); } @@ -268,46 +202,108 @@ void ABlasterCharacter::RotateInPlace(float DeltaTime) } } -void ABlasterCharacter::Tick(float DeltaTime) -{ - Super::Tick(DeltaTime); - - RotateInPlace(DeltaTime); - HideCameraIfCharacterClose(); - PollInit(); -} - -void ABlasterCharacter::PollInit() -{ - if (BlasterPlayerState == nullptr) - { - BlasterPlayerState = GetPlayerState(); - if (BlasterPlayerState) - { - // Initialize Score now we have the PlayerState - BlasterPlayerState->IncreaseScore(0.f); - BlasterPlayerState->IncreaseDefeats(0); - } - } -} - void ABlasterCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { Super::SetupPlayerInputComponent(PlayerInputComponent); PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ABlasterCharacter::Jump); - PlayerInputComponent->BindAction("Equip", IE_Pressed, this, &ABlasterCharacter::EquipButtonPressed); - PlayerInputComponent->BindAction("Reload", IE_Pressed, this, &ABlasterCharacter::ReloadButtonPressed); - PlayerInputComponent->BindAction("Crouch", IE_Pressed, this, &ABlasterCharacter::CrouchButtonPressed); - PlayerInputComponent->BindAction("Aim", IE_Pressed, this, &ABlasterCharacter::AimButtonPressed); - PlayerInputComponent->BindAction("Aim", IE_Released, this, &ABlasterCharacter::AimButtonReleased); - PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ABlasterCharacter::FireButtonPressed); - PlayerInputComponent->BindAction("Fire", IE_Released, this, &ABlasterCharacter::FireButtonReleased); PlayerInputComponent->BindAxis("MoveForward", this, &ABlasterCharacter::MoveForward); PlayerInputComponent->BindAxis("MoveRight", this, &ABlasterCharacter::MoveRight); PlayerInputComponent->BindAxis("Turn", this, &ABlasterCharacter::Turn); PlayerInputComponent->BindAxis("LookUp", this, &ABlasterCharacter::LookUp); + + PlayerInputComponent->BindAction("Equip", IE_Pressed, this, &ABlasterCharacter::EquipButtonPressed); + PlayerInputComponent->BindAction("Crouch", IE_Pressed, this, &ABlasterCharacter::CrouchButtonPressed); + PlayerInputComponent->BindAction("Aim", IE_Pressed, this, &ABlasterCharacter::AimButtonPressed); + PlayerInputComponent->BindAction("Aim", IE_Released, this, &ABlasterCharacter::AimButtonReleased); + PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ABlasterCharacter::FireButtonPressed); + PlayerInputComponent->BindAction("Fire", IE_Released, this, &ABlasterCharacter::FireButtonReleased); + PlayerInputComponent->BindAction("Reload", IE_Pressed, this, &ABlasterCharacter::ReloadButtonPressed); +} + +void ABlasterCharacter::PostInitializeComponents() +{ + Super::PostInitializeComponents(); + if (Combat) + { + Combat->Character = this; + } +} + +void ABlasterCharacter::PlayFireMontage(bool bAiming) +{ + if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return; + + UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance(); + if (AnimInstance && FireWeaponMontage) + { + AnimInstance->Montage_Play(FireWeaponMontage); + FName SectionName; + SectionName = bAiming ? FName("RifleAim") : FName("RifleHip"); + AnimInstance->Montage_JumpToSection(SectionName); + } +} + +void ABlasterCharacter::PlayReloadMontage() +{ + if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return; + + UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance(); + if (AnimInstance && ReloadMontage) + { + AnimInstance->Montage_Play(ReloadMontage); + FName SectionName; + + switch (Combat->EquippedWeapon->GetWeaponType()) + { + case EWeaponType::EWT_AssaultRifle: + SectionName = FName("Rifle"); + break; + } + + AnimInstance->Montage_JumpToSection(SectionName); + } +} + +void ABlasterCharacter::PlayEliminatedMontage() +{ + UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance(); + if (AnimInstance && EliminatedMontage) + { + AnimInstance->Montage_Play(EliminatedMontage); + } +} + +void ABlasterCharacter::PlayHitReactMontage() +{ + if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return; + + UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance(); + if (AnimInstance && HitReactMontage) + { + AnimInstance->Montage_Play(HitReactMontage); + FName SectionName("FromFront"); + AnimInstance->Montage_JumpToSection(SectionName); + } +} + +void ABlasterCharacter::ReceiveDamage(AActor* DamagedActor, float Damage, const UDamageType* DamageType, AController* InstigatorController, AActor* DamageCauser) +{ + Health = FMath::Clamp(Health - Damage, 0.f, MaxHealth); + UpdateHUDHealth(); + if (Health > 0.f) PlayHitReactMontage(); + + if (Health == 0.f) + { + ABlasterGameMode* BlasterGameMode = GetWorld()->GetAuthGameMode(); + if (BlasterGameMode) + { + BlasterPlayerController = BlasterPlayerController == nullptr ? Cast(Controller) : BlasterPlayerController; + ABlasterPlayerController* AttackerController = Cast(InstigatorController); + BlasterGameMode->PlayerEliminated(this, BlasterPlayerController, AttackerController); + } + } } void ABlasterCharacter::MoveForward(float Value) @@ -317,7 +313,6 @@ void ABlasterCharacter::MoveForward(float Value) { const FRotator YawRotation(0.f, Controller->GetControlRotation().Yaw, 0.f); const FVector Direction(FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X)); - AddMovementInput(Direction, Value); } } @@ -329,7 +324,6 @@ void ABlasterCharacter::MoveRight(float Value) { const FRotator YawRotation(0.f, Controller->GetControlRotation().Yaw, 0.f); const FVector Direction(FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y)); - AddMovementInput(Direction, Value); } } @@ -360,12 +354,11 @@ void ABlasterCharacter::EquipButtonPressed() } } -void ABlasterCharacter::ReloadButtonPressed() +void ABlasterCharacter::ServerEquipButtonPressed_Implementation() { - if (bDisableGameplay) return; if (Combat) { - Combat->Reload(); + Combat->EquipWeapon(OverlappingWeapon); } } @@ -382,6 +375,15 @@ void ABlasterCharacter::CrouchButtonPressed() } } +void ABlasterCharacter::ReloadButtonPressed() +{ + if (bDisableGameplay) return; + if (Combat) + { + Combat->Reload(); + } +} + void ABlasterCharacter::AimButtonPressed() { if (bDisableGameplay) return; @@ -400,47 +402,24 @@ void ABlasterCharacter::AimButtonReleased() } } -void ABlasterCharacter::Jump() +float ABlasterCharacter::CalculateSpeed() { - if (bDisableGameplay) return; - if (bIsCrouched) - { - UnCrouch(); - } - else - { - Super::Jump(); - } -} - -void ABlasterCharacter::FireButtonPressed() -{ - if (Combat) - { - Combat->FireButtonPressed(true); - } -} - -void ABlasterCharacter::FireButtonReleased() -{ - if (Combat) - { - Combat->FireButtonPressed(false); - } + FVector Velocity = GetVelocity(); + Velocity.Z = 0.f; + return Velocity.Size(); } void ABlasterCharacter::AimOffset(float DeltaTime) { if (Combat && Combat->EquippedWeapon == nullptr) return; - - const float Speed = CalculateSpeed(); - const bool bIsInAir = GetCharacterMovement()->IsFalling(); + float Speed = CalculateSpeed(); + bool bIsInAir = GetCharacterMovement()->IsFalling(); - if (Speed == 0.f && !bIsInAir) // Standing still, not jumping + if (Speed == 0.f && !bIsInAir) // standing still, not jumping { bRotateRootBone = true; - const FRotator CurrentAimRotation = FRotator(0.f, GetBaseAimRotation().Yaw, 0.f); - const FRotator DeltaAimRotation = UKismetMathLibrary::NormalizedDeltaRotator(CurrentAimRotation, StartingAimRotation); + FRotator CurrentAimRotation = FRotator(0.f, GetBaseAimRotation().Yaw, 0.f); + FRotator DeltaAimRotation = UKismetMathLibrary::NormalizedDeltaRotator(CurrentAimRotation, StartingAimRotation); AO_Yaw = DeltaAimRotation.Yaw; if (TurningInPlace == ETurningInPlace::ETIP_NotTurning) { @@ -449,7 +428,7 @@ void ABlasterCharacter::AimOffset(float DeltaTime) bUseControllerRotationYaw = true; TurnInPlace(DeltaTime); } - if (Speed > 0.f || bIsInAir) // Running or jumping + if (Speed > 0.f || bIsInAir) // running, or jumping { bRotateRootBone = false; StartingAimRotation = FRotator(0.f, GetBaseAimRotation().Yaw, 0.f); @@ -464,13 +443,11 @@ void ABlasterCharacter::AimOffset(float DeltaTime) void ABlasterCharacter::CalculateAO_Pitch() { AO_Pitch = GetBaseAimRotation().Pitch; - - // Fix pitch/yaw compression if (AO_Pitch > 90.f && !IsLocallyControlled()) { // map pitch from [270, 360) to [-90, 0) - const FVector2d InRange(270.f, 360.f); - const FVector2d OutRange(-90.f, 0.f); + FVector2D InRange(270.f, 360.f); + FVector2D OutRange(-90.f, 0.f); AO_Pitch = FMath::GetMappedRangeValueClamped(InRange, OutRange, AO_Pitch); } } @@ -478,20 +455,18 @@ void ABlasterCharacter::CalculateAO_Pitch() void ABlasterCharacter::SimProxiesTurn() { if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return; - bRotateRootBone = false; - - const float Speed = CalculateSpeed(); + float Speed = CalculateSpeed(); if (Speed > 0.f) { TurningInPlace = ETurningInPlace::ETIP_NotTurning; return; } - + ProxyRotationLastFrame = ProxyRotation; ProxyRotation = GetActorRotation(); ProxyYaw = UKismetMathLibrary::NormalizedDeltaRotator(ProxyRotation, ProxyRotationLastFrame).Yaw; - + if (FMath::Abs(ProxyYaw) > TurnThreshold) { if (ProxyYaw > TurnThreshold) @@ -508,13 +483,38 @@ void ABlasterCharacter::SimProxiesTurn() } return; } - TurningInPlace = ETurningInPlace::ETIP_NotTurning; } -void ABlasterCharacter::ServerEquipButtonPressed_Implementation() +void ABlasterCharacter::Jump() { - EquipButtonPressed(); + if (bDisableGameplay) return; + if (bIsCrouched) + { + UnCrouch(); + } + else + { + Super::Jump(); + } +} + +void ABlasterCharacter::FireButtonPressed() +{ + if (bDisableGameplay) return; + if (Combat) + { + Combat->FireButtonPressed(true); + } +} + +void ABlasterCharacter::FireButtonReleased() +{ + if (bDisableGameplay) return; + if (Combat) + { + Combat->FireButtonPressed(false); + } } void ABlasterCharacter::TurnInPlace(float DeltaTime) @@ -537,18 +537,6 @@ void ABlasterCharacter::TurnInPlace(float DeltaTime) StartingAimRotation = FRotator(0.f, GetBaseAimRotation().Yaw, 0.f); } } - // switch (TurningInPlace) - // { - // case ETurningInPlace::ETIP_Left: - // UE_LOG(LogTemp, Warning, TEXT("TurningInPlace: Left")); - // break; - // case ETurningInPlace::ETIP_Right: - // UE_LOG(LogTemp, Warning, TEXT("TurningInPlace: Right")); - // break; - // case ETurningInPlace::ETIP_NotTurning: - // UE_LOG(LogTemp, Warning, TEXT("TurningInPlace: NotTurning")); - // break; - // } } void ABlasterCharacter::HideCameraIfCharacterClose() @@ -572,20 +560,10 @@ void ABlasterCharacter::HideCameraIfCharacterClose() } } -float ABlasterCharacter::CalculateSpeed() -{ - FVector Velocity = GetVelocity(); - Velocity.Z = 0.f; - return Velocity.Size(); -} - void ABlasterCharacter::OnRep_Health() { UpdateHUDHealth(); - if (Health > 0.f) - { - PlayHitReactMontage(); - } + if (Health > 0.f) PlayHitReactMontage(); } void ABlasterCharacter::UpdateHUDHealth() @@ -597,6 +575,19 @@ void ABlasterCharacter::UpdateHUDHealth() } } +void ABlasterCharacter::PollInit() +{ + if (BlasterPlayerState == nullptr) + { + BlasterPlayerState = GetPlayerState(); + if (BlasterPlayerState) + { + BlasterPlayerState->AddToScore(0.f); + BlasterPlayerState->AddToDefeats(0); + } + } +} + void ABlasterCharacter::UpdateDissolveMaterial(float DissolveValue) { if (DynamicDissolveMaterialInstance) @@ -621,7 +612,6 @@ void ABlasterCharacter::SetOverlappingWeapon(AWeapon* Weapon) { OverlappingWeapon->ShowPickupWidget(false); } - OverlappingWeapon = Weapon; if (IsLocallyControlled()) { @@ -632,6 +622,18 @@ void ABlasterCharacter::SetOverlappingWeapon(AWeapon* Weapon) } } +void ABlasterCharacter::OnRep_OverlappingWeapon(AWeapon* LastWeapon) +{ + if (OverlappingWeapon) + { + OverlappingWeapon->ShowPickupWidget(true); + } + if (LastWeapon) + { + LastWeapon->ShowPickupWidget(false); + } +} + bool ABlasterCharacter::IsWeaponEquipped() { return Combat && Combat->EquippedWeapon; @@ -645,14 +647,12 @@ bool ABlasterCharacter::IsAiming() AWeapon* ABlasterCharacter::GetEquippedWeapon() { if (Combat == nullptr) return nullptr; - return Combat->EquippedWeapon; } FVector ABlasterCharacter::GetHitTarget() const { if (Combat == nullptr) return FVector(); - return Combat->HitTarget; } @@ -660,16 +660,4 @@ ECombatState ABlasterCharacter::GetCombatState() const { if (Combat == nullptr) return ECombatState::ECS_MAX; return Combat->CombatState; -} - -void ABlasterCharacter::OnRep_OverlappingWeapon(AWeapon* LastWeapon) -{ - if (OverlappingWeapon) - { - OverlappingWeapon->ShowPickupWidget(true); - } - if (LastWeapon) - { - LastWeapon->ShowPickupWidget(false); - } -} +} \ No newline at end of file diff --git a/Source/Blaster/Character/BlasterCharacter.h b/Source/Blaster/Character/BlasterCharacter.h index eeca674..08a129c 100644 --- a/Source/Blaster/Character/BlasterCharacter.h +++ b/Source/Blaster/Character/BlasterCharacter.h @@ -3,7 +3,7 @@ #pragma once #include "CoreMinimal.h" -#include "Blaster/Interfaces/InteractWithCrosshairInterface.h" +#include "Blaster/Interfaces/InteractWithCrosshairsInterface.h" #include "Blaster/Types/CombatState.h" #include "Blaster/Types/TurningInPlace.h" #include "Components/TimelineComponent.h" @@ -12,7 +12,7 @@ #include "BlasterCharacter.generated.h" UCLASS() -class BLASTER_API ABlasterCharacter : public ACharacter, public IInteractWithCrosshairInterface +class BLASTER_API ABlasterCharacter : public ACharacter, public IInteractWithCrosshairsInterface { GENERATED_BODY() diff --git a/Source/Blaster/Components/CombatComponent.cpp b/Source/Blaster/Components/CombatComponent.cpp index 6cfba8e..b4d6e34 100644 --- a/Source/Blaster/Components/CombatComponent.cpp +++ b/Source/Blaster/Components/CombatComponent.cpp @@ -4,6 +4,7 @@ #include "CombatComponent.h" #include "Blaster/Character/BlasterCharacter.h" +#include "Blaster/Interfaces/InteractWithCrosshairsInterface.h" #include "Blaster/PlayerController/BlasterPlayerController.h" #include "Blaster/Weapon/Weapon.h" #include "Camera/CameraComponent.h" @@ -17,7 +18,7 @@ UCombatComponent::UCombatComponent() PrimaryComponentTick.bCanEverTick = true; BaseWalkSpeed = 600.f; - AimWalkSpeed = 350.f; + AimWalkSpeed = 450.f; } void UCombatComponent::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const @@ -25,8 +26,8 @@ void UCombatComponent::GetLifetimeReplicatedProps(TArray& Out Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(UCombatComponent, EquippedWeapon); - DOREPLIFETIME_CONDITION(UCombatComponent, CarriedAmmo, COND_OwnerOnly); DOREPLIFETIME(UCombatComponent, bAiming); + DOREPLIFETIME_CONDITION(UCombatComponent, CarriedAmmo, COND_OwnerOnly); DOREPLIFETIME(UCombatComponent, CombatState); } @@ -65,6 +66,273 @@ void UCombatComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActo } } +void UCombatComponent::FireButtonPressed(bool bPressed) +{ + bFireButtonPressed = bPressed; + if (bFireButtonPressed && EquippedWeapon) + { + Fire(); + } +} + +void UCombatComponent::Fire() +{ + if (CanFire()) + { + bCanFire = false; + ServerFire(HitTarget); + if (EquippedWeapon) + { + CrosshairShootingFactor = .75f; + } + StartFireTimer(); + } +} + +void UCombatComponent::StartFireTimer() +{ + if (EquippedWeapon == nullptr || Character == nullptr) return; + Character->GetWorldTimerManager().SetTimer( + FireTimer, + this, + &UCombatComponent::FireTimerFinished, + EquippedWeapon->FireDelay + ); +} + +void UCombatComponent::FireTimerFinished() +{ + if (EquippedWeapon == nullptr) return; + bCanFire = true; + if (bFireButtonPressed && EquippedWeapon->bAutomatic) + { + Fire(); + } + if (EquippedWeapon->IsEmpty()) + { + Reload(); + } +} + +void UCombatComponent::ServerFire_Implementation(const FVector_NetQuantize& TraceHitTarget) +{ + MulticastFire(TraceHitTarget); +} + +void UCombatComponent::MulticastFire_Implementation(const FVector_NetQuantize& TraceHitTarget) +{ + if (EquippedWeapon == nullptr) return; + if (Character && CombatState == ECombatState::ECS_Unoccupied) + { + Character->PlayFireMontage(bAiming); + EquippedWeapon->Fire(TraceHitTarget); + } +} + +void UCombatComponent::EquipWeapon(AWeapon* WeaponToEquip) +{ + if (Character == nullptr || WeaponToEquip == nullptr) return; + if (EquippedWeapon) + { + EquippedWeapon->Dropped(); + } + EquippedWeapon = WeaponToEquip; + EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped); + const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket")); + if (HandSocket) + { + HandSocket->AttachActor(EquippedWeapon, Character->GetMesh()); + } + EquippedWeapon->SetOwner(Character); + EquippedWeapon->SetHUDAmmo(); + + if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType())) + { + CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()]; + } + + Controller = Controller == nullptr ? Cast(Character->Controller) : Controller; + if (Controller) + { + Controller->SetHUDCarriedAmmo(CarriedAmmo); + } + + if (EquippedWeapon->EquipSound) + { + UGameplayStatics::PlaySoundAtLocation( + this, + EquippedWeapon->EquipSound, + Character->GetActorLocation() + ); + } + + if (EquippedWeapon->IsEmpty()) + { + Reload(); + } + + Character->GetCharacterMovement()->bOrientRotationToMovement = false; + Character->bUseControllerRotationYaw = true; +} + +void UCombatComponent::Reload() +{ + if (CarriedAmmo > 0 && CombatState != ECombatState::ECS_Reloading) + { + ServerReload(); + } +} + +void UCombatComponent::ServerReload_Implementation() +{ + if (Character == nullptr || EquippedWeapon == nullptr) return; + + // return if weapon mag is at max capacity + if (EquippedWeapon->GetAmmo() == EquippedWeapon->GetMagCapacity()) return; + + CombatState = ECombatState::ECS_Reloading; + HandleReload(); +} + +void UCombatComponent::FinishedReloading() +{ + if (Character == nullptr) return; + if (Character->HasAuthority()) + { + CombatState = ECombatState::ECS_Unoccupied; + UpdateAmmoValues(); + } + if (bFireButtonPressed) + { + Fire(); + } +} + +void UCombatComponent::UpdateAmmoValues() +{ + if (Character == nullptr || EquippedWeapon == nullptr) return; + int32 ReloadAmount = AmountToReload(); + if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType())) + { + CarriedAmmoMap[EquippedWeapon->GetWeaponType()] -= ReloadAmount; + CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()]; + } + Controller = Controller == nullptr ? Cast(Character->Controller) : Controller; + if (Controller) + { + Controller->SetHUDCarriedAmmo(CarriedAmmo); + } + EquippedWeapon->AddAmmo(-ReloadAmount); +} + +void UCombatComponent::OnRep_CombatState() +{ + switch (CombatState) + { + case ECombatState::ECS_Reloading: + HandleReload(); + break; + case ECombatState::ECS_Unoccupied: + if (bFireButtonPressed) + { + Fire(); + } + break; + } +} + +void UCombatComponent::HandleReload() +{ + Character->PlayReloadMontage(); +} + +int32 UCombatComponent::AmountToReload() +{ + if (EquippedWeapon == nullptr) return 0; + int32 RoomInMag = EquippedWeapon->GetMagCapacity() - EquippedWeapon->GetAmmo(); + + if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType())) + { + int32 AmountCarried = CarriedAmmoMap[EquippedWeapon->GetWeaponType()]; + int32 Least = FMath::Min(RoomInMag, AmountCarried); + return FMath::Clamp(RoomInMag, 0, Least); + } + return 0; +} + +void UCombatComponent::OnRep_EquippedWeapon() +{ + if (EquippedWeapon && Character) + { + EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped); + const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket")); + if (HandSocket) + { + HandSocket->AttachActor(EquippedWeapon, Character->GetMesh()); + } + Character->GetCharacterMovement()->bOrientRotationToMovement = false; + Character->bUseControllerRotationYaw = true; + + if (EquippedWeapon->EquipSound) + { + UGameplayStatics::PlaySoundAtLocation( + this, + EquippedWeapon->EquipSound, + Character->GetActorLocation() + ); + } + } +} + +void UCombatComponent::TraceUnderCrosshairs(FHitResult& TraceHitResult) +{ + FVector2D ViewportSize; + if (GEngine && GEngine->GameViewport) + { + GEngine->GameViewport->GetViewportSize(ViewportSize); + } + + FVector2D CrosshairLocation(ViewportSize.X / 2.f, ViewportSize.Y / 2.f); + FVector CrosshairWorldPosition; + FVector CrosshairWorldDirection; + bool bScreenToWorld = UGameplayStatics::DeprojectScreenToWorld( + UGameplayStatics::GetPlayerController(this, 0), + CrosshairLocation, + CrosshairWorldPosition, + CrosshairWorldDirection + ); + + if (bScreenToWorld) + { + FVector Start = CrosshairWorldPosition; + + if (Character) + { + float DistanceToCharacter = (Character->GetActorLocation() - Start).Size(); + Start += CrosshairWorldDirection * (DistanceToCharacter + 100.f); + } + + FVector End = Start + CrosshairWorldDirection * TRACE_LENGTH; + + GetWorld()->LineTraceSingleByChannel( + TraceHitResult, + Start, + End, + ECollisionChannel::ECC_Visibility + ); + if (TraceHitResult.GetActor() && TraceHitResult.GetActor()->Implements()) + { + HUDPackage.CrosshairsColor = FLinearColor::Red; + } + else + { + HUDPackage.CrosshairsColor = FLinearColor::White; + } + + if (!TraceHitResult.bBlockingHit) TraceHitResult.ImpactPoint = End; + } +} + void UCombatComponent::SetHUDCrosshairs(float DeltaTime) { if (Character == nullptr || Character->Controller == nullptr) return; @@ -80,22 +348,22 @@ void UCombatComponent::SetHUDCrosshairs(float DeltaTime) HUDPackage.CrosshairsCenter = EquippedWeapon->CrosshairsCenter; HUDPackage.CrosshairsLeft = EquippedWeapon->CrosshairsLeft; HUDPackage.CrosshairsRight = EquippedWeapon->CrosshairsRight; - HUDPackage.CrosshairsTop = EquippedWeapon->CrosshairsTop; HUDPackage.CrosshairsBottom = EquippedWeapon->CrosshairsBottom; + HUDPackage.CrosshairsTop = EquippedWeapon->CrosshairsTop; } else { HUDPackage.CrosshairsCenter = nullptr; HUDPackage.CrosshairsLeft = nullptr; HUDPackage.CrosshairsRight = nullptr; - HUDPackage.CrosshairsTop = nullptr; HUDPackage.CrosshairsBottom = nullptr; + HUDPackage.CrosshairsTop = nullptr; } - // Calculate crosshair spread - // Velocity [0, 600] -> Spread [0, 1] - const FVector2D WalkSpeedRange(0.f, Character->GetCharacterMovement()->MaxWalkSpeed); - const FVector2D VelocityMultiplierRange(0.f, 1.f); + + // [0, 600] -> [0, 1] + FVector2D WalkSpeedRange(0.f, Character->GetCharacterMovement()->MaxWalkSpeed); + FVector2D VelocityMultiplierRange(0.f, 1.f); FVector Velocity = Character->GetVelocity(); Velocity.Z = 0.f; @@ -170,59 +438,9 @@ void UCombatComponent::ServerSetAiming_Implementation(bool bIsAiming) } } -void UCombatComponent::Fire() -{ - if (CanFire()) - { - bCanFire = false; - ServerFire(HitTarget); - - if (EquippedWeapon) - { - CrosshairShootingFactor = 0.75f; - } - - StartFireTimer(); - } - -} - -void UCombatComponent::FireButtonPressed(bool bPressed) -{ - bFireButtonPressed = bPressed; - - if (bFireButtonPressed && EquippedWeapon) - { - Fire(); - } -} - -void UCombatComponent::StartFireTimer() -{ - if (EquippedWeapon == nullptr || Character == nullptr) return; - - Character->GetWorldTimerManager().SetTimer(FireTimer, this, &UCombatComponent::FireTimerFinished, EquippedWeapon->FireDelay); -} - -void UCombatComponent::FireTimerFinished() -{ - if (EquippedWeapon == nullptr) return; - - bCanFire = true; - if (bFireButtonPressed && EquippedWeapon->bAutomatic) - { - Fire(); - } - if (EquippedWeapon->IsEmpty()) - { - Reload(); - } -} - bool UCombatComponent::CanFire() { if (EquippedWeapon == nullptr) return false; - return !EquippedWeapon->IsEmpty() && bCanFire && CombatState == ECombatState::ECS_Unoccupied; } @@ -239,212 +457,3 @@ void UCombatComponent::InitializeCarriedAmmo() { CarriedAmmoMap.Emplace(EWeaponType::EWT_AssaultRifle, StartingARAmmo); } - -void UCombatComponent::ServerFire_Implementation(const FVector_NetQuantize& TraceHitTarget) -{ - MulticastFire(TraceHitTarget); -} - -void UCombatComponent::MulticastFire_Implementation(const FVector_NetQuantize& TraceHitTarget) -{ - if (EquippedWeapon == nullptr) return; - if (Character && CombatState == ECombatState::ECS_Unoccupied) - { - Character->PlayFireMontage(bAiming); - EquippedWeapon->Fire(TraceHitTarget); - } -} - -void UCombatComponent::TraceUnderCrosshairs(FHitResult& TraceHitResult) -{ - FVector2d ViewPortSize; - if (GEngine && GEngine->GameViewport) - { - GEngine->GameViewport->GetViewportSize(ViewPortSize); - } - - FVector2d CrosshairLocation(ViewPortSize.X / 2.f, ViewPortSize.Y / 2.0f); - FVector CrosshairWorldPosition; - FVector CrosshairWorldDirection; - bool bScreenToWorld = UGameplayStatics::DeprojectScreenToWorld( - UGameplayStatics::GetPlayerController(this, 0), - CrosshairLocation, - CrosshairWorldPosition, - CrosshairWorldDirection - ); - - if (bScreenToWorld) - { - FVector Start = CrosshairWorldPosition; - if (Character) - { - float DistanceToCharacter = (Character->GetActorLocation() - Start).Size(); - Start += CrosshairWorldDirection * (DistanceToCharacter + 60.f); - } - FVector End = Start + CrosshairWorldDirection * TRACE_LENGTH; - - GetWorld()->LineTraceSingleByChannel( - TraceHitResult, - Start, - End, - ECollisionChannel::ECC_Visibility - ); - if (TraceHitResult.GetActor() && TraceHitResult.GetActor()->Implements()) - { - HUDPackage.CrosshairColor = FLinearColor::Red; - } - else - { - HUDPackage.CrosshairColor = FLinearColor::White; - } - - if (!TraceHitResult.bBlockingHit) TraceHitResult.ImpactPoint = End; - } -} - -void UCombatComponent::EquipWeapon(AWeapon* WeaponToEquip) -{ - if (Character == nullptr || WeaponToEquip == nullptr) return; - if (EquippedWeapon) - { - EquippedWeapon->Dropped(); - } - EquippedWeapon = WeaponToEquip; - EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped); - const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket")); - if (HandSocket) - { - HandSocket->AttachActor(EquippedWeapon, Character->GetMesh()); - } - EquippedWeapon->SetOwner(Character); - EquippedWeapon->SetHUDAmmo(); - - if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType())) - { - CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()]; - } - - Controller = Controller == nullptr ? Cast(Character->Controller) : Controller; - if (Controller) - { - Controller->SetHUDCarriedAmmo(CarriedAmmo); - } - - if (EquippedWeapon->EquipSound) - { - UGameplayStatics::PlaySoundAtLocation(this, EquippedWeapon->EquipSound, Character->GetActorLocation()); - } - - if (EquippedWeapon->IsEmpty()) - { - Reload(); - } - Character->GetCharacterMovement()->bOrientRotationToMovement = false; - Character->bUseControllerRotationYaw = true; -} - -void UCombatComponent::Reload() -{ - if (CarriedAmmo > 0 && CombatState != ECombatState::ECS_Reloading) - { - ServerReload(); - } -} - -void UCombatComponent::FinishedReloading() -{ - if (Character == nullptr) return; - if (Character->HasAuthority()) - { - CombatState = ECombatState::ECS_Unoccupied; - UpdateAmmoValues(); - } - if (bFireButtonPressed) - { - Fire(); - } -} - -void UCombatComponent::UpdateAmmoValues() -{ - if (Character == nullptr || EquippedWeapon == nullptr) return; - const int32 ReloadAmount = AmountToReload(); - if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType())) - { - CarriedAmmoMap[EquippedWeapon->GetWeaponType()] -= ReloadAmount; - CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()]; - } - Controller = Controller == nullptr ? Cast(Character->Controller) : Controller; - if (Controller) - { - Controller->SetHUDCarriedAmmo(CarriedAmmo); - } - EquippedWeapon->AddAmmo(-ReloadAmount); -} - -void UCombatComponent::ServerReload_Implementation() -{ - if (Character == nullptr || EquippedWeapon == nullptr) return; - - // return if weapon mag is at max capacity - if (EquippedWeapon->GetAmmo() == EquippedWeapon->GetMagCapacity()) return; - - CombatState = ECombatState::ECS_Reloading; - HandleReload(); -} - -void UCombatComponent::OnRep_CombatState() -{ - switch (CombatState) - { - case ECombatState::ECS_Reloading: - HandleReload(); - break; - case ECombatState::ECS_Unoccupied: - if (bFireButtonPressed) - { - Fire(); - } - break; - } -} - -void UCombatComponent::HandleReload() -{ - Character->PlayReloadMontage(); -} - -int32 UCombatComponent::AmountToReload() -{ - if (EquippedWeapon == nullptr) return 0; - - const int32 RoomInMag = EquippedWeapon->GetMagCapacity() - EquippedWeapon->GetAmmo(); - - if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType())) - { - const int32 AmountCarried = CarriedAmmoMap[EquippedWeapon->GetWeaponType()]; - const int32 Least = FMath::Min(RoomInMag, AmountCarried); - return FMath::Clamp(RoomInMag, 0, Least); - } - - return 0; -} - -void UCombatComponent::OnRep_EquippedWeapon() -{ - if (EquippedWeapon && Character) - { - EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped); - const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket")); - if (HandSocket) - { - HandSocket->AttachActor(EquippedWeapon, Character->GetMesh()); - } - if (EquippedWeapon->EquipSound) - { - UGameplayStatics::PlaySoundAtLocation(this, EquippedWeapon->EquipSound, Character->GetActorLocation()); - } - Character->GetCharacterMovement()->bOrientRotationToMovement = false; - Character->bUseControllerRotationYaw = true; - } -} diff --git a/Source/Blaster/GameMode/BlasterGameMode.cpp b/Source/Blaster/GameMode/BlasterGameMode.cpp index a1075f4..05824fe 100644 --- a/Source/Blaster/GameMode/BlasterGameMode.cpp +++ b/Source/Blaster/GameMode/BlasterGameMode.cpp @@ -2,13 +2,11 @@ #include "BlasterGameMode.h" - #include "Blaster/Character/BlasterCharacter.h" #include "Blaster/PlayerController/BlasterPlayerController.h" -#include "Blaster/PlayerState/BlasterPlayerState.h" -#include "GameFramework/PlayerStart.h" #include "Kismet/GameplayStatics.h" - +#include "GameFramework/PlayerStart.h" +#include "Blaster/PlayerState/BlasterPlayerState.h" namespace MatchState { @@ -27,30 +25,30 @@ void ABlasterGameMode::BeginPlay() LevelStartingTime = GetWorld()->GetTimeSeconds(); } -void ABlasterGameMode::Tick(float DeltaSeconds) +void ABlasterGameMode::Tick(float DeltaTime) { - Super::Tick(DeltaSeconds); + Super::Tick(DeltaTime); if (MatchState == MatchState::WaitingToStart) { - CountDownTime = WarmupTime - GetWorld()->GetTimeSeconds() + LevelStartingTime; - if (CountDownTime <= 0.f) + CountdownTime = WarmupTime - GetWorld()->GetTimeSeconds() + LevelStartingTime; + if (CountdownTime <= 0.f) { StartMatch(); } } else if (MatchState == MatchState::InProgress) { - CountDownTime = WarmupTime + MatchTime - GetWorld()->GetTimeSeconds() + LevelStartingTime; - if (CountDownTime <= 0.f) + CountdownTime = WarmupTime + MatchTime - GetWorld()->GetTimeSeconds() + LevelStartingTime; + if (CountdownTime <= 0.f) { SetMatchState(MatchState::Cooldown); } } else if (MatchState == MatchState::Cooldown) { - CountDownTime = CooldownTime + WarmupTime + MatchTime - GetWorld()->GetTimeSeconds() + LevelStartingTime; - if (CountDownTime <= 0.f) + CountdownTime = CooldownTime + WarmupTime + MatchTime - GetWorld()->GetTimeSeconds() + LevelStartingTime; + if (CountdownTime <= 0.f) { RestartGame(); } @@ -61,29 +59,31 @@ void ABlasterGameMode::OnMatchStateSet() { Super::OnMatchStateSet(); - for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator) + for (FConstPlayerControllerIterator It = GetWorld()->GetPlayerControllerIterator(); It; ++It) { - ABlasterPlayerController* PlayerController = Cast(*Iterator); - if (PlayerController) + ABlasterPlayerController* BlasterPlayer = Cast(*It); + if (BlasterPlayer) { - PlayerController->OnMatchStateSet(MatchState); + BlasterPlayer->OnMatchStateSet(MatchState); } } } -void ABlasterGameMode::PlayerEliminated(ABlasterCharacter* EliminatedCharacter, ABlasterPlayerController* VictimController, +void ABlasterGameMode::PlayerEliminated(class ABlasterCharacter* EliminatedCharacter, ABlasterPlayerController* VictimController, ABlasterPlayerController* AttackerController) { + if (AttackerController == nullptr || AttackerController->PlayerState == nullptr) return; + if (VictimController == nullptr || VictimController->PlayerState == nullptr) return; ABlasterPlayerState* AttackerPlayerState = AttackerController ? Cast(AttackerController->PlayerState) : nullptr; ABlasterPlayerState* VictimPlayerState = VictimController ? Cast(VictimController->PlayerState) : nullptr; if (AttackerPlayerState && AttackerPlayerState != VictimPlayerState) { - AttackerPlayerState->IncreaseScore(1.f); + AttackerPlayerState->AddToScore(1.f); } if (VictimPlayerState) { - VictimPlayerState->IncreaseDefeats(1); + VictimPlayerState->AddToDefeats(1); } if (EliminatedCharacter) @@ -99,12 +99,11 @@ void ABlasterGameMode::RequestRespawn(ACharacter* EliminatedCharacter, AControll EliminatedCharacter->Reset(); EliminatedCharacter->Destroy(); } - if (EliminatedController) { TArray PlayerStarts; UGameplayStatics::GetAllActorsOfClass(this, APlayerStart::StaticClass(), PlayerStarts); - const int32 Selection = FMath::RandRange(0, PlayerStarts.Num() - 1); + int32 Selection = FMath::RandRange(0, PlayerStarts.Num() - 1); RestartPlayerAtPlayerStart(EliminatedController, PlayerStarts[Selection]); } -} +} \ No newline at end of file diff --git a/Source/Blaster/GameMode/BlasterGameMode.h b/Source/Blaster/GameMode/BlasterGameMode.h index 1cf19f4..ff28489 100644 --- a/Source/Blaster/GameMode/BlasterGameMode.h +++ b/Source/Blaster/GameMode/BlasterGameMode.h @@ -22,7 +22,7 @@ class BLASTER_API ABlasterGameMode : public AGameMode public: ABlasterGameMode(); - virtual void Tick(float DeltaSeconds) override; + virtual void Tick(float DeltaTime) override; virtual void PlayerEliminated(class ABlasterCharacter* EliminatedCharacter, class ABlasterPlayerController* VictimController, class ABlasterPlayerController* AttackerController); virtual void RequestRespawn(ACharacter* EliminatedCharacter, AController* EliminatedController); @@ -43,8 +43,8 @@ protected: virtual void OnMatchStateSet() override; private: - float CountDownTime = 0.f; + float CountdownTime = 0.f; public: - FORCEINLINE float GetCountdownTime() const { return CountDownTime; } + FORCEINLINE float GetCountdownTime() const { return CountdownTime; } }; diff --git a/Source/Blaster/GameMode/LobbyGameMode.cpp b/Source/Blaster/GameMode/LobbyGameMode.cpp index 7328805..0adda8d 100644 --- a/Source/Blaster/GameMode/LobbyGameMode.cpp +++ b/Source/Blaster/GameMode/LobbyGameMode.cpp @@ -19,4 +19,4 @@ void ALobbyGameMode::PostLogin(APlayerController* NewPlayer) World->ServerTravel(FString("/Game/Maps/BlasterMap?listen")); } } -} +} \ No newline at end of file diff --git a/Source/Blaster/HUD/Announcement.h b/Source/Blaster/HUD/Announcement.h index 9f14d29..bff0230 100644 --- a/Source/Blaster/HUD/Announcement.h +++ b/Source/Blaster/HUD/Announcement.h @@ -13,16 +13,15 @@ UCLASS() class BLASTER_API UAnnouncement : public UUserWidget { GENERATED_BODY() - public: UPROPERTY(meta = (BindWidget)) - class UTextBlock* AnnouncementText; - + class UTextBlock* WarmupTime; + UPROPERTY(meta = (BindWidget)) - UTextBlock* CountdownText; - + UTextBlock* AnnouncementText; + UPROPERTY(meta = (BindWidget)) - UTextBlock* AnnouncementMessage; + UTextBlock* InfoText; }; diff --git a/Source/Blaster/HUD/BlasterHUD.cpp b/Source/Blaster/HUD/BlasterHUD.cpp index 9a7424a..3f9826c 100644 --- a/Source/Blaster/HUD/BlasterHUD.cpp +++ b/Source/Blaster/HUD/BlasterHUD.cpp @@ -22,7 +22,7 @@ void ABlasterHUD::AddCharacterOverlay() } } -void ABlasterHUD::AddAnnouncementOverlay() +void ABlasterHUD::AddAnnouncement() { APlayerController* PlayerController = GetOwningPlayerController(); if (PlayerController && AnnouncementClass) @@ -46,27 +46,27 @@ void ABlasterHUD::DrawHUD() if (HUDPackage.CrosshairsCenter) { const FVector2D Spread(0.f, 0.f); - DrawCrosshair(HUDPackage.CrosshairsCenter, ViewportCenter, Spread, HUDPackage.CrosshairColor); + DrawCrosshair(HUDPackage.CrosshairsCenter, ViewportCenter, Spread, HUDPackage.CrosshairsColor); } if (HUDPackage.CrosshairsLeft) { const FVector2D Spread(-SpreadScaled, 0.f); - DrawCrosshair(HUDPackage.CrosshairsLeft, ViewportCenter, Spread, HUDPackage.CrosshairColor); + DrawCrosshair(HUDPackage.CrosshairsLeft, ViewportCenter, Spread, HUDPackage.CrosshairsColor); } if (HUDPackage.CrosshairsRight) { const FVector2D Spread(SpreadScaled, 0.f); - DrawCrosshair(HUDPackage.CrosshairsRight, ViewportCenter, Spread, HUDPackage.CrosshairColor); + DrawCrosshair(HUDPackage.CrosshairsRight, ViewportCenter, Spread, HUDPackage.CrosshairsColor); } if (HUDPackage.CrosshairsTop) { const FVector2D Spread(0.f, -SpreadScaled); - DrawCrosshair(HUDPackage.CrosshairsTop, ViewportCenter, Spread, HUDPackage.CrosshairColor); + DrawCrosshair(HUDPackage.CrosshairsTop, ViewportCenter, Spread, HUDPackage.CrosshairsColor); } if (HUDPackage.CrosshairsBottom) { const FVector2D Spread(0.f, SpreadScaled); - DrawCrosshair(HUDPackage.CrosshairsBottom, ViewportCenter, Spread, HUDPackage.CrosshairColor); + DrawCrosshair(HUDPackage.CrosshairsBottom, ViewportCenter, Spread, HUDPackage.CrosshairsColor); } } } diff --git a/Source/Blaster/HUD/BlasterHUD.h b/Source/Blaster/HUD/BlasterHUD.h index 00e1e73..f803f11 100644 --- a/Source/Blaster/HUD/BlasterHUD.h +++ b/Source/Blaster/HUD/BlasterHUD.h @@ -18,7 +18,7 @@ public: UTexture2D* CrosshairsTop; UTexture2D* CrosshairsBottom; float CrosshairSpread; - FLinearColor CrosshairColor; + FLinearColor CrosshairsColor; }; /** @@ -32,7 +32,7 @@ class BLASTER_API ABlasterHUD : public AHUD public: virtual void DrawHUD() override; void AddCharacterOverlay(); - void AddAnnouncementOverlay(); + void AddAnnouncement(); UPROPERTY(EditAnywhere, Category = "Player Stats") TSubclassOf CharacterOverlayClass; diff --git a/Source/Blaster/Interfaces/InteractWithCrosshairInterface.cpp b/Source/Blaster/Interfaces/InteractWithCrosshairsInterface.cpp similarity index 81% rename from Source/Blaster/Interfaces/InteractWithCrosshairInterface.cpp rename to Source/Blaster/Interfaces/InteractWithCrosshairsInterface.cpp index 0b97038..144f424 100644 --- a/Source/Blaster/Interfaces/InteractWithCrosshairInterface.cpp +++ b/Source/Blaster/Interfaces/InteractWithCrosshairsInterface.cpp @@ -1,6 +1,6 @@ // Fill out your copyright notice in the Description page of Project Settings. -#include "InteractWithCrosshairInterface.h" +#include "InteractWithCrosshairsInterface.h" // Add default functionality here for any IInteractWithCrosshairInterface functions that are not pure virtual. diff --git a/Source/Blaster/Interfaces/InteractWithCrosshairInterface.h b/Source/Blaster/Interfaces/InteractWithCrosshairsInterface.h similarity index 70% rename from Source/Blaster/Interfaces/InteractWithCrosshairInterface.h rename to Source/Blaster/Interfaces/InteractWithCrosshairsInterface.h index 17d9211..d7a75a1 100644 --- a/Source/Blaster/Interfaces/InteractWithCrosshairInterface.h +++ b/Source/Blaster/Interfaces/InteractWithCrosshairsInterface.h @@ -4,11 +4,11 @@ #include "CoreMinimal.h" #include "UObject/Interface.h" -#include "InteractWithCrosshairInterface.generated.h" +#include "InteractWithCrosshairsInterface.generated.h" // This class does not need to be modified. UINTERFACE(MinimalAPI) -class UInteractWithCrosshairInterface : public UInterface +class UInteractWithCrosshairsInterface : public UInterface { GENERATED_BODY() }; @@ -16,7 +16,7 @@ class UInteractWithCrosshairInterface : public UInterface /** * */ -class BLASTER_API IInteractWithCrosshairInterface +class BLASTER_API IInteractWithCrosshairsInterface { GENERATED_BODY() diff --git a/Source/Blaster/PlayerController/BlasterPlayerController.cpp b/Source/Blaster/PlayerController/BlasterPlayerController.cpp index b3ac849..d71a128 100644 --- a/Source/Blaster/PlayerController/BlasterPlayerController.cpp +++ b/Source/Blaster/PlayerController/BlasterPlayerController.cpp @@ -2,7 +2,6 @@ #include "BlasterPlayerController.h" - #include "Blaster/Character/BlasterCharacter.h" #include "Blaster/Components/CombatComponent.h" #include "Blaster/GameMode/BlasterGameMode.h" @@ -31,38 +30,18 @@ void ABlasterPlayerController::GetLifetimeReplicatedProps(TArray(InPawn)) - { - SetHUDHealth(BlasterCharacter->GetHealth(), BlasterCharacter->GetMaxHealth()); - } -} - -void ABlasterPlayerController::ReceivedPlayer() -{ - Super::ReceivedPlayer(); - - if (IsLocalController()) - { - ServerRequestServerTime(GetWorld()->GetTimeSeconds()); - } -} - -void ABlasterPlayerController::CheckTimeSync(float DeltaSeconds) -{ - TimeSyncRunningTime += DeltaSeconds; + TimeSyncRunningTime += DeltaTime; if (IsLocalController() && TimeSyncRunningTime > TimeSyncFrequency) { ServerRequestServerTime(GetWorld()->GetTimeSeconds()); @@ -70,119 +49,172 @@ void ABlasterPlayerController::CheckTimeSync(float DeltaSeconds) } } -float ABlasterPlayerController::GetServerTime() -{ - if (HasAuthority()) return GetWorld()->GetTimeSeconds(); - return GetWorld()->GetTimeSeconds() + ClientServerDelta; -} - -void ABlasterPlayerController::HandleMatchHasStarted() -{ - BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; - if (BlasterHUD) - { - BlasterHUD->AddCharacterOverlay(); - if (BlasterHUD->Announcement) - { - BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Hidden); - } - } -} - -void ABlasterPlayerController::HandleCooldown() -{ - BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; - if (BlasterHUD) - { - BlasterHUD->CharacterOverlay->RemoveFromParent(); - bool bHUDValid = - BlasterHUD->Announcement && - BlasterHUD->Announcement->AnnouncementText && - BlasterHUD->Announcement->AnnouncementMessage; - - if (bHUDValid) - { - const FString AnnouncementText("New match starts in:"); - BlasterHUD->Announcement->AnnouncementText->SetText(FText::FromString(AnnouncementText)); - BlasterHUD->Announcement->AnnouncementMessage->SetText(FText()); - BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Visible); - } - } - - ABlasterCharacter* BlasterCharacter = Cast(GetPawn()); - if (BlasterCharacter && BlasterCharacter->GetCombat()) - { - BlasterCharacter->bDisableGameplay = true; - BlasterCharacter->GetCombat()->FireButtonPressed(false); - } -} - -void ABlasterPlayerController::OnMatchStateSet(FName State) -{ - MatchState = State; - - if (MatchState == MatchState::InProgress) - { - HandleMatchHasStarted(); - } - else if (MatchState == MatchState::Cooldown) - { - HandleCooldown(); - } -} - -void ABlasterPlayerController::OnRep_MatchState() -{ - if (MatchState == MatchState::InProgress) - { - HandleMatchHasStarted(); - } - else if (MatchState == MatchState::Cooldown) - { - HandleCooldown(); - } -} - void ABlasterPlayerController::ServerCheckMatchState_Implementation() { ABlasterGameMode* GameMode = Cast(UGameplayStatics::GetGameMode(this)); if (GameMode) { - LevelStartingTime = GameMode->LevelStartingTime; WarmupTime = GameMode->WarmupTime; MatchTime = GameMode->MatchTime; CooldownTime = GameMode->CooldownTime; + LevelStartingTime = GameMode->LevelStartingTime; MatchState = GameMode->GetMatchState(); - ClientJoinMidGame(MatchState, WarmupTime, MatchTime, CooldownTime, LevelStartingTime); + ClientJoinMidgame(MatchState, WarmupTime, MatchTime, CooldownTime, LevelStartingTime); } } -void ABlasterPlayerController::ClientJoinMidGame_Implementation(FName StateOfMatch, float Warmup, float Match, float Cooldown, float StartingTime) +void ABlasterPlayerController::ClientJoinMidgame_Implementation(FName StateOfMatch, float Warmup, float Match, float Cooldown, float StartingTime) { - LevelStartingTime = StartingTime; WarmupTime = Warmup; MatchTime = Match; CooldownTime = Cooldown; + LevelStartingTime = StartingTime; MatchState = StateOfMatch; OnMatchStateSet(MatchState); - if (BlasterHUD && MatchState == MatchState::WaitingToStart) { - BlasterHUD->AddAnnouncementOverlay(); + BlasterHUD->AddAnnouncement(); } } -void ABlasterPlayerController::ServerRequestServerTime_Implementation(float TimeOfClientRequest) +void ABlasterPlayerController::OnPossess(APawn* InPawn) { - const float ServerTimeOfReceipt = GetWorld()->GetTimeSeconds(); - ClientReportServerTime(TimeOfClientRequest, ServerTimeOfReceipt); + Super::OnPossess(InPawn); + ABlasterCharacter* BlasterCharacter = Cast(InPawn); + if (BlasterCharacter) + { + SetHUDHealth(BlasterCharacter->GetHealth(), BlasterCharacter->GetMaxHealth()); + } } -void ABlasterPlayerController::ClientReportServerTime_Implementation(float TimeOfClientRequest, float TimeServerReceivedClientRequest) +void ABlasterPlayerController::SetHUDHealth(float Health, float MaxHealth) { - const float RoundTripTime = GetWorld()->GetTimeSeconds() - TimeOfClientRequest; - const float CurrentServerTime = TimeServerReceivedClientRequest + (0.5f * RoundTripTime); - ClientServerDelta = CurrentServerTime - GetWorld()->GetTimeSeconds(); + BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; + bool bHUDValid = BlasterHUD && + BlasterHUD->CharacterOverlay && + BlasterHUD->CharacterOverlay->HealthBar && + BlasterHUD->CharacterOverlay->HealthText; + if (bHUDValid) + { + const float HealthPercent = Health / MaxHealth; + BlasterHUD->CharacterOverlay->HealthBar->SetPercent(HealthPercent); + FString HealthText = FString::Printf(TEXT("%d/%d"), FMath::CeilToInt(Health), FMath::CeilToInt(MaxHealth)); + BlasterHUD->CharacterOverlay->HealthText->SetText(FText::FromString(HealthText)); + } + else + { + bInitializeCharacterOverlay = true; + HUDHealth = Health; + HUDMaxHealth = MaxHealth; + } +} + +void ABlasterPlayerController::SetHUDScore(float Score) +{ + BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; + bool bHUDValid = BlasterHUD && + BlasterHUD->CharacterOverlay && + BlasterHUD->CharacterOverlay->ScoreValue; + + if (bHUDValid) + { + FString ScoreText = FString::Printf(TEXT("%d"), FMath::FloorToInt(Score)); + BlasterHUD->CharacterOverlay->ScoreValue->SetText(FText::FromString(ScoreText)); + } + else + { + bInitializeCharacterOverlay = true; + HUDScore = Score; + } +} + +void ABlasterPlayerController::SetHUDDefeats(int32 Defeats) +{ + BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; + bool bHUDValid = BlasterHUD && + BlasterHUD->CharacterOverlay && + BlasterHUD->CharacterOverlay->DefeatsValue; + if (bHUDValid) + { + FString DefeatsText = FString::Printf(TEXT("%d"), Defeats); + BlasterHUD->CharacterOverlay->DefeatsValue->SetText(FText::FromString(DefeatsText)); + } + else + { + bInitializeCharacterOverlay = true; + HUDDefeats = Defeats; + } +} + +void ABlasterPlayerController::SetHUDWeaponAmmo(int32 Ammo) +{ + BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; + bool bHUDValid = BlasterHUD && + BlasterHUD->CharacterOverlay && + BlasterHUD->CharacterOverlay->WeaponAmmoValue; + + if (bHUDValid) + { + FString AmmoText = FString::Printf(TEXT("%d"), Ammo); + BlasterHUD->CharacterOverlay->WeaponAmmoValue->SetText(FText::FromString(AmmoText)); + } +} + +void ABlasterPlayerController::SetHUDCarriedAmmo(int32 Ammo) +{ + BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; + bool bHUDValid = BlasterHUD && + BlasterHUD->CharacterOverlay && + BlasterHUD->CharacterOverlay->CarriedAmmoValue; + if (bHUDValid) + { + FString AmmoText = FString::Printf(TEXT("%d"), Ammo); + BlasterHUD->CharacterOverlay->CarriedAmmoValue->SetText(FText::FromString(AmmoText)); + } +} + +void ABlasterPlayerController::SetHUDMatchCountdown(float CountdownTime) +{ + BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; + bool bHUDValid = BlasterHUD && + BlasterHUD->CharacterOverlay && + BlasterHUD->CharacterOverlay->MatchCountdownText; + if (bHUDValid) + { + if (CountdownTime < 0.f) + { + BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText()); + return; + } + + int32 Minutes = FMath::FloorToInt(CountdownTime / 60.f); + int32 Seconds = CountdownTime - Minutes * 60; + + FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds); + BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText::FromString(CountdownText)); + } +} + +void ABlasterPlayerController::SetHUDAnnouncementCountdown(float CountdownTime) +{ + BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; + bool bHUDValid = BlasterHUD && + BlasterHUD->Announcement && + BlasterHUD->Announcement->WarmupTime; + if (bHUDValid) + { + if (CountdownTime < 0.f) + { + BlasterHUD->Announcement->WarmupTime->SetText(FText()); + return; + } + + int32 Minutes = FMath::FloorToInt(CountdownTime / 60.f); + int32 Seconds = CountdownTime - Minutes * 60; + + FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds); + BlasterHUD->Announcement->WarmupTime->SetText(FText::FromString(CountdownText)); + } } void ABlasterPlayerController::SetHUDTime() @@ -225,142 +257,95 @@ void ABlasterPlayerController::PollInit() } } -void ABlasterPlayerController::SetHUDHealth(float Health, float MaxHealth) +void ABlasterPlayerController::ServerRequestServerTime_Implementation(float TimeOfClientRequest) { - BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; - bool bHUDValid = - BlasterHUD && - BlasterHUD->CharacterOverlay && - BlasterHUD->CharacterOverlay->HealthBar && - BlasterHUD->CharacterOverlay->HealthText; + float ServerTimeOfReceipt = GetWorld()->GetTimeSeconds(); + ClientReportServerTime(TimeOfClientRequest, ServerTimeOfReceipt); +} - if (bHUDValid) +void ABlasterPlayerController::ClientReportServerTime_Implementation(float TimeOfClientRequest, float TimeServerReceivedClientRequest) +{ + float RoundTripTime = GetWorld()->GetTimeSeconds() - TimeOfClientRequest; + float CurrentServerTime = TimeServerReceivedClientRequest + (0.5f * RoundTripTime); + ClientServerDelta = CurrentServerTime - GetWorld()->GetTimeSeconds(); +} + +float ABlasterPlayerController::GetServerTime() +{ + if (HasAuthority()) return GetWorld()->GetTimeSeconds(); + return GetWorld()->GetTimeSeconds() + ClientServerDelta; +} + +void ABlasterPlayerController::ReceivedPlayer() +{ + Super::ReceivedPlayer(); + if (IsLocalController()) { - const float HealthPercent = Health / MaxHealth; - BlasterHUD->CharacterOverlay->HealthBar->SetPercent(HealthPercent); - const FString HealthText = FString::Printf(TEXT("%d/%d"), FMath::CeilToInt(Health), FMath::CeilToInt(MaxHealth)); - BlasterHUD->CharacterOverlay->HealthText->SetText(FText::FromString(HealthText)); - } - else - { - bInitializeCharacterOverlay = true; - HUDHealth = Health; - HUDMaxHealth = MaxHealth; + ServerRequestServerTime(GetWorld()->GetTimeSeconds()); } } -void ABlasterPlayerController::SetHUDScore(float Score) +void ABlasterPlayerController::OnMatchStateSet(FName State) { - BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; - bool bHUDValid = - BlasterHUD && - BlasterHUD->CharacterOverlay && - BlasterHUD->CharacterOverlay->ScoreValue; + MatchState = State; - if (bHUDValid) + if (MatchState == MatchState::InProgress) { - const FString ScoreAmount = FString::Printf(TEXT("%d"), FMath::FloorToInt(Score)); - BlasterHUD->CharacterOverlay->ScoreValue->SetText(FText::FromString(ScoreAmount)); + HandleMatchHasStarted(); } - else + else if (MatchState == MatchState::Cooldown) { - bInitializeCharacterOverlay = true; - HUDScore = Score; + HandleCooldown(); } } -void ABlasterPlayerController::SetHUDDefeats(int32 Defeats) +void ABlasterPlayerController::OnRep_MatchState() { - BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; - bool bHUDValid = - BlasterHUD && - BlasterHUD->CharacterOverlay && - BlasterHUD->CharacterOverlay->DefeatsValue; - - if (bHUDValid) + if (MatchState == MatchState::InProgress) { - const FString DefeatsAmount = FString::Printf(TEXT("%d"), Defeats); - BlasterHUD->CharacterOverlay->DefeatsValue->SetText(FText::FromString(DefeatsAmount)); + HandleMatchHasStarted(); } - else + else if (MatchState == MatchState::Cooldown) { - bInitializeCharacterOverlay = true; - HUDDefeats = Defeats; + HandleCooldown(); } } -void ABlasterPlayerController::SetHUDWeaponAmmo(int32 Ammo) +void ABlasterPlayerController::HandleMatchHasStarted() { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; - bool bHUDValid = - BlasterHUD && - BlasterHUD->CharacterOverlay && - BlasterHUD->CharacterOverlay->WeaponAmmoValue; - - if (bHUDValid) + if (BlasterHUD) { - const FString WeaponAmmoAmount = FString::Printf(TEXT("%d"), Ammo); - BlasterHUD->CharacterOverlay->WeaponAmmoValue->SetText(FText::FromString(WeaponAmmoAmount)); - } -} - -void ABlasterPlayerController::SetHUDCarriedAmmo(int32 Ammo) -{ - BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; - bool bHUDValid = - BlasterHUD && - BlasterHUD->CharacterOverlay && - BlasterHUD->CharacterOverlay->CarriedAmmoValue; - - if (bHUDValid) - { - const FString CarriedAmmoAmount = FString::Printf(TEXT("%d"), Ammo); - BlasterHUD->CharacterOverlay->CarriedAmmoValue->SetText(FText::FromString(CarriedAmmoAmount)); - } -} - -void ABlasterPlayerController::SetHUDMatchCountdown(float CountdownTime) -{ - BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; - bool bHUDValid = - BlasterHUD && - BlasterHUD->CharacterOverlay && - BlasterHUD->CharacterOverlay->MatchCountdownText; - - if (bHUDValid) - { - if (CountdownTime < 0.f) + BlasterHUD->AddCharacterOverlay(); + if (BlasterHUD->Announcement) { - BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText()); - return; + BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Hidden); } - const int32 Minutes = FMath::FloorToInt(CountdownTime / 60); - const int32 Seconds = CountdownTime - Minutes * 60; - - const FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds); - BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText::FromString(CountdownText)); } } -void ABlasterPlayerController::SetHUDAnnouncementCountdown(float CountdownTime) +void ABlasterPlayerController::HandleCooldown() { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; - bool bHUDValid = - BlasterHUD && - BlasterHUD->Announcement && - BlasterHUD->Announcement->CountdownText; - - if (bHUDValid) + if (BlasterHUD) { - if (CountdownTime < 0.f) - { - BlasterHUD->Announcement->CountdownText->SetText(FText()); - return; - } - const int32 Minutes = FMath::FloorToInt(CountdownTime / 60); - const int32 Seconds = CountdownTime - Minutes * 60; + BlasterHUD->CharacterOverlay->RemoveFromParent(); + bool bHUDValid = BlasterHUD->Announcement && + BlasterHUD->Announcement->AnnouncementText && + BlasterHUD->Announcement->InfoText; - const FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds); - BlasterHUD->Announcement->CountdownText->SetText(FText::FromString(CountdownText)); + if (bHUDValid) + { + BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Visible); + FString AnnouncementText("New match starts in:"); + BlasterHUD->Announcement->AnnouncementText->SetText(FText::FromString(AnnouncementText)); + BlasterHUD->Announcement->InfoText->SetText(FText()); + } + } + ABlasterCharacter* BlasterCharacter = Cast(GetPawn()); + if (BlasterCharacter && BlasterCharacter->GetCombat()) + { + BlasterCharacter->bDisableGameplay = true; + BlasterCharacter->GetCombat()->FireButtonPressed(false); } } diff --git a/Source/Blaster/PlayerController/BlasterPlayerController.h b/Source/Blaster/PlayerController/BlasterPlayerController.h index 7d00814..25957b2 100644 --- a/Source/Blaster/PlayerController/BlasterPlayerController.h +++ b/Source/Blaster/PlayerController/BlasterPlayerController.h @@ -15,7 +15,7 @@ class BLASTER_API ABlasterPlayerController : public APlayerController GENERATED_BODY() public: - virtual void Tick(float DeltaSeconds) override; + virtual void Tick(float DeltaTime) override; virtual void OnPossess(APawn* InPawn) override; virtual void ReceivedPlayer() override; // Sync with server clock as soon as possible virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; @@ -63,7 +63,7 @@ protected: void ServerCheckMatchState(); UFUNCTION(Client, Reliable) - void ClientJoinMidGame(FName StateOfMatch, float Warmup, float Match, float Cooldown, float StartingTime); + void ClientJoinMidgame(FName StateOfMatch, float Warmup, float Match, float Cooldown, float StartingTime); private: UPROPERTY() diff --git a/Source/Blaster/PlayerState/BlasterPlayerState.cpp b/Source/Blaster/PlayerState/BlasterPlayerState.cpp index b09d7f4..9c556a9 100644 --- a/Source/Blaster/PlayerState/BlasterPlayerState.cpp +++ b/Source/Blaster/PlayerState/BlasterPlayerState.cpp @@ -7,21 +7,6 @@ #include "Blaster/PlayerController/BlasterPlayerController.h" #include "Net/UnrealNetwork.h" -void ABlasterPlayerState::IncreaseScore(float ScoreAmount) -{ - SetScore(GetScore() + ScoreAmount); - - Character = GetCharacter(); - if (Character) - { - Controller = GetController(); - if (Controller) - { - Controller->SetHUDScore(GetScore()); - } - } -} - void ABlasterPlayerState::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); @@ -29,14 +14,13 @@ void ABlasterPlayerState::GetLifetimeReplicatedProps(TArray& DOREPLIFETIME(ABlasterPlayerState, Defeats); } -void ABlasterPlayerState::OnRep_Score() +void ABlasterPlayerState::AddToScore(float ScoreAmount) { - Super::OnRep_Score(); - - Character = GetCharacter(); + SetScore(GetScore() + ScoreAmount); + Character = Character == nullptr ? Cast(GetPawn()) : Character; if (Character) { - Controller = GetController(); + Controller = Controller == nullptr ? Cast(Character->Controller) : Controller; if (Controller) { Controller->SetHUDScore(GetScore()); @@ -44,14 +28,28 @@ void ABlasterPlayerState::OnRep_Score() } } -void ABlasterPlayerState::IncreaseDefeats(int32 DefeatsAmount) +void ABlasterPlayerState::OnRep_Score() { - Defeats += DefeatsAmount; + Super::OnRep_Score(); - Character = GetCharacter(); + Character = Character == nullptr ? Cast(GetPawn()) : Character; if (Character) { - Controller = GetController(); + Controller = Controller == nullptr ? Cast(Character->Controller) : Controller; + if (Controller) + { + Controller->SetHUDScore(GetScore()); + } + } +} + +void ABlasterPlayerState::AddToDefeats(int32 DefeatsAmount) +{ + Defeats += DefeatsAmount; + Character = Character == nullptr ? Cast(GetPawn()) : Character; + if (Character) + { + Controller = Controller == nullptr ? Cast(Character->Controller) : Controller; if (Controller) { Controller->SetHUDDefeats(Defeats); @@ -61,29 +59,13 @@ void ABlasterPlayerState::IncreaseDefeats(int32 DefeatsAmount) void ABlasterPlayerState::OnRep_Defeats() { - Character = GetCharacter(); + Character = Character == nullptr ? Cast(GetPawn()) : Character; if (Character) { - Controller = GetController(); + Controller = Controller == nullptr ? Cast(Character->Controller) : Controller; if (Controller) { Controller->SetHUDDefeats(Defeats); } } } - -ABlasterCharacter* ABlasterPlayerState::GetCharacter() const -{ - return Character == nullptr ? Cast(GetPawn()) : Character; -} - -ABlasterPlayerController* ABlasterPlayerState::GetController() const -{ - if (Character) - { - return Controller == nullptr ? Cast(Character->Controller) : Controller; - } - - return nullptr; -} - diff --git a/Source/Blaster/PlayerState/BlasterPlayerState.h b/Source/Blaster/PlayerState/BlasterPlayerState.h index 20b3fa6..e4a8c10 100644 --- a/Source/Blaster/PlayerState/BlasterPlayerState.h +++ b/Source/Blaster/PlayerState/BlasterPlayerState.h @@ -17,19 +17,18 @@ class BLASTER_API ABlasterPlayerState : public APlayerState public: virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; virtual void OnRep_Score() override; + UFUNCTION() virtual void OnRep_Defeats(); - void IncreaseScore(float ScoreAmount); - void IncreaseDefeats(int32 DefeatsAmount); + void AddToScore(float ScoreAmount); + void AddToDefeats(int32 DefeatsAmount); private: UPROPERTY() class ABlasterCharacter* Character; UPROPERTY() class ABlasterPlayerController* Controller; - ABlasterCharacter* GetCharacter() const; - ABlasterPlayerController* GetController() const; UPROPERTY(ReplicatedUsing = OnRep_Defeats) int32 Defeats; diff --git a/Source/Blaster/Types/CombatState.h b/Source/Blaster/Types/CombatState.h index 0a82ac1..0f434a6 100644 --- a/Source/Blaster/Types/CombatState.h +++ b/Source/Blaster/Types/CombatState.h @@ -5,6 +5,6 @@ enum class ECombatState : uint8 { ECS_Unoccupied UMETA(DisplayName = "Unoccupied"), ECS_Reloading UMETA(DisplayName = "Reloading"), - + ECS_MAX UMETA(DisplayName = "DefaultMAX") -}; +}; \ No newline at end of file