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 PassiveColliderInfo
{
public BaseLevelElement levelObject = null;
public Shape shape = null;
public PassiveColliderInfo(BaseLevelElement obj, Shape objShape)
{
levelObject = obj;
shape = objShape;
}
}
public class EnemyColliderInfo
{
public BaseEnemy.Instance enemyInstance = null;
public Shape shape = null;
public EnemyColliderInfo(BaseEnemy.Instance obj, Shape objShape)
{
enemyInstance = obj;
shape = objShape;
}
}
*/
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<PassiveColliderInfo> mPassiveColliders = new Vector<PassiveColliderInfo>();
private Vector<EnemyColliderInfo> mEnemyColliders = new Vector<EnemyColliderInfo>();*/
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.levelObject.isAlive())
continue;*/
if (!info.
isColliderAlive())
continue;
AABoundingBox box2 = info.
shape.
getTransformedBoundingBox();
if (!box1.
intersetcs(box2
))
continue;
// perform collision detection between actor's convex hull and shape
//CollisionResult cr = shape.getConvexHull().collide(info.collider.getShape(), move);
//CollisionResult cr = shape.getShapeElement(0).collide(info.shape, move);
//if (cr.isColliding)
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
)
{
//CollisionInfo result = new CollisionInfo();
// Check broadphase collision
//AABoundingBox box1 = AABoundingBox.fromRay(rayPos, rayDir);
mTempBoundingBox.
setFromRay(rayPos, rayDir
);
float minimumDistanceSqr =
Float.
MAX_VALUE;
result.
isColliding =
false;
// Check raycasts between object and level objects
//for (int i = 0; i < mPassiveColliders.size(); i++)
for (int i =
0; i
< mColliders.
size(); i++
)
{
ColliderInfo info = mColliders.
get(i
);
//PassiveColliderInfo info = mPassiveColliders.get(i);
if (!info.
contains(filter
))
continue;
if (!info.
isColliderAlive())
continue;
/*if (!info.levelObject.isAlive())
continue;*/
AABoundingBox box2 = info.
shape.
getTransformedBoundingBox();
if (!mTempBoundingBox.
intersetcs(box2
))
continue;
// transform ray into the shape's space
SpriteTransform t = info.
shape.
transform;
/*Vector2 p1 = t.worldToSprite(rayPos.x, rayPos.y);
Vector2 p2 = t.worldToSprite(rayPos.x + rayDir.x, rayPos.y + rayDir.y);*/
t.
worldToSprite(rayPos.
x, rayPos.
y, p1
);
t.
worldToSprite(rayPos.
x + rayDir.
x, rayPos.
y + rayDir.
y, p2
);
//Line2 ray = new Line2(p1, p2);
mRay.
set(p1, p2
);
for (int j =
0; j
< info.
shape.
getShapeElementCount(); j++
)
{
BaseShapeElement e = info.
shape.
getShapeElement(j
);
//CollisionResult cr = e.collideRayCast(ray);
//if (cr.isColliding)
if (e.
collideRayCast(mRay, mResultContactPoint
))
{
//Vector2 posToContact = new Vector2(mResultContactPoint.x - p1.x, mResultContactPoint.y - p1.y);
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
;
//Gdx.app.log("BLA", "contact: " + result.contactPoint.x + ", " + result.contactPoint.y + " - " + t.x + ", " + t.y);
//result.contactPoint = t.spriteToWorld(mResultContactPoint.x, mResultContactPoint.y);
t.
spriteToWorld(mResultContactPoint.
x, mResultContactPoint.
y, result.
contactPoint);
//Gdx.app.log("BLA", "result contact: " + result.contactPoint.x + ", " + result.contactPoint.y);
if (info.
contains(FILTER_ENEMIES
))
result.
collidingEnemyInstance = info.
enemyInstance;
else if (info.
contains(FILTER_LEVEL_ELEMENTS
))
result.
collidingLevelObject = info.
levelElement;
//result.collidingLevelObject = info.levelObject;
}
}
}
}
/*if (result.isColliding)
{
Gdx.app.log("BLA", "---> result contact: " + result.contactPoint.x + ", " + result.contactPoint.y);
}
*/
return result.
isColliding;
}
// Getters/Setters==================================================================================
}