package com.gebauz.bauzoid.math.collision;
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;
protected Vector2
[] mProjectionAxes =
null;
protected Vector2
[] mPoints =
null;
protected Vector2
[] mUntransformedPoints =
null;
protected Line2
[] mLines =
null;
protected Line2
[] mUntransformedLines =
null;
protected Line2
[] mSweepLines =
null;
private Vector2 mIntersectionPoint =
new Vector2
();
private Vector2 mContactPoint =
new Vector2
();
private CollisionUtil.
PenetrationResult penetrationResult =
new CollisionUtil.
PenetrationResult();
private int mStartFrame = -
1;
private int mEndFrame = -
1;
// Methods==========================================================================================
public BaseShapeElement
(Shape shape,
int startFrame,
int endFrame
)
{
mOwner = shape
;
mStartFrame = startFrame
;
mEndFrame = endFrame
;
}
/** Copy shape with new owner. */
public abstract BaseShapeElement copy
(Shape newOwner
);
/** 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.
* Returns true if a collision occurs.
* resultPenetration contains the minimal penetration vector.
* resultContactPoint contains the contact point.
*/
public boolean collide
(Shape shape, Vector2 move, Vector2 resultPenetration, Vector2 resultContactPoint
)
{
//CollisionResult result = new CollisionResult();
resultPenetration.
set(0,
0);
resultContactPoint.
set(0,
0);
boolean isColliding =
false;
// move
float tempX = getOwner
().
transform.
x;
float tempY = getOwner
().
transform.
y;
if (move
!=
null)
{
getOwner
().
transform.
x += move.
x;
getOwner
().
transform.
y += move.
y;
}
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();
penetrationResult.
reset();
if (CollisionUtil.
calculatePenetration(poly1, poly2, axes1, axes2, penetrationResult
))
{
isColliding =
true;
resultPenetration.
addVector(penetrationResult.
penetrationVector);
// apply correction
getOwner
().
transform.
x += penetrationResult.
penetrationVector.
x;
getOwner
().
transform.
y += penetrationResult.
penetrationVector.
y;
numContactPoints =
1;
mContactPoint.
setFrom(penetrationResult.
contactPoint);
}
}
if (isColliding
)
{
// get contact point
mContactPoint.
x /= numContactPoints
;
mContactPoint.
y /= numContactPoints
;
resultContactPoint.
setFrom(mContactPoint
);
}
// restore original position (result penetration vector is going to be applied outside)
getOwner
().
transform.
x = tempX
;
getOwner
().
transform.
y = tempY
;
return isColliding
;
}
/** Collide with a ray.
* Only returns a contact point, no penetration vector.
*/
public boolean collideRayCast
(Line2 ray, Vector2 resultContactPoint
)
{
Line2 lines
[] = getUntransformedLineSegments
();
float minimumDistanceSqr =
Float.
MAX_VALUE;
boolean foundContact =
false;
for (int i =
0; i
< lines.
length; i++
)
{
if (!ray.
getSegmentIntersection(lines
[i
], mIntersectionPoint
))
continue;
float dx = mIntersectionPoint.
x - ray.
a.
x;
float dy = mIntersectionPoint.
y - ray.
a.
y;
float distanceSqr = dx
*dx + dy
*dy
;
if (distanceSqr
< minimumDistanceSqr
)
{
minimumDistanceSqr = distanceSqr
;
resultContactPoint.
setFrom(mIntersectionPoint
);
foundContact =
true;
}
}
return foundContact
;
}
/** Check if the shape intersects a circle. */
public boolean intersectsCircleSqr
(float x,
float y,
float radiusSqr
)
{
Line2
[] poly = getLineSegments
();
//Gdx.app.log("BLA", "--------------");
//Gdx.app.log("BLA", "p: " + x + ", " + y + " r: " + radiusSqr);
for (int i =
0; i
< poly.
length; i++
)
{
Line2 l = poly
[i
];
float distanceSqr = l.
getClosestSquaredDistanceFrom(x, y
);
//Gdx.app.log("BLA", "a: " + l.a.x + ", " + l.a.y + " - " + l.b.x + ", " + l.b.y + " d: " + distanceSqr);
if (distanceSqr
<= radiusSqr
)
return true;
}
return false;
}
public boolean isInFrameRange
(int frame
)
{
int startFrame = mStartFrame
;
int endFrame = mEndFrame
;
if (startFrame == -
1)
startFrame =
0;
if (endFrame == -
1)
endFrame =
Integer.
MAX_VALUE;
return ((frame
>= startFrame
) && (frame
<= endFrame
));
}
/** Check if the point lies inside the shape element. The point should be specified in the shape's sprite space. */
public abstract boolean isInside
(float x,
float y
);
/** 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
;
}
}