mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-12 19:44:05 +09:00
door automatic opening/closing now works
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
package net.torvald.spriteanimation
|
package net.torvald.spriteanimation
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color
|
|
||||||
import com.badlogic.gdx.graphics.Pixmap
|
import com.badlogic.gdx.graphics.Pixmap
|
||||||
import com.badlogic.gdx.graphics.Texture
|
import com.badlogic.gdx.graphics.Texture
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
@@ -162,6 +161,7 @@ class AssembledSpriteAnimation(
|
|||||||
|
|
||||||
override fun render(batch: SpriteBatch, posX: Float, posY: Float, scale: Float) {
|
override fun render(batch: SpriteBatch, posX: Float, posY: Float, scale: Float) {
|
||||||
if (parentActor.isVisible) {
|
if (parentActor.isVisible) {
|
||||||
|
batch.color = colourFilter
|
||||||
renderThisAnimation(batch, posX, posY, scale, "${currentAnimation}_${1+currentFrame}")
|
renderThisAnimation(batch, posX, posY, scale, "${currentAnimation}_${1+currentFrame}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.torvald.spriteanimation
|
package net.torvald.spriteanimation
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
import com.badlogic.gdx.utils.Disposable
|
import com.badlogic.gdx.utils.Disposable
|
||||||
import com.jme3.math.FastMath
|
import com.jme3.math.FastMath
|
||||||
@@ -19,6 +20,7 @@ abstract class SpriteAnimation(@Transient val parentActor: ActorWithBody) : Disp
|
|||||||
|
|
||||||
var flipHorizontal = false
|
var flipHorizontal = false
|
||||||
var flipVertical = false
|
var flipVertical = false
|
||||||
|
var colourFilter = Color(-1)
|
||||||
|
|
||||||
open fun flip(horizontal: Boolean, vertical: Boolean) {
|
open fun flip(horizontal: Boolean, vertical: Boolean) {
|
||||||
flipHorizontal = horizontal
|
flipHorizontal = horizontal
|
||||||
@@ -144,8 +146,7 @@ class SheetSpriteAnimation(parentActor: ActorWithBody) : SpriteAnimation(parentA
|
|||||||
|
|
||||||
if (visible) {
|
if (visible) {
|
||||||
val region = textureRegion.get(currentFrame, currentRow)
|
val region = textureRegion.get(currentFrame, currentRow)
|
||||||
// batch.color = colorFilter
|
batch.color = colourFilter
|
||||||
|
|
||||||
|
|
||||||
val tx = (parentActor.hitboxTranslateX) * scale
|
val tx = (parentActor.hitboxTranslateX) * scale
|
||||||
val txF = (parentActor.hitboxTranslateX + parentActor.baseHitboxW) * scale
|
val txF = (parentActor.hitboxTranslateX + parentActor.baseHitboxW) * scale
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ open class ActorWithBody : Actor {
|
|||||||
protected set
|
protected set
|
||||||
open var tooltipText: String? = null // null: display nothing
|
open var tooltipText: String? = null // null: display nothing
|
||||||
val mouseUp: Boolean
|
val mouseUp: Boolean
|
||||||
get() = hitbox.containsPoint(Terrarum.mouseX, Terrarum.mouseY)
|
get() = hitbox.containsPoint((world?.width ?: 0) * TILE_SIZED, Terrarum.mouseX, Terrarum.mouseY)
|
||||||
|
|
||||||
var hitboxTranslateX: Int = 0// relative to spritePosX
|
var hitboxTranslateX: Int = 0// relative to spritePosX
|
||||||
protected set
|
protected set
|
||||||
|
|||||||
@@ -158,21 +158,24 @@ class Hitbox {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO consider ROUNDWORLD
|
/** *ROUNDWORLD*-aware version of intersects(Double, Double). */
|
||||||
fun containsPoint(x: Double, y: Double) = (x - hitboxStart.x) in 0.0..width && (y - hitboxStart.y) in 0.0..height
|
fun containsPoint(worldWidth: Double, x: Double, y: Double) = intersects(x, y) || intersects(x + worldWidth, y) || intersects(x - worldWidth, y)
|
||||||
fun containsPoint(p: Point2d) = containsPoint(p.x, p.y)
|
/** *ROUNDWORLD*-aware version of intersects(Poind2d). */
|
||||||
|
fun containsPoint(worldWidth: Double, p: Point2d) = containsPoint(worldWidth, p.x, p.y)
|
||||||
|
/** *ROUNDWORLD*-aware version of intersects(Hitbox). */
|
||||||
infix fun intersects(position: Point2d) =
|
fun containsHitbox(worldWidth: Double, other: Hitbox): Boolean {
|
||||||
(position.x >= startX && position.x <= startX + width) &&
|
val osx = other.startX; val osy = other.startY; val oex = other.endX; val oey = other.endY // to avoid redundant maths operations
|
||||||
(position.y >= startY && position.y <= startY + height)
|
return intersects(osx, osy, oex, oey) || intersects(osx + worldWidth, osy, oex + worldWidth, oey) || intersects(osx - worldWidth, osy, oex - worldWidth, oey)
|
||||||
infix fun intersects(other: Hitbox) =
|
}
|
||||||
(this.startX <= other.startX && other.startX <= this.endX) ||
|
|
||||||
(this.startX <= other.endX && other.endX <= this.endX) &&
|
|
||||||
|
|
||||||
(this.startY <= other.startY && other.startY <= this.endY) ||
|
|
||||||
(this.startY <= other.endY && other.endY <= this.endY)
|
|
||||||
|
|
||||||
|
fun intersects(px: Double, py: Double) =
|
||||||
|
(px in startX..endX) &&
|
||||||
|
(py in startY..endY)
|
||||||
|
infix fun intersects(position: Point2d) = intersects(position.x, position.y)
|
||||||
|
infix fun intersects(other: Hitbox) = intersects(other.startX, other.startY, other.endX, other.endY)
|
||||||
|
fun intersects(otherStartX: Double, otherStartY: Double, otherEndX: Double, otherEndY: Double) =
|
||||||
|
(this.endX >= otherStartX && otherEndX >= this.startX) &&
|
||||||
|
(this.endY >= otherStartY && otherEndY >= this.startY)
|
||||||
|
|
||||||
fun toVector(): Vector2 = Vector2(startX, startY)
|
fun toVector(): Vector2 = Vector2(startX, startY)
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
|
|||||||
* @param action a function with following arguments: posX, posY, offX, offY
|
* @param action a function with following arguments: posX, posY, offX, offY
|
||||||
*/
|
*/
|
||||||
open fun forEachBlockbox(action: (Int, Int, Int, Int) -> Unit) {
|
open fun forEachBlockbox(action: (Int, Int, Int, Int) -> Unit) {
|
||||||
|
// TODO scale-aware
|
||||||
worldBlockPos?.let { (posX, posY) ->
|
worldBlockPos?.let { (posX, posY) ->
|
||||||
for (y in posY until posY + blockBox.height) {
|
for (y in posY until posY + blockBox.height) {
|
||||||
for (x in posX until posX + blockBox.width) {
|
for (x in posX until posX + blockBox.width) {
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
|
|||||||
doorState = 0
|
doorState = 0
|
||||||
placeActorBlocks()
|
placeActorBlocks()
|
||||||
}
|
}
|
||||||
|
doorCloseQueued = false
|
||||||
}
|
}
|
||||||
|
|
||||||
open protected fun openToRight() {
|
open protected fun openToRight() {
|
||||||
@@ -113,6 +114,7 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
|
|||||||
doorState = 1
|
doorState = 1
|
||||||
placeActorBlocks()
|
placeActorBlocks()
|
||||||
}
|
}
|
||||||
|
doorCloseQueued = false
|
||||||
}
|
}
|
||||||
|
|
||||||
open protected fun openToLeft() {
|
open protected fun openToLeft() {
|
||||||
@@ -121,6 +123,7 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
|
|||||||
doorState = -1
|
doorState = -1
|
||||||
placeActorBlocks()
|
placeActorBlocks()
|
||||||
}
|
}
|
||||||
|
doorCloseQueued = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/*override fun forEachBlockbox(action: (Int, Int, Int, Int) -> Unit) {
|
/*override fun forEachBlockbox(action: (Int, Int, Int, Int) -> Unit) {
|
||||||
@@ -174,10 +177,10 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ActorWithBody.ontheLeftSideOfDoor(): Boolean {
|
private fun ActorWithBody.ontheLeftSideOfDoor(): Boolean {
|
||||||
return this.hitbox.centeredX < this@FixtureSwingingDoorBase.hitbox.centeredX
|
return this.hitbox.startX < this@FixtureSwingingDoorBase.hitbox.centeredX
|
||||||
}
|
}
|
||||||
private fun ActorWithBody.ontheRightSideOfDoor(): Boolean {
|
private fun ActorWithBody.ontheRightSideOfDoor(): Boolean {
|
||||||
return this.hitbox.centeredX > this@FixtureSwingingDoorBase.hitbox.centeredX
|
return this.hitbox.endX > this@FixtureSwingingDoorBase.hitbox.centeredX
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ActorWithBody.movingTowardsRight(): Boolean {
|
private fun ActorWithBody.movingTowardsRight(): Boolean {
|
||||||
@@ -190,66 +193,102 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
|
|||||||
return ((this.controllerV ?: Vector2()) + this.externalV).x.absoluteValue < PHYS_EPSILON_VELO
|
return ((this.controllerV ?: Vector2()) + this.externalV).x.absoluteValue < PHYS_EPSILON_VELO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var doorCloseQueueTimer = 0f
|
||||||
|
private var doorCloseQueued = false
|
||||||
|
|
||||||
|
private fun queueDoorClosing() {
|
||||||
|
doorCloseQueueTimer = 0f
|
||||||
|
doorCloseQueued = true
|
||||||
|
}
|
||||||
|
|
||||||
override fun update(delta: Float) {
|
override fun update(delta: Float) {
|
||||||
super.update(delta)
|
super.update(delta)
|
||||||
|
|
||||||
|
|
||||||
|
// debug colouring
|
||||||
|
// this.sprite?.colourFilter =
|
||||||
|
// if (doorCloseQueued) Color.YELLOW
|
||||||
|
// else if (doorStateTimer > doorHoldLength[doorState]!!) Color.LIME
|
||||||
|
// else Color.CORAL
|
||||||
|
|
||||||
|
|
||||||
if (!flagDespawn && worldBlockPos != null) {
|
if (!flagDespawn && worldBlockPos != null) {
|
||||||
val actors = INGAME.actorContainerActive.filterIsInstance<ActorWithBody>()
|
// delayed auto closing
|
||||||
|
if (doorCloseQueued && doorCloseQueueTimer >= doorOpenedHoldLength) {
|
||||||
// auto opening and closing
|
closeDoor()
|
||||||
// TODO make this work with "player_alies" faction, not just a player
|
}
|
||||||
val installer: IngamePlayer? = if (actorThatInstalledThisFixture == null) null else INGAME.actorContainerActive.filterIsInstance<IngamePlayer>().filter { it.uuid == actorThatInstalledThisFixture }.ifEmpty {
|
else if (doorCloseQueued) {
|
||||||
INGAME.actorContainerInactive.filterIsInstance<IngamePlayer>().filter { it.uuid == actorThatInstalledThisFixture }
|
doorCloseQueueTimer += delta
|
||||||
}.getOrNull(0)
|
|
||||||
|
|
||||||
// if the door is "owned" by someone, restrict access to its "amicable" (defined using Faction subsystem) actors
|
|
||||||
// if the door is owned by null, restrict access to ActorHumanoid and actors with "intelligent" actor value set up
|
|
||||||
if (actorThatInstalledThisFixture == null || installer != null) {
|
|
||||||
val amicableActors: List<ActorWithBody> = ArrayList(
|
|
||||||
if (actorThatInstalledThisFixture == null)
|
|
||||||
actors.filterIsInstance<ActorHumanoid>() union actors.filter { it.actorValue.getAsBoolean("intelligent") == true }
|
|
||||||
else {
|
|
||||||
val goodFactions = installer?.faction?.flatMap { it.factionAmicable }?.toHashSet()
|
|
||||||
if (goodFactions != null)
|
|
||||||
actors.filterIsInstance<Factionable>().filter {
|
|
||||||
(it.faction.map { it.factionName } intersect goodFactions).isNotEmpty()
|
|
||||||
} as List<ActorWithBody>
|
|
||||||
else
|
|
||||||
listOf()
|
|
||||||
}
|
|
||||||
).also {
|
|
||||||
// add the installer of the door to the amicableActors if for some reason it was not added
|
|
||||||
if (installer != null && !it.contains(installer)) it.add(0, installer)
|
|
||||||
}.filter {
|
|
||||||
// filter amicableActors so that ones standing near the door remain
|
|
||||||
it.hitbox.intersects(this.hitbox)
|
|
||||||
}
|
|
||||||
|
|
||||||
// automatic opening/closing
|
|
||||||
if (doorStateTimer > doorHoldLength[doorState]!!) {
|
|
||||||
var nobodyIsThere = true
|
|
||||||
for (actor in amicableActors) {
|
|
||||||
if (actor.ontheLeftSideOfDoor() && actor.movingTowardsRight()) {
|
|
||||||
openToRight()
|
|
||||||
nobodyIsThere = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
else if (actor.ontheRightSideOfDoor() && actor.movingTowardsLeft()) {
|
|
||||||
openToLeft()
|
|
||||||
nobodyIsThere = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nobodyIsThere) {
|
|
||||||
closeDoor()
|
|
||||||
}
|
|
||||||
|
|
||||||
doorStateTimer = 0f
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// automatic opening/closing
|
||||||
|
if (doorStateTimer > doorHoldLength[doorState]!!) {
|
||||||
|
val actors = INGAME.actorContainerActive.filterIsInstance<ActorWithBody>()
|
||||||
|
|
||||||
|
// auto opening and closing
|
||||||
|
// TODO make this work with "player_alies" faction, not just a player
|
||||||
|
val installer: IngamePlayer? = if (actorThatInstalledThisFixture == null) null
|
||||||
|
else INGAME.actorContainerActive.filterIsInstance<IngamePlayer>().filter { it.uuid == actorThatInstalledThisFixture }.ifEmpty {
|
||||||
|
INGAME.actorContainerInactive.filterIsInstance<IngamePlayer>().filter { it.uuid == actorThatInstalledThisFixture }
|
||||||
|
}.getOrNull(0)
|
||||||
|
|
||||||
|
// if the door is "owned" by someone, restrict access to its "amicable" (defined using Faction subsystem) actors
|
||||||
|
// if the door is owned by null, restrict access to ActorHumanoid and actors with "intelligent" actor value set up
|
||||||
|
if (actorThatInstalledThisFixture == null || installer != null) {
|
||||||
|
val amicableActors: List<ActorWithBody> = ArrayList(
|
||||||
|
if (actorThatInstalledThisFixture == null)
|
||||||
|
actors.filterIsInstance<ActorHumanoid>() union actors.filter { it.actorValue.getAsBoolean("intelligent") == true }
|
||||||
|
else {
|
||||||
|
val goodFactions = installer?.faction?.flatMap { it.factionAmicable }?.toHashSet()
|
||||||
|
if (goodFactions != null)
|
||||||
|
actors.filterIsInstance<Factionable>().filter {
|
||||||
|
(it.faction.map { it.factionName } intersect goodFactions).isNotEmpty()
|
||||||
|
} as List<ActorWithBody>
|
||||||
|
else
|
||||||
|
listOf()
|
||||||
|
}
|
||||||
|
).also {
|
||||||
|
// add the installer of the door to the amicableActors if for some reason it was not added
|
||||||
|
if (installer != null && !it.contains(installer)) it.add(0, installer)
|
||||||
|
}.filter {
|
||||||
|
// filter amicableActors so that ones standing near the door remain
|
||||||
|
this.hitbox.containsHitbox(INGAME.world.width * TILE_SIZED, it.hitbox)
|
||||||
|
}
|
||||||
|
|
||||||
|
var nobodyIsThere = true
|
||||||
|
val oldState = doorState
|
||||||
|
|
||||||
|
for (actor in amicableActors) {
|
||||||
|
if (doorState != 0) {
|
||||||
|
if (this.hitbox.containsHitbox(INGAME.world.width * TILE_SIZED, actor.hitbox)) {
|
||||||
|
nobodyIsThere = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (actor.ontheLeftSideOfDoor() && actor.movingTowardsRight()) {
|
||||||
|
openToRight()
|
||||||
|
nobodyIsThere = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
else if (actor.ontheRightSideOfDoor() && actor.movingTowardsLeft()) {
|
||||||
|
openToLeft()
|
||||||
|
nobodyIsThere = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nobodyIsThere && !doorCloseQueued && doorState != 0) {
|
||||||
|
queueDoorClosing()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldState != doorState) doorStateTimer = 0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
doorStateTimer += delta
|
||||||
|
}
|
||||||
|
|
||||||
doorStateTimer += delta
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user