UE5.1.1C++从0开始(5.魔法子弹的落点问题)

教程的第5和6章我不打算写文档,毕竟不是什么很难的东西,跟着做就行了,debug用的代码段我会在布置的几个作业里面很经常性的用到,各位可以做一个参考。

这篇文章先解决第一个作业:魔法子弹的落点问题,各位看教程估计也看到了,游戏内人物发射的子弹朝向虽然是和我们的视角朝向相同,但是它的落点并不是我们视角最终落在的地方。所以需要我们来修复子弹落点的问题。

首先重新审视我们之前敲的代码,先把我们所写的代码做个结构的划分。我们会发现,发射子弹的实质是生成子弹这个对象,并给子弹这个对象一个初速度,初速度方向,以及生成位置罢了。而初速度方向,这个是我们实现这个功能需要关注的点。视频里面教程给了一个示例,就是一直瞄准玩家的那个方向键,对此我进行了一个思考,我希望这个检测只在我每次摁下鼠标左键的时候才发生,而不是时时刻刻都在检测,所以我做了一个linetrace,就是最开始我们打开宝箱所用的那个函数,我们使用linetrace找到离我们最近的一面墙,让我们的子弹的最终落点落在我们的准心所指向的地方。换句话说就是,将我们的子弹的方向从与我们视角方向一直更变为朝向准心所指的方向。

请添加图片描述

如图所示,红色是从摄像机出发,沿着我们的视觉中心的一个碰撞检测,而绿色的线是我们子弹的移动路线,每次摁下鼠标左键的时候,进行一次碰撞检测,如果检测到了碰撞,那么就将碰撞点设为我们子弹的落点,而我们子弹的起点照旧不需要改变,这样一来,子弹的rotation就确定了。

代码如下:

SCharacter.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "SCharacter.h"
#include "GameFramework/SpringArmComponent.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/Controller.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "SInteractionComponent.h"
#include "TimerManager.h"
//#include "../../../../../UE_5.1/Engine/Plugins/EnhancedInput/Source/EnhancedInput/Public/EnhancedInputSubsystems.h"
//#include "../../../../../UE_5.1/Engine/Plugins/EnhancedInput/Source/EnhancedInput/Public/EnhancedInputComponent.h"


// Sets default values
ASCharacter::ASCharacter()
{
 	// 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;

	bUseControllerRotationPitch = false;
	bUseControllerRotationRoll = false;
	bUseControllerRotationYaw = false;

	GetCharacterMovement()->bOrientRotationToMovement = true;

	SpringArmComp = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	SpringArmComp->SetupAttachment(RootComponent);
	SpringArmComp->bUsePawnControlRotation = true;

	CameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
	CameraComp->SetupAttachment(SpringArmComp);
	CameraComp->bUsePawnControlRotation = false;

	InteractionComp = CreateDefaultSubobject<USInteractionComponent>(TEXT("InteractionComp"));

}

// Called when the game starts or when spawned
void ASCharacter::BeginPlay()
{
	Super::BeginPlay();
	if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
	{
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
		{
			Subsystem->AddMappingContext(DefaultMappingContext, 0);
		}
	}

	
}

void ASCharacter::Move(const FInputActionValue& Value)
{
	FVector2D MovementVector = Value.Get<FVector2D>();

	if (Controller!=nullptr)
	{
		const FRotator Rotation = Controller->GetControlRotation();
		//拿到控制器的Yaw面的旋转角度,而不是Character的旋转角度
		const FRotator YawRotation(0, Rotation.Yaw, 0);

		//把角度用向量来表示,同时获取到不同方向的向量值,而这个向量的角度是按照我们控制器的角度来说的
		const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
		
		//MovementVector的X和Y是相对于我们的视角来说的,也就是我们视角的正前方是Y,而我们视角的正右方是X
		AddMovementInput(ForwardDirection, MovementVector.Y);
		AddMovementInput(RightDirection, MovementVector.X);
	}
}

void ASCharacter::Look(const FInputActionValue& Value)
{
	FVector2D LookAxisVector = Value.Get<FVector2D>();

	if (Controller!=nullptr)
	{
		AddControllerYawInput(LookAxisVector.X);
		AddControllerPitchInput(LookAxisVector.Y);
	}
}

void ASCharacter::PrimaryAttack()
{

	GetWorldTimerManager().SetTimer(TimerHandle_PrimaryAttack,this,&ASCharacter::PrimaryAttack_TimeElasped,0.2f);

	
}

void ASCharacter::PrimaryInteract()
{
	if (InteractionComp)
	{
		InteractionComp->PrimaryInteract();
	}	
}
//此次更改代码位置
void ASCharacter::PrimaryAttack_TimeElasped()
{
	//人物起始位置
	FVector StartPoint;
	//视角起始位置
	FVector StartPoint_Camera = CameraComp->GetComponentLocation();
	//增加的旋转
	FRotator EyeRotation;
	GetActorEyesViewPoint(StartPoint, EyeRotation);
	StartPoint = GetActorLocation();
	//终点位置
	FVector EndPoint = StartPoint_Camera+(EyeRotation.Vector()*10000.0f);
	//碰撞结果
	FHitResult HitResult;
	//配置属性
	FCollisionObjectQueryParams ObjectQueryParams;
	ObjectQueryParams.AddObjectTypesToQuery(ECC_WorldStatic);
	//判断是否有碰撞
	bool bBlockingHit = GetWorld()->LineTraceSingleByObjectType(HitResult,StartPoint_Camera,EndPoint,ObjectQueryParams);
	//旋转
	FRotator StartRotation = EyeRotation;
	//没有碰撞的话那就该怎么样就怎么样
	if (bBlockingHit)
	{
		
		DrawDebugLine(GetWorld(), StartPoint_Camera, EndPoint, FColor::Red, false, 2.0f, 0U, 1.0f);
		//终点减去起点
		StartRotation = (HitResult.ImpactPoint - StartPoint).Rotation();
		FString HitPoint = FString::Printf(TEXT("EndPoint:%s, Rotation:%s"), *HitResult.ImpactPoint.ToString(), *StartRotation.ToString());
		
		DrawDebugString(GetWorld(), HitResult.ImpactPoint, HitPoint , nullptr, FColor::Red, 2.0f, true, 1.0f);
		DrawDebugLine(GetWorld(), StartPoint, HitResult.ImpactPoint, FColor::Green, false, 2.0f, 0U, 1.0f);
	};
	//记得更改SpawnTM中的Rotation属性
	FTransform SpawnTM = FTransform(StartRotation, StartPoint);
	FActorSpawnParameters SpawnParams;
	//生成参数的碰撞覆盖处理,是尽可能不和自己有重叠呢,还是说不论三七二十一就是生成对象
	SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
	SpawnParams.Instigator = this;

	GetWorld()->SpawnActor < AActor >(ProjectileClass, SpawnTM, SpawnParams);
}

// Called every frame
void ASCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

// Called to bind functionality to input
void ASCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
	{
		//MoveAction
		EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &ASCharacter::Move);

		//JumpAction
		EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ACharacter::Jump);
		EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);

		//LookAction
		EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &ASCharacter::Look);

		//PrimaryAttack
		EnhancedInputComponent->BindAction(PrimaryAttackAction, ETriggerEvent::Triggered, this, &ASCharacter::PrimaryAttack);

		//Interaction
		EnhancedInputComponent->BindAction(InteractionAction, ETriggerEvent::Triggered, this, &ASCharacter::PrimaryInteract);
	}

}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

楚江_wog1st

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值