physics almost works, except for bunch of TODOs and FIXMEs

This commit is contained in:
minjaesong
2017-05-10 03:41:46 +09:00
parent 4262b02faf
commit 31954f3ca7

View File

@@ -10,8 +10,6 @@ import net.torvald.spriteanimation.SpriteAnimation
import net.torvald.terrarum.worlddrawer.WorldCamera import net.torvald.terrarum.worlddrawer.WorldCamera
import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.blockproperties.BlockProp import net.torvald.terrarum.blockproperties.BlockProp
import net.torvald.terrarum.gameactors.ai.toInt
import org.dyn4j.Epsilon
import org.dyn4j.geometry.Vector2 import org.dyn4j.geometry.Vector2
import org.newdawn.slick.GameContainer import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics import org.newdawn.slick.Graphics
@@ -83,12 +81,12 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
var walkX: Double var walkX: Double
get() = controllerMoveDelta!!.x get() = controllerMoveDelta!!.x
protected set(value) { protected set(value) {
controllerMoveDelta!!.x = value controllerMoveDelta?.x = value
} }
var walkY: Double var walkY: Double
get() = controllerMoveDelta!!.y get() = controllerMoveDelta!!.y
protected set(value) { protected set(value) {
controllerMoveDelta!!.y = value controllerMoveDelta?.y = value
} }
// not sure we need this... // not sure we need this...
//var jumpable = true // this is kind of like "semaphore" //var jumpable = true // this is kind of like "semaphore"
@@ -415,6 +413,8 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
// these are FOR THE NEXT ROUND of update // // these are FOR THE NEXT ROUND of update //
// ((DO NOT DELETE THIS; made same mistake twice already)) // // ((DO NOT DELETE THIS; made same mistake twice already)) //
// TODO less friction for non-animating objects (make items glide far more on ice)
setHorizontalFriction() // friction SHOULD use and alter externalForce setHorizontalFriction() // friction SHOULD use and alter externalForce
if (isPlayerNoClip) { // TODO also hanging on the rope, etc. if (isPlayerNoClip) { // TODO also hanging on the rope, etc.
setVerticalFriction() setVerticalFriction()
@@ -620,14 +620,27 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
return externalForce * percentage return externalForce * percentage
} }
fun getControllerXDelta(percentage: Double): Vector2 {
if (percentage < 0.0 || percentage > 1.0)
throw IllegalArgumentException("$percentage")
return Vector2(controllerMoveDelta!!.x * percentage, 0.0)
}
fun getControllerYDelta(percentage: Double): Vector2 {
if (percentage < 0.0 || percentage > 1.0)
throw IllegalArgumentException("$percentage")
return Vector2(0.0, controllerMoveDelta!!.y * percentage)
}
val simulationHitbox = hitbox.clone()
if (externalForce.isZero) { if (externalForce.isZero) {
debug1("externalForce is zero") debug1("externalForce is zero")
} }
else { else {
val simulationHitbox = hitbox.clone()
var ccdTick: Int = ccdSteps // 0..15: collision detected, 16: not var ccdTick: Int = ccdSteps // 0..15: collision detected, 16: not
// do CCD first // do CCD first
@@ -637,38 +650,16 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
debug2("ccd $i, endY = ${simulationHitbox.endPointY}") debug2("ccd $i, endY = ${simulationHitbox.endPointY}")
if (isColliding(simulationHitbox)) { //COLLIDING_EXTRA_SIZE: doing trick so that final pos would be x.99800000 instead of y.0000000 if (isColliding(simulationHitbox)) {
ccdTick = i ccdTick = i
break break
} }
} }
// FIXME CCD-ing is not right (not-so-crucial for most cases anyway...)
// DESCRIPTION: 0.999999999999 ~ 1.0 pixels off
// I think collision detection is one pixel off -- very fucking likely
debug2("ccdTick = $ccdTick, endY = ${simulationHitbox.endPointY}") debug2("ccdTick = $ccdTick, endY = ${simulationHitbox.endPointY}")
/////////////////////////
// FIXME THE EDGE CASE //
/////////////////////////
/*
no collision; endY = 7989.683178548076
no collision; endY = 7995.169755787131
no collision; endY = 8000.749058412345 <-- CCD did NOT caught collision (8000.0 be collision)
reflY
0
0
*/
// THIS is also the consequence of COLLISION DETECTION being 1 pixel off
//
// Fixed the issue by offsetting hitbox when doing collision detection,
// now it won't jump as if it's stuck in the ground (L/R stuck)
// "snap to closest tile" does not make any difference
// collision not found // collision not found
var collisionNotFound = false var collisionNotFound = false
if (ccdTick == ccdSteps) { if (ccdTick == ccdSteps) {
@@ -716,6 +707,79 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
debug1("!! grounded ${Random().nextInt(1000)}!!") debug1("!! grounded ${Random().nextInt(1000)}!!")
} }
}
} // must end with semi-final hitbox
/////////////////////////////////
// resolve controllerMoveDelta //
/////////////////////////////////
if (controllerMoveDelta != null) {
debug3("== ControllerMoveDelta ==")
// X-Axis
val simulationHitboxX = simulationHitbox.clone()
if (controllerMoveDelta!!.x != 0.0) {
// skipping CCD and directly into BinarySearch: CCD would be unnecessary
var low = 0.0
var high = 1.0
var bmid: Double
(1..binaryBranchingMax).forEach { _ ->
bmid = (low + high) / 2.0
simulationHitboxX.reassign(simulationHitbox)
simulationHitboxX.translate(getControllerXDelta(bmid))
// set new mid
if (isTouchingSide(simulationHitboxX, COLLIDING_LEFT) || isTouchingSide(simulationHitboxX, COLLIDING_RIGHT)) {
debug3("bmid = $bmid, new endX: ${simulationHitboxX.endPointX}, going back")
high = bmid
}
else {
debug3("bmid = $bmid, new endX: ${simulationHitboxX.endPointX}, going forth")
low = bmid
}
}
}
// FIXME ceiling hit by jumping: mul controllerY by elasticity
// FIXME jitter on hitting body against a wall
// FIXME balls jitter af and stuck on a wall
// Y-Axis
val simulationHitboxY = simulationHitbox.clone()
if (controllerMoveDelta!!.y != 0.0) {
// skipping CCD and directly into BinarySearch: CCD would be unnecessary
var low = 0.0
var high = 1.0
var bmid: Double
(1..binaryBranchingMax).forEach { _ ->
bmid = (low + high) / 2.0
simulationHitboxY.reassign(simulationHitbox)
simulationHitboxY.translate(getControllerYDelta(bmid))
// set new mid
if (isTouchingSide(simulationHitboxY, COLLIDING_TOP) || isTouchingSide(simulationHitboxY, COLLIDING_BOTTOM)) {
debug3("bmid = $bmid, new endY: ${simulationHitboxY.endPointY}, going back")
high = bmid
}
else {
debug3("bmid = $bmid, new endY: ${simulationHitboxY.endPointY}, going forth")
low = bmid
}
}
}
simulationHitbox.setPosition(simulationHitboxX.posX, simulationHitboxY.posY)
debug3("== END ControllerMoveDelta ==")
}
// PUSH THE HITBOX INTO THE AIR for a pixel so IT WON'T BE COLLIDING // PUSH THE HITBOX INTO THE AIR for a pixel so IT WON'T BE COLLIDING
// //
@@ -762,16 +826,9 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
debug2("externalForce: $externalForce, displacement: ${simulationHitbox - hitbox}") debug2("externalForce: $externalForce, displacement: ${simulationHitbox - hitbox}")
//hitbox.translate(getBacktrackDelta(bmid))
hitbox.reassign(simulationHitbox) hitbox.reassign(simulationHitbox)
}
}
// resolve controllerMoveDelta
if (controllerMoveDelta != null) {
hitbox.translate(controllerMoveDelta)
}
@@ -1186,7 +1243,7 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
private fun clampHitbox() { private fun clampHitbox() {
val worldsizePxl = world.width.times(TILE_SIZE) val worldsizePxl = world.width.times(TILE_SIZE)
hitbox.setPositionFromPoint( hitbox.setPositionFromPointed(
//clampW(hitbox.pointedX), //clampW(hitbox.pointedX),
if (hitbox.pointedX < 0) if (hitbox.pointedX < 0)
hitbox.pointedX + worldsizePxl hitbox.pointedX + worldsizePxl