diff --git a/res/raw/creatures/CreatureHuman.json b/res/raw/creatures/CreatureHuman.json index 48ea7c6a4..85d309e35 100644 --- a/res/raw/creatures/CreatureHuman.json +++ b/res/raw/creatures/CreatureHuman.json @@ -12,10 +12,10 @@ "speed" : 3.0, "speedmult" : [100,100,100,100,100,100,100], - "jumppower" : 5, + "jumppower" : 4.3, "jumppowermult" : [100,100,100,100,100,100,100], - "scale" : 1, + "scale" : 1.0, "scalemult" : [100,100,100,100,100,100,100], "encumbrance" : 1000, diff --git a/src/net/torvald/terrarum/gameactors/ActorWithBody.kt b/src/net/torvald/terrarum/gameactors/ActorWithBody.kt index 5b725cecb..e8ce61311 100644 --- a/src/net/torvald/terrarum/gameactors/ActorWithBody.kt +++ b/src/net/torvald/terrarum/gameactors/ActorWithBody.kt @@ -74,10 +74,19 @@ open class ActorWithBody constructor() : Actor(), Visible { var scale: Double get() = actorValue.getAsDouble(AVKey.SCALE) ?: 1.0 set(value) = actorValue.set(AVKey.SCALE, value) + @Transient val MASS_LOWEST = 0.1 // Kilograms var mass: Double get() = actorValue.getAsDouble(AVKey.BASEMASS) ?: MASS_DEFAULT * Math.pow(scale, 3.0) - set(value) = actorValue.set(AVKey.BASEMASS, value) - @Transient private val MASS_LOWEST = 2.0 + set(value) { + if (value <= 0) + throw IllegalArgumentException("mass cannot be less than or equal to zero.") + else if (value < MASS_LOWEST) { + println("[ActorWithBody] input too low; assigning 0.1 instead.") + actorValue[AVKey.BASEMASS] = MASS_LOWEST + } + + actorValue[AVKey.BASEMASS] = value + } /** Valid range: [0, 1] */ var elasticity = 0.0 set(value) { @@ -155,7 +164,9 @@ open class ActorWithBody constructor() : Actor(), Visible { @Transient val DYNAMIC = 2 @Transient val STATIC = 3 - private val SLEEP_THRE = 0.05 + private val SLEEP_THRE = 0.125 + private val CCD_THRE = 1.0 + private val CCD_TICK = 0.125 init { @@ -237,7 +248,7 @@ open class ActorWithBody constructor() : Actor(), Visible { if (!physSleep) { // Set 'next' position (hitbox) to fiddle with - updateNextHitboxFromVelo() + setNewNextHitbox() // if not horizontally moving then ... //if (Math.abs(veloX) < 0.5) { // fix for special situations (see fig. 1 at the bottom of the source) @@ -248,8 +259,8 @@ open class ActorWithBody constructor() : Actor(), Visible { // compensate for colliding //updateHorizontalCollision() //updateVerticalCollision() - adjustHit() applyNormalForce() + adjustHit() setHorizontalFriction() if (isPlayerNoClip) setVerticalFriction() @@ -268,11 +279,10 @@ open class ActorWithBody constructor() : Actor(), Visible { /** * Apply gravitation to the every falling body (unless not levitating) - + * * Apply only if not grounded; normal force is not implemented (and redundant) * so we manually reset G to zero (not applying G. force) if grounded. */ - // FIXME abnormal jump behaviour if mass < 2, same thing happens if mass == 0 (but zero mass is invalid anyway). private fun applyGravitation() { if (!grounded) { /** @@ -476,59 +486,81 @@ open class ActorWithBody constructor() : Actor(), Visible { * nextHitbox must NOT altered before this method is called! */ private fun adjustHit() { - val delta: Vector2 = Vector2(hitbox.toVector() - nextHitbox.toVector()) // we need to traverse back, so may as well negate at the first place - delta *= SLEEP_THRE // CCD delta + if (!isNoCollideWorld){ + val delta: Vector2 = Vector2(hitbox.toVector() - nextHitbox.toVector()) // we need to traverse back, so may as well negate at the first place + val ccdDelta = delta.setMagnitude(CCD_TICK) - while (isColliding(CONTACT_AREA_LEFT) || isColliding(CONTACT_AREA_RIGHT) - || isColliding(CONTACT_AREA_TOP) || isColliding(CONTACT_AREA_BOTTOM) - ) { - // CCD to the 'delta' - nextHitbox.translate(delta) + while (isColliding(CONTACT_AREA_LEFT) || isColliding(CONTACT_AREA_RIGHT) + || isColliding(CONTACT_AREA_TOP) || isColliding(CONTACT_AREA_BOTTOM) + ) { + // while still colliding, CCD to the 'delta' + nextHitbox.translate(ccdDelta) + } } } private fun applyNormalForce() { if (!isNoCollideWorld) { - if (gravitation.y != 0.0) { - if (veloY > SLEEP_THRE && isColliding(CONTACT_AREA_BOTTOM, 0, 1)) { - veloY = 0.0 - grounded = (gravitation.y > 0) + // axis Y + if (veloY >= 0) { // check downward + if (isColliding(CONTACT_AREA_BOTTOM)) { // the ground has dug into the body + veloY = 0.0 // reset veloY, simulating normal force + elasticReflectY() + grounded = true } - else if (veloY < -SLEEP_THRE && isColliding(CONTACT_AREA_TOP, 0, -1)) { - veloY = 0.0 - grounded = (gravitation.y < 0) + else if (isColliding(CONTACT_AREA_BOTTOM, 0, 1)) { // the actor is standing ON the ground + veloY = 0.0 // reset veloY, simulating normal force + elasticReflectY() + grounded = true } - else { + else { // the actor is not grounded at all grounded = false } } - else { - if ((veloY > SLEEP_THRE && isColliding(CONTACT_AREA_BOTTOM, 0, 1)) - || (veloY < -SLEEP_THRE && isColliding(CONTACT_AREA_TOP, 0, -1)) - ) { - veloY = 0.0 + else if (veloY < 0) { // check upward + grounded = false + if (isColliding(CONTACT_AREA_TOP)) { // the ceiling has dug into the body + veloY = 0.0 // reset veloY, simulating normal force + elasticReflectY() + } + else if (isColliding(CONTACT_AREA_TOP, 0, -1)) { // the actor is touching the ceiling + veloY = 0.0 // reset veloY, simulating normal force + elasticReflectY() // reflect on ceiling, for reversed gravity + } + else { // the actor is not grounded at all } } - - if (gravitation.x != 0.0) { - if (veloX > SLEEP_THRE && isColliding(CONTACT_AREA_BOTTOM, 1, 0)) { - veloX = 0.0 - grounded = (gravitation.x > 0) + // axis X + if (veloX >= 0.5) { // check right + if (isColliding(CONTACT_AREA_RIGHT) && !isColliding(CONTACT_AREA_LEFT)) { + // the actor is embedded to the wall + veloX = 0.0 // reset veloX, simulating normal force + elasticReflectX() } - else if (veloX < -SLEEP_THRE && isColliding(CONTACT_AREA_TOP, -1, 0)) { - veloY = 0.0 - grounded = (gravitation.x < 0) + else if (isColliding(CONTACT_AREA_RIGHT, 2, 0) && !isColliding(CONTACT_AREA_LEFT, 0, 0)) { // offset by +1, to fix directional quarks + // the actor is touching the wall + veloX = 0.0 // reset veloX, simulating normal force + elasticReflectX() + } + else { + } + } + else if (veloX <= -0.5) { // check left + // System.out.println("collidingleft"); + if (isColliding(CONTACT_AREA_LEFT) && !isColliding(CONTACT_AREA_RIGHT)) { + // the actor is embedded to the wall + veloX = 0.0 // reset veloX, simulating normal force + elasticReflectX() + } + else if (isColliding(CONTACT_AREA_LEFT, -1, 0) && !isColliding(CONTACT_AREA_RIGHT, 1, 0)) { + // the actor is touching the wall + veloX = 0.0 // reset veloX, simulating normal force + elasticReflectX() } else { - grounded = false } } else { - if ((veloX > SLEEP_THRE && isColliding(CONTACT_AREA_RIGHT, 1, 0)) - || (veloX < -SLEEP_THRE && isColliding(CONTACT_AREA_LEFT, -1, 0)) - ) { - veloX = 0.0 - } } } } @@ -711,7 +743,7 @@ open class ActorWithBody constructor() : Actor(), Visible { clampW(nextHitbox.pointedX), clampH(nextHitbox.pointedY)) } - private fun updateNextHitboxFromVelo() { + private fun setNewNextHitbox() { nextHitbox.set( (hitbox.posX + veloX) @@ -724,13 +756,15 @@ open class ActorWithBody constructor() : Actor(), Visible { private fun updateHitboxX() { hitbox.setDimension( nextHitbox.width, nextHitbox.height) - hitbox.setPositionX(nextHitbox.posX) + //if (nextHitbox.posX - hitbox.posX > SLEEP_THRE.abs()) + hitbox.setPositionX(nextHitbox.posX) } private fun updateHitboxY() { hitbox.setDimension( nextHitbox.width, nextHitbox.height) - hitbox.setPositionY(nextHitbox.posY) + //if (nextHitbox.posY - hitbox.posY > SLEEP_THRE.abs()) + hitbox.setPositionY(nextHitbox.posY) } override fun drawGlow(gc: GameContainer, g: Graphics) { diff --git a/src/org/dyn4j/geometry/Vector2.kt b/src/org/dyn4j/geometry/Vector2.kt index 3fca54edd..b79bf456c 100644 --- a/src/org/dyn4j/geometry/Vector2.kt +++ b/src/org/dyn4j/geometry/Vector2.kt @@ -267,10 +267,9 @@ class Vector2 { * * * @return [Vector2] this vector */ - fun set(vector: Vector2): Vector2 { + fun set(vector: Vector2) { this.x = vector.x this.y = vector.y - return this } /** @@ -281,10 +280,9 @@ class Vector2 { * * * @return [Vector2] this vector */ - fun set(x: Double, y: Double): Vector2 { + fun set(x: Double, y: Double) { this.x = x this.y = y - return this } /** @@ -325,21 +323,19 @@ class Vector2 { fun setMagnitude(magnitude: Double): Vector2 { // check the given magnitude if (Math.abs(magnitude) <= Epsilon.E) { - this.x = 0.0 - this.y = 0.0 - return this + return Vector2(0.0, 0.0) } // is this vector a zero vector? if (this.isZero) { - return this + return Vector2(0.0, 0.0) } // get the magnitude var mag = Math.sqrt(this.x * this.x + this.y * this.y) // normalize and multiply by the new magnitude mag = magnitude / mag - this.x *= mag - this.y *= mag - return this + val newX = this.x * mag + val newY = this.y * mag + return Vector2(newX, newY) } /** @@ -359,9 +355,9 @@ class Vector2 { fun setDirection(angle: Double): Vector2 { //double magnitude = Math.hypot(this.x, this.y); val magnitude = Math.sqrt(this.x * this.x + this.y * this.y) - this.x = magnitude * Math.cos(angle) - this.y = magnitude * Math.sin(angle) - return this + val newX = magnitude * Math.cos(angle) + val newY = magnitude * Math.sin(angle) + return Vector2(newX, newY) } /** @@ -565,10 +561,9 @@ class Vector2 { * Sets the [Vector2] to the zero [Vector2] * @return [Vector2] this vector */ - fun zero(): Vector2 { + fun zero() { this.x = 0.0 this.y = 0.0 - return this } /** @@ -616,9 +611,9 @@ class Vector2 { */ fun right(): Vector2 { val temp = this.x - this.x = -this.y - this.y = temp - return this + val newX = -this.y + val newY = temp + return Vector2(newX, newY) } /** @@ -636,9 +631,9 @@ class Vector2 { */ fun left(): Vector2 { val temp = this.x - this.x = this.y - this.y = -temp - return this + val newX = this.y + val newY = -temp + return Vector2(newX, newY) } /**