UE5--015--DodgeballProjectile--EnemyCharacter
1. DodgeballProjectile
1.1 DodgeballProjectile.h
#pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "DodgeballProjectile.generated.h" UCLASS() class C005DODGEBALL_API ADodgeballProjectile : public AActor { GENERATED_BODY() UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Dodgeball, meta = (AllowPrivateAccess = "true")) class USphereComponent* SphereComponent; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Dodgeball, meta = (AllowPrivateAccess = "true")) class UProjectileMovementComponent* ProjectileMovement; public: // Sets default values for this actor's properties ADodgeballProjectile(); protected: // Called when the game starts or when spawned virtual void BeginPlay() override; // The damage the dodgeball will deal to the player's character UPROPERTY(EditAnywhere, Category = Damage) float Damage = 34.f; // The sound the dodgeball will make when it bounces off of a surface UPROPERTY(EditAnywhere, Category = Sound) class USoundBase* BounceSound; // The sound attenuation of the previous sound UPROPERTY(EditAnywhere, Category = Sound) class USoundAttenuation* BounceSoundAttenuation; // The particle system the dodgeball will spawn when it hits the player UPROPERTY(EditAnywhere, Category = Particles) class UParticleSystem* HitParticles; // The sound the dodgeball will make when it hits the player UPROPERTY(EditAnywhere, Category = Sound) class USoundBase* DamageSound; public: // Called every frame virtual void Tick(float DeltaTime) override; // UFUNCTION() void OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit); FORCEINLINE class UProjectileMovementComponent* GetProjectileMovementComponent() const { return ProjectileMovement; } };
1.2 DodgeballProjectile.cpp
#include "DodgeballProjectile.h" #include "Components/SphereComponent.h" #include "../C005DodgeballCharacter.h" #include "GameFramework/ProjectileMovementComponent.h" #include "HealthComponent.h" #include "Kismet/GameplayStatics.h" // Sets default values ADodgeballProjectile::ADodgeballProjectile() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = true; // SphereComponent = CreateDefaultSubobject<USphereComponent>(TEXT("SphereCollision")); SphereComponent->SetSphereRadius(35.f); SphereComponent->SetCollisionProfileName(FName("Dodgeball")); SphereComponent->SetSimulatePhysics(true); //Simulation generates Hit events SphereComponent->SetNotifyRigidBodyCollision(true); // // Listen to the OnComponentHit event by binding it to our function SphereComponent->OnComponentHit.AddDynamic(this, &ADodgeballProjectile::OnHit); // Set this Sphere Component as the root component, otherwise collision won't behave properly RootComponent = SphereComponent; // ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("Projectile Movement")); ProjectileMovement->InitialSpeed = 1500.f; } // Called when the game starts or when spawned void ADodgeballProjectile::BeginPlay() { Super::BeginPlay(); // SetLifeSpan(5.f); } // Called every frame void ADodgeballProjectile::Tick(float DeltaTime) { Super::Tick(DeltaTime); } void ADodgeballProjectile::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) { if (BounceSound != nullptr && NormalImpulse.Size() > 600.0f) { //UGameplayStatics::PlaySoundAtLocation(this, BounceSound, GetActorLocation(), 1.0f, FMath::RandRange(0.7f, 1.3f)); //UGameplayStatics::PlaySoundAtLocation(this, BounceSound, GetActorLocation(), 1.0f, 1.0f, 0.0f, BounceSoundAttenuation); UGameplayStatics::PlaySoundAtLocation(this, BounceSound, GetActorLocation(), 1.0f, FMath::RandRange(0.7f, 1.3f), 0.0f, BounceSoundAttenuation); } // AC005DodgeballCharacter* Player = Cast<AC005DodgeballCharacter>(OtherActor); if (Player != nullptr) { UHealthComponent* HealthComponent = Player->FindComponentByClass<UHealthComponent>(); if (HealthComponent != nullptr) { HealthComponent->LoseHealth(Damage); } // if (DamageSound != nullptr) { UGameplayStatics::PlaySound2D(this, DamageSound); } // if (HitParticles != nullptr) { UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), HitParticles, GetActorTransform()); } // Destroy(); } }
1.3 BP_DodgeballProjectile
1. EnemyCharacter
1.1 EnemyCharacter.h
#pragma once #include "CoreMinimal.h" #include "GameFramework/Character.h" #include "EnemyCharacter.generated.h" class AActor; UCLASS() class C005DODGEBALL_API AEnemyCharacter : public ACharacter { GENERATED_BODY() /** Camera boom positioning the camera behind the character */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = LookAt, meta = (AllowPrivateAccess = "true")) class USceneComponent* SightSourceDeprecated; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = LookAt, meta = (AllowPrivateAccess = "true")) class ULookAtActorComponent* LookAtActorComponent; public: // Sets default values for this character's properties AEnemyCharacter(); //The class used to spawn a dodgeball object UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = Dodgeball) TSubclassOf<class ADodgeballProjectile> DodgeballClass; protected: // Called when the game starts or when spawned virtual void BeginPlay() override; //Whether the enemy can see the player this frame bool bCanSeePlayer = false; //Whether the enemy could see the player last frame bool bPreviousCanSeePlayer = false; FTimerHandle ThrowTimerHandle; float ThrowingInterval = 2.f; float ThrowingDelay = 0.5f; void ThrowDodgeball(); public: // Called every frame virtual void Tick(float DeltaTime) override; // Called to bind functionality to input virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; public: // Change the rotation of the character to face the given actor bool LookAtActorDeprecated(AActor* TargetActor); // Can we see the given actor bool CanSeeActorDeprecated(const AActor* TargetActor) const; };
1.2 EnemyCharacter.cpp
#include "EnemyCharacter.h" #include "Engine/World.h" #include "DrawDebugHelpers.h" #include "Kismet/KismetMathLibrary.h" #include "Kismet/GameplayStatics.h" #include "Components/SceneComponent.h" #include "TimerManager.h" #include "DodgeballProjectile.h" #include "GameFramework/ProjectileMovementComponent.h" #include "DodgeballFunctionLibrary.h" #include "LookAtActorComponent.h" // Sets default values AEnemyCharacter::AEnemyCharacter() { // Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = true; // if (1 == 0) { SightSourceDeprecated = CreateDefaultSubobject<USceneComponent>(TEXT("SightSource")); SightSourceDeprecated->SetupAttachment(RootComponent); } else { LookAtActorComponent = CreateDefaultSubobject<ULookAtActorComponent>(TEXT("LookAtActor Component")); LookAtActorComponent->SetupAttachment(RootComponent); } } // Called when the game starts or when spawned void AEnemyCharacter::BeginPlay() { Super::BeginPlay(); // Fetch the character currently being controlled by the player ACharacter* PlayerCharacter = UGameplayStatics::GetPlayerCharacter(this, 0); LookAtActorComponent->SetTarget(PlayerCharacter); } // Called every frame void AEnemyCharacter::Tick(float DeltaTime) { Super::Tick(DeltaTime); // Fetch the character currently being controlled by the player ACharacter* PlayerCharacter = UGameplayStatics::GetPlayerCharacter(this, 0); if (1 == 0) { // Look at the player character every frame bCanSeePlayer = LookAtActorDeprecated(PlayerCharacter); } else { // Look at the player character every frame bCanSeePlayer = LookAtActorComponent->CanSeeTarget(); } if (bCanSeePlayer != bPreviousCanSeePlayer) { if (bCanSeePlayer) { //Start throwing dodgeballs GetWorldTimerManager().SetTimer(ThrowTimerHandle, this, &AEnemyCharacter::ThrowDodgeball, ThrowingInterval, true, ThrowingDelay); } else { //Stop throwing dodgeballs GetWorldTimerManager().ClearTimer(ThrowTimerHandle); } } bPreviousCanSeePlayer = bCanSeePlayer; } // Called to bind functionality to input void AEnemyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { Super::SetupPlayerInputComponent(PlayerInputComponent); } bool AEnemyCharacter::LookAtActorDeprecated(AActor* TargetActor) { if (TargetActor == nullptr) { return false; } if (1 == 0) { if (CanSeeActorDeprecated(TargetActor)) { FVector Start = GetActorLocation(); // // Where the Line Trace starts and ends //FVector Start = SightSource->GetComponentLocation(); FVector End = TargetActor->GetActorLocation(); // Calculate the necessary rotation for the Start point to face the End point FRotator LookAtRotation = UKismetMathLibrary::FindLookAtRotation(Start, End); //Set the enemy's rotation to that rotation SetActorRotation(LookAtRotation); return true; } } else { const TArray<const AActor*> IgnoreActors = { this, TargetActor }; if (UDodgeballFunctionLibrary::CanSeeActor(GetWorld(), SightSourceDeprecated->GetComponentLocation(), TargetActor, IgnoreActors)) { FVector Start = GetActorLocation(); // // Where the Line Trace starts and ends //FVector Start = SightSource->GetComponentLocation(); FVector End = TargetActor->GetActorLocation(); // Calculate the necessary rotation for the Start point to face the End point FRotator LookAtRotation = UKismetMathLibrary::FindLookAtRotation(Start, End); //Set the enemy's rotation to that rotation SetActorRotation(LookAtRotation); return true; } } return false; } bool AEnemyCharacter::CanSeeActorDeprecated(const AActor* TargetActor) const { if (TargetActor == nullptr) { return false; } // Store the results of the Line Trace FHitResult Hit; // Where the Line Trace starts and ends //FVector Start = GetActorLocation(); FVector Start = SightSourceDeprecated->GetComponentLocation(); FVector End = TargetActor->GetActorLocation(); if (0 == 1) { // The trace channel we want to compare against ECollisionChannel Channel = ECollisionChannel::ECC_Visibility; // Execute the Line Trace //GetWorld()->LineTraceSingleByChannel(Hit, Start, End, Channel); FCollisionQueryParams QueryParams; // Ignore the actor that's executing this Line Trace QueryParams.AddIgnoredActor(this); // Ignore the target we're checking for QueryParams.AddIgnoredActor(TargetActor); // Execute the Line Trace GetWorld()->LineTraceSingleByChannel(Hit, Start, End, Channel, QueryParams); // Show the Line Trace inside the game DrawDebugLine(GetWorld(), Start, End, FColor::Red); } else { // Rotation of the shape used in the Sweep Trace FQuat Rotation = FQuat::Identity; // The trace channel we want to compare against ECollisionChannel Channel = ECollisionChannel::ECC_Visibility; // Shape of the object used in the Sweep Trace FCollisionShape Shape = FCollisionShape::MakeBox(FVector(20.f, 20.f, 20.f)); GetWorld()->SweepSingleByChannel(Hit, Start, End, Rotation, Channel, Shape); DrawDebugLine(GetWorld(), Start, End, FColor::Red); } return !Hit.bBlockingHit; } void AEnemyCharacter::ThrowDodgeball() { if (DodgeballClass == nullptr) { return; } FVector ForwardVector = GetActorForwardVector(); float SpawnDistance = 40.f; FVector SpawnLocation = GetActorLocation() + (ForwardVector * SpawnDistance); //Spawn new dodgeball if (0 == 1) { //GetWorld()->SpawnActor<ADodgeballProjectile>(DodgeballClass, SpawnLocation, GetActorRotation()); } else { FTransform SpawnTransform(GetActorRotation(), SpawnLocation); ADodgeballProjectile* Projectile = GetWorld()->SpawnActorDeferred<ADodgeballProjectile>(DodgeballClass, SpawnTransform); Projectile->GetProjectileMovementComponent()->InitialSpeed = 2200; Projectile->FinishSpawning(SpawnTransform); } }
1.3 BP_EnemyCharacter






浙公网安备 33010602011771号