被复刻教程地址:https://www.bilibili.com/video/av46428172
准备工作
创建一个C++ FPS模板工程
创建一个TargetRed材质
添加一个类TargetStaticMeshActor,继承自StaticMeshActor。
成功后,Visual Studio会自动打开
复刻Event Hit事件节点
蓝图
一般(非全部)有两种方法添加一个事件
- 重写Notify<事件名>方法
- 用OnActor<事件名>的AddDynamic的方式动态添加
从Actor中找到NotifyHit和OnActorHit。
NotifyHit
- TargetStaticMeshActor.h
public:
virtual void NotifyHit(
class UPrimitiveComponent * MyComp, AActor * Other,
class UPrimitiveComponent * OtherComp, bool bSelfMoved,
FVector HitLocation, FVector HitNormal,
FVector NormalImpulse, const FHitResult & Hit
) override;
- TargetStaticMeshActor.cpp
void ATargetStaticMeshActor::NotifyHit(
class UPrimitiveComponent * MyComp, AActor * Other,
class UPrimitiveComponent * OtherComp, bool bSelfMoved,
FVector HitLocation, FVector HitNormal,
FVector NormalImpulse, const FHitResult & Hit
)
{
Super::NotifyHit(MyComp, Other, OtherComp, bSelfMoved,
HitLocation, HitNormal, NormalImpulse, Hit);
//处理事件
}
OnActorHit.AddDynamic
- TargetStaticMeshActor.h
public:
TargetStaticMeshActor();
UFUNCTION()
void OnHit(
class UPrimitiveComponent * MyComp, AActor * Other,
class UPrimitiveComponent * OtherComp, bool bSelfMoved,
FVector HitLocation, FVector HitNormal,
FVector NormalImpulse, const FHitResult & Hit
);
- TargetStaticMeshActor.cpp
void ATargetStaticMeshActor::ATargetStaticMeshActor()
{
OnActorHit.AddDynamic(this, &ATargetStaticMeshActor::OnHit);
}
void ATargetStaticMeshActor::OnHit(
class UPrimitiveComponent * MyComp, AActor * Other,
class UPrimitiveComponent * OtherComp, bool bSelfMoved,
FVector HitLocation, FVector HitNormal,
FVector NormalImpulse, const FHitResult & Hit
)
{
//处理事件
}
复刻CastToFirstPersonProjectile节点
蓝图
- TargetStaticMeshActor.cpp
#include "FirstPersonProjectile .h"
void ATargetStaticMeshActor::NotifyHit(..., AActor * Other,...)
{
Super::NotifyHit(MyComp, Other, OtherComp, bSelfMoved,
HitLocation, HitNormal, NormalImpulse, Hit);
//Cast to FirstPersonProjectile
AFirstPersonProjectile *projectile = Cast(Other);
if (projectile != nullptr) { //转换成功
//处理事件
}
else { //转换失败
;
}
}
复刻SetMaterial节点
蓝图
C++
- TargetStaticMeshActor.cpp
#include "Components/StaticMeshComponent.h"
...
if (projectile != nullptr) { //转换成功
UStaticMeshComponent * staticMesh = GetStaticMeshComponent();
staticMesh->SetMaterial(0, TargetRed/*变色材质,后文声明*/);
//处理事件
}
...
让蓝图给材质变量的赋值
- TargetStaticMeshActor.h
public:
UPROPERTY(EditDefaultsOnly, Categroy="TargetSetting")
UMaterialInterface *TargetRed;
UPROPERTY(EditDefaultsOnly, Categroy="TargetSetting")
UMaterialInterface *Original;
EditDefaultsOnly是可以在蓝图中编辑,不能对实例编辑。
复刻Branch节点
蓝图
- TargetStaticMeshActor.cpp
...
if (projectile != nullptr) { //转换成功
UStaticMeshComponent * staticMesh = GetStaticMeshComponent();
staticMesh->SetMaterial(0, TargetRed/*变色材质,后文声明*/);
// Branch node
if (IsPrimed) {
//True
}
else {
//False
}
}
...
复刻PlaySoundAtLocation节点
蓝图
C++
- TargetStaticMeshActor.cpp
#include "Kismet/GameplayStatics.h"
...
if (IsPrimed) {
UGameplayStatics::PlaySoundAtLocation(GetWorld(), TargetSound/*爆炸声音,后文声明*/, HitLocation);
}
else {
//False
}
...
复刻SpawnEmitterAtLocation节点
蓝图
C++
- TargetStaticMeshActor.cpp
#include "Kismet/GameplayStatics.h"
...
if (IsPrimed) {
...
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), TargeParticle/*爆炸特效,后文声明*/, HitLocation);
}
else {
//False
}
...
复刻DestroyActor节点
蓝图
C++
- TargetStaticMeshActor.cpp
...
if (IsPrimed) {
...
Destroy();
}
else {
//False
}
...
复刻Delay节点
蓝图
C++
- TargetStaticMeshActor.h
UFUNCTION()
void NotifyHitCallback();
- TargetStaticMeshActor.cpp
#include "Kismet/KismetSystemLibrary.h"
void ATargetStaticMeshActor::NotifyHitCallback()
{
class UStaticMeshComponent* staticMeshComponet = GetStaticMeshComponent();
staticMeshComponet->SetMaterial(0, Original);
}
...
if (IsPrimed) {
...
}
else {
FLatentActionInfo info;
info.Linkage = 0;
info.UUID = __LINE__;
info.ExecutionFunction = "NotifyHitCallback";
info.CallbackTarget = this;
isPrimed = true;
UKismetSystemLibrary::Delay(GetWorld(), 0.5f, info);
}
...
复刻Tick节点
蓝图
C++
- TargetStaticMeshActor.h
public:
virtual void Tick(float DeltaTime) override;
- TargetStaticMeshActor.cpp
ATargetStaticMeshActor::ATargetStaticMeshActor()
{
PrimaryActorTick.bCanEverTick = true; //必须滴
isPrimed = false;
direction = FVector(0, -10, 0);
}
void ATargetStaticMeshActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
复刻GetActorLocation/SetActorLocation相关节点
蓝图
C++
- TargetStaticMeshActor.cpp
#include "Kismet/KismetMathLibrary.h"
...
void ATargetStaticMeshActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
AddActorLocalOffset(UKismetMathLibrary::Normal(direction) * DeltaTime * 200);
}
复刻Tick中的Delay节点
蓝图
C++
- TargetStaticMeshActor.h
UFUNCTION()
void MoveCallback();
- TargetStaticMeshActor.cpp
void ATargetStaticMeshActor::MoveCallback()
{
direction *= -1;
}
void ATargetStaticMeshActor::Tick(float DeltaTime)
{
...
FLatentActionInfo info;
info.Linkage = 0;
info.UUID = __LINE__;
info.ExecutionFunction = "NotifyHitCallback";
info.CallbackTarget = this;
isPrimed = true;
UKismetSystemLibrary::Delay(GetWorld(), 0.5f, info);
}
...
完整代码@version 4.22
- TargetStaticMeshActor.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/StaticMeshActor.h"
#include "TargetStaticMeshActor.generated.h"
/**
*
*/
UCLASS()
class FIRSTPERSON_API ATargetStaticMeshActor : public AStaticMeshActor
{
GENERATED_BODY()
bool isPrimed;
FVector direction;
UFUNCTION()
void NotifyHitCallback();
UFUNCTION()
void MoveCallback();
public:
UPROPERTY(EditDefaultsOnly, Category = "TargetSetting")
UMaterialInterface* TargetRed;
UPROPERTY(EditDefaultsOnly, Category = "TargetSetting")
UMaterialInterface* Original;
UPROPERTY(EditDefaultsOnly, Category = "TargetSetting")
USoundBase *TargetSound;
UPROPERTY(EditDefaultsOnly, Category = "TargetSetting")
UParticleSystem *TargeParticle;
ATargetStaticMeshActor();
virtual void NotifyHit(
class UPrimitiveComponent* MyComp,
AActor* Other,
class UPrimitiveComponent* OtherComp,
bool bSelfMoved,
FVector HitLocation,
FVector HitNormal,
FVector NormalImpulse,
const FHitResult& Hit) override;
virtual void Tick(float DeltaTime) override;
};
- TargetStaticMeshActor.cpp
#include "TargetStaticMeshActor.h"
#include "FirstPersonProjectile.h"
#include "Components/StaticMeshComponent.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet/KismetMathLibrary.h"
ATargetStaticMeshActor::ATargetStaticMeshActor()
{
PrimaryActorTick.bCanEverTick = true;
isPrimed = false;
direction = FVector(0, -10, 0);
}
void ATargetStaticMeshActor::NotifyHitCallback()
{
class UStaticMeshComponent* staticMeshComponet = GetStaticMeshComponent();
staticMeshComponet->SetMaterial(0, Original);
}
void ATargetStaticMeshActor::NotifyHit(UPrimitiveComponent * MyComp, AActor * Other, UPrimitiveComponent * OtherComp, bool bSelfMoved, FVector HitLocation, FVector HitNormal, FVector NormalImpulse, const FHitResult & Hit)
{
Super::NotifyHit(MyComp, Other, OtherComp, bSelfMoved, HitLocation, HitNormal, NormalImpulse, Hit);
if (Other == nullptr) return;
AFirstPersonProjectile *p = Cast(Other);
if (p != nullptr) {
class UStaticMeshComponent* staticMeshComponet = GetStaticMeshComponent();
staticMeshComponet->SetMaterial(0, TargetRed);
if (isPrimed) {
UGameplayStatics::PlaySoundAtLocation(GetWorld(), TargetSound, HitLocation);
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), TargeParticle, HitLocation);
Destroy();
}
else {
FLatentActionInfo info;
info.Linkage = 0;
info.UUID = __LINE__;
info.ExecutionFunction = "NotifyHitCallback";
info.CallbackTarget = this;
isPrimed = true;
UKismetSystemLibrary::Delay(GetWorld(), 0.5f, info);
}
}
}
void ATargetStaticMeshActor::MoveCallback()
{
direction *= -1;
}
void ATargetStaticMeshActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
AddActorLocalOffset(UKismetMathLibrary::Normal(direction) * DeltaTime * 200);
FLatentActionInfo info;
info.Linkage = 0;
info.UUID = __LINE__;
info.ExecutionFunction = "MoveCallback";
info.CallbackTarget = this;
UKismetSystemLibrary::Delay(GetWorld(), 3, info);
}