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

2024-06-23 16:52

本文主要是介绍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 propertiesAMyCharacter();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 spawnedvirtual void BeginPlay() override;void CharacterMove(const FInputActionValue& Value);void CharacterLook(const FInputActionValue& Value);void BeginCrouch();void EndCtouch();public:	// Called every framevirtual void Tick(float DeltaTime) override;// Called to bind functionality to inputvirtual 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 propertiesAWeapon();protected:// Called when the game starts or when spawnedvirtual 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 framevirtual 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 propertiesAMyCharacter();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 spawnedvirtual void BeginPlay() override;void CharacterMove(const FInputActionValue& Value);void CharacterLook(const FInputActionValue& Value);void BeginCrouch();void EndCtouch();public:	// Called every framevirtual void Tick(float DeltaTime) override;// Called to bind functionality to inputvirtual 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 propertiesAWeapon();protected:// Called when the game starts or when spawnedvirtual 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 framevirtual 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);}

这篇关于UEC++ 虚幻5第三人称射击游戏(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1087730

相关文章

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c

C++归并排序代码实现示例代码

《C++归并排序代码实现示例代码》归并排序将待排序数组分成两个子数组,分别对这两个子数组进行排序,然后将排序好的子数组合并,得到排序后的数组,:本文主要介绍C++归并排序代码实现的相关资料,需要的... 目录1 算法核心思想2 代码实现3 算法时间复杂度1 算法核心思想归并排序是一种高效的排序方式,需要用

Python38个游戏开发库整理汇总

《Python38个游戏开发库整理汇总》文章介绍了多种Python游戏开发库,涵盖2D/3D游戏开发、多人游戏框架及视觉小说引擎,适合不同需求的开发者入门,强调跨平台支持与易用性,并鼓励读者交流反馈以... 目录PyGameCocos2dPySoyPyOgrepygletPanda3DBlenderFife

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

游戏闪退弹窗提示找不到storm.dll文件怎么办? Stormdll文件损坏修复技巧

《游戏闪退弹窗提示找不到storm.dll文件怎么办?Stormdll文件损坏修复技巧》DLL文件丢失或损坏会导致软件无法正常运行,例如我们在电脑上运行软件或游戏时会得到以下提示:storm.dll... 很多玩家在打开游戏时,突然弹出“找不到storm.dll文件”的提示框,随后游戏直接闪退,这通常是由于