UE5.1.1C++从0开始(10.作业三)

这次作业量和之前的相比可能会有点大,我先整理一下这次的作业清单:

  1. 魔法子弹的飞行声音以及爆炸声音
  2. 给玩家增加受击的闪亮的效果,和立方体相同的那种
  3. 增加一个health max的变量,把widget里头的health节点更换为health max节点,同时给health设置一个上下限,上限是health max , 下限是0
  4. 给我们刚创建出的显示伤害的widget设置一个动画,在受击的时候播放出来,同时伤害的显示不能写死,用变量来表示
  5. 新建一个生命药水,可以恢复生命值,回复一次之后,10秒内不能再次使用,10秒后可再次使用。当玩家血量满的时候忽略玩家的交互
  6. 给玩家的手上附加一个粒子效果(这个我没看明白,没写)
  7. 增加一个摇晃摄像头的效果

一共7项作业,量可以说是非常大了。。。不过还是一个一个来做。

1.魔法子弹的飞行声音以及爆炸效果:

我把这个功能写到了SFatherMagicProjectile里头

SFatherMagicProjectile.h

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

#pragma once

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

UCLASS()
class ACTIONROGUELIKE_API ASFatherMagicProjectile : public AActor
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere)
	class USphereComponent * SphereComp;

	UPROPERTY(EditAnywhere)
	class UProjectileMovementComponent * MovementComp;

	UPROPERTY(EditAnywhere)
	class UParticleSystemComponent * ParticleComp;
	
    //一个声音组件
	UPROPERTY(EditAnywhere)
	class UAudioComponent * AudioComp;
	
    //爆炸声
	UPROPERTY(EditAnywhere)
	class USoundBase * Sound;
	
public:	
	// Sets default values for this actor's properties
	ASFatherMagicProjectile();

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

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

	UFUNCTION()
	virtual void OnComponentHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, FHitResult Hit);

	UFUNCTION()
		void OnComponentOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
};

SFatherMagicProjectile.cpp

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


#include "SFatherMagicProjectile.h"
#include "Components/SphereComponent.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Particles/ParticleSystemComponent.h"
#include "SAttributeComponent.h"
#include "Components/AudioComponent.h"
#include "Kismet/GameplayStatics.h"

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

	FScriptDelegate OnHit;
	OnHit.BindUFunction(this, STATIC_FUNCTION_FNAME(TEXT("ASFatherMagicProjectile::OnComponentHit")));

	FScriptDelegate OnOverlap;
	OnOverlap.BindUFunction(this, STATIC_FUNCTION_FNAME(TEXT("ASFatherMagicProjectile::OnComponentOverlap")));

	SphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("Sphere Comp"));
	SphereComp->SetCollisionProfileName("Projectile");
	SphereComp->SetSphereRadius(10.0f, true);
	SphereComp->OnComponentHit.Add(OnHit);
	SphereComp->OnComponentBeginOverlap.Add(OnOverlap);
	RootComponent = SphereComp;

	MovementComp = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("Movement Comp"));
	MovementComp->InitialSpeed = 1000.0f;
	MovementComp->bRotationFollowsVelocity = true;
	MovementComp->bInitialVelocityInLocalSpace = true;
	MovementComp->ProjectileGravityScale = 0.0f;

	ParticleComp = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("Particle Comp"));
	ParticleComp->SetupAttachment(SphereComp);

	AudioComp = CreateDefaultSubobject<UAudioComponent>(TEXT("Audio Comp"));
	
}

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

	APawn* Instigator_01 = AActor::GetInstigator();

	SphereComp->IgnoreActorWhenMoving(Instigator_01, true);

    //播放飞行声效
	AudioComp->Play(0.0f);
	
}

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

}

void ASFatherMagicProjectile::OnComponentHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, FHitResult Hit)
{
	APawn* Instigator_01 = AActor::GetInstigator();

	if (Instigator_01!=OtherActor)
	{	
        //播放爆炸声效
		UGameplayStatics::PlaySoundAtLocation(GetWorld(),Sound , this->GetActorLocation(), 1.0f, 1.0f);
		GetWorld()->DestroyActor(this);
		DrawDebugSphere(GetWorld(), Hit.ImpactPoint, 10.0f, 16, FColor::Red, false, 2.0f, 0U, 1.0f);
		
	}
}

void ASFatherMagicProjectile::OnComponentOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	APawn* Instigator_01 = AActor::GetInstigator();

	if (OtherActor)
	{
		USAttributeComponent* AttributeComp = Cast<USAttributeComponent>(OtherActor->GetComponentByClass(USAttributeComponent::StaticClass()));
		if (AttributeComp)
		{
			if (Instigator_01 != OtherActor)
			{
				UGameplayStatics::Play
					AtLocation(GetWorld(), Sound, this->GetActorLocation(), 1.0f, 1.0f);
				AttributeComp->ApplyHealthChange(-20.0f);
				GetWorld()->DestroyActor(this);
			}
		}

	}
}




2.给玩家增加受击的闪亮的效果,和立方体相同的那种

这个首先得对我们的Gideon的材质进行修改

请添加图片描述

使用MatLayerBlend_Emissive函数,然后把我们的MF_HitFlash给连上去就好,再之后就是玩家角色的代码更改

SCharacter.cpp

