Skip to content

Commit

Permalink
Merge pull request #59 from StarCoreSE/collision-detection-ui
Browse files Browse the repository at this point in the history
basic collision predictor
  • Loading branch information
InvalidArgument3 authored Dec 23, 2024
2 parents 9c63ab7 + a0d26a1 commit 1bf53bc
Show file tree
Hide file tree
Showing 2 changed files with 245 additions and 0 deletions.
185 changes: 185 additions & 0 deletions CollisionWarning/Data/Scripts/CollisionPredictor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
using Sandbox.ModAPI;
using VRage.Game.Components;
using VRage.Game.ModAPI;
using VRageMath;
using VRage.ModAPI;
using System.Collections.Generic;
using VRage.Game;
using IMyCockpit = Sandbox.ModAPI.Ingame.IMyCockpit;
using System;
using VRage.Utils;

[MySessionComponentDescriptor(MyUpdateOrder.BeforeSimulation)]
public class CollisionPredictor : MySessionComponentBase
{
private const float MinSpeed = 20f;
private const float MaxRange = 1000f;
private const float ConeAngle = 30f;
private const int NotificationInterval = 60;

private int updateCounter = 0;
private Random random = new Random();
private IMyEntity currentCollisionTarget = null;
private Vector3D currentCollisionPoint;
private double currentTimeToCollision;

private class CollisionTarget
{
public IMyEntity Entity;
public Vector3D Position;
public Vector3D? Velocity;
public double TimeToCollision;
}

public override void UpdateBeforeSimulation()
{
updateCounter++;

var player = MyAPIGateway.Session?.Player;
if (player == null || player.Controller?.ControlledEntity == null)
return;

var controlledEntity = player.Controller.ControlledEntity as IMyCockpit;
if (controlledEntity == null)
return;

var grid = controlledEntity.CubeGrid as IMyCubeGrid;
if (grid == null)
return;

var myVelocity = grid.Physics.LinearVelocity;
var mySpeed = myVelocity.Length();

if (mySpeed < MinSpeed) return;

var mainDirection = Vector3D.Normalize(myVelocity);
var gridGroup = grid.GetGridGroup(GridLinkTypeEnum.Mechanical);
var gridCenter = grid.Physics.CenterOfMassWorld;

BoundingBoxD box = grid.WorldAABB;
Vector3D[] corners = new Vector3D[8];
box.GetCorners(corners);

CollisionTarget closestCollisionTarget = null;
double closestCollisionTime = double.MaxValue;

foreach (Vector3D corner in corners)
{
Vector3D rayDirection = GetRandomDirectionInCone(mainDirection);
Vector3D rayEnd = corner + rayDirection * MaxRange;

IHitInfo hitInfo;
if (MyAPIGateway.Physics.CastLongRay(corner, rayEnd, out hitInfo, false))
{
if (hitInfo.HitEntity == null) continue;

var hitGrid = hitInfo.HitEntity as IMyCubeGrid;
if (hitGrid != null && hitGrid.GetGridGroup(GridLinkTypeEnum.Mechanical) == gridGroup)
continue;

Vector3D? targetVelocity = (hitGrid != null) ? hitGrid.Physics.LinearVelocity : (Vector3D?)null;
Vector3D targetCenter = (hitGrid != null) ? hitGrid.Physics.CenterOfMassWorld : hitInfo.Position;

double? timeToCollision = CalculateTimeToCollision(
gridCenter, myVelocity,
targetCenter, targetVelocity);

if (!timeToCollision.HasValue) continue;

if (timeToCollision.Value < closestCollisionTime)
{
closestCollisionTime = timeToCollision.Value;
closestCollisionTarget = new CollisionTarget
{
Entity = hitInfo.HitEntity,
Position = targetCenter,
Velocity = targetVelocity,
TimeToCollision = timeToCollision.Value
};
}
}
}

// Draw collision warning if we found a potential collision
if (closestCollisionTarget != null && closestCollisionTarget.TimeToCollision < MaxRange / mySpeed)
{
Color warningColor = GetWarningColor(closestCollisionTarget.TimeToCollision * mySpeed);
DrawThickLine(gridCenter, closestCollisionTarget.Position, warningColor);

if (updateCounter % NotificationInterval == 0)
{
string entityName = closestCollisionTarget.Entity?.DisplayName ?? "Unknown Entity";
string relativeSpeed = closestCollisionTarget.Velocity.HasValue ?
$", Relative Speed: {(myVelocity - closestCollisionTarget.Velocity.Value).Length():F1} m/s" : "";

MyAPIGateway.Utilities.ShowNotification(
$"Warning: Potential collision with {entityName} in {closestCollisionTarget.TimeToCollision:F1}s{relativeSpeed}",
1000, MyFontEnum.Red);
}
}
}

private double? CalculateTimeToCollision(Vector3D myPosition, Vector3D myVelocity,
Vector3D targetPosition, Vector3D? targetVelocity)
{
Vector3D relativePosition = targetPosition - myPosition;
Vector3D relativeVelocity = targetVelocity.HasValue ?
myVelocity - targetVelocity.Value : myVelocity;

double relativeSpeed = relativeVelocity.Length();
if (relativeSpeed < 1) // Effectively stationary relative to each other
return null;

// Project relative position onto relative velocity
double dot = Vector3D.Dot(relativePosition, relativeVelocity);
if (dot < 0) // Moving away from each other
return null;

return dot / (relativeSpeed * relativeSpeed);
}

private Color GetWarningColor(double distance)
{
float normalizedDistance = (float)(Math.Min(Math.Max(distance, 0), MaxRange) / MaxRange);
return new Color(
(byte)(255 * (1 - normalizedDistance)),
(byte)(255 * normalizedDistance),
0);
}

private Vector3D GetRandomDirectionInCone(Vector3D mainDirection)
{
double angleRad = MathHelper.ToRadians(ConeAngle);
double randomAngle = random.NextDouble() * angleRad;
double randomAzimuth = random.NextDouble() * 2 * Math.PI;

Vector3D perp1 = Vector3D.CalculatePerpendicularVector(mainDirection);
Vector3D perp2 = Vector3D.Cross(mainDirection, perp1);

double x = Math.Sin(randomAngle) * Math.Cos(randomAzimuth);
double y = Math.Sin(randomAngle) * Math.Sin(randomAzimuth);
double z = Math.Cos(randomAngle);

return Vector3D.Normalize(z * mainDirection + x * perp1 + y * perp2);
}

private bool IsOnCollisionCourse(Vector3D currentPosition, Vector3 velocity, Vector3D obstaclePosition)
{
Vector3D predictedPosition = currentPosition + velocity;
return Vector3D.Distance(predictedPosition, obstaclePosition) < 10;
}

private void DrawLine(Vector3D start, Vector3D end, Color color)
{
Vector4 colorVector = color.ToVector4();
MySimpleObjectDraw.DrawLine(start, end, MyStringId.GetOrCompute("Square"), ref colorVector, 1f);
}

private void DrawThickLine(Vector3D start, Vector3D end, Color color)
{
Vector4 colorVector = color.ToVector4();
MySimpleObjectDraw.DrawLine(start, end, MyStringId.GetOrCompute("Square"), ref colorVector, 2f);
}

protected override void UnloadData() { }
}
60 changes: 60 additions & 0 deletions CollisionWarning/Data/Scripts/concatrecursivelyandminify.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
@echo off
setlocal enabledelayedexpansion
chcp 65001
REM ^^ this is to change the encoding to UTF-8, apparently

