float AMurphysLawCharacter::TakeDamage(float DamageAmount, struct FDamageEvent const & DamageEvent, class AController * EventInstigator, AActor * DamageCauser)
{
	float ActualDamage = 0.f;

	if (CurrentHealth > 0.f)
	{
		if (Role == ROLE_Authority)
		{
			ActualDamage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);

			// If the player actually took damage
			if (ActualDamage > 0.f)
			{
				// If the character has a HUD, we show the damages on it
				auto MyController = Cast<AMurphysLawPlayerController>(GetController());
				if (MyController != nullptr)
				{
					// We start by getting best info on the hit
					FVector ImpulseDirection;
					FHitResult Hit;
					DamageEvent.GetBestHitInfo(this, DamageCauser, Hit, ImpulseDirection);

					// We calculate the vector from the character to the damage causer
					FVector2D HitVector = FVector2D(FRotationMatrix(GetControlRotation()).InverseTransformVector(-ImpulseDirection));
					HitVector.Normalize();

					// We compute the vector representing the ForwardVector
					FVector2D StraightVector = FVector2D(1.f, 0.f);
					StraightVector.Normalize();

					// Finally, we calculate the angle where the hit came from
					float Angle = UKismetMathLibrary::DegAcos(FVector2D::DotProduct(StraightVector, HitVector));

					// The angle ranges from -180.f to 180.f
					Angle = HitVector.Y < 0.f ? -Angle : Angle;

					// Dispatch to the controller
					MyController->ShowDamage(Angle);
				}
			}
		}
		else
		{
			// Let the server do it
			Server_TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
		}
	}

	return ActualDamage;
}
Exemple #2
0
void UReporterBase::DrawLine(UCanvas* Canvas,const FVector2D& StartPos,const FVector2D& EndPos,const FLinearColor& Color, EReporterLineStyle::Type LineStyle)
{
	FCanvasLineItem LineItem;
	LineItem.SetColor( Color );
	switch(LineStyle)
	{
		case EReporterLineStyle::Line:
		{
			LineItem.Draw( Canvas->Canvas, ToScreenSpace(StartPos, Canvas), ToScreenSpace(EndPos, Canvas) );			
		} break;

		case EReporterLineStyle::Dash:
		{
			float NormalizedDashSize = DASH_LINE_SIZE / Canvas->SizeX;
			FVector2D Dir = EndPos - StartPos;
			float LineLength = Dir.Size();
			Dir.Normalize();
			FVector2D CurrentLinePos = StartPos;

			while(FVector2D::DotProduct(EndPos - CurrentLinePos, Dir) > 0)
			{
				LineItem.Draw( Canvas->Canvas, ToScreenSpace(CurrentLinePos, Canvas), ToScreenSpace(CurrentLinePos + Dir * NormalizedDashSize, Canvas) );				
				CurrentLinePos +=  Dir * NormalizedDashSize * 2.0f;
			}
		} break;
	}
	
}
float FEyeXUtils::CalculateRotationAngle(const FVector2D& Left, const FVector2D& Right)
{
	static const FVector2D Y = FVector2D(0.0f, 1.0f);
	FVector2D LeftToRight = Right - Left;
	LeftToRight.Normalize();
	const float Radians = FMath::Acos(LeftToRight | Y);
	return FMath::RadiansToDegrees(Radians) - 90.0f;
}
float ADynamicCarController::getAcceleration(float deltaSec) const
{
	float a = aMax * deltaSec;

	float velocityLength = getBrakeDistance();

	float distLeftLength = (target - to2D(agent->GetActorLocation())).Size() - safetyBuffer;

	if (velocityLength >= distLeftLength) {
		// Check if we should start breaking
		FVector2D normVelocity = to2D(velocity);
		normVelocity.Normalize();

		FVector2D normDistLeft = target - to2D(agent->GetActorLocation());
		normDistLeft.Normalize();

		if (normVelocity.Equals(normDistLeft, 0.1)) {
			return -a;
		}
	}

	return a;
}
void UPaperTerrainComponent::SpawnSegments(const TArray<FTerrainSegment>& TerrainSegments, bool bGenerateSegmentColliders)
{
#ifdef USE_SIMPLIFIED_POLYGON_COLLIDERS_FOR_SEGMENTS
	TArray<FVector2D> CollisionPolygonPoints;
#endif

	// The tangent from the first box added in this segment
	FVector2D StartTangent;

	for (const FTerrainSegment& Segment : TerrainSegments)
	{
		for (const FTerrainSpriteStamp& Stamp : Segment.Stamps)
		{
			const class UPaperSprite* NewSprite = Stamp.Sprite;
			float Position = Stamp.Time;
			float HorizontalScale = Stamp.Scale;
			float NominalWidth = Stamp.NominalWidth;
			const struct FPaperTerrainMaterialRule* Rule = Segment.Rule;

			if (bGenerateSegmentColliders && (Rule->bEnableCollision) && (CachedBodySetup != nullptr))
			{
				const FTransform LocalTransformAtCenter(GetTransformAtDistance(Position));

#ifdef USE_SIMPLIFIED_POLYGON_COLLIDERS_FOR_SEGMENTS
				// Check note be low Re: bClosedSplines
				FVector2D BoxExtents( 0.5f * NominalWidth * HorizontalScale, 0.5f * FMath::Max<float>(1.0f, FMath::Abs<float>(Rule->CollisionOffset * 0.5f)) );
				
				FVector BoxPoints[4];
				BoxPoints[0] = LocalTransformAtCenter.TransformPosition(FVector(BoxExtents.X, 0, BoxExtents.Y));
				BoxPoints[1] = LocalTransformAtCenter.TransformPosition(FVector(-BoxExtents.X, 0, BoxExtents.Y));
				BoxPoints[2] = LocalTransformAtCenter.TransformPosition(FVector(-BoxExtents.X, 0, -BoxExtents.Y));
				BoxPoints[3] = LocalTransformAtCenter.TransformPosition(FVector(BoxExtents.X, 0, -BoxExtents.Y));

				FVector2D BoxPoints2D[4];
				BoxPoints2D[0].Set(BoxPoints[0].X, BoxPoints[0].Z);
				BoxPoints2D[1].Set(BoxPoints[1].X, BoxPoints[1].Z);
				BoxPoints2D[2].Set(BoxPoints[2].X, BoxPoints[2].Z);
				BoxPoints2D[3].Set(BoxPoints[3].X, BoxPoints[3].Z);

				// If there is a previous polygon, try to merge
				if (CollisionPolygonPoints.Num() >= 4)
				{
					int InsertPoint = CollisionPolygonPoints.Num() / 2 - 1;
					float LengthV0 = FVector2D::Distance(CollisionPolygonPoints[InsertPoint], BoxPoints2D[0]);
					float LengthV1 = FVector2D::Distance(CollisionPolygonPoints[InsertPoint + 1], BoxPoints2D[3]);

					FVector2D CurrentSegmentTangent = BoxPoints2D[1] - BoxPoints2D[0];
					CurrentSegmentTangent.Normalize();

					bool bNewSegmentStraightEnough = FVector2D::DotProduct(CurrentSegmentTangent, StartTangent) > FMath::Acos(45.0f);

					// TODO: Arbitray number needs to come from somewhere...
					float MergeThreshold = 10;
					bool bMergeIntoPolygon = LengthV0 < MergeThreshold && LengthV1 < MergeThreshold;

					if (bNewSegmentStraightEnough && bMergeIntoPolygon)
					{
						CollisionPolygonPoints.Insert(BoxPoints2D[2], InsertPoint + 1);
						CollisionPolygonPoints.Insert(BoxPoints2D[1], InsertPoint + 1);
					}
					else
					{
						InsertConvexCollisionDataFromPolygon(CollisionPolygonPoints);
						CollisionPolygonPoints.Empty(0);
						CollisionPolygonPoints.Add(BoxPoints2D[0]);
						CollisionPolygonPoints.Add(BoxPoints2D[1]);
						CollisionPolygonPoints.Add(BoxPoints2D[2]);
						CollisionPolygonPoints.Add(BoxPoints2D[3]);
						StartTangent = BoxPoints2D[1] - BoxPoints2D[0];
						StartTangent.Normalize();
					}
				}
				else
				{
					CollisionPolygonPoints.Add(BoxPoints2D[0]);
					CollisionPolygonPoints.Add(BoxPoints2D[1]);
					CollisionPolygonPoints.Add(BoxPoints2D[2]);
					CollisionPolygonPoints.Add(BoxPoints2D[3]);
					StartTangent = BoxPoints2D[1] - BoxPoints2D[0];
					StartTangent.Normalize();
				}
#else
				FKBoxElem Box;
				// The spline is never "closed" properly right now
				//if (bClosedSpline)
				//{
				//	//@TODO: Add proper support for this!
				//	Box.SetTransform(LocalTransformAtCenter);
				//	Box.X = NominalWidth * HorizontalScale;
				//	Box.Y = CollisionThickness;
				//	Box.Z = 30.0f;
				//}
				//else
				{
					Box.SetTransform(LocalTransformAtCenter);
					Box.X = NominalWidth * HorizontalScale;
					Box.Y = CollisionThickness;

					Box.Z = FMath::Max<float>(1.0f, FMath::Abs<float>(Rule->CollisionOffset * 0.5f));
				}
				CachedBodySetup->AggGeom.BoxElems.Add(Box);
#endif
			}

			if (NewSprite)
			{
				FPaperTerrainSpriteGeometry& MaterialBatch = *new (GeneratedSpriteGeometry) FPaperTerrainSpriteGeometry(); //@TODO: Look up the existing one instead
				MaterialBatch.Material = NewSprite->GetDefaultMaterial();
				MaterialBatch.DrawOrder = Rule->DrawOrder;

				FSpriteDrawCallRecord& Record = *new (MaterialBatch.Records) FSpriteDrawCallRecord();
				Record.BuildFromSprite(NewSprite);
				Record.Color = TerrainColor.ToFColor(/*bSRGB=*/ false);

				// Work out if the sprite is likely to be bent > X deg (folded over itself)
				const FVector ForwardVector(1, 0, 0);
				const FTransform LocalTransformAtBack(GetTransformAtDistance(Position - 0.5f * NominalWidth * HorizontalScale));
				FVector StartForwardVector = LocalTransformAtBack.TransformVector(ForwardVector).GetSafeNormal();
				const FTransform LocalTransformAtFront(GetTransformAtDistance(Position + 0.5f * NominalWidth * HorizontalScale));
				FVector EndForwardVector = LocalTransformAtFront.TransformVector(ForwardVector).GetSafeNormal();
				bool bIsSpriteBent = FVector::DotProduct(StartForwardVector, EndForwardVector) < 0.0f;// 0.7071f; // (45deg looks worse)

				for (FVector4& XYUV : Record.RenderVerts)
				{
					FTransform LocalTransformAtX(GetTransformAtDistance(Position + (XYUV.X * HorizontalScale)));

					// When the quad is overly bent, inherit rotation from the start of the quad to unfold it
					if (bIsSpriteBent)
					{
						LocalTransformAtX.SetRotation(LocalTransformAtFront.GetRotation());
					}

					const FVector SourceVector = (XYUV.Y * PaperAxisY);
					const FVector NewVector = LocalTransformAtX.TransformPosition(SourceVector);

					const float NewX = FVector::DotProduct(NewVector, PaperAxisX);
					const float NewY = FVector::DotProduct(NewVector, PaperAxisY);

					XYUV.X = NewX;
					XYUV.Y = NewY;
				}
			}
		}
	}

	//@TODO: Sort by draw order first, materials next - Merge batches with the same material
	GeneratedSpriteGeometry.Sort([](const FPaperTerrainSpriteGeometry& A, const FPaperTerrainSpriteGeometry& B) { return B.DrawOrder > A.DrawOrder; });

#ifdef USE_SIMPLIFIED_POLYGON_COLLIDERS_FOR_SEGMENTS
	// For whatever is remaining
	if (CollisionPolygonPoints.Num() > 0)
	{
		InsertConvexCollisionDataFromPolygon(CollisionPolygonPoints);
	}
#endif
}