-
Notifications
You must be signed in to change notification settings - Fork 38
/
Copy pathStabilize.kt
70 lines (58 loc) · 2.48 KB
/
Stabilize.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package org.valkyrienskies.eureka.ship
import org.joml.Vector3d
import org.joml.Vector3dc
import org.valkyrienskies.core.api.ships.PhysShip
import org.valkyrienskies.eureka.EurekaConfig
import kotlin.math.atan
import kotlin.math.max
fun stabilize(
ship: PhysShip,
omega: Vector3dc,
vel: Vector3dc,
forces: PhysShip,
linear: Boolean,
yaw: Boolean
) {
val shipUp = Vector3d(0.0, 1.0, 0.0)
val worldUp = Vector3d(0.0, 1.0, 0.0)
ship.transform.shipToWorldRotation.transform(shipUp)
val angleBetween = shipUp.angle(worldUp)
val idealAngularAcceleration = Vector3d()
if (angleBetween > .01) {
val stabilizationRotationAxisNormalized = shipUp.cross(worldUp, Vector3d()).normalize()
idealAngularAcceleration.add(
stabilizationRotationAxisNormalized.mul(
angleBetween,
stabilizationRotationAxisNormalized
)
)
}
// Only subtract the x/z components of omega.
// We still want to allow rotation along the Y-axis (yaw).
// Except if yaw is true, then we stabilize
idealAngularAcceleration.sub(
omega.x(),
if (!yaw) 0.0 else omega.y(),
omega.z()
)
val stabilizationTorque = ship.transform.shipToWorldRotation.transform(
ship.momentOfInertia.transform(
ship.transform.shipToWorldRotation.transformInverse(idealAngularAcceleration)
)
)
val speed = ship.velocity.length()
stabilizationTorque.mul(EurekaConfig.SERVER.stabilizationTorqueConstant / max(1.0, speed * speed * EurekaConfig.SERVER.scaledInstability / ship.mass + speed * EurekaConfig.SERVER.unscaledInstability))
forces.applyInvariantTorque(stabilizationTorque)
if (linear) {
val idealVelocity = Vector3d(vel).negate()
idealVelocity.y = 0.0
// ideally this should work the same way as input is scaled
val s = EurekaConfig.SERVER.linearStabilizeMaxAntiVelocity * (1 - 1 / smoothingATanMax(EurekaConfig.SERVER.linearMaxMass, ship.mass * EurekaConfig.SERVER.linearMassScaling + 1.0)) / 10.0
if (idealVelocity.lengthSquared() > s * s)
idealVelocity.normalize(s)
idealVelocity.mul(ship.mass * (10 - EurekaConfig.SERVER.antiVelocityMassRelevance))
forces.applyInvariantForce(idealVelocity)
}
}
private fun smoothingATan(smoothing: Double, x: Double): Double = atan(x * smoothing) / smoothing
private fun smoothingATanMax(max: Double, x: Double): Double = smoothingATan(1 / (max * 0.638), x)