void ASCharacter::OnHealthChanged(AActor* InstigatorActor, USAttributeComponent* OwningComp, float NewHealth, float Delta)
{
    //这个函数做了更改,第一点是只有受伤才会触发闪亮的效果,加血的时候不需要触发这个效果
	if (NewHealth<0.0f)
	{
		this->GetMesh()->SetScalarParameterValueOnMaterials("TimeToHit", GetWorld()->TimeSeconds);
		if (Delta<0.0f)
		{
			APlayerController* PC = Cast<APlayerController>(GetController());
			DisableInput(PC);
		}
	}
	
}

3.增加一个health max的变量,把widget里头的health节点更换为health max节点,同时给health设置一个上下限,上限是health max , 下限是0

这个蛮简单的,更改如下

SAttributeComponent.cpp

bool USAttributeComponent::ApplyHealthChange(float Delta)
{
	
    //使用Clamp函数,Health的更改在Clamp函数的第一个参数那里显示了
	Health = FMath::Clamp(Health+Delta, 0, HealthMax);


	OnHealthChanged.Broadcast(nullptr,this,Health,Delta);
	return true;
}

4.给我们刚创建出的显示伤害的widget设置一个动画,在受击的时候播放出来,同时伤害的显示不能写死,用变量来表示

请添加图片描述

Cube的蓝图更改

请添加图片描述
至于动画怎么播放,看各位的设计了,这里是千人千面的。

5.新建一个生命药水,可以恢复生命值,回复一次之后,10秒内不能再次使用,10秒后可再次使用。当玩家血量满的时候忽略玩家的交互

这也没遇上啥大问题,这个的示例就是我们的可以开关的那个箱子

SHealBottle.h

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "SGameplayInterface.h"
#include "SHealBottle.generated.h"

UCLASS()
class ACTIONROGUELIKE_API ASHealBottle : public AActor, public ISGameplayInterface
{
	GENERATED_BODY()

	void Interact_Implementation(APawn* InstigatorPawn) override;

	UPROPERTY(VisibleAnywhere)
	class UStaticMeshComponent* MeshComp;

private:
	UFUNCTION()
	void RefreshBottle();

private:
	bool CanHeal;
	
	FTimerHandle Timer;

public:	
	// Sets default values for this actor's properties
	ASHealBottle();

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

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

};

SHealBottle.cpp

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


#include "SHealBottle.h"
#include "Components/StaticMeshComponent.h"
#include "SAttributeComponent.h"

//接口函数的实现
void ASHealBottle::Interact_Implementation(APawn* InstigatorPawn)
{
	ASCharacter* InstigatorCharacter_01 = Cast<ASCharacter>(InstigatorPawn);
	USAttributeComponent* attributeComp_01 = InstigatorCharacter_01->AttributeComp;
	if (attributeComp_01->GetHealth()>=100||!CanHeal)
	{
		return;
	}
	attributeComp_01->ApplyHealthChange(10.0f);
	CanHeal = false;
	MeshComp->SetVisibility(false);
    //消失10秒
	GetWorldTimerManager().SetTimer(Timer,this, &ASHealBottle::RefreshBottle, 10.0f);
}

void ASHealBottle::RefreshBottle()
{
	CanHeal = true;
	MeshComp->SetVisibility(true);
}

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

	MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh Comp"));

	CanHeal = true;

}

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

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

}


7.增加一个摇晃摄像头的效果

SCharacter.cpp

void ASCharacter::PrimaryAttack()
{
	
    //获得控制器
	APlayerController* pc = Cast<APlayerController>(GetController());
	//播放摄像机的震荡
	pc->ClientStartCameraShake(CameraShakeComp);

	GetWorldTimerManager().SetTimer(TimerHandle_PrimaryAttack,this,&ASCharacter::PrimaryAttack_TimeElasped,0.2f);
	
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
对不起,我的回答中有误。在UE5.1.1中,uperarm_r的旋转坐标是由四个值构成的,分别是Roll、Pitch、Yaw和W。因此,需要将mediapipe的坐标系转换为UE5.1.1的左手坐标系,然后计算uperarm_r的四元数值,最后将四元数值赋给uperarm_r的旋转坐标。 具体的计算方法如下: 1. 将mediapipe的坐标系转换为UE5.1.1的左手坐标系。具体来说,需要将y坐标和z坐标取负,即将(0.546142, 0.315784, -0.148612)转换为(0.546142, -0.315784, 0.148612)。 2. 计算uperarm_r的旋转四元数值。具体来说,可以使用UE5.1.1中的FQuat::FindBetweenVectors函数来计算uperarm_r的方向向量和转换后的坐标的四元数值。具体的计算方法如下: ``` FVector ShoulderPos(0.546142, -0.315784, 0.148612); // 转换后的坐标 FVector UperarmDir(1.0f, 0.0f, 0.0f); // uperarm_r的方向向量 FQuat UperarmQuat = FQuat::FindBetweenVectors(UperarmDir, ShoulderPos.GetSafeNormal()); ``` 3. 将计算得到的uperarm_r的四元数值赋给uperarm_r的旋转坐标。具体来说,需要使用UE5.1.1中的USkeletalMeshComponent::SetBoneRotationByName函数来设置uperarm_r的旋转坐标。具体的代码如下: ``` USkeletalMeshComponent* SkeletalMeshComponent; // 需要替换成实际的SkeletalMeshComponent SkeletalMeshComponent->SetBoneRotationByName(TEXT("uperarm_r"), UperarmQuat, EBoneSpaces::WorldSpace); ``` 需要注意的是,以上计算过程中需要考虑坐标系的转换和旋转角度的顺序等因素,因此具体的计算方法可能会有所不同。建议在实际使用过程中,根据具体的需求和场景进行调整和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

楚江_wog1st

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

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

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

打赏作者

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

抵扣说明:

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

余额充值