Skip to content

Commit

Permalink
Add Navigation interface, implement CharacterNavigation
Browse files Browse the repository at this point in the history
. test stub


. minimal movement implementation


. make it async, add movement type


. goForwardToLocation


. remove debug prints


. address some review comments


. add test mock data


Use Duration for timeouts.


. address review comments.


Use the CharacterMovement interface.


. address review comments


. test update


. test defaults
  • Loading branch information
PremekPaska committed Aug 2, 2022
1 parent 0ff5f3d commit a9a847e
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package spaceEngineers.navigation

import kotlinx.coroutines.delay
import kotlinx.coroutines.withTimeout
import spaceEngineers.controller.SpaceEngineers
import spaceEngineers.controller.extensions.distanceTo
import spaceEngineers.model.CharacterMovementType
import spaceEngineers.model.Vec3F
import spaceEngineers.movement.CharacterMovement
import spaceEngineers.movement.CompositeDirection3d
import spaceEngineers.movement.VectorMovement
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

interface Navigation {
suspend fun moveInLine(
targetLocation: Vec3F,
movementType: CharacterMovementType = CharacterMovementType.RUN,
timeout: Duration = 20.seconds
)
}

class CharacterNavigation(
val spaceEngineers: SpaceEngineers,
val movement: CharacterMovement = VectorMovement(spaceEngineers)
) : Navigation {

override suspend fun moveInLine(
targetLocation: Vec3F,
movementType: CharacterMovementType,
timeout: Duration
) = withTimeout(timeout) {
moveInLine(targetLocation, movementType)
}

private suspend fun moveInLine(
targetLocation: Vec3F,
movementType: CharacterMovementType
) = with(spaceEngineers) {
val me = observer.observe()
val direction = (targetLocation - me.position).normalized()

// TODO("Replace this teleport hack")
admin.character.teleport(me.position, direction, me.orientationUp)

goForwardToLocation(spaceEngineers, targetLocation, movementType, stepTicks = 20, tolerance = 1.2f)
goForwardToLocation(spaceEngineers, targetLocation, movementType, stepTicks = 6, tolerance = 0.4f)
}

private suspend fun goForwardToLocation(
spaceEngineers: SpaceEngineers,
targetLocation: Vec3F,
movementType: CharacterMovementType,
stepTicks: Int, tolerance: Float
) = with(spaceEngineers) {
var lastDistance = Float.MAX_VALUE;

fun isNotYetThereButProgressing(maxDistanceRegression: Float = 0.01f): Boolean {
val distance = observer.distanceTo(targetLocation)
if (distance < tolerance) {
return false
}
if (distance > lastDistance + maxDistanceRegression) { // Allow very small worsening of distance.
return false
}
lastDistance = distance
return true
}

while (isNotYetThereButProgressing()) {
// TODO("Correct the course from time to time")

movement.move(CompositeDirection3d.FORWARD, movementType, ticks = stepTicks)
delay((stepTicks * DELAY_PER_TICKS_MS).toLong())
}
}

companion object {
const val DELAY_PER_TICKS_MS = 12 // One tick lasts ~16.7 ms, wait slightly less to avoid character freezes.
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package spaceEngineers.game.mockable

import spaceEngineers.controller.extensions.navigationGraph
import spaceEngineers.navigation.CharacterNavigation
import testhelp.MockOrRealGameTest
import testhelp.assertGreaterThan
import testhelp.assertLessThan
import kotlin.test.Test


class NavigationTest : MockOrRealGameTest(
//forceRealGame = true
) {
@Test
fun navigateToLocation() = testContext {
val navGraph = observer.navigationGraph()
assertGreaterThan(navGraph.nodes.size, 30)

val targetLocation = navGraph.nodes[25].position
val navigator = CharacterNavigation(this)

navigator.moveInLine(targetLocation)
assertLessThan(lower = observer.observe().position.distanceTo(targetLocation), higher = 0.6f)
}
}

Large diffs are not rendered by default.

0 comments on commit a9a847e

Please sign in to comment.