diff --git a/src/net/torvald/terrarum/Point2d.kt b/src/net/torvald/terrarum/Point2d.kt index fbbb992e4..bd6e52695 100644 --- a/src/net/torvald/terrarum/Point2d.kt +++ b/src/net/torvald/terrarum/Point2d.kt @@ -11,6 +11,8 @@ class Point2d() : Cloneable { var x: Double = 0.0 var y: Double = 0.0 + constructor(other: Point2d) : this(other.x, other.y) + constructor(x: Double, y: Double) : this() { this.x = x this.y = y diff --git a/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt b/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt index 9e363f09d..917ef1232 100644 --- a/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt +++ b/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt @@ -13,12 +13,20 @@ import net.torvald.random.HQRNG import net.torvald.terrarum.* import net.torvald.terrarum.App.* import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE +import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF +import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.gameactors.ActorWithBody +import net.torvald.terrarum.gameactors.ActorWithBody.Companion.METER +import net.torvald.terrarum.gameactors.ActorWithBody.Companion.SI_TO_GAME_ACC import net.torvald.terrarum.gamecontroller.KeyToggler +import net.torvald.terrarum.gameitems.GameItem import net.torvald.terrarum.gameparticles.ParticleBase import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.fmod +import net.torvald.terrarum.modulebasegame.gameactors.Pocketed +import net.torvald.terrarum.modulebasegame.gameitems.ItemThrowable +import net.torvald.terrarum.modulebasegame.gameitems.getThrowPosAndVector import net.torvald.terrarum.ui.Toolkit import net.torvald.terrarum.weather.WeatherMixer import net.torvald.terrarum.weather.WeatherMixer.render @@ -27,6 +35,7 @@ import net.torvald.terrarum.worlddrawer.FeaturesDrawer import net.torvald.terrarum.worlddrawer.LightmapRenderer import net.torvald.terrarum.worlddrawer.WorldCamera import net.torvald.util.CircularArray +import org.dyn4j.geometry.Vector2 import kotlin.system.exitProcess @@ -248,6 +257,8 @@ object IngameRenderer : Disposable { drawToRGB(frameDelta, actorsRenderBehind, actorsRenderMiddle, actorsRenderMidTop, actorsRenderFront, actorsRenderOverlay, particlesContainer) drawToA(frameDelta, actorsRenderBehind, actorsRenderMiddle, actorsRenderMidTop, actorsRenderFront, actorsRenderOverlay, particlesContainer) drawOverlayActors(frameDelta, actorsRenderOverlay) + + if (player != null && player is Pocketed) drawAimGuide(frameDelta, player) } batch.color = Color.WHITE @@ -730,6 +741,101 @@ object IngameRenderer : Disposable { } } + private fun drawAimGuide(frameDelta: Float, player: ActorWithBody) { + fboRGB_lightMixed.inActionF(camera, batch) { fb -> + + setCameraPosition(0f, 0f) + // BlocksDrawer.renderWhateverGlow_WALL + + batch.inUse { + batch.shader = null + batch.color = Color.WHITE + + moveCameraToWorldCoord() + + (player as Pocketed).inventory.itemEquipped[GameItem.EquipPosition.HAND_GRIP]?.let { itemID -> + val heldItem = ItemCodex[itemID] // will be null for blocks + // this is a case-by-case affair + when (heldItem) { + is ItemThrowable -> drawAimGuideForThrowable(fb, batch, frameDelta, player, world, heldItem) + } + } + } + + setCameraPosition(0f, 0f) + // BlocksDrawer.renderWhateverGlow_TERRAIN + } + } + + private val externalV = Vector2() + private fun drawAimGuideForThrowable(frameBuffer: FrameBuffer, batch: SpriteBatch, frameDelta: Float, player: ActorWithBody, world: GameWorld, item: ItemThrowable) { + val (throwPos, throwVector) = getThrowPosAndVector(player) + val grav = world.gravitation + externalV.set(throwVector) + + batch.color = Color.WHITE // TODO get better colour + + + var c = 0 + while (c < 50) { + // plot a dot + Toolkit.fillArea(batch, throwPos.x.toFloat(), throwPos.y.toFloat(), 2f, 2f) + + // simulate physics + applyGravitation(grav, 7.0) // TODO use actual value instead of 7.0 + + // FIXME the ActorWithBody phys sim -- horizontal speed is lost aggressively + + // move the point + throwPos += externalV + + + // break if colliding with a tile + if (BlockCodex[world.getTileFromTerrain(throwPos.x.div(TILE_SIZED).toInt(), throwPos.x.div(TILE_SIZED).toInt())].isSolid) + break + + c++ + } + + } + + private fun applyGravitation(gravitation: Vector2, hitboxWidth: Double) { + applyForce(getDrag(externalV, gravitation, hitboxWidth)) + } + + private fun Int.viscosityToMult(): Double = 16.0 / (16.0 + this) + + private fun applyForce(acc: Vector2) { + val speedMultByTile = BlockCodex[Block.AIR].viscosity.viscosityToMult() + externalV += acc * speedMultByTile + } + + private fun getDrag(externalForce: Vector2, gravitation: Vector2, hitboxWidth: Double): Vector2 { + val dragCoefficient = 1.2 + + /** + * weight; gravitational force in action + * W = mass * G (9.8 [m/s^2]) + */ + val W: Vector2 = gravitation * Terrarum.PHYS_TIME_FRAME + /** + * Area + */ + val A: Double = (hitboxWidth / METER).sqr() // this is not physically accurate but it's needed to make large playable characters more controllable + /** + * Drag of atmosphere + * D = Cd (drag coefficient) * 0.5 * rho (density) * V^2 (velocity sqr) * A (area) + */ + val D: Vector2 = Vector2(externalForce.x.magnSqr(), externalForce.y.magnSqr()) * dragCoefficient * 0.5 * A// * tileDensityFluid.toDouble() + + val V: Vector2 = (W - D) / Terrarum.PHYS_TIME_FRAME * SI_TO_GAME_ACC + + 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. + } + private fun invokeInit() { if (!initDone) { diff --git a/src/net/torvald/terrarum/modulebasegame/gameitems/ItemThrowable.kt b/src/net/torvald/terrarum/modulebasegame/gameitems/ItemThrowable.kt index 43fb3ee86..2d3333e4e 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameitems/ItemThrowable.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameitems/ItemThrowable.kt @@ -31,19 +31,11 @@ open class ItemThrowable(originalID: ItemID, private val throwableActorClassName } override fun startPrimaryUse(actor: ActorWithBody, delta: Float): Long = mouseInInteractableRange(actor) { mx, my, mtx, mty -> - - val playerCentrePos = actor.centrePosVector - val mousePos = Vector2(mx, my) - - val actorPowMult = actor.avStrength / 2000.0 - val relativeX = relativeXposition(actor, mousePos) - val relativeY = my - playerCentrePos.y - val powX = relativeX / TILE_SIZED * 3.0 * actorPowMult - val powY = relativeY / TILE_SIZED * 3.0 * actorPowMult + val (throwPos, throwForce) = getThrowPosAndVector(actor) val lobbed = Class.forName(throwableActorClassName).getDeclaredConstructor().newInstance() as ActorWithBody - lobbed.setPosition(playerCentrePos) - lobbed.externalV.set(powX, powY) + lobbed.setPosition(throwPos) + lobbed.externalV.set(throwForce) setupLobbedActor(lobbed) Terrarum.ingame?.queueActorAddition(lobbed) @@ -52,6 +44,24 @@ open class ItemThrowable(originalID: ItemID, private val throwableActorClassName 1L } + + +} + +/** + * @return pair of throwing start position, throwing force + */ +fun getThrowPosAndVector(actor: ActorWithBody): Pair { + val playerCentrePos = Vector2(actor.centrePosVector) // make a COPY of the actor.centrePosPoint + val mousePos = Vector2(Terrarum.mouseX, Terrarum.mouseY) + + val actorPowMult = actor.avStrength / 2000.0 + val relativeX = relativeXposition(actor, mousePos) + val relativeY = mousePos.y - playerCentrePos.y + val powX = relativeX / TILE_SIZED * 3.0 * actorPowMult + val powY = relativeY / TILE_SIZED * 3.0 * actorPowMult + + return Pair(playerCentrePos, Vector2(powX, powY)) }