Skip to content

Commit

Permalink
MASSIVE BREAKING CHANGE!
Browse files Browse the repository at this point in the history
Colliders are now plain old Components. All the special add/removeCollider methods are deprecated
  • Loading branch information
prime31 committed Nov 24, 2016
1 parent eca7981 commit ea8cd09
Show file tree
Hide file tree
Showing 24 changed files with 142 additions and 447 deletions.
4 changes: 2 additions & 2 deletions FAQs/EntitySystems.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ A basic entity processing system. Use this as the base for processing many entit
public override void process( Entity entity )
{
var damage = entity.getComponent<DamageComponent>();
var colliders = Physics.boxcastBroadphase( entity.colliders.mainCollider.bounds, damage.layerMask );
var colliders = Physics.boxcastBroadphase( entity.getComponent<Collider>.bounds, damage.layerMask );

foreach( var coll in colliders )
{
if( entity.colliders.mainCollider.collidesWith( coll, out collResult ) )
if( entity.getComponent<Collider>.collidesWith( coll, out collResult ) )
{
triggerDamage( coll.entity, entity );
entity.enabled = false;
Expand Down
2 changes: 1 addition & 1 deletion FAQs/FarseerPhysics.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The `FSDebugView` Component can be added to your Scene to get a visual represent
## High Level API
The high level API wraps up the Farseer API in standard Nez Components. Farseer Components come in 3 different flavors explained below each of them with a fluent API for configuring the objects for easy method chaining and API exploration.

- **FSRigidBody**: wraps the Farseer Body. Handles keeping the Entity.transform in sync with the Farseer Body. FSRigidBody's can be any of the three body types: Dynamic, Static or Kinematic (see Understanding Farseer Objects for details on each). An FSRigidBody is required for any of the other Farseer Components to be of any use.
- **FSRigidBody**: wraps the Farseer Body. Handles keeping the Entity's Transform in sync with the Farseer Body. FSRigidBody's can be any of the three body types: Dynamic, Static or Kinematic (see Understanding Farseer Objects for details on each). An FSRigidBody is required for any of the other Farseer Components to be of any use.

- **FSCollisionShape**: wraps the Farseer Fixture and Shape objects. This is the physical shape of the collider. You can have 1 or more FSCollisionShapes on your Entity. Available FSCollisionShapes are circle, box, polygon, edge and chain.

Expand Down
20 changes: 10 additions & 10 deletions FAQs/Physics.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ It serves to reiterate what has been stated before: Nez physics is *not* a reali


## Colliders: The Root of the Physics System
Nothing happens in the physics system without Colliders. Colliders live on the Entity class and come in several varieties: BoxCollider, CircleCollider and PolygonCollider. You can add a Collider like so: `entity.colliders.add( new BoxCollider() )`. When you have debugRender enabled Colliders will be displayed with red lines (to enable debugRender either set `Core.debugRenderEnabled = true` or open the console and type "debug-render"). Colliders are automatically added to the SpatialHash when you add them to an Entity, which brings us to our next topic.
Nothing happens in the physics system without Colliders. Colliders live on the Entity class and come in several varieties: BoxCollider, CircleCollider and PolygonCollider. You can add a Collider like so: `entity.addComponent( new BoxCollider() )`. When you have debugRender enabled Colliders will be displayed with red lines (to enable debugRender either set `Core.debugRenderEnabled = true` or open the console and type "debug-render"). Colliders are automatically added to the SpatialHash when you add them to an Entity, which brings us to our next topic.



Expand Down Expand Up @@ -50,16 +50,16 @@ This first example is the easiest way to deal with collisions. `deltaMovement` i
// move the colliding Entity directly adjacent to the hit Collider.
CollisionResult collisionResult;

// do a check to see if entity.colliders[0] (the first Collider on the Entity) collides with any other Colliders in the Scene
// Note that if you have multiple Colliders you could just loop through them instead of only checking the first one.
if( entity.colliders[0].collidesWithAny( ref deltaMovement, out collisionResult ) )
// do a check to see if entity.getComponent<Collider> (the first Collider on the Entity) collides with any other Colliders in the Scene
// Note that if you have multiple Colliders you could fetch and loop through them instead of only checking the first one.
if( entity.getComponent<Collider>.collidesWithAny( ref deltaMovement, out collisionResult ) )
{
// log the CollisionResult. You may want to use it to add some particle effects or anything else relevant to your game.
Debug.log( "collision result: {0}", collisionResult );
}

// move the Entity to the new position. deltaMovement is already adjusted to resolve collisions for us.
entity.transform.position += deltaMovement;
entity.position += deltaMovement;
```


Expand All @@ -69,11 +69,11 @@ If you need a bit more control over what happens when a collision occurs you can
// declare the CollisionResult
CollisionResult collisionResult;

// do a check to see if entity.colliders[0] collides with someOtherCollider
if( entity.colliders[0].collidesWith( someOtherCollider, deltaMovement, out collisionResult ) )
// do a check to see if entity.getComponent<Collider> collides with someOtherCollider
if( entity.getComponent<Collider>.collidesWith( someOtherCollider, deltaMovement, out collisionResult ) )
{
// move entity to the position directly adjacent to the hit Collider then log the CollisionResult
entity.transform.position += deltaMovement - collisionResult.minimumTranslationVector;
entity.position += deltaMovement - collisionResult.minimumTranslationVector;
Debug.log( "collision result: {0}", collisionResult );
}
```
Expand All @@ -82,12 +82,12 @@ We can take the above example a step further using the previously mentioned `Phy

```cs
// fetch anything that we might overlap with at our position excluding ourself. We don't care about ourself here.
var neighborColliders = Physics.boxcastBroadphaseExcludingSelf( entity.colliders[0] );
var neighborColliders = Physics.boxcastBroadphaseExcludingSelf( entity.getComponent<Collider> );

// loop through and check each Collider for an overlap
foreach( var collider in neighborColliders )
{
if( entity.colliders[0].overlaps( collider )
if( entity.getComponent<Collider>.overlaps( collider )
Debug.log( "We are overlapping a Collider: {0}", collider );
}
```
Expand Down
12 changes: 9 additions & 3 deletions Nez.Portable/ECS/Components/FollowCamera.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public enum CameraStyle
public Vector2 mapSize;

Entity _targetEntity;
Collider _targetCollider;
Vector2 _desiredPositionDelta;
CameraStyle _cameraStyle;
RectangleF _worldSpaceDeadzone;
Expand Down Expand Up @@ -160,10 +161,15 @@ void updateFollow()
}
else
{
if( _targetEntity == null || _targetEntity.colliders.mainCollider == null )
return;
// make sure we have a targetCollider for CameraWindow. If we dont bail out.
if( _targetCollider == null )
{
_targetCollider = _targetEntity.getComponent<Collider>();
if( _targetCollider == null )
return;
}

var targetBounds = _targetEntity.colliders.mainCollider.bounds;
var targetBounds = _targetEntity.getComponent<Collider>().bounds;
if( !_worldSpaceDeadzone.contains( targetBounds ) )
{
// x-axis
Expand Down
19 changes: 9 additions & 10 deletions Nez.Portable/ECS/Components/Physics/ArcadeRigidbody.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public float glue
float _friction = 0.5f;
float _glue = 0.01f;
float _inverseMass;
Collider _collider;


public ArcadeRigidbody()
Expand Down Expand Up @@ -159,6 +160,12 @@ public void addImpulse( Vector2 force )
}


public override void onAddedToEntity()
{
_collider = entity.getComponent<Collider>();
}


void IUpdatable.update()
{
if( isImmovable )
Expand All @@ -170,15 +177,14 @@ void IUpdatable.update()
if( shouldUseGravity )
velocity += Physics.gravity * Time.deltaTime;

entity.colliders.unregisterAllCollidersWithPhysicsSystem();
entity.transform.position += velocity * Time.deltaTime;

CollisionResult collisionResult;
// fetch anything that we might collide with at our new position
var neighbors = Physics.boxcastBroadphase( entity.colliders.mainCollider.bounds, entity.colliders.mainCollider.collidesWithLayers );
var neighbors = Physics.boxcastBroadphaseExcludingSelf( _collider, _collider.collidesWithLayers );
foreach( var neighbor in neighbors )
{
if( entity.colliders.mainCollider.collidesWith( neighbor, out collisionResult ) )
if( _collider.collidesWith( neighbor, out collisionResult ) )
{
// if the neighbor has an ArcadeRigidbody we handle full collision response. If not, we calculate things based on the
// neighbor being immovable.
Expand All @@ -198,8 +204,6 @@ void IUpdatable.update()
}
}
}

entity.colliders.registerAllCollidersWithPhysicsSystem();
}


Expand All @@ -212,9 +216,7 @@ void processOverlap( ArcadeRigidbody other, ref Vector2 minimumTranslationVector
{
if( isImmovable )
{
other.entity.colliders.unregisterAllCollidersWithPhysicsSystem();
other.entity.transform.position += minimumTranslationVector;
other.entity.colliders.registerAllCollidersWithPhysicsSystem();
}
else if( other.isImmovable )
{
Expand All @@ -223,10 +225,7 @@ void processOverlap( ArcadeRigidbody other, ref Vector2 minimumTranslationVector
else
{
entity.transform.position -= minimumTranslationVector * 0.5f;

other.entity.colliders.unregisterAllCollidersWithPhysicsSystem();
other.entity.transform.position += minimumTranslationVector * 0.5f;
other.entity.colliders.registerAllCollidersWithPhysicsSystem();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ public float height
/// entity is added to the scene.
/// </summary>
public BoxCollider()
{}
{
// we stick a 1x1 box in here as a placeholder until the next frame when the Collider is added to the Entity and can get more
// accurate auto-sizing data
shape = new Box( 1, 1 );
_colliderRequiresAutoSizing = true;
}


/// <summary>
Expand Down Expand Up @@ -60,8 +65,9 @@ public BoxCollider setWidth( float width )
var box = shape as Box;
if( width != box.width )
{
// update the box and if we need to update our bounds in the Physics system
// update the box, dirty our bounds and if we need to update our bounds in the Physics system
box.updateBox( width, box.height );
_isPositionDirty = true;
if( entity != null && _isParentEntityAddedToScene )
Physics.updateCollider( this );
}
Expand All @@ -75,8 +81,9 @@ public BoxCollider setHeight( float height )
var box = shape as Box;
if( height != box.height )
{
// update the box and if we need to update our bounds in the Physics system
// update the box, dirty our bounds and if we need to update our bounds in the Physics system
box.updateBox( box.width, height );
_isPositionDirty = true;
if( entity != null && _isParentEntityAddedToScene )
Physics.updateCollider( this );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ public float radius
/// entity is added to the scene.
/// </summary>
public CircleCollider()
{ }
{
// we stick a 1px circle in here as a placeholder until the next frame when the Collider is added to the Entity and can get more
// accurate auto-sizing data
shape = new Circle( 1 );
_colliderRequiresAutoSizing = true;
}


/// <summary>
Expand All @@ -44,6 +49,7 @@ public CircleCollider setRadius( float radius )
if( radius != ( (Circle)shape ).radius )
{
( (Circle)shape ).radius = radius;
( (Circle)shape )._originalRadius = radius;
_isPositionDirty = true;

if( entity != null && _isParentEntityAddedToScene )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,8 @@

namespace Nez
{
public abstract class Collider
public abstract class Collider : Component
{
/// <summary>
/// the entity that owns this Collider
/// </summary>
public Entity entity;

/// <summary>
/// the underlying Shape of the Collider
/// </summary>
Expand Down Expand Up @@ -89,6 +84,7 @@ public virtual RectangleF bounds
/// safely remove the Collider from the Physics system even if it was moved before attempting to remove it.
/// </summary>
internal RectangleF registeredPhysicsBounds;
protected bool _colliderRequiresAutoSizing;

protected Vector2 _localOffset;
internal float _localOffsetLength;
Expand Down Expand Up @@ -143,14 +139,11 @@ public Collider setShouldColliderScaleAndRotateWithTransform( bool shouldCollide
#endregion


#region Collider Lifecycle
#region Component Lifecycle

/// <summary>
/// Called when the parent entity is added to a scene
/// </summary>
public virtual void onEntityAddedToScene()
public override void onAddedToEntity()
{
if( shape == null )
if( _colliderRequiresAutoSizing )
{
// we only deal with boxes and circles here
Assert.isTrue( this is BoxCollider || this is CircleCollider, "Only box and circle colliders can be created automatically" );
Expand All @@ -168,16 +161,17 @@ public virtual void onEntityAddedToScene()
// circle colliders need special care with the origin
if( this is CircleCollider )
{
var circle = this as CircleCollider;
circle.shape = new Circle( width * 0.5f );
circle.radius = Math.Max( width, height ) * 0.5f;
var circleCollider = this as CircleCollider;
circleCollider.radius = Math.Max( width, height ) * 0.5f;

// fetch the Renderable's center, transfer it to local coordinates and use that as the localOffset of our collider
localOffset = renderableBounds.center - entity.transform.position;
}
else
{
shape = new Box( width, height );
var boxCollider = this as BoxCollider;
boxCollider.width = width;
boxCollider.height = height;

// fetch the Renderable's center, transfer it to local coordinates and use that as the localOffset of our collider
localOffset = renderableBounds.center - entity.transform.position;
Expand All @@ -189,17 +183,14 @@ public virtual void onEntityAddedToScene()
}


/// <summary>
/// Called when the parent entity is removed from a scene
/// </summary>
public virtual void onEntityRemovedFromScene()
public override void onRemovedFromEntity()
{
unregisterColliderWithPhysicsSystem();
_isParentEntityAddedToScene = false;
}


public virtual void onEntityTransformChanged( Transform.Component comp )
public override void onEntityTransformChanged( Transform.Component comp )
{
// set the appropriate dirty flags
switch( comp )
Expand All @@ -220,6 +211,20 @@ public virtual void onEntityTransformChanged( Transform.Component comp )
}


public override void onEnabled()
{
registerColliderWithPhysicsSystem();
}


public override void onDisabled()
{
unregisterColliderWithPhysicsSystem();
}

#endregion


/// <summary>
/// the parent Entity will call this at various times (when added to a scene, enabled, etc)
/// </summary>
Expand All @@ -244,8 +249,6 @@ public virtual void unregisterColliderWithPhysicsSystem()
_isColliderRegistered = false;
}

#endregion


#region collision checks

Expand Down Expand Up @@ -376,11 +379,7 @@ public bool collidesWithAny( ref Vector2 motion, out CollisionResult result )
#endregion


public virtual void debugRender( Graphics graphics )
{ }


public virtual Collider clone()
public override Component clone()
{
var collider = MemberwiseClone() as Collider;
collider.entity = null;
Expand Down

0 comments on commit ea8cd09

Please sign in to comment.