package com.gebauz.burutaru.game.entities;
import java.util.Vector;
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.AABoundingBox;
import com.gebauz.bauzoid.math.collision.BaseShapeElement;
import com.gebauz.bauzoid.math.collision.Shape;
import com.gebauz.burutaru.game.GameLogic;
import com.gebauz.burutaru.game.entities.enemies.EnemyInstance;
import com.gebauz.burutaru.game.entities.level.elements.BaseLevelElement;
/** Global collision world that contains different colliders. */
public class CollisionWorld
extends Entity
{
// Constants========================================================================================
public static final int FILTER_LEVEL_ELEMENTS =
1;
public static final int FILTER_ENEMIES =
2;
public static final int FILTER_ALL = FILTER_LEVEL_ELEMENTS | FILTER_ENEMIES
;
// Embedded Types===================================================================================
public static class CollisionInfo
{
public boolean isColliding =
false;
public Vector2 penetrationVector =
new Vector2
();
public Vector2 contactPoint =
new Vector2
();
public BaseLevelElement collidingLevelObject =
null;
//public Entity collidingEntity = null;
public EnemyInstance collidingEnemyInstance =
null;
public void reset
()
{
isColliding =
false;
collidingLevelObject =
null;
collidingEnemyInstance =
null;
}
}
public class ColliderInfo
{
public int collisionFilter =
0;
public EnemyInstance enemyInstance =
null;
public BaseLevelElement levelElement =
null;
public Shape shape =
null;
public ColliderInfo
(EnemyInstance enemy,
Shape enemyShape
)
{
collisionFilter = FILTER_ENEMIES
;
enemyInstance = enemy
;
shape = enemyShape
;
}
public ColliderInfo
(BaseLevelElement levelObject,
Shape objShape
)
{
collisionFilter = FILTER_LEVEL_ELEMENTS
;
levelElement = levelObject
;
shape = objShape
;
}
public final boolean contains
(int filter
)
{
return ((collisionFilter
& filter
) !=
0);
}
public final boolean isColliderAlive
()
{
if (contains
(FILTER_LEVEL_ELEMENTS
))
return (levelElement.
isAlive());
if (contains
(FILTER_ENEMIES
))
return (enemyInstance.
isAlive());
return false;
}
}
// Fields===========================================================================================
/** Collection of passive colliders. */
private Vector<ColliderInfo
> mColliders =
new Vector<ColliderInfo
>();
/** Temp variables. */
private Vector2 mResultPenetration =
new Vector2
();
private Vector2 mResultContactPoint =
new Vector2
();
private AABoundingBox mTempBoundingBox =
new AABoundingBox
();
private Line2 mRay =
new Line2
();
private Vector2 p1 =
new Vector2
();
private Vector2 p2 =
new Vector2
();
// Methods==========================================================================================
public CollisionWorld
(GameLogic gameLogic
)
{
super(gameLogic
);
}
@
Override
public void initAsync
()
{
}
@
Override
public void init
()
{
}
@
Override
public void exit
()
{
}
@
Override
public void update
(float deltaTime
)
{
}
@
Override
public void render
()
{
}
/** Add Reference to a passive collider. */
public void addPassiveCollider
(BaseLevelElement obj,
Shape shape
)
{
//mPassiveColliders.add(new PassiveColliderInfo(obj, shape));
mColliders.
add(new ColliderInfo
(obj, shape
));
}
public void addEnemyCollider
(EnemyInstance obj,
Shape shape
)
{
//mEnemyColliders.add(new EnemyColliderInfo(obj, shape));
mColliders.
add(new ColliderInfo
(obj, shape
));
}
/** Check for collision of shape with passive colliders, return contact point and minimal translation vector.
* Suitable for ship<->environment collisions.
*/
public boolean checkCollisionSat
(int filter,
Shape shape, Vector2 move, CollisionInfo result
)
{
result.
reset();
// Check broadphase collision
shape.
transform.
x += move.
x;
shape.
transform.
y += move.
y;
AABoundingBox box1 = shape.
getTransformedBoundingBox();
// Check collision between object and level objects
for (int i =
0; i
< mColliders.
size(); i++
)
{
ColliderInfo info = mColliders.
get(i
);
if (!info.
contains(filter
))
continue;
if (!info.
isColliderAlive())
continue;
AABoundingBox box2 = info.
shape.
getTransformedBoundingBox();
if (!box1.
intersetcs(box2
))
continue;
if (shape.
getShapeElement(0).
collide(info.
shape, move, mResultPenetration, mResultContactPoint
))
{
result.
isColliding =
true;
result.
penetrationVector.
setFrom(mResultPenetration
);
if (info.
contains(FILTER_LEVEL_ELEMENTS
))
result.
collidingLevelObject = info.
levelElement;
else if (info.
contains(FILTER_ENEMIES
))
result.
collidingEnemyInstance = info.
enemyInstance;
if (mResultContactPoint
!=
null)
result.
contactPoint.
setFrom(mResultContactPoint
);
}
}
shape.
transform.
x -= move.
x;
shape.
transform.
y -= move.
y;
return result.
isColliding;
}
/** Check for collision by raycasting and return a contact point only (no minimal translation vector).
* Only suitable for thin objects where raycasting suffices as a collision detection scheme.
* Suitable for fast, thin projectile <-> environment collisions.
*/
//public CollisionInfo collideRaycast(int filter, Vector2 pos, Vector2 velocity)
public boolean checkCollisionRaycast
(int filter, Vector2 rayPos, Vector2 rayDir, CollisionInfo result
)
{
mTempBoundingBox.
setFromRay(rayPos, rayDir
);
float minimumDistanceSqr =
Float.
MAX_VALUE;
result.
isColliding =
false;
// Check raycasts between object and level objects
for (int i =
0; i
< mColliders.
size(); i++
)
{
ColliderInfo info = mColliders.
get(i
);
if (!info.
contains(filter
))
continue;
if (!info.
isColliderAlive())
continue;
AABoundingBox box2 = info.
shape.
getTransformedBoundingBox();
if (!mTempBoundingBox.
intersetcs(box2
))
continue;
// transform ray into the shape's space
SpriteTransform t = info.
shape.
transform;
t.
worldToSprite(rayPos.
x, rayPos.
y, p1
);
t.
worldToSprite(rayPos.
x + rayDir.
x, rayPos.
y + rayDir.
y, p2
);
mRay.
set(p1, p2
);
for (int j =
0; j
< info.
shape.
getShapeElementCount(); j++
)
{
BaseShapeElement e = info.
shape.
getShapeElement(j
);
if (e.
collideRayCast(mRay, mResultContactPoint
))
{
float dx = mResultContactPoint.
x - p1.
x;
float dy = mResultContactPoint.
y - p1.
y;
float distanceSqr = dx
*dx+dy
*dy
;
if (distanceSqr
< minimumDistanceSqr
)
{
result.
isColliding =
true;
minimumDistanceSqr = distanceSqr
;
t.
spriteToWorld(mResultContactPoint.
x, mResultContactPoint.
y, result.
contactPoint);
if (info.
contains(FILTER_ENEMIES
))
result.
collidingEnemyInstance = info.
enemyInstance;
else if (info.
contains(FILTER_LEVEL_ELEMENTS
))
result.
collidingLevelObject = info.
levelElement;
}
}
}
}
return result.
isColliding;
}
public boolean checkCollisionPoint
(int filter,
float px,
float py,
float radius, CollisionInfo result
)
{
result.
reset();
float radiusSqr = radius
*radius
;
for (int i =
0; i
< mColliders.
size(); i++
)
{
ColliderInfo info = mColliders.
get(i
);
if (!info.
contains(filter
))
continue;
if (!info.
isColliderAlive())
continue;
AABoundingBox box = info.
shape.
getTransformedBoundingBox();
if (!box.
isInside(px, py
))
continue;
// transform point into shape's space
//SpriteTransform t = info.shape.transform;
//t.worldToSprite(px, py, p1);
for (int j =
0; j
< info.
shape.
getShapeElementCount(); j++
)
{
BaseShapeElement e = info.
shape.
getShapeElement(j
);
if (e.
intersectsCircleSqr(px, py,
5))
//if (e.isInside(p1.x, p1.y))
{
result.
isColliding =
true;
if (info.
contains(FILTER_ENEMIES
))
result.
collidingEnemyInstance = info.
enemyInstance;
else if (info.
contains(FILTER_LEVEL_ELEMENTS
))
result.
collidingLevelObject = info.
levelElement;
/*float dx = mResultContactPoint.x - p1.x;
float dy = mResultContactPoint.y - p1.y;
float distanceSqr = dx*dx+dy*dy;
if (distanceSqr < minimumDistanceSqr)
{
result.isColliding = true;
minimumDistanceSqr = distanceSqr;
t.spriteToWorld(mResultContactPoint.x, mResultContactPoint.y, result.contactPoint);
if (info.contains(FILTER_ENEMIES))
result.collidingEnemyInstance = info.enemyInstance;
else if (info.contains(FILTER_LEVEL_ELEMENTS))
result.collidingLevelObject = info.levelElement;
}*/
}
}
}
return result.
isColliding;
}
// Getters/Setters==================================================================================
}