入门UE4没多久,看了一些网上的教程,留下一些笔记,TPS射击问题在与我们可以看到整个人物,如果我们开枪,我们期望的是从枪口发射子弹,射击的目标坐标在屏幕准星对准的位置。有些教程直接从摄像机发射一条射线,如果击中了就不再做其它判断了,这会导致一个问题。
从角色枪口射出来的子弹会发生穿墙的问题。所以应该再从角色枪口在发射一条射线做判断是否被阻碍下来。可是这中间也存在一个问题。
角色-怪物-摄像机这三点之间存在一个角度问题,而且如果怪物的距离越远就角度越小,怪物越近就角度越大。如果不解决这个问题从枪口发射出来的子弹怎么也击中不了准心瞄准的怪物位置。
所以思路基本上是先从摄像机发射一条射线,当射线击中怪物时,记下击中的坐标。然后由枪口再发射一条射线,终点为摄像机射线击中怪物时记下的坐标。这样刚好可以解决这个问题。
在UE4中,使用LineTraceSingleByChannel发射射线检测。
FVector EyesStartLocation; //玩家角色眼睛的位置,不是摄像机的位置。我这里用眼睛代替枪口位置,个人认为枪口和眼睛不一定在一个Z轴高度,如果硬要从枪口射出射线你在掩体后面露出了头部却打中的是掩体这很尴尬。
FVector EyesEndLocation; //摄像机射线的终点
FRotator ViewRotation; //人物当前的角度
FVector CameraLocation; //摄像机的位置
GetOwner()->GetActorEyesViewPoint(EyesStartLocation, ViewRotation);
EyesEndLocation = CameraLocation + ViewRotation.Vector() * 999999.0f;
FCollisionQueryParams Params;
//忽略Possess持有者
Params.AddIgnoredActor(GetOwner());
//忽略自身
Params.AddIgnoredActor(this);
//检测复杂碰撞
Params.bTraceComplex = true;
//击中的物理材质检测
Params.bReturnPhysicalMaterial = true;
FHitResult CameraHit;
//发射摄像机射线,ECC_Monster是我自己创建的碰撞通道
if (GetWorld()->LineTraceSingleByChannel(CameraHit, CameraLocation, EyesEndLocation, ECC_Monster, Params))
{
AMonsterCharacter* Monster = Cast<AMonsterCharacter>(CameraHit.GetActor());
if (Monster)
{
//摄像机的射线击中了怪物
FHitResult MonsterHit;
//从枪口发射射线,注意这里不一定能击中怪物,哪怕射线到达了目标位置CameraHit.ImpactPoint,所以后面判断有没有击中使用距离判断
if (GetWorld()->LineTraceSingleByChannel(MonsterHit, EyesStartLocation, CameraHit.ImpactPoint, ECC_Monster, Params))
{
//判断射线是否被阻挡下来
if ((MonsterHit.ImpactPoint - CameraHit.ImpactPoint).Size() <= 0.5f)
{
//怪物被击中,这里做伤害处理
}
else
{
//射线被阻碍物阻挡下来
}
}
else
{
//没有击中任何东西,那代表沿着射线路径没有阻碍物,这次发射的射线到达终点,也应当认为击中怪物了
//怪物被击中,这里做伤害处理
}
}
else
{
//摄像机发射的射线没有击中怪物
}
}
else
{
//摄像机发射的射线击中了其它东西
}