UEC++ 虚幻5第三人称射击游戏(一)

UEC++ 虚幻5第三人称射击游戏(一)

  • 创建一个空白的C++工程

人物角色基本移动

  • 创建一个Character类
  • 添加一些虚幻商城中的基础动画
    在这里插入图片描述
  • 给角色类添加Camera与SPringArm组件
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "SpringArm")
	class USpringArmComponent* SpringArm;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
	class UCameraComponent* Camera;

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

	SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
	SpringArm->SetupAttachment(GetRootComponent());
	SpringArm->TargetArmLength = 400.f;
	SpringArm->bUsePawnControlRotation = true;

	Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
	Camera->SetupAttachment(SpringArm);
	Camera->bUsePawnControlRotation = false;
}

角色基本移动增强输入系统MyCharacter.h

  • 角色基本移动增强输入系统
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "InputActionValue.h"
#include "MyCharacter.generated.h"

UCLASS()
class SHOOTGAME_API AMyCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AMyCharacter();

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
	class UInputMappingContext* DefaultMappingContext;
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
	class UInputAction* MoveAction;
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
	class UInputAction* LookAction;
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
	class UInputAction* CrouchAction;


	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "SpringArm")
	class USpringArmComponent* SpringArm;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
	class UCameraComponent* Camera;

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	void CharacterMove(const FInputActionValue& Value);
	void CharacterLook(const FInputActionValue& Value);
	void BeginCrouch();
	void EndCtouch();

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

};

角色基本移动增强输入系统MyCharacter.cpp

  • GetMovementComponent()->GetNavAgentPropertiesRef().bCanCrouch = true;:允许角色进行蹲伏(crouch)动作,并且能够影响导航代理(Navigation Agent)的行为
    • GetMovementComponent():获取角色的移动组件
    • GetNavAgentPropertiesRef():获取导航代理属性的引用。这些属性用于定义角色如何与导航系统交互,例如高度、半径、最大爬坡角度等。
    • .bCanCrouch = true;:设置导航代理的一个布尔属性,表示该角色可以进行蹲伏,并且在寻路过程中应当考虑其能通过更低矮的空间。这意味着在自动寻路时,引擎会考虑到角色在蹲伏状态下可以通过的高度限制区域。
  • Crouch与OnCrouch:虚幻自带的蹲伏函数
// Fill out your copyright notice in the Description page of Project Settings.


#include "MyCharacter.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "GameFramework/PawnMovementComponent.h"
#include "GameFramework/CharacterMovementComponent.h"

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

	//允许角色进行蹲伏(crouch)动作,并且能够影响导航代理(Navigation Agent)的行为
	GetMovementComponent()->GetNavAgentPropertiesRef().bCanCrouch = true;
	//自动转向
	GetCharacterMovement()->bOrientRotationToMovement = true;
	//对Character的Pawn的朝向进行硬编码
	bUseControllerRotationPitch = false;
	bUseControllerRotationYaw = false;
	bUseControllerRotationRoll = false;

	
	SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
	SpringArm->SetupAttachment(GetRootComponent());
	SpringArm->TargetArmLength = 400.f;
	SpringArm->bUsePawnControlRotation = true;

	Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
	Camera->SetupAttachment(SpringArm);
	Camera->bUsePawnControlRotation = false;
}

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

void AMyCharacter::CharacterMove(const FInputActionValue& Value)
{
	FVector2D MovementVector = Value.Get<FVector2D>();
	if (Controller)
	{
		FRotator Rotation = Controller->GetControlRotation();
		FRotator YawRotation = FRotator(0., Rotation.Yaw, 0.);
		FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);

		AddMovementInput(ForwardDirection, MovementVector.Y);
		AddMovementInput(RightDirection, MovementVector.X);

	}
}

void AMyCharacter::CharacterLook(const FInputActionValue& Value)
{
	FVector2D LookVector = Value.Get<FVector2D>();
	if (Controller)
	{
		AddControllerPitchInput(LookVector.Y);
		AddControllerYawInput(LookVector.X);
	}
}

void AMyCharacter::BeginCrouch()
{
	Crouch();
}

