Skip to content

Commit a824b18

Browse files
authored
Try #71:
2 parents 9c5bdfd + 66a487a commit a824b18

File tree

9 files changed

+866
-125
lines changed

9 files changed

+866
-125
lines changed

examples/dodge-the-creeps/rust/src/player.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl GodotExt for Player {
6262
.base
6363
.get_node_as::<AnimatedSprite2D>("AnimatedSprite2D");
6464

65-
let mut velocity = Vector2::new(0.0, 0.0).inner();
65+
let mut velocity = Vector2::new(0.0, 0.0);
6666

6767
// Note: exact=false by default, in Rust we have to provide it explicitly
6868
let input = Input::singleton();
@@ -80,7 +80,7 @@ impl GodotExt for Player {
8080
}
8181

8282
if velocity.length() > 0.0 {
83-
velocity = velocity.normalize() * self.speed;
83+
velocity = velocity.normalized() * self.speed;
8484

8585
let animation;
8686

@@ -101,10 +101,10 @@ impl GodotExt for Player {
101101
}
102102

103103
let change = velocity * delta as f32;
104-
let position = self.base.get_global_position().inner() + change;
104+
let position = self.base.get_global_position() + change;
105105
let position = Vector2::new(
106-
position.x.max(0.0).min(self.screen_size.inner().x),
107-
position.y.max(0.0).min(self.screen_size.inner().y),
106+
position.x.max(0.0).min(self.screen_size.x),
107+
position.y.max(0.0).min(self.screen_size.y),
108108
);
109109
self.base.set_global_position(position);
110110
}

godot-core/src/builtin/mod.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,36 @@
44
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
55
*/
66

7-
//! Built-in types like `Vector2`, `GodotString` or `Variant`.
7+
//! Built-in types like `Vector2`, `GodotString` and `Variant`.
8+
//!
9+
//! # Background on the design of vector algebra types
10+
//!
11+
//! The basic vector algebra types like `Vector2`, `Matrix4` and `Quaternion` are re-implemented
12+
//! here, with an API similar to that in the Godot engine itself. There are other approaches, but
13+
//! they all have their disadvantages:
14+
//!
15+
//! - We could invoke API methods from the engine. The implementations could be generated, but it
16+
//! is slower and prevents inlining.
17+
//!
18+
//! - We could re-export types from an existing vector algebra crate, like `glam`. This removes the
19+
//! duplication, but it would create a strong dependency on a volatile API outside our control.
20+
//! The `gdnative` crate started out this way, using types from `euclid`, but [found it
21+
//! impractical](https://github.com/godot-rust/gdnative/issues/594#issue-705061720). Moreover,
22+
//! the API would not match Godot's own, which would make porting from GDScript (slightly)
23+
//! harder.
24+
//!
25+
//! - We could opaquely wrap types from an existing vector algebra crate. This protects users of
26+
//! `gdextension` from changes in the wrapped crate. However, direct field access using `.x`,
27+
//! `.y`, `.z` is no longer possible. Instead of `v.y += a;` you would have to write
28+
//! `v.set_y(v.get_y() + a);`. (A `union` could be used to add these fields in the public API,
29+
//! but would make every field access unsafe, which is also not great.)
30+
//!
31+
//! - We could re-export types from the [`mint`](https://crates.io/crates/mint) crate, which was
32+
//! explicitly designed to solve this problem. However, it falls short because [operator
33+
//! overloading would become impossible](https://github.com/kvark/mint/issues/75).
834
935
mod macros;
36+
mod vector_macros;
1037

1138
mod arrays;
1239
mod color;
@@ -16,8 +43,11 @@ mod string;
1643
mod string_name;
1744
mod variant;
1845
mod vector2;
46+
mod vector2i;
1947
mod vector3;
48+
mod vector3i;
2049
mod vector4;
50+
mod vector4i;
2151

2252
pub mod meta;
2353

@@ -29,5 +59,8 @@ pub use string::*;
2959
pub use string_name::*;
3060
pub use variant::*;
3161
pub use vector2::*;
62+
pub use vector2i::*;
3263
pub use vector3::*;
64+
pub use vector3i::*;
3365
pub use vector4::*;
66+
pub use vector4i::*;

godot-core/src/builtin/vector2.rs

Lines changed: 79 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,80 +4,111 @@
44
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
55
*/
66

7+
use std::fmt;
8+
79
use godot_ffi as sys;
810
use sys::{ffi_methods, GodotFfi};
911

10-
type Inner = glam::f32::Vec2;
11-
//type Inner = glam::f64::DVec2;
12+
use crate::builtin::Vector2i;
1213

13-
#[derive(Default, Copy, Clone, Debug, PartialEq)]
14+
/// Vector used for 2D math using floating point coordinates.
15+
///
16+
/// 2-element structure that can be used to represent positions in 2D space or any other pair of
17+
/// numeric values.
18+
///
19+
/// It uses floating-point coordinates of 32-bit precision, unlike the engine's `float` type which
20+
/// is always 64-bit. The engine can be compiled with the option `precision=double` to use 64-bit
21+
/// vectors, but this is not yet supported in the `gdextension` crate.
22+
///
23+
/// See [`Vector2i`] for its integer counterpart.
24+
#[derive(Debug, Default, Clone, Copy, PartialEq)]
1425
#[repr(C)]
1526
pub struct Vector2 {
16-
inner: Inner,
27+
/// The vector's X component.
28+
pub x: f32,
29+
/// The vector's Y component.
30+
pub y: f32,
1731
}
1832

33+
impl_vector_operators!(Vector2, f32, (x, y));
34+
impl_vector_index!(Vector2, f32, (x, y), Vector2Axis, (X, Y));
35+
impl_common_vector_fns!(Vector2, f32);
36+
impl_float_vector_fns!(Vector2, f32);
37+
1938
impl Vector2 {
20-
pub fn new(x: f32, y: f32) -> Self {
21-
Self {
22-
inner: Inner::new(x, y),
23-
}
39+
/// Constructs a new `Vector2` from the given `x` and `y`.
40+
pub const fn new(x: f32, y: f32) -> Self {
41+
Self { x, y }
2442
}
2543

26-
pub fn from_inner(inner: Inner) -> Self {
27-
Self { inner }
44+
/// Constructs a new `Vector2` with all components set to `v`.
45+
pub const fn splat(v: f32) -> Self {
46+
Self { x: v, y: v }
2847
}
2948

30-
/// only for testing
31-
pub fn inner(self) -> Inner {
32-
self.inner
49+
/// Constructs a new `Vector2` from a [`Vector2i`].
50+
pub const fn from_vector2i(v: Vector2i) -> Self {
51+
Self { x: v.x as f32, y: v.y as f32 }
3352
}
3453

35-
// Hacks for example
36-
// pub fn length(self) -> f32 {
37-
// self.inner.length()
38-
// }
39-
// pub fn normalized(self) -> Vector2 {
40-
// Self::from_inner(self.inner.normalize())
41-
// }
42-
pub fn rotated(self, angle: f32) -> Self {
43-
Self::from_inner(glam::Affine2::from_angle(angle).transform_vector2(self.inner))
44-
}
45-
}
54+
/// Zero vector, a vector with all components set to `0.0`.
55+
pub const ZERO: Self = Self::splat(0.0);
4656

47-
impl GodotFfi for Vector2 {
48-
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
49-
}
57+
/// One vector, a vector with all components set to `1.0`.
58+
pub const ONE: Self = Self::splat(1.0);
5059

51-
impl std::fmt::Display for Vector2 {
52-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53-
self.inner.fmt(f)
54-
}
55-
}
60+
/// Infinity vector, a vector with all components set to `INFIINTY`.
61+
pub const INF: Self = Self::splat(f32::INFINITY);
5662

57-
// ----------------------------------------------------------------------------------------------------------------------------------------------
63+
/// Left unit vector. Represents the direction of left.
64+
pub const LEFT: Self = Self::new(-1.0, 0.0);
5865

59-
type IInner = glam::IVec2;
66+
/// Right unit vector. Represents the direction of right.
67+
pub const RIGHT: Self = Self::new(1.0, 0.0);
6068

61-
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
62-
#[repr(C)]
63-
pub struct Vector2i {
64-
inner: IInner,
69+
/// Up unit vector. Y is down in 2D, so this vector points -Y.
70+
pub const UP: Self = Self::new(0.0, -1.0);
71+
72+
/// Down unit vector. Y is down in 2D, so this vector points +Y.
73+
pub const DOWN: Self = Self::new(0.0, 1.0);
74+
75+
/// Returns the result of rotating this vector by `angle` (in radians).
76+
pub fn rotated(self, angle: f32) -> Self {
77+
Self::from_glam(glam::Affine2::from_angle(angle).transform_vector2(self.to_glam()))
78+
}
79+
80+
/// Converts the corresponding `glam` type to `Self`.
81+
fn from_glam(v: glam::Vec2) -> Self {
82+
Self::new(v.x, v.y)
83+
}
84+
85+
/// Converts `self` to the corresponding `glam` type.
86+
fn to_glam(self) -> glam::Vec2 {
87+
glam::Vec2::new(self.x, self.y)
88+
}
6589
}
6690

67-
impl Vector2i {
68-
pub fn new(x: i32, y: i32) -> Self {
69-
Self {
70-
inner: IInner::new(x, y),
71-
}
91+
/// Formats this vector in the same way the Godot engine would.
92+
impl fmt::Display for Vector2 {
93+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94+
write!(f, "({}, {})", self.x, self.y)
7295
}
7396
}
7497

75-
impl GodotFfi for Vector2i {
98+
impl GodotFfi for Vector2 {
7699
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
77100
}
78101

79-
impl std::fmt::Display for Vector2i {
80-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81-
self.inner.fmt(f)
82-
}
102+
/// Enumerates the axes in a [`Vector2`].
103+
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
104+
#[repr(i32)]
105+
pub enum Vector2Axis {
106+
/// The X axis.
107+
X,
108+
/// The Y axis.
109+
Y,
110+
}
111+
112+
impl GodotFfi for Vector2Axis {
113+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
83114
}

godot-core/src/builtin/vector2i.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
5+
*/
6+
7+
use std::fmt;
8+
9+
use godot_ffi as sys;
10+
use sys::{ffi_methods, GodotFfi};
11+
12+
use crate::builtin::Vector2;
13+
14+
/// Vector used for 2D math using integer coordinates.
15+
///
16+
/// 2-element structure that can be used to represent positions in 2D space or any other pair of
17+
/// numeric values.
18+
///
19+
/// It uses integer coordinates and is therefore preferable to [`Vector2`] when exact precision is
20+
/// required. Note that the values are limited to 32 bits, and unlike [`Vector2`] this cannot be
21+
/// configured with an engine build option. Use `i64` or [`PackedInt64Array`] if 64-bit values are
22+
/// needed.
23+
#[derive(Debug, Default, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
24+
#[repr(C)]
25+
pub struct Vector2i {
26+
/// The vector's X component.
27+
pub x: i32,
28+
/// The vector's Y component.
29+
pub y: i32,
30+
}
31+
32+
impl_vector_operators!(Vector2i, i32, (x, y));
33+
impl_vector_index!(Vector2i, i32, (x, y), Vector2iAxis, (X, Y));
34+
impl_common_vector_fns!(Vector2i, i32);
35+
36+
impl Vector2i {
37+
/// Constructs a new `Vector2i` from the given `x` and `y`.
38+
pub const fn new(x: i32, y: i32) -> Self {
39+
Self { x, y }
40+
}
41+
42+
/// Constructs a new `Vector2i` with all components set to `v`.
43+
pub const fn splat(v: i32) -> Self {
44+
Self { x: v, y: v }
45+
}
46+
47+
/// Constructs a new `Vector2i` from a [`Vector2`]. The floating point coordinates will be
48+
/// truncated.
49+
pub const fn from_vector2(v: Vector2) -> Self {
50+
Self { x: v.x as i32, y: v.y as i32 }
51+
}
52+
53+
/// Zero vector, a vector with all components set to `0`.
54+
pub const ZERO: Self = Self::splat(0);
55+
56+
/// One vector, a vector with all components set to `1`.
57+
pub const ONE: Self = Self::splat(1);
58+
59+
/// Left unit vector. Represents the direction of left.
60+
pub const LEFT: Self = Self::new(-1, 0);
61+
62+
/// Right unit vector. Represents the direction of right.
63+
pub const RIGHT: Self = Self::new(1, 0);
64+
65+
/// Up unit vector. Y is down in 2D, so this vector points -Y.
66+
pub const UP: Self = Self::new(0, -1);
67+
68+
/// Down unit vector. Y is down in 2D, so this vector points +Y.
69+
pub const DOWN: Self = Self::new(0, 1);
70+
71+
/// Converts the corresponding `glam` type to `Self`.
72+
fn from_glam(v: glam::IVec2) -> Self {
73+
Self::new(v.x, v.y)
74+
}
75+
76+
/// Converts `self` to the corresponding `glam` type.
77+
fn to_glam(self) -> glam::IVec2 {
78+
glam::IVec2::new(self.x, self.y)
79+
}
80+
}
81+
82+
/// Formats this vector in the same way the Godot engine would.
83+
impl fmt::Display for Vector2i {
84+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85+
write!(f, "({}, {})", self.x, self.y)
86+
}
87+
}
88+
89+
impl GodotFfi for Vector2i {
90+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
91+
}
92+
93+
/// Enumerates the axes in a [`Vector2i`].
94+
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
95+
#[repr(i32)]
96+
pub enum Vector2iAxis {
97+
/// The X axis.
98+
X,
99+
/// The Y axis.
100+
Y,
101+
}
102+
103+
impl GodotFfi for Vector2iAxis {
104+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
105+
}

0 commit comments

Comments
 (0)