using System; using System.Collections.Generic; using System.Linq; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.Interfaces.Physics; using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Physics; using Robust.Shared.ViewVariables; namespace Robust.Client.GameObjects { public class CollidableComponent : Component, ICollidableComponent { #pragma warning disable 649 [Dependency] private readonly IPhysicsManager _physicsManager; #pragma warning restore 649 private bool _collisionIsActuallyEnabled; private bool _collisionEnabled; private List _physShapes; /// public override string Name => "Collidable"; /// public override uint? NetID => NetIDs.COLLIDABLE; /// public override Type StateType => typeof(CollidableComponentState); /// [ViewVariables] Box2 IPhysBody.WorldAABB { get { var pos = Owner.Transform.WorldPosition; return ((IPhysBody) this).AABB.Translated(pos); } } /// [ViewVariables] Box2 IPhysBody.AABB { get { var angle = Owner.Transform.WorldRotation; var bounds = new Box2(); foreach (var shape in _physShapes) { var shapeBounds = shape.CalculateLocalBounds(angle); bounds = bounds.IsEmpty() ? shapeBounds : bounds.Union(shapeBounds); } return bounds; } } /// [ViewVariables] public List PhysicsShapes { get => _physShapes; } /// [ViewVariables] public MapId MapID => Owner.Transform.MapID; /// void IPhysBody.Bumped(IEntity bumpedby) { SendMessage(new BumpedEntMsg(bumpedby)); } /// void IPhysBody.Bump(List bumpedinto) { var collidecomponents = Owner.GetAllComponents().ToList(); for (var i = 0; i < collidecomponents.Count; i++) { collidecomponents[i].CollideWith(bumpedinto); } } /// [ViewVariables] public bool CollisionEnabled { get => _collisionEnabled; set { if (value == _collisionEnabled) { return; } _collisionEnabled = value; if (value) { EnableCollision(); } else { DisableCollision(); } } } /// [ViewVariables] public bool IsHardCollidable { get; set; } /// [ViewVariables] public int CollisionLayer { get; set; } /// [ViewVariables] public int CollisionMask { get; set; } /// /// gets the AABB from the sprite component and sends it to the CollisionManager. /// public override void Initialize() { base.Initialize(); // normally ExposeData would create this if(_physShapes == null) _physShapes = new List{new PhysShapeAabb()}; if (_collisionEnabled && !_collisionIsActuallyEnabled) { _physicsManager.AddBody(this); _collisionIsActuallyEnabled = true; } } /// /// removes the AABB from the CollisionManager. /// public override void Shutdown() { if (_collisionEnabled) { _physicsManager.RemoveBody(this); } base.Shutdown(); } /// public override void HandleComponentState(ComponentState curState, ComponentState nextState) { if (curState == null) return; var newState = (CollidableComponentState) curState; // edge triggered if (newState.CollisionEnabled == _collisionEnabled) return; if (newState.CollisionEnabled) EnableCollision(); else DisableCollision(); _physShapes = newState.PhysShapes; } /// public bool TryCollision(Vector2 offset, bool bump = false) { return _physicsManager.TryCollide(Owner, offset, bump); } /// /// Enables PhysicsBody /// private void EnableCollision() { _collisionEnabled = true; _collisionIsActuallyEnabled = true; _physicsManager.AddBody(this); } /// /// Disables PhysicsBody /// private void DisableCollision() { _collisionEnabled = false; _collisionIsActuallyEnabled = false; _physicsManager.RemoveBody(this); } } }