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

news2024/9/20 3:25:46

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.coloradmin.cn/o/2143177.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TensorRT-LLM——优化大型语言模型推理以实现最大性能的综合指南

引言 随着对大型语言模型 (LLM) 的需求不断增长&#xff0c;确保快速、高效和可扩展的推理变得比以往任何时候都更加重要。NVIDIA 的 TensorRT-LLM 通过提供一套专为 LLM 推理设计的强大工具和优化&#xff0c;TensorRT-LLM 可以应对这一挑战。TensorRT-LLM 提供了一系列令人印…

AD的入门操作

锦囊 1、打开AD后&#xff0c;一般默认打开上一个工程&#xff0c;这个时候如果想要打开新的工程&#xff0c;那就必须要创建一个项目&#xff0c;然后再在项目中添加原理图库和PCB库。 2、大多数情况下&#xff0c;直接使用库&#xff0c;不用自己再画原理图和封装库。 3、…

LeetCode[中等] 49.字母异位词分组

给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 思路&#xff1a; new Dictionary<string, List<string>>() 存储数据&#xff0c;key为排序之后的字符…

超高速传输 -- 相干光通信和非相干光通信

概述&#xff1a;技术对比 项目非相干光通信相干通信定义不需要相干本振光的光传输系统。采用本振光进行相干检测的光传输系统。调制解调技术发送端&#xff1a;强度调制。 接收端&#xff1a;直接检测。发送端&#xff1a;外调制。 接收端&#xff1a;本振光相干检测。码型幅…

完美的宝塔面板防御策略,基于 fail2ban

之前分享过宝塔面板配合fail2ban&#xff0c;以及开启cloudflare的cdn双重防御的教程&#xff0c;并制作了便捷的脚本这次不靠cloudflare的减速cdn&#xff0c;看看防御效果怎么样 系统环境 debian/ubuntu nginx 宝塔面板 注意要点 1.在宝塔面板开启站点日志 2.添加服务器白名…

加密与安全_HTTPS TLS 1.2 连接(RSA 握手)的整个过程解读

文章目录 HTTPS 数据传输的安全性保障SSL/TLS 作为混合加密系统的典范HTTPS TLS 1.2 连接&#xff08;RSA 握手&#xff09;的整个过程TLS 握手过程解析1. TCP 三次握手 (最顶部的黄色部分)2. TLS 握手阶段 (红色部分)2.1 Client Hello2.2 Server Hello2.3 CA 证书验证2.4 Clie…

[Python数据可视化]Plotly Express: 地图数据可视化的魅力

在数据分析和可视化的世界中&#xff0c;地图数据可视化是一个强大而直观的工具&#xff0c;它可以帮助我们更好地理解和解释地理数据。Python 的 Plotly Express 库提供了一个简单而强大的方式来创建各种地图。本文将通过一个简单的示例&#xff0c;展示如何使用 Plotly Expre…

【JavaWeb】利用IDEA2024+tomcat10配置web6.0版本搭建JavaWeb开发项目

之前写过一篇文章&#xff1a;《【JavaWeb】利用IntelliJ IDEA 2024.1.4 Tomcat10 搭建Java Web项目开发环境&#xff08;图文超详细&#xff09;》详细讲解了如何搭建JavaWeb项目的开发环境&#xff0c;里面默认使用的Web版本是4.0版本的。但在某些时候tomcat10可能无法运行we…

24年蓝桥杯及攻防世界赛题-MISC-1

2 What-is-this AZADI TOWER 3 Avatar 题目 一个恐怖份子上传了这张照片到社交网络。里面藏了什么信息&#xff1f;隐藏内容即flag 解题 ┌──(holyeyes㉿kali2023)-[~/Misc/tool-misc/outguess] └─$ outguess -r 035bfaa85410429495786d8ea6ecd296.jpg flag1.txt Rea…

iKuai使用及设置流程

