sorta works?

This commit is contained in:
minjaesong
2017-05-07 00:24:00 +09:00
parent 25e93b2552
commit 1f1fcfdf5f
3 changed files with 166 additions and 341 deletions

View File

@@ -11,6 +11,7 @@ import net.torvald.terrarum.worlddrawer.WorldCamera
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.blockproperties.BlockProp
import net.torvald.terrarum.gameactors.ai.toInt
import org.dyn4j.Epsilon
import org.dyn4j.geometry.Vector2
import org.newdawn.slick.GameContainer
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()
*/
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
get() = Hitbox.fromTwoPoints(
@@ -235,11 +235,6 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
protected val updateDelta: Int
get() = Terrarum.delta
/**
* true: This actor had just made collision
*/
var ccdCollided = false
private set
var isWalkingH = false
var isWalkingV = false
@@ -298,17 +293,10 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
y - (baseHitboxH - hitboxTranslateY) * scale,
baseHitboxW * 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) {
hitbox.translate(dx, dy)
nextHitbox.translate(dx, dy)
}
val centrePosVector: Vector2
@@ -374,9 +362,9 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
moveDelta.y = moveDelta.y.bipolarClamp(VELO_HARD_LIMIT)
if (!isChronostasis) {
///////////////////////////////////////////////////////
// Codes that (SHOULD) displaces nextHitbox directly //
///////////////////////////////////////////////////////
///////////////////////////////////////////////////
// Codes that (SHOULD) displaces hitbox directly //
///////////////////////////////////////////////////
/**
* solveCollision()?
@@ -412,30 +400,31 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
displaceHitbox()
applyNormalForce()
}
else {
hitbox.translate(moveDelta)
}
//////////////////////////////////////////////////////////////
// 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
if (isPlayerNoClip) { // TODO also hanging on the rope, etc.
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
clampHitbox()
}
// cheap solution for sticking into the wall while Left or Right is held
walledLeft = isTouchingSide(nextHitbox, COLLIDING_LEFT)
walledRight = isTouchingSide(nextHitbox, COLLIDING_RIGHT)
walledLeft = isTouchingSide(hitbox, COLLIDING_LEFT)
walledRight = isTouchingSide(hitbox, COLLIDING_RIGHT)
if (isPlayerNoClip) {
walledLeft = 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.
*/
private fun applyGravitation() {
if (!isNoSubjectToGrav) {
if (!isNoSubjectToGrav && !isTouchingSide(hitbox, COLLIDING_BOTTOM)) {
//if (!isTouchingSide(hitbox, COLLIDING_BOTTOM)) {
/**
* weight; gravitational force in action
@@ -521,43 +510,27 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
// was moving downward?
if (moveDelta.y > 0.0) {
if (moveDelta.y > 0.587777) { // dampening
if (isColliding(nextHitbox, COLLIDING_TOP)) { // hit the ceiling
hitAndReflectY() //hitAndForciblyReflectY()
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
}
if (isTouchingSide(hitbox, COLLIDING_TOP)) { // hit the ceiling
hitAndReflectY() //hitAndForciblyReflectY()
grounded = false
}
else { // dampening
else if (isTouchingSide(hitbox, COLLIDING_BOTTOM)) { // actor hit something on its bottom
hitAndReflectY()
grounded = true
}
else { // the actor is not grounded at all
grounded = false
}
}
// or was moving upward?
else if (moveDelta.y < 0.0) {
if (moveDelta.y < -0.587777) { // dampening
grounded = false
if (isTouchingSide(nextHitbox, COLLIDING_TOP)) { // actor hit something on its top
hitAndForciblyReflectY() // prevents sticking to the ceiling
}
else { // the actor is not grounded at all
}
}
else { // dampening
grounded = true // force grounded
grounded = false
if (isTouchingSide(hitbox, COLLIDING_TOP)) { // actor hit something on its top
hitAndForciblyReflectY() // prevents sticking to the ceiling
}
}
// 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
// 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!
*/
@Deprecated("It's stupid anyway.") private fun displaceByCCD() {
ccdCollided = false
if (!isNoCollideWorld) {
if (!isColliding(nextHitbox, COLLIDING_ALLSIDE))
if (!isColliding(hitbox, COLLIDING_ALLSIDE))
return
// 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) {
//ccdDelta.set(ccdDelta.setMagnitude(CCD_TICK)) // fixed 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("ccdDelta: $ccdDelta")
while (!ccdDelta.isZero && isColliding(nextHitbox, COLLIDING_ALLSIDE)) {
nextHitbox.translate(-ccdDelta)
ccdCollided = true
while (!ccdDelta.isZero && isColliding(hitbox, COLLIDING_ALLSIDE)) {
hitbox.translate(-ccdDelta)
}
//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!
*/
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() {
// 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
// - Make sure "isTouching" is perfectly useable, it depends on it
// [Procedure]
// backtrack (16) steps to determine it is embedded to the wall, or passed through it
// if (above procedure returns true):
// displace "hitbox" using linear interpolation
// else:
// hitbox = hitbox moved by the vector
// find "edge" point using binary search
// [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)) {
ccdTick = i
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
if (embeddedToTerrainCounter < backtrackSteps) {
// 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 {
// collision not found
if (ccdTick == ccdSteps) {
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() {
// 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 = 0.0
nextHitbox.translatePosY(0.5)
hitbox.translatePosY(0.5)
}
else {
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 txEnd = x2.div(TILE_SIZE).floorInt()
val tyStart = y1.div(TILE_SIZE).floorInt()
val tyEnd = y2.div(TILE_SIZE).floorInt()
val txStart = x1.plus(Epsilon.E) .div(TILE_SIZE).floorInt()
val txEnd = x2.minus(Epsilon.E).div(TILE_SIZE).floorInt()
val tyStart = y1.plus(Epsilon.E) .div(TILE_SIZE).floorInt()
val tyEnd = y2.minus(Epsilon.E).div(TILE_SIZE).floorInt()
return isCollidingInternal(txStart, tyStart, txEnd, tyEnd)
}
@@ -1002,10 +833,10 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
}
else throw IllegalArgumentException()
val txStart = x1.div(TILE_SIZE).floorInt()
val txEnd = x2.div(TILE_SIZE).floorInt()
val tyStart = y1.div(TILE_SIZE).floorInt()
val tyEnd = y2.div(TILE_SIZE).floorInt()
val txStart = x1.plus(Epsilon.E) .div(TILE_SIZE).floorInt()
val txEnd = x2.minus(Epsilon.E).div(TILE_SIZE).floorInt()
val tyStart = y1.plus(Epsilon.E) .div(TILE_SIZE).floorInt()
val tyEnd = y2.minus(Epsilon.E).div(TILE_SIZE).floorInt()
return isCollidingInternal(txStart, tyStart, txEnd, tyEnd)
}
@@ -1042,10 +873,10 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
}
else throw IllegalArgumentException()
val txStart = x1.div(TILE_SIZE).floorInt()
val txEnd = x2.div(TILE_SIZE).floorInt()
val tyStart = y1.div(TILE_SIZE).floorInt()
val tyEnd = y2.div(TILE_SIZE).floorInt()
val txStart = x1.plus(Epsilon.E) .div(TILE_SIZE).floorInt()
val txEnd = x2.minus(Epsilon.E).div(TILE_SIZE).floorInt()
val tyStart = y1.plus(Epsilon.E) .div(TILE_SIZE).floorInt()
val tyEnd = y2.minus(Epsilon.E).div(TILE_SIZE).floorInt()
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 {
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
val tileX: Int
val tileY: Int
if (side == COLLIDING_LEFT) {
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundInt()
tileX = div16TruncateToMapWidth(hitbox.hitboxStart.x.roundInt()
+ i + translateX)
tileY = div16TruncateToMapHeight(nextHitbox.hitboxEnd.y.roundInt() + translateY)
tileY = div16TruncateToMapHeight(hitbox.hitboxEnd.y.roundInt() + translateY)
}
else if (side == COLLIDING_TOP) {
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundInt()
tileX = div16TruncateToMapWidth(hitbox.hitboxStart.x.roundInt()
+ i + translateX)
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundInt() + translateY)
tileY = div16TruncateToMapHeight(hitbox.hitboxStart.y.roundInt() + translateY)
}
else if (side == COLLIDING_RIGHT) {
tileX = div16TruncateToMapWidth(nextHitbox.hitboxEnd.x.roundInt() + translateX)
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundInt()
tileX = div16TruncateToMapWidth(hitbox.hitboxEnd.x.roundInt() + translateX)
tileY = div16TruncateToMapHeight(hitbox.hitboxStart.y.roundInt()
+ i + translateY)
}
else if (side == COLLIDING_LEFT) {
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundInt() + translateX)
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundInt()
tileX = div16TruncateToMapWidth(hitbox.hitboxStart.x.roundInt() + translateX)
tileY = div16TruncateToMapHeight(hitbox.hitboxStart.y.roundInt()
+ i + translateY)
}
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) {
if (isVisible && spriteGlow != null) {
blendLightenOnly()
@@ -1420,22 +1240,22 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
private fun clampW(x: Double): Double =
if (x < TILE_SIZE + nextHitbox.width / 2) {
TILE_SIZE + nextHitbox.width / 2
if (x < TILE_SIZE + hitbox.width / 2) {
TILE_SIZE + hitbox.width / 2
}
else if (x >= (world.width * TILE_SIZE).toDouble() - TILE_SIZE.toDouble() - nextHitbox.width / 2) {
(world.width * TILE_SIZE).toDouble() - 1.0 - 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() - hitbox.width / 2
}
else {
x
}
private fun clampH(y: Double): Double =
if (y < TILE_SIZE + nextHitbox.height) {
TILE_SIZE + nextHitbox.height
if (y < TILE_SIZE + hitbox.height) {
TILE_SIZE + hitbox.height
}
else if (y >= (world.height * TILE_SIZE).toDouble() - TILE_SIZE.toDouble() - nextHitbox.height) {
(world.height * TILE_SIZE).toDouble() - 1.0 - 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() - hitbox.height
}
else {
y
@@ -1498,7 +1318,7 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
val tiles = ArrayList<Int?>()
// 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()) {
tiles.add(world.getTileFromTerrain(x, y))
@@ -1511,7 +1331,7 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean
val tileProps = ArrayList<BlockProp?>()
// 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()) {
tileProps.add(BlockCodex[world.getTileFromTerrain(x, y)])

View File

@@ -67,23 +67,22 @@ class BasicDebugInfoWindow : UICanvas {
g.color = GameFontBase.codeToCol["y"]
val hitbox = player?.hitbox
val nextHitbox = player?.nextHitbox
/**
* First column
*/
printLine(g, 1, "posX "
printLine(g, 1, "pointedX "
+ ccG
+ "${hitbox?.pointedX}"
+ " ("
+ "${(hitbox?.pointedX?.div(FeaturesDrawer.TILE_SIZE))?.toInt()}"
+ ")")
printLine(g, 2, "posY "
printLine(g, 2, "endY "
+ 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}")
@@ -95,6 +94,14 @@ class BasicDebugInfoWindow : UICanvas {
printLine(g, 5, "grounded $ccG${player?.grounded}")
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}")
val lightVal: String

View File

@@ -22,32 +22,30 @@
* 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.
*/
package org.dyn4j;
/* Kotlin modified code (c) 2017 Torvald (minjaesong) */
package org.dyn4j
/**
* Class containing an approximation of machine epsilon.
* @author William Bittle
* *
* @version 2.0.0
* *
* @since 2.0.0
*/
public final class Epsilon {
/** The double precision floating point machine epsilon approximation */
public static final double E = Epsilon.compute();
/**
* Hidden default constructor.
*/
private Epsilon() {}
object Epsilon {
/** The double precision floating point machine epsilon approximation */
val E = Epsilon.compute()
/**
* Computes an approximation of machine epsilon.
* @return double
*/
public static final double compute() {
double e = 0.5;
private fun compute(): Double {
var e = 0.5
while (1.0 + e > 1.0) {
e *= 0.5;
e *= 0.5
}
return e;
return e
}
}