void AMyCharacter::EndCtouch()
{
	UnCrouch();
}

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

}

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

	UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent);
	if (EnhancedInputComponent)
	{
		EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AMyCharacter::CharacterMove);
		EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AMyCharacter::CharacterLook);

		EnhancedInputComponent->BindAction(CrouchAction, ETriggerEvent::Triggered, this, &AMyCharacter::BeginCrouch);
		EnhancedInputComponent->BindAction(CrouchAction, ETriggerEvent::Completed, this, &AMyCharacter::EndCtouch);
	}

}

创建动画蓝图与混合空间

  • 创建一个混合空间1D
    在这里插入图片描述
  • 创建一个动画蓝图,将这个混合空间链接上去
    在这里插入图片描述
    在这里插入图片描述

引入第三人称射击模型

  • 我们新建一个Character蓝图作为第三人称射击测试角色
  • 在虚幻商城里面添加我们需要的射击动画
    在这里插入图片描述
  • 打开这个内容包的动画蓝图
    在这里插入图片描述
  • 我们只需要移动所以跳跃那些都可以删除
    在这里插入图片描述
  • 然后使用这个包自己的动画蓝图与骨骼资产,它的移动全是在动画蓝图中实现的,所以角色蓝图就不用实现移动,用我们创建的角色去使用这个动画蓝图与骨骼资产,然后设置蹲伏的逻辑
    在这里插入图片描述
    在这里插入图片描述

人物动画IK绑定

  • 首先在虚幻商城下载一个自己喜欢的模型添加到项目资产里面
    在这里插入图片描述
  • 添加IK绑定
    在这里插入图片描述
  • 选择我们第三人称射击动作那个骨骼,Pelvis设置为根组件
    在这里插入图片描述
  • 然后添加骨骼链条
    在这里插入图片描述

人物动画重定向

  • 设置自己角色的IK绑定
    在这里插入图片描述
  • 创建重定向器,源是小白人
    在这里插入图片描述
    在这里插入图片描述
  • 导出重定向的动画
    在这里插入图片描述
  • 将动画蓝图给到角色蓝图
    在这里插入图片描述

创建武器类

  • 导入武器模型
  • 创建武器类
    在这里插入图片描述
    在这里插入图片描述
  • 创建武器类的蓝图添加模型上去
    在这里插入图片描述
  • 在角色蓝图中添加一个手持武器的插槽
    在这里插入图片描述
  • 在角色蓝图中,将武器附加到角色手上
    在这里插入图片描述
  • 调整好武器的位置参数
    在这里插入图片描述
  • 运行结果
    在这里插入图片描述

创建武器追踪线

  • Weapon类中创建一个开火的函数,描绘一些射击的追踪线
    在这里插入图片描述
    在这里插入图片描述

  • LineTraceSingleByChannel:使用特定的通道追踪光线并返回第一个阻塞命中TRUE(如果发现了阻塞命中)
    在这里插入图片描述

  • 逻辑源码

void AWeapon::Fire()
{
	AActor* MyOwner = GetOwner();
	if (MyOwner)
	{
		FVector EyeLocation;
		FRotator EyeRotation;
		//返回角色视角
		MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotation);
		FVector TraceEnd = EyeLocation + (EyeRotation.Vector() * 10000);

		FCollisionQueryParams QueryParams;
		QueryParams.AddIgnoredActor(MyOwner);
		QueryParams.AddIgnoredActor(this);
		QueryParams.bTraceComplex = true;

		FHitResult Hit;
		//使用特定的通道追踪光线并返回第一个阻塞命中TRUE(如果发现了阻塞命中)
		if (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, ECC_Visibility, QueryParams))
		{
			//设置受阻,造成伤害结果
		}
		DrawDebugLine(GetWorld(), EyeLocation, TraceEnd,FColor::Red,false,1.0f,0,1.0f);
	}
}

调整追踪线位置

  • 我们需要将追踪线变为我们摄像机眼睛看见的位置,我们需要重写APawn类中的GetPawnViewLocation函数
    在这里插入图片描述
    在这里插入图片描述
  • 在角色蓝图中实例化对象Weapon类,进行鼠标左键点击测试绘画的线是否是从摄像机眼睛处发出
    在这里插入图片描述
  • 运行结果
    请添加图片描述

