FVector2D FSingleTileEditorViewportClient::WorldSpaceToTextureSpace(const FVector& SourcePoint) const { const FVector ProjectionX = SourcePoint.ProjectOnTo(PaperAxisX); const FVector ProjectionY = -SourcePoint.ProjectOnTo(PaperAxisY); const float XValue = FMath::Sign(ProjectionX | PaperAxisX) * ProjectionX.Size(); const float YValue = FMath::Sign(ProjectionY | PaperAxisY) * ProjectionY.Size(); return FVector2D(XValue, YValue); }
float AGGJ16_Player::TakeDamage(float DamageAmount, struct FDamageEvent const &DamageEvent, class AController* EventInstigator, AActor* DamageCauser) { if (!bDamaged) { health -= DamageAmount; } if (health <= 0) { playDeathAnim = true; } else { bDamaged = true; } if (DamageCauser) { FVector curForwardVector = DamageCauser->GetActorLocation() - this->GetActorLocation(); curForwardVector.ProjectOnTo(FVector(1, 1, 0)); curForwardVector.Normalize(); LaunchCharacter(curForwardVector * KnockBackAlpha, true, true); } return 0.f; //do the pretty things };
FVector2D FSingleTileEditorViewportClient::SelectedItemConvertWorldSpaceDeltaToLocalSpace(const FVector& WorldSpaceDelta) const { const FVector ProjectionX = WorldSpaceDelta.ProjectOnTo(PaperAxisX); const FVector ProjectionY = WorldSpaceDelta.ProjectOnTo(PaperAxisY); const float XValue = FMath::Sign(ProjectionX | PaperAxisX) * ProjectionX.Size(); const float YValue = FMath::Sign(ProjectionY | PaperAxisY) * ProjectionY.Size(); return FVector2D(XValue, YValue); }
FVector UKismetMathLibrary::ProjectVectorOnToVector(FVector V, FVector Target) { if (Target.SizeSquared() > SMALL_NUMBER) { return V.ProjectOnTo(Target); } else { FFrame::KismetExecutionMessage(TEXT("Divide by zero: ProjectVectorOnToVector with zero Target vector"), ELogVerbosity::Warning); return FVector::ZeroVector; } }
static FVector CombineAdjustments(FVector CurrentAdjustment, FVector AdjustmentToAdd) { // remove the part of the new adjustment that's parallel to the current adjustment if (CurrentAdjustment.IsZero()) { return AdjustmentToAdd; } FVector Projection = AdjustmentToAdd.ProjectOnTo(CurrentAdjustment); Projection = Projection.GetClampedToMaxSize(CurrentAdjustment.Size()); FVector OrthogalAdjustmentToAdd = AdjustmentToAdd - Projection; return CurrentAdjustment + OrthogalAdjustmentToAdd; }
FVector UKismetMathLibrary::ProjectOnTo(FVector X, FVector Y) { return X.ProjectOnTo( Y ); }
void UPaperTileMapComponent::RebuildRenderData(FPaperTileMapRenderSceneProxy* Proxy) { TArray<FSpriteDrawCallRecord> BatchedSprites; if (TileMap == nullptr) { return; } FVector CornerOffset; FVector OffsetYFactor; FVector StepPerTileX; FVector StepPerTileY; TileMap->GetTileToLocalParameters(/*out*/ CornerOffset, /*out*/ StepPerTileX, /*out*/ StepPerTileY, /*out*/ OffsetYFactor); UTexture2D* LastSourceTexture = nullptr; FVector TileSetOffset = FVector::ZeroVector; FVector2D InverseTextureSize(1.0f, 1.0f); FVector2D SourceDimensionsUV(1.0f, 1.0f); FVector2D TileSizeXY(0.0f, 0.0f); for (int32 Z = 0; Z < TileMap->TileLayers.Num(); ++Z) { UPaperTileLayer* Layer = TileMap->TileLayers[Z]; if (Layer == nullptr) { continue; } FLinearColor DrawColor = FLinearColor::White; #if WITH_EDITORONLY_DATA if (Layer->bHiddenInEditor) { continue; } DrawColor.A = Layer->LayerOpacity; #endif FSpriteDrawCallRecord* CurrentBatch = nullptr; for (int32 Y = 0; Y < TileMap->MapHeight; ++Y) { // In pixels FVector EffectiveTopLeftCorner; switch (TileMap->ProjectionMode) { case ETileMapProjectionMode::Orthogonal: default: EffectiveTopLeftCorner = CornerOffset; break; case ETileMapProjectionMode::IsometricDiamond: EffectiveTopLeftCorner = CornerOffset - StepPerTileX; break; case ETileMapProjectionMode::IsometricStaggered: case ETileMapProjectionMode::HexagonalStaggered: EffectiveTopLeftCorner = CornerOffset + (Y & 1) * OffsetYFactor; break; } for (int32 X = 0; X < TileMap->MapWidth; ++X) { const FPaperTileInfo TileInfo = Layer->GetCell(X, Y); // do stuff const float TotalSeparation = (TileMap->SeparationPerLayer * Z) + (TileMap->SeparationPerTileX * X) + (TileMap->SeparationPerTileY * Y); FVector TopLeftCornerOfTile = (StepPerTileX * X) + (StepPerTileY * Y) + EffectiveTopLeftCorner; TopLeftCornerOfTile += TotalSeparation * PaperAxisZ; const int32 TileWidth = TileMap->TileWidth; const int32 TileHeight = TileMap->TileHeight; { UTexture2D* SourceTexture = nullptr; FVector2D SourceUV = FVector2D::ZeroVector; if (Layer->bCollisionLayer) { if (TileInfo.PackedTileIndex == 0) { continue; } SourceTexture = UCanvas::StaticClass()->GetDefaultObject<UCanvas>()->DefaultTexture; } else { if (TileInfo.TileSet == nullptr) { continue; } if (!TileInfo.TileSet->GetTileUV(TileInfo.PackedTileIndex, /*out*/ SourceUV)) { continue; } SourceTexture = TileInfo.TileSet->TileSheet; if (SourceTexture == nullptr) { continue; } } if ((SourceTexture != LastSourceTexture) || (CurrentBatch == nullptr)) { CurrentBatch = (new (BatchedSprites) FSpriteDrawCallRecord()); CurrentBatch->Texture = SourceTexture; CurrentBatch->Color = DrawColor; CurrentBatch->Destination = TopLeftCornerOfTile.ProjectOnTo(PaperAxisZ); } if (SourceTexture != LastSourceTexture) { InverseTextureSize = FVector2D(1.0f / SourceTexture->GetSizeX(), 1.0f / SourceTexture->GetSizeY()); if (TileInfo.TileSet != nullptr) { SourceDimensionsUV = FVector2D(TileInfo.TileSet->TileWidth * InverseTextureSize.X, TileInfo.TileSet->TileHeight * InverseTextureSize.Y); TileSizeXY = FVector2D(TileInfo.TileSet->TileWidth, TileInfo.TileSet->TileHeight); TileSetOffset = (TileInfo.TileSet->DrawingOffset.X * PaperAxisX) + (TileInfo.TileSet->DrawingOffset.Y * PaperAxisY); } else { SourceDimensionsUV = FVector2D(TileWidth * InverseTextureSize.X, TileHeight * InverseTextureSize.Y); TileSizeXY = FVector2D(TileWidth, TileHeight); TileSetOffset = FVector::ZeroVector; } LastSourceTexture = SourceTexture; } TopLeftCornerOfTile += TileSetOffset; SourceUV.X *= InverseTextureSize.X; SourceUV.Y *= InverseTextureSize.Y; FSpriteDrawCallRecord& NewTile = *CurrentBatch; const float WX0 = FVector::DotProduct(TopLeftCornerOfTile, PaperAxisX); const float WY0 = FVector::DotProduct(TopLeftCornerOfTile, PaperAxisY); const FVector4 BottomLeft(WX0, WY0 - TileSizeXY.Y, SourceUV.X, SourceUV.Y + SourceDimensionsUV.Y); const FVector4 BottomRight(WX0 + TileSizeXY.X, WY0 - TileSizeXY.Y, SourceUV.X + SourceDimensionsUV.X, SourceUV.Y + SourceDimensionsUV.Y); const FVector4 TopRight(WX0 + TileSizeXY.X, WY0, SourceUV.X + SourceDimensionsUV.X, SourceUV.Y); const FVector4 TopLeft(WX0, WY0, SourceUV.X, SourceUV.Y); new (NewTile.RenderVerts) FVector4(BottomLeft); new (NewTile.RenderVerts) FVector4(TopRight); new (NewTile.RenderVerts) FVector4(BottomRight); new (NewTile.RenderVerts) FVector4(BottomLeft); new (NewTile.RenderVerts) FVector4(TopLeft); new (NewTile.RenderVerts) FVector4(TopRight); } } } } Proxy->SetBatchesHack(BatchedSprites); }
// Runs calculations on friction component, applies friction force to effected component and returns reaction forces(forces that can effect track or a wheel) void UMMTFrictionComponent::ApplyFriction(const FVector& ContactPointLocation, const FVector& ContactPointNormal, const FVector& InducedVelocity, const FVector& PreNormalForceAtPoint, const EPhysicalSurface& PhysicalSurface, const float& NumberOfContactPoints, const float& DeltaTime, FVector& NormalizedReactionForce, FVector& RollingFrictionForce) { // Gather stats SCOPE_CYCLE_COUNTER(STAT_MMTFrictionApply); float NormalForceAtContactPoint = PreNormalForceAtPoint.ProjectOnTo(ContactPointNormal).Size(); // Check if Effected Component Mesh reference is valid and escape early otherwise if (!IsValid(EffectedComponentMesh)) { GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, FString::Printf(TEXT("%s->%s component's EffectedComponentMesh reference is invalid!"), *GetOwner()->GetName(), *GetName())); UE_LOG(LogTemp, Warning, TEXT("%s->%s component's EffectedComponentMesh reference is invalid!"), *GetOwner()->GetName(), *GetName()); NormalizedReactionForce = FVector::ZeroVector; RollingFrictionForce = FVector::ZeroVector; return; } //Find relative velocity of the friction surface and ground/another object at point FVector RelativeVelocityAtPoint = EffectedComponentMesh->GetPhysicsLinearVelocityAtPoint(ContactPointLocation) + InducedVelocity + FrictionSurfaceVelocity; RelativeVelocityAtPoint = RelativeVelocityAtPoint.VectorPlaneProject(RelativeVelocityAtPoint, ContactPointNormal); //filter out oscillations when vehicle is standing still but friction overshoots RelativeVelocityAtPoint = (PrevRelativeVelocityAtPoint + RelativeVelocityAtPoint) * 0.5; PrevRelativeVelocityAtPoint = RelativeVelocityAtPoint; // early exit if velocity is too low to consider as vehicle most likely standing still if (RelativeVelocityAtPoint.Size() < 1.0f) { NormalizedReactionForce = FVector::ZeroVector; RollingFrictionForce = FVector::ZeroVector; return; } //Calculate static and kinetic friction coefficients, taking into account velocity direction and friction ellipse float MuStatic; float MuKinetic; UMMTBPFunctionLibrary::GetMuFromFrictionElipse(RelativeVelocityAtPoint.GetSafeNormal(), ReferenceFrameTransform.TransformVector(FVector(1.0f, 1.0f, 1.0f)), MuXStatic, MuXKinetic, MuYStatic, MuYKinetic, MuStatic, MuKinetic); //Calculate "stopping force" which is amount of force necessary to completely remove velocity of the object FVector StoppingForce = ((RelativeVelocityAtPoint * (-1.0f) * EffectedComponentMesh->GetMass()) / DeltaTime) / NumberOfContactPoints; //Static friction threshold float MuStaticByLoad = NormalForceAtContactPoint * MuStatic; //Friction Force that will be applied to effected mesh component FVector ApplicationForce; if (StoppingForce.Size() >= MuStaticByLoad) { ApplicationForce = StoppingForce.GetClampedToSize(0.0f, NormalForceAtContactPoint * MuKinetic); if (IsDebugMode) { DrawDebugString(GetWorld(), ContactPointLocation, FString("Kinetic Friction"), nullptr, FColor::Magenta, 0.0f, false); } } else { ApplicationForce = StoppingForce.GetClampedToSize(0.0f, MuStaticByLoad); if (IsDebugMode) { DrawDebugString(GetWorld(), ContactPointLocation, FString("Static Friction"), nullptr, FColor::Red, 0.0f, false); } } //Apply friction force UMMTBPFunctionLibrary::MMTAddForceAtLocationComponent(EffectedComponentMesh, ApplicationForce, ContactPointLocation); //Calculate Reaction force NormalizedReactionForce = (ApplicationForce * (-1.0f)) / EffectedComponentMesh->GetMass(); //Calculate Rolling Friction float RollingFrictionCoefficient = FPhysicalSurfaceRollingFrictionCoefficient().RollingFrictionCoefficient; for (int32 i = 0; i < PhysicsSurfaceResponse.Num(); i++) { if (PhysicsSurfaceResponse[i].PhysicalSurface == PhysicalSurface) { RollingFrictionCoefficient = PhysicsSurfaceResponse[i].RollingFrictionCoefficient; break; } } RollingFrictionForce = RelativeVelocityAtPoint.GetSafeNormal() * NormalForceAtContactPoint * RollingFrictionCoefficient; if (IsDebugMode) { DrawDebugLine(GetWorld(), ContactPointLocation, ContactPointLocation + ApplicationForce * 0.005f, FColor::Yellow, false, 0.0f, 0, 3.0f); DrawDebugLine(GetWorld(), ContactPointLocation, ContactPointLocation + RollingFrictionForce * 0.005f, FColor::Green, false, 0.0f, 0, 3.0f); DrawDebugString(GetWorld(), ContactPointLocation+FVector(0.0f, 0.0f, 50.0f), (PhysicalSurfaceEnum ? PhysicalSurfaceEnum->GetEnumName(PhysicalSurface) : FString("<Invalid Enum>")), nullptr, FColor::Cyan, 0.0f, false); //DrawDebugString(GetWorld(), ContactPointLocation + FVector(0.0f, 0.0f, 25.0f), FString("Normal Force: ") + FString::SanitizeFloat(NormalForceAtContactPoint), nullptr, FColor::Turquoise, 0.0f, false); } }