Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collision data shape ordering (second attempt) #45

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions echo/Shape.hx
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,11 @@ class Shape #if cog implements cog.IComponent #end {

public function collides(s:Shape):Null<CollisionData> return null;

function collide_rect(r:Rect):Null<CollisionData> return null;
function collide_rect(r:Rect, flip:Bool = false):Null<CollisionData> return null;

function collide_circle(c:Circle):Null<CollisionData> return null;
function collide_circle(c:Circle, flip:Bool = false):Null<CollisionData> return null;

function collide_polygon(p:Polygon):Null<CollisionData> return null;
function collide_polygon(p:Polygon, flip:Bool = false):Null<CollisionData> return null;

function toString() {
var s = switch (type) {
Expand Down
8 changes: 4 additions & 4 deletions echo/shape/Circle.hx
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,13 @@ class Circle extends Shape implements Poolable {
return false;
}

override inline function collides(s:Shape):Null<CollisionData> return s.collide_circle(this);
override inline function collides(s:Shape):Null<CollisionData> return s.collide_circle(this, true);

override inline function collide_rect(r:Rect):Null<CollisionData> return r.rect_and_circle(this, true);
override inline function collide_rect(r:Rect, flip:Bool = false):Null<CollisionData> return r.rect_and_circle(this, !flip);

override inline function collide_circle(c:Circle):Null<CollisionData> return c.circle_and_circle(this);
override inline function collide_circle(c:Circle, flip:Bool = false):Null<CollisionData> return c.circle_and_circle(this, !flip);

override inline function collide_polygon(p:Polygon):Null<CollisionData> return this.circle_and_polygon(p, true);
override inline function collide_polygon(p:Polygon, flip:Bool = false):Null<CollisionData> return this.circle_and_polygon(p, flip);

// getters
inline function get_radius():Float return local_radius * scale_x;
Expand Down
8 changes: 4 additions & 4 deletions echo/shape/Polygon.hx
Original file line number Diff line number Diff line change
Expand Up @@ -197,13 +197,13 @@ class Polygon extends Shape implements Poolable {
return false;
}

override inline function collides(s:Shape):Null<CollisionData> return s.collide_polygon(this);
override inline function collides(s:Shape):Null<CollisionData> return s.collide_polygon(this, true);

override inline function collide_rect(r:Rect):Null<CollisionData> return r.rect_and_polygon(this, true);
override inline function collide_rect(r:Rect, flip:Bool = false):Null<CollisionData> return r.rect_and_polygon(this, !flip);

override inline function collide_circle(c:Circle):Null<CollisionData> return c.circle_and_polygon(this);
override inline function collide_circle(c:Circle, flip:Bool = false):Null<CollisionData> return c.circle_and_polygon(this, !flip);

override inline function collide_polygon(p:Polygon):Null<CollisionData> return p.polygon_and_polygon(this, true);
override inline function collide_polygon(p:Polygon, flip:Bool = false):Null<CollisionData> return this.polygon_and_polygon(p, flip);

override inline function get_top():Float {
if (count == 0 || vertices[0] == null) return y;
Expand Down
8 changes: 4 additions & 4 deletions echo/shape/Rect.hx
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,13 @@ class Rect extends Shape implements Poolable {
return false;
}

override inline function collides(s:Shape):Null<CollisionData> return s.collide_rect(this);
override inline function collides(s:Shape):Null<CollisionData> return s.collide_rect(this, true);

override inline function collide_rect(r:Rect):Null<CollisionData> return r.rect_and_rect(this);
override inline function collide_rect(r:Rect, flip:Bool = false):Null<CollisionData> return this.rect_and_rect(r, flip);

override inline function collide_circle(c:Circle):Null<CollisionData> return this.rect_and_circle(c);
override inline function collide_circle(c:Circle, flip:Bool = false):Null<CollisionData> return this.rect_and_circle(c, flip);

override inline function collide_polygon(p:Polygon):Null<CollisionData> return this.rect_and_polygon(p);
override inline function collide_polygon(p:Polygon, flip:Bool = false):Null<CollisionData> return this.rect_and_polygon(p, flip);

override function set_parent(?body:Body) {
super.set_parent(body);
Expand Down
37 changes: 25 additions & 12 deletions echo/util/SAT.hx
Original file line number Diff line number Diff line change
Expand Up @@ -190,17 +190,17 @@ class SAT {
var col:CollisionData = null;
if (rect1.rotation != 0 || rect2.rotation != 0) {
if (rect1.transformed_rect != null) {
col = rect_and_polygon(rect2, rect1.transformed_rect, flip);
col = rect_and_polygon(rect2, rect1.transformed_rect, !flip);

if (col == null) return null;

if (flip) col.sa = rect1;
if (flip) col.sa = rect2;
else col.sb = rect1;

return col;
}
if (rect2.transformed_rect != null) {
col = rect_and_polygon(rect1, rect2.transformed_rect, !flip);
col = rect_and_polygon(rect1, rect2.transformed_rect, flip);

if (col == null) return null;

Expand Down Expand Up @@ -318,6 +318,7 @@ class SAT {
data1.put();
return data2;
}

/**
* Test a Rect and a Circle for a Collision.
* @param r
Expand All @@ -327,19 +328,24 @@ class SAT {
*/
public static function rect_and_circle(r:Rect, c:Circle, flip:Bool = false):Null<CollisionData> {
if (r.transformed_rect != null && r.rotation != 0) {
var col = circle_and_polygon(c, r.transformed_rect, flip);
var col = circle_and_polygon(c, r.transformed_rect, !flip);

if (col == null) return null;

if (flip) col.sa = r;
else col.sb = r;
// collisions used the transformed rect, set the collision data's shape back
// to the original rect
if (!flip) {
col.sa = r;
} else {
col.sb = r;
}

return col;
}

// Vector from A to B
var nx = flip ? c.x - r.x : r.x - c.x;
var ny = flip ? c.y - r.y : r.y - c.y;
var nx = flip ? r.x - c.x : c.x - r.x;
var ny = flip ? r.y - c.y : c.y - r.y;
// Closest point on A to center of B
var cx = nx;
var cy = ny;
Expand Down Expand Up @@ -407,8 +413,13 @@ class SAT {

if (col == null) return null;

if (flip) col.sb = r;
else col.sa = r;
// collisions were done with a polygon derrived from the provided rect
// so we need to set our collision data shape back to the original rectangle
if (flip) {
col.sb = r;
} else {
col.sa = r;
}

return col;
}
Expand Down Expand Up @@ -495,7 +506,7 @@ class SAT {
test1 = min1 - max2;
test2 = min2 - max1;

// Preform another test
// Preform another test // TODO: What is this test doing, exactly?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't articulate exactly what this test is doing, so a short descriptor might help future folks if they need to come in here for any reason.

if (test1 > 0 || test2 > 0) {
col.put();
return null;
Expand Down Expand Up @@ -579,7 +590,9 @@ class SAT {
col.sa = flip ? polygon2 : polygon1;
col.sb = flip ? polygon1 : polygon2;

if (flip) {
// collision normal is calculated as resolution for poly2, so we need to
// negate the normal if we are not flipping the collision check.
if (!flip) {
col.normal.negate();
}

Expand Down
2 changes: 1 addition & 1 deletion sample/Main.hx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class Main extends BaseApp {

// Set up our Sample States
sample_states = [
PolygonState, StackingState, MultiShapeState, ShapesState, GroupsState, StaticState, LinecastState, Linecast2State, TileMapState, TileMapState2,
OverlappingSpawnState, ListenerState, PolygonState, StackingState, MultiShapeState, ShapesState, GroupsState, StaticState, LinecastState, Linecast2State, TileMapState, TileMapState2,
BezierState, VerletState
];
index = 0;
Expand Down
82 changes: 82 additions & 0 deletions sample/state/ListenerState.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package state;

import echo.data.Options.ListenerOptions;
import echo.Material;
import echo.Body;
import echo.World;
import util.Random;

class ListenerState extends BaseState {

override public function enter(world:World) {
Main.instance.state_text.text = "Sample: Collision Listener";

// Create a material for all the shapes to share
var material:Material = {elasticity: 0.7};

var bodyA = new Body({
x: Random.range(60, world.width - 60),
y: Random.range(0, world.height / 2),
// rotation: Random.range(0, 360),
material: material,
shapes: [
{
type: POLYGON,
radius: Random.range(16, 32),
width: Random.range(16, 48),
height: Random.range(16, 48),
sides: Random.range_int(3, 8),
offset_y: -10,
},
{
type: POLYGON,
radius: Random.range(16, 32),
width: Random.range(16, 48),
height: Random.range(16, 48),
sides: Random.range_int(3, 8),
offset_y: 10,
}
]
});
world.add(bodyA);

// Add a Physics body at the bottom of the screen for the other Physics Bodies to stack on top of
// This body has a mass of 0, so it acts as an immovable object
var bodyB = new Body({
mass: STATIC,
x: world.width / 5,
y: world.height - 40,
material: material,
rotation: 5,
shape: {
type: RECT,
width: world.width,
height: 20
}
});
world.add(bodyB);

var dbgOpts:ListenerOptions = {
enter: (a, b, data) -> {
trace('bodyA == listener `a`: ${bodyA == a}');
// the second shape is our 'bottom' shape that is making the collision
trace('bodyA owns data `shape a`: ${bodyA.shapes.contains(data[0].sa)}');
trace('bodyB == listener `b`: ${bodyB == b}');
trace('bodyB owns `shape b`: ${bodyB.shapes.contains(data[0].sb)}');
},
};

// Create a listener for collisions between the Physics Bodies
world.listen(bodyA, bodyB, dbgOpts);
}

override function step(world:World, dt:Float) {
// Reset any off-screen Bodies
world.for_each((member) -> {
if (offscreen(member, world)) {
member.velocity.set(0, 0);
member.set_position(Random.range(0, world.width), 0);
}
});
}
}
72 changes: 72 additions & 0 deletions sample/state/OverlappingSpawnState.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package state;

import echo.data.Options.ListenerOptions;
import echo.Material;
import echo.Body;
import echo.World;
import util.Random;

class OverlappingSpawnState extends BaseState {

override public function enter(world:World) {
Main.instance.state_text.text = "Sample: Collision Listener";

// Create a material for all the shapes to share
var material:Material = {elasticity: 0.7};

var body = new Body({
x: 200,
y: 50,
rotation: 0,
material: material,
shape: {
type: CIRCLE,
radius: 16,
offset_y: 0,
}
});
world.add(body);

// body = new Body({
// x: 200,
// y: 53,
// rotation: 0,
// material: material,
// shape: {
// type: CIRCLE,
// radius: 12,
// offset_y: 0,
// }
// });
// world.add(body);

// Add a Physics body at the bottom of the screen for the other Physics Bodies to stack on top of
// This body has a mass of 0, so it acts as an immovable object
var floor = new Body({
mass: STATIC,
x: world.width / 5,
y: world.height - 40,
material: material,
// rotation: 5,
shape: {
type: RECT,
width: world.width,
height: 20
}
});
world.add(floor);

// Create a listener for collisions between the Physics Bodies
world.listen();
}

override function step(world:World, dt:Float) {
// Reset any off-screen Bodies
world.for_each((member) -> {
if (offscreen(member, world)) {
member.velocity.set(0, 0);
member.set_position(Random.range(0, world.width), 0);
}
});
}
}
2 changes: 1 addition & 1 deletion sample/state/PolygonState.hx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class PolygonState extends BaseState {
var b = new Body({
x: Random.range(60, world.width - 60),
y: Random.range(0, world.height / 2),
rotation: Random.range(0, 360),
rotation: 0,
material: material,
shape: {
type: POLYGON,
Expand Down
2 changes: 2 additions & 0 deletions sample/state/StaticState.hx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class StaticState extends BaseState {
shape: {
type: CIRCLE,
radius: Random.range(2, 4),
width: Random.range(2, 4),
height: Random.range(2, 4)
}
});
world.add(b);
Expand Down