// Project Lab - NHTV Igad #include "UnrealProject.h" #include "NetworkCharacter.h" #include "ProjectileBase.h" #include "BlueprintAbilityLibrary.h" #include "AbilityTriggerBase.h" AProjectileBase::AProjectileBase() { m_finishTimer = 0.0f; m_fixedTimer = 0.0f; maxDistance = 1000.0f; distanceTraveled = 0.0f; keepAliveAfterFinish = 1.0f; filter = EAbilityFilter::EnemyAll; m_finished = false; //server client replication bReplicateMovement = true; bReplicates = true; bAlwaysRelevant = true; PrimaryActorTick.bCanEverTick = true; } void AProjectileBase::BeginPlay() { // Get collider component collider = Cast(GetRootComponent()); if(!collider) { GWERROR(L"Projectile does not have a collider root!"); Destroy(); return; } if(Role != ROLE_Authority) { collider->SetCollisionEnabled(ECollisionEnabled::NoCollision); } else { collider->OnComponentHit.AddDynamic(this, &AProjectileBase::m_OnHit); collider->OnComponentBeginOverlap.AddDynamic(this, &AProjectileBase::m_OnOverlapBegin); // collider->SetCollisionProfileName("Projectiles"); } Super::BeginPlay(); } void AProjectileBase::NativeFixedProjectileTick(float DeltaTime) { FixedProjectileTick(DeltaTime); } //call this in inherited classes, will call move void AProjectileBase::Tick(float DeltaTime) { Super::Tick(DeltaTime); // Fixed timestep for projectiles m_fixedTimer += DeltaTime; FVector startPos = GetActorLocation(); const float delta = 1.0f / 60.0f; while(m_fixedTimer >= delta) { NativeFixedProjectileTick(delta); if (autoMove) { NativeMove(DeltaTime); FVector newLocation = GetActorLocation(); FVector movedVector = newLocation - startPos; startPos = newLocation; distanceTraveled += movedVector.Size(); } if (distanceTraveled > maxDistance) { Finish(); break; } m_fixedTimer -= delta; } if(m_finished && autoDestroy) { if((m_finishTimer -= DeltaTime) <= 0.0f) { Destroy(); } } } void AProjectileBase::m_OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) { ANetworkCharacter* netChar = Cast(OtherActor); if(netChar && ULib::CheckAbilityFilter(filter, character, netChar)) { OnProjectileHit(netChar); } } void AProjectileBase::m_OnHit(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) { Finish(); } void AProjectileBase::Finish_Implementation() { if(!m_finished) { if(Role == ROLE_Authority) { NativeServerOnFinish(); } NativeOnProjectileFinished(); if(collider) collider->SetCollisionEnabled(ECollisionEnabled::NoCollision); m_finishTimer = keepAliveAfterFinish; m_finished = true; } } void AProjectileBase::FixedProjectileTick_Implementation(float DeltaTime) { } void AProjectileBase::OnProjectileHit_Implementation(ANetworkCharacter* character) { NativeOnProjectileHit(character); } void AProjectileBase::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME_CONDITION(AProjectileBase, speed, COND_InitialOnly); DOREPLIFETIME_CONDITION(AProjectileBase, filter, COND_InitialOnly); DOREPLIFETIME_CONDITION(AProjectileBase, maxDistance, COND_InitialOnly); DOREPLIFETIME_CONDITION(AProjectileBase, autoMove, COND_InitialOnly); DOREPLIFETIME_CONDITION(AProjectileBase, autoDestroy, COND_InitialOnly); } void AProjectileBase::Move(float DeltaTime) { NativeMove(DeltaTime); } void AProjectileBase::NativeMove(float DeltaTime) { //moves with sweep to get collision float distance = speed * DeltaTime; AddActorWorldOffset(GetActorForwardVector() * distance,true); } void AProjectileBase::OnProjectileFinished_Implementation() { } void AProjectileBase::NativeOnProjectileFinished() { OnProjectileFinished(); } void AProjectileBase::NativeOnProjectileHit(ANetworkCharacter* hitCharacter) { } void AProjectileBase::NativeServerOnFinish() { ServerOnFinish(); }