package com.gebauz.bauzoid.math.collision;
import com.badlogic.gdx.Gdx;
import com.gebauz.bauzoid.graphics.Graphics;
import com.gebauz.bauzoid.graphics.sprite.SpriteTransform;
import com.gebauz.bauzoid.math.Line2;
import com.gebauz.bauzoid.math.Vector2;
import com.gebauz.bauzoid.math.collision.Shape;
/** Interface for shape element. */
public abstract class BaseShapeElement
{
// Constants========================================================================================
// Embedded Types===================================================================================
// Fields===========================================================================================
private Shape mOwner =
null;
public Line2 trajectory =
null;
// Methods==========================================================================================
public BaseShapeElement
(Shape shape
)
{
mOwner = shape
;
}
public abstract BaseShapeElement copy
(Shape newOwner
);
//public abstract boolean isInside(float x, float y);
/** Returns true if the shape intersects with this shape element.
* @param shape The shape tested against.
* @param transform Transformation matrix that brings this shape element's points into shape's space.
*/
//public abstract boolean intersects(Shape shape, Matrix4 transform);
/** Returns true if the shape intersects with this shape element. Returns a displacement vector
* that specifies by how much this shape element needs to be displaced in order to become non-colliding.
* @param shape The shape tested against.
* @param transform Transformation matrix that brings this shape element's points into shape's space.
*/
/*public abstract boolean intersects(Shape shape, Matrix4 transform, Vector2 displaceResult);
public abstract boolean intersectsLine(Line2 line);*/
/** Calculate intersection with a group of shape elements. */
public CollisionResult collide
(Shape shape
)
{
return collide
(shape,
null);
}
/** Calculate intersection with a group of shape elements along movement vector. */
public CollisionResult collide
(Shape shape, Vector2 move
)
{
CollisionResult result =
new CollisionResult
();
// move
float tempX = getOwner
().
transform.
x;
float tempY = getOwner
().
transform.
y;
if (move
!=
null)
{
getOwner
().
transform.
x += move.
x;
getOwner
().
transform.
y += move.
y;
}
//Vector2 contactPoints[] = new Vector2[shape.getShapeElementCount()];
Vector2 contactPoint =
new Vector2
();
int numContactPoints =
0;
for (int i =
0; i
< shape.
getShapeElementCount(); i++
)
{
//Line2[] poly1 = getSweepLineSegments(move);
Line2
[] poly1 = getLineSegments
();
Vector2
[] axes1 = getProjectionAxes
();
Line2
[] poly2 = shape.
getShapeElement(i
).
getLineSegments();
Vector2
[] axes2 = shape.
getShapeElement(i
).
getProjectionAxes();
// do magic
CollisionUtil.
PenetrationResult penetrationResult = CollisionUtil.
calculatePenetration(poly1, poly2, axes1, axes2
);
if (penetrationResult.
penetrationVector !=
null)
{
result.
isColliding =
true;
result.
penetrationVector.
addVector(penetrationResult.
penetrationVector);
//result.collidingEdge = penetrationResult.penetrationEdge.copy();
// apply correction
getOwner
().
transform.
x += penetrationResult.
penetrationVector.
x;
getOwner
().
transform.
y += penetrationResult.
penetrationVector.
y;
//contactPoints[numContactPoints] = penetrationResult.contactPoint;
numContactPoints =
1;
contactPoint = penetrationResult.
contactPoint;
//contactPoint.addVector(penetrationResult.contactPoint);
//numContactPoints++;
}
}
if (result.
isColliding)
{
// get contact point
contactPoint.
x /= numContactPoints
;
contactPoint.
y /= numContactPoints
;
result.
contactPoint = contactPoint
;
}
// restore original position (result penetration vector is going to be applied outside)
getOwner
().
transform.
x = tempX
;
getOwner
().
transform.
y = tempY
;
return result
;
}
/** Collide with a ray.
* Only returns a contact point, no penetration vector.
*/
public CollisionResult collideRayCast
(Line2 ray
)
{
Line2 lines
[] = getUntransformedLineSegments
();
float minimumDistanceSqr =
Float.
MAX_VALUE;
Vector2 contact =
null;
for (int i =
0; i
< lines.
length; i++
)
{
Vector2 p = ray.
getSegmentIntersection(lines
[i
]);
if (p ==
null)
continue;
float distanceSqr = p.
squaredLength();
if ((contact ==
null) ||
(distanceSqr
< minimumDistanceSqr
))
{
minimumDistanceSqr = distanceSqr
;
contact = p
;
}
}
CollisionResult cr =
new CollisionResult
();
if (contact
!=
null)
{
//Gdx.app.log("BLA", "Raycast detected");
cr.
isColliding =
true;
cr.
contactPoint = contact.
copy();
}
return cr
;
}
/** Render debug output. */
public abstract void renderDebug
(Graphics graphics, SpriteTransform t
);
/** Get a list of untransformed points that make up the polygon. */
public abstract Vector2
[] getUntransformedPoints
();
/** Get a list of transformed (with the parent shape's SpriteTransform) points that make up the polygon. */
public abstract Vector2
[] getPoints
();
/** Get a list of untransformed line segments that make up the polygon. */
public abstract Line2
[] getUntransformedLineSegments
();
/** Get a list of transformed (with the parent shape's SpriteTransform) line segments that make up the polygon. */
public abstract Line2
[] getLineSegments
();
/** Get a list of transformed line segments including the swept shape. */
public abstract Line2
[] getSweepLineSegments
(Vector2 move
);
/** Get all vectors for all distinct projection axes for separating axis theorem. */
public abstract Vector2
[] getProjectionAxes
();
// Getters/Setters==================================================================================
public final void setOwner
(Shape shape
)
{
mOwner = shape
;
}
public final Shape getOwner
()
{
return mOwner
;
}
public final SpriteTransform getTransform
()
{
return mOwner.
transform;
}
public final Vector2 getCenter
()
{
Vector2 result =
new Vector2
();
Vector2
[] points = getPoints
();
for (int i =
0; i
< points.
length; i++
)
{
result.
addVector(points
[i
]);
}
result.
x /= points.
length;
result.
y /= points.
length;
return result
;
}
}