// Fill out your copyright notice in the Description page of Project Settings. #include "MyDefaultPawn.h" #include "UObject/ConstructorHelpers.h" #include "Engine/World.h" #include "Components/StaticMeshComponent.h" #include "GameFramework/PlayerController.h" #include "Engine/CollisionProfile.h" #include "Engine/StaticMesh.h" #include "Components/SphereComponent.h" #include "GameFramework/PawnMovementComponent.h" #include "GameFramework/FloatingPawnMovement.h" #include "GameFramework/CharacterMovementComponent.h" #include "GameFramework/PlayerInput.h" FName AMyDefaultPawn::MovementComponentName(TEXT("MovementComponent0")); FName AMyDefaultPawn::CollisionComponentName(TEXT("CollisionComponent0")); FName AMyDefaultPawn::MeshComponentName(TEXT("MeshComponent0")); AMyDefaultPawn::AMyDefaultPawn(const FObjectInitializer& ObjectInitializer) : APawn(ObjectInitializer) { SetCanBeDamaged(true); SetRemoteRoleForBackwardsCompat(ROLE_SimulatedProxy); bReplicates = true; NetPriority = 3.0f; BaseEyeHeight = 0.0f; bCollideWhenPlacing = false; SpawnCollisionHandlingMethod = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; CollisionComponent = CreateDefaultSubobject(AMyDefaultPawn::CollisionComponentName); CollisionComponent->InitSphereRadius(35.0f); CollisionComponent->SetCollisionProfileName(UCollisionProfile::Pawn_ProfileName); CollisionComponent->CanCharacterStepUpOn = ECB_No; CollisionComponent->SetShouldUpdatePhysicsVolume(true); CollisionComponent->SetCanEverAffectNavigation(false); CollisionComponent->bDynamicObstacle = true; RootComponent = CollisionComponent; MovementComponent = CreateDefaultSubobject(AMyDefaultPawn::MovementComponentName); MovementComponent->UpdatedComponent = CollisionComponent; // Structure to hold one-time initialization struct FConstructorStatics { ConstructorHelpers::FObjectFinder SphereMesh; FConstructorStatics() : SphereMesh(TEXT("/Engine/EngineMeshes/Sphere")) {} }; static FConstructorStatics ConstructorStatics; MeshComponent = CreateOptionalDefaultSubobject(AMyDefaultPawn::MeshComponentName); if (MeshComponent) { MeshComponent->SetStaticMesh(ConstructorStatics.SphereMesh.Object); MeshComponent->AlwaysLoadOnClient = true; MeshComponent->AlwaysLoadOnServer = true; MeshComponent->bOwnerNoSee = true; MeshComponent->bCastDynamicShadow = true; MeshComponent->bAffectDynamicIndirectLighting = false; MeshComponent->bAffectDistanceFieldLighting = false; MeshComponent->bVisibleInRayTracing = false; MeshComponent->PrimaryComponentTick.TickGroup = TG_PrePhysics; MeshComponent->SetupAttachment(RootComponent); MeshComponent->SetCollisionProfileName(UCollisionProfile::Pawn_ProfileName); const float Scale = CollisionComponent->GetUnscaledSphereRadius() / 160.f; // @TODO: hardcoding known size of EngineMeshes.Sphere. Should use a unit sphere instead. MeshComponent->SetRelativeScale3D(FVector(Scale)); MeshComponent->SetGenerateOverlapEvents(false); MeshComponent->SetCanEverAffectNavigation(false); } // This is the default pawn class, we want to have it be able to move out of the box. bAddDefaultMovementBindings = true; } void InitializeDefaultPawnInputBindings() { static bool bBindingsAdded = false; if (!bBindingsAdded) { bBindingsAdded = true; UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveForward", EKeys::W, 1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveForward", EKeys::S, -1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveForward", EKeys::Up, 1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveForward", EKeys::Down, -1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveForward", EKeys::Gamepad_LeftY, 1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveRight", EKeys::A, -1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveRight", EKeys::D, 1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveRight", EKeys::Gamepad_LeftX, 1.f)); // HACK: Android controller bindings in ini files seem to not work // Direct overrides here some to work #if !PLATFORM_ANDROID UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Gamepad_LeftThumbstick, 1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Gamepad_RightThumbstick, -1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Gamepad_FaceButton_Bottom, 1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::LeftControl, -1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::SpaceBar, 1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::C, -1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::E, 1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Q, -1.f)); #else UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Gamepad_LeftTriggerAxis, -0.5f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Gamepad_RightTriggerAxis, 0.5f)); #endif UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_TurnRate", EKeys::Gamepad_RightX, 1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_TurnRate", EKeys::Left, -1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_TurnRate", EKeys::Right, 1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_Turn", EKeys::MouseX, 1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_LookUpRate", EKeys::Gamepad_RightY, 1.f)); UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_LookUp", EKeys::MouseY, -1.f)); } } void AMyDefaultPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { check(PlayerInputComponent); if (bAddDefaultMovementBindings) { InitializeDefaultPawnInputBindings(); PlayerInputComponent->BindAxis("DefaultPawn_MoveForward", this, &AMyDefaultPawn::MoveForward); PlayerInputComponent->BindAxis("DefaultPawn_MoveRight", this, &AMyDefaultPawn::MoveRight); PlayerInputComponent->BindAxis("DefaultPawn_MoveUp", this, &AMyDefaultPawn::MoveUp_World); PlayerInputComponent->BindAxis("DefaultPawn_Turn", this, &AMyDefaultPawn::AddControllerYawInput); PlayerInputComponent->BindAxis("DefaultPawn_TurnRate", this, &AMyDefaultPawn::TurnAtRate); PlayerInputComponent->BindAxis("DefaultPawn_LookUp", this, &AMyDefaultPawn::AddControllerPitchInput); PlayerInputComponent->BindAxis("DefaultPawn_LookUpRate", this, &AMyDefaultPawn::LookUpAtRate); } } void AMyDefaultPawn::UpdateNavigationRelevance() { if (CollisionComponent) { CollisionComponent->SetCanEverAffectNavigation(bCanAffectNavigationGeneration); } } void AMyDefaultPawn::MoveRight(float Val) { if (Val != 0.f) { if (Controller) { FRotator const ControlSpaceRot = Controller->GetControlRotation(); // transform to world space and add it AddMovementInput(FRotationMatrix(ControlSpaceRot).GetScaledAxis(EAxis::Y), Val); } } } void AMyDefaultPawn::MoveForward(float Val) { if (Val != 0.f) { if (Controller) { FRotator const ControlSpaceRot = Controller->GetControlRotation(); // transform to world space and add it AddMovementInput(FRotationMatrix(ControlSpaceRot).GetScaledAxis(EAxis::X), Val); } } } void AMyDefaultPawn::MoveUp_World(float Val) { if (Val != 0.f) { AddMovementInput(FVector::UpVector, Val); } } void AMyDefaultPawn::TurnAtRate(float Rate) { // calculate delta for this frame from the rate information AddControllerYawInput(Rate * GetWorld()->GetDeltaSeconds() * CustomTimeDilation); } void AMyDefaultPawn::LookUpAtRate(float Rate) { // calculate delta for this frame from the rate information AddControllerPitchInput(Rate * GetWorld()->GetDeltaSeconds() * CustomTimeDilation); } UPawnMovementComponent* AMyDefaultPawn::GetMovementComponent() const { return MovementComponent; }