From 84e4c82b60ba1444df442b5aead36f019b594ca8 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sun, 7 Jul 2019 22:13:37 +0900 Subject: [PATCH] throwing in a pr-tree onto the project --- .idea/libraries/lib.xml | 1 + COPYING.md | 41 ++- lib/prtree.jar | Bin 0 -> 66585 bytes src/net/torvald/terrarum/Terrarum.kt | 2 +- .../terrarum/gameactors/ActorWBMovable.kt | 41 +-- .../terrarum/modulebasegame/TerrarumIngame.kt | 21 +- .../gameactors/PlayerBuilderTestSubject1.kt | 6 +- .../gameworld/WorldSimulator.kt | 259 +++++++++++------- 8 files changed, 241 insertions(+), 130 deletions(-) create mode 100644 lib/prtree.jar diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml index 8759a8be1..c4f1a8eef 100644 --- a/.idea/libraries/lib.xml +++ b/.idea/libraries/lib.xml @@ -19,6 +19,7 @@ + diff --git a/COPYING.md b/COPYING.md index b5cad8552..ba19791ee 100644 --- a/COPYING.md +++ b/COPYING.md @@ -66,7 +66,7 @@ limitations under the License. *Accidental Noise Library* Joise is a derivative work based on Josua Tippetts' C++ library: -http://accidentalnoise.sourceforge.net/index.html + Copyright (C) 2011 Joshua Tippetts @@ -90,7 +90,7 @@ Copyright (C) 2011 Joshua Tippetts *Vector2.java*, *Epsilon.java* -Copyright (c) 2010-2015 William Bittle http://www.dyn4j.org/ +Copyright (c) 2010-2015 William Bittle All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted @@ -127,7 +127,7 @@ Ambient sound recordings: crickets_02.ogg Copyright (C) 2012, 2013, 2015, 2016, 2017 Klankbeeld -Sound from http://www.freesound.org/people/klankbeeld/ +Sound from ---- @@ -155,6 +155,39 @@ THE SOFTWARE. ---- +PRTree, a Priority R-Tree, a spatial index for java code + +Copyright (c) 2008-2012 Robert Olofsson. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the authors nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +---- Some of the resources were created by _raxod502_. @@ -176,4 +209,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file +THE SOFTWARE. diff --git a/lib/prtree.jar b/lib/prtree.jar new file mode 100644 index 0000000000000000000000000000000000000000..728a32776aa5b0aa1dc6a5c6fd64fcf81f576e5c GIT binary patch literal 66585 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 literal 0 HcmV?d00001 diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index 476035515..5f013d2ea 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -56,7 +56,7 @@ object Terrarum : Disposable { /** * To be used with physics simulator. This is a magic number. */ - val PHYS_TIME_FRAME: Double = 26.0 + (2.0 / 3.0) + const val PHYS_TIME_FRAME: Double = 26.0 + (2.0 / 3.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 diff --git a/src/net/torvald/terrarum/gameactors/ActorWBMovable.kt b/src/net/torvald/terrarum/gameactors/ActorWBMovable.kt index e8ec2d487..c96c2fa85 100644 --- a/src/net/torvald/terrarum/gameactors/ActorWBMovable.kt +++ b/src/net/torvald/terrarum/gameactors/ActorWBMovable.kt @@ -73,10 +73,10 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean = */ // got the idea from gl_FragCoord val hIntTilewiseHitbox: Hitbox get() = Hitbox.fromTwoPoints( - hitbox.startX.plus(0.00001).div(TILE_SIZE).floor() + 0.5, - hitbox.startY.plus(0.00001).div(TILE_SIZE).floor() + 0.5, - hitbox.endX.plus(0.00001).div(TILE_SIZE).floor() + 0.5, - hitbox.endY.plus(0.00001).div(TILE_SIZE).floor() + 0.5, + hitbox.startX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5, + hitbox.startY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5, + hitbox.endX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5, + hitbox.endY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5, true ) @@ -89,8 +89,8 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean = get() = 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(), + hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(), + hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(), true ) @@ -641,8 +641,8 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean = 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(), + hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(), + hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(), true ) @@ -690,7 +690,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean = }*/ // trying to use same function as the others, in an effort to eliminate the "contradiction" mentioned below - if (isColliding(stepBox)) { + if (isColliding(stepBox, vectorSum.y > PHYS_EPSILON_VELO)) { collidingStep = step } @@ -773,13 +773,13 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean = // 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 + newHitbox.endX.div(TILE_SIZE).floor() * TILE_SIZE - PHYS_EPSILON_DIST 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 + newHitbox.endY.div(TILE_SIZE).floor() * TILE_SIZE - PHYS_EPSILON_DIST else newHitbox.startY.div(TILE_SIZE).ceil() * TILE_SIZE @@ -962,7 +962,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean = /** * @see /work_files/hitbox_collision_detection_compensation.jpg */ - private fun isColliding(hitbox: Hitbox): Boolean { + private fun isColliding(hitbox: Hitbox, feet: Boolean = false): Boolean { if (isNoCollideWorld) return false // detectors are inside of the bounding box @@ -978,7 +978,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean = val tyStart = y1.plus(0.5f).div(TILE_SIZE).floorInt() val tyEnd = y2.plus(0.5f).div(TILE_SIZE).floorInt() - return isCollidingInternal(txStart, tyStart, txEnd, tyEnd) + return isCollidingInternal(txStart, tyStart, txEnd, tyEnd, feet) } /** @@ -1604,8 +1604,8 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean = 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(), + hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(), + hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(), true ) // NOT the same as intTilewiseHitbox !! @@ -1659,20 +1659,23 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean = * Constants */ - @Transient val METER = 24.0 + @Transient const val METER = 24.0 /** * [m / s^2] * SI_TO_GAME_ACC -> [px / InternalFrame^2] */ - @Transient val SI_TO_GAME_ACC = METER / (Terrarum.PHYS_TIME_FRAME * Terrarum.PHYS_TIME_FRAME) + @Transient const val SI_TO_GAME_ACC = METER / (Terrarum.PHYS_TIME_FRAME * Terrarum.PHYS_TIME_FRAME) /** * [m / s] * SI_TO_GAME_VEL -> [px / InternalFrame] */ - @Transient val SI_TO_GAME_VEL = METER / Terrarum.PHYS_TIME_FRAME + @Transient const val SI_TO_GAME_VEL = METER / Terrarum.PHYS_TIME_FRAME /** * [px / InternalFrame^2] * GAME_TO_SI_ACC -> [m / s^2] */ - @Transient val GAME_TO_SI_ACC = (Terrarum.PHYS_TIME_FRAME * Terrarum.PHYS_TIME_FRAME) / METER + @Transient const val GAME_TO_SI_ACC = (Terrarum.PHYS_TIME_FRAME * Terrarum.PHYS_TIME_FRAME) / METER + + @Transient const val PHYS_EPSILON_DIST = 0.00001 + @Transient const val PHYS_EPSILON_VELO = 0.0001 /** diff --git a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt index 96e7015d9..fc52ef317 100644 --- a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt +++ b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt @@ -484,9 +484,6 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { particlesActive = 0 - ingameController.update(delta) - - if (!paused) { WorldSimulator.resetForThisFrame() @@ -496,9 +493,15 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { /////////////////////////// BlockPropUtil.dynamicLumFuncTickClock() world.updateWorldTime(delta) - WorldSimulator.invoke(actorNowPlaying, delta) - WeatherMixer.update(delta, actorNowPlaying, world) - BlockStats.update() + AppLoader.measureDebugTime("WorldSimulator.update") { + WorldSimulator.invoke(actorNowPlaying, delta) + } + AppLoader.measureDebugTime("WeatherMixer.update") { + WeatherMixer.update(delta, actorNowPlaying, world) + } + AppLoader.measureDebugTime("BlockStats.update") { + BlockStats.update() + } @@ -524,6 +527,12 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { WorldCamera.update(gameworld, actorNowPlaying) + } + + // world click events (e.g. opening the UI that a fixture has) must go here + ingameController.update(delta) + + if (!paused) { // completely consume block change queues because why not terrainChangeQueue.clear() diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderTestSubject1.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderTestSubject1.kt index a3ecb717e..0483b6b97 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderTestSubject1.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderTestSubject1.kt @@ -11,8 +11,8 @@ import net.torvald.terrarum.worlddrawer.CreateTileAtlas object PlayerBuilderTestSubject1 { operator fun invoke(): IngamePlayer { val p: IngamePlayer = IngamePlayer( - ModMgr.getPath("basegame", "sprites/furry_sprite.properties"), - ModMgr.getPath("basegame", "sprites/furry_sprite_glow.properties"), + ModMgr.getPath("basegame", "sprites/test_sprite.properties"), + null,//ModMgr.getPath("basegame", "sprites/test_sprite_glow.properties"), -589141658L // random value thrown ) InjectCreatureRaw(p.actorValue, "basegame", "CreatureHuman.json") @@ -29,7 +29,7 @@ object PlayerBuilderTestSubject1 { p.sprite!!.setRowsAndFrames(2, 4)*/ p.sprite = SpriteAnimation(p) - p.spriteGlow = SpriteAnimation(p) + //p.spriteGlow = SpriteAnimation(p) p.reassembleSprite(p.sprite!!, p.spriteGlow) p.setHitboxDimension(15, p.actorValue.getAsInt(AVKey.BASEHEIGHT) ?: ActorHumanoid.BASE_HEIGHT, 21, 0) diff --git a/src/net/torvald/terrarum/modulebasegame/gameworld/WorldSimulator.kt b/src/net/torvald/terrarum/modulebasegame/gameworld/WorldSimulator.kt index abb604c82..326dd1ad1 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameworld/WorldSimulator.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameworld/WorldSimulator.kt @@ -1,21 +1,18 @@ package net.torvald.terrarum.modulebasegame.gameworld import com.badlogic.gdx.Input -import com.badlogic.gdx.graphics.Color -import net.torvald.aa.KDTree -import net.torvald.terrarum.AppLoader -import net.torvald.terrarum.IngameInstance -import net.torvald.terrarum.Terrarum +import net.torvald.terrarum.* import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.blockproperties.Fluid -import net.torvald.terrarum.gameactors.ActorWBMovable +import net.torvald.terrarum.gameactors.ActorWithBody import net.torvald.terrarum.gamecontroller.KeyToggler import net.torvald.terrarum.gameworld.FluidType import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid -import net.torvald.terrarum.roundInt import net.torvald.terrarum.worlddrawer.CreateTileAtlas +import net.torvald.terrarum.worlddrawer.CreateTileAtlas.TILE_SIZE +import org.khelekore.prtree.* /** * Created by minjaesong on 2016-08-03. @@ -57,25 +54,25 @@ object WorldSimulator { /** Bottom-right point */ var updateYTo = 0 - val colourNone = Color(0x808080FF.toInt()) - val colourWater = Color(0x66BBFFFF.toInt()) - private val ingame: IngameInstance get() = Terrarum.ingame!! private val world: GameWorld get() = ingame.world - // TODO use R-Tree instead? https://stackoverflow.com/questions/10269179/find-rectangles-that-contain-point-efficient-algorithm#10269695 - private var actorsKDTree: KDTree? = null + + private lateinit var actorsRTree: PRTree fun resetForThisFrame() { - actorsKDTree = null + } + /** Must be called BEFORE the actors update -- actors depend on the R-Tree for various things */ operator fun invoke(player: ActorHumanoid?, delta: Float) { - // build the kdtree that will be used during a single frame of updating - if (actorsKDTree == null) - actorsKDTree = KDTree(ingame.actorContainerActive.filter { it is ActorWBMovable }) + // build the r-tree that will be used during a single frame of updating + actorsRTree = PRTree(actorMBRConverter, 24) + actorsRTree.load(ingame.actorContainerActive.filter { it is ActorWithBody }) + + //printdbg(this, "============================") @@ -85,12 +82,49 @@ object WorldSimulator { updateXTo = updateXFrom + DOUBLE_RADIUS updateYTo = updateYFrom + DOUBLE_RADIUS } - moveFluids(delta) + //moveFluids(delta) displaceFallables(delta) //printdbg(this, "============================") } + /** + * @return list of actors under the bounding box given, list may be empty if no actor is under the point. + */ + fun getActorsAt(startPoint: Point2d, endPoint: Point2d): List { + val outList = ArrayList() + actorsRTree.find(startPoint.x, startPoint.y, endPoint.x, endPoint.y, outList) + return outList + } + + fun getActorsAt(worldX: Double, worldY: Double): List { + val outList = ArrayList() + actorsRTree.find(worldX, worldY, worldX + 1.0, worldY + 1.0, outList) + return outList + } + + /** Will use centre point of the actors + * @return List of DistanceResult, list may be empty */ + fun findKNearestActors(from: ActorWithBody, maxHits: Int): List> { + return actorsRTree.nearestNeighbour(actorDistanceCalculator, null, maxHits, object : PointND { + override fun getDimensions(): Int = 2 + override fun getOrd(axis: Int): Double = when(axis) { + 0 -> from.hitbox.centeredX + 1 -> from.hitbox.centeredY + else -> throw IllegalArgumentException("nonexistent axis $axis for ${dimensions}-dimensional object") + } + }) + } + /** Will use centre point of the actors + * @return Pair of: the actor, distance from the actor; null if none found */ + fun findNearestActors(from: ActorWithBody): DistanceResult? { + val t = findKNearestActors(from, 1) + return if (t.isNotEmpty()) + t[0] + else + null + } + /** * displace fluids. Note that the code assumes the gravity pulls things downward ONLY, * which means you'll need to modify the code A LOT if you're going to implement zero- or @@ -119,6 +153,90 @@ object WorldSimulator { return ((fluid.type sameAs type || fluid.type sameAs Fluid.NULL) && !BlockCodex[tile].isSolid) } + /** + * displace fallable tiles. It is scanned bottom-left first. To achieve the sens ofreal + * falling, each tiles are displaced by ONLY ONE TILE below. + */ + fun displaceFallables(delta: Float) { + /*for (y in updateYFrom..updateYTo) { + for (x in updateXFrom..updateXTo) { + val tile = world.getTileFromTerrain(x, y) ?: Block.STONE + val tileBelow = world.getTileFromTerrain(x, y + 1) ?: Block.STONE + + if (tile.maxSupport()) { + // displace fluid. This statement must precede isSolid() + if (tileBelow.isFluid()) { + // remove tileThis to create air pocket + world.setTileTerrain(x, y, Block.AIR) + + pour(x, y, drain(x, y, tileBelow.fluidLevel().toInt())) + // place our tile + world.setTileTerrain(x, y + 1, tile) + } + else if (!tileBelow.isSolid()) { + world.setTileTerrain(x, y, Block.AIR) + world.setTileTerrain(x, y + 1, tile) + } + } + } + }*/ + + // displace fallables (TODO implement blocks with fallable supports e.g. scaffolding) + // only displace SINGLE BOTTOMMOST block on single X-coord (this doesn't mean they must fall only one block) + // so that the "falling" should be visible to the end user + if (!DEBUG_STEPPING_MODE || DEBUG_STEPPING_MODE && KeyToggler.isOn (Input.Keys.PERIOD)) { + for (x in updateXFrom..updateXTo) { + var fallDownCounter = 0 + var fallableStackProcessed = false + // one "stack" is a contiguous fallable blocks, regardless of the actual block number + // when you are simulating the gradual falling, it is natural to process all the "stacks" at the same run, + // otherwise you'll get an artefact. + for (y in updateYTo downTo updateYFrom) { + val currentTile = world.getTileFromTerrain(x, y) + val prop = BlockCodex[currentTile] + val isSolid = prop.isSolid + val support = prop.maxSupport + val isFallable = support != -1 + + // mark the beginnig of the new "stack" + if (fallableStackProcessed && !isFallable) { + fallableStackProcessed = false + } // do not chain with "else if" + + // process the gradual falling of the selected "stack" + if (!fallableStackProcessed && fallDownCounter != 0 && isFallable) { + // replace blocks + world.setTileTerrain(x, y, Block.AIR) + world.setTileTerrain(x, y + fallDownCounter, currentTile) + + fallableStackProcessed = true + } + else if (isSolid) { + fallDownCounter = 0 + } + else if (!isSolid && !isFallable && fallDownCounter < FALLABLE_MAX_FALL_SPEED) { + fallDownCounter += 1 + } + } + } + + if (DEBUG_STEPPING_MODE) { + KeyToggler.forceSet(Input.Keys.PERIOD, false) + } + } + + + } + + + fun disperseHeat(delta: Float) { + + } + + + + + /* Explanation of get_stable_state_b (well, kind-of) : @@ -259,86 +377,6 @@ object WorldSimulator { private val FALLABLE_MAX_FALL_SPEED = 2 - /** - * displace fallable tiles. It is scanned bottom-left first. To achieve the sens ofreal - * falling, each tiles are displaced by ONLY ONE TILE below. - */ - fun displaceFallables(delta: Float) { - /*for (y in updateYFrom..updateYTo) { - for (x in updateXFrom..updateXTo) { - val tile = world.getTileFromTerrain(x, y) ?: Block.STONE - val tileBelow = world.getTileFromTerrain(x, y + 1) ?: Block.STONE - - if (tile.maxSupport()) { - // displace fluid. This statement must precede isSolid() - if (tileBelow.isFluid()) { - // remove tileThis to create air pocket - world.setTileTerrain(x, y, Block.AIR) - - pour(x, y, drain(x, y, tileBelow.fluidLevel().toInt())) - // place our tile - world.setTileTerrain(x, y + 1, tile) - } - else if (!tileBelow.isSolid()) { - world.setTileTerrain(x, y, Block.AIR) - world.setTileTerrain(x, y + 1, tile) - } - } - } - }*/ - - // displace fallables (TODO implement blocks with fallable supports e.g. scaffolding) - // only displace SINGLE BOTTOMMOST block on single X-coord (this doesn't mean they must fall only one block) - // so that the "falling" should be visible to the end user - if (!DEBUG_STEPPING_MODE || DEBUG_STEPPING_MODE && KeyToggler.isOn (Input.Keys.PERIOD)) { - for (x in updateXFrom..updateXTo) { - var fallDownCounter = 0 - var fallableStackProcessed = false - // one "stack" is a contiguous fallable blocks, regardless of the actual block number - // when you are simulating the gradual falling, it is natural to process all the "stacks" at the same run, - // otherwise you'll get an artefact. - for (y in updateYTo downTo updateYFrom) { - val currentTile = world.getTileFromTerrain(x, y) - val prop = BlockCodex[currentTile] - val isSolid = prop.isSolid - val support = prop.maxSupport - val isFallable = support != -1 - - // mark the beginnig of the new "stack" - if (fallableStackProcessed && !isFallable) { - fallableStackProcessed = false - } // do not chain with "else if" - - // process the gradual falling of the selected "stack" - if (!fallableStackProcessed && fallDownCounter != 0 && isFallable) { - // replace blocks - world.setTileTerrain(x, y, Block.AIR) - world.setTileTerrain(x, y + fallDownCounter, currentTile) - - fallableStackProcessed = true - } - else if (isSolid) { - fallDownCounter = 0 - } - else if (!isSolid && !isFallable && fallDownCounter < FALLABLE_MAX_FALL_SPEED) { - fallDownCounter += 1 - } - } - } - - if (DEBUG_STEPPING_MODE) { - KeyToggler.forceSet(Input.Keys.PERIOD, false) - } - } - - - } - - - fun disperseHeat(delta: Float) { - - } - private fun monitorIllegalFluidSetup() { for (y in 0 until fluidMap.size) { for (x in 0 until fluidMap[0].size) { @@ -380,5 +418,32 @@ object WorldSimulator { fun Int.isFallable() = BlockCodex[this].maxSupport + private val actorMBRConverter = object : MBRConverter { + override fun getDimensions(): Int = 2 + override fun getMin(axis: Int, t: ActorWithBody): Double = + when (axis) { + 0 -> t.hitbox.startX + 1 -> t.hitbox.startY + else -> throw IllegalArgumentException("nonexistent axis $axis for ${dimensions}-dimensional object") + } + override fun getMax(axis: Int, t: ActorWithBody): Double = + when (axis) { + 0 -> t.hitbox.endX + 1 -> t.hitbox.endY + else -> throw IllegalArgumentException("nonexistent axis $axis for ${dimensions}-dimensional object") + } + } + + // simple euclidean norm, squared + private val actorDistanceCalculator = object : DistanceCalculator { + override fun distanceTo(t: ActorWithBody, p: PointND): Double { + val dist1 = (p.getOrd(0) - t.hitbox.centeredX).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr() + // ROUNDWORLD implementation + val dist2 = (p.getOrd(0) - (t.hitbox.centeredX - world.width * TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr() + val dist3 = (p.getOrd(0) - (t.hitbox.centeredX + world.width * TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr() + + return minOf(dist1, minOf(dist2, dist3)) + } + } } \ No newline at end of file