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
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 441 B After Width: | Height: | Size: 441 B |
|
Before Width: | Height: | Size: 878 B After Width: | Height: | Size: 878 B |
|
Before Width: | Height: | Size: 305 B After Width: | Height: | Size: 305 B |
|
Before Width: | Height: | Size: 102 B After Width: | Height: | Size: 102 B |
|
Before Width: | Height: | Size: 902 B After Width: | Height: | Size: 902 B |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 19 KiB |
15
src/net/torvald/terrarum/ENVIRON.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
## Colour overlay ##
|
||||||
|
|
||||||
|
Colour overlay is set to 6 500 K as untouched. The value must be
|
||||||
|
|
||||||
|
* Increased when:
|
||||||
|
- Overcast (~ 7 000 K)
|
||||||
|
- Freezing area (~ 7 500 K)
|
||||||
|
|
||||||
|
* Decreased when:
|
||||||
|
- Tropical area (~ 5 500 K)
|
||||||
|
|
||||||
|
|
||||||
|
## Sunlight ##
|
||||||
|
|
||||||
|
Sunlight of the midday must have colour temperature of 5 700 K.
|
||||||
@@ -94,7 +94,7 @@ constructor() : BasicGameState() {
|
|||||||
shaderBlurV = Shader.makeShader("./res/blurV.vrt", "./res/blur.frg")
|
shaderBlurV = Shader.makeShader("./res/blurV.vrt", "./res/blur.frg")
|
||||||
|
|
||||||
|
|
||||||
GRADIENT_IMAGE = Image("res/graphics/sky_colour.png")
|
GRADIENT_IMAGE = Image("res/graphics/colourmap/sky_colour.png")
|
||||||
skyBox = Rectangle(0f, 0f, Terrarum.WIDTH.toFloat(), Terrarum.HEIGHT.toFloat())
|
skyBox = Rectangle(0f, 0f, Terrarum.WIDTH.toFloat(), Terrarum.HEIGHT.toFloat())
|
||||||
|
|
||||||
TilePropCodex()
|
TilePropCodex()
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ object AVKey {
|
|||||||
const val ENCUMBRANCE = "encumbrance"
|
const val ENCUMBRANCE = "encumbrance"
|
||||||
const val LUMINOSITY = "luminosity"
|
const val LUMINOSITY = "luminosity"
|
||||||
const val PHYSIQUEMULT = "physique$MULT"
|
const val PHYSIQUEMULT = "physique$MULT"
|
||||||
|
const val DRAGCOEFF = "dragcoeff"
|
||||||
|
|
||||||
const val NAME = "name"
|
const val NAME = "name"
|
||||||
|
|
||||||
|
|||||||
@@ -35,13 +35,13 @@ open class ActorWithBody constructor() : Actor(), Visible {
|
|||||||
* veloY += 3.0
|
* veloY += 3.0
|
||||||
* +3.0 is acceleration. You __accumulate__ acceleration to the velocity.
|
* +3.0 is acceleration. You __accumulate__ acceleration to the velocity.
|
||||||
*/
|
*/
|
||||||
val velocity = ChainedVector2(0.0, 0.0)
|
internal val positioningDelta = Vector2(0.0, 0.0)
|
||||||
var veloX: Double
|
var veloX: Double
|
||||||
get() = velocity.x
|
get() = positioningDelta.x
|
||||||
set(value) { velocity.x = value }
|
private set(value) { positioningDelta.x = value }
|
||||||
var veloY: Double
|
var veloY: Double
|
||||||
get() = velocity.y
|
get() = positioningDelta.y
|
||||||
set(value) { velocity.y = value }
|
private set(value) { positioningDelta.y = value }
|
||||||
@Transient private val VELO_HARD_LIMIT = 10000.0
|
@Transient private val VELO_HARD_LIMIT = 10000.0
|
||||||
|
|
||||||
var grounded = false
|
var grounded = false
|
||||||
@@ -92,14 +92,14 @@ open class ActorWithBody constructor() : Actor(), Visible {
|
|||||||
set(value) {
|
set(value) {
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
throw IllegalArgumentException("[ActorWithBody] Invalid elasticity value: $value; valid elasticity value is [0, 1].")
|
throw IllegalArgumentException("[ActorWithBody] Invalid elasticity value: $value; valid elasticity value is [0, 1].")
|
||||||
else if (value > 1) {
|
else if (value >= ELASTICITY_MAX) {
|
||||||
println("[ActorWithBody] Elasticity were capped to 1.")
|
println("[ActorWithBody] Elasticity were capped to $ELASTICITY_MAX.")
|
||||||
field = ELASTICITY_MAX
|
field = ELASTICITY_MAX
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
field = value * ELASTICITY_MAX
|
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
|
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 val SI_TO_GAME_VEL = METER / Terrarum.TARGET_FPS
|
||||||
|
|
||||||
@Transient private var gravitation: Vector2 = map.gravitation
|
@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_TOP = 0
|
||||||
@Transient private val CONTACT_AREA_RIGHT = 1
|
@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 posAdjustX = 0
|
||||||
@Transient private var posAdjustY = 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 KINEMATIC = 1
|
||||||
@Transient val DYNAMIC = 2
|
@Transient val DYNAMIC = 2
|
||||||
@@ -168,6 +176,10 @@ open class ActorWithBody constructor() : Actor(), Visible {
|
|||||||
private val CCD_THRE = 1.0
|
private val CCD_THRE = 1.0
|
||||||
private val CCD_TICK = 0.125
|
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 {
|
init {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -230,9 +242,6 @@ open class ActorWithBody constructor() : Actor(), Visible {
|
|||||||
baseSpriteWidth = sprite!!.width
|
baseSpriteWidth = sprite!!.width
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy gravitational constant from the map the actor is in
|
|
||||||
gravitation = map.gravitation
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actual physics thing (altering velocity) starts from here
|
* Actual physics thing (altering velocity) starts from here
|
||||||
*/
|
*/
|
||||||
@@ -242,6 +251,8 @@ open class ActorWithBody constructor() : Actor(), Visible {
|
|||||||
//applyBuoyancy()
|
//applyBuoyancy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
positioningDelta.set(movementDelta + externalDelta + gravityDelta)
|
||||||
|
|
||||||
// hard limit velocity
|
// hard limit velocity
|
||||||
if (veloX > VELO_HARD_LIMIT) veloX = VELO_HARD_LIMIT
|
if (veloX > VELO_HARD_LIMIT) veloX = VELO_HARD_LIMIT
|
||||||
if (veloY > VELO_HARD_LIMIT) veloY = 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])
|
* W = mass * G (9.8 [m/s^2])
|
||||||
*/
|
*/
|
||||||
val W: Vector2 = gravitation * mass
|
val W: Vector2 = gravitation * mass
|
||||||
|
/**
|
||||||
|
* Area
|
||||||
|
*/
|
||||||
|
val A: Double = scale * scale
|
||||||
/**
|
/**
|
||||||
* Drag of atmosphere
|
* Drag of atmosphere
|
||||||
* D = Cd (drag coefficient) * 0.5 * rho (density) * V^2 (velocity) * A (area)
|
* D = Cd (drag coefficient) * 0.5 * rho (density) * V^2 (velocity) * A (area)
|
||||||
*/
|
*/
|
||||||
// TODO replace 1.292 with fluid tile density
|
val D: Vector2 = (gravityDelta + movementDelta) * DRAG_COEFF * 0.5 * A * tileDensityFluid.toDouble()
|
||||||
val A: Double = scale * scale
|
|
||||||
val D: Vector2 = velocity.copy().toVector() * DRAG_COEFF * 0.5 * 1.292 * A
|
|
||||||
|
|
||||||
//veloY += (W - D) / mass * SI_TO_GAME_ACC
|
|
||||||
val V: Vector2 = (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
|
if (isColliding(CONTACT_AREA_BOTTOM)) { // the ground has dug into the body
|
||||||
adjustHitBottom()
|
adjustHitBottom()
|
||||||
veloY = 0.0 // reset veloY, simulating normal force
|
veloY = 0.0 // reset veloY, simulating normal force
|
||||||
elasticReflectY()
|
gravityDelta.zero()
|
||||||
|
hitAndReflectY()
|
||||||
grounded = true
|
grounded = true
|
||||||
}
|
}
|
||||||
else if (isColliding(CONTACT_AREA_BOTTOM, 0, 1)) { // the actor is standing ON the ground
|
else if (isColliding(CONTACT_AREA_BOTTOM, 0, 1)) { // the actor is standing ON the ground
|
||||||
veloY = 0.0 // reset veloY, simulating normal force
|
veloY = 0.0 // reset veloY, simulating normal force
|
||||||
elasticReflectY()
|
gravityDelta.zero()
|
||||||
|
hitAndReflectY()
|
||||||
grounded = true
|
grounded = true
|
||||||
}
|
}
|
||||||
else { // the actor is not grounded at all
|
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
|
if (isColliding(CONTACT_AREA_TOP)) { // the ceiling has dug into the body
|
||||||
adjustHitTop()
|
adjustHitTop()
|
||||||
veloY = 0.0 // reset veloY, simulating normal force
|
veloY = 0.0 // reset veloY, simulating normal force
|
||||||
elasticReflectY()
|
hitAndReflectY()
|
||||||
}
|
}
|
||||||
else if (isColliding(CONTACT_AREA_TOP, 0, -1)) { // the actor is touching the ceiling
|
else if (isColliding(CONTACT_AREA_TOP, 0, -1)) { // the actor is touching the ceiling
|
||||||
veloY = 0.0 // reset veloY, simulating normal force
|
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
|
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
|
// the actor is embedded to the wall
|
||||||
adjustHitRight()
|
adjustHitRight()
|
||||||
veloX = 0.0 // reset veloX, simulating normal force
|
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
|
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
|
// the actor is touching the wall
|
||||||
veloX = 0.0 // reset veloX, simulating normal force
|
veloX = 0.0 // reset veloX, simulating normal force
|
||||||
elasticReflectX()
|
hitAndReflectX()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
}
|
}
|
||||||
@@ -425,12 +439,12 @@ open class ActorWithBody constructor() : Actor(), Visible {
|
|||||||
// the actor is embedded to the wall
|
// the actor is embedded to the wall
|
||||||
adjustHitLeft()
|
adjustHitLeft()
|
||||||
veloX = 0.0 // reset veloX, simulating normal force
|
veloX = 0.0 // reset veloX, simulating normal force
|
||||||
elasticReflectX()
|
hitAndReflectX()
|
||||||
}
|
}
|
||||||
else if (isColliding(CONTACT_AREA_LEFT, -1, 0) && !isColliding(CONTACT_AREA_RIGHT, 1, 0)) {
|
else if (isColliding(CONTACT_AREA_LEFT, -1, 0) && !isColliding(CONTACT_AREA_RIGHT, 1, 0)) {
|
||||||
// the actor is touching the wall
|
// the actor is touching the wall
|
||||||
veloX = 0.0 // reset veloX, simulating normal force
|
veloX = 0.0 // reset veloX, simulating normal force
|
||||||
elasticReflectX()
|
hitAndReflectX()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
}
|
}
|
||||||
@@ -503,14 +517,10 @@ open class ActorWithBody constructor() : Actor(), Visible {
|
|||||||
if (!isNoCollideWorld) {
|
if (!isNoCollideWorld) {
|
||||||
// axis Y
|
// axis Y
|
||||||
if (veloY >= 0) { // check downward
|
if (veloY >= 0) { // check downward
|
||||||
if (isColliding(CONTACT_AREA_BOTTOM)) { // the ground has dug into the body
|
if (isColliding(CONTACT_AREA_BOTTOM) || isColliding(CONTACT_AREA_BOTTOM, 0, 1)) {
|
||||||
veloY = 0.0 // reset veloY, simulating normal force
|
// the actor is hitting the ground
|
||||||
elasticReflectY()
|
//veloY = 0.0 // reset veloY, simulating normal force
|
||||||
grounded = true
|
hitAndReflectY()
|
||||||
}
|
|
||||||
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
|
grounded = true
|
||||||
}
|
}
|
||||||
else { // the actor is not grounded at all
|
else { // the actor is not grounded at all
|
||||||
@@ -519,43 +529,32 @@ open class ActorWithBody constructor() : Actor(), Visible {
|
|||||||
}
|
}
|
||||||
else if (veloY < 0) { // check upward
|
else if (veloY < 0) { // check upward
|
||||||
grounded = false
|
grounded = false
|
||||||
if (isColliding(CONTACT_AREA_TOP)) { // the ceiling has dug into the body
|
if (isColliding(CONTACT_AREA_TOP) || isColliding(CONTACT_AREA_TOP, 0, -1)) {
|
||||||
veloY = 0.0 // reset veloY, simulating normal force
|
// the actor is hitting the ceiling
|
||||||
elasticReflectY()
|
//veloY = 0.0 // reset veloY, simulating normal force
|
||||||
}
|
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
|
|
||||||
}
|
}
|
||||||
else { // the actor is not grounded at all
|
else { // the actor is not grounded at all
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// axis X
|
// axis X
|
||||||
if (veloX >= 0.5) { // check right
|
if (veloX >= 0.5) { // check right
|
||||||
if (isColliding(CONTACT_AREA_RIGHT) && !isColliding(CONTACT_AREA_LEFT)) {
|
if ((isColliding(CONTACT_AREA_RIGHT) && !isColliding(CONTACT_AREA_LEFT))
|
||||||
// the actor is embedded to the wall
|
|| (isColliding(CONTACT_AREA_RIGHT, 1, 0) && !isColliding(CONTACT_AREA_LEFT, 0, -1))) {
|
||||||
veloX = 0.0 // reset veloX, simulating normal force
|
// the actor is hitting the right wall
|
||||||
elasticReflectX()
|
//veloX = 0.0 // reset veloX, simulating normal force
|
||||||
}
|
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()
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (veloX <= -0.5) { // check left
|
else if (veloX <= -0.5) { // check left
|
||||||
// System.out.println("collidingleft");
|
// System.out.println("collidingleft");
|
||||||
if (isColliding(CONTACT_AREA_LEFT) && !isColliding(CONTACT_AREA_RIGHT)) {
|
if ((isColliding(CONTACT_AREA_LEFT) && !isColliding(CONTACT_AREA_RIGHT))
|
||||||
// the actor is embedded to the wall
|
|| (isColliding(CONTACT_AREA_LEFT, -1, 0) && !isColliding(CONTACT_AREA_RIGHT, 1, 0))) {
|
||||||
veloX = 0.0 // reset veloX, simulating normal force
|
// the actor is hitting the left wall
|
||||||
elasticReflectX()
|
//veloX = 0.0 // reset veloX, simulating normal force
|
||||||
}
|
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()
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
}
|
}
|
||||||
@@ -565,17 +564,22 @@ open class ActorWithBody constructor() : Actor(), Visible {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun elasticReflectX() {
|
private fun hitAndReflectX() {
|
||||||
if (veloX != 0.0 && (veloX * elasticity).abs() > 0.5) {
|
if ((veloX * elasticity).abs() > SLEEP_THRE) {
|
||||||
veloX = -veloX * elasticity
|
veloX = -veloX * elasticity
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
veloX = 0.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun elasticReflectY() {
|
private fun hitAndReflectY() {
|
||||||
if (veloY != 0.0 && (veloY * elasticity).abs() > 0.5) {
|
if ((veloY * elasticity).abs() > SLEEP_THRE) {
|
||||||
veloY = -veloY * elasticity
|
veloY = -veloY * elasticity
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
veloY = 0.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isColliding(side: Int, tx: Int = 0, ty: Int = 0): Boolean = getContactingArea(side, tx, ty) > 1
|
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.
|
* Get highest friction value from feet tiles.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private val tileFriction: Int
|
internal val tileFriction: Int
|
||||||
get() {
|
get() {
|
||||||
var friction = 0
|
var friction = 0
|
||||||
|
|
||||||
//get highest friction
|
// take highest value
|
||||||
val tilePosXStart = (hitbox.posX / TSIZE).roundToInt()
|
val tilePosXStart = (hitbox.posX / TSIZE).roundToInt()
|
||||||
val tilePosXEnd = (hitbox.hitboxEnd.x / TSIZE).roundToInt()
|
val tilePosXEnd = (hitbox.hitboxEnd.x / TSIZE).roundToInt()
|
||||||
val tilePosY = (hitbox.pointedY.plus(1) / 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
|
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.
|
* Get highest density (specific gravity) value from tiles that the body occupies.
|
||||||
* @return
|
* @return
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import net.torvald.terrarum.gamecontroller.KeyMap
|
|||||||
import net.torvald.terrarum.mapdrawer.MapDrawer
|
import net.torvald.terrarum.mapdrawer.MapDrawer
|
||||||
import net.torvald.terrarum.Terrarum
|
import net.torvald.terrarum.Terrarum
|
||||||
import net.torvald.spriteanimation.SpriteAnimation
|
import net.torvald.spriteanimation.SpriteAnimation
|
||||||
|
import org.dyn4j.geometry.ChainedVector2
|
||||||
|
import org.dyn4j.geometry.Vector2
|
||||||
import org.lwjgl.input.Controller
|
import org.lwjgl.input.Controller
|
||||||
import org.lwjgl.input.Controllers
|
import org.lwjgl.input.Controllers
|
||||||
import org.newdawn.slick.GameContainer
|
import org.newdawn.slick.GameContainer
|
||||||
@@ -33,8 +35,10 @@ class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, Lan
|
|||||||
|
|
||||||
var vehicleRiding: Controllable? = null
|
var vehicleRiding: Controllable? = null
|
||||||
|
|
||||||
|
/** how long the jump button has down, in frames */
|
||||||
internal var jumpCounter = 0
|
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
|
@Transient private val MAX_JUMP_LENGTH = 17 // use 17; in internal frames
|
||||||
|
|
||||||
private var readonly_totalX = 0.0
|
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)
|
* @param absAxisVal (set AXIS_POSMAX if keyboard controlled)
|
||||||
*/
|
*/
|
||||||
private fun walkHorizontal(left: Boolean, absAxisVal: Float) {
|
private fun walkHorizontal(left: Boolean, absAxisVal: Float) {
|
||||||
readonly_totalX = veloX +
|
readonly_totalX = //veloX +
|
||||||
actorValue.getAsDouble(AVKey.ACCEL)!! *
|
/*actorValue.getAsDouble(AVKey.ACCEL)!! *
|
||||||
actorValue.getAsDouble(AVKey.ACCELMULT)!! *
|
actorValue.getAsDouble(AVKey.ACCELMULT)!! *
|
||||||
Math.sqrt(scale) *
|
Math.sqrt(scale) *
|
||||||
applyAccelRealism(walkPowerCounter) *
|
applyAccelRealism(walkPowerCounter) *
|
||||||
(if (left) -1 else 1).toFloat() *
|
(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) {
|
walkCounter += 1
|
||||||
walkPowerCounter += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clamp veloX
|
// Clamp veloX
|
||||||
veloX = absClamp(veloX, actorValue.getAsDouble(AVKey.SPEED)!!
|
movementDelta.x = absClamp(movementDelta.x,
|
||||||
* actorValue.getAsDouble(AVKey.SPEEDMULT)!!
|
actorValue.getAsDouble(AVKey.SPEED)!!
|
||||||
* Math.sqrt(scale))
|
* actorValue.getAsDouble(AVKey.SPEEDMULT)!!
|
||||||
|
* Math.sqrt(scale))
|
||||||
|
|
||||||
// Heading flag
|
// Heading flag
|
||||||
if (left)
|
if (left)
|
||||||
walkHeading = LEFT
|
walkHeading = LEFT
|
||||||
else
|
else
|
||||||
walkHeading = RIGHT
|
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)
|
* @param absAxisVal (set AXIS_POSMAX if keyboard controlled)
|
||||||
*/
|
*/
|
||||||
private fun walkVertical(up: Boolean, absAxisVal: Float) {
|
private fun walkVertical(up: Boolean, absAxisVal: Float) {
|
||||||
readonly_totalY = veloY +
|
readonly_totalY =
|
||||||
actorValue.getAsDouble(AVKey.ACCEL)!! *
|
actorValue.getAsDouble(AVKey.ACCEL)!! *
|
||||||
actorValue.getAsDouble(AVKey.ACCELMULT)!! *
|
actorValue.getAsDouble(AVKey.ACCELMULT)!! *
|
||||||
Math.sqrt(scale) *
|
Math.sqrt(scale) *
|
||||||
applyAccelRealism(walkPowerCounter) *
|
applyVelo(walkCounter) *
|
||||||
(if (up) -1 else 1).toFloat() *
|
(if (up) -1 else 1).toFloat() *
|
||||||
absAxisVal
|
absAxisVal
|
||||||
|
|
||||||
veloY = readonly_totalY
|
movementDelta.set(Vector2(0.0, readonly_totalY))
|
||||||
|
|
||||||
if (walkPowerCounter < WALK_FRAMES_TO_MAX_ACCEL) {
|
if (walkCounter <= WALK_FRAMES_TO_MAX_ACCEL) walkCounter += 1
|
||||||
walkPowerCounter += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clamp veloX
|
// Clamp veloX
|
||||||
veloY = absClamp(veloY, actorValue.getAsDouble(AVKey.SPEED)!!
|
movementDelta.y = absClamp(movementDelta.y,
|
||||||
* actorValue.getAsDouble(AVKey.SPEEDMULT)!!
|
actorValue.getAsDouble(AVKey.SPEED)!! *
|
||||||
* Math.sqrt(scale))
|
actorValue.getAsDouble(AVKey.SPEEDMULT)!! *
|
||||||
|
Math.sqrt(scale))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private fun applyAccel(x: Int): Double {
|
||||||
* For realistic accelerating while walking.
|
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:
|
private fun applyVelo(x: Int): Double {
|
||||||
|
return if (x < WALK_FRAMES_TO_MAX_ACCEL)
|
||||||
* a
|
0.5 - 0.5 * Math.cos(Math.PI * x / WALK_FRAMES_TO_MAX_ACCEL)
|
||||||
* | ------------
|
else 1.0
|
||||||
* |
|
|
||||||
* |
|
|
||||||
* 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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// stops; let the friction kick in by doing nothing to the velocity here
|
// 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
|
//veloX = 0f
|
||||||
|
|
||||||
walkPowerCounter = 0
|
walkCounter = 0
|
||||||
|
movementDelta.zero()
|
||||||
}
|
}
|
||||||
|
|
||||||
// stops; let the friction kick in by doing nothing to the velocity here
|
// 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
|
///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() {
|
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 {
|
private fun isFuncDown(input: Input, fn: EnumKeyFunc): Boolean {
|
||||||
return input.isKeyDown(KeyMap.getKeyCode(fn))
|
return input.isKeyDown(KeyMap.getKeyCode(fn))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,10 +127,10 @@ object CollisionSolver {
|
|||||||
val vy_1 = (uy_2 * (m1 - m2) + 2 * m2 * uy_2) / (m1 + m2)
|
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)
|
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
|
a.veloY = vy_1
|
||||||
b.veloX = vx_2
|
b.veloX = vx_2
|
||||||
b.veloY = vy_2
|
b.veloY = vy_2*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ constructor(//properties
|
|||||||
|
|
||||||
//public World physWorld = new World( new Vec2(0, -TerrarumMain.game.gravitationalAccel) );
|
//public World physWorld = new World( new Vec2(0, -TerrarumMain.game.gravitationalAccel) );
|
||||||
//physics
|
//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)
|
var gravitation: Vector2 = Vector2(0.0, 9.8)
|
||||||
/** RGB in Integer */
|
/** RGB in Integer */
|
||||||
var globalLight: Int = 0
|
var globalLight: Int = 0
|
||||||
|
|||||||
@@ -229,8 +229,7 @@ object LightmapRenderer {
|
|||||||
}
|
}
|
||||||
// luminous tile on top of air
|
// luminous tile on top of air
|
||||||
else if (thisWall == AIR && thisTileLuminosity.toInt() > 0) {
|
else if (thisWall == AIR && thisTileLuminosity.toInt() > 0) {
|
||||||
val darkenSunlight = darkenColoured(sunLight, thisTileOpacity)
|
lightLevelThis = maximiseRGB(sunLight, thisTileLuminosity) // maximise to not exceed 1.0 with normal (<= 1.0) light
|
||||||
lightLevelThis = maximiseRGB(darkenSunlight, thisTileLuminosity) // maximise to not exceed 1.0 with normal (<= 1.0) light
|
|
||||||
}
|
}
|
||||||
// opaque wall and luminous tile
|
// opaque wall and luminous tile
|
||||||
else if (thisWall != AIR && thisTileLuminosity.toInt() > 0) {
|
else if (thisWall != AIR && thisTileLuminosity.toInt() > 0) {
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ import org.newdawn.slick.*
|
|||||||
object MapDrawer {
|
object MapDrawer {
|
||||||
const val TILE_SIZE = 16
|
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_LOWEST = 5500
|
||||||
private val ENV_COLTEMP_HIGHEST = 7500
|
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
|
private var colTemp: Int = 0
|
||||||
|
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ class ChainedVector2 {
|
|||||||
* *
|
* *
|
||||||
* @return [ChainedVector2] this vector
|
* @return [ChainedVector2] this vector
|
||||||
*/
|
*/
|
||||||
operator fun plus(vector: ChainedVector2): ChainedVector2 {
|
fun plus(vector: ChainedVector2): ChainedVector2 {
|
||||||
this.x += vector.x
|
this.x += vector.x
|
||||||
this.y += vector.y
|
this.y += vector.y
|
||||||
return this
|
return this
|
||||||
@@ -428,7 +428,7 @@ class ChainedVector2 {
|
|||||||
* *
|
* *
|
||||||
* @return [ChainedVector2] this vector
|
* @return [ChainedVector2] this vector
|
||||||
*/
|
*/
|
||||||
operator fun minus(vector: ChainedVector2): ChainedVector2 {
|
fun minus(vector: ChainedVector2): ChainedVector2 {
|
||||||
this.x -= vector.x
|
this.x -= vector.x
|
||||||
this.y -= vector.y
|
this.y -= vector.y
|
||||||
return this
|
return this
|
||||||
@@ -500,7 +500,7 @@ class ChainedVector2 {
|
|||||||
* *
|
* *
|
||||||
* @return [ChainedVector2] this vector
|
* @return [ChainedVector2] this vector
|
||||||
*/
|
*/
|
||||||
operator fun times(scalar: Double): ChainedVector2 {
|
fun times(scalar: Double): ChainedVector2 {
|
||||||
this.x *= scalar
|
this.x *= scalar
|
||||||
this.y *= scalar
|
this.y *= scalar
|
||||||
return this
|
return this
|
||||||
@@ -512,7 +512,7 @@ class ChainedVector2 {
|
|||||||
* *
|
* *
|
||||||
* @return [ChainedVector2] this vector
|
* @return [ChainedVector2] this vector
|
||||||
*/
|
*/
|
||||||
operator fun div(scalar: Double): ChainedVector2 {
|
fun div(scalar: Double): ChainedVector2 {
|
||||||
this.x /= scalar
|
this.x /= scalar
|
||||||
this.y /= scalar
|
this.y /= scalar
|
||||||
return this
|
return this
|
||||||
@@ -525,7 +525,7 @@ class ChainedVector2 {
|
|||||||
* *
|
* *
|
||||||
* @return [ChainedVector2]
|
* @return [ChainedVector2]
|
||||||
*/
|
*/
|
||||||
infix fun product(scalar: Double): ChainedVector2 {
|
fun product(scalar: Double): ChainedVector2 {
|
||||||
return ChainedVector2(this.x * scalar, this.y * scalar)
|
return ChainedVector2(this.x * scalar, this.y * scalar)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,7 +536,7 @@ class ChainedVector2 {
|
|||||||
* *
|
* *
|
||||||
* @return double
|
* @return double
|
||||||
*/
|
*/
|
||||||
infix fun dot(vector: ChainedVector2): Double {
|
fun dot(vector: ChainedVector2): Double {
|
||||||
return this.x * vector.x + this.y * vector.y
|
return this.x * vector.x + this.y * vector.y
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,7 +559,7 @@ class ChainedVector2 {
|
|||||||
* *
|
* *
|
||||||
* @return double
|
* @return double
|
||||||
*/
|
*/
|
||||||
infix fun cross(vector: ChainedVector2): Double {
|
fun cross(vector: ChainedVector2): Double {
|
||||||
return this.x * vector.y - this.y * vector.x
|
return this.x * vector.y - this.y * vector.x
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -581,7 +581,7 @@ class ChainedVector2 {
|
|||||||
* *
|
* *
|
||||||
* @return [ChainedVector2]
|
* @return [ChainedVector2]
|
||||||
*/
|
*/
|
||||||
infix fun cross(z: Double): ChainedVector2 {
|
fun cross(z: Double): ChainedVector2 {
|
||||||
return ChainedVector2(-1.0 * this.y * z, this.x * z)
|
return ChainedVector2(-1.0 * this.y * z, this.x * z)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,7 +628,7 @@ class ChainedVector2 {
|
|||||||
* Negates this [ChainedVector2].
|
* Negates this [ChainedVector2].
|
||||||
* @return [ChainedVector2] this vector
|
* @return [ChainedVector2] this vector
|
||||||
*/
|
*/
|
||||||
operator fun not() = negate()
|
fun not() = negate()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Negates this [ChainedVector2].
|
* Negates this [ChainedVector2].
|
||||||
@@ -663,7 +663,7 @@ class ChainedVector2 {
|
|||||||
* *
|
* *
|
||||||
* @return [ChainedVector2] this vector
|
* @return [ChainedVector2] this vector
|
||||||
*/
|
*/
|
||||||
infix fun rotate(theta: Double): ChainedVector2 {
|
fun rotate(theta: Double): ChainedVector2 {
|
||||||
val cos = Math.cos(theta)
|
val cos = Math.cos(theta)
|
||||||
val sin = Math.sin(theta)
|
val sin = Math.sin(theta)
|
||||||
val x = this.x
|
val x = this.x
|
||||||
|
|||||||
1
work_files/graphics/colourmap/.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.{psd,tga,ogg} filter=lfs diff=lfs merge=lfs -text
|
||||||