创建伤害效果

  • 补全Fire函数中的伤害处理逻辑
  • 首先添加一个UDamageType模版变量,来存储造成伤害的类
    在这里插入图片描述
  • 补全逻辑
    在这里插入图片描述
  • Fire函数
void AWeapon::Fire()
{
	AActor* MyOwner = GetOwner();
	if (MyOwner)
	{
		FVector EyeLocation;
		FRotator EyeRotation;
		//返回角色视角
		MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotation);
		FVector TraceEnd = EyeLocation + (EyeRotation.Vector() * 10000);

		FCollisionQueryParams QueryParams;
		QueryParams.AddIgnoredActor(MyOwner);
		QueryParams.AddIgnoredActor(this);
		QueryParams.bTraceComplex = true;

		FHitResult Hit;
		FVector ShotDirection = EyeRotation.Vector();
		//使用特定的通道追踪光线并返回第一个阻塞命中TRUE(如果发现了阻塞命中)
		if (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, ECC_Visibility, QueryParams))
		{
			//设置受阻,造成伤害结果
			AActor* HitActor = Hit.GetActor();
			UGameplayStatics::ApplyPointDamage(HitActor, 10.f, ShotDirection, Hit, MyOwner->GetInstigatorController(),
				this, DamageType);

		}
		DrawDebugLine(GetWorld(), EyeLocation, TraceEnd,FColor::Red,false,1.0f,0,1.0f);
	}
}
  • 运行结果

创建射击特效

  • 导入粒子资源
  • 添加两个粒子系统,与一个附加到骨骼的变量
    在这里插入图片描述
  • 默认骨骼名
    在这里插入图片描述
  • Fire函数中添加特效与位置逻辑,一个是开火的特效粒子,一个是子弹打击到目标身上的掉血粒子
    在这里插入图片描述
  • 将特效添加到武器蓝图中
    在这里插入图片描述
  • 将武器骨骼插槽的名字改为我们设置的名字
    在这里插入图片描述
  • 微调一下摄像机方便测试
    在这里插入图片描述
  • 运行结果
    请添加图片描述

Weapon.h

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

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Weapon.generated.h"

UCLASS()
class SHOOTGAME_API AWeapon : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AWeapon();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	//武器骨骼
	UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "Components")
	class USkeletalMeshComponent* SkeletalComponent;
	//开火
	UFUNCTION(BlueprintCallable,Category = "WeaponFire")
	void Fire();

	//描述所造成的伤害的类
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Weapon")
	TSubclassOf<class UDamageType> DamageType;

	//炮口粒子系统
	UPROPERTY(EditAnywhere,BlueprintReadOnly,Category="WeaponParticle")
	class UParticleSystem* MuzzleEffect;

	//粒子附加到骨骼的名字
	UPROPERTY(EditAnywhere,BlueprintReadOnly,Category="WeaponParticle")
	FName MuzzleSocketName;

	//撞击到敌人身上的粒子系统
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "WeaponParticle")
	UParticleSystem* ImpactEffect;
public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

};

Weapon.cpp

// Fill out your copyright notice in the Description page of Project Settings.
#include "Weapon.h"
#include <Kismet/GameplayStatics.h>
#include "Particles/ParticleSystem.h"
// Sets default values
AWeapon::AWeapon()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
	SkeletalComponent = CreateAbstractDefaultSubobject<USkeletalMeshComponent>(TEXT("SkeletalComponent"));
	SkeletalComponent->SetupAttachment(GetRootComponent());

	MuzzleSocketName = "MuzzleSocket";
}

// Called when the game starts or when spawned
void AWeapon::BeginPlay()
{
	Super::BeginPlay();
	
}

