mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-06 08:38:30 +09:00
Compare commits
3 Commits
delta_t_aw
...
delta_t_aw
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aef601e9b8 | ||
|
|
88db71f780 | ||
|
|
ded9cb1a10 |
@@ -7,11 +7,11 @@ import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.collections.HashSet
|
||||
|
||||
data class Joint(val name: String, val position: ADPropertyObject.Vector2i) {
|
||||
internal data class Joint(val name: String, val position: ADPropertyObject.Vector2i) {
|
||||
override fun toString() = "$name $position"
|
||||
}
|
||||
|
||||
data class Skeleton(val name: String, val joints: List<Joint>) {
|
||||
internal data class Skeleton(val name: String, val joints: List<Joint>) {
|
||||
override fun toString() = "$name=$joints"
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@ data class Skeleton(val name: String, val joints: List<Joint>) {
|
||||
* @param frames number of frames this animation has
|
||||
* @param skeleton list of joints to be transformed
|
||||
*/
|
||||
data class Animation(val name: String, val delay: Float, val row: Int, val frames: Int, val skeleton: Skeleton) {
|
||||
internal data class Animation(val name: String, val delay: Float, val row: Int, val frames: Int, val skeleton: Skeleton) {
|
||||
override fun toString() = "$name delay: $delay, row: $row, frames: $frames, skeleton: ${skeleton.name}"
|
||||
}
|
||||
|
||||
/** Later the 'translate' can be changed so that it represents affine transformation (Matrix2d) */
|
||||
data class Transform(val joint: Joint, val translate: ADPropertyObject.Vector2i) {
|
||||
internal data class Transform(val joint: Joint, val translate: ADPropertyObject.Vector2i) {
|
||||
override fun toString() = "$joint transform: $translate"
|
||||
}
|
||||
|
||||
@@ -41,11 +41,11 @@ class ADProperties {
|
||||
lateinit var bodyparts: List<String>; private set
|
||||
lateinit var bodypartFiles: List<String>; private set
|
||||
/** properties that are being used as skeletons (SKELETON_STAND) */
|
||||
lateinit var skeletons: HashMap<String, Skeleton>; private set
|
||||
internal lateinit var skeletons: HashMap<String, Skeleton>; private set
|
||||
/** properties that are recognised as animations (ANIM_RUN, ANIM)IDLE) */
|
||||
lateinit var animations: HashMap<String, Animation>; private set
|
||||
internal lateinit var animations: HashMap<String, Animation>; private set
|
||||
/** an "animation frame" property (ANIM_RUN_1, ANIM_RUN_2) */
|
||||
lateinit var transforms: HashMap<String, List<Transform>>; private set
|
||||
internal lateinit var transforms: HashMap<String, List<Transform>>; private set
|
||||
|
||||
private val reservedProps = listOf("SPRITESHEET", "EXTENSION")
|
||||
private val animMustContain = listOf("DELAY", "ROW", "SKELETON")
|
||||
@@ -56,7 +56,7 @@ class ADProperties {
|
||||
var frameHeight: Int = -1; private set
|
||||
var originX: Int = -1; private set
|
||||
var originY: Int = -1; private set
|
||||
val origin: ADPropertyObject.Vector2i
|
||||
internal val origin: ADPropertyObject.Vector2i
|
||||
get() = ADPropertyObject.Vector2i(originX, originY)
|
||||
|
||||
private val animFrameSuffixRegex = Regex("""_[0-9]+""")
|
||||
@@ -209,11 +209,11 @@ class ADProperties {
|
||||
fun toFilename(partName: String) =
|
||||
"${this.baseFilename}${partName.toLowerCase()}${this.extension}"
|
||||
|
||||
fun getAnimByFrameName(frameName: String) = animations[getAnimNameFromFrame(frameName)]!!
|
||||
fun getFrameNumberFromName(frameName: String) = frameName.substring(frameName.lastIndexOf('_') + 1 until frameName.length).toInt()
|
||||
internal fun getAnimByFrameName(frameName: String) = animations[getAnimNameFromFrame(frameName)]!!
|
||||
internal fun getFrameNumberFromName(frameName: String) = frameName.substring(frameName.lastIndexOf('_') + 1 until frameName.length).toInt()
|
||||
|
||||
fun getSkeleton(name: String) = skeletons[name]!!
|
||||
fun getTransform(name: String) = transforms[name]!!
|
||||
internal fun getSkeleton(name: String) = skeletons[name]!!
|
||||
internal fun getTransform(name: String) = transforms[name]!!
|
||||
|
||||
private fun getAnimNameFromFrame(s: String) = s.substring(0 until s.lastIndexOf('_'))
|
||||
|
||||
@@ -271,7 +271,7 @@ class ADPropertyObject(propertyRaw: String) {
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal companion object {
|
||||
private val floatRegex = Regex("""-?[0-9]+(\.[0-9]*)?""")
|
||||
private val ivec2Regex = Regex("""-?[0-9]+,-?[0-9]+""")
|
||||
private val variableInputSepRegex = Regex(""" +""")
|
||||
@@ -292,7 +292,7 @@ class ADPropertyObject(propertyRaw: String) {
|
||||
fun isADstring(property: String) = !isADvariable(property)
|
||||
}
|
||||
|
||||
data class Vector2i(var x: Int, var y: Int) {
|
||||
internal data class Vector2i(var x: Int, var y: Int) {
|
||||
override fun toString() = "($x, $y)"
|
||||
|
||||
operator fun plus(other: Vector2i) = Vector2i(this.x + other.x, this.y + other.y)
|
||||
|
||||
@@ -89,7 +89,7 @@ object AssembleSheetPixmap {
|
||||
|
||||
}
|
||||
|
||||
object AssembleFrameBase {
|
||||
internal object AssembleFrameBase {
|
||||
/**
|
||||
* Returns joints list with tranform applied.
|
||||
* @param skeleton list of joints
|
||||
|
||||
@@ -207,6 +207,8 @@ public class AppLoader implements ApplicationListener {
|
||||
Gdx.gl20.glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
public static final double UPDATE_RATE = 1.0 / 61.0; // TODO set it like 1/100, because apparent framerate is limited by update rate
|
||||
|
||||
private float loadTimer = 0f;
|
||||
private final float showupTime = 100f / 1000f;
|
||||
|
||||
@@ -235,7 +237,7 @@ public class AppLoader implements ApplicationListener {
|
||||
updateFullscreenQuad(appConfig.width, appConfig.height);
|
||||
}
|
||||
|
||||
private static double _kalman_xhat_k = 1.0 / 60.0;
|
||||
private static double _kalman_xhat_k = UPDATE_RATE;
|
||||
private static double _kalman_return_value = _kalman_xhat_k;
|
||||
private static double _kalman_p_k = 1.0;
|
||||
private static final double _kalman_R = 0.2; // 0.2: empirical value
|
||||
@@ -254,7 +256,7 @@ public class AppLoader implements ApplicationListener {
|
||||
}
|
||||
|
||||
public static void resetDeltaSmoothingHistory() {
|
||||
_kalman_xhat_k = 1.0 / 60.0;
|
||||
_kalman_xhat_k = UPDATE_RATE;
|
||||
_kalman_p_k = 1.0;
|
||||
}
|
||||
|
||||
@@ -365,7 +367,7 @@ public class AppLoader implements ApplicationListener {
|
||||
}
|
||||
// draw the screen
|
||||
else {
|
||||
screen.render(((float) getSmoothDelta()));
|
||||
screen.render((float) UPDATE_RATE);
|
||||
}
|
||||
|
||||
// nested FBOs are just not a thing in GL!
|
||||
|
||||
@@ -74,22 +74,12 @@ object Terrarum : Screen {
|
||||
get() = HEIGHT.ushr(1)
|
||||
|
||||
/**
|
||||
* To be used with physics simulator
|
||||
* To be used with physics simulator. This is a magic number.
|
||||
*/
|
||||
val PHYS_TIME_FRAME: Double = 26.0 + (2.0 / 3.0)
|
||||
val PHYS_CONST_MULT: Double = 60.0 / (26.0 + (2.0 / 3.0))
|
||||
val PHYS_REF_FPS: Double = 60.0
|
||||
// 26.0 + (2.0 / 3.0) // lower value == faster gravity response (IT WON'T HOTSWAP!!)
|
||||
// protip: using METER, game unit and SI unit will have same number
|
||||
|
||||
/**
|
||||
* To be used with render, to achieve smooth frame drawing
|
||||
* TARGET_INTERNAL_FPS > PHYS_TIME_FRAME for smooth frame drawing
|
||||
*/
|
||||
val TARGET_INTERNAL_FPS: Double = 60.0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var previousScreen: Screen? = null // to be used with temporary states like StateMonitorCheck
|
||||
@@ -483,13 +473,9 @@ object Terrarum : Screen {
|
||||
get() = Gdx.input.x
|
||||
inline val mouseScreenY: Int
|
||||
get() = Gdx.input.y
|
||||
/** Bigger than 1.0 */
|
||||
/** Delta converted as it it was a FPS */
|
||||
inline val updateRate: Double
|
||||
get() = 1.0 / AppLoader.getSmoothDelta()
|
||||
/** Smaller than 1.0 */
|
||||
val renderRate = 1.0 / TARGET_INTERNAL_FPS
|
||||
val renderRateStr = TARGET_INTERNAL_FPS.toString()
|
||||
|
||||
/**
|
||||
* Usage:
|
||||
*
|
||||
@@ -738,6 +724,7 @@ fun absMax(left: Double, right: Double): Double {
|
||||
}
|
||||
}
|
||||
|
||||
fun Double.magnSqr() = if (this >= 0.0) this.sqr() else -this.sqr()
|
||||
fun Double.sign() = if (this > 0.0) 1.0 else if (this < 0.0) -1.0 else 0.0
|
||||
fun interpolateLinear(scale: Double, startValue: Double, endValue: Double): Double {
|
||||
if (startValue == endValue) {
|
||||
|
||||
@@ -199,23 +199,11 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
|
||||
private val introUncoverTime: Second = 0.3f
|
||||
private var introUncoverDeltaCounter = 0f
|
||||
private var updateDeltaCounter = 0.0
|
||||
protected val renderRate = Terrarum.renderRate
|
||||
|
||||
override fun render(delta: Float) {
|
||||
// async update
|
||||
updateDeltaCounter += delta
|
||||
if (delta < 1f / 10f) { // discard async if measured FPS <= 10
|
||||
var updateTries = 0
|
||||
while (updateDeltaCounter >= renderRate && updateTries < 6) {
|
||||
updateScreen(delta)
|
||||
updateDeltaCounter -= renderRate
|
||||
updateTries++
|
||||
}
|
||||
}
|
||||
else {
|
||||
updateScreen(delta)
|
||||
}
|
||||
// TODO async update
|
||||
|
||||
updateScreen(delta)
|
||||
// render? just do it anyway
|
||||
renderScreen()
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import org.dyn4j.geometry.Vector2
|
||||
import java.util.*
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
/**
|
||||
@@ -95,15 +94,13 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
true
|
||||
)
|
||||
|
||||
private val nullVec = Vector2(0.0, 0.0)
|
||||
|
||||
/**
|
||||
* TODO Pixels per 1/60 seconds.
|
||||
* Unit: Pixels per 1/60 (or AppLoader.UPDATE_RATE) seconds.
|
||||
*
|
||||
* When the engine resolves this value, the framerate must be accounted for. E.g.:
|
||||
* 3.0 is resolved as 3.0 if FPS is 60, but the same value should be resolved as 6.0 if FPS is 30.
|
||||
* v_resolved = v * (60/FPS) or, v * (60 * delta_t)
|
||||
* (Use this code verbatim: '(Terrarum.PHYS_REF_FPS * delta)', for easy grep later)
|
||||
* (Use this code verbatim: '(Terrarum.PHYS_REF_FPS * delta)')
|
||||
*
|
||||
*
|
||||
* Elevators/Movingwalks/etc.: edit hitbox manually!
|
||||
@@ -112,20 +109,21 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
* Acceleration: used in code like:
|
||||
* veloY += 3.0
|
||||
* +3.0 is acceleration. You __accumulate__ acceleration to the velocity.
|
||||
*
|
||||
* V for Velocity!
|
||||
*/
|
||||
internal val externalV = Vector2(0.0, 0.0)
|
||||
|
||||
internal val externalA = Vector2(0.0, 0.0)
|
||||
|
||||
@Transient private val VELO_HARD_LIMIT = 100.0
|
||||
|
||||
/**
|
||||
* Unit: Pixels per 1/60 (or AppLoader.UPDATE_RATE) seconds.
|
||||
*
|
||||
* for "Controllable" actors
|
||||
*
|
||||
* V for Velocity!
|
||||
*/
|
||||
var controllerMoveV: Vector2? = if (this is Controllable) Vector2() else null
|
||||
|
||||
|
||||
|
||||
var controllerV: Vector2? = if (this is Controllable) Vector2() else null
|
||||
|
||||
// not sure we need this...
|
||||
//var jumpable = true // this is kind of like "semaphore"
|
||||
@@ -226,7 +224,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
* meter to pixel : 24/FPS
|
||||
*/
|
||||
private val gravitation: Vector2
|
||||
get() = world?.gravitation ?: Vector2(0.0, 0.31)
|
||||
get() = world?.gravitation ?: Vector2(0.0, 9.8)
|
||||
@Transient val DRAG_COEFF_DEFAULT = 1.2
|
||||
/** Drag coefficient. Parachutes have much higher value than bare body (1.2) */
|
||||
var dragCoefficient: Double
|
||||
@@ -356,23 +354,17 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
* @param acc : Acceleration in Vector2
|
||||
*/
|
||||
fun applyForce(acc: Vector2) {
|
||||
externalA += acc
|
||||
externalV += acc * speedMultByTile
|
||||
}
|
||||
|
||||
private val bounceDampenVelThreshold = 0.5
|
||||
|
||||
override fun update(fdelta: Float) {
|
||||
override fun update(delta: Float) {
|
||||
if (isUpdate && !flagDespawn) {
|
||||
|
||||
//val delta = Gdx.graphics.rawDeltaTime.toDouble()
|
||||
val delta = AppLoader.getSmoothDelta()
|
||||
//println("${Gdx.graphics.rawDeltaTime.toDouble()}\t${AppLoader.getSmoothDelta()}")
|
||||
|
||||
|
||||
if (!assertPrinted) assertInit()
|
||||
|
||||
if (sprite != null) sprite!!.update(fdelta)
|
||||
if (spriteGlow != null) spriteGlow!!.update(fdelta)
|
||||
if (sprite != null) sprite!!.update(delta)
|
||||
if (spriteGlow != null) spriteGlow!!.update(delta)
|
||||
|
||||
// make NoClip work for player
|
||||
if (true) {//this == Terrarum.ingame!!.actorNowPlaying) {
|
||||
@@ -418,11 +410,11 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
* This body is NON-STATIC and the other body is STATIC
|
||||
*/
|
||||
if (!isNoCollideWorld) {
|
||||
displaceHitbox(delta)
|
||||
displaceHitbox(delta.toDouble())
|
||||
}
|
||||
else {
|
||||
val vecSum = externalV + (controllerMoveV ?: Vector2(0.0, 0.0))
|
||||
hitbox.translate(vecSum * (Terrarum.PHYS_REF_FPS * delta))
|
||||
val vecSum = externalV + (controllerV ?: Vector2(0.0, 0.0))
|
||||
hitbox.translate(vecSum)
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
@@ -504,12 +496,12 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
}
|
||||
}*/
|
||||
|
||||
fun getDrag(delta: Double, externalForce: Vector2): Vector2 {
|
||||
fun getDrag(delta: Float, externalForce: Vector2): Vector2 {
|
||||
/**
|
||||
* weight; gravitational force in action
|
||||
* W = mass * G (9.8 [m/s^2])
|
||||
*/
|
||||
val W: Vector2 = gravitation// * Terrarum.PHYS_TIME_FRAME.toDouble()
|
||||
val W: Vector2 = gravitation * Terrarum.PHYS_TIME_FRAME.toDouble()
|
||||
/**
|
||||
* Area
|
||||
*/
|
||||
@@ -518,12 +510,11 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
* Drag of atmosphere
|
||||
* D = Cd (drag coefficient) * 0.5 * rho (density) * V^2 (velocity sqr) * A (area)
|
||||
*/
|
||||
val V = externalV + controllerMoveV
|
||||
val D: Vector2 = V.magnSqr() * dragCoefficient * 0.5 * A// * tileDensityFluid.toDouble()
|
||||
val D: Vector2 = Vector2(externalForce.x.magnSqr(), externalForce.y.magnSqr()) * dragCoefficient * 0.5 * A// * tileDensityFluid.toDouble()
|
||||
|
||||
val final: Vector2 = (W - D)
|
||||
val V: Vector2 = (W - D) / Terrarum.PHYS_TIME_FRAME * SI_TO_GAME_ACC
|
||||
|
||||
return final
|
||||
return V
|
||||
|
||||
// FIXME v * const, where const = 1.0 for FPS=60, sqrt(2.0) for FPS=30, etc.
|
||||
// this is "close enough" solution and not perfect.
|
||||
@@ -544,14 +535,12 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
*
|
||||
* Apply only if not grounded; normal force is precessed separately.
|
||||
*/
|
||||
private fun applyGravitation(delta: Double) {
|
||||
private fun applyGravitation(delta: Float) {
|
||||
|
||||
if (!isNoSubjectToGrav && !(gravitation.y > 0 && walledBottom || gravitation.y < 0 && walledTop)) {
|
||||
//applyForce(getDrag(delta, externalV))
|
||||
|
||||
//applyForce(gravitation)
|
||||
|
||||
applyForce(Vector2(0.0, 0.5) / (Terrarum.PHYS_REF_FPS * delta).pow(0.5))
|
||||
//if (!isWalled(hitbox, COLLIDING_BOTTOM)) {
|
||||
applyForce(getDrag(delta, externalV))
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -607,297 +596,287 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
//
|
||||
// ((comments)) [Label]
|
||||
|
||||
if (world == null) {
|
||||
return
|
||||
}
|
||||
if (world != null) {
|
||||
|
||||
fun debug1(wut: Any?) {
|
||||
// vvvvv set it true to make debug print work
|
||||
if (true) printdbg(this, wut)
|
||||
}
|
||||
|
||||
fun debug2(wut: Any?) {
|
||||
// vvvvv set it true to make debug print work
|
||||
if (false) printdbg(this, wut)
|
||||
}
|
||||
|
||||
fun debug3(wut: Any?) {
|
||||
// vvvvv set it true to make debug print work
|
||||
if (false) printdbg(this, wut)
|
||||
}
|
||||
|
||||
fun debug4(wut: Any?) {
|
||||
// vvvvv set it true to make debug print work
|
||||
if (false) printdbg(this, wut)
|
||||
}
|
||||
|
||||
fun BlockAddress.isFeetTile(hitbox: Hitbox): Boolean {
|
||||
val (x, y) = LandUtil.resolveBlockAddr(world!!, this)
|
||||
val newTilewiseHitbox = Hitbox.fromTwoPoints(
|
||||
hitbox.startX.div(TILE_SIZE).floor(),
|
||||
hitbox.startY.div(TILE_SIZE).floor(),
|
||||
hitbox.endX.minus(0.00001).div(TILE_SIZE).floor(),
|
||||
hitbox.endY.minus(0.00001).div(TILE_SIZE).floor(),
|
||||
true
|
||||
)
|
||||
|
||||
// offset 1 pixel to the down so that friction would work
|
||||
return (y == hitbox.endY.plus(1.0).div(TILE_SIZE).floorInt()) && // copied from forEachFeetTileNum
|
||||
(x in newTilewiseHitbox.startX.toInt()..newTilewiseHitbox.endX.toInt()) // copied from forEachOccupyingTilePos
|
||||
}
|
||||
|
||||
fun Double.modTile() = this.toInt().div(TILE_SIZE).times(TILE_SIZE)
|
||||
fun Double.modTileDelta() = this - this.modTile()
|
||||
|
||||
|
||||
// displacement relative to the original position
|
||||
// x = x_0 + v_0 t + 0.5 a t^2 // v_0: old velocity
|
||||
// x = x_0 + v t - 0.5 a t^2 // v: current velocity
|
||||
val t = (Terrarum.PHYS_REF_FPS * delta)
|
||||
val v0 = externalV + (controllerMoveV ?: nullVec)
|
||||
v0 += externalA * t
|
||||
val displacement = v0 * t - externalA * (0.5 * t * t)
|
||||
val ccdSteps = minOf(16, (displacement.magnitudeSquared / TILE_SIZE.sqr()).floorInt() + 1) // adaptive
|
||||
|
||||
|
||||
// * NEW idea: wall pushes the actors (ref. SM64 explained by dutch pancake) *
|
||||
// direction to push is determined by the velocity
|
||||
// proc:
|
||||
// 10 I detect being walled and displace myself
|
||||
// 11 There's 16 possible case so work all 16 (some can be merged obviously)
|
||||
// 12 Amount of displacement can be obtained with modTileDelta()
|
||||
// 13 isWalled() is confirmed to be working
|
||||
// 20 sixteenStep may be optional, I think, but it'd be good to have
|
||||
|
||||
// ignore MOST of the codes below (it might be possible to recycle the structure??)
|
||||
// and the idea above has not yet implemented, and may never will. --Torvald, 2018-12-30
|
||||
|
||||
val sixteenStep = (0..ccdSteps).map { hitbox.clone().translate(displacement * (it / ccdSteps.toDouble())) } // zeroth step is for special condition
|
||||
|
||||
var collidingStep: Int? = null
|
||||
|
||||
for (step in 1..ccdSteps) {
|
||||
|
||||
val stepBox = sixteenStep[step]
|
||||
|
||||
forEachOccupyingTilePos(stepBox) {
|
||||
val tileCoord = LandUtil.resolveBlockAddr(world!!, it)
|
||||
val tile = world!!.getTileFromTerrain(tileCoord.first, tileCoord.second) ?: Block.STONE
|
||||
|
||||
if (shouldICollideWithThis(tile) || (it.isFeetTile(stepBox) && shouldICollideWithThisFeet(tile))) {
|
||||
collidingStep = step
|
||||
}
|
||||
fun debug1(wut: Any?) {
|
||||
// vvvvv set it true to make debug print work
|
||||
if (true) printdbg(this, wut)
|
||||
}
|
||||
|
||||
if (collidingStep != null) break
|
||||
}
|
||||
|
||||
|
||||
val COLL_LEFTSIDE = 1
|
||||
val COLL_BOTTOMSIDE = 2
|
||||
val COLL_RIGHTSIDE = 4
|
||||
val COLL_TOPSIDE = 8
|
||||
|
||||
var bounceX = false
|
||||
var bounceY = false
|
||||
var zeroX = false
|
||||
var zeroY = false
|
||||
// collision NOT detected
|
||||
if (collidingStep == null) {
|
||||
hitbox.translate(displacement)
|
||||
// grounded = false
|
||||
}
|
||||
// collision detected
|
||||
else {
|
||||
debug1("== Collision step: $collidingStep / $ccdSteps")
|
||||
|
||||
|
||||
val newHitbox = hitbox.reassign(sixteenStep[collidingStep!!])
|
||||
|
||||
var selfCollisionStatus = 0
|
||||
if (isWalled(newHitbox, COLLIDING_LEFT)) selfCollisionStatus += COLL_LEFTSIDE // 1
|
||||
if (isWalled(newHitbox, COLLIDING_RIGHT)) selfCollisionStatus += COLL_RIGHTSIDE // 4
|
||||
if (isWalled(newHitbox, COLLIDING_TOP)) selfCollisionStatus += COLL_TOPSIDE // 8
|
||||
if (isWalled(newHitbox, COLLIDING_BOTTOM)) selfCollisionStatus += COLL_BOTTOMSIDE // 2
|
||||
|
||||
// fixme UP and RIGHT && LEFT and DOWN bug
|
||||
|
||||
when (selfCollisionStatus) {
|
||||
0 -> {
|
||||
debug1("[ActorWBMovable] Contradiction -- collision detected by CCD, but isWalled() says otherwise")
|
||||
}
|
||||
5 -> {
|
||||
zeroX = true
|
||||
}
|
||||
10 -> {
|
||||
zeroY = true
|
||||
}
|
||||
15 -> {
|
||||
newHitbox.reassign(sixteenStep[0]); zeroX = true; zeroY = true
|
||||
}
|
||||
// one-side collision
|
||||
1, 11 -> {
|
||||
newHitbox.translatePosX(TILE_SIZE - newHitbox.startX.modTileDelta()); bounceX = true
|
||||
}
|
||||
4, 14 -> {
|
||||
newHitbox.translatePosX(-newHitbox.endX.modTileDelta()); bounceX = true
|
||||
}
|
||||
8, 13 -> {
|
||||
newHitbox.translatePosY(TILE_SIZE - newHitbox.startY.modTileDelta()); bounceY = true
|
||||
}
|
||||
2, 7 -> {
|
||||
newHitbox.translatePosY(-newHitbox.endY.modTileDelta()); bounceY = true
|
||||
}
|
||||
fun debug2(wut: Any?) {
|
||||
// vvvvv set it true to make debug print work
|
||||
if (false) printdbg(this, wut)
|
||||
}
|
||||
|
||||
|
||||
// fire Collision Event with one/two/three-side collision
|
||||
// for the ease of writing, this jumptable is separated from above.
|
||||
when (selfCollisionStatus) {
|
||||
// TODO compose CollisionInfo and fire collided()
|
||||
fun debug3(wut: Any?) {
|
||||
// vvvvv set it true to make debug print work
|
||||
if (false) printdbg(this, wut)
|
||||
}
|
||||
|
||||
fun debug4(wut: Any?) {
|
||||
// vvvvv set it true to make debug print work
|
||||
if (false) printdbg(this, wut)
|
||||
}
|
||||
|
||||
// two-side collision
|
||||
if (selfCollisionStatus in listOf(3, 6, 9, 12)) {
|
||||
debug1("twoside collision $selfCollisionStatus")
|
||||
|
||||
// !! this code is based on Dyn4j Vector's coord system; V(1,0) -> 0, V(0,1) -> pi, V(0,-1) -> -pi !! //
|
||||
|
||||
// we can use selfCollisionStatus to tell which of those four side we care
|
||||
|
||||
// points to the EDGE of the tile in world dimension (don't use this directly to get tilewise coord!!)
|
||||
val offendingTileWorldX = if (selfCollisionStatus in listOf(6, 12))
|
||||
newHitbox.endX.div(TILE_SIZE).floor() * TILE_SIZE - 0.00001
|
||||
else
|
||||
newHitbox.startX.div(TILE_SIZE).ceil() * TILE_SIZE
|
||||
|
||||
// points to the EDGE of the tile in world dimension (don't use this directly to get tilewise coord!!)
|
||||
val offendingTileWorldY = if (selfCollisionStatus in listOf(3, 6))
|
||||
newHitbox.endY.div(TILE_SIZE).floor() * TILE_SIZE - 0.00001
|
||||
else
|
||||
newHitbox.startY.div(TILE_SIZE).ceil() * TILE_SIZE
|
||||
|
||||
val offendingHitboxPointX = if (selfCollisionStatus in listOf(6, 12))
|
||||
newHitbox.endX
|
||||
else
|
||||
newHitbox.startX
|
||||
|
||||
val offendingHitboxPointY = if (selfCollisionStatus in listOf(3, 6))
|
||||
newHitbox.endY
|
||||
else
|
||||
newHitbox.startY
|
||||
|
||||
|
||||
|
||||
val angleOfIncidence =
|
||||
if (selfCollisionStatus in listOf(3, 9))
|
||||
displacement.direction.toPositiveRad()
|
||||
else
|
||||
displacement.direction
|
||||
|
||||
val angleThreshold =
|
||||
if (selfCollisionStatus in listOf(3, 9))
|
||||
(Vector2(offendingHitboxPointX, offendingHitboxPointY) -
|
||||
Vector2(offendingTileWorldX, offendingTileWorldY)).direction.toPositiveRad()
|
||||
else
|
||||
(Vector2(offendingHitboxPointX, offendingHitboxPointY) -
|
||||
Vector2(offendingTileWorldX, offendingTileWorldY)).direction
|
||||
|
||||
|
||||
debug1("vectorSum: $displacement, vectorDirRaw: ${displacement.direction / Math.PI}pi")
|
||||
debug1("incidentAngle: ${angleOfIncidence / Math.PI}pi, threshold: ${angleThreshold / Math.PI}pi")
|
||||
|
||||
|
||||
val displacementAbs = Vector2(
|
||||
(offendingTileWorldX - offendingHitboxPointX).abs(),
|
||||
(offendingTileWorldY - offendingHitboxPointY).abs()
|
||||
fun BlockAddress.isFeetTile(hitbox: Hitbox): Boolean {
|
||||
val (x, y) = LandUtil.resolveBlockAddr(world!!, this)
|
||||
val newTilewiseHitbox = Hitbox.fromTwoPoints(
|
||||
hitbox.startX.div(TILE_SIZE).floor(),
|
||||
hitbox.startY.div(TILE_SIZE).floor(),
|
||||
hitbox.endX.minus(0.00001).div(TILE_SIZE).floor(),
|
||||
hitbox.endY.minus(0.00001).div(TILE_SIZE).floor(),
|
||||
true
|
||||
)
|
||||
|
||||
// offset 1 pixel to the down so that friction would work
|
||||
return (y == hitbox.endY.plus(1.0).div(TILE_SIZE).floorInt()) && // copied from forEachFeetTileNum
|
||||
(x in newTilewiseHitbox.startX.toInt()..newTilewiseHitbox.endX.toInt()) // copied from forEachOccupyingTilePos
|
||||
}
|
||||
|
||||
// FIXME jump-thru-ceil bug on 1px-wide (the edge), case-9 collision (does not occur on case-12 coll.)
|
||||
fun Double.modTile() = this.toInt().div(TILE_SIZE).times(TILE_SIZE)
|
||||
fun Double.modTileDelta() = this - this.modTile()
|
||||
|
||||
|
||||
val displacementUnitVector =
|
||||
if (angleOfIncidence == angleThreshold)
|
||||
-displacement
|
||||
else {
|
||||
when (selfCollisionStatus) {
|
||||
3 -> if (angleOfIncidence > angleThreshold) Vector2(1.0, 0.0) else Vector2(0.0, -1.0)
|
||||
6 -> if (angleOfIncidence > angleThreshold) Vector2(0.0, -1.0) else Vector2(-1.0, 0.0)
|
||||
9 -> if (angleOfIncidence > angleThreshold) Vector2(0.0, 1.0) else Vector2(1.0, 0.0)
|
||||
12 -> if (angleOfIncidence > angleThreshold) Vector2(-1.0, 0.0) else Vector2(0.0, 1.0)
|
||||
else -> throw InternalError("Blame hardware or universe")
|
||||
val vectorSum = (externalV + controllerV)
|
||||
val ccdSteps = minOf(16, (vectorSum.magnitudeSquared / TILE_SIZE.sqr()).floorInt() + 1) // adaptive
|
||||
|
||||
|
||||
|
||||
// * NEW idea: wall pushes the actors (ref. SM64 explained by dutch pancake) *
|
||||
// direction to push is determined by the velocity
|
||||
// proc:
|
||||
// 10 I detect being walled and displace myself
|
||||
// 11 There's 16 possible case so work all 16 (some can be merged obviously)
|
||||
// 12 Amount of displacement can be obtained with modTileDelta()
|
||||
// 13 isWalled() is confirmed to be working
|
||||
// 20 sixteenStep may be optional, I think, but it'd be good to have
|
||||
|
||||
// ignore MOST of the codes below (it might be possible to recycle the structure??)
|
||||
// and the idea above has not yet implemented, and may never will. --Torvald, 2018-12-30
|
||||
|
||||
val sixteenStep = (0..ccdSteps).map { hitbox.clone().translate(vectorSum * (it / ccdSteps.toDouble())) } // zeroth step is for special condition
|
||||
|
||||
var collidingStep: Int? = null
|
||||
|
||||
for (step in 1..ccdSteps) {
|
||||
|
||||
val stepBox = sixteenStep[step]
|
||||
|
||||
forEachOccupyingTilePos(stepBox) {
|
||||
val tileCoord = LandUtil.resolveBlockAddr(world!!, it)
|
||||
val tile = world!!.getTileFromTerrain(tileCoord.first, tileCoord.second) ?: Block.STONE
|
||||
|
||||
if (shouldICollideWithThis(tile) || (it.isFeetTile(stepBox) && shouldICollideWithThisFeet(tile))) {
|
||||
collidingStep = step
|
||||
}
|
||||
}
|
||||
|
||||
if (collidingStep != null) break
|
||||
}
|
||||
|
||||
|
||||
val COLL_LEFTSIDE = 1
|
||||
val COLL_BOTTOMSIDE = 2
|
||||
val COLL_RIGHTSIDE = 4
|
||||
val COLL_TOPSIDE = 8
|
||||
|
||||
var bounceX = false
|
||||
var bounceY = false
|
||||
var zeroX = false
|
||||
var zeroY = false
|
||||
// collision NOT detected
|
||||
if (collidingStep == null) {
|
||||
hitbox.translate(vectorSum)
|
||||
// grounded = false
|
||||
}
|
||||
// collision detected
|
||||
else {
|
||||
debug1("== Collision step: $collidingStep / $ccdSteps")
|
||||
|
||||
|
||||
val newHitbox = hitbox.reassign(sixteenStep[collidingStep!!])
|
||||
|
||||
var selfCollisionStatus = 0
|
||||
if (isWalled(newHitbox, COLLIDING_LEFT)) selfCollisionStatus += COLL_LEFTSIDE // 1
|
||||
if (isWalled(newHitbox, COLLIDING_RIGHT)) selfCollisionStatus += COLL_RIGHTSIDE // 4
|
||||
if (isWalled(newHitbox, COLLIDING_TOP)) selfCollisionStatus += COLL_TOPSIDE // 8
|
||||
if (isWalled(newHitbox, COLLIDING_BOTTOM)) selfCollisionStatus += COLL_BOTTOMSIDE // 2
|
||||
|
||||
// fixme UP and RIGHT && LEFT and DOWN bug
|
||||
|
||||
when (selfCollisionStatus) {
|
||||
0 -> {
|
||||
debug1("[ActorWBMovable] Contradiction -- collision detected by CCD, but isWalled() says otherwise")
|
||||
}
|
||||
5 -> {
|
||||
zeroX = true
|
||||
}
|
||||
10 -> {
|
||||
zeroY = true
|
||||
}
|
||||
15 -> {
|
||||
newHitbox.reassign(sixteenStep[0]); zeroX = true; zeroY = true
|
||||
}
|
||||
// one-side collision
|
||||
1, 11 -> {
|
||||
newHitbox.translatePosX(TILE_SIZE - newHitbox.startX.modTileDelta()); bounceX = true
|
||||
}
|
||||
4, 14 -> {
|
||||
newHitbox.translatePosX(-newHitbox.endX.modTileDelta()); bounceX = true
|
||||
}
|
||||
8, 13 -> {
|
||||
newHitbox.translatePosY(TILE_SIZE - newHitbox.startY.modTileDelta()); bounceY = true
|
||||
}
|
||||
2, 7 -> {
|
||||
newHitbox.translatePosY(-newHitbox.endY.modTileDelta()); bounceY = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// fire Collision Event with one/two/three-side collision
|
||||
// for the ease of writing, this jumptable is separated from above.
|
||||
when (selfCollisionStatus) {
|
||||
// TODO compose CollisionInfo and fire collided()
|
||||
}
|
||||
|
||||
|
||||
// two-side collision
|
||||
if (selfCollisionStatus in listOf(3, 6, 9, 12)) {
|
||||
debug1("twoside collision $selfCollisionStatus")
|
||||
|
||||
// !! this code is based on Dyn4j Vector's coord system; V(1,0) -> 0, V(0,1) -> pi, V(0,-1) -> -pi !! //
|
||||
|
||||
// we can use selfCollisionStatus to tell which of those four side we care
|
||||
|
||||
// points to the EDGE of the tile in world dimension (don't use this directly to get tilewise coord!!)
|
||||
val offendingTileWorldX = if (selfCollisionStatus in listOf(6, 12))
|
||||
newHitbox.endX.div(TILE_SIZE).floor() * TILE_SIZE - 0.00001
|
||||
else
|
||||
newHitbox.startX.div(TILE_SIZE).ceil() * TILE_SIZE
|
||||
|
||||
// points to the EDGE of the tile in world dimension (don't use this directly to get tilewise coord!!)
|
||||
val offendingTileWorldY = if (selfCollisionStatus in listOf(3, 6))
|
||||
newHitbox.endY.div(TILE_SIZE).floor() * TILE_SIZE - 0.00001
|
||||
else
|
||||
newHitbox.startY.div(TILE_SIZE).ceil() * TILE_SIZE
|
||||
|
||||
val offendingHitboxPointX = if (selfCollisionStatus in listOf(6, 12))
|
||||
newHitbox.endX
|
||||
else
|
||||
newHitbox.startX
|
||||
|
||||
val offendingHitboxPointY = if (selfCollisionStatus in listOf(3, 6))
|
||||
newHitbox.endY
|
||||
else
|
||||
newHitbox.startY
|
||||
|
||||
|
||||
|
||||
val angleOfIncidence =
|
||||
if (selfCollisionStatus in listOf(3, 9))
|
||||
vectorSum.direction.toPositiveRad()
|
||||
else
|
||||
vectorSum.direction
|
||||
|
||||
val angleThreshold =
|
||||
if (selfCollisionStatus in listOf(3, 9))
|
||||
(Vector2(offendingHitboxPointX, offendingHitboxPointY) -
|
||||
Vector2(offendingTileWorldX, offendingTileWorldY)).direction.toPositiveRad()
|
||||
else
|
||||
(Vector2(offendingHitboxPointX, offendingHitboxPointY) -
|
||||
Vector2(offendingTileWorldX, offendingTileWorldY)).direction
|
||||
|
||||
|
||||
debug1("vectorSum: $vectorSum, vectorDirRaw: ${vectorSum.direction / Math.PI}pi")
|
||||
debug1("incidentAngle: ${angleOfIncidence / Math.PI}pi, threshold: ${angleThreshold / Math.PI}pi")
|
||||
|
||||
|
||||
val displacementAbs = Vector2(
|
||||
(offendingTileWorldX - offendingHitboxPointX).abs(),
|
||||
(offendingTileWorldY - offendingHitboxPointY).abs()
|
||||
)
|
||||
|
||||
|
||||
// FIXME jump-thru-ceil bug on 1px-wide (the edge), case-9 collision (does not occur on case-12 coll.)
|
||||
|
||||
|
||||
val displacementUnitVector =
|
||||
if (angleOfIncidence == angleThreshold)
|
||||
-vectorSum
|
||||
else {
|
||||
when (selfCollisionStatus) {
|
||||
3 -> if (angleOfIncidence > angleThreshold) Vector2(1.0, 0.0) else Vector2(0.0, -1.0)
|
||||
6 -> if (angleOfIncidence > angleThreshold) Vector2(0.0, -1.0) else Vector2(-1.0, 0.0)
|
||||
9 -> if (angleOfIncidence > angleThreshold) Vector2(0.0, 1.0) else Vector2(1.0, 0.0)
|
||||
12 -> if (angleOfIncidence > angleThreshold) Vector2(-1.0, 0.0) else Vector2(0.0, 1.0)
|
||||
else -> throw InternalError("Blame hardware or universe")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val finalDisplacement =
|
||||
if (angleOfIncidence == angleThreshold)
|
||||
displacementUnitVector
|
||||
else
|
||||
Vector2(
|
||||
displacementAbs.x * displacementUnitVector.x,
|
||||
displacementAbs.y * displacementUnitVector.y
|
||||
)
|
||||
val finalDisplacement =
|
||||
if (angleOfIncidence == angleThreshold)
|
||||
displacementUnitVector
|
||||
else
|
||||
Vector2(
|
||||
displacementAbs.x * displacementUnitVector.x,
|
||||
displacementAbs.y * displacementUnitVector.y
|
||||
)
|
||||
|
||||
newHitbox.translate(finalDisplacement)
|
||||
newHitbox.translate(finalDisplacement)
|
||||
|
||||
|
||||
debug1("displacement: $finalDisplacement")
|
||||
debug1("displacement: $finalDisplacement")
|
||||
|
||||
|
||||
// TODO: translate other axis proportionally to the incident vector
|
||||
// TODO: translate other axis proportionally to the incident vector
|
||||
|
||||
bounceX = angleOfIncidence == angleThreshold || displacementUnitVector.x != 0.0
|
||||
bounceY = angleOfIncidence == angleThreshold || displacementUnitVector.y != 0.0
|
||||
bounceX = angleOfIncidence == angleThreshold || displacementUnitVector.x != 0.0
|
||||
bounceY = angleOfIncidence == angleThreshold || displacementUnitVector.y != 0.0
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// bounce X/Y
|
||||
if (bounceX) {
|
||||
externalV.x *= elasticity
|
||||
externalA.x *= elasticity
|
||||
controllerMoveV?.let { controllerMoveV!!.x *= elasticity }
|
||||
}
|
||||
if (bounceY) {
|
||||
externalV.y *= elasticity
|
||||
externalA.y *= elasticity
|
||||
controllerMoveV?.let { controllerMoveV!!.y *= elasticity }
|
||||
}
|
||||
if (zeroX) {
|
||||
externalV.x = 0.0
|
||||
externalA.x = 0.0
|
||||
controllerMoveV?.let { controllerMoveV!!.x = 0.0 }
|
||||
}
|
||||
if (zeroY) {
|
||||
externalV.y = 0.0
|
||||
externalA.y = 0.0
|
||||
controllerMoveV?.let { controllerMoveV!!.y = 0.0 }
|
||||
}
|
||||
// bounce X/Y
|
||||
if (bounceX) {
|
||||
externalV.x *= elasticity
|
||||
controllerV?.let { controllerV!!.x *= elasticity }
|
||||
}
|
||||
if (bounceY) {
|
||||
externalV.y *= elasticity
|
||||
controllerV?.let { controllerV!!.y *= elasticity }
|
||||
}
|
||||
if (zeroX) {
|
||||
externalV.x = 0.0
|
||||
controllerV?.let { controllerV!!.x = 0.0 }
|
||||
}
|
||||
if (zeroY) {
|
||||
externalV.y = 0.0
|
||||
controllerV?.let { controllerV!!.y = 0.0 }
|
||||
}
|
||||
|
||||
|
||||
hitbox.reassign(newHitbox)
|
||||
hitbox.reassign(newHitbox)
|
||||
|
||||
|
||||
// slam-into-whatever damage (such dirty; much hack; wow)
|
||||
// vvvv hack (supposed to be 1.0) vvv 50% hack
|
||||
val collisionDamage = mass * (displacement.magnitude / (10.0 / Terrarum.PHYS_TIME_FRAME).sqr()) / fallDamageDampening.sqr() * GAME_TO_SI_ACC
|
||||
// kg * m / s^2 (mass * acceleration), acceleration -> (vectorMagn / (0.01)^2).gameToSI()
|
||||
if (collisionDamage != 0.0) debug1("Collision damage: $collisionDamage N")
|
||||
// FIXME instead of 0.5mv^2, we can model after "change of velocity (aka accel)", just as in real-life; big change of accel on given unit time is what kills
|
||||
// slam-into-whatever damage (such dirty; much hack; wow)
|
||||
// vvvv hack (supposed to be 1.0) vvv 50% hack
|
||||
val collisionDamage = mass * (vectorSum.magnitude / (10.0 / Terrarum.PHYS_TIME_FRAME).sqr()) / fallDamageDampening.sqr() * GAME_TO_SI_ACC
|
||||
// kg * m / s^2 (mass * acceleration), acceleration -> (vectorMagn / (0.01)^2).gameToSI()
|
||||
if (collisionDamage != 0.0) debug1("Collision damage: $collisionDamage N")
|
||||
// FIXME instead of 0.5mv^2, we can model after "change of velocity (aka accel)", just as in real-life; big change of accel on given unit time is what kills
|
||||
|
||||
|
||||
// grounded = true
|
||||
}// end of collision not detected
|
||||
// grounded = true
|
||||
}// end of collision not detected
|
||||
|
||||
|
||||
return
|
||||
return
|
||||
|
||||
|
||||
|
||||
// if collision not detected, just don't care; it's not your job to apply moveDelta
|
||||
// if collision not detected, just don't care; it's not your job to apply moveDelta
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1033,11 +1012,11 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
(BlockCodex[tile].isSolid) ||
|
||||
// platforms, moving downward AND not "going down"
|
||||
(this is ActorHumanoid && BlockCodex[tile].isPlatform &&
|
||||
externalV.y + (controllerMoveV?.y ?: 0.0) >= 0.0 &&
|
||||
externalV.y + (controllerV?.y ?: 0.0) >= 0.0 &&
|
||||
!this.isDownDown && this.axisY <= 0f) ||
|
||||
// platforms, moving downward
|
||||
(this !is ActorHumanoid && BlockCodex[tile].isPlatform &&
|
||||
externalV.y + (controllerMoveV?.y ?: 0.0) >= 0.0)
|
||||
externalV.y + (controllerV?.y ?: 0.0) >= 0.0)
|
||||
// TODO: as for the platform, only apply it when it's a feet tile
|
||||
|
||||
|
||||
@@ -1092,7 +1071,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
|
||||
/** about stopping
|
||||
* for about get moving, see updateMovementControl */
|
||||
private fun setHorizontalFriction(delta: Double) {
|
||||
private fun setHorizontalFriction(delta: Float) {
|
||||
val friction = if (isNoClip)
|
||||
BASE_FRICTION * BlockCodex[Block.STONE].friction.frictionToMult()
|
||||
else {
|
||||
@@ -1110,18 +1089,18 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
}
|
||||
|
||||
if (this is Controllable) {
|
||||
if (controllerMoveV!!.x < 0) {
|
||||
controllerMoveV!!.x += friction
|
||||
if (controllerMoveV!!.x > 0) controllerMoveV!!.x = 0.0
|
||||
if (controllerV!!.x < 0) {
|
||||
controllerV!!.x += friction
|
||||
if (controllerV!!.x > 0) controllerV!!.x = 0.0
|
||||
}
|
||||
else if (controllerMoveV!!.x > 0) {
|
||||
controllerMoveV!!.x -= friction
|
||||
if (controllerMoveV!!.x < 0) controllerMoveV!!.x = 0.0
|
||||
else if (controllerV!!.x > 0) {
|
||||
controllerV!!.x -= friction
|
||||
if (controllerV!!.x < 0) controllerV!!.x = 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setVerticalFriction(delta: Double) {
|
||||
private fun setVerticalFriction(delta: Float) {
|
||||
val friction = if (isNoClip)
|
||||
BASE_FRICTION * BlockCodex[Block.STONE].friction.frictionToMult()
|
||||
else
|
||||
@@ -1137,13 +1116,13 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
}
|
||||
|
||||
if (this is Controllable) {
|
||||
if (controllerMoveV!!.y < 0) {
|
||||
controllerMoveV!!.y += friction
|
||||
if (controllerMoveV!!.y > 0) controllerMoveV!!.y = 0.0
|
||||
if (controllerV!!.y < 0) {
|
||||
controllerV!!.y += friction
|
||||
if (controllerV!!.y > 0) controllerV!!.y = 0.0
|
||||
}
|
||||
else if (controllerMoveV!!.y > 0) {
|
||||
controllerMoveV!!.y -= friction
|
||||
if (controllerMoveV!!.y < 0) controllerMoveV!!.y = 0.0
|
||||
else if (controllerV!!.y > 0) {
|
||||
controllerV!!.y -= friction
|
||||
if (controllerV!!.y < 0) controllerV!!.y = 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1465,7 +1444,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
|
||||
if (value) {
|
||||
externalV.zero()
|
||||
controllerMoveV?.zero()
|
||||
controllerV?.zero()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ import org.luaj.vm2.*
|
||||
*/
|
||||
fun composeActorObject(actor: ActorWBMovable): LuaTable {
|
||||
val t: LuaTable = LuaTable()
|
||||
val moveDelta = actor.externalV + actor.controllerMoveV
|
||||
val moveDelta = actor.externalV + actor.controllerV
|
||||
|
||||
t["name"] = actor.actorValue.getAsString(AVKey.NAME).toLua()
|
||||
t["startX"] = actor.hitbox.centeredX.toLua()
|
||||
|
||||
@@ -52,8 +52,8 @@ open class GameWorld {
|
||||
|
||||
//public World physWorld = new World( new Vec2(0, -Terrarum.game.gravitationalAccel) );
|
||||
//physics
|
||||
/** Some arbitrary and empirical value */
|
||||
var gravitation: Vector2 = Vector2(0.0, 0.31)
|
||||
/** Meter per second squared. Currently only the downward gravity is supported. No reverse gravity :p */
|
||||
var gravitation: Vector2 = Vector2(0.0, 9.80665)
|
||||
/** 0.0..1.0+ */
|
||||
var globalLight = Color(0f,0f,0f,0f)
|
||||
var averageTemperature = 288f // 15 deg celsius; simulates global warming
|
||||
|
||||
@@ -120,9 +120,6 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
}
|
||||
|
||||
protected var updateDeltaCounter = 0.0
|
||||
protected val updateRate = 1.0 / Terrarum.TARGET_INTERNAL_FPS
|
||||
|
||||
private val actorsRenderOverlay = ArrayList<ActorWithBody>()
|
||||
|
||||
init {
|
||||
@@ -161,19 +158,8 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
// ASYNCHRONOUS UPDATE AND RENDER //
|
||||
|
||||
|
||||
// async update
|
||||
updateDeltaCounter += delta
|
||||
if (delta < 1f / 10f) { // discard async if measured FPS <= 10
|
||||
var updateTries = 0
|
||||
while (updateDeltaCounter >= updateRate) {
|
||||
updateGame(delta)
|
||||
updateDeltaCounter -= updateRate
|
||||
updateTries++
|
||||
}
|
||||
}
|
||||
else {
|
||||
updateGame(delta)
|
||||
}
|
||||
// TODO async update
|
||||
updateGame(delta)
|
||||
|
||||
// render? just do it anyway
|
||||
renderGame()
|
||||
|
||||
@@ -66,6 +66,11 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
private val actorsRenderFront = ArrayList<ActorWithBody>(ACTORCONTAINER_INITIAL_SIZE)
|
||||
private val actorsRenderOverlay= ArrayList<ActorWithBody>(ACTORCONTAINER_INITIAL_SIZE)
|
||||
|
||||
private var visibleActorsRenderBehind: List<ActorWithBody> = ArrayList(1)
|
||||
private var visibleActorsRenderMiddle: List<ActorWithBody> = ArrayList(1)
|
||||
private var visibleActorsRenderMidTop: List<ActorWithBody> = ArrayList(1)
|
||||
private var visibleActorsRenderFront: List<ActorWithBody> = ArrayList(1)
|
||||
private var visibleActorsRenderOverlay: List<ActorWithBody> = ArrayList(1)
|
||||
|
||||
//var screenZoom = 1.0f // definition moved to IngameInstance
|
||||
//val ZOOM_MAXIMUM = 4.0f // definition moved to IngameInstance
|
||||
@@ -82,7 +87,7 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
fun getCanonicalTitle() = AppLoader.GAME_NAME +
|
||||
" — F: ${Gdx.graphics.framesPerSecond}" +
|
||||
if (AppLoader.IS_DEVELOPMENT_BUILD)
|
||||
" (Δt${Terrarum.updateRateStr} / RT${Terrarum.renderRateStr})" +
|
||||
" (ΔF${Terrarum.updateRateStr})" +
|
||||
" — M: J${Terrarum.memJavaHeap}M / N${Terrarum.memNativeHeap}M / X${Terrarum.memXmx}M"
|
||||
else
|
||||
""
|
||||
@@ -379,6 +384,7 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
LightmapRenderer.fireRecalculateEvent()
|
||||
|
||||
|
||||
AppLoader.debugTimers["Ingame.updateCounter"] = 0
|
||||
|
||||
|
||||
|
||||
@@ -408,8 +414,6 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
itemOnGrip?.endSecondaryUse(delta)
|
||||
}
|
||||
|
||||
protected val renderRate = Terrarum.renderRate
|
||||
|
||||
private var firstTimeRun = true
|
||||
|
||||
///////////////
|
||||
@@ -422,6 +426,7 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
private var countdownToDeltaReset = 15 // number of frames
|
||||
private var updateAkku = 0.0
|
||||
|
||||
override fun render(delta: Float) {
|
||||
// Q&D solution for LoadScreen and Ingame, where while LoadScreen is working, Ingame now no longer has GL Context
|
||||
@@ -443,7 +448,7 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
|
||||
if (countdownToDeltaReset >= 0) {3
|
||||
if (countdownToDeltaReset >= 0) {
|
||||
if (countdownToDeltaReset == 0) {
|
||||
AppLoader.resetDeltaSmoothingHistory()
|
||||
}
|
||||
@@ -453,23 +458,18 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
// ASYNCHRONOUS UPDATE AND RENDER //
|
||||
|
||||
|
||||
/** UPDATE CODE GOES HERE */
|
||||
val dt = AppLoader.getSmoothDelta()
|
||||
updateAkku += dt
|
||||
|
||||
|
||||
|
||||
if (false && AppLoader.getConfigBoolean("multithread")) { // NO MULTITHREADING: camera don't like concurrent modification (jittery actor movements)
|
||||
if (firstTimeRun || updateThreadWrapper.state == Thread.State.TERMINATED) {
|
||||
updateThreadWrapper = Thread(ingameUpdateThread, "Terrarum UpdateThread")
|
||||
updateThreadWrapper.start()
|
||||
|
||||
if (firstTimeRun) firstTimeRun = false
|
||||
}
|
||||
// else, NOP;
|
||||
}
|
||||
else {
|
||||
var i = 0L
|
||||
while (updateAkku >= delta) {
|
||||
AppLoader.debugTimers["Ingame.update"] = measureNanoTime { updateGame(delta) }
|
||||
updateAkku -= delta
|
||||
i += 1
|
||||
}
|
||||
AppLoader.debugTimers["Ingame.updateCounter"] = i
|
||||
|
||||
|
||||
|
||||
/** RENDER CODE GOES HERE */
|
||||
@@ -522,6 +522,13 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
particlesContainer.forEach { if (!it.flagDespawn) particlesActive++; it.update(delta) }
|
||||
// TODO thread pool(?)
|
||||
CollisionSolver.process()
|
||||
|
||||
|
||||
visibleActorsRenderBehind = actorsRenderBehind.filter { it.inScreen() }
|
||||
visibleActorsRenderMiddle = actorsRenderMiddle.filter { it.inScreen() }
|
||||
visibleActorsRenderMidTop = actorsRenderMidTop.filter { it.inScreen() }
|
||||
visibleActorsRenderFront = actorsRenderFront.filter { it.inScreen() }
|
||||
visibleActorsRenderOverlay=actorsRenderOverlay.filter { it.inScreen() }
|
||||
}
|
||||
|
||||
|
||||
@@ -545,11 +552,11 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
IngameRenderer.invoke(
|
||||
world as GameWorldExtension,
|
||||
actorsRenderBehind,
|
||||
actorsRenderMiddle,
|
||||
actorsRenderMidTop,
|
||||
actorsRenderFront,
|
||||
actorsRenderOverlay,
|
||||
visibleActorsRenderBehind,
|
||||
visibleActorsRenderMiddle,
|
||||
visibleActorsRenderMidTop,
|
||||
visibleActorsRenderFront,
|
||||
visibleActorsRenderOverlay,
|
||||
particlesContainer,
|
||||
actorNowPlaying,
|
||||
uiContainer
|
||||
@@ -962,4 +969,5 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
printdbg(this, "-> $it")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -124,11 +124,11 @@ open class ActorHumanoid(
|
||||
@Transient private val KEY_NULL = -1
|
||||
|
||||
/** how long the jump button has down, in frames */
|
||||
internal var jumpCounter = 0f
|
||||
internal var jumpCounter = 0
|
||||
internal var jumpAcc = 0.0
|
||||
/** how long the walk button has down, in frames */
|
||||
internal var walkCounterX = 0f
|
||||
internal var walkCounterY = 0f
|
||||
internal var walkCounterX = 0
|
||||
internal var walkCounterY = 0
|
||||
@Transient private val MAX_JUMP_LENGTH = 25 // manages "heaviness" of the jump control. Higher = heavier
|
||||
|
||||
private var readonly_totalX = 0.0
|
||||
@@ -289,24 +289,24 @@ open class ActorHumanoid(
|
||||
|
||||
if (hasController) {
|
||||
if (axisX != 0f) {
|
||||
walkHorizontal(delta, axisX < 0f, axisX.abs())
|
||||
walkHorizontal(axisX < 0f, axisX.abs())
|
||||
}
|
||||
}
|
||||
// ↑F, ↓S
|
||||
if (isRightDown && !isLeftDown) {
|
||||
walkHorizontal(delta, false, AXIS_KEYBOARD)
|
||||
walkHorizontal(false, AXIS_KEYBOARD)
|
||||
prevHMoveKey = AppLoader.getConfigInt("keyright")
|
||||
} // ↓F, ↑S
|
||||
else if (isLeftDown && !isRightDown) {
|
||||
walkHorizontal(delta, true, AXIS_KEYBOARD)
|
||||
walkHorizontal(true, AXIS_KEYBOARD)
|
||||
prevHMoveKey = AppLoader.getConfigInt("keyleft")
|
||||
} // ↓F, ↓S
|
||||
/*else if (isLeftDown && isRightDown) {
|
||||
if (prevHMoveKey == KeyMap.getKeyCode(EnumKeyFunc.MOVE_LEFT)) {
|
||||
walkHorizontal(delta, false, AXIS_KEYBOARD)
|
||||
walkHorizontal(false, AXIS_KEYBOARD)
|
||||
prevHMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_RIGHT)
|
||||
} else if (prevHMoveKey == KeyMap.getKeyCode(EnumKeyFunc.MOVE_RIGHT)) {
|
||||
walkHorizontal(delta, true, AXIS_KEYBOARD)
|
||||
walkHorizontal(true, AXIS_KEYBOARD)
|
||||
prevHMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_LEFT)
|
||||
}
|
||||
}*/
|
||||
@@ -317,24 +317,24 @@ open class ActorHumanoid(
|
||||
if (isNoClip || COLLISION_TEST_MODE) {
|
||||
if (hasController) {
|
||||
if (axisY != 0f) {
|
||||
walkVertical(delta, axisY < 0, axisY.abs())
|
||||
walkVertical(axisY < 0, axisY.abs())
|
||||
}
|
||||
}
|
||||
// ↑E, ↓D
|
||||
if (isDownDown && !isUpDown) {
|
||||
walkVertical(delta, false, AXIS_KEYBOARD)
|
||||
walkVertical(false, AXIS_KEYBOARD)
|
||||
prevVMoveKey = AppLoader.getConfigInt("keydown")
|
||||
} // ↓E, ↑D
|
||||
else if (isUpDown && !isDownDown) {
|
||||
walkVertical(delta, true, AXIS_KEYBOARD)
|
||||
walkVertical(true, AXIS_KEYBOARD)
|
||||
prevVMoveKey = AppLoader.getConfigInt("keyup")
|
||||
} // ↓E, ↓D
|
||||
/*else if (isUpDown && isDownDown) {
|
||||
if (prevVMoveKey == KeyMap.getKeyCode(EnumKeyFunc.MOVE_UP)) {
|
||||
walkVertical(delta, false, AXIS_KEYBOARD)
|
||||
walkVertical(false, AXIS_KEYBOARD)
|
||||
prevVMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_DOWN)
|
||||
} else if (prevVMoveKey == KeyMap.getKeyCode(EnumKeyFunc.MOVE_DOWN)) {
|
||||
walkVertical(delta, true, AXIS_KEYBOARD)
|
||||
walkVertical(true, AXIS_KEYBOARD)
|
||||
prevVMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_UP)
|
||||
}
|
||||
}*/
|
||||
@@ -349,15 +349,15 @@ open class ActorHumanoid(
|
||||
(!airJumpingAllowed && walledBottom)) {
|
||||
jumping = true
|
||||
}
|
||||
jump(delta)
|
||||
jump()
|
||||
}
|
||||
else {
|
||||
walkVertical(delta, true, AXIS_KEYBOARD)
|
||||
walkVertical(true, AXIS_KEYBOARD)
|
||||
}
|
||||
}
|
||||
else {
|
||||
jumping = false
|
||||
jumpCounter = 0f
|
||||
jumpCounter = 0
|
||||
jumpAcc = 0.0
|
||||
}
|
||||
|
||||
@@ -388,7 +388,7 @@ open class ActorHumanoid(
|
||||
* @param absAxisVal (set AXIS_KEYBOARD if keyboard controlled)
|
||||
* @author minjaesong
|
||||
*/
|
||||
private fun walkHorizontal(delta: Float, left: Boolean, absAxisVal: Float) {
|
||||
private fun walkHorizontal(left: Boolean, absAxisVal: Float) {
|
||||
|
||||
|
||||
if (avAcceleration.isNaN()) {
|
||||
@@ -406,12 +406,12 @@ open class ActorHumanoid(
|
||||
avAcceleration * applyVelo(walkCounterX) * (if (left) -1f else 1f) * absAxisVal
|
||||
|
||||
if (absAxisVal != AXIS_KEYBOARD)
|
||||
controllerMoveV?.x?.let { controllerMoveV!!.x = controllerMoveV!!.x.plus(readonly_totalX).bipolarClamp(avSpeedCap * absAxisVal) }
|
||||
controllerV?.x?.let { controllerV!!.x = controllerV!!.x.plus(readonly_totalX).bipolarClamp(avSpeedCap * absAxisVal) }
|
||||
else
|
||||
controllerMoveV?.x?.let { controllerMoveV!!.x = controllerMoveV!!.x.plus(readonly_totalX).bipolarClamp(avSpeedCap) }
|
||||
controllerV?.x?.let { controllerV!!.x = controllerV!!.x.plus(readonly_totalX).bipolarClamp(avSpeedCap) }
|
||||
|
||||
if (walkCounterX < 1000000) {
|
||||
walkCounterX += 1 * (Terrarum.PHYS_REF_FPS * delta).toFloat()
|
||||
walkCounterX += 1
|
||||
}
|
||||
|
||||
isWalkingH = true
|
||||
@@ -428,7 +428,7 @@ open class ActorHumanoid(
|
||||
* *
|
||||
* @param absAxisVal (set AXIS_KEYBOARD if keyboard controlled)
|
||||
*/
|
||||
private fun walkVertical(delta: Float, up: Boolean, absAxisVal: Float) {
|
||||
private fun walkVertical(up: Boolean, absAxisVal: Float) {
|
||||
if (up && walledTop || !up && walledBottom) return
|
||||
|
||||
|
||||
@@ -444,12 +444,12 @@ open class ActorHumanoid(
|
||||
avAcceleration * applyVelo(walkCounterY) * (if (up) -1f else 1f) * absAxisVal
|
||||
|
||||
if (absAxisVal != AXIS_KEYBOARD)
|
||||
controllerMoveV?.y?.let { controllerMoveV!!.y = controllerMoveV!!.y.plus(readonly_totalY).bipolarClamp(avSpeedCap * absAxisVal) }
|
||||
controllerV?.y?.let { controllerV!!.y = controllerV!!.y.plus(readonly_totalY).bipolarClamp(avSpeedCap * absAxisVal) }
|
||||
else
|
||||
controllerMoveV?.y?.let { controllerMoveV!!.y = controllerMoveV!!.y.plus(readonly_totalY).bipolarClamp(avSpeedCap) }
|
||||
controllerV?.y?.let { controllerV!!.y = controllerV!!.y.plus(readonly_totalY).bipolarClamp(avSpeedCap) }
|
||||
|
||||
if (walkCounterY < 1000000) {
|
||||
walkCounterY += 1 * (Terrarum.PHYS_REF_FPS * delta).toFloat()
|
||||
walkCounterY += 1
|
||||
}
|
||||
|
||||
|
||||
@@ -462,7 +462,7 @@ open class ActorHumanoid(
|
||||
else 0.0
|
||||
}
|
||||
|
||||
private fun applyVelo(x: Float): Double {
|
||||
private fun applyVelo(x: Int): Double {
|
||||
return if (x < WALK_FRAMES_TO_MAX_ACCEL)
|
||||
0.5 - 0.5 * Math.cos(Math.PI * x / WALK_FRAMES_TO_MAX_ACCEL)
|
||||
else 1.0
|
||||
@@ -470,13 +470,13 @@ open class ActorHumanoid(
|
||||
|
||||
// stops; let the friction kick in by doing nothing to the velocity here
|
||||
private fun walkHStop() {
|
||||
walkCounterX = 0f
|
||||
walkCounterX = 0
|
||||
isWalkingH = false
|
||||
}
|
||||
|
||||
// stops; let the friction kick in by doing nothing to the velocity here
|
||||
private fun walkVStop() {
|
||||
walkCounterY = 0f
|
||||
walkCounterY = 0
|
||||
isWalkingV = false
|
||||
}
|
||||
|
||||
@@ -489,7 +489,7 @@ open class ActorHumanoid(
|
||||
private var oldJUMPPOWERBUFF = -1.0 // init
|
||||
private var oldScale = -1.0
|
||||
private var oldDragCoefficient = -1.0
|
||||
// used by some AIs?
|
||||
// used by some AIs
|
||||
var jumpAirTime: Double = -1.0
|
||||
get() {
|
||||
// compare all the affecting variables
|
||||
@@ -513,14 +513,14 @@ open class ActorHumanoid(
|
||||
|
||||
var simYPos = 0.0
|
||||
var forceVec = Vector2(0.0, 0.0)
|
||||
var jmpCtr = 0f
|
||||
var jmpCtr = 0
|
||||
while (true) {
|
||||
if (jmpCtr < MAX_JUMP_LENGTH) jmpCtr++
|
||||
|
||||
|
||||
val timedJumpCharge = jumpFunc(MAX_JUMP_LENGTH, jmpCtr)
|
||||
forceVec.y -= getJumpAcc(jumpPower, timedJumpCharge)
|
||||
forceVec.y += getDrag(1.0 / Terrarum.PHYS_REF_FPS, forceVec).y
|
||||
forceVec.y += getDrag(AppLoader.UPDATE_RATE.toFloat(), forceVec).y
|
||||
|
||||
simYPos += forceVec.y // ignoring all the fluid drag OTHER THAN THE AIR
|
||||
|
||||
@@ -543,7 +543,7 @@ open class ActorHumanoid(
|
||||
private val jumpPower: Double
|
||||
get() = actorValue.getAsDouble(AVKey.JUMPPOWER)!! * (actorValue.getAsDouble(AVKey.JUMPPOWERBUFF) ?: 1.0)
|
||||
|
||||
private fun jumpFunc(len: Int, counter: Float): Double {
|
||||
private fun jumpFunc(len: Int, counter: Int): Double {
|
||||
// linear time mode
|
||||
val init = (len + 1) / 2.0
|
||||
var timedJumpCharge = init - init / len * counter
|
||||
@@ -556,7 +556,7 @@ open class ActorHumanoid(
|
||||
*
|
||||
* TODO linear function (play Super Mario Bros. and you'll get what I'm talking about) -- SCRATCH THAT!
|
||||
*/
|
||||
private fun jump(delta: Float) {
|
||||
private fun jump() {
|
||||
if (jumping) {// && jumpable) {
|
||||
// increment jump counter
|
||||
if (jumpCounter < MAX_JUMP_LENGTH) jumpCounter += 1
|
||||
@@ -565,7 +565,7 @@ open class ActorHumanoid(
|
||||
|
||||
jumpAcc = getJumpAcc(jumpPower, timedJumpCharge)
|
||||
|
||||
controllerMoveV?.y?.let { controllerMoveV!!.y -= jumpAcc } // feed negative value to the vector
|
||||
controllerV?.y?.let { controllerV!!.y -= jumpAcc } // feed negative value to the vector
|
||||
// do not think of resetting this to zero when counter hit the ceiling; that's HOW NOT
|
||||
// newtonian physics work, stupid myself :(
|
||||
|
||||
@@ -580,7 +580,7 @@ open class ActorHumanoid(
|
||||
if (jumpCounter >= MAX_JUMP_LENGTH && !isGamer) {
|
||||
isJumpDown = false
|
||||
jumping = false
|
||||
jumpCounter = 0f
|
||||
jumpCounter = 0
|
||||
jumpAcc = 0.0
|
||||
}
|
||||
}
|
||||
@@ -610,7 +610,7 @@ open class ActorHumanoid(
|
||||
sprite?.update(delta)
|
||||
spriteGlow?.update(delta)
|
||||
|
||||
if (walledBottom && controllerMoveV?.x != 0.0) {
|
||||
if (walledBottom && controllerV?.x != 0.0) {
|
||||
//switch row
|
||||
sprite?.switchRow(SPRITE_ROW_WALK)
|
||||
spriteGlow?.switchRow(SPRITE_ROW_WALK)
|
||||
@@ -618,8 +618,8 @@ open class ActorHumanoid(
|
||||
// set anim frame delay
|
||||
// 4f of the divider is a magic number, empirically decided
|
||||
if (this is HasAssembledSprite) {
|
||||
sprite?.delays?.set(SPRITE_ROW_WALK, scale.sqrt().toFloat() / (4f * (controllerMoveV?.x ?: 0.0001).abs().toFloat())) // FIXME empirical value
|
||||
spriteGlow?.delays?.set(SPRITE_ROW_WALK, scale.sqrt().toFloat() / (4f * (controllerMoveV?.x ?: 0.0001).abs().toFloat())) // FIXME empirical value
|
||||
sprite?.delays?.set(SPRITE_ROW_WALK, scale.sqrt().toFloat() / (4f * (controllerV?.x ?: 0.0001).abs().toFloat())) // FIXME empirical value
|
||||
spriteGlow?.delays?.set(SPRITE_ROW_WALK, scale.sqrt().toFloat() / (4f * (controllerV?.x ?: 0.0001).abs().toFloat())) // FIXME empirical value
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class PhysTestLuarLander : ActorWBMovable(RenderOrder.MIDTOP), Controllable {
|
||||
super.update(delta)
|
||||
|
||||
if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
|
||||
controllerMoveV!!.y = avSpeedCap
|
||||
controllerV!!.y = avSpeedCap
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -150,8 +150,8 @@ object CollisionSolver {
|
||||
|
||||
// if they actually makes collision (e.g. player vs ball), solve it
|
||||
if (a makesCollisionWith b) {
|
||||
val a_moveDelta = a.externalV + a.controllerMoveV
|
||||
val b_moveDelta = b.externalV + b.controllerMoveV
|
||||
val a_moveDelta = a.externalV + a.controllerV
|
||||
val b_moveDelta = b.externalV + b.controllerV
|
||||
|
||||
val ux_1 = a_moveDelta.x
|
||||
val ux_2 = b_moveDelta.x
|
||||
|
||||
@@ -111,8 +111,8 @@ class BasicDebugInfoWindow : UICanvas() {
|
||||
printLine(batch, 3, "veloX reported $ccG${player.externalV.x}")
|
||||
printLine(batch, 4, "veloY reported $ccG${player.externalV.y}")
|
||||
|
||||
printLine(batch, 5, "p_WalkX $ccG${player.controllerMoveV?.x}")
|
||||
printLine(batch, 6, "p_WalkY $ccG${player.controllerMoveV?.y}")
|
||||
printLine(batch, 5, "p_WalkX $ccG${player.controllerV?.x}")
|
||||
printLine(batch, 6, "p_WalkY $ccG${player.controllerV?.y}")
|
||||
|
||||
printLineColumn(batch, 2, 3, "veloX measured $ccG${xdelta}")
|
||||
printLineColumn(batch, 2, 4, "veloY measured $ccG${ydelta}")
|
||||
|
||||
@@ -360,13 +360,6 @@ class Vector2 {
|
||||
return Vector2(newX, newY)
|
||||
}
|
||||
|
||||
private fun Double.magnSqr() = if (this >= 0.0) this * this else -(this * this)
|
||||
|
||||
/**
|
||||
* Returns new vector whose magnitude is squared, and direction is preserved.
|
||||
*/
|
||||
fun magnSqr(): Vector2 = Vector2(x.magnSqr(), y.magnSqr())
|
||||
|
||||
/**
|
||||
* Adds the given [Vector2] to this [Vector2].
|
||||
* @param vector the [Vector2]
|
||||
|
||||
Reference in New Issue
Block a user