UE5学习笔记22-武器瞄准和武器自动开火

0、一些疑问的记录

        1.UUserWidget类和AHUD类的区别。两者都是关于界面显示的类。

       实践:

        想让界面和用户有交互使用UUserWidget,如果不要交互只是显示使用AHUD类,例如使用UUserWidget类制作开始界面,游戏开始,游戏设置,自作人员等,使用AHUD类显示准心,角色血量,武器图标等。

        理论:

  • 绘制方式

    • AHUD:通过Canvas直接在屏幕上绘制2D元素(代码驱动)。
    • UUserWidget:通过UMG系统创建基于Widget的UI,支持拖拽式设计、复杂的布局和交互。
  • 适用场景

    • AHUD:适合需要低级别控制的简单HUD,如准星、生命值、计时器等。
    • UUserWidget:适合复杂的、交互式的UI,如菜单、装备栏、对话框、设置界面等。
  • 复杂度

    • AHUD:简单的绘制系统,但对复杂UI需求不太友好。
    • UUserWidget:高度可定制和交互式,适合更复杂和丰富的用户体验。

        2.UTexture和UTexture2D和UTexture3D的区别和何时使用

        实践:

  1. UTexture2D 使用场景

    • 材质贴图:如常规的模型纹理(Albedo、Normal、Metallic等)。
    • UI图像:如按钮、背景、图标等二维界面元素。
    • 常规图像数据:如2D背景图片、纹理集等。
  2. UTexture3D 使用场景

    • 体积效果:如烟雾、云朵、火焰等,需要体积数据的效果。
    • 体积存储:如3D噪声、光照体积等。
    • 特殊材质:一些高级渲染技术和效果(如3D映射、Voxel-based渲染)。
  3. UTexture

    • 通用纹理基类:通常不会直接使用,而是作为基类为具体的纹理类型提供基础功能。

         理论:

        UTexture是纹理的基类不能直接使用

        UTexture2D表示一个二维纹理(图像)用于给模型、材质和界面元素等应用图像数据,支持多级纹理细化(Mipmaps)、压缩格式(如DXT、BC5等),可用于渲染优化

        UTexture3D表示三维纹理(体积纹理),用于存储和处理三维的纹理数据,每个数据点(Texel)不仅有二维的xy,还包括z方向的深度值

        3.FTransform:

        包含了物体的位置旋转和缩放

FTransform MyTransform;
// 设置位置 MyTransform.SetTranslation(FVector(100.0f, 200.0f, 300.0f));
// 设置旋转 MyTransform.SetRotation(FQuat(FRotator(45.0f, 0.0f, 0.0f)));
// 设置缩放 MyTransform.SetScale3D(FVector(2.0f, 2.0f, 2.0f));
// 获取位置 FVector Position = MyTransform.GetTranslation();
// 获取旋转 FRotator Rotation = MyTransform.GetRotation().Rotator();
// 获取缩放 FVector Scale = MyTransform.GetScale3D();

        4. 具有调试作用的函数

        4.1DrawDebugLine画一条线

void UKismetSystemLibrary::DrawDebugLine(const UObject* WorldContextObject,    //当前世界FVector LineStart,                    //其实位置FVector LineEnd,                      //终点位置FLinearColor LineColor = FLinearColor(1.f, 0.f, 0.f, 1.f), //颜色float Duration = 0.f,                 //持续时间float Thickness = 0.f                 //粗细
);

        5.FindLookAtRotation函数返回的旋转默认返回X轴方向的旋转

一、完成了哪些

        完成武器自动开火,武器瞄准是在界面会有准心显示,跳跃射击等动作时准心改变大小,给角色添加被击中时的动画,将角色网格体胶囊被击改成角

色模型被击,

二、准心

        1.需要通过获得当前角色控制器(PlayerController)通过类APlayController::GetHUD()函数获得当前客户端的界面,函数返回一个类AHUD类的指针,定义一个类继承自AHUD类将返回的指针转到子类类型,通过DrwaHUD()函数和DrawTexture()函数绘制准心

        角色控制器可以通过角色类指针调用Controller获得,获得的是一个AController类,定义类继承APlayerController,类APlayerController继承自AController。类APlayController和AHUD是UE5中已经存在的类。

        2.创建新的C++类分别继承自APlayController和AHUD。将玩家控制器类命名为BlasterPlayerController界面类命名为ABasterHUD(并定义对应蓝图类)

         3.类AABasterHUD代码

