新建一个对象通道
打开CoopGame.h,添加一个值
#define COLLISION_WEAPON ECC_GameTraceChannel1
然后在fire函数的该弹道函数里换上该参数
======================================
给武器类添加一个基础伤害成员变量
//基础伤害
UPROPERTY(EditDefaultsOnly, Category = "Weapon")
float BaseDamage;
在构造函数中,初始化
BaseDamage = 20;
继续完善一下fire函数
void ASWeapen::Fire()
{
//创建一个撞击句柄,用来获取弹道相关信息
FHitResult Hit;
//弹道的起点,我们设置为角色眼睛的位置
AActor * MyOwner = GetOwner();
if (MyOwner)
{ //位置
FVector EyeLocation;
//方向
FRotator EyeRotator;
//得到眼睛的位置和角度
MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotator);
//弹道的终点就是起点+方向*10000
FVector TraceEnd = EyeLocation + (EyeRotator.Vector() * 1000);
//弹道特效的结束点
FVector TraceEndPoint = TraceEnd;
//设置碰撞通道为可见性通道
FCollisionQueryParams QueryParams;
//让射线忽略玩家和枪
QueryParams.AddIgnoredActor(MyOwner);
QueryParams.AddIgnoredActor(this);
//符合追踪设为true,可以让射击更加精准
QueryParams.bTraceComplex = true;
//返回命中目标的表面材质
QueryParams.bReturnPhysicalMaterial = true;
//在创建一个单轨迹线来计算弹道
//LineTraceSingleByChannel击中物体返回true
if (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, COLLISION_WEAPON, QueryParams))
{
//命中对象
AActor * HitActor = Hit.GetActor();
//实际的伤害
float ActualDamage = BaseDamage;
//得到命中物体表面材质
EPhysicalSurface SurfaceType = UPhysicalMaterial::DetermineSurfaceType(Hit.PhysMaterial.Get());
//如果命中的是头部表面材质,伤害变成四倍
if (SurfaceType == SURFACE_FLESHVULNERABLE)
{
ActualDamage *= 4;
}
//调用伤害函数
//参数分别为伤害对象、基础伤害、设计方向、命中信息(命中句柄)、MyOwner->GetInstigatorController(暂时不了解)
//this(伤害者) 和伤害类型
UGameplayStatics::ApplyPointDamage(HitActor, ActualDamage, EyeRotator.Vector(), Hit, MyOwner->GetInstigatorController(), this, DamageType);
//根据材质的不同,进行不同的处理
UParticleSystem * SelectedEffect = nullptr;
switch (SurfaceType)
{
//这两种情况是一个效果
case SURFACE_FLESHDEFAULT:
case SURFACE_FLESHVULNERABLE:
SelectedEffect = FleshImpactEffect;
break;
default:
SelectedEffect = DefaultImpactEffect;
break;
}
//生成特效在命中点
//ImpactEffect:特效 ImpactPoint:打击点 Rotation():打击方向
if (SelectedEffect)
{
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), SelectedEffect, Hit.ImpactPoint, Hit.ImpactNormal.Rotation());
}
//命中的时候,修改弹道特效的终点
TraceEndPoint = Hit.ImpactPoint;
}
//方便debug
DrawDebugLine(GetWorld(), EyeLocation, TraceEnd, FColor::Red, false, 1, 0, 1);
//射击特效
PlayFireEffects(TraceEndPoint);
}
}
为了验证,其伤害效果,我们在靶子的蓝图编辑事件
测试
====================================
武器类里面声明两个函数
//开始射击函数
void StartFire();
//停止设计函数
void StoptFire();
再声明几个变量
//计时器句柄
FTimerHandle TimerHandle_TimeBetweenShots;
//上次开火时间点
float FireLastTime;
//开火的频率,每分钟多少枪
UPROPERTY(EditDefaultsOnly, Category = "Weapon")
float RateOfFire;
//开火的间隔时间
float TimeBetweenShots;
在构造函数中初始化RateOfFire
RateOfFire = 600;
然后在游戏开始函数里,算得开火间隔
// Called when the game starts or when spawned
void ASWeapen::BeginPlay()
{
Super::BeginPlay();
TimeBetweenShots = 60 / RateOfFire;
}
在fire函数的最下面,记录最后开火的时间
void ASWeapen::Fire()
{
//创建一个撞击句柄,用来获取弹道相关信息
FHitResult Hit;
//弹道的起点,我们设置为角色眼睛的位置
AActor * MyOwner = GetOwner();
if (MyOwner)
{ //位置
FVector EyeLocation;
//方向
FRotator EyeRotator;
//得到眼睛的位置和角度
MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotator);
//弹道的终点就是起点+方向*10000
FVector TraceEnd = EyeLocation + (EyeRotator.Vector() * 1000);
//弹道特效的结束点
FVector TraceEndPoint = TraceEnd;
//设置碰撞通道为可见性通道
FCollisionQueryParams QueryParams;
//让射线忽略玩家和枪
QueryParams.AddIgnoredActor(MyOwner);
QueryParams.AddIgnoredActor(this);
//符合追踪设为true,可以让射击更加精准
QueryParams.bTraceComplex = true;
//返回命中目标的表面材质
QueryParams.bReturnPhysicalMaterial = true;
//在创建一个单轨迹线来计算弹道
//LineTraceSingleByChannel击中物体返回true
if (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, COLLISION_WEAPON, QueryParams))
{
//命中对象
AActor * HitActor = Hit.GetActor();
//实际的伤害
float ActualDamage = BaseDamage;
//得到命中物体表面材质
EPhysicalSurface SurfaceType = UPhysicalMaterial::DetermineSurfaceType(Hit.PhysMaterial.Get());
//如果命中的是头部表面材质,伤害变成四倍
if (SurfaceType == SURFACE_FLESHVULNERABLE)
{
ActualDamage *= 4;
}
//调用伤害函数
//参数分别为伤害对象、基础伤害、设计方向、命中信息(命中句柄)、MyOwner->GetInstigatorController(暂时不了解)
//this(伤害者) 和伤害类型
UGameplayStatics::ApplyPointDamage(HitActor, ActualDamage, EyeRotator.Vector(), Hit, MyOwner->GetInstigatorController(), this, DamageType);
//根据材质的不同,进行不同的处理
UParticleSystem * SelectedEffect = nullptr;
switch (SurfaceType)
{
//这两种情况是一个效果
case SURFACE_FLESHDEFAULT:
case SURFACE_FLESHVULNERABLE:
SelectedEffect = FleshImpactEffect;
break;
default:
SelectedEffect = DefaultImpactEffect;
break;
}
//生成特效在命中点
//ImpactEffect:特效 ImpactPoint:打击点 Rotation():打击方向
if (SelectedEffect)
{
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), SelectedEffect, Hit.ImpactPoint, Hit.ImpactNormal.Rotation());
}
//命中的时候,修改弹道特效的终点
TraceEndPoint = Hit.ImpactPoint;
}
//方便debug
DrawDebugLine(GetWorld(), EyeLocation, TraceEnd, FColor::Red, false, 1, 0, 1);
//射击特效
PlayFireEffects(TraceEndPoint);
//最后开火的时间
FireLastTime = GetWorld()->TimeSeconds;
}
}
实现这两个函数
void ASWeapen::StartFire()
{
float FirstDelay = FMath::Max(0.0f, FireLastTime + TimeBetweenShots - GetWorld()->TimeSeconds);
GetWorldTimerManager().SetTimer(TimerHandle_TimeBetweenShots, this, &ASWeapen::Fire, TimeBetweenShots, true, FirstDelay);
}
void ASWeapen::StoptFire()
{
GetWorldTimerManager().ClearTimer(TimerHandle_TimeBetweenShots);
}
然后在玩家类里也声明两个函数
//开始射击函数
void StartFire();
//停止设计函数
void StoptFire();
之前的fire函数就不要了
然后定义函数
void ASCharacter::StartFire()
{
if (CurrentWeapen1)
{
CurrentWeapen1->StartFire();
}
}
void ASCharacter::StoptFire()
{
if (CurrentWeapen1)
{
CurrentWeapen1->StoptFire();
}
}
绑定开火
//开火
PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ASCharacter::StartFire);
PlayerInputComponent->BindAction("Fire", IE_Released, this, &ASCharacter::StoptFire);