【目标】
攻击时的骨骼控制
【思路】
1 武器骨骼碰撞时要受碰撞面影响
2 参考FootPlaceMent的机制
3 AUDKPawn.DoFootPlacement
4 为
5
问题:
1)如何确定射线方向
作为参数
2)是否需要三个方向的射线(XYZ轴)
方案:
1 每帧Tick检测碰撞的结果,碰撞的结果影响骨骼位置
2
方案2:
1 USkelControlAttack.CalculateNewBoneTransforms中,从当前骨骼上面找两块骨骼,分别为End Mid Start(Start为最上面的)
2 计算最上面Start到End方向上的射线检测,碰撞的点就是当前
【问题】骨骼的方向并不一定是武器下落时的方向,一般情况应是骨骼方向的垂直方向
所以在原方向上要有旋转
3 如果用碰撞体?
4 【问题】
如果碰撞到设置骨骼位置,只影响一块骨骼就会出现
如何约束骨骼的旋转
可以采用一根骨骼的方法
5 【问题】
武器没有AnimTree,需要手动添加上去
USkeletalMeshComponent.Animations
是配置到USkeletonMesh上,还是在代码中设置?
6 【问题】
如果检测的结果在正面和反面
就会出现
7
【步骤】
1 新建DevelopmentSrcEngineClassesSkelControlHitPlacement.uc
hidecategories(Effector)
native(Anim);
cpptext
{
// USkelControlBase interface
virtual void CalculateNewBoneTransforms(INT BoneIndex, USkeletalMeshComponent* SkelComp, TArray<FBoneAtom>& OutBoneTransforms);
}
defaultproperties
{
}
编译
2 添加USkelControlHitPlacement.CalculateNewBoneTransforms
{
check(BoneIndex != 0);
INT LowerLimbIndex = SkelComp->SkeletalMesh->RefSkeleton(BoneIndex).ParentIndex;
check(LowerLimbIndex != 0);
INT UpperLimbIndex = SkelComp->SkeletalMesh->RefSkeleton(LowerLimbIndex).ParentIndex;
// Find the root and end position in world space.
FVector RootPos = SkelComp->SpaceBases(UpperLimbIndex).GetOrigin();
FVector WorldRootPos = SkelComp->LocalToWorld.TransformFVector(RootPos);
FVector EndPos = SkelComp->SpaceBases(BoneIndex).GetOrigin();
FVector WorldEndPos = SkelComp->LocalToWorld.TransformFVector(EndPos);
FVector LegDelta = WorldEndPos - WorldRootPos;
FVector LegDir = LegDelta.SafeNormal();
FMatrix WorldMatrix = SkelComp->SpaceBases(BoneIndex).ToMatrix() * SkelComp->LocalToWorld;
LegDir = WorldMatrix.TransformNormal(GetAxisDirVector(AXIS_X,false).SafeNormal());
FVector CheckEndPos = WorldEndPos + (1000.f) * LegDir;
FVector HitLocation, HitNormal;
UBOOL bHit = SkelComp->LegLineCheck( WorldRootPos, CheckEndPos, HitLocation, HitNormal);
AActor* Owner = SkelComp->GetOwner();
if(bHit)
{
EffectorLocation = HitLocation;
}
else
EffectorLocation = WorldEndPos;
EffectorLocationSpace = BCS_WorldSpace;
Super::CalculateNewBoneTransforms(BoneIndex, SkelComp, OutBoneTransforms);
check(OutBoneTransforms.Num() == 3);
if( Owner )
{
Owner->DrawDebugLine(WorldRootPos,CheckEndPos,255,0,0);
Owner->DrawDebugPoint(EffectorLocation,10,FLinearColor(255,255,0));
}
}
3 调整射线方向 脚骨骼的Z轴方向
绿色点为起点 黄色点为检测到的碰撞点
4 添加属性DevelopmentSrcEngineClassesSkelControlHitPlacement.uc
相应的C++
【问题】
目前只有剑尖有检测,调整的是剑尖的骨骼位置
如果需要中部骨骼检测,再调整体的旋转怎么办?
【问题】
细红线为射线,方向有可能两边,交点法线方向
所以,用射线和交点法线方向决定不了骨骼是否碰撞了面
方案1:
减少射线长度,减少误差,
就会出现很近才能检测到结果,
方案2:
交点到骨骼的方向和交点法线方向 (还是不能确定)
方案3
骨骼A到B的射线检测,如果有交点且红色射线也检测到交点,说明真正有交点
A和B如果都在物体中呢,AB的射线长度多少呢?
方案4
采取A到C的射线检测,和红色射线检测来共同决定
5
{
check(BoneIndex != 0);
INT LowerLimbIndex = SkelComp->SkeletalMesh->RefSkeleton(BoneIndex).ParentIndex;
check(LowerLimbIndex != 0);
INT UpperLimbIndex = SkelComp->SkeletalMesh->RefSkeleton(LowerLimbIndex).ParentIndex;
// Find the root and end position in world space.
FVector RootPos = SkelComp->SpaceBases(UpperLimbIndex).GetOrigin();
FVector WorldRootPos = SkelComp->LocalToWorld.TransformFVector(RootPos);
FVector EndPos = SkelComp->SpaceBases(BoneIndex).GetOrigin();
FVector WorldEndPos = SkelComp->LocalToWorld.TransformFVector(EndPos);
FVector LegDelta = WorldEndPos - WorldRootPos;
FVector LegDir = LegDelta.SafeNormal();
FMatrix WorldMatrix = SkelComp->SpaceBases(BoneIndex).ToMatrix() * SkelComp->LocalToWorld;
LegDir = WorldMatrix.TransformNormal(GetAxisDirVector(CheckAxis,bInvertCheckAxis).SafeNormal());
FVector CheckEndPos = WorldEndPos + CheckLineRadius * LegDir;
FVector CheckStartPos = WorldEndPos - CheckLineRadius * LegDir;
FVector HitLocation, HitNormal;
UBOOL bBoneHit = SkelComp->LegLineCheck( CheckStartPos, CheckEndPos, HitLocation, HitNormal);
FVector HitLocation2, HitNormal2;
UBOOL bBoneLineHit = SkelComp->LegLineCheck( WorldEndPos, WorldRootPos, HitLocation2, HitNormal2);
AActor* Owner = SkelComp->GetOwner();
if(bBoneHit && bBoneLineHit)
{
EffectorLocation = HitLocation;
}
else
EffectorLocation = WorldEndPos;
EffectorLocationSpace = BCS_WorldSpace;
Super::CalculateNewBoneTransforms(BoneIndex, SkelComp, OutBoneTransforms);
check(OutBoneTransforms.Num() == 3);
if( Owner )
{
Owner->DrawDebugLine(CheckStartPos,CheckEndPos,255,0,0);
Owner->DrawDebugPoint(EffectorLocation,10,FLinearColor(255,255,0));
Owner->DrawDebugPoint(WorldRootPos,8,FLinearColor(0,0,255));
Owner->DrawDebugPoint(CheckEndPos,8,FLinearColor(0,255,255));
Owner->DrawDebugPoint(CheckStartPos,8,FLinearColor(0,255,0));
}
}
6