Hi,
I am trying to make an arch to display an object trajectory when throwing it. For that I am using Predict Projectile Path to do this, however I am having a couple of issues.
One is I am having trouble to display it correctly on screen. It does not looks like an arch and is not really predicting very well where the object will fall. Bellow is the code I am using to predict the path, throw the object and display using spline:
UTP_ThrowableItemComponent::UTP_ThrowableItemComponent()
{
TrajectorySpline = CreateDefaultSubobject<USplineComponent>(TEXT("TrajectorySpline"));
TrajectorySpline->SetupAttachment(this);
TrajectorySpline->SetMobility(EComponentMobility::Movable);
}
void UTP_ThrowableItemComponent::StartChargingThrow()
{
if (Character == nullptr)
{
UE_LOG(LogTemp, Error, TEXT("Character is null whe trying to throw item"));
return;
}
UE_LOG(LogTemp, Warning, TEXT("Start Throw item"));
CurrentChargeTime = 0.0f;
GetWorld()->GetTimerManager().SetTimer(ChargeTimerHandle, this, &UTP_ThrowableItemComponent::ChargeTick, 0.1f, true);
GetWorld()->GetTimerManager().SetTimer(UpdateArcTimerHandle, this, &UTP_ThrowableItemComponent::UpdateThrowArc, 0.1f, true);
}
void UTP_ThrowableItemComponent::ReleaseThrow()
{
GetWorld()->GetTimerManager().ClearTimer(ChargeTimerHandle);
GetWorld()->GetTimerManager().ClearTimer(UpdateArcTimerHandle);
ClearThrowArc();
UE_LOG(LogTemp, Warning, TEXT("Release Throw item"));
DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform);
SetSimulatePhysics(true);
float ThrowStrength = FMath::Lerp(MinThrowStrength, MaxThrowStrength, CurrentChargeTime / MaxChargeTime);
FVector ForwardVector = Character->GetControlRotation().Vector();
FVector Impulse = ForwardVector * ThrowStrength;
AddImpulse(Impulse, NAME_None, true);
DrawDebugLine(GetWorld(), GetComponentLocation(), GetComponentLocation() + Impulse, FColor::Green, false, 2.0f, 0, 5.0f);
RemoveThrowableMappingContext();
Character->SetWeaponHidden(false);
Character->SetCanSwitchWeapon(true);
}
void UTP_ThrowableItemComponent::ChargeTick()
{
CurrentChargeTime = FMath::Min(CurrentChargeTime + 0.1f, MaxChargeTime);
}
void UTP_ThrowableItemComponent::UpdateThrowArc()
{
//TrajectoryPoints.Empty();
ClearThrowArc();
float ThrowStrength = FMath::Lerp(MinThrowStrength, MaxThrowStrength, CurrentChargeTime / MaxChargeTime);
FVector ForwardVector = Character->GetControlRotation().Vector();
FVector Impulse = ForwardVector * ThrowStrength;
FPredictProjectilePathParams PredictParams;
PredictParams.StartLocation = Character->GetActorLocation(); //GetComponentLocation(); //Character->GetActorLocation(); // *100.0f;
PredictParams.LaunchVelocity = Impulse;
PredictParams.bTraceWithCollision = true;
//PredictParams.bTraceComplex = false;
//PredictParams.ProjectileRadius = 10.0f;
PredictParams.MaxSimTime = 1.0f;
PredictParams.SimFrequency = 13.f;
TArray<AActor> ActorsToIgnore;
PredictParams.ActorsToIgnore.Add(Character);
PredictParams.ActorsToIgnore.Add(this->GetOwner());
//PredictParams.OverrideGravityZ = -980.f; // Default value
FPredictProjectilePathResult PredictResult;
if (UGameplayStatics::PredictProjectilePath(GetWorld(), PredictParams, PredictResult))
{
for (const FPredictProjectilePathPointData& PointData : PredictResult.PathData)
{
//TrajectoryPoints.Add(PointData.Location);
TrajectorySpline->AddSplinePoint(PointData.Location, ESplineCoordinateSpace::World);
//Character->AddPointToSpline(PointData.Location);
}
}
//Character->UpdateSplineMeshes();
UpdateSplineMeshes();
}
void UTP_ThrowableItemComponent::ClearThrowArc()
{
//TODO: issue where following uses are getting clear without even showing in screen
UE_LOG(LogTemp, Warning, TEXT("Call clear"));
// Remove all spline meshes
TArray<USceneComponent*> AttachedComponents;
TrajectorySpline->GetChildrenComponents(false, AttachedComponents);
for (USceneComponent* Component : AttachedComponents)
{
UE_LOG(LogTemp, Warning, TEXT("Going to try to clear"));
if (USplineMeshComponent* SplineMeshComp = Cast<USplineMeshComponent>(Component))
{
UE_LOG(LogTemp, Warning, TEXT("Going to call destroy"));
SplineMeshComp->DestroyComponent();
}
}
TrajectorySpline->ClearSplinePoints();
}
void UTP_ThrowableItemComponent::UpdateSplineMeshes()
{
if (!SplineMesh || !SplineMaterial)
{
return;
}
//ClearThrowArc();
int32 NumPoints = TrajectorySpline->GetNumberOfSplinePoints();
UE_LOG(LogTemp, Warning, TEXT("Number of spline points: %d"), NumPoints);
for (int i = 0; i < NumPoints - 2; i++)
{
FVector StartLocation, StartTangent;
FVector EndLocation, EndTangent;
TrajectorySpline->GetLocationAndTangentAtSplinePoint(i, StartLocation, StartTangent, ESplineCoordinateSpace::World);
TrajectorySpline->GetLocationAndTangentAtSplinePoint(i + 1, EndLocation, EndTangent, ESplineCoordinateSpace::World);
FVector EndLocationLerp = FMath::Lerp(StartLocation, EndLocation, 0.5f);
FVector EndTangentLerp = FMath::Lerp(StartTangent, EndTangent, 0.5f);
USplineMeshComponent* SplineMeshComp = NewObject<USplineMeshComponent>(TrajectorySpline);
if (SplineMeshComp)
{
SplineMeshComp->SetCollisionEnabled(ECollisionEnabled::NoCollision);
SplineMeshComp->SetMobility(EComponentMobility::Movable);
SplineMeshComp->SetStaticMesh(SplineMesh);
SplineMeshComp->SetMaterial(0, SplineMaterial);
SplineMeshComp->RegisterComponent();
SplineMeshComp->AttachToComponent(TrajectorySpline, FAttachmentTransformRules::KeepRelativeTransform);
SplineMeshComp->SetStartAndEnd(StartLocation, EndLocationLerp, StartTangent, EndTangentLerp);
}
}
}
This is how it looks on screen:
Another issue that I am having is that I am only getting to the predict path to show what is in the image above the first time, if I pickup another object and try to throw it it will not show anything. If I remove ClearThrowArc() from UpdateThrowArc() it does show, but when I do that it creates many instance of the spline and complete fills the screen with it.
I would appreciate any help with this, thanks in advance!