Collision detection updates
This commit is contained in:
parent
1526a1c127
commit
2b94bfd41f
@ -82,7 +82,7 @@ dependencies {
|
|||||||
implementation("net.java.dev.jna:jna:5.13.0")
|
implementation("net.java.dev.jna:jna:5.13.0")
|
||||||
implementation("com.github.jnr:jnr-ffi:2.2.13")
|
implementation("com.github.jnr:jnr-ffi:2.2.13")
|
||||||
|
|
||||||
implementation("ru.dbotthepony:kvector:2.11.0")
|
implementation("ru.dbotthepony:kvector:2.11.1")
|
||||||
|
|
||||||
implementation("com.github.ben-manes.caffeine:caffeine:3.1.5")
|
implementation("com.github.ben-manes.caffeine:caffeine:3.1.5")
|
||||||
implementation("org.classdump.luna:luna-all-shaded:0.4.1")
|
implementation("org.classdump.luna:luna-all-shaded:0.4.1")
|
||||||
|
@ -82,7 +82,7 @@ fun main() {
|
|||||||
for (chunkX in 0 .. 100) {
|
for (chunkX in 0 .. 100) {
|
||||||
//for (chunkX in 0 .. 17) {
|
//for (chunkX in 0 .. 17) {
|
||||||
// for (chunkY in 21 .. 21) {
|
// for (chunkY in 21 .. 21) {
|
||||||
for (chunkY in 0 .. 24) {
|
for (chunkY in 18 .. 24) {
|
||||||
val data = db.read(byteArrayOf(1, (chunkX shr 8).toByte(), chunkX.toByte(), (chunkY shr 8).toByte(), chunkY.toByte()))
|
val data = db.read(byteArrayOf(1, (chunkX shr 8).toByte(), chunkX.toByte(), (chunkY shr 8).toByte(), chunkY.toByte()))
|
||||||
val data2 = db.read(byteArrayOf(2, (chunkX shr 8).toByte(), chunkX.toByte(), (chunkY shr 8).toByte(), chunkY.toByte()))
|
val data2 = db.read(byteArrayOf(2, (chunkX shr 8).toByte(), chunkX.toByte(), (chunkY shr 8).toByte(), chunkY.toByte()))
|
||||||
|
|
||||||
|
@ -188,29 +188,29 @@ abstract class Entity(val world: World<*, *>) {
|
|||||||
|
|
||||||
if (polies.isEmpty()) break
|
if (polies.isEmpty()) break
|
||||||
|
|
||||||
val intersects = ArrayList<Poly.Penetration<CollisionPoly>>()
|
val intersects = ArrayList<Pair<Poly.Penetration, CollisionPoly>>()
|
||||||
|
|
||||||
localHitboxes.forEach { hitbox ->
|
localHitboxes.forEach { hitbox ->
|
||||||
polies.forEach { poly -> hitbox.intersect(poly.poly, poly)?.let { intersects.add(it) } }
|
polies.forEach { poly -> hitbox.intersect(poly.poly)?.let { intersects.add(it to poly) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intersects.isEmpty()) {
|
if (intersects.isEmpty()) {
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
val max = intersects.max()
|
val (max, data) = intersects.maxByOrNull { it.first }!!
|
||||||
// resolve collision
|
// resolve collision
|
||||||
position += max.vector
|
position += max.axis * max.penetration
|
||||||
// collision response
|
// collision response
|
||||||
val response = max.axis * velocity.dot(max.axis * (1.0 + max.data.bounceFactor) * (1.0 + movementParameters.bounceFactor.orElse(0.0)))
|
val response = max.axis * velocity.dot(max.axis * (1.0 + data.bounceFactor) * (1.0 + movementParameters.bounceFactor.orElse(0.0)))
|
||||||
velocity -= response
|
velocity -= response
|
||||||
|
|
||||||
val gravityDot = world.gravity.unitVector.dot(max.axis)
|
val gravityDot = world.gravity.unitVector.dot(max.axis)
|
||||||
// impulse?
|
// impulse?
|
||||||
velocity += max.data.velocity * gravityDot * dt
|
velocity += data.velocity * gravityDot * dt
|
||||||
// friction
|
// friction
|
||||||
velocity *= 1.0 - gravityDot.absoluteValue * 0.08
|
velocity *= 1.0 - gravityDot.absoluteValue * 0.08
|
||||||
|
|
||||||
onTouch(response, max.axis, max.data)
|
onTouch(response, max.axis, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,5 @@ enum class CollisionType(val isEmpty: Boolean) {
|
|||||||
PLATFORM(false),
|
PLATFORM(false),
|
||||||
DYNAMIC(false),
|
DYNAMIC(false),
|
||||||
SLIPPERY(false),
|
SLIPPERY(false),
|
||||||
BLOCK(false),
|
BLOCK(false);
|
||||||
// stairs made out of blocks
|
|
||||||
BLOCK_SLOPE(false);
|
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ fun getBlockPlatforms(x: Int, y: Int, getter: CollisionTypeGetter, kind: Collisi
|
|||||||
target.addBlock(listOf(Vector2d(dx, dy + 1), Vector2d(dx + 1, dy + 1)), kind)
|
target.addBlock(listOf(Vector2d(dx, dy + 1), Vector2d(dx + 1, dy + 1)), kind)
|
||||||
} else if (upLeft && downLeft && !upRight && !downRight) {
|
} else if (upLeft && downLeft && !upRight && !downRight) {
|
||||||
target.addBlock(listOf(Vector2d(dx + 1, dy), Vector2d(dx, dy + 1)), kind)
|
target.addBlock(listOf(Vector2d(dx + 1, dy), Vector2d(dx, dy + 1)), kind)
|
||||||
} else if (upRight && downRight && !upLeft && !upRight) { // TODO: figure out what original starbound devs meant by this condition
|
} else if (upRight && downRight && !upLeft) { // Fix: copy-paste typo in original sources
|
||||||
target.addBlock(listOf(Vector2d(dx, dy), Vector2d(dx + 1, dy + 1)), kind)
|
target.addBlock(listOf(Vector2d(dx, dy), Vector2d(dx + 1, dy + 1)), kind)
|
||||||
} else if (upRight && downLeft) {
|
} else if (upRight && downLeft) {
|
||||||
target.addBlock(listOf(Vector2d(dx, dy), Vector2d(dx + 1, dy + 1)), kind)
|
target.addBlock(listOf(Vector2d(dx, dy), Vector2d(dx + 1, dy + 1)), kind)
|
||||||
|
@ -7,6 +7,7 @@ import com.google.gson.TypeAdapterFactory
|
|||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import com.google.gson.stream.JsonReader
|
import com.google.gson.stream.JsonReader
|
||||||
import com.google.gson.stream.JsonWriter
|
import com.google.gson.stream.JsonWriter
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
||||||
import org.lwjgl.opengl.GL11.GL_LINES
|
import org.lwjgl.opengl.GL11.GL_LINES
|
||||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||||
@ -21,22 +22,33 @@ import ru.dbotthepony.kvector.vector.RGBAColor
|
|||||||
import ru.dbotthepony.kvector.vector.Vector2d
|
import ru.dbotthepony.kvector.vector.Vector2d
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
private fun calculateEdges(points: List<Vector2d>): ImmutableList<Poly.Edge> {
|
private fun calculateEdges(points: List<Vector2d>): Pair<ImmutableList<Poly.Edge>, ImmutableList<Vector2d>> {
|
||||||
require(points.size >= 2) { "Provided poly is invalid (only ${points.size} points are defined)" }
|
require(points.size >= 2) { "Provided poly is invalid (only ${points.size} points are defined)" }
|
||||||
|
|
||||||
val edges = ImmutableList.Builder<Poly.Edge>()
|
val edges = ImmutableList.Builder<Poly.Edge>()
|
||||||
|
|
||||||
for (i in points.indices) {
|
if (points.size == 2) {
|
||||||
val p0 = points[i]
|
// line, to make it one faced, we need to make only one edge
|
||||||
val p1 = points[(i + 1) % points.size]
|
|
||||||
|
val (p0, p1) = points
|
||||||
|
|
||||||
val diff = (p1 - p0).unitVector
|
val diff = (p1 - p0).unitVector
|
||||||
val normal = Vector2d(-diff.y, diff.x)
|
val normal = Vector2d(-diff.y, diff.x)
|
||||||
|
|
||||||
edges.add(Poly.Edge(p0, p1, normal))
|
edges.add(Poly.Edge(p0, p1, normal))
|
||||||
|
} else {
|
||||||
|
for (i in points.indices) {
|
||||||
|
val p0 = points[i]
|
||||||
|
val p1 = points[(i + 1) % points.size]
|
||||||
|
|
||||||
|
val diff = (p1 - p0).unitVector
|
||||||
|
val normal = Vector2d(-diff.y, diff.x)
|
||||||
|
|
||||||
|
edges.add(Poly.Edge(p0, p1, normal))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return edges.build()
|
return edges.build() to ImmutableList.copyOf(points)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,7 +57,8 @@ private fun calculateEdges(points: List<Vector2d>): ImmutableList<Poly.Edge> {
|
|||||||
* If poly shape is not convex behavior of SAT is undefined
|
* If poly shape is not convex behavior of SAT is undefined
|
||||||
*/
|
*/
|
||||||
class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: ImmutableList<Vector2d>) {
|
class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: ImmutableList<Vector2d>) {
|
||||||
constructor(points: List<Vector2d>) : this(calculateEdges(points), ImmutableList.copyOf(points))
|
private constructor(pair: Pair<ImmutableList<Edge>, ImmutableList<Vector2d>>) : this(pair.first, pair.second)
|
||||||
|
constructor(points: List<Vector2d>) : this(calculateEdges(points))
|
||||||
constructor(aabb: AABB) : this(listOf(aabb.bottomLeft, aabb.topLeft, aabb.topRight, aabb.bottomRight))
|
constructor(aabb: AABB) : this(listOf(aabb.bottomLeft, aabb.topLeft, aabb.topRight, aabb.bottomRight))
|
||||||
|
|
||||||
val aabb = AABB(
|
val aabb = AABB(
|
||||||
@ -71,15 +84,15 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Penetration<T>(val axis: Vector2d, val penetration: Double, val data: T) : Comparable<Penetration<*>> {
|
data class Penetration(val axis: Vector2d, val penetration: Double) : Comparable<Penetration> {
|
||||||
val vector = axis * penetration
|
val vector = axis * penetration
|
||||||
|
|
||||||
override fun compareTo(other: Penetration<*>): Int {
|
override fun compareTo(other: Penetration): Int {
|
||||||
return penetration.absoluteValue.compareTo(other.penetration.absoluteValue)
|
return penetration.absoluteValue.compareTo(other.penetration.absoluteValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun plus(value: Penetration<*>): Poly {
|
operator fun plus(value: Penetration): Poly {
|
||||||
val vertices = ImmutableList.Builder<Vector2d>()
|
val vertices = ImmutableList.Builder<Vector2d>()
|
||||||
val edges = ImmutableList.Builder<Edge>()
|
val edges = ImmutableList.Builder<Edge>()
|
||||||
|
|
||||||
@ -144,7 +157,7 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
|
|||||||
return Vector2d(min, max)
|
return Vector2d(min, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> intersect(other: Poly, data: T): Penetration<T>? {
|
fun intersect(other: Poly): Penetration? {
|
||||||
if (!aabb.intersectWeak(other.aabb))
|
if (!aabb.intersectWeak(other.aabb))
|
||||||
return null
|
return null
|
||||||
|
|
||||||
@ -152,7 +165,7 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
|
|||||||
edges.forEach { normals.add(it.normal) }
|
edges.forEach { normals.add(it.normal) }
|
||||||
other.edges.forEach { normals.add(it.normal) }
|
other.edges.forEach { normals.add(it.normal) }
|
||||||
|
|
||||||
val intersections = ArrayList<Penetration<T>>()
|
val intersections = ArrayList<Penetration>()
|
||||||
|
|
||||||
for (normal in normals) {
|
for (normal in normals) {
|
||||||
val projectThis = project(normal)
|
val projectThis = project(normal)
|
||||||
@ -173,10 +186,10 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
|
|||||||
|
|
||||||
if (minMin <= maxMax) {
|
if (minMin <= maxMax) {
|
||||||
// push to left
|
// push to left
|
||||||
intersections.add(Penetration(normal, -minMin - width, data))
|
intersections.add(Penetration(normal, -minMin - width))
|
||||||
} else {
|
} else {
|
||||||
// push to right
|
// push to right
|
||||||
intersections.add(Penetration(normal, maxMax + width, data))
|
intersections.add(Penetration(normal, maxMax + width))
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
projectThis.component1() in projectOther.component1() .. projectOther.component2() &&
|
projectThis.component1() in projectOther.component1() .. projectOther.component2() &&
|
||||||
@ -188,17 +201,17 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
|
|||||||
|
|
||||||
if (minMin <= maxMax) {
|
if (minMin <= maxMax) {
|
||||||
// push to left
|
// push to left
|
||||||
intersections.add(Penetration(normal, -minMin - width, data))
|
intersections.add(Penetration(normal, -minMin - width))
|
||||||
} else {
|
} else {
|
||||||
// push to right
|
// push to right
|
||||||
intersections.add(Penetration(normal, maxMax + width, data))
|
intersections.add(Penetration(normal, maxMax + width))
|
||||||
}
|
}
|
||||||
} else if (projectOther.component1() in projectThis.component1() .. projectThis.component2()) {
|
} else if (projectOther.component1() in projectThis.component1() .. projectThis.component2()) {
|
||||||
// other's min point is within this
|
// other's min point is within this
|
||||||
intersections.add(Penetration(normal, projectOther.component1() - projectThis.component2(), data))
|
intersections.add(Penetration(normal, projectOther.component1() - projectThis.component2()))
|
||||||
} else {
|
} else {
|
||||||
// other's max point in within this
|
// other's max point in within this
|
||||||
intersections.add(Penetration(normal, projectOther.component2() - projectThis.component1(), data))
|
intersections.add(Penetration(normal, projectOther.component2() - projectThis.component1()))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intersections.last().penetration == 0.0) {
|
if (intersections.last().penetration == 0.0) {
|
||||||
@ -213,8 +226,6 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
|
|||||||
return intersections.min()
|
return intersections.min()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun intersect(other: Poly) = intersect(other, Unit)
|
|
||||||
|
|
||||||
fun render(client: StarboundClient = StarboundClient.current(), color: RGBAColor = RGBAColor.LIGHT_GREEN) {
|
fun render(client: StarboundClient = StarboundClient.current(), color: RGBAColor = RGBAColor.LIGHT_GREEN) {
|
||||||
val program = client.programs.position
|
val program = client.programs.position
|
||||||
val lines = program.builder.builder
|
val lines = program.builder.builder
|
||||||
|
Loading…
Reference in New Issue
Block a user