void AWeapon::Fire()
{
	AActor* MyOwner = GetOwner();
	if (MyOwner)
	{
		FVector EyeLocation;
		FRotator EyeRotation;
		//返回角色视角
		MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotation);
		FVector TraceEnd = EyeLocation + (EyeRotation.Vector() * 10000);

		FCollisionQueryParams QueryParams;
		QueryParams.AddIgnoredActor(MyOwner);
		QueryParams.AddIgnoredActor(this);
		QueryParams.bTraceComplex = true;

		FHitResult Hit;
		FVector ShotDirection = EyeRotation.Vector();
		//使用特定的通道追踪光线并返回第一个阻塞命中TRUE(如果发现了阻塞命中)
		if (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, ECC_Visibility, QueryParams))
		{
			//设置受阻,造成伤害结果
			AActor* HitActor = Hit.GetActor();
			UGameplayStatics::ApplyPointDamage(HitActor, 10.f, ShotDirection, Hit, MyOwner->GetInstigatorController(),
				this, DamageType);

			//粒子生成的位置
			UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ImpactEffect, Hit.ImpactPoint,
				Hit.ImpactNormal.Rotation());
		}
		DrawDebugLine(GetWorld(), EyeLocation, TraceEnd,FColor::Red,false,1.0f,0,1.0f);
		
		if (MuzzleEffect)
		{
			//附加粒子效果
			UGameplayStatics::SpawnEmitterAttached(MuzzleEffect,SkeletalComponent,MuzzleSocketName);
		}

	}
}

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

}

创建十字准心

  • 创建一个控件蓝图作为十字准心的窗口
    在这里插入图片描述
  • 在角色蓝图的BeginPlay中添加这个视口到窗口中
    在这里插入图片描述
  • 运行结果
    在这里插入图片描述

MyCharacter.h

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "InputActionValue.h"
#include "MyCharacter.generated.h"

UCLASS()
class SHOOTGAME_API AMyCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AMyCharacter();

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
	class UInputMappingContext* DefaultMappingContext;
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
	class UInputAction* MoveAction;
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
	class UInputAction* LookAction;
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
	class UInputAction* CrouchAction;


	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "SpringArm")
	class USpringArmComponent* SpringArm;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
	class UCameraComponent* Camera;

	//UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Animation", meta = (AllowPrivateAccess = "true"))
	//class UAnimInstance* MyAnimInstance; // 或者使用 TSubclassOf<UAnimInstance> 作为类型指向动画蓝图类

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;


	void CharacterMove(const FInputActionValue& Value);
	void CharacterLook(const FInputActionValue& Value);
	void BeginCrouch();
	void EndCtouch();

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

	//重写GetPawnViewLocation函数将其返回摄像机的眼睛看见的位置
	virtual FVector GetPawnViewLocation() const override;
};

MyCharacter.cpp

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


#include "MyCharacter.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "GameFramework/PawnMovementComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Engine/Engine.h"

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

	//允许角色进行蹲伏(crouch)动作,并且能够影响导航代理(Navigation Agent)的行为
	GetMovementComponent()->GetNavAgentPropertiesRef().bCanCrouch = true;
	//自动转向
	GetCharacterMovement()->bOrientRotationToMovement = true;
	//对Character的Pawn的朝向进行硬编码
	bUseControllerRotationPitch = false;
	bUseControllerRotationYaw = false;
	bUseControllerRotationRoll = false;

	
	SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
	SpringArm->SetupAttachment(GetRootComponent());
	SpringArm->TargetArmLength = 400.f;
	SpringArm->bUsePawnControlRotation = true;

	Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
	Camera->SetupAttachment(SpringArm);
	Camera->bUsePawnControlRotation = false;
}

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

void AMyCharacter::CharacterMove(const FInputActionValue& Value)
{
	FVector2D MovementVector = Value.Get<FVector2D>();
	if (Controller)
	{
		FRotator Rotation = Controller->GetControlRotation();
		FRotator YawRotation = FRotator(0., Rotation.Yaw, 0.);
		FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);

		AddMovementInput(ForwardDirection, MovementVector.Y);
		AddMovementInput(RightDirection, MovementVector.X);

	}
}

void AMyCharacter::CharacterLook(const FInputActionValue& Value)
{
	FVector2D LookVector = Value.Get<FVector2D>();
	if (Controller)
	{
		AddControllerPitchInput(LookVector.Y);
		AddControllerYawInput(LookVector.X);
	}
}

