斯坦福UE4 + C++课学习记录 5:实现发射粒子

一、创建魔法粒子

  1. 创建投掷物类,.h中添加三个用于计算碰撞和显示特效的组件,在.cpp中创建实例:
  2. 球体组件USphereComponent用于计算碰撞;投掷物类有专门的运动组件UProjectileMovementComponent,显示各种特效需要粒子系统UParticleSystemComponent
  3. 关于抛体组件:(源码很长就不引用了)
  • 计算逻辑:
    ① 抛体运动,受重力加速度影响(当然也可以设置不受重力影响,就更简单了),匀变速运动公式:V = V0+ a*t 得出 a = (V - V0)/t
    ② 移动组件要计算每一帧的位置,则需要计算出每帧需要做多少位移。匀变速运动的位移公式:S = V*t + 1/2 *a * t^2得出x = V0*t + 1/2*(V - V0) * t
    ③ 最后根据算出的MoveDelta,通过UProjectileMovementComponent::MoveUpdatedComponent方法赋给SceneComponent,。
    4.关于bInitialVelocityInLocalSpace:是一个布尔类型的属性,用于控制初始速度的参考系。具体来说,它决定了初始速度是在物体的本地空间中还是在世界空间中定义的。
  • 本地空间Local Space:相对于物体自身的坐标系。也就是说,初始速度的方向和大小是基于物体自身的方向和旋转。
  • 世界空间World Space:相对于整个世界的坐标系。也就是说,初始速度的方向和大小是基于整个世界的固定坐标系。

再举个例子:
假设有一个火箭,我们设置它的初始速度设置为(100, 0, 0)。
(1)bInitialVelocityInLocalSpace = true

  • 火箭的初始速度相对于它自身的朝向。如果火箭面向世界的X轴方向(正前方),那么它将以(100, 0, 0)的速度向前移动。如果火箭旋转90度面向世界的Y轴方向,那么它将以(0, 100, 0)的速度向前移动。

(2)bInitialVelocityInLocalSpace = false

  • 火箭的初始速度相对于世界坐标系固定,不论火箭的朝向如何变化。无论火箭面向哪个方向,它的初始速度始终为(100, 0, 0),即始终沿世界的X轴方向移动。
  • SurMagicProjectile.h
// SurMagicProjectile.h
class USphereComponent;
class UProjectileMovementComponent;
class UParticleSystemComponent;

UCLASS()
class SURKEAUE_API ASurMagicProjectile : public AActor
{
protected:

	// 球体,用于计算碰撞
	UPROPERTY(VisibleAnywhere)
	USphereComponent* SphereComp;
	// 投射体,控制球体的运动
	UPROPERTY(VisibleAnywhere)
	UProjectileMovementComponent* MovementComp;
	// 粒子系统,控制特效
	UPROPERTY(VisibleAnywhere)
	UParticleSystemComponent* EffectComp;
}; 
  • SurMagicProjectile.cpp
// SurMagicProjectile.cpp
#include "Components/SphereComponent.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Particles/ParticleSystemComponent.h"

ASurMagicProjectile::ASurMagicProjectile()
{
    SphereComp = CreateDefaultSubobject<USphereComponent>("SphereComp");
	RootComponent = SphereComp;

	MovementComp = CreateDefaultSubobject<UProjectileMovementComponent>("MovementComp");
	MovementComp->InitialSpeed = 1000.0f;
	MovementComp->bRotationFollowsVelocity = true;
	MovementComp->bInitialVelocityInLocalSpace = true;

	EffectComp = CreateDefaultSubobject<UParticleSystemComponent>("EffectComp");
	EffectComp->SetupAttachment(SphereComp);
} 
  1. 在UE中创建蓝图类 ,为MagicProjectile类在粒子系统控件EffectComp的“粒子”属性中模板

二、控制粒子生成

  1. SetupPlayerInputComponent()函数中绑定一个新动作。对于按下按钮这种动作需要使用操作绑定,即BindAction()函数
