Merge physics rewrite

This commit is contained in:
Pieter-Jan Briers
2020-05-23 01:23:36 +02:00
parent b6b4482ca0
commit 18ce80a43c
20 changed files with 224 additions and 104 deletions

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Content.Server.Interfaces.GameObjects.Components.Movement; using Content.Server.Interfaces.GameObjects.Components.Movement;
using Content.Shared.Physics; using Content.Shared.Physics;
using Robust.Server.AI; using Robust.Server.AI;
@@ -114,7 +115,7 @@ namespace Content.Server.AI
var ray = new CollisionRay(myTransform.WorldPosition, dir.Normalized, (int)(CollisionGroup.MobImpassable | CollisionGroup.Impassable)); var ray = new CollisionRay(myTransform.WorldPosition, dir.Normalized, (int)(CollisionGroup.MobImpassable | CollisionGroup.Impassable));
// cast the ray // cast the ray
var result = _physMan.IntersectRay(myTransform.MapID, ray, maxRayLen, SelfEntity); var result = _physMan.IntersectRay(myTransform.MapID, ray, maxRayLen, SelfEntity).First();
// add to visible list // add to visible list
if (result.HitEntity == entity) if (result.HitEntity == entity)

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Content.Server.GameObjects.Components.Movement; using Content.Server.GameObjects.Components.Movement;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces.Chat; using Content.Server.Interfaces.Chat;
@@ -127,17 +128,20 @@ namespace Content.Server.AI
{ {
var dir = new Vector2(Random01(ref rngState) * 2 - 1, Random01(ref rngState) *2 -1).Normalized; var dir = new Vector2(Random01(ref rngState) * 2 - 1, Random01(ref rngState) *2 -1).Normalized;
var ray = new CollisionRay(entWorldPos, dir, (int) CollisionGroup.Impassable); var ray = new CollisionRay(entWorldPos, dir, (int) CollisionGroup.Impassable);
var rayResult = _physMan.IntersectRay(SelfEntity.Transform.MapID, ray, MaxWalkDistance, SelfEntity); var rayResults = _physMan.IntersectRay(SelfEntity.Transform.MapID, ray, MaxWalkDistance, SelfEntity).ToList();
if (rayResult.DidHitObject && rayResult.Distance > 1) // hit an impassable object if (rayResults.Count == 1)
{
var rayResult = rayResults[0];
if (rayResult.Distance > 1) // hit an impassable object
{ {
// set the new position back from the wall a bit // set the new position back from the wall a bit
_walkTargetPos = entWorldPos + dir * (rayResult.Distance - 0.5f); _walkTargetPos = entWorldPos + dir * (rayResult.Distance - 0.5f);
WalkingPositiveEdge(); WalkingPositiveEdge();
return; return;
} }
}
if (!rayResult.DidHitObject) // hit nothing (path clear) else // hit nothing (path clear)
{ {
_walkTargetPos = dir * MaxWalkDistance; _walkTargetPos = dir * MaxWalkDistance;
WalkingPositiveEdge(); WalkingPositiveEdge();

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using Content.Server.GameObjects.Components.Access; using Content.Server.GameObjects.Components.Access;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Doors; using Content.Shared.GameObjects.Components.Doors;
@@ -17,7 +18,7 @@ namespace Content.Server.GameObjects
{ {
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
public class ServerDoorComponent : Component, IActivate public class ServerDoorComponent : Component, IActivate, ICollideBehavior
{ {
public override string Name => "Door"; public override string Name => "Door";
@@ -85,26 +86,16 @@ namespace Content.Server.GameObjects
ActivateImpl(eventArgs); ActivateImpl(eventArgs);
} }
public override void HandleMessage(ComponentMessage message, IComponent component)
{
base.HandleMessage(message, component);
switch (message) void ICollideBehavior.CollideWith(IEntity entity)
{ {
case BumpedEntMsg msg:
if (State != DoorState.Closed) if (State != DoorState.Closed)
{ {
return; return;
} }
if (entity.HasComponent(typeof(SpeciesComponent)))
// Only open when bumped by mobs.
if (!msg.Entity.HasComponent(typeof(SpeciesComponent)))
{ {
return; TryOpen(entity);
}
TryOpen(msg.Entity);
break;
} }
} }
@@ -155,7 +146,7 @@ namespace Content.Server.GameObjects
Timer.Spawn(OpenTimeOne, async () => Timer.Spawn(OpenTimeOne, async () =>
{ {
collidableComponent.IsHardCollidable = false; collidableComponent.CanCollide = false;
await Timer.Delay(OpenTimeTwo, _cancellationTokenSource.Token); await Timer.Delay(OpenTimeTwo, _cancellationTokenSource.Token);
@@ -191,14 +182,14 @@ namespace Content.Server.GameObjects
public bool Close() public bool Close()
{ {
if (collidableComponent.TryCollision(Vector2.Zero)) if (collidableComponent.IsColliding(Vector2.Zero))
{ {
// Do nothing, somebody's in the door. // Do nothing, somebody's in the door.
return false; return false;
} }
State = DoorState.Closing; State = DoorState.Closing;
collidableComponent.IsHardCollidable = true; collidableComponent.CanCollide = true;
OpenTimeCounter = 0; OpenTimeCounter = 0;
SetAppearance(DoorVisualState.Closing); SetAppearance(DoorVisualState.Closing);

View File

@@ -34,7 +34,7 @@ namespace Content.Server.GameObjects.Components.Fluids
// Small puddles will evaporate after a set delay // Small puddles will evaporate after a set delay
// TODO: 'leaves fluidtracks', probably in a separate component for stuff like gibb chunks?; // TODO: 'leaves fluidtracks', probably in a separate component for stuff like gibb chunks?;
// TODO: Add stuff like slipping -> probably in a separate component (for stuff like bananas) and using BumpEntMsg // TODO: Add stuff like slipping -> probably in a separate component (for stuff like bananas)
// based on behaviour (e.g. someone being punched vs slashed with a sword would have different blood sprite) // based on behaviour (e.g. someone being punched vs slashed with a sword would have different blood sprite)
// to check for low volumes for evaporation or whatever // to check for low volumes for evaporation or whatever

View File

@@ -190,7 +190,7 @@ namespace Content.Server.GameObjects.Components
{ {
if (Owner.TryGetComponent<ICollidableComponent>(out var collidableComponent)) if (Owner.TryGetComponent<ICollidableComponent>(out var collidableComponent))
{ {
collidableComponent.CollisionEnabled = IsCollidableWhenOpen || !Open; collidableComponent.CanCollide = IsCollidableWhenOpen || !Open;
} }
if (Owner.TryGetComponent<PlaceableSurfaceComponent>(out var placeableSurfaceComponent)) if (Owner.TryGetComponent<PlaceableSurfaceComponent>(out var placeableSurfaceComponent))
@@ -250,7 +250,7 @@ namespace Content.Server.GameObjects.Components
entity.Transform.WorldPosition = worldPos; entity.Transform.WorldPosition = worldPos;
if (entityCollidableComponent != null) if (entityCollidableComponent != null)
{ {
entityCollidableComponent.CollisionEnabled = false; entityCollidableComponent.CanCollide = false;
} }
return true; return true;
} }
@@ -265,7 +265,7 @@ namespace Content.Server.GameObjects.Components
{ {
if (contained.TryGetComponent<ICollidableComponent>(out var entityCollidableComponent)) if (contained.TryGetComponent<ICollidableComponent>(out var entityCollidableComponent))
{ {
entityCollidableComponent.CollisionEnabled = true; entityCollidableComponent.CanCollide = true;
} }
} }
} }

View File

@@ -195,7 +195,7 @@ namespace Content.Server.GameObjects
if (entity.TryGetComponent(out CollidableComponent collidable)) if (entity.TryGetComponent(out CollidableComponent collidable))
{ {
collidable.CollisionEnabled = false; collidable.CanCollide = false;
} }
} }
@@ -205,7 +205,7 @@ namespace Content.Server.GameObjects
if (entity.TryGetComponent(out CollidableComponent collidable)) if (entity.TryGetComponent(out CollidableComponent collidable))
{ {
collidable.CollisionEnabled = true; collidable.CanCollide = true;
} }
} }

View File

@@ -63,7 +63,7 @@ namespace Content.Server.GameObjects.Components.Movement
base.OnAdd(); base.OnAdd();
if (Owner.TryGetComponent<CollidableComponent>(out var collide)) if (Owner.TryGetComponent<CollidableComponent>(out var collide))
{ {
collide.IsHardCollidable = false; //collide.IsHardCollidable = false;
} }
_state = PortalState.Pending; _state = PortalState.Pending;

View File

@@ -65,8 +65,8 @@ namespace Content.Server.GameObjects.Components.Movement
if (!gridEntity.HasComponent<ICollidableComponent>()) if (!gridEntity.HasComponent<ICollidableComponent>())
{ {
var collideComp = gridEntity.AddComponent<CollidableComponent>(); var collideComp = gridEntity.AddComponent<CollidableComponent>();
collideComp.CollisionEnabled = true; collideComp.CanCollide = true;
collideComp.IsHardCollidable = true; //collideComp.IsHardCollidable = true;
collideComp.PhysicsShapes.Add(new PhysShapeGrid(grid)); collideComp.PhysicsShapes.Add(new PhysShapeGrid(grid));
} }

View File

@@ -62,12 +62,10 @@ namespace Content.Server.GameObjects.Components.Projectiles
} }
/// <summary> /// <summary>
/// Applys the damage when our projectile collides with its victim /// Applies the damage when our projectile collides with its victim
/// </summary> /// </summary>
/// <param name="collidedwith"></param> /// <param name="entity"></param>
void ICollideBehavior.CollideWith(List<IEntity> collidedwith) void ICollideBehavior.CollideWith(IEntity entity)
{
foreach (var entity in collidedwith)
{ {
if (entity.TryGetComponent(out DamageableComponent damage)) if (entity.TryGetComponent(out DamageableComponent damage))
{ {
@@ -75,7 +73,6 @@ namespace Content.Server.GameObjects.Components.Projectiles
foreach (var (damageType, amount) in _damages) foreach (var (damageType, amount) in _damages)
{ {
damage.TakeDamage(damageType, amount, Owner, shooter); damage.TakeDamage(damageType, amount, Owner, shooter);
} }
} }
@@ -88,10 +85,9 @@ namespace Content.Server.GameObjects.Components.Projectiles
} }
} }
if (collidedwith.Count > 0) void ICollideBehavior.PostCollide(int collideCount)
{ {
Owner.Delete(); if (collideCount > 0) Owner.Delete();
}
} }
} }
} }