echo Starting operation...

set TEMP_OUTPUT=temp_concatenated.txt
set FINAL_OUTPUT=minified_output.txt
set /a COUNT=0
set /a ERRORS=0

if exist "%TEMP_OUTPUT%" (
echo Existing temporary file found. Deleting...
del "%TEMP_OUTPUT%"
)

if exist "%FINAL_OUTPUT%" (
echo Existing output file found. Deleting...
del "%FINAL_OUTPUT%"
)

for /r %%i in (*.cs) do (
echo Processing: "%%i"
type "%%i" >> "%TEMP_OUTPUT%"
if errorlevel 1 (
echo Error processing "%%i".
set /a ERRORS+=1
) else (
set /a COUNT+=1
)
)

echo Concatenation completed.
echo Total files processed: %COUNT%
if %ERRORS% gtr 0 (
echo There were %ERRORS% errors during the concatenation.
) else (
echo No errors encountered during concatenation.
)

echo Minifying concatenated file...
csmin < "%TEMP_OUTPUT%" > "%FINAL_OUTPUT%"
if errorlevel 1 (
echo Error occurred during minification.
set /a ERRORS+=1
) else (
echo Minification completed successfully.
)

echo Cleaning up temporary file...
del "%TEMP_OUTPUT%"

echo Operation completed.
if %ERRORS% gtr 0 (
echo There were %ERRORS% errors during the entire operation.
) else (
echo No errors encountered during the entire operation.
)
pause

0 comments on commit 1bf53bc

Please sign in to comment.