mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-17 14:04:05 +09:00
WIP collision solver, colour-codes in game fonts
Former-commit-id: 0bb85999176d89956398bbcc24e1b33cacd3e87c Former-commit-id: 0ef0c1ac9b88f8fe42a7439fee69a8d4792be96a
This commit is contained in:
@@ -5,15 +5,20 @@ import org.newdawn.slick.GameContainer
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
interface Actor {
|
||||
abstract class Actor : Comparable<Actor> {
|
||||
|
||||
fun update(gc: GameContainer, delta_t: Int)
|
||||
abstract fun update(gc: GameContainer, delta_t: Int)
|
||||
|
||||
/**
|
||||
* Valid RefID is equal to or greater than 32768.
|
||||
* @return Reference ID. (32768-0xFFFF_FFFF)
|
||||
*/
|
||||
var referenceID: Int
|
||||
abstract var referenceID: Int
|
||||
|
||||
var actorValue: ActorValue
|
||||
abstract var actorValue: ActorValue
|
||||
|
||||
override fun equals(other: Any?) = referenceID == (other as Actor).referenceID
|
||||
override fun hashCode() = referenceID
|
||||
override fun toString() = "ActorID: ${hashCode()}"
|
||||
override fun compareTo(other: Actor): Int = this.referenceID - other.referenceID
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import org.newdawn.slick.Graphics
|
||||
*
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
open class ActorWithBody constructor() : Actor, Visible, Glowing {
|
||||
open class ActorWithBody constructor() : Actor(), Visible {
|
||||
|
||||
override var actorValue: ActorValue = ActorValue()
|
||||
|
||||
@@ -26,15 +26,13 @@ open class ActorWithBody constructor() : Actor, Visible, Glowing {
|
||||
var baseHitboxH: Int = 0
|
||||
|
||||
/**
|
||||
* Velocity for newtonian sim.
|
||||
* Fluctuation in, otherwise still, velocity is equal to acceleration.
|
||||
|
||||
* Velocity vector (broken down by axes) for newtonian sim.
|
||||
* Acceleration: used in code like:
|
||||
* veloY += 3.0
|
||||
* +3.0 is acceleration. You __accumulate__ acceleration to the velocity.
|
||||
*/
|
||||
@Volatile var veloX: Float = 0.toFloat()
|
||||
@Volatile var veloY: Float = 0.toFloat()
|
||||
var veloX: Float = 0.toFloat()
|
||||
var veloY: Float = 0.toFloat()
|
||||
@Transient private val VELO_HARD_LIMIT = 10000f
|
||||
|
||||
var grounded = false
|
||||
@@ -61,16 +59,17 @@ open class ActorWithBody constructor() : Actor, Visible, Glowing {
|
||||
@Transient val nextHitbox = Hitbox(0f,0f,0f,0f)
|
||||
|
||||
/**
|
||||
* Physical properties
|
||||
* Physical properties.
|
||||
* Values derived from ActorValue must be @Transient.
|
||||
*/
|
||||
@Volatile @Transient var scale = 1f
|
||||
@Volatile @Transient var mass = 2f
|
||||
@Transient var scale = 1f
|
||||
@Transient var mass = 2f
|
||||
@Transient private val MASS_LOWEST = 2f
|
||||
/** Valid range: [0, 1] */
|
||||
var elasticity = 0f
|
||||
set(value) {
|
||||
if (value < 0)
|
||||
throw IllegalArgumentException("[ActorWithBody] $value: valid elasticity value is [0, 1].")
|
||||
throw IllegalArgumentException("[ActorWithBody] Invalid elasticity value: $value; valid elasticity value is [0, 1].")
|
||||
else if (value > 1) {
|
||||
println("[ActorWithBody] Elasticity were capped to 1.")
|
||||
field = ELASTICITY_MAX
|
||||
@@ -89,11 +88,11 @@ open class ActorWithBody constructor() : Actor, Visible, Glowing {
|
||||
*/
|
||||
@Transient private val METER = 24f
|
||||
/**
|
||||
* [m / s^2] * SI_TO_GAME_ACC -> [px / IFrame^2]
|
||||
* [m / s^2] * SI_TO_GAME_ACC -> [px / InternalFrame^2]
|
||||
*/
|
||||
@Transient private val SI_TO_GAME_ACC = METER / FastMath.sqr(Terrarum.TARGET_FPS.toFloat())
|
||||
/**
|
||||
* [m / s] * SI_TO_GAME_VEL -> [px / IFrame]
|
||||
* [m / s] * SI_TO_GAME_VEL -> [px / InternalFrame]
|
||||
*/
|
||||
@Transient private val SI_TO_GAME_VEL = METER / Terrarum.TARGET_FPS
|
||||
|
||||
@@ -131,6 +130,8 @@ open class ActorWithBody constructor() : Actor, Visible, Glowing {
|
||||
|
||||
@Transient private val MASS_DEFAULT = 60f
|
||||
|
||||
internal val physSleep: Boolean
|
||||
get() = veloX.abs() < 0.5 && veloY.abs() < 0.5
|
||||
|
||||
private var posAdjustX = 0
|
||||
private var posAdjustY = 0
|
||||
|
||||
104
src/net/torvald/terrarum/gameactors/CollisionSolver.kt
Normal file
104
src/net/torvald/terrarum/gameactors/CollisionSolver.kt
Normal file
@@ -0,0 +1,104 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-04-22.
|
||||
*/
|
||||
object CollisionSolver {
|
||||
|
||||
private const val STARTPOINT = 1
|
||||
private const val ENDPOINT = 2
|
||||
|
||||
private const val COLL_LIST_SIZE = 256
|
||||
private const val COLL_CANDIDATES_SIZE = 128
|
||||
private const val COLL_FINAL_CANDIDATES_SIZE = 16
|
||||
|
||||
private val collListX = ArrayList<CollisionMarkings>(COLL_LIST_SIZE)
|
||||
private val collListY = ArrayList<CollisionMarkings>(COLL_LIST_SIZE)
|
||||
|
||||
private val collCandidateX = ArrayList<Pair<ActorWithBody, ActorWithBody>>(COLL_CANDIDATES_SIZE)
|
||||
private val collCandidateY = ArrayList<Pair<ActorWithBody, ActorWithBody>>(COLL_CANDIDATES_SIZE)
|
||||
private val collCandidates = ArrayList<Pair<ActorWithBody, ActorWithBody>>(COLL_FINAL_CANDIDATES_SIZE)
|
||||
|
||||
/**
|
||||
* @link https://www.toptal.com/game/video-game-physics-part-ii-collision-detection-for-solid-objects
|
||||
*/
|
||||
fun process() {
|
||||
// mark list x
|
||||
Terrarum.game.actorContainer.forEach { it ->
|
||||
if (it is ActorWithBody) {
|
||||
collListX.add(CollisionMarkings(it.hitbox.hitboxStart.x, STARTPOINT, it.referenceID))
|
||||
collListX.add(CollisionMarkings(it.hitbox.hitboxEnd.x, ENDPOINT, it.referenceID))
|
||||
}
|
||||
}
|
||||
|
||||
// sort list x (will use Timsort with Java SE >= 8, Mergesort otherwise)
|
||||
collListX.sortBy { it.pos }
|
||||
|
||||
// set candidateX
|
||||
|
||||
// mark list y
|
||||
Terrarum.game.actorContainer.forEach { it ->
|
||||
if (it is ActorWithBody) {
|
||||
collListY.add(CollisionMarkings(it.hitbox.hitboxStart.y, STARTPOINT, it.referenceID))
|
||||
collListY.add(CollisionMarkings(it.hitbox.hitboxEnd.y, ENDPOINT, it.referenceID))
|
||||
}
|
||||
}
|
||||
|
||||
// sort list y
|
||||
collListY.sortBy { it.pos }
|
||||
|
||||
// set candidateY
|
||||
|
||||
// look for overlaps in candidate X/Y and put them into collCandidates
|
||||
|
||||
// solve collision for actors in collCandidates
|
||||
}
|
||||
|
||||
private fun solveCollision(a: ActorWithBody, b: ActorWithBody) {
|
||||
|
||||
}
|
||||
|
||||
private infix fun ActorWithBody.isCollidingWith(other: ActorWithBody): Boolean {
|
||||
val ax = this.hitbox.centeredX
|
||||
val ay = this.hitbox.centeredY
|
||||
val bx = other.hitbox.centeredX
|
||||
val by = other.hitbox.centeredY
|
||||
|
||||
// will refer 'actor_dist_t' as 't' afterward
|
||||
val actor_dist_t_sqr = ((ay - by).sqr() + (ax - bx).sqr()) // no sqrt; 'power' is slower than 'times'
|
||||
val dist_x = (ax - bx).abs() // 'tx'
|
||||
val dist_y = (ay - by).abs() // 'ty'
|
||||
val tangent = dist_y / dist_x
|
||||
|
||||
var t_ax: Float; var t_ay: Float
|
||||
if (dist_x > dist_y) {
|
||||
t_ax = this.hitbox.width / 2
|
||||
t_ay = t_ax * tangent
|
||||
}
|
||||
else {
|
||||
t_ay = this.hitbox.height / 2
|
||||
t_ax = t_ay * tangent
|
||||
}
|
||||
|
||||
return (t_ax.sqr() + t_ay.sqr()) < actor_dist_t_sqr
|
||||
}
|
||||
|
||||
fun Float.abs() = if (this < 0) -this else this
|
||||
fun Float.sqr() = this * this
|
||||
|
||||
data class CollisionMarkings(
|
||||
val pos: Float,
|
||||
val kind: Int,
|
||||
val actorID: Int
|
||||
)
|
||||
|
||||
/**
|
||||
* === Some useful physics knowledge ===
|
||||
*
|
||||
* * Momentum = mass × Velocity
|
||||
*/
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import org.newdawn.slick.GameContainer
|
||||
import org.newdawn.slick.Graphics
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
interface Glowing {
|
||||
fun drawGlow(gc: GameContainer, g: Graphics)
|
||||
|
||||
fun updateGlowSprite(gc: GameContainer, delta: Int)
|
||||
}
|
||||
@@ -15,7 +15,7 @@ class PhysTestBall : ActorWithBody {
|
||||
constructor(): super() {
|
||||
setHitboxDimension(16, 16, 0, 0)
|
||||
isVisible = true
|
||||
mass = 10f
|
||||
actorValue[AVKey.BASEMASS] = 10f
|
||||
|
||||
color = RoguelikeRandomiser.composeColourFrom(RoguelikeRandomiser.POTION_PRIMARY_COLSET)
|
||||
}
|
||||
@@ -23,9 +23,9 @@ class PhysTestBall : ActorWithBody {
|
||||
override fun drawBody(gc: GameContainer, g: Graphics) {
|
||||
g.color = color
|
||||
g.fillOval(
|
||||
hitbox!!.posX,
|
||||
hitbox!!.posY,
|
||||
hitbox!!.width,
|
||||
hitbox!!.height)
|
||||
hitbox.posX,
|
||||
hitbox.posY,
|
||||
hitbox.width,
|
||||
hitbox.height)
|
||||
}
|
||||
}
|
||||
@@ -12,4 +12,8 @@ interface Visible {
|
||||
fun drawBody(gc: GameContainer, g: Graphics)
|
||||
|
||||
fun updateBodySprite(gc: GameContainer, delta: Int)
|
||||
|
||||
fun drawGlow(gc: GameContainer, g: Graphics)
|
||||
|
||||
fun updateGlowSprite(gc: GameContainer, delta: Int)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user