mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-10 10:34:06 +09:00
partially working conveyor
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.INGAME
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
import net.torvald.terrarum.inUse
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
import java.util.*
|
||||
import kotlin.math.*
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2025-03-10.
|
||||
*/
|
||||
class ActorConveyors : ActorWithBody {
|
||||
|
||||
// make it savegame-reloadable
|
||||
private constructor() {
|
||||
x1 = -1
|
||||
y1 = -1
|
||||
x2 = -1
|
||||
y2 = -1
|
||||
|
||||
s = 0.0
|
||||
|
||||
di = 0.0
|
||||
dd = 0.0
|
||||
|
||||
cx1 = 0.0
|
||||
cy1 = 0.0
|
||||
cx2 = 0.0
|
||||
cy2 = 0.0
|
||||
|
||||
r = 0.5 * TILE_SIZED.minus(2)
|
||||
c = 0
|
||||
|
||||
btx1 = 0.0
|
||||
bty1 = 0.0
|
||||
btx2 = 0.0
|
||||
bty2 = 0.0
|
||||
|
||||
bbx1 = 0.0
|
||||
bby1 = 0.0
|
||||
bbx2 = 0.0
|
||||
bby2 = 0.0
|
||||
}
|
||||
|
||||
val x1: Int // can be negative when the conveyor crosses the world border
|
||||
val y1: Int
|
||||
val x2: Int // always positive
|
||||
val y2: Int
|
||||
|
||||
private val s: Double // belt length
|
||||
private val c: Int // segment counts
|
||||
|
||||
private val di: Double // inclination deg
|
||||
private val dd: Double // declination deg
|
||||
|
||||
private val cx1: Double // centre of the left spindle
|
||||
private val cy1: Double
|
||||
private val cx2: Double // centre of the right spindle
|
||||
private val cy2: Double
|
||||
|
||||
private val r: Double // radius
|
||||
|
||||
private val btx1: Double // line points of the top belt
|
||||
private val bty1: Double
|
||||
private val btx2: Double
|
||||
private val bty2: Double
|
||||
|
||||
private val bbx1: Double // line points of the bottom bolt
|
||||
private val bby1: Double
|
||||
private val bbx2: Double
|
||||
private val bby2: Double
|
||||
|
||||
/**
|
||||
* xy1 is always the starting point, and the starting point's x-value is always lower than the end points',
|
||||
* even when the conveyor crosses the edge of the world border, in which case the x-value is negative.
|
||||
*/
|
||||
constructor(x1: Int, y1: Int, x2: Int, y2: Int) {
|
||||
this.x1 = x1
|
||||
this.y1 = y1
|
||||
this.x2 = x2
|
||||
this.y2 = y2
|
||||
|
||||
s = calcBeltLength(x1, y1, x2, y2)
|
||||
|
||||
di = atan2(this.y2.toDouble() - this.y1, this.x2.toDouble() - this.x1)
|
||||
dd = atan2(this.y1.toDouble() - this.y2, this.x1.toDouble() - this.x2)
|
||||
|
||||
cx1 = (this.x1 + 0.5) * TILE_SIZED
|
||||
cy1 = (this.y1 + 0.5) * TILE_SIZED
|
||||
cx2 = (this.x2 + 0.5) * TILE_SIZED
|
||||
cy2 = (this.y2 + 0.5) * TILE_SIZED
|
||||
|
||||
r = 0.5 * TILE_SIZED.minus(2)
|
||||
c = (s / 8).roundToInt() * 2 // 4px segments rounded towards nearest even number
|
||||
|
||||
btx1 = cx1 + r * sin(di)
|
||||
bty1 = cy1 + r * cos(di)
|
||||
btx2 = cx2 + r * sin(di)
|
||||
bty2 = cy2 + r * cos(di)
|
||||
|
||||
bbx1 = cx1 + r * sin(dd)
|
||||
bby1 = cy1 + r * cos(dd)
|
||||
bbx2 = cx2 + r * sin(dd)
|
||||
bby2 = cy2 + r * cos(dd)
|
||||
}
|
||||
|
||||
private fun calcBeltLength(x1: Int, y1: Int, x2: Int, y2: Int) =
|
||||
2 * (hypot((x2 - x1) * TILE_SIZED, (y2 - y1) * TILE_SIZED) + Math.PI * TILE_SIZED / 2)
|
||||
|
||||
|
||||
override fun drawBody(frameDelta: Float, batch: SpriteBatch) {
|
||||
|
||||
App.shapeRender.inUse {
|
||||
it.color = Color.RED
|
||||
|
||||
// belt top
|
||||
drawLineOnWorld(btx1, bty1, btx2, bty2)
|
||||
// belt bottom
|
||||
drawLineOnWorld(bbx1, bby1, bbx2, bby2)
|
||||
// left arc
|
||||
drawArcOnWorld(cx1, cy1, r, dd, Math.PI)
|
||||
// right arc
|
||||
drawArcOnWorld(cx2, cy2, r, di, Math.PI)
|
||||
}
|
||||
}
|
||||
|
||||
private fun drawLineOnWorld(x1: Double, y1: Double, x2: Double, y2: Double) {
|
||||
val w = 2.0f
|
||||
App.shapeRender.rectLine(
|
||||
x1.toFloat() - WorldCamera.x, y1.toFloat() - WorldCamera.y,
|
||||
x2.toFloat() - WorldCamera.x, y2.toFloat() - WorldCamera.y,
|
||||
w
|
||||
)
|
||||
}
|
||||
|
||||
private fun drawArcOnWorld(xc: Double, yc: Double, r: Double, arcStart: Double, arcDeg: Double) {
|
||||
// dissect the circle
|
||||
// val pathLen = arcDeg * r
|
||||
//// estimated number of segments. pathLen divided by sqrt(2)
|
||||
// val segments = Math.round(pathLen / Double.fromBits(0x3FF6A09E667F3BCDL)).coerceAtLeast(1L).toInt()
|
||||
val segments = 12 * 8
|
||||
|
||||
for (i in 0 until segments) {
|
||||
val degStart = (i.toDouble() / segments) * arcDeg + arcStart
|
||||
val degEnd = ((i + 1.0) / segments) * arcDeg + arcStart
|
||||
|
||||
val x1 = r * sin(degStart) + xc
|
||||
val y1 = r * cos(degStart) + yc
|
||||
val x2 = r * sin(degEnd) + xc
|
||||
val y2 = r * cos(degEnd) + yc
|
||||
|
||||
drawLineOnWorld(x1, y1, x2, y2)
|
||||
}
|
||||
}
|
||||
|
||||
/** Real time, in nanoseconds */
|
||||
@Transient var spawnRequestedTime: Long = 0L
|
||||
protected set
|
||||
|
||||
internal var actorThatInstalledThisFixture: UUID? = null
|
||||
|
||||
open fun spawn(installerUUID: UUID?): Boolean {
|
||||
this.isVisible = true
|
||||
|
||||
val posXtl = minOf(x1, x2).toDouble()
|
||||
val posYtl = minOf(y1, y2).toDouble()
|
||||
val posXbr = maxOf(x1, x2).toDouble()
|
||||
val posYbr = maxOf(y1, y2).toDouble()
|
||||
|
||||
this.hitbox.setFromTwoPoints(posXtl * TILE_SIZED, posYtl * TILE_SIZED, (posXbr+1) * TILE_SIZED, (posYbr+1) * TILE_SIZED)
|
||||
this.setHitboxDimension(this.hitbox.width.toInt(), this.hitbox.height.toInt(), 0, 1)
|
||||
this.intTilewiseHitbox.setFromTwoPoints(posXtl, posYtl, posXbr, posYbr)
|
||||
|
||||
// actually add this actor into the world
|
||||
INGAME.queueActorAddition(this)
|
||||
spawnRequestedTime = System.nanoTime()
|
||||
|
||||
actorThatInstalledThisFixture = installerUUID
|
||||
|
||||
//makeNoiseAndDust(posXtl, posYtl)
|
||||
|
||||
onSpawn()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Callend whenever the fixture was spawned successfully.
|
||||
*/
|
||||
open fun onSpawn() {}
|
||||
}
|
||||
@@ -104,10 +104,7 @@ open class FixtureItemBase(originalID: ItemID, val fixtureClassName: String) : G
|
||||
// return true when placed, false when cannot be placed
|
||||
}
|
||||
|
||||
override fun startSecondaryUse(actor: ActorWithBody, delta: Float) = mouseInInteractableRange(actor) { mwx, mwy, mtx, mty ->
|
||||
(INGAME as TerrarumIngame).pickupFixtureOrDroppedItem(actor, delta, mwx, mwy, mtx, mty, false)
|
||||
-1
|
||||
}
|
||||
override fun startSecondaryUse(actor: ActorWithBody, delta: Float) = fixturePickupFun(actor, delta)
|
||||
|
||||
/**
|
||||
* Also see: [net.torvald.terrarum.modulebasegame.gameactors.FixtureBase.Companion]
|
||||
@@ -128,5 +125,10 @@ open class FixtureItemBase(originalID: ItemID, val fixtureClassName: String) : G
|
||||
TextureRegion(Texture(ModMgr.getGdxFile(module, path)))
|
||||
} as TextureRegion
|
||||
}
|
||||
|
||||
fun fixturePickupFun(actor: ActorWithBody, delta: Float) = mouseInInteractableRange(actor) { mwx, mwy, mtx, mty ->
|
||||
(INGAME as TerrarumIngame).pickupFixtureOrDroppedItem(actor, delta, mwx, mwy, mtx, mty, false)
|
||||
-1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameitems
|
||||
|
||||
import net.torvald.terrarum.INGAME
|
||||
import net.torvald.terrarum.Point2i
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.gameitems.mouseInInteractableRange
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorConveyors
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2025-03-15.
|
||||
*/
|
||||
open class ItemConveyorBelt(originalID: ItemID) : GameItem(originalID) {
|
||||
override var baseMass = 10.0
|
||||
override var baseToolSize: Double? = null
|
||||
override var inventoryCategory = Category.FIXTURE
|
||||
override val canBeDynamic = false
|
||||
override val materialId = ""
|
||||
override var equipPosition = EquipPosition.HAND_GRIP
|
||||
|
||||
override var originalName = "CONVEYOR_BELT"
|
||||
|
||||
|
||||
protected val AXLE_COUNT = 2
|
||||
|
||||
|
||||
private var currentStatus = 0 // 0: initial, 1+: place n-th axle
|
||||
|
||||
private val occupiedPoints = HashSet<Point2i>()
|
||||
|
||||
override fun startPrimaryUse(actor: ActorWithBody, delta: Float) = mouseInInteractableRange(actor) { _, _, mtx, mty ->
|
||||
val ret = when (currentStatus) {
|
||||
0 -> placeFirstAxle(mtx, mty)
|
||||
1 -> placeSecondAxleAndFinalise(mtx, mty)
|
||||
else -> {
|
||||
currentStatus = 0
|
||||
-1L
|
||||
}
|
||||
}
|
||||
|
||||
currentStatus += 1
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
override fun startSecondaryUse(actor: ActorWithBody, delta: Float): Long {
|
||||
return when (currentStatus) {
|
||||
0 -> FixtureItemBase.fixturePickupFun(actor, delta)
|
||||
else -> {
|
||||
currentStatus = -1
|
||||
-1L
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun placeFirstAxle(mx: Int, my: Int): Long {
|
||||
occupiedPoints.add(Point2i(mx, my))
|
||||
return 0L
|
||||
}
|
||||
|
||||
private fun placeSecondAxleAndFinalise(mx: Int, my: Int): Long {
|
||||
Point2i(mx, my).let { p2 ->
|
||||
if (!occupiedPoints.contains(p2)) {
|
||||
occupiedPoints.add(p2)
|
||||
}
|
||||
else {
|
||||
currentStatus = -1
|
||||
return 0L
|
||||
}
|
||||
|
||||
// sort occupiedPoints by its x value
|
||||
val points = occupiedPoints.toMutableList().also { it.sortBy { it.x } }.also { list ->
|
||||
// check for ROUNDWORLD
|
||||
val xMin = list[0].x
|
||||
val xMax = list[1].x
|
||||
// normalise it by making the x value for left spindle to negative
|
||||
if (xMin >= 0 && xMin < INGAME.world.width / 2 && xMax >= INGAME.world.width / 2) {
|
||||
list[0].x -= INGAME.world.width
|
||||
}
|
||||
}
|
||||
|
||||
val conveyors = ActorConveyors(points[0].x, points[0].y, points[1].x, points[1].y)
|
||||
conveyors.spawn((INGAME.actorNowPlaying as? IngamePlayer)?.uuid)
|
||||
}
|
||||
|
||||
occupiedPoints.clear()
|
||||
currentStatus = -1
|
||||
|
||||
return 1L
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user