mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Had to optimize the physics so that the client runs on my laptop.
This commit is contained in:
@@ -36,9 +36,9 @@ namespace Robust.Client.Physics
|
||||
SimulateWorld((float) diff.TotalSeconds, ActuallyRelevant());
|
||||
}
|
||||
|
||||
private List<IPhysicsComponent> ActuallyRelevant()
|
||||
private List<ICollidableComponent> ActuallyRelevant()
|
||||
{
|
||||
var relevant = _componentManager.GetAllComponents<IPhysicsComponent>().Where(p => p.Predict)
|
||||
var relevant = _componentManager.GetAllComponents<ICollidableComponent>().Where(p => p.Predict)
|
||||
.ToList();
|
||||
return relevant;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Robust.Server.GameObjects.EntitySystems
|
||||
{
|
||||
SimulateWorld(frameTime,
|
||||
RelevantEntities.Where(e => !e.Deleted && !_pauseManager.IsEntityPaused(e))
|
||||
.Select(p => p.GetComponent<IPhysicsComponent>()).ToList());
|
||||
.Select(p => p.GetComponent<ICollidableComponent>()).ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,6 +161,12 @@ namespace Robust.Shared.GameObjects.Components
|
||||
/// </summary>
|
||||
/// <returns>True if all of the controllers were reset, false otherwise.</returns>
|
||||
bool Stop();
|
||||
|
||||
/// <summary>
|
||||
/// Can this body be moved?
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool CanMove();
|
||||
}
|
||||
|
||||
partial class CollidableComponent : ICollidableComponent
|
||||
@@ -418,5 +424,11 @@ namespace Robust.Shared.GameObjects.Components
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool CanMove()
|
||||
{
|
||||
return !Anchored && !Deleted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects.Components;
|
||||
@@ -35,10 +36,13 @@ namespace Robust.Shared.GameObjects.Systems
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
protected void SimulateWorld(float frameTime, List<IPhysicsComponent> physicsComponents)
|
||||
protected void SimulateWorld(float frameTime, List<ICollidableComponent> physicsComponents)
|
||||
{
|
||||
foreach (var physics in physicsComponents)
|
||||
{
|
||||
if(!physics.CanMove())
|
||||
continue;
|
||||
|
||||
var linearVelocity = Vector2.Zero;
|
||||
|
||||
foreach (var controller in physics.Controllers.Values)
|
||||
@@ -51,7 +55,7 @@ namespace Robust.Shared.GameObjects.Systems
|
||||
}
|
||||
|
||||
// Calculate collisions and store them in the cache
|
||||
ProcessCollisions();
|
||||
ProcessCollisions(physicsComponents);
|
||||
|
||||
// Remove all entities that were deleted during collision handling
|
||||
physicsComponents.RemoveAll(p => p.Deleted);
|
||||
@@ -89,7 +93,8 @@ namespace Robust.Shared.GameObjects.Systems
|
||||
{
|
||||
foreach (var physics in physicsComponents)
|
||||
{
|
||||
UpdatePosition(physics, frameTime / divisions);
|
||||
if(physics.CanMove())
|
||||
UpdatePosition(physics, frameTime / divisions);
|
||||
}
|
||||
|
||||
for (var j = 0; j < divisions; ++j)
|
||||
@@ -103,11 +108,11 @@ namespace Robust.Shared.GameObjects.Systems
|
||||
}
|
||||
|
||||
// Runs collision behavior and updates cache
|
||||
private void ProcessCollisions()
|
||||
private void ProcessCollisions(IEnumerable<ICollidableComponent> bodies)
|
||||
{
|
||||
var collisionsWith = new Dictionary<ICollideBehavior, int>();
|
||||
|
||||
FindCollisions();
|
||||
FindCollisions(bodies);
|
||||
|
||||
var counter = 0;
|
||||
|
||||
@@ -115,14 +120,14 @@ namespace Robust.Shared.GameObjects.Systems
|
||||
{
|
||||
counter++;
|
||||
var impulse = _physicsManager.SolveCollisionImpulse(collision);
|
||||
if (collision.APhysics != null)
|
||||
if (collision.A.CanMove())
|
||||
{
|
||||
collision.APhysics.Momentum -= impulse;
|
||||
collision.A.Momentum -= impulse;
|
||||
}
|
||||
|
||||
if (collision.BPhysics != null)
|
||||
if (collision.B.CanMove())
|
||||
{
|
||||
collision.BPhysics.Momentum += impulse;
|
||||
collision.B.Momentum += impulse;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,34 +172,28 @@ namespace Robust.Shared.GameObjects.Systems
|
||||
}
|
||||
}
|
||||
|
||||
private void FindCollisions()
|
||||
private void FindCollisions(IEnumerable<ICollidableComponent> bodies)
|
||||
{
|
||||
_collisionCache.Clear();
|
||||
var combinations = new HashSet<(EntityUid, EntityUid)>();
|
||||
foreach (var physics in _componentManager.GetAllComponents<IPhysicsComponent>())
|
||||
foreach (var aCollidable in bodies)
|
||||
{
|
||||
if (!physics.Owner.TryGetComponent<ICollidableComponent>(out var aCollidable))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
aCollidable.SleepAccumulator++;
|
||||
|
||||
if (physics.LinearVelocity == Vector2.Zero)
|
||||
if (aCollidable.LinearVelocity == Vector2.Zero)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FindCollisionsFor(aCollidable, physics, combinations);
|
||||
FindCollisionsFor(aCollidable, combinations);
|
||||
}
|
||||
}
|
||||
|
||||
private void FindCollisionsFor(ICollidableComponent a, IPhysicsComponent aPhysics,
|
||||
HashSet<(EntityUid, EntityUid)> combinations)
|
||||
private void FindCollisionsFor(ICollidableComponent a, HashSet<(EntityUid, EntityUid)> combinations)
|
||||
{
|
||||
foreach (var b in a.GetCollidingEntities(Vector2.Zero))
|
||||
foreach (var b in _physicsManager.GetCollidingEntities(a, Vector2.Zero))
|
||||
{
|
||||
var aUid = ((IPhysBody)a).Entity.Uid;
|
||||
var aUid = a.Entity.Uid;
|
||||
var bUid = b.Uid;
|
||||
|
||||
if (bUid.CompareTo(aUid) > 0)
|
||||
@@ -210,14 +209,7 @@ namespace Robust.Shared.GameObjects.Systems
|
||||
}
|
||||
|
||||
var bCollidable = b.GetComponent<ICollidableComponent>();
|
||||
if (b.TryGetComponent<IPhysicsComponent>(out var bPhysics))
|
||||
{
|
||||
_collisionCache.Add(new Manifold(a, bCollidable, aPhysics, bPhysics, a.Hard && bCollidable.Hard, _physicsManager));
|
||||
}
|
||||
else
|
||||
{
|
||||
_collisionCache.Add(new Manifold(a, bCollidable, aPhysics, null, a.Hard && bCollidable.Hard, _physicsManager));
|
||||
}
|
||||
_collisionCache.Add(new Manifold(a, bCollidable, a.Hard && bCollidable.Hard));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,38 +240,38 @@ namespace Robust.Shared.GameObjects.Systems
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ProcessFriction(IPhysicsComponent physics)
|
||||
private void ProcessFriction(ICollidableComponent body)
|
||||
{
|
||||
if (physics.LinearVelocity == Vector2.Zero) return;
|
||||
if (body.LinearVelocity == Vector2.Zero) return;
|
||||
|
||||
// Calculate frictional force
|
||||
var friction = GetFriction(physics);
|
||||
var friction = GetFriction(body);
|
||||
|
||||
// Clamp friction because friction can't make you accelerate backwards
|
||||
friction = Math.Min(friction, physics.LinearVelocity.Length);
|
||||
friction = Math.Min(friction, body.LinearVelocity.Length);
|
||||
|
||||
// No multiplication/division by mass here since that would be redundant.
|
||||
var frictionVelocityChange = physics.LinearVelocity.Normalized * -friction;
|
||||
var frictionVelocityChange = body.LinearVelocity.Normalized * -friction;
|
||||
|
||||
physics.LinearVelocity += frictionVelocityChange;
|
||||
body.LinearVelocity += frictionVelocityChange;
|
||||
}
|
||||
|
||||
private void UpdatePosition(IPhysicsComponent physics, float frameTime)
|
||||
private static void UpdatePosition(ICollidableComponent body, float frameTime)
|
||||
{
|
||||
var ent = physics.Owner;
|
||||
physics.LinearVelocity = new Vector2(Math.Abs(physics.LinearVelocity.X) < Epsilon ? 0.0f : physics.LinearVelocity.X, Math.Abs(physics.LinearVelocity.Y) < Epsilon ? 0.0f : physics.LinearVelocity.Y);
|
||||
if (physics.Anchored ||
|
||||
physics.LinearVelocity == Vector2.Zero && Math.Abs(physics.AngularVelocity) < Epsilon) return;
|
||||
var ent = body.Owner;
|
||||
body.LinearVelocity = new Vector2(Math.Abs(body.LinearVelocity.X) < Epsilon ? 0.0f : body.LinearVelocity.X, Math.Abs(body.LinearVelocity.Y) < Epsilon ? 0.0f : body.LinearVelocity.Y);
|
||||
if (body.Anchored ||
|
||||
body.LinearVelocity == Vector2.Zero && Math.Abs(body.AngularVelocity) < Epsilon) return;
|
||||
|
||||
if (ContainerHelpers.IsInContainer(ent) && physics.LinearVelocity != Vector2.Zero)
|
||||
if (ContainerHelpers.IsInContainer(ent) && body.LinearVelocity != Vector2.Zero)
|
||||
{
|
||||
ent.Transform.Parent!.Owner.SendMessage(ent.Transform, new RelayMovementEntityMessage(ent));
|
||||
// This prevents redundant messages from being sent if solveIterations > 1 and also simulates the entity "colliding" against the locker door when it opens.
|
||||
physics.LinearVelocity = Vector2.Zero;
|
||||
body.LinearVelocity = Vector2.Zero;
|
||||
}
|
||||
|
||||
physics.Owner.Transform.WorldRotation += physics.AngularVelocity * frameTime;
|
||||
physics.Owner.Transform.WorldPosition += physics.LinearVelocity * frameTime;
|
||||
body.Owner.Transform.WorldRotation += body.AngularVelocity * frameTime;
|
||||
body.Owner.Transform.WorldPosition += body.LinearVelocity * frameTime;
|
||||
}
|
||||
|
||||
// Based off of Randy Gaul's ImpulseEngine code
|
||||
@@ -296,32 +288,31 @@ namespace Robust.Shared.GameObjects.Systems
|
||||
}
|
||||
|
||||
var penetration = _physicsManager.CalculatePenetration(collision.A, collision.B);
|
||||
if (penetration > allowance)
|
||||
{
|
||||
done = false;
|
||||
var correction = collision.Normal * Math.Abs(penetration) * percent;
|
||||
if (collision.APhysics != null && !collision.APhysics.Anchored && !collision.APhysics.Deleted)
|
||||
collision.APhysics.Owner.Transform.WorldPosition -= correction;
|
||||
if (collision.BPhysics != null && !collision.BPhysics.Anchored && !collision.BPhysics.Deleted)
|
||||
collision.BPhysics.Owner.Transform.WorldPosition += correction;
|
||||
}
|
||||
|
||||
if (penetration <= allowance)
|
||||
continue;
|
||||
|
||||
done = false;
|
||||
var correction = collision.Normal * Math.Abs(penetration) * percent;
|
||||
if (collision.A.CanMove())
|
||||
collision.A.Owner.Transform.WorldPosition -= correction;
|
||||
if (collision.B.CanMove())
|
||||
collision.B.Owner.Transform.WorldPosition += correction;
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
private float GetFriction(IPhysicsComponent physics)
|
||||
private float GetFriction(ICollidableComponent body)
|
||||
{
|
||||
var ent = physics.Owner;
|
||||
if (ent.HasComponent<ICollidableComponent>() && physics.OnGround)
|
||||
{
|
||||
var location = ent.Transform;
|
||||
var grid = _mapManager.GetGrid(location.GridPosition.GridID);
|
||||
var tile = grid.GetTileRef(location.GridPosition);
|
||||
var tileDef = _tileDefinitionManager[tile.Tile.TypeId];
|
||||
return tileDef.Friction;
|
||||
}
|
||||
return 0.0f;
|
||||
if (!body.OnGround)
|
||||
return 0.0f;
|
||||
|
||||
var location = body.Owner.Transform;
|
||||
var grid = _mapManager.GetGrid(location.GridPosition.GridID);
|
||||
var tile = grid.GetTileRef(location.GridPosition);
|
||||
var tileDef = _tileDefinitionManager[tile.Tile.TypeId];
|
||||
return tileDef.Friction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,14 +71,6 @@ namespace Robust.Shared.Interfaces.Physics
|
||||
/// <returns>The distance the ray traveled while colliding with entities</returns>
|
||||
public float IntersectRayPenetration(MapId mapId, CollisionRay ray, float maxLength, IEntity? ignoredEnt = null);
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the normal vector for two colliding bodies
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <returns></returns>
|
||||
Vector2 CalculateNormal(IPhysBody target, IPhysBody source);
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the penetration depth of the axis-of-least-penetration for a
|
||||
/// </summary>
|
||||
@@ -127,54 +119,38 @@ namespace Robust.Shared.Interfaces.Physics
|
||||
public float MaxLength { get; }
|
||||
}
|
||||
|
||||
public struct Manifold
|
||||
public readonly struct Manifold
|
||||
{
|
||||
public readonly ICollidableComponent A;
|
||||
public readonly ICollidableComponent B;
|
||||
|
||||
public readonly Vector2 Normal;
|
||||
public readonly bool Hard;
|
||||
|
||||
public Vector2 RelativeVelocity
|
||||
{
|
||||
get
|
||||
{
|
||||
if (APhysics != null)
|
||||
if (A != null)
|
||||
{
|
||||
if (BPhysics != null)
|
||||
{
|
||||
return BPhysics.LinearVelocity - APhysics.LinearVelocity;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -APhysics.LinearVelocity;
|
||||
}
|
||||
if (B != null)
|
||||
return B.LinearVelocity - A.LinearVelocity;
|
||||
return -A.LinearVelocity;
|
||||
}
|
||||
|
||||
if (BPhysics != null)
|
||||
{
|
||||
return BPhysics.LinearVelocity;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Vector2.Zero;
|
||||
}
|
||||
if (B != null)
|
||||
return B.LinearVelocity;
|
||||
return Vector2.Zero;
|
||||
}
|
||||
}
|
||||
public readonly Vector2 Normal;
|
||||
public readonly IPhysBody A;
|
||||
public readonly IPhysBody B;
|
||||
public IPhysicsComponent? APhysics;
|
||||
public IPhysicsComponent? BPhysics;
|
||||
public readonly bool Hard;
|
||||
|
||||
public float InvAMass => 1 / APhysics?.Mass ?? 0.0f;
|
||||
public float InvBMass => 1 / BPhysics?.Mass ?? 0.0f;
|
||||
|
||||
public bool Unresolved => Vector2.Dot(RelativeVelocity, Normal) < 0 && Hard;
|
||||
|
||||
public Manifold(IPhysBody A, IPhysBody B, IPhysicsComponent? aPhysics, IPhysicsComponent? bPhysics, bool hard,
|
||||
IPhysicsManager physicsManager)
|
||||
public Manifold(ICollidableComponent a, ICollidableComponent b, bool hard)
|
||||
{
|
||||
this.A = A;
|
||||
this.B = B;
|
||||
Normal = physicsManager.CalculateNormal(A, B);
|
||||
APhysics = aPhysics;
|
||||
BPhysics = bPhysics;
|
||||
A = a;
|
||||
B = b;
|
||||
Normal = PhysicsManager.CalculateNormal(a, b);
|
||||
Hard = hard;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,14 @@ namespace Robust.Shared.Physics
|
||||
return !_mapManager.GetGrid(gridPosition.GridID).HasGravity || tile.IsEmpty;
|
||||
}
|
||||
|
||||
public Vector2 CalculateNormal(IPhysBody target, IPhysBody source)
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the normal vector for two colliding bodies
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <returns></returns>
|
||||
public static Vector2 CalculateNormal(IPhysBody target, IPhysBody source)
|
||||
{
|
||||
var manifold = target.WorldAABB.Intersect(source.WorldAABB);
|
||||
if (manifold.IsEmpty()) return Vector2.Zero;
|
||||
@@ -80,8 +87,8 @@ namespace Robust.Shared.Physics
|
||||
// Impulse resolution algorithm based on Box2D's approach in combination with Randy Gaul's Impulse Engine resolution algorithm.
|
||||
public Vector2 SolveCollisionImpulse(Manifold manifold)
|
||||
{
|
||||
var aP = manifold.APhysics;
|
||||
var bP = manifold.BPhysics;
|
||||
var aP = manifold.A;
|
||||
var bP = manifold.B;
|
||||
if (aP == null && bP == null) return Vector2.Zero;
|
||||
var restitution = 0.01f;
|
||||
var normal = CalculateNormal(manifold.A, manifold.B);
|
||||
|
||||
Reference in New Issue
Block a user