void AMyCharacter::BeginCrouch()
{
	//bIsCrouched = true;
	//Crouch();
	//FString MessageString;
	//MessageString.AppendInt((TEXT("bIsCrouched is111, %s"), bIsCrouched));
	//GEngine->AddOnScreenDebugMessage(0, 10.f, FColor::Red, MessageString);
	GEngine->AddOnScreenDebugMessage(0, 10.f, FColor::Red, FString::Printf(bIsCrouched));
}

void AMyCharacter::EndCtouch()
{
	//bIsCrouched = false;
	//UnCrouch();
	//FString MessageString;
	//MessageString.AppendInt((TEXT("bIsCrouched is222, %s"), bIsCrouched));
	//GEngine->AddOnScreenDebugMessage(0, 10.f, FColor::Red, MessageString);
}

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

}

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

	UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent);
	if (EnhancedInputComponent)
	{
		EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AMyCharacter::CharacterMove);
		EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AMyCharacter::CharacterLook);

		EnhancedInputComponent->BindAction(CrouchAction, ETriggerEvent::Triggered, this, &AMyCharacter::BeginCrouch);
		EnhancedInputComponent->BindAction(CrouchAction, ETriggerEvent::Completed, this, &AMyCharacter::EndCtouch);
	}

}

FVector AMyCharacter::GetPawnViewLocation() const
{
	if (Camera)
	{
		//返回摄像机眼睛的位置
		return Camera->GetComponentLocation();
	}
	return Super::GetPawnViewLocation();
}

Weapon.h

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Weapon.generated.h"

UCLASS()
class SHOOTGAME_API AWeapon : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AWeapon();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	//武器骨骼
	UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "Components")
	class USkeletalMeshComponent* SkeletalComponent;
	//开火
	UFUNCTION(BlueprintCallable,Category = "WeaponFire")
	void Fire();

	//描述所造成的伤害的类
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Weapon")
	TSubclassOf<class UDamageType> DamageType;

	//炮口粒子系统
	UPROPERTY(EditAnywhere,BlueprintReadOnly,Category="WeaponParticle")
	class UParticleSystem* MuzzleEffect;

	//粒子附加到骨骼的名字
	UPROPERTY(EditAnywhere,BlueprintReadOnly,Category="WeaponParticle")
	FName MuzzleSocketName;

	//撞击到敌人身上的粒子系统
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "WeaponParticle")
	UParticleSystem* ImpactEffect;
public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

};

Weapon.cpp

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


#include "Weapon.h"
#include <Kismet/GameplayStatics.h>
#include "Particles/ParticleSystem.h"
// Sets default values
AWeapon::AWeapon()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
	SkeletalComponent = CreateAbstractDefaultSubobject<USkeletalMeshComponent>(TEXT("SkeletalComponent"));
	SkeletalComponent->SetupAttachment(GetRootComponent());

	MuzzleSocketName = "MuzzleSocket";
}

// Called when the game starts or when spawned
void AWeapon::BeginPlay()
{
	Super::BeginPlay();
	
}

void AWeapon::Fire()
{
	AActor* MyOwner = GetOwner();
	if (MyOwner)
	{
		FVector EyeLocation;
		FRotator EyeRotation;
		//返回角色视角
		MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotation);
		FVector TraceEnd = EyeLocation + (EyeRotation.Vector() * 10000);

		FCollisionQueryParams QueryParams;
		QueryParams.AddIgnoredActor(MyOwner);
		QueryParams.AddIgnoredActor(this);
		QueryParams.bTraceComplex = true;

		FHitResult Hit;
		FVector ShotDirection = EyeRotation.Vector();
		//使用特定的通道追踪光线并返回第一个阻塞命中TRUE(如果发现了阻塞命中)
		if (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, ECC_Visibility, QueryParams))
		{
			//设置受阻,造成伤害结果
			AActor* HitActor = Hit.GetActor();
			UGameplayStatics::ApplyPointDamage(HitActor, 10.f, ShotDirection, Hit, MyOwner->GetInstigatorController(),
				this, DamageType);

			//粒子生成的位置
			UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ImpactEffect, Hit.ImpactPoint,
				Hit.ImpactNormal.Rotation());
		}
		DrawDebugLine(GetWorld(), EyeLocation, TraceEnd,FColor::White,false,1.0f,0,1.0f);
		
		if (MuzzleEffect)
		{
			//附加粒子效果
			UGameplayStatics::SpawnEmitterAttached(MuzzleEffect,SkeletalComponent,MuzzleSocketName);
		}

	}
}

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

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/735906.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

