您现在的位置是:首页 >其他 >UE5.1.1C++从0开始(10.作业三)网站首页其他

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

楚江_wog1st 2024-06-25 12:01:03
简介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);
	
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。