Temporal fix to collision detector — Full quantisation of float-point hitboxes. "Jump to teleport to ceiling" was my shit

Former-commit-id: a3421b000b9ecf71ca5f03f79f11658cf57a17db
Former-commit-id: e4e540ed339161d3c89228077f217fcb57d01c06
This commit is contained in:
Song Minjae
2016-03-02 01:20:22 +09:00
parent 9eb5b00a95
commit 630f0c6118
25 changed files with 141 additions and 171 deletions

View File

@@ -17,7 +17,9 @@
<root url="jar://$PROJECT_DIR$/lib/natives-mac.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/natives-windows.jar!/" />
</NATIVE>
<SOURCES />
<SOURCES>
<root url="file://$USER_HOME$/Downloads/slick/src" />
</SOURCES>
<excluded>
<root url="jar://$PROJECT_DIR$/lib/gson-2.5-javadoc.jar!/" />
<root url="file://$PROJECT_DIR$/lib/apidocs" />

View File

@@ -40,7 +40,7 @@
"34";"TILE_PLATFORM_BIRCH" ; "0"; "0"; "0"; "N/A"; "0"; "0"; "0"; "34"; "0";"16"
"35";"TILE_PLATFORM_BLOODROSE" ; "0"; "0"; "0"; "N/A"; "0"; "0"; "0"; "35"; "0";"16"
"36";"TILE_TORCH" ; "0"; "0"; "0"; "N/A"; "0"; "0";"63680"; "36"; "0";"16"
"36";"TILE_TORCH" ; "0"; "0"; "0"; "N/A"; "0"; "0";"63412"; "36"; "0";"16"
# 63412 (ffa44e) : real candlelight colour taken from properly configured camera.
"239";"TILE_WATER" ; "6522"; "100"; "1"; "2"; "0"; "0"; "0"; "239"; "0";"16"
"255";"TILE_LAVA" ; "62358"; "100"; "1"; "2"; "0"; "0";"48320"; "239"; "0";"16"
Can't render this file because it contains an unexpected character in line 1 and column 12.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -97,13 +97,13 @@ public class ActorWithBody implements Actor, Visible, Glowing {
long referenceID;
private final int EVENT_COLLIDE_TOP = 0;
private final int EVENT_COLLIDE_RIGHT = 1;
private final int EVENT_COLLIDE_BOTTOM = 2;
private final int EVENT_COLLIDE_LEFT = 3;
private final int EVENT_COLLIDE_NONE = -1;
private final int EVENT_MOVE_TOP = 0;
private final int EVENT_MOVE_RIGHT = 1;
private final int EVENT_MOVE_BOTTOM = 2;
private final int EVENT_MOVE_LEFT = 3;
private final int EVENT_MOVE_NONE = -1;
int collisionEvent = EVENT_COLLIDE_NONE; // cannot collide both X-axis and Y-axis, or else jump control breaks up.
int eventMoving = EVENT_MOVE_NONE; // cannot collide both X-axis and Y-axis, or else jump control breaks up.
/**
* in milliseconds
@@ -179,17 +179,12 @@ public class ActorWithBody implements Actor, Visible, Glowing {
if (veloY > VELO_HARD_LIMIT) veloY = VELO_HARD_LIMIT;
// Set 'next' positions to fiddle with
// updateNextHitboxYFromVelo();
// updateNextHitboxXFromVelo();
updateNextHitboxFromVelo();
// do horizontal collision detection first!
// updateHorizontalPos();
updateHitboxX();
updateHorizontalPos();
updateVerticalPos();
updateHitboxX();
updateHitboxY();
@@ -269,12 +264,12 @@ public class ActorWithBody implements Actor, Visible, Glowing {
boolean colliding;
do {
colliding = isColliding(CONTACT_AREA_BOTTOM, 0, -newYOff);
newYOff += 1;
colliding = isColliding(CONTACT_AREA_BOTTOM, 0, -newYOff);
} while (colliding);
float newY = nextHitbox.getPointedY() - newYOff;
nextHitbox.setPositionFromPoint(newX, newY + 1);
nextHitbox.setPositionFromPoint(newX - 1, newY);
}
private void adjustHitTop() {
@@ -286,136 +281,92 @@ public class ActorWithBody implements Actor, Visible, Glowing {
boolean colliding;
do {
colliding = isColliding(CONTACT_AREA_TOP, 0, newYOff);
newYOff += 1;
colliding = isColliding(CONTACT_AREA_TOP, 0, newYOff);
} while (colliding);
float newY = nextHitbox.getPosY() + newYOff;
nextHitbox.setPosition(newX, newY - 1);
nextHitbox.setPosition(newX + 1, newY);
}
private void updateHorizontalPos() {
if (!isPlayerNoClip()) {
resetCollisionEventFlag();
collidedRightAndAdjusted();
if (collisionEvent == EVENT_COLLIDE_RIGHT) {
veloX = 0;
walledRight = true;
}
collidedLeftAndAdjusted();
if (collisionEvent == EVENT_COLLIDE_LEFT) {
veloX = 0;
walledLeft = true;
}
if (collisionEvent != EVENT_COLLIDE_LEFT && collisionEvent != EVENT_COLLIDE_RIGHT) {
walledRight = false;
walledLeft = false;
}
}
}
void collidedRightAndAdjusted() {
if (getContactingArea(CONTACT_AREA_RIGHT, 1, 0) == 0) {
resetCollisionEventFlag();
}
/**
* seemingly adjusted and one pixel below has ground
*
* seemingly adjusted: adjustHitBottom sets position one pixel above the ground
* (stepping on ground in-game look, as the sprite render is one pixel offseted to Y)
*/
else if (getContactingArea(CONTACT_AREA_RIGHT, 1, 0) > 0
&& getContactingArea(CONTACT_AREA_RIGHT, 0, 0) == 0) {
collisionEvent = EVENT_COLLIDE_RIGHT;
}
else {
// check right
if (veloX > 0) { // use TERNARY for L/R!
// order of the if-elseif chain is IMPORTANT
if (isColliding(CONTACT_AREA_RIGHT) && !isColliding(CONTACT_AREA_LEFT)) {
adjustHitRight();
collisionEvent = EVENT_COLLIDE_RIGHT;
veloX = 0;
}
}
void collidedLeftAndAdjusted() {
if (getContactingArea(CONTACT_AREA_LEFT, -1, 0) == 0) {
resetCollisionEventFlag();
}
/**
* seemingly adjusted and one pixel below has ground
*
* seemingly adjusted: adjustHitBottom sets position one pixel above the ground
* (stepping on ground in-game look, as the sprite render is one pixel offseted to Y)
*/
else if (getContactingArea(CONTACT_AREA_LEFT, -1, 0) > 0
&& getContactingArea(CONTACT_AREA_LEFT, 0, 0) == 0) {
collisionEvent = EVENT_COLLIDE_LEFT;
else if (isColliding(CONTACT_AREA_RIGHT, 1, 0)
&& !isColliding(CONTACT_AREA_LEFT, -1, 0)) {
veloX = 0;
}
else {
}
}
else if (veloX < 0) {
// order of the if-elseif chain is IMPORTANT
if (isColliding(CONTACT_AREA_LEFT) && !isColliding(CONTACT_AREA_RIGHT)) {
adjustHitLeft();
collisionEvent = EVENT_COLLIDE_LEFT;
veloX = 0;
}
else if (isColliding(CONTACT_AREA_LEFT, -1, 0)
&& !isColliding(CONTACT_AREA_RIGHT, 1, 0)) {
veloX = 0;
}
else {
}
}
else {
}
}
}
private void adjustHitRight() {
int tX = 0;
int contactArea = getContactingArea(CONTACT_AREA_RIGHT, 0, 0);
for (int lim = 0; lim < LR_COMPENSATOR_MAX; lim++) {
/**
* get contact area and move up and get again.
* keep track of this value, and some point they will be set as lowest
* and become static. The very point where the value first became lowest
* is the value what we want.
*/
int newContactArea = getContactingArea(CONTACT_AREA_RIGHT, -lim, 0);
if (newContactArea < contactArea) {
tX = -lim;
}
contactArea = newContactArea;
}
//nextHitbox.setPositionYFromPoint(nextHitbox.getPointedX() + tX);
nextHitbox.set(
FastMath.ceil(nextHitbox.getPosX() + tX)
, nextHitbox.getPosY()
, nextHitbox.getWidth()
, nextHitbox.getHeight()
float newY = nextHitbox.getPosY(); // look carefully, getPos or getPointed
// int-ify posY of nextHitbox
nextHitbox.setPositionX( FastMath.floor(nextHitbox.getPosX() + nextHitbox.getWidth())
- nextHitbox.getWidth()
);
int newXOff = 0; // always positive
boolean colliding;
do {
newXOff += 1;
colliding = isColliding(CONTACT_AREA_BOTTOM, -newXOff, 0);
} while (newXOff < TSIZE && colliding);
float newX = nextHitbox.getPosX() - newXOff;
nextHitbox.setPosition(newX, newY);
}
private void adjustHitLeft() {
int tX = 0;
int contactArea = getContactingArea(CONTACT_AREA_LEFT, 0, 0);
for (int lim = 0; lim < LR_COMPENSATOR_MAX; lim++) {
/**
* get contact area and move up and get again.
* keep track of this value, and some point they will be set as lowest
* and become static. The very point where the value first became lowest
* is the value what we want.
*/
int newContactArea = getContactingArea(CONTACT_AREA_LEFT, lim, 0);
float newY = nextHitbox.getPosY();
// int-ify posY of nextHitbox
nextHitbox.setPositionX( FastMath.ceil(nextHitbox.getPosX()) );
if (newContactArea < contactArea) {
tX = lim;
}
contactArea = newContactArea;
}
//nextHitbox.setPositionYFromPoint(nextHitbox.getPointedX() + tX);
nextHitbox.set(
FastMath.floor(nextHitbox.getPosX() + tX + 1)
, nextHitbox.getPosY()
, nextHitbox.getWidth()
, nextHitbox.getHeight()
);
int newXOff = 0; // always positive
boolean colliding;
do {
newXOff += 1;
colliding = isColliding(CONTACT_AREA_TOP, newXOff, 0);
} while (newXOff < TSIZE && colliding);
float newX = nextHitbox.getPosX() + newXOff;
nextHitbox.setPosition(newX, newY);
}
private boolean isColliding(int side) {
return getContactingArea(side) > 0;
return isColliding(side, 0, 0);
}
private boolean isColliding(int side, int tx, int ty) {
return getContactingArea(side, tx, ty) > 0;
return getContactingArea(side, tx, ty) > 1;
}
private int getContactingArea(int side) {
@@ -429,7 +380,7 @@ public class ActorWithBody implements Actor, Visible, Glowing {
; i++) {
// set tile positions
int tileX, tileY;
if (side == CONTACT_AREA_BOTTOM) {
/*if (side == CONTACT_AREA_BOTTOM) {
tileX = div16TruncateToMapWidth(Math.round(nextHitbox.getHitboxStart().getX())
+ i + translateX);
tileY = div16TruncateToMapHeight(FastMath.floor(nextHitbox.getHitboxEnd().getY())
@@ -452,6 +403,30 @@ public class ActorWithBody implements Actor, Visible, Glowing {
+ translateX);
tileY = div16TruncateToMapHeight(Math.round(nextHitbox.getHitboxStart().getY())
+ i + translateY);
}*/
if (side == CONTACT_AREA_BOTTOM) {
tileX = div16TruncateToMapWidth(Math.round(nextHitbox.getHitboxStart().getX())
+ i + translateX);
tileY = div16TruncateToMapHeight(Math.round(nextHitbox.getHitboxEnd().getY())
+ translateY);
}
else if (side == CONTACT_AREA_TOP) {
tileX = div16TruncateToMapWidth(Math.round(nextHitbox.getHitboxStart().getX())
+ i + translateX);
tileY = div16TruncateToMapHeight(Math.round(nextHitbox.getHitboxStart().getY())
+ translateY);
}
else if (side == CONTACT_AREA_RIGHT) {
tileX = div16TruncateToMapWidth(Math.round(nextHitbox.getHitboxEnd().getX())
+ translateX);
tileY = div16TruncateToMapHeight(Math.round(nextHitbox.getHitboxStart().getY())
+ i + translateY);
}
else if (side == CONTACT_AREA_LEFT) {
tileX = div16TruncateToMapWidth(Math.round(nextHitbox.getHitboxStart().getX())
+ translateX);
tileY = div16TruncateToMapHeight(Math.round(nextHitbox.getHitboxStart().getY())
+ i + translateY);
}
else {
throw new IllegalArgumentException(String.valueOf(side) + ": Wrong side input");
@@ -466,10 +441,6 @@ public class ActorWithBody implements Actor, Visible, Glowing {
return contactAreaCounter;
}
private void resetCollisionEventFlag() {
collisionEvent = EVENT_COLLIDE_NONE;
}
private void clampHitbox() {
hitbox.setPositionFromPoint(
clampW(hitbox.getPointedX())
@@ -484,30 +455,14 @@ public class ActorWithBody implements Actor, Visible, Glowing {
);
}
private void updateNextHitboxXFromVelo() {
nextHitbox.set(
hitbox.getPosX() + veloX
, hitbox.getPosY()
, baseHitboxW * scale
, baseHitboxH * scale
);
}
private void updateNextHitboxYFromVelo() {
nextHitbox.set(
hitbox.getPosX()
, hitbox.getPosY() + veloY
, baseHitboxW * scale
, baseHitboxH * scale
);
}
private void updateNextHitboxFromVelo() {
nextHitbox.set(
hitbox.getPosX() + veloX
, hitbox.getPosY() + veloY
, baseHitboxW * scale
, baseHitboxH * scale
Math.round(hitbox.getPosX() + veloX)
, Math.round(hitbox.getPosY() + veloY)
, Math.round(baseHitboxW * scale)
, Math.round(baseHitboxH * scale)
/** Full quantisation; wonder what havoc these statements would wreak...
*/
);
}

View File

@@ -62,7 +62,7 @@ public class PBFSigrid {
p.actorValue.set("luminosity", 22819);
p.setHitboxDimension(17, 46, 9, 0);
p.setHitboxDimension(18, 47, 8, 0);
p.inventory = new ActorInventory(0x7FFFFFFF, true);

View File

@@ -42,5 +42,5 @@ public class PlayerDebugger {
public ActorValue actorValue() { return getPlayer().getActorValue(); }
public float mass() { return getPlayer().getMass(); }
public boolean noClip() { return getPlayer().isNoClip(); }
public int collisionEvent() { return getPlayer().collisionEvent; }
public int eventMoving() { return getPlayer().eventMoving; }
}

View File

@@ -145,11 +145,7 @@ public class Game extends BasicGameState {
TileStat.update();
/** Placed before actor update to give some dynamic view of player on screen,
* or else player will always stay same spot, which is somewhat dull.
*/
MapDrawer.update(gc, delta_t);
MapCamera.update(gc, delta_t);
actorContainer.forEach(actor -> actor.update(gc, delta_t));
actorContainer.forEach(
@@ -163,6 +159,12 @@ public class Game extends BasicGameState {
}
);
/** Placed before actor update to give some dynamic view of player on screen,
* or else player will always stay same spot, which is somewhat dull.
*/
MapDrawer.update(gc, delta_t);
MapCamera.update(gc, delta_t);
uiContainer.forEach(ui -> ui.update(gc, delta_t));
//bulletin.update(gc, delta_t);

View File

@@ -26,6 +26,12 @@ public class GameController {
}
public static void processInput(Input input) {
int mouseTileX = (int) ((MapCamera.getCameraX() + input.getMouseX() / Terrarum.game.screenZoom)
/ MapDrawer.TILE_SIZE);
int mouseTileY = (int) ((MapCamera.getCameraY() + input.getMouseY() / Terrarum.game.screenZoom)
/ MapDrawer.TILE_SIZE);
if (!Terrarum.game.consoleHandler.isTakingControl()) {
if (Terrarum.game.getPlayer().vehicleRiding != null) {
Terrarum.game.getPlayer().vehicleRiding.processInput(input);
@@ -42,16 +48,11 @@ public class GameController {
}
int mouseTileX = (int) ((MapCamera.getCameraX() + input.getMouseX() / Terrarum.game.screenZoom)
/ MapDrawer.TILE_SIZE);
int mouseTileY = (int) ((MapCamera.getCameraY() + input.getMouseY() / Terrarum.game.screenZoom)
/ MapDrawer.TILE_SIZE);
if (input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) {
// test tile remove
try {
Terrarum.game.map.setTileTerrain(mouseTileX, mouseTileY, TileNameCode.AIR);
Terrarum.game.map.setTileWall(mouseTileX, mouseTileY, TileNameCode.AIR);
// Terrarum.game.map.setTileWall(mouseTileX, mouseTileY, TileNameCode.AIR);
}
catch (ArrayIndexOutOfBoundsException e) {
}

View File

@@ -36,8 +36,11 @@ public class Terrarum extends StateBasedGame {
public static final int TARGET_INTERNAL_FPS = 100;
public static AppGameContainer appgc;
public static final int WIDTH = 960;
public static final int HEIGHT = 720;
public static final int WIDTH = 1060;
public static final int HEIGHT = 742; // IMAX ratio
public static boolean VSYNC = true;
public static Game game;
public static String OSName;
@@ -93,11 +96,14 @@ public class Terrarum extends StateBasedGame {
{
appgc = new AppGameContainer(new Terrarum("Terrarum"));
appgc.setDisplayMode(WIDTH, HEIGHT, false);
appgc.setTargetFrameRate(TARGET_INTERNAL_FPS);
appgc.setVSync(true);
appgc.setVSync(VSYNC);
appgc.setMaximumLogicUpdateInterval(1000 / TARGET_INTERNAL_FPS);
appgc.setShowFPS(false);
appgc.setUpdateOnlyWhenVisible(false);
appgc.setMaximumLogicUpdateInterval(1000 / TARGET_INTERNAL_FPS);
appgc.start();
}
catch (SlickException ex)

View File

@@ -40,7 +40,7 @@
"34";"TILE_PLATFORM_BIRCH" ; "0"; "0"; "0"; "N/A"; "0"; "0"; "0"; "34"; "0";"16"
"35";"TILE_PLATFORM_BLOODROSE" ; "0"; "0"; "0"; "N/A"; "0"; "0"; "0"; "35"; "0";"16"
"36";"TILE_TORCH" ; "0"; "0"; "0"; "N/A"; "0"; "0";"63680"; "36"; "0";"16"
"36";"TILE_TORCH" ; "0"; "0"; "0"; "N/A"; "0"; "0";"63412"; "36"; "0";"16"
# 63412 (ffa44e) : real candlelight colour taken from properly configured camera.
"239";"TILE_WATER" ; "6522"; "100"; "1"; "2"; "0"; "0"; "0"; "239"; "0";"16"
"255";"TILE_LAVA" ; "62358"; "100"; "1"; "2"; "0"; "0";"48320"; "239"; "0";"16"
Can't render this file because it contains an unexpected character in line 1 and column 12.

View File

@@ -6,7 +6,6 @@ import com.Torvald.Terrarum.LangPack.Lang;
import com.Torvald.Terrarum.MapDrawer.LightmapRenderer;
import com.Torvald.Terrarum.MapDrawer.MapDrawer;
import com.Torvald.Terrarum.Terrarum;
import com.Torvald.Terrarum.Game;
import com.Torvald.Terrarum.MapDrawer.MapCamera;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
@@ -105,7 +104,7 @@ public class BasicDebugInfoWindow implements UICanvas {
*/
String[] collisionFlagKey = {"top", "right", "bottom", "left"};
int collisonFlag = playerDbg.collisionEvent();
int collisonFlag = playerDbg.eventMoving();
printLineColumn(g, 2, 1, "CollisionFlag : "
+ ((collisonFlag == -1) ? "none" : collisionFlagKey[collisonFlag]));
printLineColumn(g, 2, 2, "Env colour temp : " + MapDrawer.getColTemp());

View File

@@ -23,9 +23,14 @@ def getB40(raw):
def intFromCol(r, g, b):
return r * MUL_2 + g * MUL + b
return int(r * MUL_2 + g * MUL + b)
def intFromRGB24(r24, g24, b24):
roundR = round(r24 / 255.0 * 39)
roundG = round(g24 / 255.0 * 39)
roundB = round(b24 / 255.0 * 39)
return intFromCol(roundR, roundG, roundB)
def colFromNum(raw):
return getR40(raw), getG40(raw), getB40(raw)
print(colFromNum(9979))
print(intFromCol(3,5,9))
print(intFromRGB24(255, 164, 78))