// 绑定按键动作("UE中调用的名称";触发的时机如按下或释放;对象;具体方法实现)
PlayerInputComponent->BindAction("PrimaryAttack", IE_Pressed, this, &ASurCharacter::PrimaryAttack); 
  1. 增加一个控制释放攻击的函数PrimaryAttack()。这个函数的核心是GetWorld()在当前世界下SpawnActor()来生成上面创建的魔法粒子。其中传入三个对象参数分别为:要生成的对象的class、所有Actor基本的Transform变换属性(控制Actor的位置和缩放)、生成的相关参数设置
    在这里插入图片描述
void ASurCharacter::PrimaryAttack() {
	// Spawn Transform Matrix,spawn的变换矩阵
	// 朝向角色方向,在角色的中心位置生成
	FTransform SpawnTM = FTransform(GetActorRotation(),GetActorLocation());

	// 参数设置。
    // 此处设置碰撞检测规则为:即使碰撞也总是生成,因为粒子在角色中间生成必然碰撞
	FActorSpawnParameters SpawnParams;
	SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;

	// 所有能放置或生成的对象都是Actor
	GetWorld()->SpawnActor<AActor>(ProjectileClass, SpawnTM, SpawnParams);
} 
  1. 传入SpawnActor()的第一个参数是ProjectileClass,这是一个需要在.h定义的AActor子类。同时,利用UPROPERTY宏定义将其暴露在UE中,这样就可以在Player蓝图类的细节面板中,像选择参数那样直接选择MagicProjection实例进行调用。
  2. TSubclassOf<AActor> 是什么?
  • TSubclassOf 是一种模板类,它允许你在 C++ 中存储一个类的子类类型。代码中的TSubclassOf<AActor> 表示可以存储任何 AActor 的子类。这种类型的变量通常用于动态创建对象,因为它可以在运行时指定要创建的具体子类。
  • 允许在蓝图中指定要生成的具体投射体类,而不是硬编码在 C++ 代码中。
UCLASS()
class SURKEAUE_API ASurCharacter : public ACharacter
{
protected:
    // 投射体子类
	UPROPERTY(EditAnywhere)
	TSubclassOf<AActor> ProjectileClass;

	void PrimaryAttack();
}; 
  1. 打开UE,将PrimaryAttack绑定为鼠标左键;同时将Character中的ProjectileClass选择为第一步创建的蓝图类MagicProjectile。

三、更改粒子发射位置

  1. 最佳的攻击演出效果,应该是从角色的手掌发出,所以首先需要找到骨骼体模型中手的位置。双击Player使用的网格体可以打开Gideon的模型,再点击右上角可以切换为骨骼。界面左侧会出现所有的骨骼和Socket,可以找到角色右手的位置为Muzzle_01,即为枪口位置。
  2. 获取枪口位置,修改之前的代码
// 获取模型右手位置
	FVector RightHandLoc  = GetMesh()->GetSocketLocation("Muzzle_01");

	// Spawn Transform Matrix, spawn的变换矩阵
	// 朝向角色方向,在角色的右手位置生成
	FTransform SpawnTM = FTransform(GetActorRotation(), RightHandLoc);

四、实现物理碰撞

  1. 首先,将MagicProjectileMovementComp组件的“发射重力范围”设置为0,(我当时设置了还是会下落,不知道为什么,最后是在C++中加的代码)这样发射的粒子可以不收重力下落而保持直线运动。然后在项目设置 -> 碰撞 -> Preset中新建名为“Projectile”的配置,用于魔法粒子碰撞检测。 (这里可以自定义自己的碰撞文件,之后可直接引用)
  2. 然后在MagicProjectile中的“碰撞”属性中设置使用该配置,或者直接使用如下C++代码实现:
SphereComp->SetCollisionProfileName("Projectile"); 
  • 21
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值