中间有个点 

        头文件

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "ABasterHUD.generated.h"//如上图一共五个资产文件 所以结构体中有五个UTexture2D指针USTRUCT(BlueprintType)
struct FHUDPackage
{GENERATED_BODY()
public:class UTexture2D* CrosshairsCenter;UTexture2D* CrosshairsLeft;UTexture2D* CrosshairsRight;UTexture2D* CrosshairsTop;UTexture2D* CrosshairsBottom;float CrosshairSpreed;//当人物奔跑跳跃时,准心大小改变FLinearColor CrosshairsColor;
};/*** */
UCLASS()
class BLASTER_API AABasterHUD : public AHUD
{GENERATED_BODY()public:/* 该函数会在每一帧被调用 */virtual void DrawHUD() override;private:FHUDPackage HUDPackage;//绘画准心void DrawCrosshair(UTexture2D* Texture , FVector2D ViewPointCenter , FVector2D Spreed , FLinearColor CrosshairsColor);UPROPERTY(EditAnywhere)float CrosshairSpreadMax = 16.f; //准心扩展或缩小的速度
public:FORCEINLINE void SetHUDPackage(const FHUDPackage& Package) { HUDPackage = Package; }
};

        源文件

// Fill out your copyright notice in the Description page of Project Settings.#include "ABasterHUD.h"void AABasterHUD::DrawHUD()
{Super::DrawHUD();FVector2D ViewportSize;if (GEngine){/* 获得视口大小 */GEngine->GameViewport->GetViewportSize(ViewportSize);const FVector2D ViewportCenter(ViewportSize.X / 2.0, ViewportSize.Y / 2.0);float SpreadScaled =  CrosshairSpreadMax* HUDPackage.CrosshairSpreed;if (HUDPackage.CrosshairsCenter){FVector2D Spreed(0.f, 0.f);DrawCrosshair(HUDPackage.CrosshairsCenter, ViewportCenter, Spreed, HUDPackage.CrosshairsColor);}if (HUDPackage.CrosshairsLeft){FVector2D Spreed(-SpreadScaled, 0.f);DrawCrosshair(HUDPackage.CrosshairsLeft, ViewportCenter , Spreed, HUDPackage.CrosshairsColor);}if (HUDPackage.CrosshairsRight){FVector2D Spreed(SpreadScaled, 0.f);DrawCrosshair(HUDPackage.CrosshairsRight, ViewportCenter , Spreed, HUDPackage.CrosshairsColor);}if (HUDPackage.CrosshairsTop){FVector2D Spreed(0.f , -SpreadScaled);DrawCrosshair(HUDPackage.CrosshairsTop, ViewportCenter , Spreed, HUDPackage.CrosshairsColor);}if (HUDPackage.CrosshairsBottom){FVector2D Spreed(0.f, SpreadScaled);DrawCrosshair(HUDPackage.CrosshairsBottom, ViewportCenter , Spreed, HUDPackage.CrosshairsColor);}}
}void AABasterHUD::DrawCrosshair(UTexture2D* Texture, FVector2D ViewPointCenter , FVector2D Spreed , FLinearColor CrosshairsColor)
{const float TextureWidth = Texture->GetSizeX();const float TextureHigh = Texture->GetSizeY();const FVector2D TexturePoint(ViewPointCenter.X - (TextureWidth / 2.0) + Spreed.X,ViewPointCenter.Y - (TextureHigh / 2.0) + Spreed.Y);/**void DrawTexture(UTexture* Texture,              // 1. 纹理对象float ScreenX,                  // 2. 屏幕上绘制位置的 X 坐标float ScreenY,                  // 3. 屏幕上绘制位置的 Y 坐标float ScreenW,                  // 4. 纹理的宽度(缩放后的)float ScreenH,                  // 5. 纹理的高度(缩放后的)float CoordinateX = 0.f,        // 6. 纹理UV坐标的X起始点float CoordinateY = 0.f,        // 7. 纹理UV坐标的Y起始点float CoordinateW = 1.f,        // 8. 纹理UV的宽度float CoordinateH = 1.f,        // 9. 纹理UV的高度FLinearColor TintColor = FLinearColor::White,  // 10. 颜色渲染/染色 (可以用来控制透明度)EBlendMode BlendMode = SE_BLEND_Translucent,   // 11. 混合模式 (用于控制如何混合纹理与背景)float Scale = 1.f,              // 12. 缩放比例bool bScalePosition = false,    // 13. 是否同时缩放位置float Rotation = 0.f,           // 14. 纹理旋转角度FVector2D RotPivot = FVector2D(0.5f, 0.5f)     // 15. 旋转中心点 (以纹理为中心默认旋转));*/DrawTexture(Texture,TexturePoint.X,TexturePoint.Y,TextureWidth,TextureHigh,0.f,0.f,1.f,1.f,CrosshairsColor);
}

         4.不同的武器可能会有不同的准心,所以在武器类中定义(Weapon.h)

	UPROPERTY(EditAnywhere, Category = Crosshairs)class UTexture2D* CrosshairsCenter; //静态纹理类UPROPERTY(EditAnywhere, Category = Crosshairs)class UTexture2D* CrosshairsLeft; //静态纹理类UPROPERTY(EditAnywhere, Category = Crosshairs)class UTexture2D* CrosshairsRight; //静态纹理类UPROPERTY(EditAnywhere, Category = Crosshairs)class UTexture2D* CrosshairsTop; //静态纹理类UPROPERTY(EditAnywhere, Category = Crosshairs)class UTexture2D* CrosshairsBottom; //静态纹理类

        5.编译后,打开对应的武器的蓝图,设置如下 

        6.纹理资产设置,想让纹理显示在界面上,所以是一个2D类型的纹理需要确保纹理是2D类型

         7.在游戏模式蓝图中设置对应属性(BP_xxx都是自己定义的蓝图类)

        8. 设置准心纹理

        头文件

        在战斗组件类中定义(准心会放大缩小,所以需要使用插值,函数会有时间参数(DeltaTime))

