// Fill out your copyright notice in the Description page of Project Settings. #include "BasePawn.h" #include "Components/StaticMeshComponent.h" #include "GameFramework/FloatingPawnMovement.h" #include "Util.h" #define LogInfo(Msg) Util::log_info(TEXT("ABasePawn"), Msg) // Sets default values ABasePawn::ABasePawn(const FObjectInitializer &object_initializer): APawn(object_initializer) { // Create default components. root_component = object_initializer.CreateDefaultSubobject(this, FName("Root")); RootComponent = root_component; collision = object_initializer.CreateDefaultSubobject(this, FName("Collision")); collision->SetupAttachment(RootComponent); collision->SetCollisionProfileName(FName("Pawn")); collision->SetCanEverAffectNavigation(false); player_mesh = object_initializer.CreateDefaultSubobject(this, FName("PlayerMesh")); player_mesh->SetupAttachment(collision); player_mesh->SetCollisionEnabled(ECollisionEnabled::NoCollision); player_mesh->SetCanEverAffectNavigation(false); movement_component = object_initializer.CreateDefaultSubobject(this, FName("MovementComponent")); movement_component->UpdatedComponent = collision; PrimaryActorTick.bCanEverTick = true; // Set defaults. max_health = 100; max_ammo = 25; } // Called when the game starts or when spawned void ABasePawn::BeginPlay() { Super::BeginPlay(); /* * Setup collision handler. */ collision->OnComponentHit.AddDynamic(this, &ABasePawn::handle_hit); /* * Set base state. */ current_health = max_health; current_ammo = max_ammo; } void ABasePawn::handle_hit( UPrimitiveComponent* hit_component, AActor* other_actor, UPrimitiveComponent* other_component, FVector normal_impulse, const FHitResult& hit ) { UClass* other_class = other_actor->GetClass(); if (damage_class_map.Contains(other_class)) { // Update current health. current_health -= damage_class_map[other_class]; LogInfo(FString::Printf(TEXT("Total health %d"), current_health)); } } UPawnMovementComponent* ABasePawn::GetMovementComponent() const { return movement_component; } FVector ABasePawn::get_location() const { return collision->GetComponentLocation(); } // Called every frame void ABasePawn::Tick(float DeltaTime) { Super::Tick(DeltaTime); /* * Auto-fire. */ shoot_time_elapsed += DeltaTime; if (shooting_enabled && shoot_time_elapsed > fire_rate_s) { shoot(); } /* * Handle death. */ if (current_health <= 0) { handle_death(); current_health = max_health; } } void ABasePawn::handle_move_forward(float axis) { if (axis != 0) { AddMovementInput(FVector(1,0,0), axis); } } void ABasePawn::handle_move_right(float axis) { if (axis != 0) { AddMovementInput(FVector(0, 1, 0), axis); } } void ABasePawn::update_yaw_x(float x_component) { yaw.x_component = x_component; } void ABasePawn::update_yaw_y(float y_component) { yaw.y_component = y_component; } void ABasePawn::start_shooting() { shooting_enabled = true; shoot(); } void ABasePawn::stop_shooting() { shooting_enabled = false; } void ABasePawn::shoot() { if (current_ammo > 0) { FVector player_location = player_mesh->GetComponentLocation(); const float y = yaw.calculate_yaw(); const FRotator rotator(0, y, 0); FVector forward = FRotationMatrix(rotator).GetUnitAxis(EAxis::X) * 100; FVector spawn_location = player_location + forward; FActorSpawnParameters spawnParameters; spawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; spawnParameters.Owner = this; spawnParameters.Instigator = this; AActor* bullet = GetWorld()->SpawnActor( bullet_actor_class, spawn_location, rotator, spawnParameters ); shoot_time_elapsed = 0; current_ammo -= 1; } } void ABasePawn::handle_death() { /* * Disable collision. */ collision->SetCollisionEnabled(ECollisionEnabled::NoCollision); if (death_effect) { death_effect->Destroy(); death_effect = nullptr; } /* * Spawn particle effect. */ FVector player_location = player_mesh->GetComponentLocation(); FActorSpawnParameters spawnParameters; spawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; death_effect = GetWorld()->SpawnActor( death_class, player_location, FRotator(0,0,0), spawnParameters ); destroy_self(); } void ABasePawn::destroy_self() { /* * Remove thyself from this world. */ Destroy(); }