设计软件有哪些?贴图插件篇(1),渲染100邀请码1a12

设计师经常要处理贴图&#xff0c;这里介绍一些贴图所用到的插件。 1、Substance 3D Painter Substance 3D Painter是Substance 3D软件套件中的一部分&#xff0c;是一款专业的纹理绘制软件。它提供了直观的界面和强大的工具&#xff0c;用于在3D模型上进行高质量的纹理绘制和…

Docker常用命令与实战示例

docker 1. 安装2. 常用命令3. 存储4. 网络5. redis主从复制示例6. wordpress示例7. DockerFile8. 一键安装超多中间件&#xff08;compose&#xff09; 1. 安装 以centOS系统为例 # 移除旧版本docker sudo yum remove docker \docker-client \docker-client-latest \docker-c…

第14章. GPIO简介

目录 0. 《STM32单片机自学教程》专栏 14.1 GPIO基本结构 14.1.1 保护二极管 14.1.2 上拉、下拉电阻 14.1.3 施密特触发器 14.1.4 P-MOS 管和 N-MOS 管 14.1.5 输出数据寄存器 14.1.6 输入数据寄存器 14.2 GPIO工作模式 14.2.1 输入模式 14.2.1.1 输入浮空模式 1…

ubuntu 18.04 server源码编译安装freeswitch 1.10.7支持音视频通话、收发短信——筑梦之路

软件版本说明 ubuntu版本18.04&#xff1a;https://releases.ubuntu.com/18.04.6/ubuntu-18.04.6-live-server-amd64.iso freeswitch 版本1.10.7&#xff1a;https://files.freeswitch.org/freeswitch-releases/freeswitch-1.10.7.-release.tar.gz spandsp包&#xff1a;https:…

【电路笔记】-共发射极放大器

共发射极放大器 文章目录 共发射极放大器1、概述2、完整的CEA配置3、直流等效电路4、交流等效电路5、输入阻抗6、输出阻抗7、电压增益8、微分电容的重要性9、信号源的衰减10、电流增益11、相位反转12、总结1、概述 在本文中,我们将介绍基于双极晶体管的放大器的最后一种拓扑:…

51-52Windows密码安全性测试与Windows提权

目录 Windows密码安全性测试 一、本地管理员密码如何直接提取 1、直接通过mimikatz读取管理员密码 2、使用laZagne工具读取管理员密码 二、利用Hash远程登录系统 window提权 三、远程webshell执行命令解决 不能执行原因&#xff1a; 解决方法&#xff1a;单独上传cmd.e…

Leetcode84 柱状图中最大的矩形

题目描述 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积 解题思路 思路一&#xff1a;暴力寻找&#xff0c;从每个位置出发&#xff0c;向左右两边扩…

Android View点击事件分发原理,源码解读

View点击事件分发原理&#xff0c;源码解读 前言1. 原理总结2.1 时序图总结2.2 流程图总结 2. 源码解读2.1 Activity到ViewGroup2.2 ViewGroup事件中断逆序搜索自己处理点击事件ViewGroup总结 2.3 ViewOnTouchListeneronTouchEvent 3. 附录&#xff1a;时序图uml代码 前言 两年…

Windows Api如何创建一个快捷方式并且在开始菜单搜索到自己的应用

原文链接&#xff1a;http://cshelloworld.com/home/detail/1804473083243925504 当我们点击win10系统搜索框的时候&#xff0c;输入名称 &#xff0c;win10会帮助我们匹配到对应的应用。这里搜索框实际上就是windows系统的开始菜单。 接下来我们随便找一个应用&#xff0c;右…

Adobe XD最新2023资源百度云盘下载(附教程)

如大家所了解的&#xff0c;Adobe XD是一种基于矢量的UI和UX设计工具&#xff0c;可用于设计从智能手表应用程序到成熟网站的任何内容&#xff0c;功能非常强大且操作便捷。目前最新已推出2023版本。 Adobe XD解决了Photoshop和其他图形应用程序无法解决的两个主要问题&#xf…

