From 12876a5ce23618040567b9bbfeb06d8556f57ee2 Mon Sep 17 00:00:00 2001 From: Song Minjae Date: Thu, 5 May 2016 17:11:01 +0900 Subject: [PATCH] corrected lighting bug where illuminant in front of the sun can take over the light level of the sun for a tile the illuminant occupies, ActorWithBody phys WIP Former-commit-id: a1ce45eded6136464d0a2c02227c61ee8f2adcb2 Former-commit-id: e4af5a44eb79b4db85458c9233e43a6117797331 --- .../black_body_col_1000_40000_K.png | Bin .../{ => colourmap}/black_body_how_to_use.txt | 0 .../{ => colourmap}/col12spectrum.png | Bin .../{ => colourmap}/col216spectrum.png | Bin res/graphics/{ => colourmap}/colourkey12.png | Bin res/graphics/{ => colourmap}/colourkey216.png | Bin .../health_bar_colouring_4096.png | Bin res/graphics/{ => colourmap}/sky_colour.png | Bin 16986 -> 19578 bytes src/net/torvald/terrarum/ENVIRON.md | 15 ++ src/net/torvald/terrarum/Game.kt | 2 +- src/net/torvald/terrarum/gameactors/AVKey.kt | 1 + .../terrarum/gameactors/ActorWithBody.kt | 162 ++++++++++-------- src/net/torvald/terrarum/gameactors/Player.kt | 154 ++++++++--------- .../physicssolver/CollisionSolver.kt | 4 +- src/net/torvald/terrarum/gamemap/GameMap.kt | 2 +- .../terrarum/mapdrawer/LightmapRenderer.kt | 3 +- .../torvald/terrarum/mapdrawer/MapDrawer.kt | 4 +- src/org/dyn4j/geometry/ChainedVector2.kt | 20 +-- work_files/graphics/colourmap/.gitattributes | 1 + 19 files changed, 205 insertions(+), 163 deletions(-) rename res/graphics/{ => colourmap}/black_body_col_1000_40000_K.png (100%) rename res/graphics/{ => colourmap}/black_body_how_to_use.txt (100%) rename res/graphics/{ => colourmap}/col12spectrum.png (100%) rename res/graphics/{ => colourmap}/col216spectrum.png (100%) rename res/graphics/{ => colourmap}/colourkey12.png (100%) rename res/graphics/{ => colourmap}/colourkey216.png (100%) rename res/graphics/{ => colourmap}/health_bar_colouring_4096.png (100%) rename res/graphics/{ => colourmap}/sky_colour.png (70%) create mode 100644 src/net/torvald/terrarum/ENVIRON.md create mode 100644 work_files/graphics/colourmap/.gitattributes diff --git a/res/graphics/black_body_col_1000_40000_K.png b/res/graphics/colourmap/black_body_col_1000_40000_K.png similarity index 100% rename from res/graphics/black_body_col_1000_40000_K.png rename to res/graphics/colourmap/black_body_col_1000_40000_K.png diff --git a/res/graphics/black_body_how_to_use.txt b/res/graphics/colourmap/black_body_how_to_use.txt similarity index 100% rename from res/graphics/black_body_how_to_use.txt rename to res/graphics/colourmap/black_body_how_to_use.txt diff --git a/res/graphics/col12spectrum.png b/res/graphics/colourmap/col12spectrum.png similarity index 100% rename from res/graphics/col12spectrum.png rename to res/graphics/colourmap/col12spectrum.png diff --git a/res/graphics/col216spectrum.png b/res/graphics/colourmap/col216spectrum.png similarity index 100% rename from res/graphics/col216spectrum.png rename to res/graphics/colourmap/col216spectrum.png diff --git a/res/graphics/colourkey12.png b/res/graphics/colourmap/colourkey12.png similarity index 100% rename from res/graphics/colourkey12.png rename to res/graphics/colourmap/colourkey12.png diff --git a/res/graphics/colourkey216.png b/res/graphics/colourmap/colourkey216.png similarity index 100% rename from res/graphics/colourkey216.png rename to res/graphics/colourmap/colourkey216.png diff --git a/res/graphics/health_bar_colouring_4096.png b/res/graphics/colourmap/health_bar_colouring_4096.png similarity index 100% rename from res/graphics/health_bar_colouring_4096.png rename to res/graphics/colourmap/health_bar_colouring_4096.png diff --git a/res/graphics/sky_colour.png b/res/graphics/colourmap/sky_colour.png similarity index 70% rename from res/graphics/sky_colour.png rename to res/graphics/colourmap/sky_colour.png index 57fb26e8866026cf6bfa6badb43b73783a1990f2..995a57d0bc62edf331656a13fa5e78223464557e 100644 GIT binary patch delta 5219 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 v_Mq+JA3 1) { - println("[ActorWithBody] Elasticity were capped to 1.") + else if (value >= ELASTICITY_MAX) { + println("[ActorWithBody] Elasticity were capped to $ELASTICITY_MAX.") field = ELASTICITY_MAX } else field = value * ELASTICITY_MAX } - @Transient private val ELASTICITY_MAX = 0.993 + @Transient private val ELASTICITY_MAX = 0.993 // No perpetual motion! private var density = 1000.0 /** @@ -119,7 +119,15 @@ 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 DRAG_COEFF = 1.0 + @Transient val DRAG_COEFF_DEFAULT = 1.2 + /** Drag coeffisient. Parachutes have much higher value than bare body (1.2) */ + private var DRAG_COEFF: Double + get() = actorValue.getAsDouble(AVKey.DRAGCOEFF) ?: DRAG_COEFF_DEFAULT + set(value) { + if (value < 0) + throw IllegalArgumentException("[ActorWithBody] drag coefficient cannot be negative.") + actorValue[AVKey.DRAGCOEFF] = value + } @Transient private val CONTACT_AREA_TOP = 0 @Transient private val CONTACT_AREA_RIGHT = 1 @@ -158,7 +166,7 @@ open class ActorWithBody constructor() : Actor(), Visible { @Transient private var posAdjustX = 0 @Transient private var posAdjustY = 0 - @Transient private val BASE_FRICTION = 0.3 + @Transient internal val BASE_FRICTION = 0.3 @Transient val KINEMATIC = 1 @Transient val DYNAMIC = 2 @@ -168,6 +176,10 @@ 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 { } @@ -230,9 +242,6 @@ open class ActorWithBody constructor() : Actor(), Visible { baseSpriteWidth = sprite!!.width } - // copy gravitational constant from the map the actor is in - gravitation = map.gravitation - /** * Actual physics thing (altering velocity) starts from here */ @@ -242,6 +251,8 @@ 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 @@ -290,18 +301,19 @@ open class ActorWithBody constructor() : Actor(), Visible { * W = mass * G (9.8 [m/s^2]) */ val W: Vector2 = gravitation * mass + /** + * Area + */ + val A: Double = scale * scale /** * Drag of atmosphere * D = Cd (drag coefficient) * 0.5 * rho (density) * V^2 (velocity) * A (area) */ - // TODO replace 1.292 with fluid tile density - val A: Double = scale * scale - val D: Vector2 = velocity.copy().toVector() * DRAG_COEFF * 0.5 * 1.292 * A + val D: Vector2 = (gravityDelta + movementDelta) * DRAG_COEFF * 0.5 * A * tileDensityFluid.toDouble() - //veloY += (W - D) / mass * SI_TO_GAME_ACC val V: Vector2 = (W - D) / mass * SI_TO_GAME_ACC - veloX += V.x - veloY += V.y + + gravityDelta += V } } @@ -335,12 +347,14 @@ 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 - elasticReflectY() + 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 - elasticReflectY() + gravityDelta.zero() + hitAndReflectY() grounded = true } else { // the actor is not grounded at all @@ -352,11 +366,11 @@ open class ActorWithBody constructor() : Actor(), Visible { if (isColliding(CONTACT_AREA_TOP)) { // the ceiling has dug into the body adjustHitTop() veloY = 0.0 // reset veloY, simulating normal force - elasticReflectY() + hitAndReflectY() } 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 + hitAndReflectY() // reflect on ceiling, for reversed gravity } else { // the actor is not grounded at all } @@ -409,12 +423,12 @@ open class ActorWithBody constructor() : Actor(), Visible { // the actor is embedded to the wall adjustHitRight() veloX = 0.0 // reset veloX, simulating normal force - elasticReflectX() + hitAndReflectX() } 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() + hitAndReflectX() } else { } @@ -425,12 +439,12 @@ open class ActorWithBody constructor() : Actor(), Visible { // the actor is embedded to the wall adjustHitLeft() veloX = 0.0 // reset veloX, simulating normal force - elasticReflectX() + hitAndReflectX() } 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() + hitAndReflectX() } else { } @@ -503,14 +517,10 @@ open class ActorWithBody constructor() : Actor(), Visible { if (!isNoCollideWorld) { // 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 (isColliding(CONTACT_AREA_BOTTOM, 0, 1)) { // the actor is standing ON the ground - veloY = 0.0 // reset veloY, simulating normal force - elasticReflectY() + if (isColliding(CONTACT_AREA_BOTTOM) || isColliding(CONTACT_AREA_BOTTOM, 0, 1)) { + // the actor is hitting the ground + //veloY = 0.0 // reset veloY, simulating normal force + hitAndReflectY() grounded = true } else { // the actor is not grounded at all @@ -519,43 +529,32 @@ open class ActorWithBody constructor() : Actor(), Visible { } 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 + if (isColliding(CONTACT_AREA_TOP) || isColliding(CONTACT_AREA_TOP, 0, -1)) { + // the actor is hitting the ceiling + //veloY = 0.0 // reset veloY, simulating normal force + hitAndReflectY() } else { // the actor is not grounded at all } } // 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 (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() + if ((isColliding(CONTACT_AREA_RIGHT) && !isColliding(CONTACT_AREA_LEFT)) + || (isColliding(CONTACT_AREA_RIGHT, 1, 0) && !isColliding(CONTACT_AREA_LEFT, 0, -1))) { + // the actor is hitting the right wall + //veloX = 0.0 // reset veloX, simulating normal force + hitAndReflectX() } 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() + if ((isColliding(CONTACT_AREA_LEFT) && !isColliding(CONTACT_AREA_RIGHT)) + || (isColliding(CONTACT_AREA_LEFT, -1, 0) && !isColliding(CONTACT_AREA_RIGHT, 1, 0))) { + // the actor is hitting the left wall + //veloX = 0.0 // reset veloX, simulating normal force + hitAndReflectX() } else { } @@ -565,17 +564,22 @@ open class ActorWithBody constructor() : Actor(), Visible { } } - private fun elasticReflectX() { - if (veloX != 0.0 && (veloX * elasticity).abs() > 0.5) { + private fun hitAndReflectX() { + if ((veloX * elasticity).abs() > SLEEP_THRE) { veloX = -veloX * elasticity - + } + else { + veloX = 0.0 } } - private fun elasticReflectY() { - if (veloY != 0.0 && (veloY * elasticity).abs() > 0.5) { + private fun hitAndReflectY() { + if ((veloY * elasticity).abs() > SLEEP_THRE) { veloY = -veloY * elasticity } + else { + veloY = 0.0 + } } private fun isColliding(side: Int, tx: Int = 0, ty: Int = 0): Boolean = getContactingArea(side, tx, ty) > 1 @@ -689,11 +693,11 @@ open class ActorWithBody constructor() : Actor(), Visible { * Get highest friction value from feet tiles. * @return */ - private val tileFriction: Int + internal val tileFriction: Int get() { var friction = 0 - //get highest friction + // take highest value val tilePosXStart = (hitbox.posX / TSIZE).roundToInt() val tilePosXEnd = (hitbox.hitboxEnd.x / TSIZE).roundToInt() val tilePosY = (hitbox.pointedY.plus(1) / TSIZE).roundToInt() @@ -708,6 +712,30 @@ open class ActorWithBody constructor() : Actor(), Visible { } fun Int.tileFrictionToMult() = this / 16.0 + /** + * Get highest tile density from occupying tiles, fluid only + */ + private val tileDensityFluid: Int + get() { + var density = 0 + + // take highest value + val tilePosXStart = (hitbox.posX / TSIZE).roundToInt() + val tilePosXEnd = (hitbox.hitboxEnd.x / TSIZE).roundToInt() + val tilePosYStart = (hitbox.posY / TSIZE).roundToInt() + val tilePosYEnd = (hitbox.hitboxEnd.y / TSIZE).roundToInt() + for (y in tilePosXStart..tilePosYEnd) { + for (x in tilePosXStart..tilePosXEnd) { + val tile = map.getTileFromTerrain(x, y) + val prop = TilePropCodex.getProp(tile) + + if (prop.isFluid && prop.density > density) + density = prop.density + } + } + return density + } + /** * Get highest density (specific gravity) value from tiles that the body occupies. * @return diff --git a/src/net/torvald/terrarum/gameactors/Player.kt b/src/net/torvald/terrarum/gameactors/Player.kt index 73da15585..19e0e916e 100644 --- a/src/net/torvald/terrarum/gameactors/Player.kt +++ b/src/net/torvald/terrarum/gameactors/Player.kt @@ -6,6 +6,8 @@ import net.torvald.terrarum.gamecontroller.KeyMap import net.torvald.terrarum.mapdrawer.MapDrawer import net.torvald.terrarum.Terrarum import net.torvald.spriteanimation.SpriteAnimation +import org.dyn4j.geometry.ChainedVector2 +import org.dyn4j.geometry.Vector2 import org.lwjgl.input.Controller import org.lwjgl.input.Controllers import org.newdawn.slick.GameContainer @@ -33,8 +35,10 @@ class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, Lan var vehicleRiding: Controllable? = null + /** how long the jump button has down, in frames */ internal var jumpCounter = 0 - internal var walkPowerCounter = 0 + /** how long the walk button has down, in frames */ + internal var walkCounter = 0 @Transient private val MAX_JUMP_LENGTH = 17 // use 17; in internal frames private var readonly_totalX = 0.0 @@ -115,30 +119,38 @@ class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, Lan * @param absAxisVal (set AXIS_POSMAX if keyboard controlled) */ private fun walkHorizontal(left: Boolean, absAxisVal: Float) { - readonly_totalX = veloX + - actorValue.getAsDouble(AVKey.ACCEL)!! * + readonly_totalX = //veloX + + /*actorValue.getAsDouble(AVKey.ACCEL)!! * actorValue.getAsDouble(AVKey.ACCELMULT)!! * Math.sqrt(scale) * applyAccelRealism(walkPowerCounter) * (if (left) -1 else 1).toFloat() * - absAxisVal + absAxisVal*/ + actorValue.getAsDouble(AVKey.ACCEL)!! * + actorValue.getAsDouble(AVKey.ACCELMULT)!! * + Math.sqrt(scale) * + applyVelo(walkCounter) * + (if (left) -1 else 1).toFloat() * + absAxisVal - veloX = readonly_totalX + // veloX = readonly_totalX + movementDelta += Vector2(readonly_totalX, 0.0) - if (walkPowerCounter < WALK_FRAMES_TO_MAX_ACCEL) { - walkPowerCounter += 1 - } + walkCounter += 1 // Clamp veloX - veloX = absClamp(veloX, actorValue.getAsDouble(AVKey.SPEED)!! - * actorValue.getAsDouble(AVKey.SPEEDMULT)!! - * Math.sqrt(scale)) + 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}") } /** @@ -148,51 +160,35 @@ class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, Lan * @param absAxisVal (set AXIS_POSMAX if keyboard controlled) */ private fun walkVertical(up: Boolean, absAxisVal: Float) { - readonly_totalY = veloY + + readonly_totalY = actorValue.getAsDouble(AVKey.ACCEL)!! * - actorValue.getAsDouble(AVKey.ACCELMULT)!! * - Math.sqrt(scale) * - applyAccelRealism(walkPowerCounter) * - (if (up) -1 else 1).toFloat() * - absAxisVal + actorValue.getAsDouble(AVKey.ACCELMULT)!! * + Math.sqrt(scale) * + applyVelo(walkCounter) * + (if (up) -1 else 1).toFloat() * + absAxisVal - veloY = readonly_totalY + movementDelta.set(Vector2(0.0, readonly_totalY)) - if (walkPowerCounter < WALK_FRAMES_TO_MAX_ACCEL) { - walkPowerCounter += 1 - } + if (walkCounter <= WALK_FRAMES_TO_MAX_ACCEL) walkCounter += 1 // Clamp veloX - veloY = absClamp(veloY, actorValue.getAsDouble(AVKey.SPEED)!! - * actorValue.getAsDouble(AVKey.SPEEDMULT)!! - * Math.sqrt(scale)) + movementDelta.y = absClamp(movementDelta.y, + actorValue.getAsDouble(AVKey.SPEED)!! * + actorValue.getAsDouble(AVKey.SPEEDMULT)!! * + Math.sqrt(scale)) } - /** - * For realistic accelerating while walking. + private fun applyAccel(x: Int): Double { + return if (x < WALK_FRAMES_TO_MAX_ACCEL) + Math.sin(Math.PI * x / WALK_FRAMES_TO_MAX_ACCEL) + else 0.0 + } - * Naïve 'veloX += 3' is actually like: - - * a - * | ------------ - * | - * | - * 0+------············ t - - * which is unrealistic, so this method tries to introduce some realism by doing: - - * a - * | ------------ - * | --- - * | - - * | --- - * 0+----··················· t - - - * @param x - */ - private fun applyAccelRealism(x: Int): Double { - return 0.5 + 0.5 * -Math.cos(10 * x / (WALK_FRAMES_TO_MAX_ACCEL * Math.PI)) + private fun applyVelo(x: Int): Double { + return if (x < WALK_FRAMES_TO_MAX_ACCEL) + 0.5 - 0.5 * Math.cos(Math.PI * x / WALK_FRAMES_TO_MAX_ACCEL) + else 1.0 } // stops; let the friction kick in by doing nothing to the velocity here @@ -217,7 +213,8 @@ class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, Lan //veloX = 0f - walkPowerCounter = 0 + walkCounter = 0 + movementDelta.zero() } // stops; let the friction kick in by doing nothing to the velocity here @@ -243,7 +240,36 @@ class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, Lan ///veloY = 0f - walkPowerCounter = 0 + walkCounter = 0 + movementDelta.zero() + } + + /** + * See ./work_files/Jump\ power\ by\ pressing\ time.gcx + */ + private fun jump() { + if (jumping) { + val len = MAX_JUMP_LENGTH.toFloat() + val pwr = actorValue.getAsDouble(AVKey.JUMPPOWER)!! * (actorValue.getAsDouble(AVKey.JUMPPOWERMULT) ?: 1.0) + + // increment jump counter + if (jumpCounter < len) jumpCounter += 1 + + // linear time mode + val init = (len + 1) / 2.0 + var timedJumpCharge = init - init / len * jumpCounter + if (timedJumpCharge < 0) timedJumpCharge = 0.0 + + val jumpAcc = pwr * timedJumpCharge * JUMP_ACCELERATION_MOD * Math.sqrt(scale) + + movementDelta.y -= jumpAcc + } + + // for mob ai: + //super.setVeloY(veloY + // - + // pwr * Math.sqrt(scale) + //); } private fun updateMovementControl() { @@ -391,34 +417,6 @@ class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, Lan } - /** - * See ./work_files/Jump\ power\ by\ pressing\ time.gcx - */ - private fun jump() { - if (jumping) { - val len = MAX_JUMP_LENGTH.toFloat() - val pwr = actorValue.getAsDouble(AVKey.JUMPPOWER)!! * (actorValue.getAsDouble(AVKey.JUMPPOWERMULT) ?: 1.0) - - // increment jump counter - if (jumpCounter < len) jumpCounter += 1 - - // linear time mode - val init = (len + 1) / 2.0 - var timedJumpCharge = init - init / len * jumpCounter - if (timedJumpCharge < 0) timedJumpCharge = 0.0 - - val jumpAcc = pwr * timedJumpCharge * JUMP_ACCELERATION_MOD * Math.sqrt(scale) - - veloY -= jumpAcc - } - - // for mob ai: - //super.setVeloY(veloY - // - - // pwr * Math.sqrt(scale) - //); - } - private fun isFuncDown(input: Input, fn: EnumKeyFunc): Boolean { return input.isKeyDown(KeyMap.getKeyCode(fn)) } diff --git a/src/net/torvald/terrarum/gameactors/physicssolver/CollisionSolver.kt b/src/net/torvald/terrarum/gameactors/physicssolver/CollisionSolver.kt index c5baccbba..fa0002e62 100644 --- a/src/net/torvald/terrarum/gameactors/physicssolver/CollisionSolver.kt +++ b/src/net/torvald/terrarum/gameactors/physicssolver/CollisionSolver.kt @@ -127,10 +127,10 @@ object CollisionSolver { val vy_1 = (uy_2 * (m1 - m2) + 2 * m2 * uy_2) / (m1 + m2) val vy_2 = (uy_2 * (m2 - m1) + 2 * m1 * uy_1) / (m1 + m2) - a.veloX = vx_1 + /*a.veloX = vx_1 a.veloY = vy_1 b.veloX = vx_2 - b.veloY = vy_2 + b.veloY = vy_2*/ } } } diff --git a/src/net/torvald/terrarum/gamemap/GameMap.kt b/src/net/torvald/terrarum/gamemap/GameMap.kt index bca168cd6..236c439b2 100644 --- a/src/net/torvald/terrarum/gamemap/GameMap.kt +++ b/src/net/torvald/terrarum/gamemap/GameMap.kt @@ -32,7 +32,7 @@ constructor(//properties //public World physWorld = new World( new Vec2(0, -TerrarumMain.game.gravitationalAccel) ); //physics - /** \[m / s^2\] */ + /** Meter per second squared. Currently only the downward gravity is supported. No reverse gravity :p */ var gravitation: Vector2 = Vector2(0.0, 9.8) /** RGB in Integer */ var globalLight: Int = 0 diff --git a/src/net/torvald/terrarum/mapdrawer/LightmapRenderer.kt b/src/net/torvald/terrarum/mapdrawer/LightmapRenderer.kt index a64475215..972b65a3d 100644 --- a/src/net/torvald/terrarum/mapdrawer/LightmapRenderer.kt +++ b/src/net/torvald/terrarum/mapdrawer/LightmapRenderer.kt @@ -229,8 +229,7 @@ object LightmapRenderer { } // luminous tile on top of air else if (thisWall == AIR && thisTileLuminosity.toInt() > 0) { - val darkenSunlight = darkenColoured(sunLight, thisTileOpacity) - lightLevelThis = maximiseRGB(darkenSunlight, thisTileLuminosity) // maximise to not exceed 1.0 with normal (<= 1.0) light + lightLevelThis = maximiseRGB(sunLight, thisTileLuminosity) // maximise to not exceed 1.0 with normal (<= 1.0) light } // opaque wall and luminous tile else if (thisWall != AIR && thisTileLuminosity.toInt() > 0) { diff --git a/src/net/torvald/terrarum/mapdrawer/MapDrawer.kt b/src/net/torvald/terrarum/mapdrawer/MapDrawer.kt index 071950cef..96ef3cae6 100644 --- a/src/net/torvald/terrarum/mapdrawer/MapDrawer.kt +++ b/src/net/torvald/terrarum/mapdrawer/MapDrawer.kt @@ -13,12 +13,12 @@ import org.newdawn.slick.* object MapDrawer { const val TILE_SIZE = 16 - private var envOverlayColourmap: Image = Image("./res/graphics/black_body_col_1000_40000_K.png") + private var envOverlayColourmap: Image = Image("./res/graphics/colourmap/black_body_col_1000_40000_K.png") private val ENV_COLTEMP_LOWEST = 5500 private val ENV_COLTEMP_HIGHEST = 7500 - val ENV_COLTEMP_NOON = 6500 + val ENV_COLTEMP_NOON = 6500 // 6500 == sRGB White == untouched! private var colTemp: Int = 0 diff --git a/src/org/dyn4j/geometry/ChainedVector2.kt b/src/org/dyn4j/geometry/ChainedVector2.kt index 4957e64ac..550d41ba3 100644 --- a/src/org/dyn4j/geometry/ChainedVector2.kt +++ b/src/org/dyn4j/geometry/ChainedVector2.kt @@ -378,7 +378,7 @@ class ChainedVector2 { * * * @return [ChainedVector2] this vector */ - operator fun plus(vector: ChainedVector2): ChainedVector2 { + fun plus(vector: ChainedVector2): ChainedVector2 { this.x += vector.x this.y += vector.y return this @@ -428,7 +428,7 @@ class ChainedVector2 { * * * @return [ChainedVector2] this vector */ - operator fun minus(vector: ChainedVector2): ChainedVector2 { + fun minus(vector: ChainedVector2): ChainedVector2 { this.x -= vector.x this.y -= vector.y return this @@ -500,7 +500,7 @@ class ChainedVector2 { * * * @return [ChainedVector2] this vector */ - operator fun times(scalar: Double): ChainedVector2 { + fun times(scalar: Double): ChainedVector2 { this.x *= scalar this.y *= scalar return this @@ -512,7 +512,7 @@ class ChainedVector2 { * * * @return [ChainedVector2] this vector */ - operator fun div(scalar: Double): ChainedVector2 { + fun div(scalar: Double): ChainedVector2 { this.x /= scalar this.y /= scalar return this @@ -525,7 +525,7 @@ class ChainedVector2 { * * * @return [ChainedVector2] */ - infix fun product(scalar: Double): ChainedVector2 { + fun product(scalar: Double): ChainedVector2 { return ChainedVector2(this.x * scalar, this.y * scalar) } @@ -536,7 +536,7 @@ class ChainedVector2 { * * * @return double */ - infix fun dot(vector: ChainedVector2): Double { + fun dot(vector: ChainedVector2): Double { return this.x * vector.x + this.y * vector.y } @@ -559,7 +559,7 @@ class ChainedVector2 { * * * @return double */ - infix fun cross(vector: ChainedVector2): Double { + fun cross(vector: ChainedVector2): Double { return this.x * vector.y - this.y * vector.x } @@ -581,7 +581,7 @@ class ChainedVector2 { * * * @return [ChainedVector2] */ - infix fun cross(z: Double): ChainedVector2 { + fun cross(z: Double): ChainedVector2 { return ChainedVector2(-1.0 * this.y * z, this.x * z) } @@ -628,7 +628,7 @@ class ChainedVector2 { * Negates this [ChainedVector2]. * @return [ChainedVector2] this vector */ - operator fun not() = negate() + fun not() = negate() /** * Negates this [ChainedVector2]. @@ -663,7 +663,7 @@ class ChainedVector2 { * * * @return [ChainedVector2] this vector */ - infix fun rotate(theta: Double): ChainedVector2 { + fun rotate(theta: Double): ChainedVector2 { val cos = Math.cos(theta) val sin = Math.sin(theta) val x = this.x diff --git a/work_files/graphics/colourmap/.gitattributes b/work_files/graphics/colourmap/.gitattributes new file mode 100644 index 000000000..ca82ef549 --- /dev/null +++ b/work_files/graphics/colourmap/.gitattributes @@ -0,0 +1 @@ +*.{psd,tga,ogg} filter=lfs diff=lfs merge=lfs -text \ No newline at end of file