I'm super-new to Rust and Bevy (a week in) and don't quite now a ton of things. If anyone's bored and willing to provide some critique for the messy code of mine that would be a great help. Thank you kindly in advance. Code: https://pastebin.com/51jgJt3K (Edit) Updated the code, fixed clear color and removed redundant stuff: https://pastebin.com/kM4DXGJc
Related #showcase message: #showcase message
#Draggable dynamic window experiment
23 messages · Page 1 of 1 (latest)
move_toward can be safely replaced with
fn move_towards(current: Vec2, target: Vec2, delta: f32) -> Vec2 {
let distance = current.distance(target);
let move_ratio = (delta / distance).min(1.0);
current.lerp(target, move_ratio)
}
ooooh, you actually move the window on the desktop instead of making it fullscreen as I would have imagined. That's really nice.
Making the camera a child of the sprite, nice way of handling it
Of course, you'd want to rotate the sprite, add some angular momentum, to make it feel so much more fun. to do that, instead of setting the window size the same as the sprite, you can set it to sqrt(width²+height²)
Fairly certain you can make dedicated system for handling velocity and grabbing. You just need to order them so that the grabbing system runs before the velocity system, this should make the code a bit more decoupled
Ah, I would have done it this way:
let cursor_position = if let Some(pos) = window.cursor_position() {
Vec2 { y: window_rect.height() - pos.y, .. pos }
} else {
grabber.previous_cursor_position
};
``` instead of ```rust
let mut cursor_position: Vec2;
if window.cursor_position().is_some() {
cursor_position = window.cursor_position().unwrap();
cursor_position.y = window_rect.height() - cursor_position.y;
} else {
cursor_position = grabber.previous_cursor_position;
}
``` in rust, everything is an expression, this allows avoiding defining `cursor_position` as `mut` when you can just define it as the result of an if-expression. This also allow you to avoid `.unwrap()`
Instead of
transform.translation += Vec3 {
x: cursor_delta.x,
y: cursor_delta.y,
z: 0.0,
} * drag_force
* delta
``` You can do: ```rust
transform.translation += cursor_delta.extend(0.) * drag_force * delta
If the box reaches the edge of the screen, instead of "pushing it toward the center," you should probably just invert the velocity. When a rubber ball hits the floor, that is what happens, it's (vertical) velocity is inverted. Here you could emulate something similar by inverting the relevant component (axis) of the velocity vector. Maybe you'll need to add a flag to make sure it doesn't get stuck at the edge, so that it doesn't keep flipping the velocity each frame.
But yeah, you should try having a dedicated system that updates the transform based on the velocity, and a dedicated to handle grabbing the cube.
Here is a starter kit
fn main() {
app
//...
.add_system(update_grab.before(update_velocity))
.add_system(update_velocity)
.add_system(move_by_velocity.after(update_velocity))
.add_system(update_window.after(move_by_velocity))
// ...
}
#[derive(Component)]
struct CompanionCube;
fn update_grab(
mut query: Query<(&mut Grabber, &mut Velocity)>,
windows: Res<Windows>,
mouse_buttons: Res<Input<MouseButton>>,
) {
for (mut grab, mut velocity) in &mut query {
todo!("update velocity based on graby movement");
}
}
fn move_by_velocity(
mut query: Query<(&mut Transform, &Velocity)>,
) {
for (mut transform, velocity) in &mut query {
transform.translation += velocity;
}
}
fn update_velocity(
mut query: Query<(&Transform, &mut Velocity)>,
time: Res<Time>,
) {
for (transform, mut velocity) in &mut query {
todo!("Check bounce from screen border\n\
And also add friction (reduce gradually velocity)\n\
And also gravity (decrease gradually `y` component)");
}
}
fn update_window(
cube_transform: Query<&Transform, With<CompanionCube>>,
mut windows: ResMut<Windows>,
) {
let Ok(cube_transform) = cube_transform.get_single() else { return };
let cube_position = cube_transform.translation;
todo!("move window to follow cube position");
}
ECS is about isolating the functionalities of individual components. Of course in your case, a single massive update system make sense, but if you want to work toward ECS, you gotta grok how to make isolated systems that work on a very narrow scope.
Just today I separated a very large input system that handled all input schemes to 6 different systems that handled each input schemes (Mouse/Keyboard, Controller, Bot; each split in two, one for character movement the other for neck movement (it's a game about giraffes))
Hello, @edgy dock.
Wow, such an input, that's a huge help, really, thank you so much for your time and doing it all. It'll take some time for me to analyze what you did there to improve my tiny experiment, I'm really slow at understanding or maybe rather switching to thinking in Rust. There has been plenty of times when I've been thinking that I've got the basics, but then realizing I'm doing it all the old way, sigh 😋 I'll be back with a heavily improved version later 😀
Regarding the things you've said...
-
Thank you kindly for the function, I was struggling to find something that fits in there, I've already switched three methods for that thing over there.
-
I couldn't really do it fullscreen because I haven't found a way of clicking through the transparent window so user still could interact with OS elements, somehow I don't even think it's possible to make it that way. Hell, I didn't even find how to make it always on top but unfocused too 😄 I guess winit has it, but those are not exposed to bevy yet. Though it's nothing like it's high priority yet, just something I wanted to see as a core feature in the end.
-
I've made the camera as a child after I've struggled to fix the issue with keeping the window transparent and camera clear color not setting any background while still clearing the buffer, it was infinitely spamming and keeping texture's pixels all over the place. Then instead of moving the camera along I've cheated to prevent the camera's movements by making it always follow the cube entity as a child. Of course, I have fixed it now, but so far keeping the camera as a child makes sense 🙂
⠀
-
Haven't really thought of rotating, though I was thinking adding rapier2d physics later once all the base systems are in. Isn't it Pythagorean theorem? I thought it's being used for finding a vector's length only. How one would use it for rotation? That part confused me. Or you just meant to use it for window size fit. Oh, by the way, setting the window's size doesn't at all for some reason, yet to figure out why.
-
I wanted to separate grabbing and moving, I just didn't feel confident of separating it all until it work as I wanted it to, I thought jumping between functions might make it more confusing for myself, but I'm not entirely sure. It's just that I sometimes struggle to satisfy the Rust's compiler in VS Code that yells at me through the analyzer plugin all the time, and when it interrupts me I get lost while being in the middle of doing something particular, that's all 🙃 I've already switched to IntelliJ IDEA with Rust plugin, maybe that'll do better for me, it looks cleaner in terms of having less distractions even just visually for the code (e.g. like showing variables types much better way.)
-
let x if let Some(y) = zmade me want to jump out of window 🤣 Must investigate this part, it does look wa-a-a-ay better than my ugly mess that's for sure. Thank you, I'll try to understand it as well.everything is an expressionmindset should really help me start improving a lot of parts eventually. I had a feeling that using.unwrap()everywhere is bad practice as I've noticed it appeared too often in my code.
⠀
-
I didn't want the cube to just ricochet from the screen's boundaries, but instead get back more smoothly, though I still like the idea of inverting the velocity better, didn't think about it this way, it makes much more sense now. Before the code I've shared in here there was another method for it which was just pushing velocity by x and y back separately, which was even uglier than sending it to the screen's center, which of course is still not good, I admit.
-
I get the main idea behind ECS, I read and watch plenty of things before about it, but it's my first time actually finally trying it out 🙂 I really liked the Bob Nystrom's talk about it, though I think he has somewhat mixed it with OOP in his roguelike example here https://youtu.be/JxI3Eu5DPwE My brain is just tied to the 'classic way' too much right now as I've been doing it one way for about ten years now while developing games. Honestly I think that my code used to make much more sense before I learned about classes and etc. Strictly interconnected objects made it harder to handle and more confusing with years. So I hope to kind of untie that knot using the ECS mindset instead.
Didn't expect my answer in the morning to be such a wall of text, but here we are 🤪
Thank you kindly once again for helping me on my journey 💖
Oh, regarding the window size and camera being child of the sprite. I think those are good ideas that you should keep. they make sense for what you are building.
I actually wanted to build a system where each entity or GUI groups have their own window... But that's because I currently don't see a way for user to click through the app's window to still be able to interact with OS while the app running on top, but unfocused.
For the pythagoras' theroem. It's not a way to compute rotation, but simply a way to compute the minimum window size necessary to still display the whole sprite event if it was rotated 45º
Yeah, that's what I thought, but wanted to make sure. I'm learning math in parallel with Rust too now, before I only used tons of Unity functions and other complete simple things.
I mean, I still don't fully understand why that formula would help with that too, I need to investigate it deeper...
I might be wrong on that one
Ah, I think I see it now. Since it gives us the length between the two opposite corners we might as well use it as diameter too.