Changed circleQuadCollisionEdge function -> Now works perfectly also with moving obstacles

Note: Just works for ball-obstacle-collision, when circle diameter is bigger than quad width or height, won't work anymore
This commit is contained in:
= 2018-01-07 15:39:25 +01:00
parent 77b927cb1a
commit 4629419d3e
5 changed files with 187 additions and 52 deletions

View File

@ -89,5 +89,50 @@
</stars> </stars>
<energy x="17.053387" y="-0.8066667"/> <energy x="17.053387" y="-0.8066667"/>
</level> </level>
<level packId="2" id="2" goalX="3.0" startSpeed="0.5" endSpeed="0.5" terrainEdge="-0.6" ceilingEdge="1.0">
<terrainTiles class="java.util.ArrayList">
<tileData x="-2.75" width="0.5"/>
<tileData x="2.75" width="0.5"/>
</terrainTiles>
<ceilingTiles class="java.util.ArrayList">
<tileData x="0.0" width="6.0"/>
</ceilingTiles>
<obstacles class="java.util.ArrayList">
<obstacleData floating="true" moving="true" deadly="false" leftEdge="-1.1566665" rightEdge="-0.6566666" height="0.5" y="-0.99333346">
<moveComponent length="3.687" rotation="55.602" startOffset="0.0" direction="1.0" speed="0.0" hasPlayerXSpeed="true" triggerDistance="0.0"/>
</obstacleData>
</obstacles>
<stars class="java.util.ArrayList"/>
</level>
<level packId="2" id="3" goalX="3.0" startSpeed="0.5" endSpeed="0.5" terrainEdge="-0.6" ceilingEdge="1.0">
<terrainTiles class="java.util.ArrayList">
<tileData x="-2.75" width="0.5"/>
<tileData x="2.75" width="0.5"/>
</terrainTiles>
<ceilingTiles class="java.util.ArrayList">
<tileData x="0.0" width="6.0"/>
</ceilingTiles>
<obstacles class="java.util.ArrayList">
<obstacleData floating="true" moving="true" deadly="false" leftEdge="-1.1233333" rightEdge="-0.62333333" height="0.5" y="-0.96000004">
<moveComponent length="5.0" rotation="22.618" startOffset="0.0" direction="1.0" speed="0.0" hasPlayerXSpeed="true" triggerDistance="0.0"/>
</obstacleData>
</obstacles>
<stars class="java.util.ArrayList"/>
</level>
<level packId="2" id="4" goalX="3.0" startSpeed="0.5" endSpeed="0.5" terrainEdge="-0.6" ceilingEdge="1.0">
<terrainTiles class="java.util.ArrayList">
<tileData x="-2.75" width="0.5"/>
<tileData x="2.75" width="0.5"/>
</terrainTiles>
<ceilingTiles class="java.util.ArrayList">
<tileData x="0.0" width="6.0"/>
</ceilingTiles>
<obstacles class="java.util.ArrayList">
<obstacleData floating="true" moving="true" deadly="false" leftEdge="-1.1566666" rightEdge="-0.65666664" height="0.5" y="-0.92666656">
<moveComponent length="2.929" rotation="84.817" startOffset="0.0" direction="1.0" speed="0.0" hasPlayerXSpeed="true" triggerDistance="0.0"/>
</obstacleData>
</obstacles>
<stars class="java.util.ArrayList"/>
</level>
</levels> </levels>
</levelPack> </levelPack>

View File