View File

@@ -18,6 +18,8 @@ namespace Content.Server.GameObjects.Components
[Dependency] private readonly IEntitySystemManager _entitySystemManager; [Dependency] private readonly IEntitySystemManager _entitySystemManager;
#pragma warning restore 649 #pragma warning restore 649
private bool _shouldCollide = true;
public override string Name => "ThrownItem"; public override string Name => "ThrownItem";
/// <summary> /// <summary>
@@ -25,32 +27,37 @@ namespace Content.Server.GameObjects.Components
/// </summary> /// </summary>
public IEntity User; public IEntity User;
void ICollideBehavior.CollideWith(List<IEntity> collidedwith) void ICollideBehavior.CollideWith(IEntity entity)
{
foreach (var entity in collidedwith)
{ {
if (!_shouldCollide) return;
if (entity.TryGetComponent(out DamageableComponent damage)) if (entity.TryGetComponent(out DamageableComponent damage))
{ {
damage.TakeDamage(DamageType.Brute, 10, Owner, User); damage.TakeDamage(DamageType.Brute, 10, Owner, User);
} }
}
// Stop colliding with mobs, this mimics not having enough velocity to do damage // Stop colliding with mobs, this mimics not having enough velocity to do damage
// after impacting the first object. // after impacting the first object.
// For realism this should actually be changed when the velocity of the object is less than a threshold. // For realism this should actually be changed when the velocity of the object is less than a threshold.
// This would allow ricochets off walls, and weird gravity effects from slowing the object. // This would allow ricochets off walls, and weird gravity effects from slowing the object.
if (collidedwith.Count > 0 && Owner.TryGetComponent(out CollidableComponent body) && body.PhysicsShapes.Count >= 1) if (Owner.TryGetComponent(out CollidableComponent body) && body.PhysicsShapes.Count >= 1)
{
_shouldCollide = false;
}
}
public void PostCollide(int collideCount)
{
if (collideCount > 0 && Owner.TryGetComponent(out CollidableComponent body) && body.PhysicsShapes.Count >= 1)
{ {
body.PhysicsShapes[0].CollisionMask &= (int)~CollisionGroup.MobImpassable; body.PhysicsShapes[0].CollisionMask &= (int)~CollisionGroup.MobImpassable;
body.IsScrapingFloor = true;
// KYS, your job is finished. Trigger ILand as well. // KYS, your job is finished. Trigger ILand as well.
var physics = Owner.GetComponent<PhysicsComponent>();
(physics.Controller as ThrowController).StopThrow();
physics.RemoveController();
Owner.RemoveComponent<ThrownItemComponent>(); Owner.RemoveComponent<ThrownItemComponent>();
_entitySystemManager.GetEntitySystem<InteractionSystem>().LandInteraction(User, Owner, Owner.Transform.GridPosition); _entitySystemManager.GetEntitySystem<InteractionSystem>().LandInteraction(User, Owner, Owner.Transform.GridPosition);
} }
} }
} }
} }

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects; using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Items; using Content.Shared.GameObjects.Components.Items;
@@ -140,7 +141,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
for (var i = 0; i < increments; i++) for (var i = 0; i < increments; i++)
{ {
var castAngle = new Angle(baseAngle + increment * i); var castAngle = new Angle(baseAngle + increment * i);
var res = _physicsManager.IntersectRay(mapId, new CollisionRay(position, castAngle.ToVec(), 23), _range, ignore, ignoreNonHardCollidables: true); var res = _physicsManager.IntersectRay(mapId, new CollisionRay(position, castAngle.ToVec(), 23), _range, ignore).First();
if (res.HitEntity != null) if (res.HitEntity != null)
{ {
resSet.Add(res.HitEntity); resSet.Add(res.HitEntity);

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using Content.Server.GameObjects.Components.Power; using Content.Server.GameObjects.Components.Power;
using Content.Server.GameObjects.Components.Sound; using Content.Server.GameObjects.Components.Sound;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
@@ -90,10 +91,13 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
var angle = new Angle(clickLocation.Position - userPosition); var angle = new Angle(clickLocation.Position - userPosition);
var ray = new CollisionRay(userPosition, angle.ToVec(), (int)(CollisionGroup.Impassable | CollisionGroup.MobImpassable)); var ray = new CollisionRay(userPosition, angle.ToVec(), (int)(CollisionGroup.Impassable | CollisionGroup.MobImpassable));
var rayCastResults = IoCManager.Resolve<IPhysicsManager>().IntersectRay(user.Transform.MapID, ray, MaxLength, user, ignoreNonHardCollidables: true); var rayCastResults = IoCManager.Resolve<IPhysicsManager>().IntersectRay(user.Transform.MapID, ray, MaxLength, user).ToList();
Hit(rayCastResults, energyModifier, user); if (rayCastResults.Count == 1)
AfterEffects(user, rayCastResults, angle, energyModifier); {
Hit(rayCastResults[0], energyModifier, user);
AfterEffects(user, rayCastResults[0], angle, energyModifier);
}
} }
protected virtual void Hit(RayCastResults ray, float damageModifier, IEntity user = null) protected virtual void Hit(RayCastResults ray, float damageModifier, IEntity user = null)
@@ -109,7 +113,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
protected virtual void AfterEffects(IEntity user, RayCastResults ray, Angle angle, float energyModifier) protected virtual void AfterEffects(IEntity user, RayCastResults ray, Angle angle, float energyModifier)
{ {
var time = IoCManager.Resolve<IGameTiming>().CurTime; var time = IoCManager.Resolve<IGameTiming>().CurTime;
var dist = ray.DidHitObject ? ray.Distance : MaxLength; var dist = ray.Distance;
var offset = angle.ToVec() * dist / 2; var offset = angle.ToVec() * dist / 2;
var message = new EffectSystemMessage var message = new EffectSystemMessage
{ {

View File

@@ -9,6 +9,7 @@ using Content.Server.Observer;
using Content.Shared.Audio; using Content.Shared.Audio;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
using Content.Shared.Maps; using Content.Shared.Maps;
using Content.Shared.Physics;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Server.GameObjects.EntitySystems; using Robust.Server.GameObjects.EntitySystems;
@@ -148,7 +149,13 @@ namespace Content.Server.GameObjects.EntitySystems
private void UpdateKinematics(ITransformComponent transform, IMoverComponent mover, PhysicsComponent physics, CollidableComponent collider = null) private void UpdateKinematics(ITransformComponent transform, IMoverComponent mover, PhysicsComponent physics, CollidableComponent collider = null)
{ {
bool weightless = false; if (physics.Controller == null)
{
// Set up controller
physics.SetController<MoverController>();
}
var weightless = false;
var tile = _mapManager.GetGrid(transform.GridID).GetTileRef(transform.GridPosition).Tile; var tile = _mapManager.GetGrid(transform.GridID).GetTileRef(transform.GridPosition).Tile;
@@ -167,27 +174,27 @@ namespace Content.Server.GameObjects.EntitySystems
&& !entity.HasComponent<ItemComponent>(); // This can't be an item && !entity.HasComponent<ItemComponent>(); // This can't be an item
} }
} }
if (!touching) if (!touching)
{ {
return; return;
} }
} }
if (mover.VelocityDir.LengthSquared < 0.001 || !ActionBlockerSystem.CanMove(mover.Owner))
{
if (physics.LinearVelocity != Vector2.Zero)
physics.LinearVelocity = Vector2.Zero;
if (mover.VelocityDir.LengthSquared < 0.001 || !ActionBlockerSystem.CanMove(mover.Owner) && !weightless)
{
(physics.Controller as MoverController)?.StopMoving();
} }
else else
{ {
if (weightless) if (weightless)
{ {
physics.LinearVelocity = mover.VelocityDir * mover.CurrentPushSpeed; (physics.Controller as MoverController)?.Push(mover.VelocityDir, mover.CurrentPushSpeed);
transform.LocalRotation = mover.VelocityDir.GetDir().ToAngle(); transform.LocalRotation = mover.VelocityDir.GetDir().ToAngle();
return; return;
} }
(physics.Controller as MoverController)?.Move(mover.VelocityDir,
physics.LinearVelocity = mover.VelocityDir * (mover.Sprinting ? mover.CurrentSprintSpeed : mover.CurrentWalkSpeed); mover.Sprinting ? mover.CurrentSprintSpeed : mover.CurrentWalkSpeed);
transform.LocalRotation = mover.VelocityDir.GetDir().ToAngle(); transform.LocalRotation = mover.VelocityDir.GetDir().ToAngle();
// Handle footsteps. // Handle footsteps.

View File

@@ -26,7 +26,7 @@ namespace Content.Server.Throw
var mapManager = IoCManager.Resolve<IMapManager>(); var mapManager = IoCManager.Resolve<IMapManager>();
colComp.CollisionEnabled = true; colComp.CanCollide = true;
// I can now collide with player, so that i can do damage. // I can now collide with player, so that i can do damage.
if (!thrownEnt.TryGetComponent(out ThrownItemComponent projComp)) if (!thrownEnt.TryGetComponent(out ThrownItemComponent projComp))
@@ -37,7 +37,7 @@ namespace Content.Server.Throw
colComp.PhysicsShapes.Add(new PhysShapeAabb()); colComp.PhysicsShapes.Add(new PhysShapeAabb());
colComp.PhysicsShapes[0].CollisionMask |= (int) (CollisionGroup.MobImpassable | CollisionGroup.Impassable); colComp.PhysicsShapes[0].CollisionMask |= (int) (CollisionGroup.MobImpassable | CollisionGroup.Impassable);
colComp.IsScrapingFloor = false; colComp.Status = BodyStatus.InAir;
} }
var angle = new Angle(targetLoc.ToMapPos(mapManager) - sourceLoc.ToMapPos(mapManager)); var angle = new Angle(targetLoc.ToMapPos(mapManager) - sourceLoc.ToMapPos(mapManager));
@@ -58,20 +58,16 @@ namespace Content.Server.Throw
if (!thrownEnt.TryGetComponent(out PhysicsComponent physComp)) if (!thrownEnt.TryGetComponent(out PhysicsComponent physComp))
physComp = thrownEnt.AddComponent<PhysicsComponent>(); physComp = thrownEnt.AddComponent<PhysicsComponent>();
// TODO: Move this into PhysicsSystem, we need an ApplyForce function.
var a = throwForce / (float) Math.Max(0.001, physComp.Mass); // a = f / m
var timing = IoCManager.Resolve<IGameTiming>(); var timing = IoCManager.Resolve<IGameTiming>();
var spd = a / (1f / timing.TickRate); // acceleration is applied in 1 tick instead of 1 second, scale appropriately var spd = throwForce / (1f / timing.TickRate); // acceleration is applied in 1 tick instead of 1 second, scale appropriately
physComp.LinearVelocity = angle.ToVec() * spd; physComp.SetController<ThrowController>();
(physComp.Controller as ThrowController)?.StartThrow(angle.ToVec() * spd);
if (throwSourceEnt != null) if (throwSourceEnt != null && throwSourceEnt.TryGetComponent<PhysicsComponent>(out var physics))
{ {
var p = throwSourceEnt.GetComponent<PhysicsComponent>(); const float ThrowFactor = 5.0f; // Break Newton's Third Law for better gameplay
var playerAccel = 5 * throwForce / (float) Math.Max(0.001, p.Mass); (physics.Controller as MoverController)?.Push(-angle.ToVec(), spd * ThrowFactor / physics.Mass);
p.LinearVelocity = Angle.FromDegrees(angle.Degrees + 180).ToVec()
* playerAccel / (1f / timing.TickRate);
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using Content.Shared.Physics; using Content.Shared.Physics;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.GameObjects.Systems; using Robust.Shared.GameObjects.Systems;
@@ -48,8 +49,8 @@ namespace Content.Server.GameObjects.EntitySystems
if (range > 0f && !(dir.LengthSquared <= range * range)) return false; if (range > 0f && !(dir.LengthSquared <= range * range)) return false;
var ray = new CollisionRay(coords.Position, dir.Normalized, collisionMask); var ray = new CollisionRay(coords.Position, dir.Normalized, collisionMask);
var rayResults = _physicsManager.IntersectRayWithPredicate(coords.MapId, ray, dir.Length, predicate, true); var rayResults = _physicsManager.IntersectRayWithPredicate(coords.MapId, ray, dir.Length, predicate).ToList();
if(!rayResults.DidHitObject || (insideBlockerValid && rayResults.DidHitObject && (rayResults.HitPos - otherCoords).Length < 1f)) if(rayResults.Count == 0 || (insideBlockerValid && rayResults.Count > 0 && (rayResults[0].HitPos - otherCoords).Length < 1f))
{ {
if (_mapManager.TryFindGridAt(coords, out var mapGrid) && mapGrid != null) if (_mapManager.TryFindGridAt(coords, out var mapGrid) && mapGrid != null)

View File

@@ -0,0 +1,61 @@
using System;
using Robust.Shared.Interfaces.Physics;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
namespace Content.Shared.Physics
{
public class MoverController: VirtualController
{
private Vector2 _velocity;
private SharedPhysicsComponent _component = null;
public Vector2 Velocity
{
get => _velocity;
set => _velocity = value;
}
public override SharedPhysicsComponent ControlledComponent
{
set => _component = value;
}
public MoverController()
{
_velocity = Vector2.Zero;
}
public void Move(Vector2 velocityDirection, float speed)
{
if (IoCManager.Resolve<IPhysicsManager>().IsWeightless(_component.Owner.Transform.GridPosition)) return;
Push(velocityDirection, speed);
}
public void Push(Vector2 velocityDirection, float speed)
{
Velocity = velocityDirection * speed;
}
public void StopMoving()
{
Velocity = Vector2.Zero;
}
public override void UpdateBeforeProcessing()
{
base.UpdateBeforeProcessing();
if (Velocity == Vector2.Zero)
{
// Try to stop movement
_component.LinearVelocity = Vector2.Zero;
}
else
{
_component.LinearVelocity = Velocity;
}
}
}
}

View File

@@ -0,0 +1,51 @@
using Robust.Shared.Interfaces.Physics;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Timers;
namespace Content.Shared.Physics
{
public class ThrowController: VirtualController
{
private float _throwTime;
private SharedPhysicsComponent _component;
private const float DefaultThrowTime = 0.25f;
public float ThrowTime
{
get => _throwTime;
set => _throwTime = value;
}
public override SharedPhysicsComponent ControlledComponent
{
set => _component = value;
}
public void StartThrow(Vector2 initialImpulse)
{
_component.Momentum = initialImpulse;
_component.Status = BodyStatus.InAir;
Timer.Spawn((int) (ThrowTime * 1000), StopThrow);
}
public void StopThrow()
{
if (_component == null) return;
if (IoCManager.Resolve<IPhysicsManager>().IsWeightless(_component.Owner.Transform.GridPosition))
{
Timer.Spawn((int) (ThrowTime * 1000), StopThrow);
return;
}
_component.Status = BodyStatus.OnGround;
_component.LinearVelocity = Vector2.Zero;
}
public ThrowController()
{
ThrowTime = DefaultThrowTime;
}
}
}