Files
Terrarum/src/net/torvald/terrarum/gameactors/Hitbox.kt
2021-08-28 16:31:06 +09:00

183 lines
5.3 KiB
Kotlin

package net.torvald.terrarum.gameactors
import net.torvald.terrarum.Point2d
import net.torvald.terrarum.printStackTrace
import org.dyn4j.geometry.Vector2
/**
* Constructor: (top-left position, width, height)
*
* Can also use Hitbox.fromTwoPoints(x1, y1, x2, y2
*
* Created by minjaesong on 2016-01-15.
*/
class Hitbox {
var suppressWarning = true
private constructor()
constructor(x1: Double, y1: Double, width: Double, height: Double, suppressWarning: Boolean = true) : this() {
this.suppressWarning = suppressWarning
hitboxStart = Point2d(x1, y1)
this.width = width
this.height = height
if (!suppressWarning && (width == 0.0 || height == 0.0)) {
println("[Hitbox] width or height is zero ($this), perhaps you want to check it out?")
printStackTrace(this)
}
}
@Volatile var hitboxStart: Point2d = Point2d(-1.0, -1.0)
private set
inline val hitboxEnd: Point2d
get() = Point2d(hitboxStart.x + width, hitboxStart.y + height)
var width: Double = 0.0
private set
var height: Double = 0.0
private set
val startX: Double
get() = hitboxStart.x
val startY: Double
get() = hitboxStart.y
val endX: Double
get() = hitboxStart.x + width
val endY: Double
get() = hitboxStart.y + height
val centeredX: Double
get() = hitboxStart.x + width * 0.5
val centeredY: Double
get() = hitboxStart.y + height * 0.5
/**
* @return bottom-centered point of hitbox.
*/
val canonicalX: Double
get() = centeredX
/**
* @return bottom-centered point of hitbox.
*/
inline val canonicalY: Double
get() = endY
/**
* Set to the point top left
* @param x1
* @param y1
* @param width
* @param height
*/
fun setFromWidthHeight(x1: Double, y1: Double, width: Double, height: Double): Hitbox {
hitboxStart = Point2d(x1, y1)
this.width = width
this.height = height
if (!suppressWarning && (width == 0.0 || height == 0.0)) {
println("[Hitbox] width or height is zero ($this), perhaps you want to check it out?")
printStackTrace(this)
}
return this
}
fun setFromTwoPoints(x1: Double, y1: Double, x2: Double, y2: Double): Hitbox {
return setFromWidthHeight(x1, y1, x2 - x1, y2 - y1)
}
fun reassign(other: Hitbox) = setFromTwoPoints(other.startX, other.startY, other.endX, other.endY)
fun translate(x: Double, y: Double) = setPosition(startX + x, startY + y)
fun translate(vec: Vector2?) = if (vec != null) translate(vec.x, vec.y) else this
fun setPosition(x1: Double, y1: Double): Hitbox {
hitboxStart = Point2d(x1, y1)
if (!suppressWarning && (width == 0.0 || height == 0.0)) {
println("[Hitbox] width or height is zero ($this), perhaps you want to check it out?")
printStackTrace(this)
}
return this
}
fun setPosition(vector: Vector2) = setPosition(vector.x, vector.y)
fun setPositionX(x: Double) = setPosition(x, startY)
fun setPositionY(y: Double) = setPosition(startX, y)
/**
* Set position from bottom-centre point
*/
fun setPositionFromPointed(x1: Double, y1: Double): Hitbox {
hitboxStart = Point2d(x1 - width / 2, y1 - height)
return this
}
fun translatePosX(d: Double): Hitbox {
setPositionX(startX + d)
return this
}
fun translatePosY(d: Double): Hitbox {
setPositionY(startY + d)
return this
}
/**
* For initial setup only. Use CanonicalResize for graceful resizing
*/
fun setDimension(w: Double, h: Double): Hitbox {
width = w
height = h
return this
}
fun canonicalResize(w: Double, h: Double): Hitbox {
// sx_1 + 0.5w_1 = sx_2 + 0.5w_2 // equals because the final point must not move. sx_1: old start-x, sx_2: new start-x which is what we want
// sx_2 = sx_1 + 0.5w_1 - 0.5w_2 // move variables to right-hand side to derive final value sx_2
hitboxStart.set(
startX + 0.5 * width - 0.5 * w,
startY + height - h
)
width = w
height = h
return this
}
fun containsPoint(x: Double, y: Double) = (hitboxStart.x - x) in 0.0..width && (hitboxStart.y - y) in 0.0..height
fun containsPoint(p: Point2d) = containsPoint(p.x, p.y)
infix fun intersects(position: Point2d) =
(position.x >= startX && position.x <= startX + width) &&
(position.y >= startY && position.y <= startY + height)
fun toVector(): Vector2 = Vector2(startX, startY)
fun clone(): Hitbox = Hitbox(startX, startY, width, height)
companion object {
fun fromTwoPoints(x1: Double, y1: Double, x2: Double, y2: Double, nowarn: Boolean = false) =
Hitbox(x1, y1, x2 - x1, y2 - y1, nowarn)
}
operator fun minus(other: Hitbox): Vector2 {
return Vector2(other.centeredX - this.centeredX, other.centeredY - this.centeredY)
}
override fun equals(other: Any?): Boolean {
return this.hitboxStart == (other as Hitbox).hitboxStart &&
this.width == other.width &&
this.height == other.height
}
override fun toString(): String {
return "[$hitboxStart - $hitboxEnd]"
}
}