mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
collision detection and CCD: Not exactly fixed but it works good enough
Former-commit-id: 3feb9b1156fc941390b4efe4c1540ed4c5dbd109 Former-commit-id: 8c97b0ade765731800ef09b722e0742e44443338
This commit is contained in:
BIN
res/graphics/gui/progress_round_sheet.png
Normal file
BIN
res/graphics/gui/progress_round_sheet.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
@@ -3,19 +3,9 @@ package net.torvald.point
|
|||||||
/**
|
/**
|
||||||
* Created by minjaesong on 16-01-15.
|
* Created by minjaesong on 16-01-15.
|
||||||
*/
|
*/
|
||||||
class Point2d(x: Double, y: Double) {
|
class Point2d(var x: Double, var y: Double) : Cloneable {
|
||||||
|
|
||||||
var x: Double = 0.toDouble()
|
fun set(x: Double, y: Double) {
|
||||||
private set
|
|
||||||
var y: Double = 0.toDouble()
|
|
||||||
private set
|
|
||||||
|
|
||||||
init {
|
|
||||||
this.x = x
|
|
||||||
this.y = y
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun set(x: Double, y: Double) {
|
|
||||||
this.x = x
|
this.x = x
|
||||||
this.y = y
|
this.y = y
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -252,12 +252,9 @@ constructor(gamename: String) : StateBasedGame(gamename) {
|
|||||||
get() {
|
get() {
|
||||||
val lan = System.getProperty("user.language")
|
val lan = System.getProperty("user.language")
|
||||||
var country = System.getProperty("user.country")
|
var country = System.getProperty("user.country")
|
||||||
if (lan == "en")
|
if (lan == "en") country = "US"
|
||||||
country = "US"
|
else if (lan == "fr") country = "FR"
|
||||||
else if (lan == "fr")
|
else if (lan == "de") country = "DE"
|
||||||
country = "FR"
|
|
||||||
else if (lan == "de")
|
|
||||||
country = "DE"
|
|
||||||
else if (lan == "ko") country = "KR"
|
else if (lan == "ko") country = "KR"
|
||||||
|
|
||||||
return lan + country
|
return lan + country
|
||||||
|
|||||||
@@ -6,30 +6,69 @@ package net.torvald.terrarum.gameactors
|
|||||||
object AVKey {
|
object AVKey {
|
||||||
const val MULT = "mult"
|
const val MULT = "mult"
|
||||||
|
|
||||||
|
/** pixels per frame
|
||||||
|
* walking/running speed
|
||||||
|
*/
|
||||||
const val SPEED = "speed"
|
const val SPEED = "speed"
|
||||||
const val SPEEDMULT = "speed$MULT"
|
const val SPEEDMULT = "speed$MULT"
|
||||||
|
/** pixels per frame squared
|
||||||
|
* acceleration of the movement (e.g. running, flying, driving, etc.)
|
||||||
|
*/
|
||||||
const val ACCEL = "accel"
|
const val ACCEL = "accel"
|
||||||
const val ACCELMULT = "accel$MULT"
|
const val ACCELMULT = "accel$MULT"
|
||||||
const val SCALE = "scale"
|
const val SCALE = "scale"
|
||||||
|
/** pixels */
|
||||||
const val BASEHEIGHT = "baseheight"
|
const val BASEHEIGHT = "baseheight"
|
||||||
|
/** kilogrammes */
|
||||||
const val BASEMASS = "basemass"
|
const val BASEMASS = "basemass"
|
||||||
|
/** pixels per frame */
|
||||||
const val JUMPPOWER = "jumppower"
|
const val JUMPPOWER = "jumppower"
|
||||||
const val JUMPPOWERMULT = "jumppower$MULT"
|
const val JUMPPOWERMULT = "jumppower$MULT"
|
||||||
|
|
||||||
|
/** Int
|
||||||
|
* "Default" value of 1 000
|
||||||
|
*/
|
||||||
const val STRENGTH = "strength"
|
const val STRENGTH = "strength"
|
||||||
const val ENCUMBRANCE = "encumbrance"
|
const val ENCUMBRANCE = "encumbrance"
|
||||||
|
/** 30-bit RGB (Int)
|
||||||
|
* 0000 0010000000 0010000000 0010000000
|
||||||
|
* ^ Red ^ Green ^ Blue
|
||||||
|
*/
|
||||||
const val LUMINOSITY = "luminosity"
|
const val LUMINOSITY = "luminosity"
|
||||||
const val PHYSIQUEMULT = "physique$MULT"
|
const val PHYSIQUEMULT = "physique$MULT"
|
||||||
const val DRAGCOEFF = "dragcoeff"
|
const val DRAGCOEFF = "dragcoeff"
|
||||||
|
|
||||||
|
/** String
|
||||||
|
* e.g. Jarppi
|
||||||
|
*/
|
||||||
const val NAME = "name"
|
const val NAME = "name"
|
||||||
|
|
||||||
|
/** String
|
||||||
|
* e.g. Duudson
|
||||||
|
*/
|
||||||
const val RACENAME = "racename"
|
const val RACENAME = "racename"
|
||||||
|
/** String
|
||||||
|
* e.g. Duudsonit
|
||||||
|
*/
|
||||||
const val RACENAMEPLURAL = "racenameplural"
|
const val RACENAMEPLURAL = "racenameplural"
|
||||||
|
/** killogrammes
|
||||||
|
* will affect attack strength, speed and inventory label
|
||||||
|
* (see "Attack momentum calculator.numbers")
|
||||||
|
* e.g. Hatchet (tiny)
|
||||||
|
*/
|
||||||
const val TOOLSIZE = "toolsize"
|
const val TOOLSIZE = "toolsize"
|
||||||
|
/** Boolean
|
||||||
|
* whether the player can talk with it
|
||||||
|
*/
|
||||||
const val INTELLIGENT = "intelligent"
|
const val INTELLIGENT = "intelligent"
|
||||||
|
|
||||||
const val BASEDEFENCE = "basedefence" // creature base
|
/** (unit TBA)
|
||||||
const val ARMOURDEFENCE = "armourdefence" // armour points
|
* base defence point of the species
|
||||||
|
*/
|
||||||
|
const val BASEDEFENCE = "basedefence"
|
||||||
|
/** (unit TBA)
|
||||||
|
* current defence point of worn armour(s)
|
||||||
|
*/
|
||||||
|
const val ARMOURDEFENCE = "armourdefence"
|
||||||
const val ARMOURDEFENCEMULT = "armourdefence$MULT"
|
const val ARMOURDEFENCEMULT = "armourdefence$MULT"
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@ import net.torvald.terrarum.tileproperties.TilePropCodex
|
|||||||
import net.torvald.spriteanimation.SpriteAnimation
|
import net.torvald.spriteanimation.SpriteAnimation
|
||||||
import com.jme3.math.FastMath
|
import com.jme3.math.FastMath
|
||||||
import net.torvald.terrarum.tileproperties.TileNameCode
|
import net.torvald.terrarum.tileproperties.TileNameCode
|
||||||
|
import org.dyn4j.Epsilon
|
||||||
import org.dyn4j.geometry.ChainedVector2
|
import org.dyn4j.geometry.ChainedVector2
|
||||||
import org.dyn4j.geometry.Vector2
|
import org.dyn4j.geometry.Vector2
|
||||||
import org.newdawn.slick.GameContainer
|
import org.newdawn.slick.GameContainer
|
||||||
@@ -22,15 +23,15 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
|
|
||||||
override var actorValue: ActorValue = ActorValue()
|
override var actorValue: ActorValue = ActorValue()
|
||||||
|
|
||||||
var hitboxTranslateX: Double = 0.toDouble()// relative to spritePosX
|
var hitboxTranslateX: Double = 0.0// relative to spritePosX
|
||||||
var hitboxTranslateY: Double = 0.toDouble()// relative to spritePosY
|
var hitboxTranslateY: Double = 0.0// relative to spritePosY
|
||||||
var baseHitboxW: Int = 0
|
var baseHitboxW: Int = 0
|
||||||
var baseHitboxH: Int = 0
|
var baseHitboxH: Int = 0
|
||||||
|
|
||||||
@Transient private val map: GameMap = Terrarum.game.map
|
@Transient private val map: GameMap = Terrarum.game.map
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Velocity vector (broken down by axes) for newtonian sim.
|
* Velocity vector for newtonian sim.
|
||||||
* Acceleration: used in code like:
|
* Acceleration: used in code like:
|
||||||
* 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.
|
||||||
@@ -85,7 +86,7 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
if (value <= 0)
|
if (value <= 0)
|
||||||
throw IllegalArgumentException("mass cannot be less than or equal to zero.")
|
throw IllegalArgumentException("mass cannot be less than or equal to zero.")
|
||||||
else if (value < MASS_LOWEST) {
|
else if (value < MASS_LOWEST) {
|
||||||
println("[ActorWithBody] input too low; assigning 0.1 instead.")
|
println("[ActorWithBody] input too small; using $MASS_LOWEST instead.")
|
||||||
actorValue[AVKey.BASEMASS] = MASS_LOWEST
|
actorValue[AVKey.BASEMASS] = MASS_LOWEST
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +96,7 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
var elasticity: Double = 0.0
|
var elasticity: Double = 0.0
|
||||||
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("invalid elasticity value $value; valid elasticity value is [0, 1].")
|
||||||
else if (value >= ELASTICITY_MAX) {
|
else if (value >= ELASTICITY_MAX) {
|
||||||
println("[ActorWithBody] Elasticity were capped to $ELASTICITY_MAX.")
|
println("[ActorWithBody] Elasticity were capped to $ELASTICITY_MAX.")
|
||||||
field = ELASTICITY_MAX
|
field = ELASTICITY_MAX
|
||||||
@@ -118,12 +119,6 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
|
|
||||||
private var density = 1000.0
|
private var density = 1000.0
|
||||||
|
|
||||||
/**
|
|
||||||
* Gravitational Constant G. Load from gamemap.
|
|
||||||
* [m / s^2]
|
|
||||||
* s^2 = 1/FPS = 1/60 if FPS is targeted to 60
|
|
||||||
* meter to pixel : 24/FPS
|
|
||||||
*/
|
|
||||||
@Transient private val METER = 24.0
|
@Transient private val METER = 24.0
|
||||||
/**
|
/**
|
||||||
* [m / s^2] * SI_TO_GAME_ACC -> [px / InternalFrame^2]
|
* [m / s^2] * SI_TO_GAME_ACC -> [px / InternalFrame^2]
|
||||||
@@ -133,10 +128,15 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
* [m / s] * SI_TO_GAME_VEL -> [px / InternalFrame]
|
* [m / s] * SI_TO_GAME_VEL -> [px / InternalFrame]
|
||||||
*/
|
*/
|
||||||
@Transient private val SI_TO_GAME_VEL = METER / Terrarum.TARGET_FPS
|
@Transient private val SI_TO_GAME_VEL = METER / Terrarum.TARGET_FPS
|
||||||
|
/**
|
||||||
|
* Gravitational Constant G. Load from gamemap.
|
||||||
|
* [m / s^2]
|
||||||
|
* s^2 = 1/FPS = 1/60 if FPS is targeted to 60
|
||||||
|
* meter to pixel : 24/FPS
|
||||||
|
*/
|
||||||
@Transient private val gravitation: Vector2 = map.gravitation
|
@Transient private val gravitation: Vector2 = map.gravitation
|
||||||
@Transient val DRAG_COEFF_DEFAULT = 1.2
|
@Transient val DRAG_COEFF_DEFAULT = 1.2
|
||||||
/** Drag coeffisient. Parachutes have much higher value than bare body (1.2) */
|
/** Drag coefficient. Parachutes have much higher value than bare body (1.2) */
|
||||||
private var DRAG_COEFF: Double
|
private var DRAG_COEFF: Double
|
||||||
get() = actorValue.getAsDouble(AVKey.DRAGCOEFF) ?: DRAG_COEFF_DEFAULT
|
get() = actorValue.getAsDouble(AVKey.DRAGCOEFF) ?: DRAG_COEFF_DEFAULT
|
||||||
set(value) {
|
set(value) {
|
||||||
@@ -145,11 +145,6 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
actorValue[AVKey.DRAGCOEFF] = value
|
actorValue[AVKey.DRAGCOEFF] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transient private val CONTACT_AREA_TOP = 0
|
|
||||||
@Transient private val CONTACT_AREA_RIGHT = 1
|
|
||||||
@Transient private val CONTACT_AREA_BOTTOM = 2
|
|
||||||
@Transient private val CONTACT_AREA_LEFT = 3
|
|
||||||
|
|
||||||
@Transient private val UD_COMPENSATOR_MAX = TSIZE
|
@Transient private val UD_COMPENSATOR_MAX = TSIZE
|
||||||
@Transient private val LR_COMPENSATOR_MAX = TSIZE
|
@Transient private val LR_COMPENSATOR_MAX = TSIZE
|
||||||
|
|
||||||
@@ -158,14 +153,6 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
*/
|
*/
|
||||||
@Transient private val G_MUL_PLAYABLE_CONST = 1.4142
|
@Transient private val G_MUL_PLAYABLE_CONST = 1.4142
|
||||||
|
|
||||||
@Transient private val EVENT_MOVE_TOP = 0
|
|
||||||
@Transient private val EVENT_MOVE_RIGHT = 1
|
|
||||||
@Transient private val EVENT_MOVE_BOTTOM = 2
|
|
||||||
@Transient private val EVENT_MOVE_LEFT = 3
|
|
||||||
@Transient private val EVENT_MOVE_NONE = -1
|
|
||||||
|
|
||||||
@Transient internal var eventMoving = EVENT_MOVE_NONE // cannot collide both X-axis and Y-axis, or else jump control breaks up.
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Post-hit invincibility, in milliseconds
|
* Post-hit invincibility, in milliseconds
|
||||||
*/
|
*/
|
||||||
@@ -188,26 +175,36 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
@Transient val DYNAMIC = 2
|
@Transient val DYNAMIC = 2
|
||||||
@Transient val STATIC = 3 // does not be budged by external forces, target of collision
|
@Transient val STATIC = 3 // does not be budged by external forces, target of collision
|
||||||
|
|
||||||
private val SLEEP_THRE = 1.0 / 16.0
|
var collisionType = DYNAMIC
|
||||||
private val CCD_TICK = 1.0 / 16.0
|
|
||||||
|
|
||||||
|
@Transient private val CCD_TICK = 1.0 / 256.0
|
||||||
|
@Transient private val CCD_TRY_MAX = 25600
|
||||||
|
|
||||||
|
// to use with Controller (incl. player)
|
||||||
internal var walledLeft = false
|
internal var walledLeft = false
|
||||||
internal var walledRight = false
|
internal var walledRight = false
|
||||||
|
|
||||||
|
// just some trivial magic numbers
|
||||||
|
@Transient private val A_PIXEL = 2.0
|
||||||
|
@Transient private val COLLIDING_TOP = 0
|
||||||
|
@Transient private val COLLIDING_RIGHT = 1
|
||||||
|
@Transient private val COLLIDING_BOTTOM = 2
|
||||||
|
@Transient private val COLLIDING_LEFT = 3
|
||||||
|
@Transient private val COLLIDING_UD = 4
|
||||||
|
@Transient private val COLLIDING_LR = 5
|
||||||
|
@Transient private val COLLIDING_ALLSIDE = 6
|
||||||
|
|
||||||
|
@Transient private var assertPrinted = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// any initialiser goes here...
|
// some initialiser goes here...
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
* @param w
|
* @param w
|
||||||
* *
|
|
||||||
* @param h
|
* @param h
|
||||||
* *
|
|
||||||
* @param tx +: translate drawn sprite to LEFT.
|
* @param tx +: translate drawn sprite to LEFT.
|
||||||
* *
|
|
||||||
* @param ty +: translate drawn sprite to DOWN.
|
* @param ty +: translate drawn sprite to DOWN.
|
||||||
* *
|
|
||||||
* @see ActorWithBody.drawBody
|
* @see ActorWithBody.drawBody
|
||||||
* @see ActorWithBody.drawGlow
|
* @see ActorWithBody.drawGlow
|
||||||
*/
|
*/
|
||||||
@@ -221,7 +218,6 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
/**
|
/**
|
||||||
* Set hitbox position from bottom-center point
|
* Set hitbox position from bottom-center point
|
||||||
* @param x
|
* @param x
|
||||||
* *
|
|
||||||
* @param y
|
* @param y
|
||||||
*/
|
*/
|
||||||
fun setPosition(x: Double, y: Double) {
|
fun setPosition(x: Double, y: Double) {
|
||||||
@@ -255,6 +251,8 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
override fun update(gc: GameContainer, delta: Int) {
|
override fun update(gc: GameContainer, delta: Int) {
|
||||||
if (isUpdate) {
|
if (isUpdate) {
|
||||||
|
|
||||||
|
if (!assertPrinted) assertInit()
|
||||||
|
|
||||||
// make NoClip work for player
|
// make NoClip work for player
|
||||||
if (this is Player) {
|
if (this is Player) {
|
||||||
isNoSubjectToGrav = isPlayerNoClip
|
isNoSubjectToGrav = isPlayerNoClip
|
||||||
@@ -281,47 +279,43 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
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
|
||||||
|
|
||||||
moveDelta.x = veloX + walkX
|
moveDelta.set(velocity + Vector2(walkX, walkY))
|
||||||
moveDelta.y = veloY + walkY
|
|
||||||
|
|
||||||
if (!physSleep) {
|
if (!physSleep) {
|
||||||
// Set 'next' position (hitbox) to fiddle with
|
// Set 'next' position (hitbox) from canonical and walking velocity
|
||||||
setNewNextHitbox()
|
setNewNextHitbox()
|
||||||
|
|
||||||
|
applyNormalForce()
|
||||||
/**
|
/**
|
||||||
* Solve collision
|
* solveCollision()?
|
||||||
* If and only if:
|
* If and only if:
|
||||||
* This body is NON-STATIC and the other body is STATIC
|
* This body is NON-STATIC and the other body is STATIC
|
||||||
*/
|
*/
|
||||||
applyNormalForce()
|
displaceByCCD()
|
||||||
adjustHit()
|
|
||||||
|
|
||||||
setHorizontalFriction()
|
setHorizontalFriction()
|
||||||
if (isPlayerNoClip) setVerticalFriction()
|
if (isPlayerNoClip) // or hanging on the rope, etc.
|
||||||
//}
|
setVerticalFriction()
|
||||||
|
|
||||||
// apply our compensation to actual hitbox
|
// apply our compensation to actual hitbox
|
||||||
updateHitboxX()
|
updateHitbox()
|
||||||
updateHitboxY()
|
|
||||||
|
|
||||||
// make sure the actor does not go out of the map
|
// make sure the actor does not go out of the map
|
||||||
clampNextHitbox()
|
|
||||||
clampHitbox()
|
clampHitbox()
|
||||||
}
|
}
|
||||||
|
|
||||||
walledLeft = isColliding(CONTACT_AREA_LEFT, -1, 0)
|
walledLeft = isColliding(COLLIDING_LEFT)
|
||||||
walledRight = isColliding(CONTACT_AREA_RIGHT, 1, 0)
|
walledRight = isColliding(COLLIDING_RIGHT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply gravitation to the every falling body (unless not levitating)
|
* Apply gravitation to the every falling body (unless not levitating)
|
||||||
*
|
*
|
||||||
* Apply only if not grounded; normal force is not implemented (and redundant)
|
* Apply only if not grounded; normal force is precessed separately.
|
||||||
* so we manually reset G to zero (not applying G. force) if grounded.
|
|
||||||
*/
|
*/
|
||||||
private fun applyGravitation() {
|
private fun applyGravitation() {
|
||||||
if (!grounded) {
|
if (!grounded) {//(!isColliding(COLLIDING_BOTTOM)) { // or !grounded
|
||||||
/**
|
/**
|
||||||
* weight; gravitational force in action
|
* weight; gravitational force in action
|
||||||
* W = mass * G (9.8 [m/s^2])
|
* W = mass * G (9.8 [m/s^2])
|
||||||
@@ -333,9 +327,9 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
val A: Double = scale * scale
|
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 sqr) * A (area)
|
||||||
*/
|
*/
|
||||||
val D: Vector2 = velocity * 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
|
val V: Vector2 = (W - D) / mass * SI_TO_GAME_ACC
|
||||||
|
|
||||||
@@ -343,8 +337,218 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun applyNormalForce() {
|
||||||
|
if (!isNoCollideWorld) {
|
||||||
|
// axis Y
|
||||||
|
if (moveDelta.y >= 0.0) { // check downward
|
||||||
|
//FIXME "isColliding" (likely the newer one) is the perkeleen vittupää
|
||||||
|
if (isColliding(COLLIDING_UD)) {
|
||||||
|
// the actor is hitting the ground
|
||||||
|
hitAndReflectY()
|
||||||
|
grounded = true
|
||||||
|
}
|
||||||
|
else { // the actor is not grounded at all
|
||||||
|
grounded = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (moveDelta.y < 0.0) { // check upward
|
||||||
|
grounded = false
|
||||||
|
if (isColliding(COLLIDING_UD)) {
|
||||||
|
// the actor is hitting the ceiling
|
||||||
|
hitAndReflectY()
|
||||||
|
}
|
||||||
|
else { // the actor is not grounded at all
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// axis X
|
||||||
|
if (isColliding(COLLIDING_LR) && moveDelta.x != 0.0) { // check right and left
|
||||||
|
// the actor is hitting the wall
|
||||||
|
hitAndReflectX()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nextHitbox must NOT be altered before this method is called!
|
||||||
|
*/
|
||||||
|
private fun displaceByCCD() {
|
||||||
|
if (!isNoCollideWorld){
|
||||||
|
// vector, toward the previous position; implies linear interpolation
|
||||||
|
val deltaNegative = Vector2(hitbox.toVector() - nextHitbox.toVector()) // we need to traverse back, so may as well negate at the first place
|
||||||
|
val ccdDelta = if (deltaNegative.magnitudeSquared > CCD_TICK.sqr())
|
||||||
|
deltaNegative.setMagnitude(CCD_TICK)
|
||||||
|
else
|
||||||
|
deltaNegative
|
||||||
|
var ccdCount = 0
|
||||||
|
|
||||||
|
// Q&D fix: quantise hitbox by direction
|
||||||
|
/*if (deltaNegative.y < 0) {
|
||||||
|
if (deltaNegative.x > 0)
|
||||||
|
nextHitbox.setPosition(
|
||||||
|
nextHitbox.posX.floor(),
|
||||||
|
nextHitbox.endPointY.ceil().minus(nextHitbox.height)
|
||||||
|
)
|
||||||
|
else if (deltaNegative.x < 0)
|
||||||
|
nextHitbox.setPosition(
|
||||||
|
nextHitbox.endPointX.ceil().minus(nextHitbox.width),
|
||||||
|
nextHitbox.endPointY.ceil().minus(nextHitbox.height)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else if (deltaNegative.y > 0) {
|
||||||
|
if (deltaNegative.x > 0)
|
||||||
|
nextHitbox.setPosition(
|
||||||
|
nextHitbox.posX.floor(),
|
||||||
|
nextHitbox.posY.floor()
|
||||||
|
)
|
||||||
|
else if (deltaNegative.x < 0)
|
||||||
|
nextHitbox.setPosition(
|
||||||
|
nextHitbox.endPointX.ceil().minus(nextHitbox.width),
|
||||||
|
nextHitbox.posY.floor()
|
||||||
|
)
|
||||||
|
}*/
|
||||||
|
|
||||||
|
while (isColliding(COLLIDING_ALLSIDE) && ccdCount < CCD_TRY_MAX) { // no thresholding?
|
||||||
|
nextHitbox.translate(ccdDelta)
|
||||||
|
ccdCount += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ccdCount > 0) {
|
||||||
|
println("Displacement: ${ccdDelta.magnitude * ccdCount} ($ccdCount times)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hitAndReflectX() {
|
||||||
|
if ((veloX * elasticity).abs() > Epsilon.E) {
|
||||||
|
veloX *= -elasticity
|
||||||
|
walkX *= -elasticity
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
veloX = 0.0
|
||||||
|
walkX = 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hitAndReflectY() {
|
||||||
|
if ((veloY * elasticity).abs() > Epsilon.E) {
|
||||||
|
veloY *= -elasticity
|
||||||
|
walkY *= -elasticity
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
veloY = 0.0
|
||||||
|
walkY *= 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isColliding() = isColliding(0)
|
||||||
|
|
||||||
|
private fun isColliding(option: Int): Boolean {
|
||||||
|
if (isNoCollideWorld) return false
|
||||||
|
|
||||||
|
// offsets will stretch and shrink detection box according to the argument
|
||||||
|
val x1: Double; val x2: Double; val y1: Double; val y2: Double
|
||||||
|
if (option == COLLIDING_LR || option == COLLIDING_UD) {
|
||||||
|
val offsetX = if (option == COLLIDING_LR) A_PIXEL else 0.0
|
||||||
|
val offsetY = if (option == COLLIDING_UD) A_PIXEL else 0.0
|
||||||
|
|
||||||
|
x1 = nextHitbox.posX - offsetX + offsetY
|
||||||
|
x2 = nextHitbox.posX + offsetX - offsetY + nextHitbox.width
|
||||||
|
y1 = nextHitbox.posY + offsetX - offsetY
|
||||||
|
y2 = nextHitbox.posY - offsetX + offsetY + nextHitbox.height
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (option == COLLIDING_LEFT) {
|
||||||
|
x1 = nextHitbox.posX - A_PIXEL
|
||||||
|
x2 = nextHitbox.posX - A_PIXEL + nextHitbox.width
|
||||||
|
y1 = nextHitbox.posY + A_PIXEL
|
||||||
|
y2 = nextHitbox.posY - A_PIXEL + nextHitbox.height
|
||||||
|
}
|
||||||
|
else if (option == COLLIDING_RIGHT) {
|
||||||
|
x1 = nextHitbox.posX + A_PIXEL
|
||||||
|
x2 = nextHitbox.posX + A_PIXEL + nextHitbox.width
|
||||||
|
y1 = nextHitbox.posY + A_PIXEL
|
||||||
|
y2 = nextHitbox.posY - A_PIXEL + nextHitbox.height
|
||||||
|
}
|
||||||
|
else if (option == COLLIDING_TOP) {
|
||||||
|
x1 = nextHitbox.posX + A_PIXEL
|
||||||
|
x2 = nextHitbox.posX - A_PIXEL + nextHitbox.width
|
||||||
|
y1 = nextHitbox.posY - A_PIXEL
|
||||||
|
y2 = nextHitbox.posY - A_PIXEL + nextHitbox.height
|
||||||
|
}
|
||||||
|
else if (option == COLLIDING_BOTTOM) {
|
||||||
|
x1 = nextHitbox.posX + A_PIXEL
|
||||||
|
x2 = nextHitbox.posX - A_PIXEL + nextHitbox.width
|
||||||
|
y1 = nextHitbox.posY + A_PIXEL
|
||||||
|
y2 = nextHitbox.posY + A_PIXEL + nextHitbox.height
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
x1 = nextHitbox.posX
|
||||||
|
x2 = nextHitbox.posX + nextHitbox.width
|
||||||
|
y1 = nextHitbox.posY
|
||||||
|
y2 = nextHitbox.posY + nextHitbox.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val txStart = x1.div(TSIZE).floorInt()
|
||||||
|
val txEnd = x2.div(TSIZE).floorInt()
|
||||||
|
val tyStart = y1.div(TSIZE).floorInt()
|
||||||
|
val tyEnd = y2.div(TSIZE).floorInt()
|
||||||
|
|
||||||
|
for (y in tyStart..tyEnd) {
|
||||||
|
for (x in txStart..txEnd) {
|
||||||
|
val tile = map.getTileFromTerrain(x, y)
|
||||||
|
if (TilePropCodex.getProp(tile).isSolid)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
// set tile positions
|
||||||
|
val tileX: Int
|
||||||
|
val tileY: Int
|
||||||
|
if (side == COLLIDING_LEFT) {
|
||||||
|
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundInt()
|
||||||
|
+ i + translateX)
|
||||||
|
tileY = div16TruncateToMapHeight(nextHitbox.hitboxEnd.y.roundInt() + translateY)
|
||||||
|
}
|
||||||
|
else if (side == COLLIDING_TOP) {
|
||||||
|
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundInt()
|
||||||
|
+ i + translateX)
|
||||||
|
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundInt() + translateY)
|
||||||
|
}
|
||||||
|
else if (side == COLLIDING_RIGHT) {
|
||||||
|
tileX = div16TruncateToMapWidth(nextHitbox.hitboxEnd.x.roundInt() + translateX)
|
||||||
|
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundInt()
|
||||||
|
+ i + translateY)
|
||||||
|
}
|
||||||
|
else if (side == COLLIDING_LEFT) {
|
||||||
|
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundInt() + translateX)
|
||||||
|
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundInt()
|
||||||
|
+ i + translateY)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw IllegalArgumentException(side.toString() + ": Wrong side input")
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate
|
||||||
|
if (TilePropCodex.getProp(map.getTileFromTerrain(tileX, tileY)).isFluid) {
|
||||||
|
contactAreaCounter += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return contactAreaCounter
|
||||||
|
}
|
||||||
|
|
||||||
private fun setHorizontalFriction() {
|
private fun setHorizontalFriction() {
|
||||||
val friction = BASE_FRICTION * tileFriction.tileFrictionToMult()
|
val friction = if (isPlayerNoClip)
|
||||||
|
BASE_FRICTION * TilePropCodex.getProp(TileNameCode.STONE).friction.tileFrictionToMult()
|
||||||
|
else
|
||||||
|
BASE_FRICTION * tileFriction.tileFrictionToMult()
|
||||||
|
|
||||||
if (veloX < 0) {
|
if (veloX < 0) {
|
||||||
veloX += friction
|
veloX += friction
|
||||||
@@ -366,7 +570,10 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setVerticalFriction() {
|
private fun setVerticalFriction() {
|
||||||
val friction = BASE_FRICTION * tileFriction.tileFrictionToMult()
|
val friction = if (isPlayerNoClip)
|
||||||
|
BASE_FRICTION * TilePropCodex.getProp(TileNameCode.STONE).friction.tileFrictionToMult()
|
||||||
|
else
|
||||||
|
BASE_FRICTION * tileFriction.tileFrictionToMult()
|
||||||
|
|
||||||
if (veloY < 0) {
|
if (veloY < 0) {
|
||||||
veloY += friction
|
veloY += friction
|
||||||
@@ -387,351 +594,6 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateVerticalCollision() {
|
|
||||||
if (!isNoCollideWorld) {
|
|
||||||
if (veloY >= 0) { // check downward
|
|
||||||
if (isColliding(CONTACT_AREA_BOTTOM)) { // the ground has dug into the body
|
|
||||||
adjustHitBottom()
|
|
||||||
veloY = 0.0 // reset veloY, simulating normal force
|
|
||||||
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
|
|
||||||
hitAndReflectY()
|
|
||||||
grounded = true
|
|
||||||
}
|
|
||||||
else { // the actor is not grounded at all
|
|
||||||
grounded = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (veloY < 0) { // check upward
|
|
||||||
grounded = false
|
|
||||||
if (isColliding(CONTACT_AREA_TOP)) { // the ceiling has dug into the body
|
|
||||||
adjustHitTop()
|
|
||||||
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
|
|
||||||
hitAndReflectY() // reflect on ceiling, for reversed gravity
|
|
||||||
}
|
|
||||||
else { // the actor is not grounded at all
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun adjustHitBottom() {
|
|
||||||
val newX = nextHitbox.pointedX // look carefully, getPos or getPointed
|
|
||||||
// int-ify posY of nextHitbox
|
|
||||||
nextHitbox.setPositionYFromPoint(Math.floor(nextHitbox.pointedY).toDouble())
|
|
||||||
|
|
||||||
var newYOff = 0 // always positive
|
|
||||||
|
|
||||||
// count up Y offset until the actor is not touching the ground
|
|
||||||
var colliding: Boolean
|
|
||||||
do {
|
|
||||||
newYOff += 1
|
|
||||||
colliding = isColliding(CONTACT_AREA_BOTTOM, 0, -newYOff)
|
|
||||||
} while (colliding)
|
|
||||||
|
|
||||||
posAdjustY = -newYOff
|
|
||||||
val newY = nextHitbox.pointedY - newYOff
|
|
||||||
nextHitbox.setPositionFromPoint(newX, newY)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun adjustHitTop() {
|
|
||||||
val newX = nextHitbox.posX
|
|
||||||
// int-ify posY of nextHitbox
|
|
||||||
nextHitbox.setPositionY(Math.ceil(nextHitbox.posY).toDouble())
|
|
||||||
|
|
||||||
var newYOff = 0 // always positive
|
|
||||||
|
|
||||||
// count up Y offset until the actor is not touching the ceiling
|
|
||||||
var colliding: Boolean
|
|
||||||
do {
|
|
||||||
newYOff += 1
|
|
||||||
colliding = isColliding(CONTACT_AREA_TOP, 0, newYOff)
|
|
||||||
} while (colliding)
|
|
||||||
|
|
||||||
posAdjustY = newYOff
|
|
||||||
val newY = nextHitbox.posY + newYOff
|
|
||||||
nextHitbox.setPosition(newX, newY)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateHorizontalCollision() {
|
|
||||||
if (!isNoCollideWorld) {
|
|
||||||
if (veloX >= 0.5) { // check right
|
|
||||||
if (isColliding(CONTACT_AREA_RIGHT) && !isColliding(CONTACT_AREA_LEFT)) {
|
|
||||||
// the actor is embedded to the wall
|
|
||||||
adjustHitRight()
|
|
||||||
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
|
|
||||||
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
|
|
||||||
adjustHitLeft()
|
|
||||||
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
|
|
||||||
hitAndReflectX()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // check both sides?
|
|
||||||
// System.out.println("updatehorizontal - |velo| < 0.5");
|
|
||||||
//if (isColliding(CONTACT_AREA_LEFT) || isColliding(CONTACT_AREA_RIGHT)) {
|
|
||||||
// veloX = 0.0 // reset veloX, simulating normal force
|
|
||||||
// elasticReflectX()
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun adjustHitRight() {
|
|
||||||
val newY = nextHitbox.posY // look carefully, posY or pointedY
|
|
||||||
// int-ify posY of nextHitbox
|
|
||||||
nextHitbox.setPositionX(Math.floor(nextHitbox.posX + nextHitbox.width) - nextHitbox.width)
|
|
||||||
|
|
||||||
var newXOff = 0 // always positive
|
|
||||||
|
|
||||||
// count up Y offset until the actor is not touching the wall
|
|
||||||
var colliding: Boolean
|
|
||||||
do {
|
|
||||||
newXOff += 1
|
|
||||||
colliding = isColliding(CONTACT_AREA_BOTTOM, -newXOff + 1, 0) // offset by +1, to fix directional quarks
|
|
||||||
} while (newXOff < TSIZE && colliding)
|
|
||||||
|
|
||||||
val newX = nextHitbox.posX - newXOff // -1: Q&D way to prevent the actor sticking to the wall and won't detach
|
|
||||||
nextHitbox.setPosition(newX, newY)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun adjustHitLeft() {
|
|
||||||
val newY = nextHitbox.posY
|
|
||||||
// int-ify posY of nextHitbox
|
|
||||||
nextHitbox.setPositionX(Math.ceil(nextHitbox.posX).toDouble())
|
|
||||||
|
|
||||||
var newXOff = 0 // always positive
|
|
||||||
|
|
||||||
// count up Y offset until the actor is not touching the wall
|
|
||||||
var colliding: Boolean
|
|
||||||
do {
|
|
||||||
newXOff += 1
|
|
||||||
colliding = isColliding(CONTACT_AREA_TOP, newXOff, 0)
|
|
||||||
} while (newXOff < TSIZE && colliding)
|
|
||||||
|
|
||||||
posAdjustX = newXOff
|
|
||||||
val newX = nextHitbox.posX + newXOff // +1: Q&D way to prevent the actor sticking to the wall and won't detach
|
|
||||||
nextHitbox.setPosition(newX, newY)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* nextHitbox must NOT altered before this method is called!
|
|
||||||
*/
|
|
||||||
private fun adjustHit() {
|
|
||||||
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)
|
|
||||||
val ccdTryMax = 400
|
|
||||||
var ccdCount = 0
|
|
||||||
|
|
||||||
while (((ccdDelta.x.abs() >= SLEEP_THRE) || (ccdDelta.y.abs() >= SLEEP_THRE))
|
|
||||||
&& (isColliding(CONTACT_AREA_LEFT) || isColliding(CONTACT_AREA_RIGHT)
|
|
||||||
|| isColliding(CONTACT_AREA_TOP) || isColliding(CONTACT_AREA_BOTTOM))
|
|
||||||
&& ccdCount < ccdTryMax
|
|
||||||
) {
|
|
||||||
nextHitbox.translate(ccdDelta)
|
|
||||||
ccdCount += 1
|
|
||||||
}
|
|
||||||
//}
|
|
||||||
/*else { // stuck while standing still
|
|
||||||
// CCD upward
|
|
||||||
var upwardDelta = 0.0
|
|
||||||
while (isColliding(CONTACT_AREA_LEFT) || isColliding(CONTACT_AREA_RIGHT)
|
|
||||||
|| isColliding(CONTACT_AREA_TOP) || isColliding(CONTACT_AREA_BOTTOM)
|
|
||||||
) {
|
|
||||||
nextHitbox.translate(0.0, -CCD_TICK)
|
|
||||||
upwardDelta += CCD_TICK
|
|
||||||
|
|
||||||
if (upwardDelta >= TSIZE) break
|
|
||||||
|
|
||||||
/* TODO CCD in order of:
|
|
||||||
|
|
||||||
.. 10 11 12 13 14 ..
|
|
||||||
.. 08 03 04 05 09 ..
|
|
||||||
.. 06 01 [] 02 07 ..
|
|
||||||
|
|
||||||
until the stucking is resolved
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyNormalForce() {
|
|
||||||
if (!isNoCollideWorld) {
|
|
||||||
// axis Y
|
|
||||||
if (moveDelta.y > SLEEP_THRE) { // check downward
|
|
||||||
if (isColliding(CONTACT_AREA_BOTTOM) || isColliding(CONTACT_AREA_BOTTOM, 0, 1)) {
|
|
||||||
// the actor is hitting the ground
|
|
||||||
hitAndReflectY()
|
|
||||||
grounded = true
|
|
||||||
}
|
|
||||||
else { // the actor is not grounded at all
|
|
||||||
grounded = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (moveDelta.y < SLEEP_THRE) { // check upward
|
|
||||||
grounded = false
|
|
||||||
if (isColliding(CONTACT_AREA_TOP) || isColliding(CONTACT_AREA_TOP, 0, -1)) {
|
|
||||||
// the actor is hitting the ceiling
|
|
||||||
hitAndReflectY()
|
|
||||||
}
|
|
||||||
else { // the actor is not grounded at all
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// axis X
|
|
||||||
if (moveDelta.x > SLEEP_THRE) { // check right
|
|
||||||
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
|
|
||||||
hitAndReflectX()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (moveDelta.x < SLEEP_THRE) { // check left
|
|
||||||
// System.out.println("collidingleft");
|
|
||||||
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
|
|
||||||
hitAndReflectX()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hitAndReflectX() {
|
|
||||||
if ((veloX * elasticity).abs() > SLEEP_THRE) {
|
|
||||||
veloX *= -elasticity
|
|
||||||
walkX *= -elasticity
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
veloX = 0.0
|
|
||||||
walkX = 0.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hitAndReflectY() {
|
|
||||||
if ((veloY * elasticity).abs() > SLEEP_THRE) {
|
|
||||||
veloY *= -elasticity
|
|
||||||
walkY *= -elasticity
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
veloY = 0.0
|
|
||||||
walkY *= 0.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isColliding(side: Int, tx: Int = 0, ty: Int = 0): Boolean = getContactingArea(side, tx, ty) > 1
|
|
||||||
|
|
||||||
private fun getContactingArea(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).roundToInt() - 1) {
|
|
||||||
// set tile positions
|
|
||||||
val tileX: Int
|
|
||||||
val tileY: Int
|
|
||||||
if (side == CONTACT_AREA_BOTTOM) {
|
|
||||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundToInt()
|
|
||||||
+ i + translateX)
|
|
||||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxEnd.y.roundToInt() + translateY)
|
|
||||||
}
|
|
||||||
else if (side == CONTACT_AREA_TOP) {
|
|
||||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundToInt()
|
|
||||||
+ i + translateX)
|
|
||||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundToInt() + translateY)
|
|
||||||
}
|
|
||||||
else if (side == CONTACT_AREA_RIGHT) {
|
|
||||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxEnd.x.roundToInt() + translateX)
|
|
||||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundToInt()
|
|
||||||
+ i + translateY)
|
|
||||||
}
|
|
||||||
else if (side == CONTACT_AREA_LEFT) {
|
|
||||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundToInt() + translateX)
|
|
||||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundToInt()
|
|
||||||
+ i + translateY)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw IllegalArgumentException(side.toString() + ": Wrong side input")
|
|
||||||
}
|
|
||||||
|
|
||||||
// evaluate
|
|
||||||
if (TilePropCodex.getProp(map.getTileFromTerrain(tileX, tileY) ?: TileNameCode.STONE).isSolid) {
|
|
||||||
contactAreaCounter += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return contactAreaCounter
|
|
||||||
}
|
|
||||||
|
|
||||||
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).roundToInt() - 1) {
|
|
||||||
// set tile positions
|
|
||||||
val tileX: Int
|
|
||||||
val tileY: Int
|
|
||||||
if (side == CONTACT_AREA_BOTTOM) {
|
|
||||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundToInt()
|
|
||||||
+ i + translateX)
|
|
||||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxEnd.y.roundToInt() + translateY)
|
|
||||||
}
|
|
||||||
else if (side == CONTACT_AREA_TOP) {
|
|
||||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundToInt()
|
|
||||||
+ i + translateX)
|
|
||||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundToInt() + translateY)
|
|
||||||
}
|
|
||||||
else if (side == CONTACT_AREA_RIGHT) {
|
|
||||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxEnd.x.roundToInt() + translateX)
|
|
||||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundToInt()
|
|
||||||
+ i + translateY)
|
|
||||||
}
|
|
||||||
else if (side == CONTACT_AREA_LEFT) {
|
|
||||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundToInt() + translateX)
|
|
||||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundToInt()
|
|
||||||
+ i + translateY)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw IllegalArgumentException(side.toString() + ": Wrong side input")
|
|
||||||
}
|
|
||||||
|
|
||||||
// evaluate
|
|
||||||
if (TilePropCodex.getProp(map.getTileFromTerrain(tileX, tileY)).isFluid) {
|
|
||||||
contactAreaCounter += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return contactAreaCounter
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [N] = [kg * m / s^2]
|
* [N] = [kg * m / s^2]
|
||||||
* F(bo) = density * submerged_volume * gravitational_acceleration [N]
|
* F(bo) = density * submerged_volume * gravitational_acceleration [N]
|
||||||
@@ -754,8 +616,8 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
|
|
||||||
private val submergedHeight: Double
|
private val submergedHeight: Double
|
||||||
get() = Math.max(
|
get() = Math.max(
|
||||||
getContactingAreaFluid(CONTACT_AREA_LEFT),
|
getContactingAreaFluid(COLLIDING_LEFT),
|
||||||
getContactingAreaFluid(CONTACT_AREA_RIGHT)
|
getContactingAreaFluid(COLLIDING_RIGHT)
|
||||||
).toDouble()*/
|
).toDouble()*/
|
||||||
|
|
||||||
|
|
||||||
@@ -768,9 +630,9 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
var friction = 0
|
var friction = 0
|
||||||
|
|
||||||
// take highest value
|
// take highest value
|
||||||
val tilePosXStart = (hitbox.posX / TSIZE).roundToInt()
|
val tilePosXStart = (hitbox.posX / TSIZE).roundInt()
|
||||||
val tilePosXEnd = (hitbox.hitboxEnd.x / TSIZE).roundToInt()
|
val tilePosXEnd = (hitbox.hitboxEnd.x / TSIZE).roundInt()
|
||||||
val tilePosY = (hitbox.pointedY.plus(1) / TSIZE).roundToInt()
|
val tilePosY = (hitbox.pointedY.plus(1) / TSIZE).roundInt()
|
||||||
for (x in tilePosXStart..tilePosXEnd) {
|
for (x in tilePosXStart..tilePosXEnd) {
|
||||||
val tile = map.getTileFromTerrain(x, tilePosY)
|
val tile = map.getTileFromTerrain(x, tilePosY)
|
||||||
val thisFriction = TilePropCodex.getProp(tile).friction
|
val thisFriction = TilePropCodex.getProp(tile).friction
|
||||||
@@ -790,10 +652,10 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
var density = 0
|
var density = 0
|
||||||
|
|
||||||
// take highest value
|
// take highest value
|
||||||
val tilePosXStart = (hitbox.posX / TSIZE).roundToInt()
|
val tilePosXStart = (hitbox.posX / TSIZE).roundInt()
|
||||||
val tilePosXEnd = (hitbox.hitboxEnd.x / TSIZE).roundToInt()
|
val tilePosXEnd = (hitbox.hitboxEnd.x / TSIZE).roundInt()
|
||||||
val tilePosYStart = (hitbox.posY / TSIZE).roundToInt()
|
val tilePosYStart = (hitbox.posY / TSIZE).roundInt()
|
||||||
val tilePosYEnd = (hitbox.hitboxEnd.y / TSIZE).roundToInt()
|
val tilePosYEnd = (hitbox.hitboxEnd.y / TSIZE).roundInt()
|
||||||
for (y in tilePosXStart..tilePosYEnd) {
|
for (y in tilePosXStart..tilePosYEnd) {
|
||||||
for (x in tilePosXStart..tilePosXEnd) {
|
for (x in tilePosXStart..tilePosXEnd) {
|
||||||
val tile = map.getTileFromTerrain(x, y)
|
val tile = map.getTileFromTerrain(x, y)
|
||||||
@@ -815,10 +677,10 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
var density = 0
|
var density = 0
|
||||||
|
|
||||||
//get highest fluid density
|
//get highest fluid density
|
||||||
val tilePosXStart = (nextHitbox.posX / TSIZE).roundToInt()
|
val tilePosXStart = (nextHitbox.posX / TSIZE).roundInt()
|
||||||
val tilePosYStart = (nextHitbox.posY / TSIZE).roundToInt()
|
val tilePosYStart = (nextHitbox.posY / TSIZE).roundInt()
|
||||||
val tilePosXEnd = (nextHitbox.hitboxEnd.x / TSIZE).roundToInt()
|
val tilePosXEnd = (nextHitbox.hitboxEnd.x / TSIZE).roundInt()
|
||||||
val tilePosYEnd = (nextHitbox.hitboxEnd.y / TSIZE).roundToInt()
|
val tilePosYEnd = (nextHitbox.hitboxEnd.y / TSIZE).roundInt()
|
||||||
for (y in tilePosYStart..tilePosYEnd) {
|
for (y in tilePosYStart..tilePosYEnd) {
|
||||||
for (x in tilePosXStart..tilePosXEnd) {
|
for (x in tilePosXStart..tilePosXEnd) {
|
||||||
val tile = map.getTileFromTerrain(x, y)
|
val tile = map.getTileFromTerrain(x, y)
|
||||||
@@ -836,34 +698,16 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
clampW(hitbox.pointedX), clampH(hitbox.pointedY))
|
clampW(hitbox.pointedX), clampH(hitbox.pointedY))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun clampNextHitbox() {
|
|
||||||
nextHitbox.setPositionFromPoint(
|
|
||||||
clampW(nextHitbox.pointedX), clampH(nextHitbox.pointedY))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setNewNextHitbox() {
|
private fun setNewNextHitbox() {
|
||||||
|
|
||||||
nextHitbox.set(
|
nextHitbox.set(
|
||||||
(hitbox.posX + moveDelta.x)
|
hitbox.posX + moveDelta.x,
|
||||||
, (hitbox.posY + moveDelta.y)
|
hitbox.posY + moveDelta.y,
|
||||||
, (baseHitboxW * scale)
|
baseHitboxW * scale,
|
||||||
, (baseHitboxH * scale)
|
baseHitboxH * scale
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateHitboxX() {
|
private fun updateHitbox() = hitbox.set(nextHitbox)
|
||||||
hitbox.setDimension(
|
|
||||||
nextHitbox.width, nextHitbox.height)
|
|
||||||
//if (nextHitbox.posX - hitbox.posX > SLEEP_THRE.abs())
|
|
||||||
hitbox.setPositionX(nextHitbox.posX)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateHitboxY() {
|
|
||||||
hitbox.setDimension(
|
|
||||||
nextHitbox.width, nextHitbox.height)
|
|
||||||
//if (nextHitbox.posY - hitbox.posY > SLEEP_THRE.abs())
|
|
||||||
hitbox.setPositionY(nextHitbox.posY)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun drawGlow(gc: GameContainer, g: Graphics) {
|
override fun drawGlow(gc: GameContainer, g: Graphics) {
|
||||||
if (isVisible && spriteGlow != null) {
|
if (isVisible && spriteGlow != null) {
|
||||||
@@ -958,12 +802,28 @@ open class ActorWithBody : Actor(), Visible {
|
|||||||
private val AUTO_CLIMB_RATE: Int
|
private val AUTO_CLIMB_RATE: Int
|
||||||
get() = Math.min(TSIZE / 8 * Math.sqrt(scale), TSIZE.toDouble()).toInt()
|
get() = Math.min(TSIZE / 8 * Math.sqrt(scale), TSIZE.toDouble()).toInt()
|
||||||
|
|
||||||
|
fun Double.floorInt() = Math.floor(this).toInt()
|
||||||
fun Double.round() = Math.round(this).toDouble()
|
fun Double.round() = Math.round(this).toDouble()
|
||||||
fun Double.roundToInt(): Int = Math.round(this).toInt()
|
fun Double.floor() = Math.floor(this)
|
||||||
|
fun Double.ceil() = this.floor() + 1.0
|
||||||
|
fun Double.roundInt(): Int = Math.round(this).toInt()
|
||||||
fun Double.abs() = Math.abs(this)
|
fun Double.abs() = Math.abs(this)
|
||||||
fun Double.sqr() = this * this
|
fun Double.sqr() = this * this
|
||||||
fun Int.abs() = if (this < 0) -this else this
|
fun Int.abs() = if (this < 0) -this else this
|
||||||
|
|
||||||
|
private fun assertInit() {
|
||||||
|
// errors
|
||||||
|
if (baseHitboxW == 0 || baseHitboxH == 0)
|
||||||
|
throw RuntimeException("Hitbox dimension was not set.")
|
||||||
|
if (sprite == null && isVisible)
|
||||||
|
throw RuntimeException("Actor ${this.javaClass.canonicalName} is visible but the sprite was not set.")
|
||||||
|
// warnings
|
||||||
|
if (!isVisible && sprite != null)
|
||||||
|
println("[ActorWithBody] Caution: actor ${this.javaClass.canonicalName} is invisible but the sprite was given.")
|
||||||
|
|
||||||
|
assertPrinted = true
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@Transient private val TSIZE = MapDrawer.TILE_SIZE
|
@Transient private val TSIZE = MapDrawer.TILE_SIZE
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class FixturesTikiTorch : FixturesBase(), Luminous {
|
|||||||
sprite!!.setAsVisible()
|
sprite!!.setAsVisible()
|
||||||
|
|
||||||
actorValue[AVKey.BASEMASS] = 1.0
|
actorValue[AVKey.BASEMASS] = 1.0
|
||||||
actorValue[AVKey.LUMINOSITY] = TilePropCodex.getProp(TileNameCode.TORCH).luminosity
|
|
||||||
|
luminosity = TilePropCodex.getProp(TileNameCode.TORCH).luminosity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,15 +7,15 @@ import org.dyn4j.geometry.Vector2
|
|||||||
/**
|
/**
|
||||||
* Created by minjaesong on 16-01-15.
|
* Created by minjaesong on 16-01-15.
|
||||||
*/
|
*/
|
||||||
class Hitbox(x1: Double, y1: Double, width: Double, height: Double) {
|
class Hitbox(x1: Double, y1: Double, width: Double, height: Double) : Cloneable {
|
||||||
|
|
||||||
@Volatile var hitboxStart: Point2d
|
@Volatile var hitboxStart: Point2d
|
||||||
private set
|
private set
|
||||||
@Volatile var hitboxEnd: Point2d
|
@Volatile var hitboxEnd: Point2d
|
||||||
private set
|
private set
|
||||||
var width: Double = 0.toDouble()
|
var width: Double = 0.0
|
||||||
private set
|
private set
|
||||||
var height: Double = 0.toDouble()
|
var height: Double = 0.0
|
||||||
private set
|
private set
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -39,14 +39,16 @@ class Hitbox(x1: Double, y1: Double, width: Double, height: Double) {
|
|||||||
val pointedY: Double
|
val pointedY: Double
|
||||||
get() = hitboxEnd.y
|
get() = hitboxEnd.y
|
||||||
|
|
||||||
|
val endPointX: Double
|
||||||
|
get() = hitboxEnd.x
|
||||||
|
val endPointY: Double
|
||||||
|
get() = hitboxEnd.y
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set to the point top left
|
* Set to the point top left
|
||||||
* @param x1
|
* @param x1
|
||||||
* *
|
|
||||||
* @param y1
|
* @param y1
|
||||||
* *
|
|
||||||
* @param width
|
* @param width
|
||||||
* *
|
|
||||||
* @param height
|
* @param height
|
||||||
*/
|
*/
|
||||||
fun set(x1: Double, y1: Double, width: Double, height: Double) {
|
fun set(x1: Double, y1: Double, width: Double, height: Double) {
|
||||||
@@ -56,6 +58,13 @@ class Hitbox(x1: Double, y1: Double, width: Double, height: Double) {
|
|||||||
this.height = height
|
this.height = height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set this hitbox from other
|
||||||
|
*/
|
||||||
|
fun set(other: Hitbox) {
|
||||||
|
set(other.posX, other.posY, other.width, other.height)
|
||||||
|
}
|
||||||
|
|
||||||
fun translate(x: Double, y: Double) {
|
fun translate(x: Double, y: Double) {
|
||||||
setPosition(posX + x, posY + y)
|
setPosition(posX + x, posY + y)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class Player : ActorWithBody(), Controllable, Pocketed, Factionable, Luminous, L
|
|||||||
get() = Hitbox(0.0, 0.0, hitbox.width, hitbox.height) // use getter; dimension of the player may change by time.
|
get() = Hitbox(0.0, 0.0, hitbox.width, hitbox.height) // use getter; dimension of the player may change by time.
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@Transient internal const val ACCEL_MULT_IN_FLIGHT: Double = 0.21 // TODO air control still too 'slippery' with 0.31, lower the value!
|
@Transient internal const val ACCEL_MULT_IN_FLIGHT: Double = 0.21
|
||||||
@Transient internal const val WALK_ACCEL_BASE: Double = 0.67
|
@Transient internal const val WALK_ACCEL_BASE: Double = 0.67
|
||||||
|
|
||||||
@Transient const val PLAYER_REF_ID: Int = 0x51621D
|
@Transient const val PLAYER_REF_ID: Int = 0x51621D
|
||||||
@@ -93,6 +93,7 @@ class Player : ActorWithBody(), Controllable, Pocketed, Factionable, Luminous, L
|
|||||||
isVisible = true
|
isVisible = true
|
||||||
referenceID = PLAYER_REF_ID // forcibly set ID
|
referenceID = PLAYER_REF_ID // forcibly set ID
|
||||||
super.setDensity(BASE_DENSITY)
|
super.setDensity(BASE_DENSITY)
|
||||||
|
collisionType = KINEMATIC
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun update(gc: GameContainer, delta: Int) {
|
override fun update(gc: GameContainer, delta: Int) {
|
||||||
|
|||||||
@@ -488,7 +488,7 @@ object LightmapRenderer {
|
|||||||
* @param brighten (-1.0 - 1.0) negative means darkening
|
* @param brighten (-1.0 - 1.0) negative means darkening
|
||||||
* @return processed colour
|
* @return processed colour
|
||||||
*/
|
*/
|
||||||
fun brightenUniform(data: Int, brighten: Float): Int {
|
fun alterBrightnessUniform(data: Int, brighten: Float): Int {
|
||||||
val modifier = if (brighten < 0)
|
val modifier = if (brighten < 0)
|
||||||
constructRGBFromFloat(-brighten, -brighten, -brighten)
|
constructRGBFromFloat(-brighten, -brighten, -brighten)
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -10,46 +10,68 @@ import net.torvald.terrarum.mapdrawer.LightmapRenderer
|
|||||||
* Created by minjaesong on 16-06-16.
|
* Created by minjaesong on 16-06-16.
|
||||||
*/
|
*/
|
||||||
object TilePropUtil {
|
object TilePropUtil {
|
||||||
var flickerFuncX = 0 // in milliseconds; saves current status of func
|
var flickerFuncX = 0 // in milliseconds; saves current status (time) of func
|
||||||
val flickerFuncDomain = 100 // time between two noise sample, in milliseconds
|
val flickerFuncDomain = 100 // time between two noise sample, in milliseconds
|
||||||
val flickerFuncRange = 0.012f // intensity [0, 1]
|
val flickerFuncRange = 0.012f // intensity [0, 1]
|
||||||
|
|
||||||
val random = HQRNG();
|
var breathFuncX = 0
|
||||||
var funcY = 0f
|
val breathRange = 0.02f
|
||||||
|
val breathCycleDuration = 2000 // in milliseconds
|
||||||
|
|
||||||
var patternThis = getNewRandom()
|
var pulsateFuncX = 0
|
||||||
var patternNext = getNewRandom()
|
val pulsateRange = 0.034f
|
||||||
|
val pulsateCycleDuration = 500 // in milliseconds
|
||||||
|
|
||||||
|
val random = HQRNG();
|
||||||
|
|
||||||
|
var flickerPatternThis = getNewRandom()
|
||||||
|
var flickerPatternNext = getNewRandom()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTorchFlicker(baseLum: Int): Int {
|
private fun getTorchFlicker(baseLum: Int): Int {
|
||||||
funcY = linearInterpolation1D(patternThis, patternNext,
|
val funcY = linearInterpolation1D(flickerPatternThis, flickerPatternNext,
|
||||||
flickerFuncX.toFloat() / flickerFuncDomain
|
flickerFuncX.toFloat() / flickerFuncDomain
|
||||||
)
|
)
|
||||||
|
|
||||||
return LightmapRenderer.brightenUniform(baseLum, funcY)
|
return LightmapRenderer.alterBrightnessUniform(baseLum, funcY)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSlowBreath(baseLum: Int): Int {
|
private fun getSlowBreath(baseLum: Int): Int {
|
||||||
return baseLum
|
val funcY = FastMath.sin(FastMath.PI * breathFuncX / breathCycleDuration) * breathRange
|
||||||
|
|
||||||
|
return LightmapRenderer.alterBrightnessUniform(baseLum, funcY)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPulsate(baseLum: Int): Int {
|
private fun getPulsate(baseLum: Int): Int {
|
||||||
return baseLum
|
val funcY = FastMath.sin(FastMath.PI * pulsateFuncX / pulsateCycleDuration) * pulsateRange
|
||||||
|
|
||||||
|
return LightmapRenderer.alterBrightnessUniform(baseLum, funcY)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun dynamicLumFuncTickClock() {
|
internal fun dynamicLumFuncTickClock() {
|
||||||
if (Terrarum.appgc.fps > 0)
|
// FPS-time compensation
|
||||||
|
if (Terrarum.appgc.fps > 0) {
|
||||||
flickerFuncX += 1000 / Terrarum.appgc.fps
|
flickerFuncX += 1000 / Terrarum.appgc.fps
|
||||||
|
breathFuncX += 1000 / Terrarum.appgc.fps
|
||||||
|
pulsateFuncX += 1000 / Terrarum.appgc.fps
|
||||||
|
}
|
||||||
|
|
||||||
|
// flicker-related vars
|
||||||
if (flickerFuncX > flickerFuncDomain) {
|
if (flickerFuncX > flickerFuncDomain) {
|
||||||
flickerFuncX -= flickerFuncDomain
|
flickerFuncX -= flickerFuncDomain
|
||||||
|
|
||||||
patternThis = patternNext
|
flickerPatternThis = flickerPatternNext
|
||||||
patternNext = getNewRandom()
|
flickerPatternNext = getNewRandom()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// breath-related vars
|
||||||
|
if (breathFuncX > breathCycleDuration) breathFuncX -= breathCycleDuration
|
||||||
|
|
||||||
|
// pulsate-related vars
|
||||||
|
if (pulsateFuncX > pulsateCycleDuration) pulsateFuncX -= pulsateCycleDuration
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNewRandom() = random.nextFloat().times(2).minus(1f) * flickerFuncRange
|
private fun getNewRandom() = random.nextFloat().times(2).minus(1f) * flickerFuncRange
|
||||||
|
|||||||
@@ -123,7 +123,7 @@
|
|||||||
## Notes ##
|
## Notes ##
|
||||||
|
|
||||||
# Friction: 0: frictionless, <16: slippery, 16: regular, >16: sticky
|
# Friction: 0: frictionless, <16: slippery, 16: regular, >16: sticky
|
||||||
# Opacity/Lumcolor: 30-bit RGB
|
# Opacity/Lumcolor: 30-bit RGB. Light diffusers have a value of ZERO.
|
||||||
# Solid: whether the tile has full collision
|
# Solid: whether the tile has full collision
|
||||||
# movr: Movement resistance, (walkspeedmax) / (1 + (n/16)), 16 halves movement speed
|
# movr: Movement resistance, (walkspeedmax) / (1 + (n/16)), 16 halves movement speed
|
||||||
# dsty: density. As we are putting water an 1000, it is identical to specific gravity. [g/l]
|
# dsty: density. As we are putting water an 1000, it is identical to specific gravity. [g/l]
|
||||||
|
|||||||
|
Can't render this file because it contains an unexpected character in line 1 and column 18.
|
@@ -66,10 +66,10 @@ import org.dyn4j.Epsilon
|
|||||||
class Vector2 {
|
class Vector2 {
|
||||||
|
|
||||||
/** The magnitude of the x component of this [Vector2] */
|
/** The magnitude of the x component of this [Vector2] */
|
||||||
var x: Double = 0.toDouble()
|
var x: Double = 0.0
|
||||||
|
|
||||||
/** The magnitude of the y component of this [Vector2] */
|
/** The magnitude of the y component of this [Vector2] */
|
||||||
var y: Double = 0.toDouble()
|
var y: Double = 0.0
|
||||||
|
|
||||||
/** Default constructor. */
|
/** Default constructor. */
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 503 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 497 KiB |
Reference in New Issue
Block a user