pub struct Position { /* private fields */ }
Expand description
Represents a position in a particular room in Screeps, stored in Rust memory.
Use RoomPosition
if a reference to an object stored in JavaScript memory
is preferred.
This should be a very efficient type to use in most if not all situations.
It’s represented by a single u32
, all math operations are implemented in
pure-Rust code, and uploading to / downloading from JavaScript only requires
transferring a single i32
.
Using Position
You can retrieve a Position
by getting the position of a game object using
HasPosition::pos
, or by creating one from coordinates with
Position::new
.
You can use any of the math methods available on this page to manipulate
Position
, and you can pass it to any game methods expecting a position
or something with a position.
Serialization
Position
implements both serde::Serialize
and
serde::Deserialize
.
When serializing, it will use the format {roomName: String, x: u32, y: u32}
in “human readable” formats like JSON, and will serialize as a single
i32
in “non-human readable” formats like bincode
.
If you need a reference to a RoomPosition
in JavaScript,
convert the native Position
to a RoomPosition
:
use screeps::{Position, RoomCoordinate, RoomPosition};
use std::convert::TryFrom;
let pos = Position::new(
RoomCoordinate::try_from(20).unwrap(),
RoomCoordinate::try_from(21).unwrap(),
"E5N6".parse().unwrap(),
);
let js_pos = RoomPosition::from(pos);
let result = js_pos.room_name();
Deserialization
Position
implements TryFrom<Value>
, allowing conversion from values
retrieved from JavaScript. The implementation is fairly lenient, and will
try to accept the value as any of the following things, in order:
- an integer representing the packedPos
- this can be produced by retrieving the
__packedPos
field of aRoomPosition
- this can be produced by retrieving the
- an object with a
__packedPos
property- this allows converting from a JavaScript
RoomPosition
to aPosition
without referencing__packedPos
manually, but is less efficient since it requires an extra callback into JavaScript to grab that field from within the conversion code
- this allows converting from a JavaScript
- an object with
x
,y
androomName
properties- this is mainly intended to decode
Position
s which were previously sent to JavaScript using@{}
injs!{}
, or serialized usingserde::Serialize
- this will also understand
RoomPosition
s in private servers versions3.2.1
and below, prior to when__packedPos
was added
- this is mainly intended to decode
World vs. in-room coordinates
When converting Position
to integer x/y coordinates, there are two main
methods. The first is to use x
/y
as “in room” coordinates, which are
bounded within 0..=49
. These coordinates only identify the location within
a given room name. These are used by Position::x
, Position::y
,
Position::new
as well as Position::coords
,
Position::coords_signed
and the various implementations of Into<([ui*], [ui*])>
for Position
.
The second is to use x
/y
as “world” coordinates, which are coordinates
spread across the world. To ensures they agree with in-room coordinates,
south is positive y
, north is negative y
, east is positive x
and west
is negative x
. One way to think of them is as extending the room
coordinates of the room E0S0
throughout the entire map.
World coordinates are used by Position::world_x
, Position::world_y
,
Position::world_coords
, Position::from_world_coords
, and by all
implementations which allow adding or subtracting positions (see Addition
and subtraction).
Method Behavior
While this corresponds with the JavaScript RoomPosition
type, it is not
identical. In particular, all “calculation” methods which take in another
position are re-implemented in pure Rust code, and some behave slightly
different.
For instance, Position::get_range_to
operates on positions as world
coordinates, and will return accurate distances for positions in different
rooms. This is in contrast to RoomPosition.getRangeTo
in JavaScript, which
will return Infinity
for positions from different rooms.
Position::in_range_to
has a similar difference.
Besides extending behavior to work between rooms, we’ve tried to keep methods as in-sync with the JavaScript versions as possible. Everything will “just work”, and there should be some speed advantage because of not having to call into JavaScript to perform calculations.
Addition and subtraction
Position
implements Add<(i32, i32)>
, Sub<(i32, i32)>
and
Sub<Position>
. All of these implementations work on positions as world
positions, and will treat positions from different rooms just as if they’re
further apart.
The Add
implementation can be used to add an offset to a position:
let pos1 = Position::new(
RoomCoordinate::try_from(0).unwrap(),
RoomCoordinate::try_from(0).unwrap(),
"E1N1".parse().unwrap(),
);
let pos2 = Position::new(
RoomCoordinate::try_from(40).unwrap(),
RoomCoordinate::try_from(20).unwrap(),
"E1N1".parse().unwrap(),
);
assert_eq!(pos1 + (40, 20), pos2);
And the Sub
implementation can be used to get the offset between two
positions:
let pos1 = Position::new(
RoomCoordinate::try_from(4).unwrap(),
RoomCoordinate::try_from(20).unwrap(),
"E20S21".parse().unwrap(),
);
let pos2 = Position::new(
RoomCoordinate::try_from(4).unwrap(),
RoomCoordinate::try_from(30).unwrap(),
"E20S22".parse().unwrap(),
);
assert_eq!(pos2 - pos1, (0, 60));
let pos3 = Position::new(
RoomCoordinate::try_from(0).unwrap(),
RoomCoordinate::try_from(0).unwrap(),
"E20S21".parse().unwrap(),
);
assert_eq!(pos3 - pos1, (-4, -20));
Ordering
To facilitate use as a key in a BTreeMap
or other similar data
structures, Position
implements PartialOrd
and Ord
.
Position
s are ordered first by ascending world y
position, then by
ascending world x
position. World x
and y
here simply extend the x,y
coords within the room E0S0
throughout the map.
Looking at positions as tuples (world_x, world_y)
, the sorting obeys rules
such as:
(a, 0) < (b, 1)
for anya
,b
(0, c) < (1, c)
for anyc
This follows left-to-right reading order when looking at the Screeps map from above.
Implementations§
source§impl Position
impl Position
sourcepub fn towards(self, target: Position, distance_towards_target: i32) -> Position
pub fn towards(self, target: Position, distance_towards_target: i32) -> Position
Calculates an approximate midpoint between this point and the target.
In case of a tie, rounds towards this point.
If distance_towards_target
is bigger than the distance to the target,
the target is returned.
sourcepub fn between(self, target: Position, distance_from_target: i32) -> Position
pub fn between(self, target: Position, distance_from_target: i32) -> Position
Calculates an approximate midpoint between this point and the target.
In case of a tie, rounds towards the target.
If distance_from_target
is bigger than the distance to the target,
this position is returned.
sourcepub fn midpoint_between(self, target: Position) -> Position
pub fn midpoint_between(self, target: Position) -> Position
Calculates an approximate midpoint between this point and the target.
In case of a tie, rounds towards the target.
source§impl Position
impl Position
sourcepub fn offset(&mut self, x: i32, y: i32)
pub fn offset(&mut self, x: i32, y: i32)
Returns a new position offset from this position by the specified x coords and y coords.
This function operates on world coordinates, and will wrap between rooms if necessary.
To return a new position rather than modifying in place, use pos + (x, y)
. See the implementation of Add<(i32, i32)>
for
Position
further down on this page.
Panics
Will panic if the new position overflows the world. See
Position::from_world_coords
.
Example
let e21s21 = "E21S21".parse().unwrap();
let e21s22 = "E21S22".parse().unwrap();
let mut pos = Position::new(
RoomCoordinate::try_from(21).unwrap(),
RoomCoordinate::try_from(21).unwrap(),
e21s21,
);
pos.offset(5, 5);
assert_eq!(
pos,
Position::new(
RoomCoordinate::try_from(26).unwrap(),
RoomCoordinate::try_from(26).unwrap(),
e21s21
)
);
pos.offset(0, 49);
assert_eq!(
pos,
Position::new(
RoomCoordinate::try_from(26).unwrap(),
RoomCoordinate::try_from(25).unwrap(),
e21s22
)
);
sourcepub fn checked_add(
self,
rhs: (i32, i32)
) -> Result<Position, WorldPositionOutOfBoundsError>
pub fn checked_add( self, rhs: (i32, i32) ) -> Result<Position, WorldPositionOutOfBoundsError>
Adds an (x, y)
pair to this room position’s world coordinates and
returns the result.
Will change rooms if necessary.
Errors
Returns Err
if the new position’s room is outside bounds.
For a panicking variant of this function, see Position::add
.
sourcepub fn checked_add_direction(
self,
direction: Direction
) -> Result<Position, WorldPositionOutOfBoundsError>
pub fn checked_add_direction( self, direction: Direction ) -> Result<Position, WorldPositionOutOfBoundsError>
source§impl Position
impl Position
sourcepub fn get_direction_to(self, target: Position) -> Option<Direction>
pub fn get_direction_to(self, target: Position) -> Option<Direction>
Gets linear direction to the specified position.
Note that this chooses between Top
/Bottom
/Left
/Right
and
TopLeft
/TopRight
/BottomLeft
/BottomRight
by the magnitude in both
directions. For instance, Direction::Top
can be returned even
if the target has a slightly different x
coordinate.
sourcepub fn get_range_to(self, target: Position) -> u32
pub fn get_range_to(self, target: Position) -> u32
Gets linear range to the specified position.
Linear range (also called Chebyshev Distance) is an alternate calculation of distance, calculated as the greater of the distance along the x axis or the y axis. Most calculations in Screeps use this distance metric. For more information see Chebeshev Distance.
This operates on positions as “world positions”, and will return an
accurate range for positions in different rooms. Note that the
corresponding JavaScript method, RoomPosition.getRangeTo
returns
Infinity
if given positions in different rooms.
Examples
// (5, 10) in E0N0
let pos_1 = Position::from_world_coords(5, 10);
// (8, 15) in E0N0
let pos_2 = Position::from_world_coords(8, 15);
// The differences are 3 along the X axis and 5 along the Y axis
// so the linear distance is 5.
assert_eq!(pos_1.get_range_to(pos_2), 5);
sourcepub fn in_range_to(self, target: Position, range: u32) -> bool
pub fn in_range_to(self, target: Position, range: u32) -> bool
Checks whether this position is in the given range of another position.
Linear range (also called Chebyshev Distance) is an alternate calculation of distance, calculated as the greater of the distance along the x axis or the y axis. Most calculations in Screeps use this distance metric. For more information see Chebeshev Distance.
This operates on positions as “world positions”, and may return true for
positions in different rooms which are still within the given range.
Note that the corresponding JavaScript method, RoomPosition.inRangeTo
,
will always return false
for positions from different rooms.
Examples
// (5, 10) in E0N0
let pos_1 = Position::from_world_coords(5, 10);
// (8, 10) in E0N0
let pos_2 = Position::from_world_coords(8, 15);
// The differences are 3 along the X axis and 0 along the Y axis
// so the linear distance is 3.
assert_eq!(pos_1.in_range_to(pos_2, 5), true);
// (8, 15) in E0N0
let pos_3 = Position::from_world_coords(8, 15);
// The differences are 3 along the X axis and 5 along the Y axis
// so the linear distance is 5.
// `in_range_to` returns true if the linear distance is equal to the range
assert_eq!(pos_1.in_range_to(pos_3, 5), true);
// (20, 20) in E0N0
let pos_4 = Position::from_world_coords(20, 20);
// The differences are 15 along the X axis and 10 along the Y axis
// so the linear distance is 15.
assert_eq!(pos_1.in_range_to(pos_4, 5), false);
sourcepub fn is_equal_to(self, target: Position) -> bool
pub fn is_equal_to(self, target: Position) -> bool
Checks whether this position is the same as the specified position.
Note that this is equivalent to this_pos == target.pos()
.
sourcepub fn is_near_to(self, target: Position) -> bool
pub fn is_near_to(self, target: Position) -> bool
True if this position is in the same room as the target, and the range is at most 1.
source§impl Position
impl Position
sourcepub fn create_construction_site(
self,
ty: StructureType,
name: Option<&JsString>
) -> Result<(), ErrorCode>
pub fn create_construction_site( self, ty: StructureType, name: Option<&JsString> ) -> Result<(), ErrorCode>
Creates a ConstructionSite
at this position. If it’s a
StructureSpawn
, a name can optionally be assigned for the structure.
sourcepub fn create_flag(
self,
name: Option<&JsString>,
color: Option<Color>,
secondary_color: Option<Color>
) -> Result<JsString, ErrorCode>
pub fn create_flag( self, name: Option<&JsString>, color: Option<Color>, secondary_color: Option<Color> ) -> Result<JsString, ErrorCode>
Creates a Flag
at this position. If successful, returns the name of
the created flag.
sourcepub fn find_closest_by_path<T>(
self,
ty: T,
options: Option<&Object>
) -> Option<T::Item>
pub fn find_closest_by_path<T>( self, ty: T, options: Option<&Object> ) -> Option<T::Item>
Find the closest object by path among a list of objects, or use
a find
constant to search for all objects of that type in the room.
sourcepub fn find_closest_by_range<T>(self, ty: T) -> Option<T::Item>where
T: FindConstant,
pub fn find_closest_by_range<T>(self, ty: T) -> Option<T::Item>where
T: FindConstant,
Find the closest object by range among a list of objects, or use
a find
constant to search for all objects of that type in the room.
Will not work for objects in other rooms.
sourcepub fn find_in_range<T>(self, ty: T, range: u8) -> Vec<T::Item>where
T: FindConstant,
pub fn find_in_range<T>(self, ty: T, range: u8) -> Vec<T::Item>where
T: FindConstant,
Find all relevant objects within a certain range among a list of
objects, or use a find
constant to search all objects of that type
in the room.
sourcepub fn find_path_to<T, F, R>(
&self,
target: &T,
options: Option<FindPathOptions<F, R>>
) -> Path
pub fn find_path_to<T, F, R>( &self, target: &T, options: Option<FindPathOptions<F, R>> ) -> Path
Find a path from this position to a position or room object, with an optional options object
sourcepub fn find_path_to_xy<F, R>(
self,
x: RoomCoordinate,
y: RoomCoordinate,
options: Option<FindPathOptions<F, R>>
) -> Path
pub fn find_path_to_xy<F, R>( self, x: RoomCoordinate, y: RoomCoordinate, options: Option<FindPathOptions<F, R>> ) -> Path
Find a path from this position to the given coordinates in the same room, with an optional options object.
sourcepub fn look(self) -> Result<Vec<LookResult>, ErrorCode>
pub fn look(self) -> Result<Vec<LookResult>, ErrorCode>
Get all objects at this position. Will fail if the position is in a room that’s not visible during the current tick.
source§impl Position
impl Position
sourcepub fn world_x(self) -> i32
pub fn world_x(self) -> i32
Returns this position’s horizontal “world coordinate”.
The value is equal to 50 * room_x + x
, where room_x
is defined as
room_x = -xx - 1
for Wxx
rooms and as room_x = xx
for Exx
rooms.
sourcepub fn world_y(self) -> i32
pub fn world_y(self) -> i32
Returns this position’s vertical “world coordinate”.
The value is equal to 50 * room_y + y
, where room_y
is defined as
room_y = -yy - 1
for Nyy
rooms and as room_y = yy
for Syy
rooms.
sourcepub fn world_coords(self) -> (i32, i32)
pub fn world_coords(self) -> (i32, i32)
Returns this position’s “world coordinates”.
The first value is equal to 50 * room_x + x
, where room_x
is defined
as room_x = -xx - 1
for Wxx
rooms and as room_x = xx
for Exx
rooms.
The second value is equal to 50 * room_y + y
, where room_y
is
defined as room_y = -yy - 1
for Nyy
rooms and as room_y = yy
for Syy
rooms.
See also Position::world_x
and
Position::world_y
.
sourcepub fn from_world_coords(x: i32, y: i32) -> Self
pub fn from_world_coords(x: i32, y: i32) -> Self
Creates a room position from world coords.
Panics
Panics if either x or y is out of the range -128 * 50 .. +128 * 50
.
For a checked variant of this function, see
Position::checked_from_world_coords
.
sourcepub fn checked_from_world_coords(
x: i32,
y: i32
) -> Result<Self, WorldPositionOutOfBoundsError>
pub fn checked_from_world_coords( x: i32, y: i32 ) -> Result<Self, WorldPositionOutOfBoundsError>
Creates a room position from world coords if they are within the range
-128 * 50 .. +128 * 50
. Otherwise returns None
.
For a panicing variant of this function, see
Position::from_world_coords
.
source§impl Position
impl Position
sourcepub fn new(x: RoomCoordinate, y: RoomCoordinate, room_name: RoomName) -> Self
pub fn new(x: RoomCoordinate, y: RoomCoordinate, room_name: RoomName) -> Self
Create a new Position
Panics
Will panic if either x
or y
is larger than 49, or if room_name
is
outside of the range E127N127 - W127S127
.
pub const fn packed_repr(self) -> u32
pub fn from_packed(packed: u32) -> Self
sourcepub fn x(self) -> RoomCoordinate
pub fn x(self) -> RoomCoordinate
Gets this position’s in-room x coordinate.
sourcepub fn y(self) -> RoomCoordinate
pub fn y(self) -> RoomCoordinate
Gets this position’s in-room y coordinate.
pub fn room_name(self) -> RoomName
pub fn set_x(&mut self, x: RoomCoordinate)
pub fn set_y(&mut self, y: RoomCoordinate)
pub fn set_room_name(&mut self, room_name: RoomName)
pub fn with_x(self, x: RoomCoordinate) -> Self
pub fn with_y(self, y: RoomCoordinate) -> Self
pub fn with_room_name(self, room_name: RoomName) -> Self
Trait Implementations§
source§impl Add<(i32, i32)> for Position
impl Add<(i32, i32)> for Position
source§fn add(self, (x, y): (i32, i32)) -> Self
fn add(self, (x, y): (i32, i32)) -> Self
Adds an (x, y)
pair to this room position’s world coordinates.
Will change rooms if necessary.
Panics
Will panic if the new position’s room is outside bounds. See
Position::from_world_coords
.
Example
let w5s6 = "W5S6".parse().unwrap();
let w5s5 = "W5S5".parse().unwrap();
let pos1 = Position::new(
RoomCoordinate::try_from(42).unwrap(),
RoomCoordinate::try_from(42).unwrap(),
w5s6,
);
let pos2 = pos1 + (7, 7);
assert_eq!(
pos2,
Position::new(
RoomCoordinate::try_from(49).unwrap(),
RoomCoordinate::try_from(49).unwrap(),
w5s6
)
);
let pos3 = pos2 + (0, -59);
assert_eq!(
pos3,
Position::new(
RoomCoordinate::try_from(49).unwrap(),
RoomCoordinate::try_from(40).unwrap(),
w5s5
)
);
let pos4 = pos3 - (49, 0);
assert_eq!(
pos4,
Position::new(
RoomCoordinate::try_from(0).unwrap(),
RoomCoordinate::try_from(40).unwrap(),
w5s5
)
);
source§impl<'de> Deserialize<'de> for Position
impl<'de> Deserialize<'de> for Position
source§fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
source§impl From<&Position> for RoomPosition
impl From<&Position> for RoomPosition
source§impl From<&RoomPosition> for Position
impl From<&RoomPosition> for Position
source§fn from(js_pos: &RoomPosition) -> Self
fn from(js_pos: &RoomPosition) -> Self
source§impl From<Position> for RoomPosition
impl From<Position> for RoomPosition
source§impl From<RoomPosition> for Position
impl From<RoomPosition> for Position
source§fn from(js_pos: RoomPosition) -> Self
fn from(js_pos: RoomPosition) -> Self
source§impl Index<Position> for LocalCostMatrix
impl Index<Position> for LocalCostMatrix
source§impl IndexMut<Position> for LocalCostMatrix
impl IndexMut<Position> for LocalCostMatrix
source§impl Ord for Position
impl Ord for Position
source§impl PartialEq for Position
impl PartialEq for Position
source§impl PartialOrd for Position
impl PartialOrd for Position
1.0.0 · source§fn le(&self, other: &Rhs) -> bool
fn le(&self, other: &Rhs) -> bool
self
and other
) and is used by the <=
operator. Read moresource§impl Sub for Position
impl Sub for Position
source§fn sub(self, other: Position) -> (i32, i32)
fn sub(self, other: Position) -> (i32, i32)
Subtracts the other room position from this one, extracting the difference as the output.
Example
let e5n5 = "E5N5".parse().unwrap();
let e5n6 = "E5N6".parse().unwrap();
let pos1 = Position::new(
RoomCoordinate::try_from(40).unwrap(),
RoomCoordinate::try_from(40).unwrap(),
e5n5,
);
let pos2 = Position::new(
RoomCoordinate::try_from(0).unwrap(),
RoomCoordinate::try_from(20).unwrap(),
e5n6,
);
assert_eq!(pos1 - pos2, (40, 70));