近期研究了GameplayAbilities框架,写个简单的可以用于Dedicated Server的技能系统,其中最先研究的就像类似火球术或冰枪类似的技能。在Abilities框架里,这种技能只要播放一个蒙太奇,在指定的动作帧里,在指定的骨骼槽点位置创建一个发射物的Actor,通过Actor本身和Actor的运动组件的同步,就可以将这个子弹同步给所有玩家。
但是,我们如果只是取玩家向前的朝向,并不一定保证发射物能飞向自己的屏幕准星。屏幕准星实际是绘制的我们角色摄像机正方向延伸出的一条射线。而且火球术这种技能,可能在玩家的某个动作中,在左手或右手发出。这样我们需要一个函数,输入就是发射物的起点,返回值就是发射物的行进方向。
假设我们子弹的射程为100米(可以设置为一个变量),然后我们需要给发射物建立一个碰撞通道,碰撞通道如果不理解可以到官方wiki上研究下。如果在我摄像机为起点的这条射线中,我们检测到了子弹能Hit到的障碍物,那我们就把子弹的终点设置为碰撞点。否则就是射线的射程到达的终点位置。这样我们就确定了子弹的终点。见下面大概的示意图。
上图中假设发射物是从玩家左手发出,如果我们的准星射线没有扫描到障碍物,那么终点就会是最大射程位置,发射物的轨迹将如红线所示。如果中间有障碍物,我们的射线将返回一个子弹通道的撞击点,这个撞击点将是子弹终点位置,发射物运动轨迹将如图中绿线所示。
那么重点就是这个函数,代码大概实现如下:
// 获取一个发射子弹的运动方向
UFUNCTION(BlueprintPure, Category = Ability)
static FRotator GetProjectileDir(ASMyCharacter* User, FVector StartP);
// 获取一个发射子弹的运动方向
FRotator USGASBlueprintLibrary::GetProjectileDir(ASMyCharacter* User, FVector StartP)
{
// 保护
FRotator FinalRotator = FRotator::ZeroRotator;
if (User == nullptr)
{
return FinalRotator;
}
UCameraComponent* CameraComp = nullptr;
ASMyCharacter* PlayerChar = Cast<ASMyCharacter>(User);
if (PlayerChar != nullptr)
{
CameraComp = PlayerChar->CameraComp;
}
if (CameraComp == nullptr)
{
return FinalRotator;
}
// 分类计算子弹方向
ASPlayerController* PC = Cast<ASPlayerController>(User->GetController());
if (PC != nullptr)
{
// 先做一次射线Trace碰撞点(现在假定射程最大为100米)
FVector TStartP = CameraComp->GetComponentLocation();
FVector TEndP = TStartP + CameraComp->GetForwardVector() * 10000.0f;
FVector EndP = TEndP;
FCollisionQueryParams QueryParams;
QueryParams.AddIgnoredActor(User);
QueryParams.bTraceComplex = true;
FHitResult HitRes;
if (User->GetWorld()->LineTraceSingleByChannel(HitRes, TStartP, TEndP,
COLLISION_PROJECTILE, QueryParams))
{
EndP = HitRes.ImpactPoint;
}
// 计算子弹的行进方向
FinalRotator = UKismetMathLibrary::FindLookAtRotation(StartP, EndP);
}
return FinalRotator;
}
代码如上,因为是可以支持蓝图调用的,而GameplayAbilities技能基本都是蓝图实现。我再蓝图中创建发射物并确定发现的蓝图片段如下:发射物在玩家骨骼上指定的槽点发射出,一定会打到准星瞄准的位置上。
DEMO中测试效果图如下,第一张是瞄准了一个障碍物,冰弹集中障碍物并爆炸:
第二张图是准星没有瞄准到任何障碍物,冰弹飞向最大射程后消失:
所有记录都是支持Dedicated Server模式下,已经做好服务器和客户端表现同步的。这次就先随笔结束。