İlk yürütme

This commit is contained in:
2026-08-02 22:34:52 +03:00
commit 26bde15faa
601 changed files with 4420 additions and 0 deletions
@@ -0,0 +1,167 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "ShooterProjectile.h"
#include "Components/SphereComponent.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "GameFramework/Character.h"
#include "Kismet/GameplayStatics.h"
#include "GameFramework/DamageType.h"
#include "GameFramework/Pawn.h"
#include "GameFramework/Controller.h"
#include "Engine/OverlapResult.h"
#include "Engine/World.h"
#include "TimerManager.h"
AShooterProjectile::AShooterProjectile()
{
PrimaryActorTick.bCanEverTick = true;
// create the collision component and assign it as the root
RootComponent = CollisionComponent = CreateDefaultSubobject<USphereComponent>(TEXT("Collision Component"));
CollisionComponent->SetSphereRadius(16.0f);
CollisionComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
CollisionComponent->SetCollisionResponseToAllChannels(ECR_Block);
CollisionComponent->CanCharacterStepUpOn = ECanBeCharacterBase::ECB_No;
// create the projectile movement component. No need to attach it because it's not a Scene Component
ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("Projectile Movement"));
ProjectileMovement->InitialSpeed = 3000.0f;
ProjectileMovement->MaxSpeed = 3000.0f;
ProjectileMovement->bShouldBounce = true;
// set the default damage type
HitDamageType = UDamageType::StaticClass();
}
void AShooterProjectile::BeginPlay()
{
Super::BeginPlay();
// ignore the pawn that shot this projectile
CollisionComponent->IgnoreActorWhenMoving(GetInstigator(), true);
}
void AShooterProjectile::EndPlay(EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
// clear the destruction timer
GetWorld()->GetTimerManager().ClearTimer(DestructionTimer);
}
void AShooterProjectile::NotifyHit(class UPrimitiveComponent* MyComp, AActor* Other, class UPrimitiveComponent* OtherComp, bool bSelfMoved, FVector HitLocation, FVector HitNormal, FVector NormalImpulse, const FHitResult& Hit)
{
// ignore if we've already hit something else
if (bHit)
{
return;
}
bHit = true;
// disable collision on the projectile
CollisionComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
// make AI perception noise
MakeNoise(NoiseLoudness, GetInstigator(), GetActorLocation(), NoiseRange, NoiseTag);
if (bExplodeOnHit)
{
// apply explosion damage centered on the projectile
ExplosionCheck(GetActorLocation());
} else {
// single hit projectile. Process the collided actor
ProcessHit(Other, OtherComp, Hit.ImpactPoint, -Hit.ImpactNormal);
}
// pass control to BP for any extra effects
BP_OnProjectileHit(Hit);
// check if we should schedule deferred destruction of the projectile
if (DeferredDestructionTime > 0.0f)
{
GetWorld()->GetTimerManager().SetTimer(DestructionTimer, this, &AShooterProjectile::OnDeferredDestruction, DeferredDestructionTime, false);
} else {
// destroy the projectile right away
Destroy();
}
}
void AShooterProjectile::ExplosionCheck(const FVector& ExplosionCenter)
{
// do a sphere overlap check look for nearby actors to damage
TArray<FOverlapResult> Overlaps;
FCollisionShape OverlapShape;
OverlapShape.SetSphere(ExplosionRadius);
FCollisionObjectQueryParams ObjectParams;
ObjectParams.AddObjectTypesToQuery(ECC_Pawn);
ObjectParams.AddObjectTypesToQuery(ECC_WorldDynamic);
ObjectParams.AddObjectTypesToQuery(ECC_PhysicsBody);
FCollisionQueryParams QueryParams;
QueryParams.AddIgnoredActor(this);
if (!bDamageOwner)
{
QueryParams.AddIgnoredActor(GetInstigator());
}
GetWorld()->OverlapMultiByObjectType(Overlaps, ExplosionCenter, FQuat::Identity, ObjectParams, OverlapShape, QueryParams);
TArray<AActor*> DamagedActors;
// process the overlap results
for (const FOverlapResult& CurrentOverlap : Overlaps)
{
// overlaps may return the same actor multiple times per each component overlapped
// ensure we only damage each actor once by adding it to a damaged list
if (DamagedActors.Find(CurrentOverlap.GetActor()) == INDEX_NONE)
{
DamagedActors.Add(CurrentOverlap.GetActor());
// apply physics force away from the explosion
const FVector& ExplosionDir = CurrentOverlap.GetActor()->GetActorLocation() - GetActorLocation();
// push and/or damage the overlapped actor
ProcessHit(CurrentOverlap.GetActor(), CurrentOverlap.GetComponent(), GetActorLocation(), ExplosionDir.GetSafeNormal());
}
}
}
void AShooterProjectile::ProcessHit(AActor* HitActor, UPrimitiveComponent* HitComp, const FVector& HitLocation, const FVector& HitDirection)
{
// have we hit a character?
if (ACharacter* HitCharacter = Cast<ACharacter>(HitActor))
{
// ignore the owner of this projectile
if (HitCharacter != GetOwner() || bDamageOwner)
{
// apply damage to the character
UGameplayStatics::ApplyDamage(HitCharacter, HitDamage, GetInstigator()->GetController(), this, HitDamageType);
}
}
// have we hit a physics object?
if (HitComp->IsSimulatingPhysics())
{
// give some physics impulse to the object
HitComp->AddImpulseAtLocation(HitDirection * PhysicsForce, HitLocation);
}
}
void AShooterProjectile::OnDeferredDestruction()
{
// destroy this actor
Destroy();
}