/* 准心 */
void SetHUDCrosshairs(float DeltaTime); //每帧调用
/* 准心 *//**
* HUD and Crosshairs
*/float CrosshairVelocityFactor; //行走速度
float CrosshairInAirFactor;    //是否在空中,跳跃
float CrosshairAimFactor;      //瞄准
float CrosshairShootingFactor; //蹲下
FHUDPackage HUDPackage;class ABlasterPlayerController* Controller; //可以通过这个类去获得HUD
class AABasterHUD* HUD;

         源文件

void UCombatComponent::SetHUDCrosshairs(float DeltaTime)
{if (Character == nullptr || Character->Controller == nullptr) return;Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;if (Controller){HUD = HUD == nullptr ? Cast<AABasterHUD>(Controller->GetHUD()) : HUD;if (HUD){if (EquippedWeapon){HUDPackage.CrosshairsCenter = EquippedWeapon->CrosshairsCenter;HUDPackage.CrosshairsLeft = EquippedWeapon->CrosshairsLeft;HUDPackage.CrosshairsRight = EquippedWeapon->CrosshairsRight;HUDPackage.CrosshairsBottom = EquippedWeapon->CrosshairsBottom;HUDPackage.CrosshairsTop = EquippedWeapon->CrosshairsTop;}else{HUDPackage.CrosshairsCenter = nullptr;HUDPackage.CrosshairsLeft = nullptr;HUDPackage.CrosshairsRight = nullptr;HUDPackage.CrosshairsBottom = nullptr;HUDPackage.CrosshairsTop = nullptr;}// 计算准心扩展/缩小// [0 , 600] -> [0 , 1]FVector2D WalkSpeedRange(0.f, Character->GetCharacterMovement()->MaxWalkSpeed);FVector2D VeclocityMultiplierRange(0.f, 1.f);FVector Velocity = Character->GetVelocity();Velocity.Z = 0.f;/*float GetMappedRangeValueClamped(const TInterval<float>&InputRange,  // 输入范围const TInterval<float>&OutputRange, // 输出范围float Value                          // 输入的数值);*//* 函数返回的值是Velocity.Size()在映射中的值 */CrosshairVelocityFactor = FMath::GetMappedRangeValueClamped(WalkSpeedRange, VeclocityMultiplierRange, Velocity.Size());if (Character->GetCharacterMovement()->IsFalling()){CrosshairInAirFactor = FMath::FInterpTo(CrosshairInAirFactor, 2.25f, DeltaTime, 2.25f);}else{CrosshairInAirFactor = FMath::FInterpTo(CrosshairInAirFactor, 0.f, DeltaTime, 30.f);}if (bAiming){CrosshairAimFactor = FMath::FInterpTo(CrosshairAimFactor, 0.58f, DeltaTime, 30.f);}else{CrosshairAimFactor = FMath::FInterpTo(CrosshairAimFactor, 0.f, DeltaTime, 30.f);}CrosshairShootingFactor = FMath::FInterpTo(CrosshairShootingFactor, 0.f, DeltaTime, 40.f);HUDPackage.CrosshairSpreed =0.5f +CrosshairVelocityFactor +CrosshairInAirFactor -CrosshairAimFactor +CrosshairShootingFactor;HUD->SetHUDPackage(HUDPackage);}}
}void UCombatComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{Super::TickComponent(DeltaTime, TickType, ThisTickFunction);SetHUDCrosshairs(DeltaTime);
}

        9.将武器发射子弹的方向和瞄准方向保证统一,并且只想在本地客户端上让右手骨骼和目标在同一个方向。

        9.1在角色动画类中定义右手的旋转,让右手旋转到瞄准的目标的方向,代码如下

        头文件

UPROPERTY(BlueprintReadOnly, Category = Character, meta = (AllowPrivateAccess = "true"))/** 蓝图只读 类型是Character 允许私有访问 */
FRotator RightHandRotation;UPROPERTY(BlueprintReadOnly, Category = Character, meta = (AllowPrivateAccess = "true"))/** 蓝图只读 类型是Character 允许私有访问 */
bool bLocallyControlled;

        源文件 , 注释是测试代码,第一个if判断当前是否有武器,武器指针存在,武器网格体存在,角色网格体存在,第二个if判断当前角色是否是本地控制(是否是当前客户端),不想在代理商显示

void UBlasterAnimInstance::NativeUpdateAnimation(float DeltaTime)
{Super::NativeUpdateAnimation(DeltaTime);if (bWeaponEquipped && EquippedWeapon && EquippedWeapon->GetWeaponMesh() && BlasterCharacter->GetMesh()){if (BlasterCharacter->IsLocallyControlled()){bLocallyControlled = true;FTransform RightHandTransform = EquippedWeapon->GetWeaponMesh()->GetSocketTransform(FName("Hand_R"), ERelativeTransformSpace::RTS_World);//让当前对象从当前位置朝向目标位置所需的旋转//FindLookAtRotation函数返回的旋转默认返回X轴方向的旋转FRotator LookAtRotation = UKismetMathLibrary::FindLookAtRotation(RightHandTransform.GetLocation(), RightHandTransform.GetLocation() + (RightHandTransform.GetLocation() - BlasterCharacter->GetHitTarget()));RightHandRotation = FMath::RInterpTo(RightHandRotation, LookAtRotation, DeltaTime, 30.f);//RightHandRotation = UKismetMathLibrary::FindLookAtRotation(RightHandTransform.GetLocation(), RightHandTransform.GetLocation() + (RightHandTransform.GetLocation() - BlasterCharacter->GetHitTarget()));}//FTransform MuzzleTipTransform = EquippedWeapon->GetWeaponMesh()->GetSocketTransform(FName("MuzzleFlash"), ERelativeTransformSpace::RTS_World);//FVector MuzzleX(FRotationMatrix(MuzzleTipTransform.GetRotation().Rotator()).GetUnitAxis(EAxis::X));//DrawDebugLine(GetWorld(), MuzzleTipTransform.GetLocation(), MuzzleTipTransform.GetLocation() + MuzzleX * 1000.f, FColor::Red);////DrawDebugLine(GetWorld(), MuzzleTipTransform.GetLocation(), BlasterCharacter->GetHitTarget(), FColor::Black);}
}

        动画蓝图

        将平移(Transform),缩放(Scale) ,透明度(Alpha)去掉不显示(可以根据自己需要)

        将动画/UseCachePoses节点直接连接到该节点上会有如图的效果,中间会自动生成一个节点,另一边的连线连接到正确的位置同样也有一个节点

         最后整体流程

        10. 装备武器时的视场角的缩放

        角色类偷头文件定义 (获得相机组件类指针的函数)

FORCEINLINE UCameraComponent* GetFollowCamera() const { return FollowCamera; };

        武器类头文件定义

	/***	瞄准时武器需要放大多少倍*/UPROPERTY(EditAnywhere)float ZoomedFOV = 30.f; //视场角的缩放UPROPERTY(EditAnywhere)float ZoomInterpSpeed = 20.f; // 缩放的速度

        战斗组件类中头文件

	/***	瞄准的视场角*//* 默认的视场角 没有瞄准 */float DefaultFOV;UPROPERTY(EditAnywhere, Category = Combat)float ZommedFOV = 30.f;float CurrentFOV;UPROPERTY(EditAnywhere, Category = Combat)float ZoomInterpSpeed = 20.f; // 缩放的速度void InterpFOV(float DeltaTime);FORCEINLINE float GetZoomedFOV() const { return ZoomedFOV; };
FORCEINLINE float GetZoomInterpSpeed() const { return ZoomInterpSpeed; };

        战斗组件类中源文件

void UCombatComponent::InterpFOV(float DeltaTime)
{if (EquippedWeapon == nullptr) return;if (bAiming){CurrentFOV = FMath::FInterpTo(CurrentFOV, EquippedWeapon->GetZoomedFOV(), DeltaTime, EquippedWeapon->GetZoomInterpSpeed());}else{CurrentFOV = FMath::FInterpTo(CurrentFOV, DefaultFOV, DeltaTime, ZoomInterpSpeed);}if (Character && Character->GetFollowCamera()){Character->GetFollowCamera()->SetFieldOfView(CurrentFOV);}
}void UCombatComponent::BeginPlay()
{Super::BeginPlay();if (Character){Character->GetCharacterMovement()->MaxWalkSpeed = BaseWalkSpeed;if (Character->GetFollowCamera()){DefaultFOV = Character->GetFollowCamera()->FieldOfView; //获得最开始的视场角CurrentFOV = DefaultFOV;//当前视角初始化}}
}void UCombatComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{Super::TickComponent(DeltaTime, TickType, ThisTickFunction);if (Character && Character->IsLocallyControlled()){InterpFOV(DeltaTime);}
}

三、更改准心颜色,在瞄准人物时将准星变成红色

        0.没有更改准心颜色的功能将上面的代码删掉Color相关即可

        1.创建UE接口类,角色类继承该接口类

        2. 接口类使用

        2.1具体使用查看UE5官方文档,英文版使用浏览器的自动翻译Unreal Engine 中的接口 |Unreal Engine 5.4 文档 |Epic 开发者社区 (epicgames.com)icon-default.png?t=O83Ahttps://dev.epicgames.com/documentation/en-us/unreal-engine/interfaces-in-unreal-engine        2.2当前使用说明

        角色类继承了public IInteractWithCrosshairsInterface,I开头的接口类

        2.3战斗成分类中在Tick函数中 TraceHitResult时检测到的目标的结果类型时FHitResult

if (TraceHitResult.GetActor() && TraceHitResult.GetActor()->Implements<UInteractWithCrosshairsInterface>())
{HUDPackage.CrosshairsColor = FColor::Red;
}
else
{HUDPackage.CrosshairsColor = FColor::White;
}

        2.4若在测试时碰到角色在移动时摄像机贴在了当前角色身上时,可能是因为摄像机碰到了其他角色,在角色C++类的构造中添加以下代码,取消角色和摄像机的碰撞,若还会碰撞,请查看角色类蓝图中摄像机的碰撞在哪里打了√

GetMesh()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Camera, ECollisionResponse::ECR_Ignore);

四、当人物靠在墙边时,摄像头会紧贴在角色上,看不见前方的东西

        1.判断角色和摄像机的距离是否小于特定的值,如果小于将角色网格体隐藏,不小于显示

角色类头文件

	void HideCameraIfCharactorClose();UPROPERTY(EditAnywhere)float CameraThreadhold = 200.f;

角色类源文件

void ABlasterCharacter::HideCameraIfCharactorClose()
{if (!IsLocallyControlled()) return;if ((FollowCamera->GetComponentLocation() - GetActorLocation()).Size() < CameraThreadhold){GetMesh()->SetVisibility(false);if (Combat && Combat->EquippedWeapon && Combat->EquippedWeapon->GetWeaponMesh()){Combat->EquippedWeapon->GetWeaponMesh()->bOwnerNoSee = true;}}else{GetMesh()->SetVisibility(true);if (Combat && Combat->EquippedWeapon && Combat->EquippedWeapon->GetWeaponMesh()){Combat->EquippedWeapon->GetWeaponMesh()->bOwnerNoSee = false;}}
}

五、自定义碰撞频道

        0.我将角色骨骼设置成新的碰撞,在子弹类中定义了该类型的碰撞,这样在子弹命中人物时会判定在骨骼体上而不是网格体。之后会判断命中的身体部位是哪

        1.项目设置中设置如下没在引擎-碰撞中新建Object通道如下图

         2.在项目名.h的文件中定义,例如我的项目是Blaster

        Blaster.h

#define ECC_SkeletalMesh ECollisionChannel::ECC_GameTraceChannel1

        3.在会发生碰撞的物体中将设置碰撞的代码如下

CollisionBox->SetCollisionResponseToChannel(ECC_SkeletalMesh, ECollisionResponse::ECR_Block);

        4.设置碰撞类型,在对应蓝图中将怕碰撞预设的对象类型设置成1中的新建的对应的名字

六、 复制运动的通知函数

        1.问题描述

        当控制角色旋转是在其他客户端上会有轻微抖动问题

        2.原因

        角色蓝图中调用了RotateRootBone节点旋转骨头,在自己的客户端和服务器上,该旋转骨头会每帧调用,在其他客户端上,我们的角色在其他客户端上是代理角色,并不会每帧调用旋转骨骼的节点,所以会有抖动产生

        3.解决

        重写  virtual void OnRep_ReplicatedMovement() override;函数这是一个AActor类中关于运动的回调函数,在运动时会执行该函数

        角色类头文件

/* 解决当前旋转骨骼不是每帧调用时会在其他客户端存在抖动问题 */
void SimProxiesTurn();
/* 解决当前旋转骨骼不是每帧调用时会在其他客户端存在抖动问题 *///在AActor.h中定义,当角色移动是会调用当前回调
virtual void OnRep_ReplicatedMovement() override;蓝图中进行判断用
FORCEINLINE bool ShouldRotateRootBone() const { return bRotateRootBone; };bool bRotateRootBone;//是否进行了骨骼旋转float TimeSinceLastMovementReplication;//多长时间没有进行旋转

        角色类源文件

void ABlasterCharacter::Tick(float DeltaTime)
{Super::Tick(DeltaTime);TimeSinceLastMovementReplication += DeltaTime;//当一段时间没有移动时调用回调函数if (TimeSinceLastMovementReplication > 0.25f){OnRep_ReplicatedMovement();}CalculateA0_Pitch();
}void ABlasterCharacter::OnRep_ReplicatedMovement()
{Super::OnRep_ReplicatedMovement();//if (GetLocalRole() == ENetRole::ROLE_SimulatedProxy)//{//	SimProxiesTurn();//}SimProxiesTurn();TimeSinceLastMovementReplication = 0.f;
}void ABlasterCharacter::SimProxiesTurn()
{//处理模拟界面的转弯if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;bRotateRootBone = false;float Speed = CalculateSpeed();if (Speed > 0.f){TurningInPlace = ETurningInPlace::ETIP_NotTurning;return;}//CalculateA0_Pitch();ProxyRotationLastFrame = ProxyRotation;ProxyRotation = GetActorRotation();//计算两个角度的最小旋转角度变化在 [-180, 180] 范围内ProxyYaw = UKismetMathLibrary::NormalizedDeltaRotator(ProxyRotation, ProxyRotationLastFrame).Yaw;if (FMath::Abs(ProxyYaw) > TurnThreshold){if (ProxyYaw > TurnThreshold){TurningInPlace = ETurningInPlace::ETIP_Right;}else if (ProxyYaw < -TurnThreshold){TurningInPlace = ETurningInPlace::ETIP_Left;}else{TurningInPlace = ETurningInPlace::ETIP_NotTurning;}return;}TurningInPlace = ETurningInPlace::ETIP_NotTurning;
}float ABlasterCharacter::CalculateSpeed()
{/* 只想获得平面上xy的速度的向量,将z方向的速度置为0 */FVector Velocity = GetVelocity();Velocity.Z = 0.f;return Velocity.Size();
}

         4.蓝图中获得是否旋转骨头的bool类型变量,在动画蓝图中判断如果旋转了骨头则直接旋转没有旋转骨头就直接角色旋转

        在判断是否具有本地控制权限(FullBody就是上面的流程(使用了cache poses))

七、自动射击 

        1.使用了FTimerManager类让武器间隔一段时后再次发射子弹

         战斗类头文件

	/***	自动开火*/FTimerHandle FireTimer; //定时器类bool bCanFire = true;void StartFireTimer();void FireTimerFinished();

        战斗类源文件

void UCombatComponent::StartFireTimer()
{if (EquippedWeapon == nullptr || Character == nullptr) return;Character->GetWorldTimerManager().SetTimer(FireTimer,this,&UCombatComponent::FireTimerFinished,EquippedWeapon->FireDelay);
}void UCombatComponent::FireTimerFinished()
{if (EquippedWeapon == nullptr) return;bCanFire = true;if (bFireButtonPressed && EquippedWeapon->bAutomatic){Fire();}
}

        武器类头文件

	/***	自动开火*/UPROPERTY(EditAnywhere, Category = Combat)float FireDelay = 0.15f; //开火速率UPROPERTY(EditAnywhere, Category = Combat)bool bAutomatic = true; //武器是否自动

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习之图像数据集增强(Data Augmentation)

文章目录 一、 数据增强概述二、python实现传统数据增强参考文献 一、 数据增强概述 数据增强&#xff08;Data Augmentation&#xff09;是一种技术&#xff0c;通过对现有数据进行各种变换和处理来生成新的训练样本&#xff0c;从而增加数据集的多样性和数量。这些变换可以是…

C#使用TCP-S7协议读写西门子PLC(五)-测试程序

上面四篇我们进行封装连接PLC以及读写PLC内存地址表 C#使用TCP-S7协议读写西门子PLC(一)-CSDN博客 C#使用TCP-S7协议读写西门子PLC(二)-CSDN博客 C#使用TCP-S7协议读写西门子PLC(三)-CSDN博客 C#使用TCP-S7协议读写西门子PLC(四)-CSDN博客 这里我们进行测试操作 西门子PLC-…

[JAVA]介绍怎样在Java中通过字节字符流实现文件读取与写入

一&#xff0c;初识File类及其常用方法 File类是java.io包下代表与平台无关的文件和目录&#xff0c;程序中操作文件和目录&#xff0c;都可以通过File类来完成。 通过这个File对象&#xff0c;可以进行一系列与文件相关的操作&#xff0c;比如判断文件是否存在&#xff0c;获…

floodfill+DFS(2)

文章目录 太平洋大西洋流水问题扫雷游戏迷路的机器人 太平洋大西洋流水问题 class Solution { public:vector<vector<int>> res;int m 0, n 0;vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {m heights.size…

珠宝首饰检测系统源码分享

珠宝首饰检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

在 Python 中使用 JSON

了解如何在 Python 中使用 JSON&#xff0c;从基础到高级技术。本指南涵盖解析、序列化、API 集成和最佳实践。 1. JSON 简介 1.1. 什么是 JSON&#xff1f; JSON&#xff08;JavaScript 对象表示法&#xff09;是一种轻量级数据交换格式&#xff0c;人类可以轻松读取和写入…

mongoDB-1

文章目录 一、疑似坑1.11.2 mongo ops manager1.3 mongo features视图固定大小集合&#xff08;有点类似ringbuffer数据结构&#xff0c;capped collections&#xff09;(聚簇集合)clustered collection(类比到Mysql的聚簇索引)聚合管道 aggregation pipelineWiredTiger (默认存…

uniapp微信小程序用户授权方法

效果 步骤 1&#xff09;div标签 <button type"primary" class"btn-login" click"getUserInfo">一键登录</button>2&#xff09;js方法 methods: {getUserInfo() {console.log("aaaa")uni.getUserProfile({desc: Wexin, …

iPhone 上丢失了重要的联系人?如何恢复已删除的 iPhone 联系人

丢失 iPhone 上的联系人可能会带来灾难。无论是一份很棒的新工作机会、潜在的恋爱对象&#xff0c;还是您一直想打电话的老朋友&#xff0c;如果您打开“联系人”应用时看到空白&#xff0c;这绝不是好事。不过&#xff0c;一切并非全无&#xff0c;仍然可以通过备份或专业软件…

Mamba对UNet王炸升级!全新混合架构参数小了116倍,精度依旧完成超车

UNet又升级了&#xff01;北大最新提出LightM-UNet&#xff0c;用Mamba设计1.8M参数UNet&#xff0c;比nnU-Net小了116倍&#xff0c;计算量减少21倍&#xff0c;精度依然SOTA&#xff01; 这种将Mamba与UNet结合的策略利用了两者在图像处理和网络架构上的优势&#xff0c;既能…

Renesas R7FA8D1BH (Cortex®-M85)控制SHT20

目录 概述 1 硬件接口介绍 2 SHT20模块 2.1 SHT20简介 2.2 SHT-20模块电路 3 I2C接口实现 3.1 FSP配置I2C 3.2 I2C驱动程序实现 4 SHT20驱动程序 4.1 SHT20驱动代码结构 4.2 源代码文件 5 测试 5.1 测试功能介绍 5.2 测试代码实现 5.3 运行代码 概述 本文主要介…

持续集成与持续交付CI/CD

CI/CD 是指持续集成&#xff08;Continuous Integration&#xff09;和持续部署&#xff08;Continuous Deployment&#xff09;或持续交付&#xff08;Continuous Delivery&#xff09; 持续集成&#xff08;Continuous Integration&#xff09; 持续集成是一种软件开发实践&…

BFS 解决边权为1的最短路问题

边权为1的最短路问题 最短路问题&#xff1a; 比如说从D->K&#xff0c;找出最短的那条&#xff0c;其中每条路都是有权值&#xff0c;此篇主要讲解的边权为1的最短路问题。 即边权都是一样的。 解法就是从起点开始&#xff0c;做一次BFS&#xff1a; 需要一个队列、一个…

Spring-IOC容器-ApplicationContext

IOC:Inversion of Control 控制反转&#xff0c;是一种设计原则&#xff0c;spring 中通过DI&#xff08;dependency Injection&#xff09;来具体实现。 比如原本对象的实例化&#xff0c;是通过程序主动New出来&#xff0c;IOC中的对象实例交给Spring框架来实例化&#xff0…

后台数据管理系统 - 项目架构设计-Vue3+axios+Element-plus(0917)

七、引入 element-ui 组件库 官方文档&#xff1a; https://element-plus.org/zh-CN/ 安装 $ pnpm add element-plus自动按需&#xff1a; 安装插件 pnpm add -D unplugin-vue-components unplugin-auto-import然后把下列代码插入到你的 Vite 或 Webpack 的配置文件中 ..…

maxcompute使用篇

文章目录 maxcompute使用篇1.mongoDB与maxcompute 进行数据同步1.1 基本类型的数据1.2部分复杂类型的数据 2.maxcompute中复杂数据类型解析2.1 get_json_object2.2 json_tuple2.3 处理json几种失效的情况:2.4 STR_TO_MAP、MAP_KEYS2.5 regexp_replace2.6 FROM_JSON2.7 nvl2.8 t…

【Hot100】LeetCode—51. N 皇后

目录 1- 思路题目识别回溯 2- 实现⭐51. N 皇后——题解思路 3- ACM 实现 原题链接&#xff1a;51. N 皇后 1- 思路 题目识别 识别1 &#xff1a;给定一个整数 n &#xff0c;求解如何放置棋子的问题。 回溯 回溯三部曲 1- 回溯参数和返回值 传参 cheeseBoard、n、row 传递…

C语言:刷题日志(1)

一.阶乘计算升级版 本题要求实现一个打印非负整数阶乘的函数。 其中n是用户传入的参数&#xff0c;其值不超过1000。如果n是非负整数&#xff0c;则该函数必须在一行中打印出n!的值&#xff0c;否则打印“Invalid input”。 首先&#xff0c;知道阶乘是所有小于及等于该数的…

Solidity优质例子(一)食品溯源智能合约

这个智能合约FoodInfoItem的功能是管理食品的追溯信息&#xff0c;包括食品在不同阶段的流转、质量记录、消费者评分等。它通过区块链记录食品的生产、分销和销售过程&#xff0c;确保每一环节的透明和不可篡改性。 实际生活中的用途&#xff1a; 食品安全和质量控制&#xff1…

实时数仓3.0DWD层

实时数仓3.0DWD层 DWD层设计要点&#xff1a;9.1 流量域未经加工的事务事实表9.1.1 主要任务9.1.2 思路9.1.3 图解9.1.4 代码 9.2 流量域独立访客事务事实表9.2.1 主要任务9.2.2 思路分析9.2.3 图解9.2.4 代码 9.3 流量域用户跳出事务事实表9.3.1 主要任务9.3.2 思路分析9.3.3 …