mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-09 01:54:04 +09:00
sorta works?
This commit is contained in:
@@ -11,6 +11,7 @@ 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 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
|
||||||
@@ -53,7 +54,6 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
* !! external class should not hitbox.set(); use setHitboxDimension() and setPosition()
|
* !! external class should not hitbox.set(); use setHitboxDimension() and setPosition()
|
||||||
*/
|
*/
|
||||||
override val hitbox = Hitbox(0.0, 0.0, 0.0, 0.0) // Hitbox is implemented using Double;
|
override val hitbox = Hitbox(0.0, 0.0, 0.0, 0.0) // Hitbox is implemented using Double;
|
||||||
//@Transient val nextHitbox = Hitbox(0.0, 0.0, 0.0, 0.0) // 52 mantissas ought to be enough for anybody...
|
|
||||||
|
|
||||||
val tilewiseHitbox: Hitbox
|
val tilewiseHitbox: Hitbox
|
||||||
get() = Hitbox.fromTwoPoints(
|
get() = Hitbox.fromTwoPoints(
|
||||||
@@ -235,11 +235,6 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
protected val updateDelta: Int
|
protected val updateDelta: Int
|
||||||
get() = Terrarum.delta
|
get() = Terrarum.delta
|
||||||
|
|
||||||
/**
|
|
||||||
* true: This actor had just made collision
|
|
||||||
*/
|
|
||||||
var ccdCollided = false
|
|
||||||
private set
|
|
||||||
|
|
||||||
var isWalkingH = false
|
var isWalkingH = false
|
||||||
var isWalkingV = false
|
var isWalkingV = false
|
||||||
@@ -298,17 +293,10 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
y - (baseHitboxH - hitboxTranslateY) * scale,
|
y - (baseHitboxH - hitboxTranslateY) * scale,
|
||||||
baseHitboxW * scale,
|
baseHitboxW * scale,
|
||||||
baseHitboxH * scale)
|
baseHitboxH * scale)
|
||||||
|
|
||||||
/*nextHitbox.setFromWidthHeight(
|
|
||||||
x - (baseHitboxW / 2 - hitboxTranslateX) * scale,
|
|
||||||
y - (baseHitboxH - hitboxTranslateY) * scale,
|
|
||||||
baseHitboxW * scale,
|
|
||||||
baseHitboxH * scale)*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translatePosition(dx: Double, dy: Double) {
|
private fun translatePosition(dx: Double, dy: Double) {
|
||||||
hitbox.translate(dx, dy)
|
hitbox.translate(dx, dy)
|
||||||
nextHitbox.translate(dx, dy)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val centrePosVector: Vector2
|
val centrePosVector: Vector2
|
||||||
@@ -374,9 +362,9 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
moveDelta.y = moveDelta.y.bipolarClamp(VELO_HARD_LIMIT)
|
moveDelta.y = moveDelta.y.bipolarClamp(VELO_HARD_LIMIT)
|
||||||
|
|
||||||
if (!isChronostasis) {
|
if (!isChronostasis) {
|
||||||
///////////////////////////////////////////////////////
|
///////////////////////////////////////////////////
|
||||||
// Codes that (SHOULD) displaces nextHitbox directly //
|
// Codes that (SHOULD) displaces hitbox directly //
|
||||||
///////////////////////////////////////////////////////
|
///////////////////////////////////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* solveCollision()?
|
* solveCollision()?
|
||||||
@@ -412,30 +400,31 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
displaceHitbox()
|
displaceHitbox()
|
||||||
applyNormalForce()
|
applyNormalForce()
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
hitbox.translate(moveDelta)
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
// Codes that modifies velocity (after hitbox displacement) //
|
// Codes that modifies velocity (after hitbox displacement) //
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// modified vectors below SHOULD NOT IMMEDIATELY APPLIED!! //
|
||||||
|
// these are FOR THE NEXT ROUND of update //
|
||||||
|
// ((DO NOT DELETE THIS; made same mistake twice already)) //
|
||||||
|
|
||||||
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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// some spacing //
|
|
||||||
|
|
||||||
|
|
||||||
// apply our compensation to actual hitbox
|
|
||||||
updateHitbox()
|
|
||||||
|
|
||||||
// make sure if the actor tries to go out of the map, loop back instead
|
// make sure if the actor tries to go out of the map, loop back instead
|
||||||
clampHitbox()
|
clampHitbox()
|
||||||
}
|
}
|
||||||
|
|
||||||
// cheap solution for sticking into the wall while Left or Right is held
|
// cheap solution for sticking into the wall while Left or Right is held
|
||||||
walledLeft = isTouchingSide(nextHitbox, COLLIDING_LEFT)
|
walledLeft = isTouchingSide(hitbox, COLLIDING_LEFT)
|
||||||
walledRight = isTouchingSide(nextHitbox, COLLIDING_RIGHT)
|
walledRight = isTouchingSide(hitbox, COLLIDING_RIGHT)
|
||||||
if (isPlayerNoClip) {
|
if (isPlayerNoClip) {
|
||||||
walledLeft = false
|
walledLeft = false
|
||||||
walledRight = false
|
walledRight = false
|
||||||
@@ -491,7 +480,7 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
* Apply only if not grounded; normal force is precessed separately.
|
* Apply only if not grounded; normal force is precessed separately.
|
||||||
*/
|
*/
|
||||||
private fun applyGravitation() {
|
private fun applyGravitation() {
|
||||||
if (!isNoSubjectToGrav) {
|
if (!isNoSubjectToGrav && !isTouchingSide(hitbox, COLLIDING_BOTTOM)) {
|
||||||
//if (!isTouchingSide(hitbox, COLLIDING_BOTTOM)) {
|
//if (!isTouchingSide(hitbox, COLLIDING_BOTTOM)) {
|
||||||
/**
|
/**
|
||||||
* weight; gravitational force in action
|
* weight; gravitational force in action
|
||||||
@@ -521,43 +510,27 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
|
|
||||||
// was moving downward?
|
// was moving downward?
|
||||||
if (moveDelta.y > 0.0) {
|
if (moveDelta.y > 0.0) {
|
||||||
if (moveDelta.y > 0.587777) { // dampening
|
if (isTouchingSide(hitbox, COLLIDING_TOP)) { // hit the ceiling
|
||||||
if (isColliding(nextHitbox, COLLIDING_TOP)) { // hit the ceiling
|
hitAndReflectY() //hitAndForciblyReflectY()
|
||||||
hitAndReflectY() //hitAndForciblyReflectY()
|
grounded = false
|
||||||
grounded = false
|
|
||||||
}
|
|
||||||
else if (isColliding(nextHitbox)) {
|
|
||||||
hitAndReflectY()
|
|
||||||
grounded = true
|
|
||||||
}
|
|
||||||
else if (isTouchingSide(nextHitbox, COLLIDING_BOTTOM) && !isColliding(nextHitbox)) { // actor hit something on its bottom
|
|
||||||
hitAndReflectY()
|
|
||||||
grounded = true
|
|
||||||
}
|
|
||||||
else { // the actor is not grounded at all
|
|
||||||
grounded = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else { // dampening
|
else if (isTouchingSide(hitbox, COLLIDING_BOTTOM)) { // actor hit something on its bottom
|
||||||
|
hitAndReflectY()
|
||||||
grounded = true
|
grounded = true
|
||||||
}
|
}
|
||||||
|
else { // the actor is not grounded at all
|
||||||
|
grounded = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// or was moving upward?
|
// or was moving upward?
|
||||||
else if (moveDelta.y < 0.0) {
|
else if (moveDelta.y < 0.0) {
|
||||||
if (moveDelta.y < -0.587777) { // dampening
|
grounded = false
|
||||||
grounded = false
|
if (isTouchingSide(hitbox, COLLIDING_TOP)) { // actor hit something on its top
|
||||||
if (isTouchingSide(nextHitbox, COLLIDING_TOP)) { // actor hit something on its top
|
hitAndForciblyReflectY() // prevents sticking to the ceiling
|
||||||
hitAndForciblyReflectY() // prevents sticking to the ceiling
|
|
||||||
}
|
|
||||||
else { // the actor is not grounded at all
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // dampening
|
|
||||||
grounded = true // force grounded
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// axis X
|
// axis X
|
||||||
if (isTouchingSide(nextHitbox, COLLIDING_LEFT) || isTouchingSide(nextHitbox, COLLIDING_RIGHT)) { // check right and left
|
if (isTouchingSide(hitbox, COLLIDING_LEFT) || isTouchingSide(hitbox, COLLIDING_RIGHT)) { // check right and left
|
||||||
// the actor is hitting the wall
|
// the actor is hitting the wall
|
||||||
|
|
||||||
// FIXME balls are stuck in this
|
// FIXME balls are stuck in this
|
||||||
@@ -572,14 +545,12 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
* nextHitbox must NOT be altered before this method is called!
|
* nextHitbox must NOT be altered before this method is called!
|
||||||
*/
|
*/
|
||||||
@Deprecated("It's stupid anyway.") private fun displaceByCCD() {
|
@Deprecated("It's stupid anyway.") private fun displaceByCCD() {
|
||||||
ccdCollided = false
|
|
||||||
|
|
||||||
if (!isNoCollideWorld) {
|
if (!isNoCollideWorld) {
|
||||||
if (!isColliding(nextHitbox, COLLIDING_ALLSIDE))
|
if (!isColliding(hitbox, COLLIDING_ALLSIDE))
|
||||||
return
|
return
|
||||||
|
|
||||||
// do some CCD between hitbox and nextHitbox
|
// do some CCD between hitbox and nextHitbox
|
||||||
val ccdDelta = (nextHitbox.toVector() - hitbox.toVector())
|
val ccdDelta = (hitbox.toVector() - hitbox.toVector())
|
||||||
if (ccdDelta.x != 0.0 || ccdDelta.y != 0.0) {
|
if (ccdDelta.x != 0.0 || ccdDelta.y != 0.0) {
|
||||||
//ccdDelta.set(ccdDelta.setMagnitude(CCD_TICK)) // fixed tick
|
//ccdDelta.set(ccdDelta.setMagnitude(CCD_TICK)) // fixed tick
|
||||||
val displacement = Math.min(1.0.div(moveDelta.magnitude * 2), 0.5) // adaptive tick
|
val displacement = Math.min(1.0.div(moveDelta.magnitude * 2), 0.5) // adaptive tick
|
||||||
@@ -589,9 +560,8 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
//println("deltaMax: $deltaMax")
|
//println("deltaMax: $deltaMax")
|
||||||
//println("ccdDelta: $ccdDelta")
|
//println("ccdDelta: $ccdDelta")
|
||||||
|
|
||||||
while (!ccdDelta.isZero && isColliding(nextHitbox, COLLIDING_ALLSIDE)) {
|
while (!ccdDelta.isZero && isColliding(hitbox, COLLIDING_ALLSIDE)) {
|
||||||
nextHitbox.translate(-ccdDelta)
|
hitbox.translate(-ccdDelta)
|
||||||
ccdCollided = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//println("ccdCollided: $ccdCollided")
|
//println("ccdCollided: $ccdCollided")
|
||||||
@@ -601,7 +571,8 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
/**
|
/**
|
||||||
* nextHitbox must NOT be altered before this method is called!
|
* nextHitbox must NOT be altered before this method is called!
|
||||||
*/
|
*/
|
||||||
private val backtrackSteps = 16 // max allowed velocity = backtrackSteps * TILE_SIZE
|
private val ccdSteps = 16 // max allowed velocity = backtrackSteps * TILE_SIZE
|
||||||
|
private val binaryBranchingMax = 54 // higher = more precise; theoretical max = 54 (# of mantissa + 2)
|
||||||
|
|
||||||
private fun displaceHitbox() {
|
private fun displaceHitbox() {
|
||||||
// I kinda need these notes when I'm not caffeinated
|
// I kinda need these notes when I'm not caffeinated
|
||||||
@@ -614,240 +585,100 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
// - Displace `hitbox` directly
|
// - Displace `hitbox` directly
|
||||||
// - Make sure "isTouching" is perfectly useable, it depends on it
|
// - Make sure "isTouching" is perfectly useable, it depends on it
|
||||||
// [Procedure]
|
// [Procedure]
|
||||||
// backtrack (16) steps to determine it is embedded to the wall, or passed through it
|
// find "edge" point using binary search
|
||||||
// if (above procedure returns true):
|
|
||||||
// displace "hitbox" using linear interpolation
|
|
||||||
// else:
|
|
||||||
// hitbox = hitbox moved by the vector
|
|
||||||
// [END OF SUBROUTINE]
|
// [END OF SUBROUTINE]
|
||||||
|
|
||||||
|
if (moveDelta.isZero) return
|
||||||
|
|
||||||
fun getBacktrackDelta(counter: Double): Vector2 =
|
|
||||||
moveDelta * (counter) / backtrackSteps.toDouble()
|
|
||||||
|
|
||||||
var embeddedToTerrainCounter = 0.0 //0..16: embedding detected (detected at this-th try)
|
fun getBacktrackDelta(percentage: Double): Vector2 {
|
||||||
|
if (percentage < 0.0 || percentage > 1.0)
|
||||||
|
throw IllegalArgumentException("$percentage")
|
||||||
|
|
||||||
|
return moveDelta * percentage
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
val simulationHitbox = hitbox.clone()
|
||||||
|
var ccdTick: Int = ccdSteps // 0..15: collision detected, 16: not
|
||||||
|
|
||||||
|
// do CCD first
|
||||||
|
for (i in 0..ccdSteps - 1) { // 0..15 because (i+1) is always implied by Binary Search
|
||||||
|
simulationHitbox.reassign(hitbox)
|
||||||
|
simulationHitbox.translate(getBacktrackDelta(i.toDouble() / ccdSteps))
|
||||||
|
|
||||||
// it's rather a _simulator_ rather than _backtracker_, though
|
|
||||||
var simulationHitbox = hitbox.clone()
|
|
||||||
for (i in 0..backtrackSteps - 1) {
|
|
||||||
// check collision
|
|
||||||
if (isColliding(simulationHitbox)) {
|
if (isColliding(simulationHitbox)) {
|
||||||
|
ccdTick = i
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
val backtrackSize = getBacktrackDelta(i.toDouble()) //to avoid fp precision error derived from the Integration
|
|
||||||
simulationHitbox = hitbox.translate(backtrackSize) // make new hitbox every turn to avoid fp precision error
|
|
||||||
embeddedToTerrainCounter += 1.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// collision detected
|
// collision not found
|
||||||
if (embeddedToTerrainCounter < backtrackSteps) {
|
if (ccdTick == ccdSteps) {
|
||||||
// linear interpolation kicks in
|
|
||||||
// or block-wise binary search for the collision point
|
|
||||||
// do this along X- and Y-axis and take the lowest
|
|
||||||
|
|
||||||
val HB_START = 1; val HB_END = -1
|
|
||||||
val xDestInTileCoord: Int // may contain placeholder value
|
|
||||||
val yDestInTileCoord: Int // may contain placeholder value
|
|
||||||
val xDestMode: Int? // null means NO OPERATION
|
|
||||||
val yDestMode: Int? // null means NO OPERATION
|
|
||||||
|
|
||||||
// doing whatever for X-axis
|
|
||||||
// determine if we should use LEFT or RIGHT side
|
|
||||||
if (moveDelta.x > 0) { // going RIGHT, use RIGHT side
|
|
||||||
var embedLow = embeddedToTerrainCounter
|
|
||||||
var embedHigh = embeddedToTerrainCounter + 1.0
|
|
||||||
var low = (hitbox.endPointX + getBacktrackDelta(embedLow).x).div(TILE_SIZE).floorInt()
|
|
||||||
var lowY = hitbox.posY + getBacktrackDelta(embedLow).y
|
|
||||||
var high = (hitbox.endPointX + getBacktrackDelta(embedHigh).x).div(TILE_SIZE).floorInt()
|
|
||||||
var highY = hitbox.posY + getBacktrackDelta(embedHigh).y
|
|
||||||
|
|
||||||
while (low <= high) {
|
|
||||||
val mid = (low + high).ushr(1)
|
|
||||||
val midY = (lowY / 2) + (highY / 2) // to eliminate precision loss (which is negligible anyway...)
|
|
||||||
// y pos : middle of (low, high) hbxs
|
|
||||||
val yStart = midY.div(TILE_SIZE).floorInt()
|
|
||||||
val yEnd = (midY + hitbox.height).div(TILE_SIZE).floorInt()
|
|
||||||
|
|
||||||
val isColliding = (yStart..yEnd).map {
|
|
||||||
BlockCodex[world.getTileFromTerrain(mid, it) ?: Block.STONE].isSolid.toInt()
|
|
||||||
}.sum() != 0
|
|
||||||
|
|
||||||
if (isColliding) {
|
|
||||||
high = mid - 1
|
|
||||||
embedHigh = (embedLow / 2) + (embedHigh / 2)
|
|
||||||
highY = hitbox.posY + getBacktrackDelta(embedHigh).y
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
low = mid + 1
|
|
||||||
embedLow = (embedLow / 2) + (embedHigh / 2)
|
|
||||||
lowY = hitbox.posY + getBacktrackDelta(embedLow).y
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xDestInTileCoord = minOf(low, high)
|
|
||||||
xDestMode = HB_END
|
|
||||||
}
|
|
||||||
else if (moveDelta.x < 0) { // going LEFT, use LEFT side
|
|
||||||
var embedLow = embeddedToTerrainCounter + 1.0
|
|
||||||
var embedHigh = embeddedToTerrainCounter
|
|
||||||
var low = (hitbox.posX + getBacktrackDelta(embedLow).x).div(TILE_SIZE).floorInt()
|
|
||||||
var lowY = hitbox.posY + getBacktrackDelta(embedLow).y
|
|
||||||
var high = (hitbox.posX + getBacktrackDelta(embedHigh).x).div(TILE_SIZE).floorInt()
|
|
||||||
var highY = hitbox.posY + getBacktrackDelta(embedHigh).y
|
|
||||||
|
|
||||||
while (low <= high) {
|
|
||||||
val mid = (low + high).ushr(1)
|
|
||||||
val midY = (lowY / 2) + (highY / 2) // to eliminate precision loss (which is negligible anyway...)
|
|
||||||
// y pos : middle of (low, high) hbxs
|
|
||||||
val yStart = midY.div(TILE_SIZE).floorInt()
|
|
||||||
val yEnd = (midY + hitbox.height).div(TILE_SIZE).floorInt()
|
|
||||||
|
|
||||||
val isColliding = (yStart..yEnd).map {
|
|
||||||
BlockCodex[world.getTileFromTerrain(mid, it) ?: Block.STONE].isSolid.toInt()
|
|
||||||
}.sum() != 0
|
|
||||||
|
|
||||||
if (!isColliding) {
|
|
||||||
high = mid - 1
|
|
||||||
embedHigh = (embedLow / 2) + (embedHigh / 2)
|
|
||||||
highY = hitbox.posY + getBacktrackDelta(embedHigh).y
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
low = mid + 1
|
|
||||||
embedLow = (embedLow / 2) + (embedHigh / 2)
|
|
||||||
lowY = hitbox.posY + getBacktrackDelta(embedLow).y
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xDestInTileCoord = maxOf(low, high)
|
|
||||||
xDestMode = HB_START
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
xDestInTileCoord = 0 // placeholder
|
|
||||||
xDestMode = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// doing whatever for Y-axis
|
|
||||||
// determine if we should use UP or DOWN side
|
|
||||||
if (moveDelta.y > 0) { // going DOWN, use DOWN side
|
|
||||||
var embedLow = embeddedToTerrainCounter
|
|
||||||
var embedHigh = embeddedToTerrainCounter + 1.0
|
|
||||||
var low = (hitbox.endPointY + getBacktrackDelta(embedLow).y).div(TILE_SIZE).floorInt()
|
|
||||||
var lowX = hitbox.posX + getBacktrackDelta(embedLow).x
|
|
||||||
var high = (hitbox.endPointY + getBacktrackDelta(embedHigh).y).div(TILE_SIZE).floorInt()
|
|
||||||
var highX = hitbox.posX + getBacktrackDelta(embedHigh).x
|
|
||||||
|
|
||||||
while (low <= high) {
|
|
||||||
val mid = (low + high).ushr(1)
|
|
||||||
val midX = (lowX / 2) + (highX / 2) // to eliminate precision loss (which is negligible anyway...)
|
|
||||||
// x pos : middle of (low, high) hbxs
|
|
||||||
val xStart = midX.div(TILE_SIZE).floorInt()
|
|
||||||
val xEnd = (midX + hitbox.width).div(TILE_SIZE).floorInt()
|
|
||||||
|
|
||||||
val isColliding = (xStart..xEnd).map {
|
|
||||||
BlockCodex[world.getTileFromTerrain(it, mid) ?: Block.STONE].isSolid.toInt()
|
|
||||||
}.sum() != 0
|
|
||||||
|
|
||||||
if (isColliding) {
|
|
||||||
high = mid - 1
|
|
||||||
embedHigh = (embedLow / 2) + (embedHigh / 2)
|
|
||||||
highX = hitbox.posX + getBacktrackDelta(embedHigh).x
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
low = mid + 1
|
|
||||||
embedLow = (embedLow / 2) + (embedHigh / 2)
|
|
||||||
lowX = hitbox.posX + getBacktrackDelta(embedLow).x
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
yDestInTileCoord = minOf(low, high)
|
|
||||||
yDestMode = HB_END
|
|
||||||
}
|
|
||||||
else if (moveDelta.y < 0) { // going UP, use UP side
|
|
||||||
var embedLow = embeddedToTerrainCounter + 1.0
|
|
||||||
var embedHigh = embeddedToTerrainCounter
|
|
||||||
var low = (hitbox.posY + getBacktrackDelta(embedLow).y).div(TILE_SIZE).floorInt()
|
|
||||||
var lowX = hitbox.posX + getBacktrackDelta(embedLow).x
|
|
||||||
var high = (hitbox.posY + getBacktrackDelta(embedHigh).y).div(TILE_SIZE).floorInt()
|
|
||||||
var highX = hitbox.posX + getBacktrackDelta(embedHigh).x
|
|
||||||
|
|
||||||
while (low <= high) {
|
|
||||||
val mid = (low + high).ushr(1)
|
|
||||||
val midX = (lowX / 2) + (highX / 2) // to eliminate precision loss (which is negligible anyway...)
|
|
||||||
// x pos : middle of (low, high) hbxs
|
|
||||||
val xStart = midX.div(TILE_SIZE).floorInt()
|
|
||||||
val xEnd = (midX + hitbox.width).div(TILE_SIZE).floorInt()
|
|
||||||
|
|
||||||
val isColliding = (xStart..xEnd).map {
|
|
||||||
BlockCodex[world.getTileFromTerrain(it, mid) ?: Block.STONE].isSolid.toInt()
|
|
||||||
}.sum() != 0
|
|
||||||
|
|
||||||
if (!isColliding) {
|
|
||||||
high = mid - 1
|
|
||||||
embedHigh = (embedLow / 2) + (embedHigh / 2)
|
|
||||||
highX = hitbox.posX + getBacktrackDelta(embedHigh).x
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
low = mid + 1
|
|
||||||
embedLow = (embedLow / 2) + (embedHigh / 2)
|
|
||||||
lowX = hitbox.posX + getBacktrackDelta(embedLow).x
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
yDestInTileCoord = maxOf(low, high)
|
|
||||||
yDestMode = HB_START
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
yDestInTileCoord = 0 // placeholder
|
|
||||||
yDestMode = null
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// displace for axes
|
|
||||||
if (xDestMode != null) {
|
|
||||||
if (xDestMode == HB_START) {
|
|
||||||
hitbox.setFromTwoPoints(
|
|
||||||
xDestInTileCoord.times(TILE_SIZE).toDouble(),
|
|
||||||
hitbox.posY,
|
|
||||||
xDestInTileCoord.times(TILE_SIZE) + hitbox.width,
|
|
||||||
hitbox.endPointY
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else if (xDestMode == HB_END) {
|
|
||||||
hitbox.setFromTwoPoints(
|
|
||||||
xDestInTileCoord.times(TILE_SIZE) - hitbox.width,
|
|
||||||
hitbox.posY,
|
|
||||||
xDestInTileCoord.times(TILE_SIZE).toDouble(),
|
|
||||||
hitbox.endPointY
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (yDestMode != null) {
|
|
||||||
if (yDestMode == HB_START) {
|
|
||||||
hitbox.setFromTwoPoints(
|
|
||||||
hitbox.posX,
|
|
||||||
yDestInTileCoord.times(TILE_SIZE).toDouble(),
|
|
||||||
hitbox.endPointX,
|
|
||||||
yDestInTileCoord.times(TILE_SIZE) + hitbox.height
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else if (yDestMode == HB_END) {
|
|
||||||
hitbox.setFromTwoPoints(
|
|
||||||
hitbox.posX,
|
|
||||||
yDestInTileCoord.times(TILE_SIZE) - hitbox.height,
|
|
||||||
hitbox.endPointX,
|
|
||||||
yDestInTileCoord.times(TILE_SIZE).toDouble()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // END IF collision detected
|
|
||||||
else {
|
|
||||||
hitbox.translate(moveDelta)
|
hitbox.translate(moveDelta)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// find no-collision point using binary search
|
||||||
|
// trust me, X- and Y-axis must move simultaneously.
|
||||||
|
//// binary search ////
|
||||||
|
var low = ccdTick.toDouble() / ccdSteps
|
||||||
|
var high = (ccdTick + 1).toDouble() / ccdSteps
|
||||||
|
//var mid = 0.5
|
||||||
|
//var midDelta = 0.5
|
||||||
|
var bmid = (low / 2.0) + (high / 2.0)
|
||||||
|
|
||||||
|
(2..binaryBranchingMax + 1).forEach {
|
||||||
|
|
||||||
|
bmid = (low / 2.0) + (high / 2.0)
|
||||||
|
|
||||||
|
simulationHitbox.reassign(hitbox)
|
||||||
|
//simulationHitbox.translate(getBacktrackDelta(mid))
|
||||||
|
simulationHitbox.translate(getBacktrackDelta(bmid))
|
||||||
|
|
||||||
|
// set new mid
|
||||||
|
if (isColliding(simulationHitbox)) {
|
||||||
|
//midDelta /= 2
|
||||||
|
//mid -= midDelta
|
||||||
|
high = bmid
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//midDelta /= 2
|
||||||
|
//mid += midDelta
|
||||||
|
low = bmid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmove again (gah!)
|
||||||
|
TBA
|
||||||
|
|
||||||
|
//println("moveDelta: $moveDelta, displacement: ${getBacktrackDelta(mid)}, mid: $mid")
|
||||||
|
//hitbox.translate(getBacktrackDelta(mid- 0.0000000000004))
|
||||||
|
println("moveDelta: $moveDelta, displacement: ${getBacktrackDelta(bmid)}, mid: $bmid")
|
||||||
|
hitbox.translate(getBacktrackDelta(bmid))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*var ccdStep = 0.0
|
||||||
|
while (!isColliding(simulationHitbox) && ccdStep < 1.0) {
|
||||||
|
simulationHitbox.reassign(hitbox)
|
||||||
|
simulationHitbox.translate(getBacktrackDelta(ccdStep))
|
||||||
|
ccdStep += 1.0/256.0
|
||||||
|
}
|
||||||
|
|
||||||
|
hitbox.translate(getBacktrackDelta(ccdStep))
|
||||||
|
|
||||||
|
println("endY: ${hitbox.endPointY}\tccdStep: $ccdStep")*/
|
||||||
|
|
||||||
|
|
||||||
|
//println("pointedY: ${hitbox.pointedY}")
|
||||||
|
|
||||||
|
// if collision not detected, just don't care; it's not your job to apply moveDelta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private fun hitAndReflectX() {
|
private fun hitAndReflectX() {
|
||||||
// when it sticks, externalForce.x goes back and forth
|
// when it sticks, externalForce.x goes back and forth
|
||||||
/*
|
/*
|
||||||
@@ -904,7 +735,7 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
externalForce.y = moveDelta.y * CEILING_HIT_ELASTICITY
|
externalForce.y = moveDelta.y * CEILING_HIT_ELASTICITY
|
||||||
//externalForce.y = 0.0
|
//externalForce.y = 0.0
|
||||||
|
|
||||||
nextHitbox.translatePosY(0.5)
|
hitbox.translatePosY(0.5)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw Error("Check this out bitch (moveDelta.y = ${moveDelta.y})")
|
throw Error("Check this out bitch (moveDelta.y = ${moveDelta.y})")
|
||||||
@@ -963,10 +794,10 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val txStart = x1.div(TILE_SIZE).floorInt()
|
val txStart = x1.plus(Epsilon.E) .div(TILE_SIZE).floorInt()
|
||||||
val txEnd = x2.div(TILE_SIZE).floorInt()
|
val txEnd = x2.minus(Epsilon.E).div(TILE_SIZE).floorInt()
|
||||||
val tyStart = y1.div(TILE_SIZE).floorInt()
|
val tyStart = y1.plus(Epsilon.E) .div(TILE_SIZE).floorInt()
|
||||||
val tyEnd = y2.div(TILE_SIZE).floorInt()
|
val tyEnd = y2.minus(Epsilon.E).div(TILE_SIZE).floorInt()
|
||||||
|
|
||||||
return isCollidingInternal(txStart, tyStart, txEnd, tyEnd)
|
return isCollidingInternal(txStart, tyStart, txEnd, tyEnd)
|
||||||
}
|
}
|
||||||
@@ -1002,10 +833,10 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
}
|
}
|
||||||
else throw IllegalArgumentException()
|
else throw IllegalArgumentException()
|
||||||
|
|
||||||
val txStart = x1.div(TILE_SIZE).floorInt()
|
val txStart = x1.plus(Epsilon.E) .div(TILE_SIZE).floorInt()
|
||||||
val txEnd = x2.div(TILE_SIZE).floorInt()
|
val txEnd = x2.minus(Epsilon.E).div(TILE_SIZE).floorInt()
|
||||||
val tyStart = y1.div(TILE_SIZE).floorInt()
|
val tyStart = y1.plus(Epsilon.E) .div(TILE_SIZE).floorInt()
|
||||||
val tyEnd = y2.div(TILE_SIZE).floorInt()
|
val tyEnd = y2.minus(Epsilon.E).div(TILE_SIZE).floorInt()
|
||||||
|
|
||||||
return isCollidingInternal(txStart, tyStart, txEnd, tyEnd)
|
return isCollidingInternal(txStart, tyStart, txEnd, tyEnd)
|
||||||
}
|
}
|
||||||
@@ -1042,10 +873,10 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
}
|
}
|
||||||
else throw IllegalArgumentException()
|
else throw IllegalArgumentException()
|
||||||
|
|
||||||
val txStart = x1.div(TILE_SIZE).floorInt()
|
val txStart = x1.plus(Epsilon.E) .div(TILE_SIZE).floorInt()
|
||||||
val txEnd = x2.div(TILE_SIZE).floorInt()
|
val txEnd = x2.minus(Epsilon.E).div(TILE_SIZE).floorInt()
|
||||||
val tyStart = y1.div(TILE_SIZE).floorInt()
|
val tyStart = y1.plus(Epsilon.E) .div(TILE_SIZE).floorInt()
|
||||||
val tyEnd = y2.div(TILE_SIZE).floorInt()
|
val tyEnd = y2.minus(Epsilon.E).div(TILE_SIZE).floorInt()
|
||||||
|
|
||||||
return isCollidingInternal(txStart, tyStart, txEnd, tyEnd)
|
return isCollidingInternal(txStart, tyStart, txEnd, tyEnd)
|
||||||
}
|
}
|
||||||
@@ -1064,28 +895,28 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
|
|
||||||
private fun getContactingAreaFluid(side: Int, translateX: Int = 0, translateY: Int = 0): Int {
|
private fun getContactingAreaFluid(side: Int, translateX: Int = 0, translateY: Int = 0): Int {
|
||||||
var contactAreaCounter = 0
|
var contactAreaCounter = 0
|
||||||
for (i in 0..(if (side % 2 == 0) nextHitbox.width else nextHitbox.height).roundInt() - 1) {
|
for (i in 0..(if (side % 2 == 0) hitbox.width else hitbox.height).roundInt() - 1) {
|
||||||
// set tile positions
|
// set tile positions
|
||||||
val tileX: Int
|
val tileX: Int
|
||||||
val tileY: Int
|
val tileY: Int
|
||||||
if (side == COLLIDING_LEFT) {
|
if (side == COLLIDING_LEFT) {
|
||||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundInt()
|
tileX = div16TruncateToMapWidth(hitbox.hitboxStart.x.roundInt()
|
||||||
+ i + translateX)
|
+ i + translateX)
|
||||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxEnd.y.roundInt() + translateY)
|
tileY = div16TruncateToMapHeight(hitbox.hitboxEnd.y.roundInt() + translateY)
|
||||||
}
|
}
|
||||||
else if (side == COLLIDING_TOP) {
|
else if (side == COLLIDING_TOP) {
|
||||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundInt()
|
tileX = div16TruncateToMapWidth(hitbox.hitboxStart.x.roundInt()
|
||||||
+ i + translateX)
|
+ i + translateX)
|
||||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundInt() + translateY)
|
tileY = div16TruncateToMapHeight(hitbox.hitboxStart.y.roundInt() + translateY)
|
||||||
}
|
}
|
||||||
else if (side == COLLIDING_RIGHT) {
|
else if (side == COLLIDING_RIGHT) {
|
||||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxEnd.x.roundInt() + translateX)
|
tileX = div16TruncateToMapWidth(hitbox.hitboxEnd.x.roundInt() + translateX)
|
||||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundInt()
|
tileY = div16TruncateToMapHeight(hitbox.hitboxStart.y.roundInt()
|
||||||
+ i + translateY)
|
+ i + translateY)
|
||||||
}
|
}
|
||||||
else if (side == COLLIDING_LEFT) {
|
else if (side == COLLIDING_LEFT) {
|
||||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundInt() + translateX)
|
tileX = div16TruncateToMapWidth(hitbox.hitboxStart.x.roundInt() + translateX)
|
||||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundInt()
|
tileY = div16TruncateToMapHeight(hitbox.hitboxStart.y.roundInt()
|
||||||
+ i + translateY)
|
+ i + translateY)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1322,17 +1153,6 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setNewNextHitbox() {
|
|
||||||
nextHitbox.setFromWidthHeight(
|
|
||||||
hitbox.posX + moveDelta.x,
|
|
||||||
hitbox.posY + moveDelta.y,
|
|
||||||
baseHitboxW * scale,
|
|
||||||
baseHitboxH * scale
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateHitbox() = hitbox.reassign(nextHitbox)
|
|
||||||
|
|
||||||
override fun drawGlow(g: Graphics) {
|
override fun drawGlow(g: Graphics) {
|
||||||
if (isVisible && spriteGlow != null) {
|
if (isVisible && spriteGlow != null) {
|
||||||
blendLightenOnly()
|
blendLightenOnly()
|
||||||
@@ -1420,22 +1240,22 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
|
|
||||||
|
|
||||||
private fun clampW(x: Double): Double =
|
private fun clampW(x: Double): Double =
|
||||||
if (x < TILE_SIZE + nextHitbox.width / 2) {
|
if (x < TILE_SIZE + hitbox.width / 2) {
|
||||||
TILE_SIZE + nextHitbox.width / 2
|
TILE_SIZE + hitbox.width / 2
|
||||||
}
|
}
|
||||||
else if (x >= (world.width * TILE_SIZE).toDouble() - TILE_SIZE.toDouble() - nextHitbox.width / 2) {
|
else if (x >= (world.width * TILE_SIZE).toDouble() - TILE_SIZE.toDouble() - hitbox.width / 2) {
|
||||||
(world.width * TILE_SIZE).toDouble() - 1.0 - TILE_SIZE.toDouble() - nextHitbox.width / 2
|
(world.width * TILE_SIZE).toDouble() - 1.0 - TILE_SIZE.toDouble() - hitbox.width / 2
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
x
|
x
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun clampH(y: Double): Double =
|
private fun clampH(y: Double): Double =
|
||||||
if (y < TILE_SIZE + nextHitbox.height) {
|
if (y < TILE_SIZE + hitbox.height) {
|
||||||
TILE_SIZE + nextHitbox.height
|
TILE_SIZE + hitbox.height
|
||||||
}
|
}
|
||||||
else if (y >= (world.height * TILE_SIZE).toDouble() - TILE_SIZE.toDouble() - nextHitbox.height) {
|
else if (y >= (world.height * TILE_SIZE).toDouble() - TILE_SIZE.toDouble() - hitbox.height) {
|
||||||
(world.height * TILE_SIZE).toDouble() - 1.0 - TILE_SIZE.toDouble() - nextHitbox.height
|
(world.height * TILE_SIZE).toDouble() - 1.0 - TILE_SIZE.toDouble() - hitbox.height
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
y
|
y
|
||||||
@@ -1498,7 +1318,7 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
val tiles = ArrayList<Int?>()
|
val tiles = ArrayList<Int?>()
|
||||||
|
|
||||||
// offset 1 pixel to the down so that friction would work
|
// offset 1 pixel to the down so that friction would work
|
||||||
val y = nextHitbox.endPointY.plus(1.0).div(TILE_SIZE).floorInt()
|
val y = hitbox.endPointY.plus(1.0).div(TILE_SIZE).floorInt()
|
||||||
|
|
||||||
for (x in tilewiseHitbox.posX.toInt()..tilewiseHitbox.endPointX.toInt()) {
|
for (x in tilewiseHitbox.posX.toInt()..tilewiseHitbox.endPointX.toInt()) {
|
||||||
tiles.add(world.getTileFromTerrain(x, y))
|
tiles.add(world.getTileFromTerrain(x, y))
|
||||||
@@ -1511,7 +1331,7 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
|
|||||||
val tileProps = ArrayList<BlockProp?>()
|
val tileProps = ArrayList<BlockProp?>()
|
||||||
|
|
||||||
// offset 1 pixel to the down so that friction would work
|
// offset 1 pixel to the down so that friction would work
|
||||||
val y = nextHitbox.endPointY.plus(1.0).div(TILE_SIZE).floorInt()
|
val y = hitbox.endPointY.plus(1.0).div(TILE_SIZE).floorInt()
|
||||||
|
|
||||||
for (x in tilewiseHitbox.posX.toInt()..tilewiseHitbox.endPointX.toInt()) {
|
for (x in tilewiseHitbox.posX.toInt()..tilewiseHitbox.endPointX.toInt()) {
|
||||||
tileProps.add(BlockCodex[world.getTileFromTerrain(x, y)])
|
tileProps.add(BlockCodex[world.getTileFromTerrain(x, y)])
|
||||||
|
|||||||
@@ -67,23 +67,22 @@ class BasicDebugInfoWindow : UICanvas {
|
|||||||
g.color = GameFontBase.codeToCol["y"]
|
g.color = GameFontBase.codeToCol["y"]
|
||||||
|
|
||||||
val hitbox = player?.hitbox
|
val hitbox = player?.hitbox
|
||||||
val nextHitbox = player?.nextHitbox
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* First column
|
* First column
|
||||||
*/
|
*/
|
||||||
|
|
||||||
printLine(g, 1, "posX "
|
printLine(g, 1, "pointedX "
|
||||||
+ ccG
|
+ ccG
|
||||||
+ "${hitbox?.pointedX}"
|
+ "${hitbox?.pointedX}"
|
||||||
+ " ("
|
+ " ("
|
||||||
+ "${(hitbox?.pointedX?.div(FeaturesDrawer.TILE_SIZE))?.toInt()}"
|
+ "${(hitbox?.pointedX?.div(FeaturesDrawer.TILE_SIZE))?.toInt()}"
|
||||||
+ ")")
|
+ ")")
|
||||||
printLine(g, 2, "posY "
|
printLine(g, 2, "endY "
|
||||||
+ ccG
|
+ ccG
|
||||||
+ hitbox?.pointedY.toString()
|
+ hitbox?.endPointY.toString()
|
||||||
+ " ("
|
+ " ("
|
||||||
+ (hitbox?.pointedY?.div(FeaturesDrawer.TILE_SIZE))?.toInt().toString()
|
+ (hitbox?.endPointY?.div(FeaturesDrawer.TILE_SIZE))?.toInt().toString()
|
||||||
+ ")")
|
+ ")")
|
||||||
|
|
||||||
printLine(g, 3, "veloX reported $ccG${player?.moveDelta?.x}")
|
printLine(g, 3, "veloX reported $ccG${player?.moveDelta?.x}")
|
||||||
@@ -95,6 +94,14 @@ class BasicDebugInfoWindow : UICanvas {
|
|||||||
printLine(g, 5, "grounded $ccG${player?.grounded}")
|
printLine(g, 5, "grounded $ccG${player?.grounded}")
|
||||||
printLine(g, 6, "noClip $ccG${player?.noClip}")
|
printLine(g, 6, "noClip $ccG${player?.noClip}")
|
||||||
|
|
||||||
|
|
||||||
|
if (player != null) {
|
||||||
|
printLine(g, 7,
|
||||||
|
"walled ${if (player.walledLeft) "$ccR" else "$ccG"}L" +
|
||||||
|
"${if (player.walledRight) "$ccR" else "$ccG"}R"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
//printLine(g, 7, "jump $ccG${player.jumpAcc}")
|
//printLine(g, 7, "jump $ccG${player.jumpAcc}")
|
||||||
|
|
||||||
val lightVal: String
|
val lightVal: String
|
||||||
|
|||||||
@@ -22,32 +22,30 @@
|
|||||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package org.dyn4j;
|
/* Kotlin modified code (c) 2017 Torvald (minjaesong) */
|
||||||
|
package org.dyn4j
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class containing an approximation of machine epsilon.
|
* Class containing an approximation of machine epsilon.
|
||||||
* @author William Bittle
|
* @author William Bittle
|
||||||
|
* *
|
||||||
* @version 2.0.0
|
* @version 2.0.0
|
||||||
|
* *
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
public final class Epsilon {
|
object Epsilon {
|
||||||
/** The double precision floating point machine epsilon approximation */
|
/** The double precision floating point machine epsilon approximation */
|
||||||
public static final double E = Epsilon.compute();
|
val E = Epsilon.compute()
|
||||||
|
|
||||||
/**
|
|
||||||
* Hidden default constructor.
|
|
||||||
*/
|
|
||||||
private Epsilon() {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes an approximation of machine epsilon.
|
* Computes an approximation of machine epsilon.
|
||||||
* @return double
|
* @return double
|
||||||
*/
|
*/
|
||||||
public static final double compute() {
|
private fun compute(): Double {
|
||||||
double e = 0.5;
|
var e = 0.5
|
||||||
while (1.0 + e > 1.0) {
|
while (1.0 + e > 1.0) {
|
||||||
e *= 0.5;
|
e *= 0.5
|
||||||
}
|
}
|
||||||
return e;
|
return e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user