LSSS算法实现,基于eigen和pbc密码库【一文搞懂LSSS,原理+代码】

文章目录 一. LSSS简介1.1 概述1.2 线性秘密分享方案&#xff08;LSSS&#xff09;与 Shamir的秘密分享方案对比LSSS1.2.1 Shamir的秘密分享方案1.2.2 线性秘密分享方案&#xff08;LSSS&#xff09;1.2.3 主要区别 二. 基于矩阵的LSSS加解密原理分析2.1 LSSS矩阵构造2.1.1 定义…

Bytebase 对接本地部署的 llama3 开启ChatSQL功能

Bytebase 是为开发人员、测试、DBA和运维工程师构建的数据库 DevOps 领域的&#xff0c;类 GitLab/GitHub 平台。 这篇文章主要关注 Bytebase SQL 编辑器中的 AI 增强功能。使用此功能您可以使用自然语言在 Bytebase SQL 编辑器中查询数据库。同时还能给出针对查询的索引建议&…

WSL+Anconda(pytorch深度学习)环境配置

动机 最近在读point cloud相关论文&#xff0c;准备拉github上相应的code跑一下&#xff0c;但是之前没有深度学习的经验&#xff0c;在配置环境方面踩了超级多的坑&#xff0c;依次来记录一下。 一开始我直接将code拉到了windows本地来运行&#xff0c;遇到了数不清的问题&a…

骑马与砍杀-战团mod制作-基础篇-武器模型入骑砍(二)

骑马与砍杀战团mod制作-基础-武器模型入骑砍笔记&#xff08;二&#xff09; 资料来源 学习的资料来源&#xff1a; b站【三啸解说】手把手教你做【骑砍】MOD&#xff0c;基础篇&#xff0c;链接为&#xff1a; https://www.bilibili.com/video/BV19x411Q7No?p4&vd_sour…

【Python】已解决:安装python-Levenshtein包时遇到的subprocess-exited-with-error问题

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例及解决方案五、注意事项 已解决&#xff1a;安装python-Levenshtein包时遇到的subprocess-exited-with-error问题 一、分析问题背景 在安装python-Levenshtein这个Python包时&#xff0c;有时会…

Applied Spatial Statistics(七):Python 中的空间回归

Applied Spatial Statistics&#xff08;七&#xff09;&#xff1a;Python 中的空间回归 本笔记本演示了如何使用 pysal 的 spreg 库拟合空间滞后模型和空间误差模型。 OLS空间误差模型空间滞后模型三种模型的比较探索滞后模型中的直接和间接影响 import numpy as np impor…

【人工智能】—XGBoost算法在构建互联网防火墙异常行为识别模型应用案例

摘要&#xff1a; 近年来&#xff0c;各地党委、政府加快推进新型工业化&#xff0c;部署实施制造强市战略&#xff0c;提出工业企业“智改数转”是推动全市工业经济稳增长的重要引擎&#xff0c;更是稳增长、促发展的重要抓手。今天博主就以互联网防火墙异常行为识别为例给大家…

js实现canvas截图功能

关键代码 使用canvas的导出功能和drawImage函数 class CropShape{cropShape(shape){let {x,y,w,h} shapeconsole.log(x,y,w,h)const roiCanvas document.createElement(canvas);document.getElementById(app).append(roiCanvas)const roiCtx roiCanvas.getContext(2d);roi…

CTO的职责是什么?

看《架构思维》作者是这样讲的&#xff1a; CTO 到底是做什么的&#xff1f; 我当下的答案是&#xff1a;“CTO 就是一个从技术视角出发&#xff0c;为公司或者所在的部门做正确决策的 CEO。”怎么理解这句话呢&#xff1f;作为一个 CTO&#xff0c;其长期目标和决策优先级与…

vscode用vue框架2,续写登陆页面逻辑,以及首页框架的搭建

目录 前言&#xff1a; 一、实现登录页信息验证逻辑 1.实现登录数据双向绑定 2.验证用户输入数据是否和默认数据相同 补充知识1&#xff1a; 知识点补充2&#xff1a; 二、首页和登录页之间的逻辑(1) 1. 修改路由&#xff0c;使得程序被访问先访问首页 知识点补充3&am…