extends GutTest ## Cursor-to-world conversion. ## ## This broke the moment the camera started scrolling: the old code treated ## "mouse relative to the centre of the screen" as a world position, which was ## true only while the world was drawn fixed at the origin. Afterwards the ship ## aimed at a fixed world location regardless of where the cursor was. const SCREEN := Vector2(1280.0, 720.0) const CENTRE := Vector2(640.0, 360.0) ## The camera the game actually uses: world_view.position = centre - player. func _offset_for(player: Vector2) -> Vector2: return CENTRE - player func _aim_from(mouse_screen: Vector2, player: Vector2) -> Vector2: var world_mouse := ClientRuntime.screen_to_world(mouse_screen, _offset_for(player)) return world_mouse - player func test_screen_to_world_inverts_the_draw_transform() -> void: # The view draws at screen = world + offset, so this must be its inverse or # everything derived from the cursor is off by the camera position. var offset := _offset_for(Vector2(900.0, -400.0)) var world := Vector2(123.0, -456.0) var screen := world + offset assert_eq(ClientRuntime.screen_to_world(screen, offset), world) func test_aim_follows_the_cursor_not_a_world_location() -> void: # Same cursor position, two very different player positions: the aim # direction must be identical, because the player is drawn centred. var mouse := CENTRE + Vector2(100.0, 0.0) var near_origin := _aim_from(mouse, Vector2.ZERO) var far_away := _aim_from(mouse, Vector2(4000.0, -2500.0)) assert_almost_eq(near_origin.angle(), far_away.angle(), 0.0001, "aim must depend on the cursor, not on where in the map you stand") assert_almost_eq(near_origin.angle(), 0.0, 0.0001, "cursor right of centre aims right") func test_the_four_cardinal_directions() -> void: var player := Vector2(3000.0, 1500.0) assert_almost_eq(_aim_from(CENTRE + Vector2(50.0, 0.0), player).angle(), 0.0, 0.001) assert_almost_eq(_aim_from(CENTRE + Vector2(0.0, 50.0), player).angle(), PI * 0.5, 0.001) assert_almost_eq(_aim_from(CENTRE + Vector2(0.0, -50.0), player).angle(), -PI * 0.5, 0.001) assert_almost_eq(absf(_aim_from(CENTRE + Vector2(-50.0, 0.0), player).angle()), PI, 0.001) ## The regression itself, stated directly: with the old expression the aim ## vector picked up the player's position, so walking around the map swung the ## crosshair even with the mouse held still. func test_walking_does_not_swing_the_aim() -> void: var mouse := CENTRE + Vector2(0.0, -120.0) var angles: Array[float] = [] for step in 5: angles.append(_aim_from(mouse, Vector2(step * 500.0, step * -300.0)).angle()) for a in angles: assert_almost_eq(a, angles[0], 0.0001, "the crosshair must not move when only the player moves")