iKuai使用及设置流程 iKuai安装步骤 一、配置主机 1.电脑连接ETH0网口 2.ETH1网口连接猫上面的千兆口 3.手动配置pc的IP地址和192.168.1.1./24在同一网段 3.浏览器输入192.168.1.1 admin admin 二、外网设置 1.直接联通电信网络设置 2.点击 网络设置-内外网设置-点击接…

LeetCode从入门到超凡(一)枚举算法

前言 大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年9月学习赛的LeetCode学习总结文档&#xff1b;本文主要讲解枚举算法。&#x1f495;&#x1f495;&#x1f60a; 一、基本概念 1.定义 定义&am…

记录小数点

记录data frame小数点后面省略掉0的问题 iloc得到的series .to_list() 0被省略掉 to_list() 可能会将浮点数转换为默认格式。先将数据转换为字符串以保留格式 df_2708.iloc[2,:].apply(lambda x: f{x:.3f}).to_list()自定义保留小数点后几位 def formatter(value):return &q…

【工作流集成】springboot+vue工作流审批系统(实际源码)

前言 activiti工作流引擎项目&#xff0c;企业erp、oa、hr、crm等企事业办公系统轻松落地&#xff0c;一套完整并且实际运用在多套项目中的案例&#xff0c;满足日常业务流程审批需求。 一、项目形式 springbootvueactiviti集成了activiti在线编辑器&#xff0c;流行的前后端…

Java 入门指南:JVM(Java虚拟机)垃圾回收机制 —— 垃圾回收算法

文章目录 垃圾回收机制垃圾判断算法引用计数法可达性分析算法虚拟机栈中的引用&#xff08;方法的参数、局部变量等&#xff09;本地方法栈中 JNI 的引用类静态变量运行时常量池中的常量 垃圾收集算法Mark-Sweep&#xff08;标记-清除&#xff09;算法Copying&#xff08;标记-…

电脑右击没有txt文件

文本文档是一个好工具&#xff0c;小而快&#xff0c;比word快多&#xff0c;一般情况下&#xff0c;记录都会先用txt文本&#xff0c;但是今天发现右击菜单新建里面没有&#xff0c;怎么回事&#xff1f; 这个需要打开注册编辑表修改 一、打开注册编辑表 win R 输入regedi…

JetLinks物联网学习(前后端项目启动)

前后端项目启动 1、后端1.1 pgsql改mysql报错2、elasticSearch7.0版本以上_doc格式取消 2、前端 1、后端 环境准备&#xff1a; 1、window系统7,8&#xff0c;10 。 硬件资源最低要求4c8G&#xff0c;硬盘40G 2、JDK 1.8.0_2xx (需要小版本号大于200) 3、Maven3.6.3 4、Redis …

专题四_位运算( >> , << , , | , ^ )_算法详细总结

目录 位运算 常见位运算总结 1.基础位运算 2.给一个数 n ,确定它的二进制表示中的第 x 位是 0 还是 1 3.运算符的优先级 4.将一个数 n 的二进制表示的第 x 位修改成 1 5.将一个数n的二进制表示的第x位修改成0 6.位图的思想 7.提取一个数&#xff08;n&#xff09;二进…

解决使用阿里云DataV Geo在线地图路径访问403问题

文章目录 1. DataV Geo在线地图路径访问403问题2. 解决方法3. 重启生效 1. DataV Geo在线地图路径访问403问题 最近在写一个省市下钻的demo&#xff0c;用到的是 阿里云DataV Geo在线地图 去动态获取GeoJSON 省市的数据&#xff0c;如下代码 axios.get("https://geo.dat…

Ubuntu24.04 安装opencv4.10

Ubuntu24.04 安装opencv4.10 一、下载OpenCV二、更新系统&#xff0c;安装必要的包1、“E: unable to locate libjasper-dev"的解决方法2、没有公钥&#xff0c;无法验证下列签名 :NO_PUBKEY 的解决方法 三、配置&#xff0c;使用cmake工具1、新建build目录2、在build中&a…

计算机毕业设计 玩具租赁系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…