// Copyright Team Lumi. All Rights Reserved. #include "LumiCharacter.h" #include "Engine/LocalPlayer.h" #include "Camera/CameraComponent.h" #include "Components/CapsuleComponent.h" #include "GameFramework/SpringArmComponent.h" #include "GameFramework/Controller.h" #include "EnhancedInputComponent.h" #include "EnhancedInputSubsystems.h" #include "InputActionValue.h" #include "GameFramework/CharacterMovementComponent.h" DEFINE_LOG_CATEGORY(LogLumiCharacter); // Sets default values ALumiCharacter::ALumiCharacter() { // 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; // Set size for collision capsule GetCapsuleComponent()->InitCapsuleSize(35.0f, 90.0f); // Allow double jumping JumpMaxCount = 2; // Don't rotate when the controller rotates. Let that just affect the camera. bUseControllerRotationPitch = false; bUseControllerRotationYaw = false; bUseControllerRotationRoll = false; // Create a camera boom (pulls in towards the player if there is a collision) CameraBoom = CreateDefaultSubobject(TEXT("CameraBoom")); CameraBoom->SetupAttachment(RootComponent); CameraBoom->TargetArmLength = 400.0f; // The camera follows at this distance behind the character CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller CameraBoom->SocketOffset = DefaultBoomOffset; // Create a follow camera FollowCamera = CreateDefaultSubobject(TEXT("FollowCamera")); FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm } ELumiStance ALumiCharacter::GetCurrentStance() const { return CurrentStance; } // Called when the game starts or when spawned void ALumiCharacter::BeginPlay() { Super::BeginPlay(); // Add Input Mapping Context if (const APlayerController* PlayerController = Cast(Controller)) { if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem< UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer())) { Subsystem->AddMappingContext(DefaultMappingContext, 0); } } } /* // Called every frame void ALumiCharacter::Tick(float DeltaTime) { Super::Tick(DeltaTime); } */ bool ALumiCharacter::IsLastJump() { return JumpCurrentCountPreJump == JumpMaxCount - 1; } // Called to bind functionality to input void ALumiCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { Super::SetupPlayerInputComponent(PlayerInputComponent); // Set up action bindings if (UEnhancedInputComponent* EnhancedInputComponent = Cast(PlayerInputComponent)) { // Grabbing EnhancedInputComponent->BindAction(GrabAction, ETriggerEvent::Triggered, this, &ALumiCharacter::OnGrabActionTriggered); // Jumping EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &ALumiCharacter::OnJumpActionStarted); EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Ongoing, this, &ALumiCharacter::OnJumpActionOngoing); EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ALumiCharacter::OnJumpActionCompleted); // Moving EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &ALumiCharacter::OnMoveActionTriggered); // Looking EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &ALumiCharacter::OnLookActionTriggered); } else { UE_LOG( LogLumiCharacter, Error, TEXT( "'%s' Failed to find an Enhanced Input component! " "This template is built to use the Enhanced Input system. " "If you intend to use the legacy system, then you will need to update this C++ file." ), *GetNameSafe(this) ); } } void ALumiCharacter::OnGrabActionTriggered(const FInputActionValue& Value) { UE_LOG(LogLumiCharacter, Log, TEXT("Grab Triggered")); } void ALumiCharacter::OnJumpActionStarted(const FInputActionValue& Value) { // Broadcast that the jump has started OnJumpStarted.Broadcast(); UE_LOG(LogLumiCharacter, Log, TEXT("Jump Started")); Jump(); } void ALumiCharacter::OnJumpActionOngoing(const FInputActionValue& Value) { } void ALumiCharacter::OnJumpActionCompleted(const FInputActionValue& Value) { StopJumping(); } void ALumiCharacter::OnMoveActionTriggered(const FInputActionValue& Value) { // input is a Vector2D const FVector2D MovementVector = Value.Get(); if (Controller != nullptr) { // find out which way is forward const FRotator Rotation = Controller->GetControlRotation(); const FRotator YawRotation(0, Rotation.Yaw, 0); // get forward vector const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X); // get right vector const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y); // add movement AddMovementInput(ForwardDirection, MovementVector.Y); AddMovementInput(RightDirection, MovementVector.X); } } void ALumiCharacter::OnLookActionTriggered(const FInputActionValue& Value) { // input is a Vector2D const FVector2D LookAxisVector = Value.Get(); if (Controller != nullptr) { // add yaw and pitch input to controller AddControllerYawInput(LookAxisVector.X); AddControllerPitchInput(LookAxisVector.Y); } } void ALumiCharacter::OnDefaultStance_Implementation() { UE_LOG(LogLumiCharacter, Log, TEXT("OnDefaultStance_Implementation()")); } void ALumiCharacter::OnMagicStance_Implementation() { UE_LOG(LogLumiCharacter, Log, TEXT("OnMagicStance_Implementation()")); } ELumiStance ALumiCharacter::SetCurrentStance(const ELumiStance NewStance) { const ELumiStance OldStance = CurrentStance; UCharacterMovementComponent* Movement = GetCharacterMovement(); if (NewStance == ELumiStance::Default) { Movement->bOrientRotationToMovement = true; Movement->bUseControllerDesiredRotation = false; OnDefaultStance(); } else if (NewStance == ELumiStance::Magic) { Movement->bOrientRotationToMovement = false; Movement->bUseControllerDesiredRotation = true; OnMagicStance(); } CurrentStance = NewStance; return OldStance; }