diff --git a/Source/MyProject3/EnemySpaceship.cpp b/Source/MyProject3/EnemySpaceship.cpp new file mode 100644 index 0000000..f8885bf --- /dev/null +++ b/Source/MyProject3/EnemySpaceship.cpp @@ -0,0 +1,92 @@ +#include "EnemySpaceship.h" +#include "SpaceshipPawn.h" +#include "SpaceshipProjectile.h" +#include "Kismet/GameplayStatics.h" + +AEnemySpaceship::AEnemySpaceship() +{ + PrimaryActorTick.bCanEverTick = true; + + ShipMesh = CreateDefaultSubobject(TEXT("ShipMesh")); + RootComponent = ShipMesh; + + CurrentHealth = MaxHealth; +} + +void AEnemySpaceship::BeginPlay() +{ + Super::BeginPlay(); + + PlayerPawn = Cast(UGameplayStatics::GetPlayerPawn(GetWorld(), 0)); + GetWorldTimerManager().SetTimer(FireTimerHandle, this, &AEnemySpaceship::FireAtPlayer, FireRate, true); +} + +void AEnemySpaceship::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); + + if (PlayerPawn) + { + // Calculate distance to player + float DistanceToPlayer = FVector::Dist(GetActorLocation(), PlayerPawn->GetActorLocation()); + + if (DistanceToPlayer <= DetectionRange) + { + // Look at player + FVector Direction = PlayerPawn->GetActorLocation() - GetActorLocation(); + FRotator NewRotation = Direction.Rotation(); + SetActorRotation(FMath::RInterpTo(GetActorRotation(), NewRotation, DeltaTime, 2.0f)); + + // Move towards player while maintaining some distance + float TargetDistance = 1000.0f; + if (DistanceToPlayer > TargetDistance) + { + FVector NewLocation = GetActorLocation() + (Direction.GetSafeNormal() * MovementSpeed * DeltaTime); + SetActorLocation(NewLocation); + } + else if (DistanceToPlayer < TargetDistance - 100.0f) + { + FVector NewLocation = GetActorLocation() - (Direction.GetSafeNormal() * MovementSpeed * DeltaTime); + SetActorLocation(NewLocation); + } + } + } +} + +void AEnemySpaceship::FireAtPlayer() +{ + if (PlayerPawn && FVector::Dist(GetActorLocation(), PlayerPawn->GetActorLocation()) <= DetectionRange) + { + UWorld* World = GetWorld(); + if (World) + { + FVector SpawnLocation = GetActorLocation() + (GetActorForwardVector() * 100.0f); + FRotator SpawnRotation = GetActorRotation(); + FActorSpawnParameters SpawnParams; + SpawnParams.Owner = this; + SpawnParams.Instigator = GetInstigator(); + + ASpaceshipProjectile* Projectile = World->SpawnActor( + ASpaceshipProjectile::StaticClass(), + SpawnLocation, + SpawnRotation, + SpawnParams + ); + } + } +} + +float AEnemySpaceship::TakeDamage(float Damage, FDamageEvent const& DamageEvent, + AController* EventInstigator, AActor* DamageCauser) +{ + float ActualDamage = Super::TakeDamage(Damage, DamageEvent, EventInstigator, DamageCauser); + + CurrentHealth -= ActualDamage; + if (CurrentHealth <= 0) + { + // Destroy the enemy ship + Destroy(); + } + + return ActualDamage; +} \ No newline at end of file diff --git a/Source/MyProject3/EnemySpaceship.h b/Source/MyProject3/EnemySpaceship.h new file mode 100644 index 0000000..b7ef931 --- /dev/null +++ b/Source/MyProject3/EnemySpaceship.h @@ -0,0 +1,41 @@ +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/Pawn.h" +#include "EnemySpaceship.generated.h" + +UCLASS() +class MYPROJECT3_API AEnemySpaceship : public APawn +{ + GENERATED_BODY() + +public: + AEnemySpaceship(); + virtual void Tick(float DeltaTime) override; + +protected: + virtual void BeginPlay() override; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components") + class UStaticMeshComponent* ShipMesh; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI") + float DetectionRange = 1500.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI") + float FireRate = 2.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement") + float MovementSpeed = 500.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Combat") + float MaxHealth = 100.0f; + + float CurrentHealth; + FTimerHandle FireTimerHandle; + class ASpaceshipPawn* PlayerPawn; + + void FireAtPlayer(); + virtual float TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, + AController* EventInstigator, AActor* DamageCauser) override; +}; \ No newline at end of file diff --git a/Source/MyProject3/SpaceshipPawn.cpp b/Source/MyProject3/SpaceshipPawn.cpp new file mode 100644 index 0000000..630b705 --- /dev/null +++ b/Source/MyProject3/SpaceshipPawn.cpp @@ -0,0 +1,99 @@ +#include "SpaceshipPawn.h" +#include "GameFramework/SpringArmComponent.h" +#include "Camera/CameraComponent.h" +#include "Components/StaticMeshComponent.h" +#include "SpaceshipProjectile.h" + +ASpaceshipPawn::ASpaceshipPawn() +{ + PrimaryActorTick.bCanEverTick = true; + + // Create and setup the ship's mesh + ShipMesh = CreateDefaultSubobject(TEXT("ShipMesh")); + RootComponent = ShipMesh; + + // Create and setup the camera spring arm + CameraSpringArm = CreateDefaultSubobject(TEXT("CameraSpringArm")); + CameraSpringArm->SetupAttachment(RootComponent); + CameraSpringArm->TargetArmLength = 400.0f; + CameraSpringArm->bEnableCameraLag = true; + CameraSpringArm->CameraLagSpeed = 3.0f; + + // Create and setup the camera + Camera = CreateDefaultSubobject(TEXT("Camera")); + Camera->SetupAttachment(CameraSpringArm, USpringArmComponent::SocketName); +} + +void ASpaceshipPawn::BeginPlay() +{ + Super::BeginPlay(); +} + +void ASpaceshipPawn::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); + + if (!CurrentVelocity.IsZero()) + { + FVector NewLocation = GetActorLocation() + (CurrentVelocity * DeltaTime); + SetActorLocation(NewLocation); + } +} + +void ASpaceshipPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) +{ + Super::SetupPlayerInputComponent(PlayerInputComponent); + + PlayerInputComponent->BindAxis("MoveForward", this, &ASpaceshipPawn::MoveForward); + PlayerInputComponent->BindAxis("MoveRight", this, &ASpaceshipPawn::MoveRight); + PlayerInputComponent->BindAxis("Turn", this, &ASpaceshipPawn::Turn); + PlayerInputComponent->BindAxis("LookUp", this, &ASpaceshipPawn::LookUp); + PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ASpaceshipPawn::Fire); +} + +void ASpaceshipPawn::MoveForward(float Value) +{ + CurrentVelocity.X = FMath::Clamp(Value, -1.0f, 1.0f) * MovementSpeed; +} + +void ASpaceshipPawn::MoveRight(float Value) +{ + CurrentVelocity.Y = FMath::Clamp(Value, -1.0f, 1.0f) * MovementSpeed; +} + +void ASpaceshipPawn::Turn(float Value) +{ + AddActorLocalRotation(FRotator(0.0f, Value * RotationSpeed * GetWorld()->GetDeltaSeconds(), 0.0f)); +} + +void ASpaceshipPawn::LookUp(float Value) +{ + float NewPitch = CameraSpringArm->GetRelativeRotation().Pitch + Value * RotationSpeed * GetWorld()->GetDeltaSeconds(); + NewPitch = FMath::Clamp(NewPitch, -80.0f, 80.0f); + CameraSpringArm->SetRelativeRotation(FRotator(NewPitch, 0.0f, 0.0f)); +} + +void ASpaceshipPawn::Fire() +{ + UWorld* World = GetWorld(); + if (World) + { + FVector SpawnLocation = ShipMesh->GetSocketLocation(TEXT("ProjectileSpawn")); + if (SpawnLocation == FVector::ZeroVector) + { + SpawnLocation = GetActorLocation() + (GetActorForwardVector() * 100.0f); + } + + FRotator SpawnRotation = GetActorRotation(); + FActorSpawnParameters SpawnParams; + SpawnParams.Owner = this; + SpawnParams.Instigator = GetInstigator(); + + ASpaceshipProjectile* Projectile = World->SpawnActor( + ASpaceshipProjectile::StaticClass(), + SpawnLocation, + SpawnRotation, + SpawnParams + ); + } +} \ No newline at end of file diff --git a/Source/MyProject3/SpaceshipPawn.h b/Source/MyProject3/SpaceshipPawn.h new file mode 100644 index 0000000..cdc0cba --- /dev/null +++ b/Source/MyProject3/SpaceshipPawn.h @@ -0,0 +1,44 @@ +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/Pawn.h" +#include "SpaceshipPawn.generated.h" + +UCLASS() +class MYPROJECT3_API ASpaceshipPawn : public APawn +{ + GENERATED_BODY() + +public: + ASpaceshipPawn(); + virtual void Tick(float DeltaTime) override; + virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; + +protected: + virtual void BeginPlay() override; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components") + class UStaticMeshComponent* ShipMesh; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components") + class USpringArmComponent* CameraSpringArm; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components") + class UCameraComponent* Camera; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement") + float MovementSpeed = 1000.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement") + float RotationSpeed = 100.0f; + + // Movement functions + void MoveForward(float Value); + void MoveRight(float Value); + void Turn(float Value); + void LookUp(float Value); + void Fire(); + +private: + FVector CurrentVelocity; +}; \ No newline at end of file diff --git a/Source/MyProject3/SpaceshipProjectile.cpp b/Source/MyProject3/SpaceshipProjectile.cpp new file mode 100644 index 0000000..14dc22a --- /dev/null +++ b/Source/MyProject3/SpaceshipProjectile.cpp @@ -0,0 +1,43 @@ +#include "SpaceshipProjectile.h" +#include "GameFramework/ProjectileMovementComponent.h" +#include "Components/StaticMeshComponent.h" + +ASpaceshipProjectile::ASpaceshipProjectile() +{ + PrimaryActorTick.bCanEverTick = true; + + // Create and setup the projectile mesh + ProjectileMesh = CreateDefaultSubobject(TEXT("ProjectileMesh")); + RootComponent = ProjectileMesh; + ProjectileMesh->SetCollisionProfileName(TEXT("Projectile")); + ProjectileMesh->OnComponentHit.AddDynamic(this, &ASpaceshipProjectile::OnHit); + + // Create and setup projectile movement + ProjectileMovement = CreateDefaultSubobject(TEXT("ProjectileMovement")); + ProjectileMovement->UpdatedComponent = ProjectileMesh; + ProjectileMovement->InitialSpeed = ProjectileSpeed; + ProjectileMovement->MaxSpeed = ProjectileSpeed; + ProjectileMovement->bRotationFollowsVelocity = true; + ProjectileMovement->ProjectileGravityScale = 0.0f; + + // Set lifetime + InitialLifeSpan = 3.0f; +} + +void ASpaceshipProjectile::BeginPlay() +{ + Super::BeginPlay(); +} + +void ASpaceshipProjectile::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, + FVector NormalImpulse, const FHitResult& Hit) +{ + if (OtherActor && OtherActor != this) + { + // Apply damage to the hit actor (if it implements damage interface) + FDamageEvent DamageEvent; + OtherActor->TakeDamage(DamageAmount, DamageEvent, nullptr, this); + } + + Destroy(); +} \ No newline at end of file diff --git a/Source/MyProject3/SpaceshipProjectile.h b/Source/MyProject3/SpaceshipProjectile.h new file mode 100644 index 0000000..3c6bd95 --- /dev/null +++ b/Source/MyProject3/SpaceshipProjectile.h @@ -0,0 +1,33 @@ +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/Actor.h" +#include "SpaceshipProjectile.generated.h" + +UCLASS() +class MYPROJECT3_API ASpaceshipProjectile : public AActor +{ + GENERATED_BODY() + +public: + ASpaceshipProjectile(); + +protected: + virtual void BeginPlay() override; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components") + class UStaticMeshComponent* ProjectileMesh; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components") + class UProjectileMovementComponent* ProjectileMovement; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Projectile") + float ProjectileSpeed = 3000.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Projectile") + float DamageAmount = 20.0f; + + UFUNCTION() + void OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, + FVector NormalImpulse, const FHitResult& Hit); +}; \ No newline at end of file