// Fill out your copyright notice in the Description page of Project Settings. #include "MPlayerMech.h" #include "DrawDebugHelpers.h" #include "MCharacter.h" #include "NavigationSystem.h" #include "Camera/CameraComponent.h" #include "Components/CapsuleComponent.h" #include "Components/BoxComponent.h" #include "Components/ArrowComponent.h" #include "GameFramework/SpringArmComponent.h" #include "MHealthComponent.h" #include "Components/WidgetComponent.h" #include "EnvironmentQuery/EnvQueryManager.h" #include "EnvironmentQuery/EnvQueryTypes.h" #include "Kismet/GameplayStatics.h" #include "Misc/OutputDeviceDebug.h" int32 AMPlayerMech::DebugMechDrawing = 0; FAutoConsoleVariableRef CVAR_DebugMechDrawing( TEXT("MDEF.DebugMechDrawing"), AMPlayerMech::DebugMechDrawing, TEXT("Draw debug visualizations for the player mech"), ECVF_Cheat); AMPlayerMech::AMPlayerMech() { PrimaryActorTick.bCanEverTick = true; MeshComponent = CreateDefaultSubobject("MeshComponent"); RootComponent = MeshComponent; SpringArmComponent = CreateDefaultSubobject("SpringArmComponent"); SpringArmComponent->SetupAttachment(MeshComponent); SpringArmComponent->TargetArmLength = 1500.f; CameraComponent = CreateDefaultSubobject(TEXT("CameraComponent")); CameraComponent->SetupAttachment(SpringArmComponent); CameraComponent->SetRelativeLocation(FVector(0.f, 0.f, BaseEyeHeight)); HealthComponent = CreateDefaultSubobject(TEXT("HealthComponent")); StatusIndicatorWidget = CreateDefaultSubobject(TEXT("StatusIndicator")); StatusIndicatorWidget->SetupAttachment(RootComponent); PlayerDismountRadius = 500.f; PlayerDismountGroundOffset = 100.f; ResetZOffset = 200.f; MountedPlayerCharacter = nullptr; } void AMPlayerMech::BeginPlay() { Super::BeginPlay(); GetWorldTimerManager().SetTimerForNextTick(this, &layerMech::SetupHealthIndicator); } void AMPlayerMech::SetupHealthIndicator() { UUserWidget* IndicatorWidget = StatusIndicatorWidget->GetWidget(); if(IndicatorWidget) { FObjectProperty* ObjProp = FindFProperty(IndicatorWidget->GetClass(), TEXT("HealthComponent")); if(ObjProp) { ObjProp->SetObjectPropertyValue_InContainer(IndicatorWidget, HealthComponent, 0); } const FString Command = FString::Printf(TEXT("SetupHealthChangeAnims")); FOutputDeviceDebug DebugOutputDevice; if(!IndicatorWidget->CallFunctionByNameWithArguments(*Command, DebugOutputDevice, IndicatorWidget, true)) { UE_LOG(LogTemp, Log, TEXT("Failed to setup health change anims")); } } } void AMPlayerMech::MoveForward(float ScaleValue) { //AddMovementInput(GetActorForwardVector(), ScaleValue); } void AMPlayerMech::MoveRight(float ScaleValue) { //AddMovementInput(GetActorRightVector(), ScaleValue); //AddControllerYawInput(ScaleValue); } void AMPlayerMech::RequestDismount() { FEnvQueryRequest DismountQueryRequest = FEnvQueryRequest(DismountEQS); DismountQueryRequest.Execute(EEnvQueryRunMode::SingleResult, this, &layerMech::HandleDismountResponse); } void AMPlayerMech::RevertOrientation() { const FRotator CameraOrientation = CameraComponent->GetComponentRotation(); const FRotator NewRotation(0.f, CameraOrientation.Yaw, 0.f); const FVector NewLocation = GetActorLocation() + FVector(0.f, 0.f, ResetZOffset); SetActorLocationAndRotation(NewLocation, NewRotation, false, nullptr, ETeleportType::TeleportPhysics); } void AMPlayerMech::HandleDismountResponse(TSharedPtr QueryResult) { if(QueryResult->IsSuccsessful()) { FVector DismountLocation = QueryResult->GetItemAsLocation(0); if(DebugMechDrawing > 0) DrawDebugSphere(GetWorld(), DismountLocation, 50.f, 20, FColor::Green, false, 5.f, 0, 1.f); if(MountedPlayerCharacter) { MountedPlayerCharacter->DetachFromActor(FDetachmentTransformRules::KeepWorldTransform); MountedPlayerCharacter->SetActorHiddenInGame(false); MountedPlayerCharacter->SetActorEnableCollision(true); MountedPlayerCharacter->SetActorTickEnabled(true); //DismountLocation.Z += PlayerDismountGroundOffset; // Add a bit of offset from the ground to avoid player falling from the ground when dismounting MountedPlayerCharacter->SetActorLocationAndRotation(DismountLocation, FRotator(0.f, GetActorRotation().Yaw, 0.f), false, nullptr, ETeleportType::ResetPhysics); APlayerController* PC = Cast(GetController()); if(PC) { PC->Possess(Cast(MountedPlayerCharacter)); } MountedPlayerCharacter->SetMounted(false); MountedPlayerCharacter->CheckIfInSafeZone(); MountedPlayerCharacter = nullptr; if(MountSound) UGameplayStatics::PlaySound2D(this, MountSound); } } else { UE_LOG(LogTemp, Log, TEXT("Could not find suitable location to dismount")); } } void AMPlayerMech::Tick(float DeltaTime) { Super::Tick(DeltaTime); } void AMPlayerMech::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { Super::SetupPlayerInputComponent(PlayerInputComponent); PlayerInputComponent->BindAxis("MoveForward", this, &layerMech::MoveForward); PlayerInputComponent->BindAxis("MoveRight", this, &layerMech::MoveRight); //PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput); PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput); PlayerInputComponent->BindAction("Dismount", IE_Pressed, this, &layerMech::RequestDismount); PlayerInputComponent->BindAction("ResetVehicle", IE_Pressed, this, &layerMech::RevertOrientation); } void AMPlayerMech::MountPlayerCharacter(AMCharacter* PlayerCharacter) { if(!PlayerCharacter) return; MountedPlayerCharacter = PlayerCharacter; MountedPlayerCharacter->SetActorHiddenInGame(true); MountedPlayerCharacter->SetActorEnableCollision(false); MountedPlayerCharacter->SetActorTickEnabled(false); PlayerCharacter->AttachToActor(this, FAttachmentTransformRules::SnapToTargetNotIncludingScale, PlayerAttachmentSocket); if(MountSound) UGameplayStatics::PlaySound2D(this, MountSound); } void AMPlayerMech::GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const { TagContainer = ActorTags; } UMeshComponent* AMPlayerMech::GetHoveredMeshComponent() { return MeshComponent; }