From 127e6344cf70b7ae825207bb0d7a6c84717f70cc Mon Sep 17 00:00:00 2001 From: Song Minjae Date: Sun, 8 May 2016 01:29:52 +0900 Subject: [PATCH] player now walks again, still stick to wall if key is kept down, but gravity is no longer accumulated (because the walking velocity is now separated) Former-commit-id: f9394abe6230a4e60f2f7a42e81f7e85264a60c5 Former-commit-id: 1cd5b78c5800aef082d5eeec13a0a0a50ccea35b --- src/net/torvald/terrarum/Game.kt | 44 ++++++----- .../terrarum/gameactors/ActorWithBody.kt | 76 +++++++++++++------ src/net/torvald/terrarum/gameactors/Player.kt | 27 ++----- .../terrarum/ui/BasicDebugInfoWindow.kt | 4 +- src/org/dyn4j/geometry/Vector2.kt | 8 +- 5 files changed, 94 insertions(+), 65 deletions(-) diff --git a/src/net/torvald/terrarum/Game.kt b/src/net/torvald/terrarum/Game.kt index 80120abd2..bb28169ef 100644 --- a/src/net/torvald/terrarum/Game.kt +++ b/src/net/torvald/terrarum/Game.kt @@ -52,7 +52,7 @@ constructor() : BasicGameState() { lateinit var consoleHandler: UIHandler lateinit var debugWindow: UIHandler - lateinit var notifinator: UIHandler + lateinit var notifier: UIHandler lateinit internal var player: Player @@ -123,10 +123,10 @@ constructor() : BasicGameState() { debugWindow = UIHandler(BasicDebugInfoWindow()) debugWindow.setPosition(0, 0) - notifinator = UIHandler(Notification()) - notifinator.setPosition( - (Terrarum.WIDTH - notifinator.UI.width) / 2, Terrarum.HEIGHT - notifinator.UI.height) - notifinator.setVisibility(true) + notifier = UIHandler(Notification()) + notifier.setPosition( + (Terrarum.WIDTH - notifier.UI.width) / 2, Terrarum.HEIGHT - notifier.UI.height) + notifier.setVisibility(true) if (Terrarum.gameConfig.getAsBoolean("smoothlighting") == true) KeyToggler.forceSet(KEY_LIGHTMAP_SMOOTH, true) @@ -164,7 +164,7 @@ constructor() : BasicGameState() { debugWindow.update(gc, delta) - notifinator.update(gc, delta) + notifier.update(gc, delta) Terrarum.appgc.setVSync(Terrarum.appgc.fps >= Terrarum.VSYNC_TRIGGER_THRESHOLD) } @@ -250,7 +250,7 @@ constructor() : BasicGameState() { uiContainer.forEach { ui -> ui.render(gc, g) } debugWindow.render(gc, g) consoleHandler.render(gc, g) - notifinator.render(gc, g) + notifier.render(gc, g) } private fun getGradientColour(row: Int): Color { @@ -311,20 +311,21 @@ constructor() : BasicGameState() { g.fill(skyBox, skyColourFill) } + /** Send message to notifier UI and toggle the UI as opened. */ fun sendNotification(msg: Array) { - (notifinator.UI as Notification).sendNotification(Terrarum.appgc, update_delta, msg) - notifinator.setAsOpening() + (notifier.UI as Notification).sendNotification(Terrarum.appgc, update_delta, msg) + notifier.setAsOpening() } fun wakeDormantActors() { - // determine whether the inactive actor should be re-active + // determine whether the dormant actor should be re-activated var actorContainerSize = actorContainerInactive.size var i = 0 while (i < actorContainerSize) { // loop thru actorContainerInactive val actor = actorContainerInactive[i] val actorIndex = i if (actor is Visible && actor.inUpdateRange()) { - addActor(actor) + addActor(actor) // duplicates are checked here actorContainerInactive.removeAt(actorIndex) actorContainerSize -= 1 i-- // array removed 1 elem, so also decrement counter by 1 @@ -336,14 +337,14 @@ constructor() : BasicGameState() { fun updateAndInactivateDistantActors(gc: GameContainer, delta: Int) { var actorContainerSize = actorContainer.size var i = 0 - // determine whether the actor should be active or dormant by its distance from the player - // will put dormant actors to list specifically for them + // determine whether the actor should be active or dormant by its distance from the player. + // If the actor must be dormant, the target actor will be put to the list specifically for them. // if the actor is not to be dormant, update it - while (i < actorContainerSize) { // loop thru actorContainer + while (i < actorContainerSize) { // loop through the actorContainer val actor = actorContainer[i] val actorIndex = i if (actor is Visible && !actor.inUpdateRange()) { - actorContainerInactive.add(actor) // duplicates are checked when the actor is re-activated + actorContainerInactive.add(actor) // naïve add; duplicates are checked when the actor is re-activated actorContainer.removeAt(actorIndex) actorContainerSize -= 1 i-- // array removed 1 elem, so also decrement counter by 1 @@ -359,6 +360,7 @@ constructor() : BasicGameState() { get() = getGradientColour(2).getRGB24().rgb24ExpandToRgb30() fun Color.getRGB24(): Int = (this.redByte shl 16) or (this.greenByte shl 8) or (this.blueByte) + /** Remap 8-bit value (0.0-1.0) to 10-bit value (0.0-4.0) by prepending two bits of zero for each R, G and B. */ fun Int.rgb24ExpandToRgb30(): Int = (this and 0xff) or (this and 0xff00).ushr(8).shl(10) or (this and 0xff0000).ushr(16).shl(20) @@ -382,11 +384,16 @@ constructor() : BasicGameState() { actorContainer.binarySearch(ID) >= 0 fun removeActor(actor: Actor) = removeActor(actor.referenceID) + /** + * get index of the actor and delete by the index. + * we can do this as the list is guaranteed to be sorted + * and only contains unique values. + * + * Any values behind the index will be automatically pushed to front. + * This is how remove function of [java.util.ArrayList] is defined. + */ fun removeActor(ID: Int) { if (ID == player.referenceID) throw RuntimeException("Attempted to remove player.") - // get index of the actor and delete by the index. - // we can do this as the list is guaranteed to be sorted - // and only contains unique values val indexToDelete = actorContainer.binarySearch(ID) if (indexToDelete >= 0) actorContainer.removeAt(indexToDelete) } @@ -418,7 +425,6 @@ constructor() : BasicGameState() { } private fun insertionSortLastElem(arr: ArrayList) { - // 'insertion sort' last element var x: Actor var j: Int var index: Int = arr.size - 1 diff --git a/src/net/torvald/terrarum/gameactors/ActorWithBody.kt b/src/net/torvald/terrarum/gameactors/ActorWithBody.kt index 6b3903f22..013d10363 100644 --- a/src/net/torvald/terrarum/gameactors/ActorWithBody.kt +++ b/src/net/torvald/terrarum/gameactors/ActorWithBody.kt @@ -35,13 +35,16 @@ open class ActorWithBody constructor() : Actor(), Visible { * veloY += 3.0 * +3.0 is acceleration. You __accumulate__ acceleration to the velocity. */ - internal val positioningDelta = Vector2(0.0, 0.0) + internal val velocity = Vector2(0.0, 0.0) var veloX: Double - get() = positioningDelta.x - private set(value) { positioningDelta.x = value } + get() = velocity.x + private set(value) { velocity.x = value } var veloY: Double - get() = positioningDelta.y - private set(value) { positioningDelta.y = value } + get() = velocity.y + private set(value) { velocity.y = value } + var walkX: Double = 0.0 + var walkY: Double = 0.0 + val moveDelta = Vector2(0.0, 0.0) @Transient private val VELO_HARD_LIMIT = 10000.0 var grounded = false @@ -118,7 +121,7 @@ open class ActorWithBody constructor() : Actor(), Visible { */ @Transient private val SI_TO_GAME_VEL = METER / Terrarum.TARGET_FPS - @Transient private var gravitation: Vector2 = map.gravitation + @Transient private val gravitation: Vector2 = map.gravitation @Transient val DRAG_COEFF_DEFAULT = 1.2 /** Drag coeffisient. Parachutes have much higher value than bare body (1.2) */ private var DRAG_COEFF: Double @@ -157,8 +160,8 @@ open class ActorWithBody constructor() : Actor(), Visible { @Transient private val MASS_DEFAULT: Double = 60.0 - internal val physSleep: Boolean - get() = veloX.abs() < 0.5 && veloY.abs() < 0.5 + internal var physSleep: Boolean = false + private set /** * for collide-to-world compensation @@ -176,10 +179,6 @@ open class ActorWithBody constructor() : Actor(), Visible { private val CCD_THRE = 1.0 private val CCD_TICK = 0.125 - val movementDelta = Vector2(0.0, 0.0) - val externalDelta = Vector2(0.0, 0.0) - private val gravityDelta = Vector2(0.0 , 0.0) - init { } @@ -226,6 +225,18 @@ open class ActorWithBody constructor() : Actor(), Visible { override fun run() = update(Terrarum.appgc, Terrarum.game.DELTA_T) + /** + * Add vector value to the velocity, in the time unit of single frame. + * + * Since we're adding some value every frame, the value is equivalent to the acceleration. + * Find about Newton's second law for the background knowledge. + * @param vec : Acceleration in Vector2 + */ + fun applyForce(vec: Vector2) { + velocity += vec + physSleep = false + } + override fun update(gc: GameContainer, delta_t: Int) { if (isUpdate) { @@ -251,12 +262,13 @@ open class ActorWithBody constructor() : Actor(), Visible { //applyBuoyancy() } - positioningDelta.set(movementDelta + externalDelta + gravityDelta) - // hard limit velocity if (veloX > VELO_HARD_LIMIT) veloX = VELO_HARD_LIMIT if (veloY > VELO_HARD_LIMIT) veloY = VELO_HARD_LIMIT + moveDelta.x = veloX + walkX + moveDelta.y = veloY + walkY + if (!physSleep) { // Set 'next' position (hitbox) to fiddle with setNewNextHitbox() @@ -309,16 +321,17 @@ open class ActorWithBody constructor() : Actor(), Visible { * Drag of atmosphere * D = Cd (drag coefficient) * 0.5 * rho (density) * V^2 (velocity) * A (area) */ - val D: Vector2 = (gravityDelta + movementDelta) * DRAG_COEFF * 0.5 * A * tileDensityFluid.toDouble() + val D: Vector2 = velocity * DRAG_COEFF * 0.5 * A * tileDensityFluid.toDouble() val V: Vector2 = (W - D) / mass * SI_TO_GAME_ACC - gravityDelta += V + applyForce(V) } } private fun setHorizontalFriction() { val friction = BASE_FRICTION * tileFriction.tileFrictionToMult() + if (veloX < 0) { veloX += friction if (veloX > 0) veloX = 0.0 // compensate overshoot @@ -327,18 +340,37 @@ open class ActorWithBody constructor() : Actor(), Visible { veloX -= friction if (veloX < 0) veloX = 0.0 // compensate overshoot } + + if (walkX < 0) { + walkX += friction + if (walkX > 0) walkX = 0.0 + } + else if (walkX > 0) { + walkX -= friction + if (walkX < 0) walkX = 0.0 + } } private fun setVerticalFriction() { val friction = BASE_FRICTION * tileFriction.tileFrictionToMult() + if (veloY < 0) { veloY += friction - if (veloY > 0) veloY = 0.0 // compensate overshoot + if (veloY > 0) veloX = 0.0 // compensate overshoot } else if (veloY > 0) { veloY -= friction if (veloY < 0) veloY = 0.0 // compensate overshoot } + + if (walkY < 0) { + walkY += friction + if (walkY > 0) walkY = 0.0 + } + else if (walkY > 0) { + walkY -= friction + if (walkY < 0) walkY = 0.0 + } } private fun updateVerticalCollision() { @@ -347,13 +379,11 @@ open class ActorWithBody constructor() : Actor(), Visible { if (isColliding(CONTACT_AREA_BOTTOM)) { // the ground has dug into the body adjustHitBottom() veloY = 0.0 // reset veloY, simulating normal force - gravityDelta.zero() hitAndReflectY() grounded = true } else if (isColliding(CONTACT_AREA_BOTTOM, 0, 1)) { // the actor is standing ON the ground veloY = 0.0 // reset veloY, simulating normal force - gravityDelta.zero() hitAndReflectY() grounded = true } @@ -566,7 +596,7 @@ open class ActorWithBody constructor() : Actor(), Visible { private fun hitAndReflectX() { if ((veloX * elasticity).abs() > SLEEP_THRE) { - veloX = -veloX * elasticity + veloX *= -elasticity } else { veloX = 0.0 @@ -575,7 +605,7 @@ open class ActorWithBody constructor() : Actor(), Visible { private fun hitAndReflectY() { if ((veloY * elasticity).abs() > SLEEP_THRE) { - veloY = -veloY * elasticity + veloY *= -elasticity } else { veloY = 0.0 @@ -774,8 +804,8 @@ open class ActorWithBody constructor() : Actor(), Visible { private fun setNewNextHitbox() { nextHitbox.set( - (hitbox.posX + veloX) - , (hitbox.posY + veloY) + (hitbox.posX + moveDelta.x) + , (hitbox.posY + moveDelta.y) , (baseHitboxW * scale) , (baseHitboxH * scale) ) diff --git a/src/net/torvald/terrarum/gameactors/Player.kt b/src/net/torvald/terrarum/gameactors/Player.kt index 19e0e916e..e9b956bf4 100644 --- a/src/net/torvald/terrarum/gameactors/Player.kt +++ b/src/net/torvald/terrarum/gameactors/Player.kt @@ -133,24 +133,19 @@ class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, Lan (if (left) -1 else 1).toFloat() * absAxisVal - // veloX = readonly_totalX - movementDelta += Vector2(readonly_totalX, 0.0) + //applyForce(Vector2(readonly_totalX, 0.0)) + walkX += readonly_totalX + walkX = absClamp(walkX, actorValue.getAsDouble(AVKey.SPEED)!! * actorValue.getAsDouble(AVKey.SPEEDMULT)!!) walkCounter += 1 - // Clamp veloX - movementDelta.x = absClamp(movementDelta.x, - actorValue.getAsDouble(AVKey.SPEED)!! - * actorValue.getAsDouble(AVKey.SPEEDMULT)!! - * Math.sqrt(scale)) - // Heading flag if (left) walkHeading = LEFT else walkHeading = RIGHT - println("$walkCounter: ${movementDelta.x}") + println("$walkCounter: ${readonly_totalX}") } /** @@ -168,15 +163,9 @@ class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, Lan (if (up) -1 else 1).toFloat() * absAxisVal - movementDelta.set(Vector2(0.0, readonly_totalY)) + applyForce(Vector2(0.0, readonly_totalY)) if (walkCounter <= WALK_FRAMES_TO_MAX_ACCEL) walkCounter += 1 - - // Clamp veloX - movementDelta.y = absClamp(movementDelta.y, - actorValue.getAsDouble(AVKey.SPEED)!! * - actorValue.getAsDouble(AVKey.SPEEDMULT)!! * - Math.sqrt(scale)) } private fun applyAccel(x: Int): Double { @@ -214,7 +203,6 @@ class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, Lan //veloX = 0f walkCounter = 0 - movementDelta.zero() } // stops; let the friction kick in by doing nothing to the velocity here @@ -241,7 +229,6 @@ class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, Lan ///veloY = 0f walkCounter = 0 - movementDelta.zero() } /** @@ -260,9 +247,9 @@ class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, Lan var timedJumpCharge = init - init / len * jumpCounter if (timedJumpCharge < 0) timedJumpCharge = 0.0 - val jumpAcc = pwr * timedJumpCharge * JUMP_ACCELERATION_MOD * Math.sqrt(scale) + val jumpAcc = pwr * timedJumpCharge * JUMP_ACCELERATION_MOD * Math.sqrt(scale) // positive value - movementDelta.y -= jumpAcc + applyForce(Vector2(0.0, -jumpAcc)) } // for mob ai: diff --git a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt index 00fd8cb48..4f9c9ac29 100644 --- a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt +++ b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt @@ -85,8 +85,8 @@ class BasicDebugInfoWindow:UICanvas { + (hitbox.pointedY / MapDrawer.TILE_SIZE).toInt().toString() + ")") - printLine(g, 3, "veloX reported $ccG${if (player.physSleep) "(sleep)" else player.veloX}") - printLine(g, 4, "veloY reported $ccG${if (player.physSleep) "(sleep)" else player.veloY}") + printLine(g, 3, "veloX reported $ccG${if (player.physSleep) "(sleep)" else player.moveDelta.x}") + printLine(g, 4, "veloY reported $ccG${if (player.physSleep) "(sleep)" else player.moveDelta.y}") printLineColumn(g, 2, 3, "veloX measured $ccG${xdelta}") printLineColumn(g, 2, 4, "veloY measured $ccG${ydelta}") diff --git a/src/org/dyn4j/geometry/Vector2.kt b/src/org/dyn4j/geometry/Vector2.kt index b79bf456c..d6b8cab85 100644 --- a/src/org/dyn4j/geometry/Vector2.kt +++ b/src/org/dyn4j/geometry/Vector2.kt @@ -542,12 +542,18 @@ class Vector2 { */ operator fun not() = negate() + /** + * Negates this [Vector2]. + * @return [Vector2] this vector + */ + operator fun unaryMinus() = negate() + /** * Negates this [Vector2]. * @return [Vector2] this vector */ fun negate(): Vector2 { - return Vector2(x * -1.0, y * -1.0) + return Vector2(-x, -y) } /**