@ -53,6 +53,12 @@ public class Vector {
return this; return this;
} }
public Vector abs(){
this.x = Math.abs(x);
this.y = Math.abs(y);
return this;
}
public Vector mul(float z) { public Vector mul(float z) {
x *= z; x *= z;
y *= z; y *= z;

View File

@ -67,12 +67,10 @@ public class Obstacle extends Entity {
moveProgress = 2 - moveProgress; moveProgress = 2 - moveProgress;
moveDirection *= -1; moveDirection *= -1;
} }
Vector oldPosition = new Vector(super.getPosition());
super.setPosition(moveComponent.getPositionForProgress(moveProgress)); super.setPosition(moveComponent.getPositionForProgress(moveProgress));
Vector newPosition = new Vector(super.getPosition()); super.setMovement(moveComponent.getMovementVector(moveDirection));
Vector move = newPosition.translate(oldPosition.negate()); GameLog.i(super.getMovement().getX() + "; " + player.getMovement().getX());
move.mul(1 / frameTime);
super.setMovement(move);
} }
public boolean isMoving() { public boolean isMoving() {

View File

@ -7,7 +7,6 @@ import de.frajul.endlessroll.entities.collision.collisionData.EntityCollisionDat
import de.frajul.endlessroll.entities.collision.geometry.Circle; import de.frajul.endlessroll.entities.collision.geometry.Circle;
import de.frajul.endlessroll.entities.collision.geometry.Quad; import de.frajul.endlessroll.entities.collision.geometry.Quad;
import de.frajul.endlessroll.entities.collision.geometry.Triangle; import de.frajul.endlessroll.entities.collision.geometry.Triangle;
import de.frajul.endlessroll.main.GameLog;
/** /**
* Created by Julian on 01.12.2015. * Created by Julian on 01.12.2015.
@ -140,69 +139,153 @@ public class CollisionDetector {
if (isCircleQuadCollision(circle, quad)) { if (isCircleQuadCollision(circle, quad)) {
Edge edge = circleQuadCollisionEdge(circle, player.getMovement(), quad, Edge edge = circleQuadCollisionEdge(circle, player.getMovement(), quad,
entity.getMovement()); entity.getMovement());
//Obstacles with MoveComponent do not have entity.getMovement() --> if player not moving, relativeMovement.x = 0
return new EntityCollisionData(entity, edge); return new EntityCollisionData(entity, edge);
} }
return new EntityCollisionData(null, null); return new EntityCollisionData(null, null);
} }
private Edge circleQuadCollisionEdge(Circle circle, Vector circleMovement, Quad quad, Vector quadMovement) { private Edge circleQuadCollisionEdge(Circle circle, Vector circleMovement, Quad quad, Vector quadMovement) {
boolean circleFullyInsideQuad = false;
if (circle.getCenter().getX() + circle.getRadius() <= quad.getRightEdge() && circle
.getCenter().getX() - circle.getRadius() >= quad.getLeftEdge()) {
if (circle.getCenter().getY() + circle.getRadius() <= quad.getTopEdge() && circle
.getCenter().getY() - circle.getRadius() >= quad.getBottomEdge()) {
circleFullyInsideQuad = true;
}
}
if (circleFullyInsideQuad)
return circleCenterInQuadCollisionEdge(circle, circleMovement, quad, quadMovement);
return circlePartlyOutsideQuadCollisionEdge(circle, quad);
}
private Edge circlePartlyOutsideQuadCollisionEdge(Circle circle, Quad quad) {
Edge edge = Edge.NONE;
if (circle.getCenter().getY() + circle.getRadius() >= quad.getTopEdge())
edge = Edge.TOP;
else if (circle.getCenter().getY() - circle.getRadius() <= quad.getBottomEdge())
edge = Edge.BOTTOM;
if (circle.getCenter().getX() - circle.getRadius() <= quad.getLeftEdge()) {
if (edge != Edge.NONE) {
if (edge == Edge.TOP) {
float m = -1;
float t = quad.getTopEdge() - m * quad.getLeftEdge();
if (circle.getCenter().getY() >= m * circle.getCenter().getX() + t)
edge = Edge.TOP;
else
edge = Edge.LEFT;
} else if (edge == Edge.BOTTOM) {
float m = 1;
float t = quad.getBottomEdge() - m * quad.getLeftEdge();
if (circle.getCenter().getY() <= m * circle.getCenter().getX() + t)
edge = Edge.BOTTOM;
else
edge = Edge.LEFT;
}
} else
edge = Edge.LEFT;
} else if (circle.getCenter().getX() + circle.getRadius() >= quad.getRightEdge()) {
if (edge != Edge.NONE) {
if (edge == Edge.TOP) {
float m = 1;
float t = quad.getTopEdge() - m * quad.getRightEdge();
if (circle.getCenter().getY() >= m * circle.getCenter().getX() + t)
edge = Edge.TOP;
else
edge = Edge.RIGHT;
} else if (edge == Edge.BOTTOM) {
float m = -1;
float t = quad.getBottomEdge() - m * quad.getRightEdge();
if (circle.getCenter().getY() <= m * circle.getCenter().getX() + t)
edge = Edge.BOTTOM;
else
edge = Edge.RIGHT;
}
} else
edge = Edge.RIGHT;
}
return edge;
}
private Edge circleCenterInQuadCollisionEdge(Circle circle, Vector circleMovement, Quad quad, Vector quadMovement) {
Vector relativeMovement = circleMovement.translate(quadMovement.negate()); Vector relativeMovement = circleMovement.translate(quadMovement.negate());
//LEFT || TOP || BOTTOM float m = relativeMovement.getY() / relativeMovement.getX();
if (relativeMovement.x > 0) { float t = circle.getCenter().getY() - m * circle.getCenter().getX();
//LEFT || BOTTOM
if (relativeMovement.y > 0) { float yAtLeftEdge = m * quad.getLeftEdge() + t;
float toLeftDistance = quad.getLeftEdge() - circle.getCenter().x - circle.getRadius(); boolean touchingLeftEdge = yAtLeftEdge < quad.getTopEdge() && yAtLeftEdge > quad
float actualY = toLeftDistance * (relativeMovement.y / relativeMovement.x) + circle .getBottomEdge();
.getCenter().y + circle.getRadius(); float yAtRightEdge = m * quad.getRightEdge() + t;
if (actualY <= quad.getBottomEdge()) boolean touchingRightEdge = yAtRightEdge < quad.getTopEdge() && yAtRightEdge > quad
return Edge.BOTTOM; .getBottomEdge();
else
return Edge.LEFT; float xAtTopEdge = (quad.getTopEdge() - t) / m;
boolean touchingTopEdge = xAtTopEdge >= quad.getLeftEdge() && xAtTopEdge <= quad
.getRightEdge();
float xAtBottomEdge = (quad.getBottomEdge() - t) / m;
boolean touchingBottomEdge = xAtBottomEdge >= quad.getLeftEdge() && xAtBottomEdge <= quad
.getRightEdge();
if (relativeMovement.getX() == 0) {
if (circle.getCenter().getX() - circle.getRadius() <= quad.getRightEdge() && circle
.getCenter().getX() + circle.getRadius() >= quad.getLeftEdge()) {
touchingTopEdge = true;
touchingBottomEdge = true;
} }
//LEFT || TOP }
else if (relativeMovement.y < 0) {
float toLeftDistance = quad.getLeftEdge() - circle.getCenter().x - circle.getRadius(); // CORNERS BELONGING TO TOP / BOTTOM EDGES
float actualY = toLeftDistance * (relativeMovement.y / relativeMovement.x) + circle if (touchingLeftEdge) {
.getCenter().y - circle.getRadius(); if (touchingRightEdge) {
if (actualY > quad.getTopEdge()) if (circle.getCenter().getX() <= quad.getPosition().getX())
return Edge.TOP;
else
return Edge.LEFT; return Edge.LEFT;
return Edge.RIGHT;
} else if (touchingTopEdge) {
// Normale through vertex
float mn = -1 / m;
float tn = quad.getTopEdge() - mn * quad.getLeftEdge();
if (circle.getCenter().getY() < mn * circle.getCenter().getX() + tn)
return Edge.LEFT;
return Edge.TOP;
} else if (touchingBottomEdge) {
// Normale through vertex
float mn = -1 / m;
float tn = quad.getBottomEdge() - mn * quad.getLeftEdge();
if (circle.getCenter().getY() > mn * circle.getCenter().getX() + tn)
return Edge.LEFT;
return Edge.BOTTOM;
} else { } else {
return Edge.LEFT; return Edge.LEFT;
} }
} } else if (touchingRightEdge) {
//RIGHT || TOP || BOTTOM if (touchingTopEdge) {
else if (relativeMovement.x < 0) { // Normale through vertex
//RIGHT || BOTTOM float mn = -1 / m;
if (relativeMovement.y > 0) { float tn = quad.getTopEdge() - mn * quad.getRightEdge();
float toRightDistance = quad.getRightEdge() - circle.getCenter().x + circle.getRadius(); if (circle.getCenter().getY() < mn * circle.getCenter().getX() + tn)
float actualY = toRightDistance * (relativeMovement.y / relativeMovement.x) + circle
.getCenter().y + circle.getRadius();
if (actualY <= quad.getBottomEdge())
return Edge.BOTTOM;
else
return Edge.RIGHT; return Edge.RIGHT;
}
//RIGHT || TOP
else if (relativeMovement.y < 0) {
float toRightDistance = quad.getRightEdge() - circle.getCenter().x + circle.getRadius();
float actualY = toRightDistance * (relativeMovement.y / relativeMovement.x) + circle
.getCenter().y - circle.getRadius();
if (actualY > quad.getTopEdge())
return Edge.TOP; return Edge.TOP;
else } else if (touchingBottomEdge) {
// Normale through vertex
float mn = -1 / m;
float tn = quad.getBottomEdge() - mn * quad.getRightEdge();
if (circle.getCenter().getY() > mn * circle.getCenter().getX() + tn)
return Edge.RIGHT; return Edge.RIGHT;
return Edge.BOTTOM;
} else { } else {
return Edge.RIGHT; return Edge.RIGHT;
} }
} else { } else if (touchingTopEdge) {
if (relativeMovement.y > 0) if (touchingBottomEdge) {
return Edge.BOTTOM; if (circle.getCenter().getY() >= quad.getPosition().getY())
else if (relativeMovement.y < 0)
return Edge.TOP; return Edge.TOP;
return Edge.BOTTOM;
} else {
return Edge.TOP;
}
} else if (touchingBottomEdge) {
return Edge.BOTTOM;
} }
return Edge.NONE; return Edge.NONE;
} }

View File

@ -71,9 +71,7 @@ public class MoveComponent {
public void calcSpeedForPlayerSpeed(Player player) { public void calcSpeedForPlayerSpeed(Player player) {
float xSpeed = player.getSpeed(); float xSpeed = player.getSpeed();
double invertRotationRadians = Math.toRadians(90 - getRotation()); speed = xSpeed / new Vector(triangleWidth, triangleHeight).normalize().getX();
float ySpeed = (float) (xSpeed * Math.sin(invertRotationRadians));
speed = (float) Math.sqrt(xSpeed * xSpeed + ySpeed * ySpeed);
speed /= TRANSITION_VALUE; speed /= TRANSITION_VALUE;
} }
@ -81,6 +79,11 @@ public class MoveComponent {
return triangleWidth >= 0 ? position.x : position.x + triangleWidth; return triangleWidth >= 0 ? position.x : position.x + triangleWidth;
} }
public Vector getMovementVector(float moveDirection) {
return new Vector(triangleWidth, triangleHeight).normalize()
.mul(moveDirection * getSpeed() * TRANSITION_VALUE);
}
public Vector getPositionForProgress(float progress) { public Vector getPositionForProgress(float progress) {
return new Vector(position.x + triangleWidth * progress, return new Vector(position.x + triangleWidth * progress,
position.y + triangleHeight * progress); position.y + triangleHeight * progress);