#[repr(C)]pub struct Vec2 {
pub x: f32,
pub y: f32,
}
Expand description
A 2-dimensional vector.
Fields§
§x: f32
§y: f32
Implementations§
source§impl Vec2
impl Vec2
sourcepub const fn new(x: f32, y: f32) -> Vec2
pub const fn new(x: f32, y: f32) -> Vec2
Creates a new vector.
Examples found in repository?
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
fn wrap_around(v: &Vec2) -> Vec2 {
let mut vr = Vec2::new(v.x, v.y);
if vr.x > screen_width() {
vr.x = 0.;
}
if vr.x < 0. {
vr.x = screen_width()
}
if vr.y > screen_height() {
vr.y = 0.;
}
if vr.y < 0. {
vr.y = screen_height()
}
vr
}
#[macroquad::main("Asteroids")]
async fn main() {
let mut ship = Ship {
pos: Vec2::new(screen_width() / 2., screen_height() / 2.),
rot: 0.,
vel: Vec2::new(0., 0.),
};
let mut bullets = Vec::new();
let mut last_shot = get_time();
let mut asteroids = Vec::new();
let mut gameover = false;
let mut screen_center;
loop {
if gameover {
clear_background(LIGHTGRAY);
let mut text = "You Win!. Press [enter] to play again.";
let font_size = 30.;
if asteroids.len() > 0 {
text = "Game Over. Press [enter] to play again.";
}
let text_size = measure_text(text, None, font_size as _, 1.0);
draw_text(
text,
screen_width() / 2. - text_size.width / 2.,
screen_height() / 2. - text_size.height / 2.,
font_size,
DARKGRAY,
);
if is_key_down(KeyCode::Enter) {
ship = Ship {
pos: Vec2::new(screen_width() / 2., screen_height() / 2.),
rot: 0.,
vel: Vec2::new(0., 0.),
};
bullets = Vec::new();
asteroids = Vec::new();
gameover = false;
screen_center = Vec2::new(screen_width() / 2., screen_height() / 2.);
for _ in 0..10 {
asteroids.push(Asteroid {
pos: screen_center
+ Vec2::new(rand::gen_range(-1., 1.), rand::gen_range(-1., 1.))
.normalize()
* screen_width().min(screen_height())
/ 2.,
vel: Vec2::new(rand::gen_range(-1., 1.), rand::gen_range(-1., 1.)),
rot: 0.,
rot_speed: rand::gen_range(-2., 2.),
size: screen_width().min(screen_height()) / 10.,
sides: rand::gen_range(3, 8),
collided: false,
})
}
}
next_frame().await;
continue;
}
let frame_t = get_time();
let rotation = ship.rot.to_radians();
let mut acc = -ship.vel / 100.; // Friction
// Forward
if is_key_down(KeyCode::Up) {
acc = Vec2::new(rotation.sin(), -rotation.cos()) / 3.;
}
// Shot
if is_key_down(KeyCode::Space) && frame_t - last_shot > 0.5 {
let rot_vec = Vec2::new(rotation.sin(), -rotation.cos());
bullets.push(Bullet {
pos: ship.pos + rot_vec * SHIP_HEIGHT / 2.,
vel: rot_vec * 7.,
shot_at: frame_t,
collided: false,
});
last_shot = frame_t;
}
// Steer
if is_key_down(KeyCode::Right) {
ship.rot += 5.;
} else if is_key_down(KeyCode::Left) {
ship.rot -= 5.;
}
// Euler integration
ship.vel += acc;
if ship.vel.length() > 5. {
ship.vel = ship.vel.normalize() * 5.;
}
ship.pos += ship.vel;
ship.pos = wrap_around(&ship.pos);
// Move each bullet
for bullet in bullets.iter_mut() {
bullet.pos += bullet.vel;
}
// Move each asteroid
for asteroid in asteroids.iter_mut() {
asteroid.pos += asteroid.vel;
asteroid.pos = wrap_around(&asteroid.pos);
asteroid.rot += asteroid.rot_speed;
}
// Bullet lifetime
bullets.retain(|bullet| bullet.shot_at + 1.5 > frame_t);
let mut new_asteroids = Vec::new();
for asteroid in asteroids.iter_mut() {
// Asteroid/ship collision
if (asteroid.pos - ship.pos).length() < asteroid.size + SHIP_HEIGHT / 3. {
gameover = true;
break;
}
// Asteroid/bullet collision
for bullet in bullets.iter_mut() {
if (asteroid.pos - bullet.pos).length() < asteroid.size {
asteroid.collided = true;
bullet.collided = true;
// Break the asteroid
if asteroid.sides > 3 {
new_asteroids.push(Asteroid {
pos: asteroid.pos,
vel: Vec2::new(bullet.vel.y, -bullet.vel.x).normalize()
* rand::gen_range(1., 3.),
rot: rand::gen_range(0., 360.),
rot_speed: rand::gen_range(-2., 2.),
size: asteroid.size * 0.8,
sides: asteroid.sides - 1,
collided: false,
});
new_asteroids.push(Asteroid {
pos: asteroid.pos,
vel: Vec2::new(-bullet.vel.y, bullet.vel.x).normalize()
* rand::gen_range(1., 3.),
rot: rand::gen_range(0., 360.),
rot_speed: rand::gen_range(-2., 2.),
size: asteroid.size * 0.8,
sides: asteroid.sides - 1,
collided: false,
})
}
break;
}
}
}
// Remove the collided objects
bullets.retain(|bullet| bullet.shot_at + 1.5 > frame_t && !bullet.collided);
asteroids.retain(|asteroid| !asteroid.collided);
asteroids.append(&mut new_asteroids);
// You win?
if asteroids.len() == 0 {
gameover = true;
}
if gameover {
continue;
}
clear_background(LIGHTGRAY);
for bullet in bullets.iter() {
draw_circle(bullet.pos.x, bullet.pos.y, 2., BLACK);
}
for asteroid in asteroids.iter() {
draw_poly_lines(
asteroid.pos.x,
asteroid.pos.y,
asteroid.sides,
asteroid.size,
asteroid.rot,
2.,
BLACK,
)
}
let v1 = Vec2::new(
ship.pos.x + rotation.sin() * SHIP_HEIGHT / 2.,
ship.pos.y - rotation.cos() * SHIP_HEIGHT / 2.,
);
let v2 = Vec2::new(
ship.pos.x - rotation.cos() * SHIP_BASE / 2. - rotation.sin() * SHIP_HEIGHT / 2.,
ship.pos.y - rotation.sin() * SHIP_BASE / 2. + rotation.cos() * SHIP_HEIGHT / 2.,
);
let v3 = Vec2::new(
ship.pos.x + rotation.cos() * SHIP_BASE / 2. - rotation.sin() * SHIP_HEIGHT / 2.,
ship.pos.y + rotation.sin() * SHIP_BASE / 2. + rotation.cos() * SHIP_HEIGHT / 2.,
);
draw_triangle_lines(v1, v2, v3, 2., BLACK);
next_frame().await
}
}
More examples
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
async fn main() {
loop {
clear_background(WHITE);
root_ui().window(hash!(), Vec2::new(20., 20.), Vec2::new(450., 200.), |ui| {
let (mouse_x, mouse_y) = mouse_position();
ui.label(None, &format!("Mouse position: {} {}", mouse_x, mouse_y));
let (mouse_wheel_x, mouse_wheel_y) = mouse_wheel();
ui.label(None, &format!("Mouse wheel x: {}", mouse_wheel_x));
ui.label(None, &format!("Mouse wheel y: {}", mouse_wheel_y));
widgets::Group::new(hash!(), Vec2::new(200., 90.))
.position(Vec2::new(240., 0.))
.ui(ui, |ui| {
ui.label(None, "Pressed kbd keys");
if let Some(key) = get_last_key_pressed() {
ui.label(None, &format!("{:?}", key))
}
});
widgets::Group::new(hash!(), Vec2::new(200., 90.))
.position(Vec2::new(240., 92.))
.ui(ui, |ui| {
ui.label(None, "Pressed mouse keys");
if is_mouse_button_down(MouseButton::Left) {
ui.label(None, "Left");
}
if is_mouse_button_down(MouseButton::Right) {
ui.label(None, "Right");
}
if is_mouse_button_down(MouseButton::Middle) {
ui.label(None, "Middle");
}
});
});
next_frame().await;
}
}
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
async fn main() {
let mut rustaceanes: Vec<Rustaceane> = Vec::new();
let rustacean_tex = load_texture("examples/rustacean_happy.png").await.unwrap();
rustacean_tex.set_filter(FilterMode::Nearest);
loop {
clear_background(Color::default());
if macroquad::input::is_mouse_button_down(MouseButton::Left) {
for _i in 0..100 {
rustaceanes.push(Rustaceane {
pos: Vec2::from(macroquad::input::mouse_position()),
speed: Vec2::new(
rand::gen_range(-250., 250.) / 60.,
rand::gen_range(-250., 250.) / 60.,
),
color: Color::from_rgba(
rand::gen_range(50, 240),
rand::gen_range(80, 240),
rand::gen_range(100, 240),
255,
),
})
}
}
for rustaceane in &mut rustaceanes {
rustaceane.pos += rustaceane.speed;
if ((rustaceane.pos.x + rustacean_tex.width() / 2.) > screen_width())
|| ((rustaceane.pos.x + rustacean_tex.width() / 2.) < 0.)
{
rustaceane.speed.x *= -1.;
}
if ((rustaceane.pos.y + rustacean_tex.height() / 2.) > screen_height())
|| ((rustaceane.pos.y + rustacean_tex.height() / 2.) < 0.)
{
rustaceane.speed.y *= -1.;
}
draw_texture(
&rustacean_tex,
rustaceane.pos.x,
rustaceane.pos.y,
rustaceane.color,
);
}
draw_text(format!("FPS: {}", get_fps()).as_str(), 0., 16., 32., WHITE);
draw_text(
format!("Rustaceanes: {}", rustaceanes.len()).as_str(),
0.,
32.,
32.,
WHITE,
);
next_frame().await
}
}
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
fn slots(&mut self, ui: &mut Ui) {
let item_dragging = &mut self.item_dragging;
let fit_command = &mut self.fit_command;
for (label, slot) in self.slots.iter_mut() {
Group::new(hash!("grp", slot.id, &label), Vec2::new(210., 55.)).ui(ui, |ui| {
let drag = Group::new(slot.id, Vec2::new(50., 50.))
// slot without item is not draggable
.draggable(slot.item.is_some())
// but could be a target of drag
.hoverable(*item_dragging)
// and is highlighted with other color when some item is dragging
.highlight(*item_dragging)
.ui(ui, |ui| {
if let Some(ref item) = slot.item {
ui.label(Vec2::new(5., 10.), &item);
}
});
match drag {
// there is some item in this slot and it was dragged to another slot
Drag::Dropped(_, Some(id)) if slot.item.is_some() => {
*fit_command = Some(FittingCommand::Refit {
target_slot: id,
origin_slot: slot.id,
});
}
// there is some item in this slot and it was dragged out - unfit it
Drag::Dropped(_, None) if slot.item.is_some() => {
*fit_command = Some(FittingCommand::Unfit {
target_slot: slot.id,
});
}
// there is no item in this slot
// this is impossible - slots without items are non-draggable
Drag::Dropped(_, _) => unreachable!(),
Drag::Dragging(pos, id) => {
debug!("slots: pos: {:?}, id {:?}", pos, id);
*item_dragging = true;
}
Drag::No => {}
}
ui.label(Vec2::new(60., 20.), label);
});
}
}
fn inventory(&mut self, ui: &mut Ui) {
let item_dragging = &mut self.item_dragging;
for (n, item) in self.inventory.iter().enumerate() {
let drag = Group::new(hash!("inventory", n), Vec2::new(50., 50.))
.draggable(true)
.ui(ui, |ui| {
ui.label(Vec2::new(5., 10.), &item);
});
match drag {
Drag::Dropped(_, Some(id)) => {
self.fit_command = Some(FittingCommand::Fit {
target_slot: id,
item: item.clone(),
});
*item_dragging = false;
}
Drag::Dropped(_, _) => {
*item_dragging = false;
}
Drag::Dragging(pos, id) => {
debug!("inventory: pos: {:?}, id {:?}", pos, id);
*item_dragging = true;
}
_ => {}
}
}
}
fn set_item(&mut self, id: u64, item: Option<String>) {
if let Some(slot) = self.slots.iter_mut().find(|(_, slot)| slot.id == id) {
slot.1.item = item;
}
}
}
#[macroquad::main("UI showcase")]
async fn main() {
let mut data = Data::new();
let mut data0 = String::new();
let mut data1 = String::new();
let mut text0 = String::new();
let mut text1 = String::new();
let mut number0 = 0.;
let mut number1 = 0.;
let texture: Texture2D = load_texture("examples/ferris.png").await.unwrap();
loop {
clear_background(WHITE);
widgets::Window::new(hash!(), vec2(400., 200.), vec2(320., 400.))
.label("Shop")
.titlebar(true)
.ui(&mut *root_ui(), |ui| {
for i in 0..30 {
Group::new(hash!("shop", i), Vec2::new(300., 80.)).ui(ui, |ui| {
ui.label(Vec2::new(10., 10.), &format!("Item N {}", i));
ui.label(Vec2::new(260., 40.), "10/10");
ui.label(Vec2::new(200., 58.), &format!("{} kr", 800));
if ui.button(Vec2::new(260., 55.), "buy") {
data.inventory.push(format!("Item {}", i));
}
});
}
});
widgets::Window::new(hash!(), vec2(100., 220.), vec2(542., 430.))
.label("Fitting window")
.titlebar(true)
.ui(&mut *root_ui(), |ui| {
Group::new(hash!(), Vec2::new(230., 400.)).ui(ui, |ui| {
data.slots(ui);
});
Group::new(hash!(), Vec2::new(280., 400.)).ui(ui, |ui| {
data.inventory(ui);
});
});
widgets::Window::new(hash!(), vec2(470., 50.), vec2(300., 300.))
.label("Megaui Showcase Window")
.ui(&mut *root_ui(), |ui| {
ui.tree_node(hash!(), "input", |ui| {
ui.label(None, "Some random text");
if ui.button(None, "click me") {
println!("hi");
}
ui.separator();
ui.label(None, "Some other random text");
if ui.button(None, "other button") {
println!("hi2");
}
ui.separator();
ui.input_text(hash!(), "<- input text 1", &mut data0);
ui.input_text(hash!(), "<- input text 2", &mut data1);
ui.label(
None,
&format!("Text entered: \"{}\" and \"{}\"", data0, data1),
);
ui.separator();
});
ui.tree_node(hash!(), "buttons", |ui| {
widgets::Button::new(texture.clone())
.size(vec2(120., 70.))
.ui(ui);
ui.same_line(0.);
widgets::Button::new("Button").size(vec2(120., 70.)).ui(ui);
widgets::Button::new("Button").size(vec2(120., 70.)).ui(ui);
ui.same_line(0.);
widgets::Button::new(texture.clone())
.size(vec2(120., 70.))
.ui(ui);
});
ui.tree_node(hash!(), "sliders", |ui| {
ui.slider(hash!(), "[-10 .. 10]", -10f32..10f32, &mut number0);
ui.slider(hash!(), "[0 .. 100]", 0f32..100f32, &mut number1);
});
ui.tree_node(hash!(), "editbox 1", |ui| {
ui.label(None, "This is editbox!");
ui.editbox(hash!(), vec2(285., 165.), &mut text0);
});
ui.tree_node(hash!(), "editbox 2", |ui| {
ui.label(None, "This is editbox!");
ui.editbox(hash!(), vec2(285., 165.), &mut text1);
});
});
match data.fit_command.take() {
Some(FittingCommand::Unfit { target_slot }) => data.set_item(target_slot, None),
Some(FittingCommand::Fit { target_slot, item }) => {
data.set_item(target_slot, Some(item));
}
Some(FittingCommand::Refit {
target_slot,
origin_slot,
}) => {
let origin_item = data
.slots
.iter()
.find_map(|(_, slot)| {
if slot.id == origin_slot {
Some(slot.item.clone())
} else {
None
}
})
.flatten();
data.set_item(target_slot, origin_item);
data.set_item(origin_slot, None);
}
None => {}
};
next_frame().await;
}
}
sourcepub fn select(mask: BVec2, if_true: Vec2, if_false: Vec2) -> Vec2
pub fn select(mask: BVec2, if_true: Vec2, if_false: Vec2) -> Vec2
Creates a vector from the elements in if_true
and if_false
, selecting which to use
for each element of self
.
A true element in the mask uses the corresponding element from if_true
, and false
uses the element from if_false
.
sourcepub const fn from_array(a: [f32; 2]) -> Vec2
pub const fn from_array(a: [f32; 2]) -> Vec2
Creates a new vector from an array.
sourcepub const fn from_slice(slice: &[f32]) -> Vec2
pub const fn from_slice(slice: &[f32]) -> Vec2
Creates a vector from the first 2 values in slice
.
§Panics
Panics if slice
is less than 2 elements long.
sourcepub fn write_to_slice(self, slice: &mut [f32])
pub fn write_to_slice(self, slice: &mut [f32])
Writes the elements of self
to the first 2 elements in slice
.
§Panics
Panics if slice
is less than 2 elements long.
sourcepub fn min(self, rhs: Vec2) -> Vec2
pub fn min(self, rhs: Vec2) -> Vec2
Returns a vector containing the minimum values for each element of self
and rhs
.
In other words this computes [self.x.min(rhs.x), self.y.min(rhs.y), ..]
.
sourcepub fn max(self, rhs: Vec2) -> Vec2
pub fn max(self, rhs: Vec2) -> Vec2
Returns a vector containing the maximum values for each element of self
and rhs
.
In other words this computes [self.x.max(rhs.x), self.y.max(rhs.y), ..]
.
sourcepub fn clamp(self, min: Vec2, max: Vec2) -> Vec2
pub fn clamp(self, min: Vec2, max: Vec2) -> Vec2
Component-wise clamping of values, similar to f32::clamp
.
Each element in min
must be less-or-equal to the corresponding element in max
.
§Panics
Will panic if min
is greater than max
when glam_assert
is enabled.
sourcepub fn min_element(self) -> f32
pub fn min_element(self) -> f32
Returns the horizontal minimum of self
.
In other words this computes min(x, y, ..)
.
sourcepub fn max_element(self) -> f32
pub fn max_element(self) -> f32
Returns the horizontal maximum of self
.
In other words this computes max(x, y, ..)
.
sourcepub fn cmpeq(self, rhs: Vec2) -> BVec2
pub fn cmpeq(self, rhs: Vec2) -> BVec2
Returns a vector mask containing the result of a ==
comparison for each element of
self
and rhs
.
In other words, this computes [self.x == rhs.x, self.y == rhs.y, ..]
for all
elements.
sourcepub fn cmpne(self, rhs: Vec2) -> BVec2
pub fn cmpne(self, rhs: Vec2) -> BVec2
Returns a vector mask containing the result of a !=
comparison for each element of
self
and rhs
.
In other words this computes [self.x != rhs.x, self.y != rhs.y, ..]
for all
elements.
sourcepub fn cmpge(self, rhs: Vec2) -> BVec2
pub fn cmpge(self, rhs: Vec2) -> BVec2
Returns a vector mask containing the result of a >=
comparison for each element of
self
and rhs
.
In other words this computes [self.x >= rhs.x, self.y >= rhs.y, ..]
for all
elements.
sourcepub fn cmpgt(self, rhs: Vec2) -> BVec2
pub fn cmpgt(self, rhs: Vec2) -> BVec2
Returns a vector mask containing the result of a >
comparison for each element of
self
and rhs
.
In other words this computes [self.x > rhs.x, self.y > rhs.y, ..]
for all
elements.
sourcepub fn cmple(self, rhs: Vec2) -> BVec2
pub fn cmple(self, rhs: Vec2) -> BVec2
Returns a vector mask containing the result of a <=
comparison for each element of
self
and rhs
.
In other words this computes [self.x <= rhs.x, self.y <= rhs.y, ..]
for all
elements.
sourcepub fn cmplt(self, rhs: Vec2) -> BVec2
pub fn cmplt(self, rhs: Vec2) -> BVec2
Returns a vector mask containing the result of a <
comparison for each element of
self
and rhs
.
In other words this computes [self.x < rhs.x, self.y < rhs.y, ..]
for all
elements.
sourcepub fn abs(self) -> Vec2
pub fn abs(self) -> Vec2
Returns a vector containing the absolute value of each element of self
.
sourcepub fn signum(self) -> Vec2
pub fn signum(self) -> Vec2
Returns a vector with elements representing the sign of self
.
1.0
if the number is positive,+0.0
orINFINITY
-1.0
if the number is negative,-0.0
orNEG_INFINITY
NAN
if the number isNAN
sourcepub fn is_finite(self) -> bool
pub fn is_finite(self) -> bool
Returns true
if, and only if, all elements are finite. If any element is either
NaN
, positive or negative infinity, this will return false
.
sourcepub fn is_nan_mask(self) -> BVec2
pub fn is_nan_mask(self) -> BVec2
Performs is_nan
on each element of self, returning a vector mask of the results.
In other words, this computes [x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]
.
sourcepub fn length(self) -> f32
pub fn length(self) -> f32
Computes the length of self
.
Examples found in repository?
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
async fn main() {
let mut ship = Ship {
pos: Vec2::new(screen_width() / 2., screen_height() / 2.),
rot: 0.,
vel: Vec2::new(0., 0.),
};
let mut bullets = Vec::new();
let mut last_shot = get_time();
let mut asteroids = Vec::new();
let mut gameover = false;
let mut screen_center;
loop {
if gameover {
clear_background(LIGHTGRAY);
let mut text = "You Win!. Press [enter] to play again.";
let font_size = 30.;
if asteroids.len() > 0 {
text = "Game Over. Press [enter] to play again.";
}
let text_size = measure_text(text, None, font_size as _, 1.0);
draw_text(
text,
screen_width() / 2. - text_size.width / 2.,
screen_height() / 2. - text_size.height / 2.,
font_size,
DARKGRAY,
);
if is_key_down(KeyCode::Enter) {
ship = Ship {
pos: Vec2::new(screen_width() / 2., screen_height() / 2.),
rot: 0.,
vel: Vec2::new(0., 0.),
};
bullets = Vec::new();
asteroids = Vec::new();
gameover = false;
screen_center = Vec2::new(screen_width() / 2., screen_height() / 2.);
for _ in 0..10 {
asteroids.push(Asteroid {
pos: screen_center
+ Vec2::new(rand::gen_range(-1., 1.), rand::gen_range(-1., 1.))
.normalize()
* screen_width().min(screen_height())
/ 2.,
vel: Vec2::new(rand::gen_range(-1., 1.), rand::gen_range(-1., 1.)),
rot: 0.,
rot_speed: rand::gen_range(-2., 2.),
size: screen_width().min(screen_height()) / 10.,
sides: rand::gen_range(3, 8),
collided: false,
})
}
}
next_frame().await;
continue;
}
let frame_t = get_time();
let rotation = ship.rot.to_radians();
let mut acc = -ship.vel / 100.; // Friction
// Forward
if is_key_down(KeyCode::Up) {
acc = Vec2::new(rotation.sin(), -rotation.cos()) / 3.;
}
// Shot
if is_key_down(KeyCode::Space) && frame_t - last_shot > 0.5 {
let rot_vec = Vec2::new(rotation.sin(), -rotation.cos());
bullets.push(Bullet {
pos: ship.pos + rot_vec * SHIP_HEIGHT / 2.,
vel: rot_vec * 7.,
shot_at: frame_t,
collided: false,
});
last_shot = frame_t;
}
// Steer
if is_key_down(KeyCode::Right) {
ship.rot += 5.;
} else if is_key_down(KeyCode::Left) {
ship.rot -= 5.;
}
// Euler integration
ship.vel += acc;
if ship.vel.length() > 5. {
ship.vel = ship.vel.normalize() * 5.;
}
ship.pos += ship.vel;
ship.pos = wrap_around(&ship.pos);
// Move each bullet
for bullet in bullets.iter_mut() {
bullet.pos += bullet.vel;
}
// Move each asteroid
for asteroid in asteroids.iter_mut() {
asteroid.pos += asteroid.vel;
asteroid.pos = wrap_around(&asteroid.pos);
asteroid.rot += asteroid.rot_speed;
}
// Bullet lifetime
bullets.retain(|bullet| bullet.shot_at + 1.5 > frame_t);
let mut new_asteroids = Vec::new();
for asteroid in asteroids.iter_mut() {
// Asteroid/ship collision
if (asteroid.pos - ship.pos).length() < asteroid.size + SHIP_HEIGHT / 3. {
gameover = true;
break;
}
// Asteroid/bullet collision
for bullet in bullets.iter_mut() {
if (asteroid.pos - bullet.pos).length() < asteroid.size {
asteroid.collided = true;
bullet.collided = true;
// Break the asteroid
if asteroid.sides > 3 {
new_asteroids.push(Asteroid {
pos: asteroid.pos,
vel: Vec2::new(bullet.vel.y, -bullet.vel.x).normalize()
* rand::gen_range(1., 3.),
rot: rand::gen_range(0., 360.),
rot_speed: rand::gen_range(-2., 2.),
size: asteroid.size * 0.8,
sides: asteroid.sides - 1,
collided: false,
});
new_asteroids.push(Asteroid {
pos: asteroid.pos,
vel: Vec2::new(-bullet.vel.y, bullet.vel.x).normalize()
* rand::gen_range(1., 3.),
rot: rand::gen_range(0., 360.),
rot_speed: rand::gen_range(-2., 2.),
size: asteroid.size * 0.8,
sides: asteroid.sides - 1,
collided: false,
})
}
break;
}
}
}
// Remove the collided objects
bullets.retain(|bullet| bullet.shot_at + 1.5 > frame_t && !bullet.collided);
asteroids.retain(|asteroid| !asteroid.collided);
asteroids.append(&mut new_asteroids);
// You win?
if asteroids.len() == 0 {
gameover = true;
}
if gameover {
continue;
}
clear_background(LIGHTGRAY);
for bullet in bullets.iter() {
draw_circle(bullet.pos.x, bullet.pos.y, 2., BLACK);
}
for asteroid in asteroids.iter() {
draw_poly_lines(
asteroid.pos.x,
asteroid.pos.y,
asteroid.sides,
asteroid.size,
asteroid.rot,
2.,
BLACK,
)
}
let v1 = Vec2::new(
ship.pos.x + rotation.sin() * SHIP_HEIGHT / 2.,
ship.pos.y - rotation.cos() * SHIP_HEIGHT / 2.,
);
let v2 = Vec2::new(
ship.pos.x - rotation.cos() * SHIP_BASE / 2. - rotation.sin() * SHIP_HEIGHT / 2.,
ship.pos.y - rotation.sin() * SHIP_BASE / 2. + rotation.cos() * SHIP_HEIGHT / 2.,
);
let v3 = Vec2::new(
ship.pos.x + rotation.cos() * SHIP_BASE / 2. - rotation.sin() * SHIP_HEIGHT / 2.,
ship.pos.y + rotation.sin() * SHIP_BASE / 2. + rotation.cos() * SHIP_HEIGHT / 2.,
);
draw_triangle_lines(v1, v2, v3, 2., BLACK);
next_frame().await
}
}
sourcepub fn length_squared(self) -> f32
pub fn length_squared(self) -> f32
Computes the squared length of self
.
This is faster than length()
as it avoids a square root operation.
sourcepub fn length_recip(self) -> f32
pub fn length_recip(self) -> f32
Computes 1.0 / length()
.
For valid results, self
must not be of length zero.
sourcepub fn distance(self, rhs: Vec2) -> f32
pub fn distance(self, rhs: Vec2) -> f32
Computes the Euclidean distance between two points in space.
sourcepub fn distance_squared(self, rhs: Vec2) -> f32
pub fn distance_squared(self, rhs: Vec2) -> f32
Compute the squared euclidean distance between two points in space.
sourcepub fn normalize(self) -> Vec2
pub fn normalize(self) -> Vec2
Returns self
normalized to length 1.0.
For valid results, self
must not be of length zero, nor very close to zero.
See also Self::try_normalize
and Self::normalize_or_zero
.
Panics
Will panic if self
is zero length when glam_assert
is enabled.
Examples found in repository?
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
async fn main() {
let mut ship = Ship {
pos: Vec2::new(screen_width() / 2., screen_height() / 2.),
rot: 0.,
vel: Vec2::new(0., 0.),
};
let mut bullets = Vec::new();
let mut last_shot = get_time();
let mut asteroids = Vec::new();
let mut gameover = false;
let mut screen_center;
loop {
if gameover {
clear_background(LIGHTGRAY);
let mut text = "You Win!. Press [enter] to play again.";
let font_size = 30.;
if asteroids.len() > 0 {
text = "Game Over. Press [enter] to play again.";
}
let text_size = measure_text(text, None, font_size as _, 1.0);
draw_text(
text,
screen_width() / 2. - text_size.width / 2.,
screen_height() / 2. - text_size.height / 2.,
font_size,
DARKGRAY,
);
if is_key_down(KeyCode::Enter) {
ship = Ship {
pos: Vec2::new(screen_width() / 2., screen_height() / 2.),
rot: 0.,
vel: Vec2::new(0., 0.),
};
bullets = Vec::new();
asteroids = Vec::new();
gameover = false;
screen_center = Vec2::new(screen_width() / 2., screen_height() / 2.);
for _ in 0..10 {
asteroids.push(Asteroid {
pos: screen_center
+ Vec2::new(rand::gen_range(-1., 1.), rand::gen_range(-1., 1.))
.normalize()
* screen_width().min(screen_height())
/ 2.,
vel: Vec2::new(rand::gen_range(-1., 1.), rand::gen_range(-1., 1.)),
rot: 0.,
rot_speed: rand::gen_range(-2., 2.),
size: screen_width().min(screen_height()) / 10.,
sides: rand::gen_range(3, 8),
collided: false,
})
}
}
next_frame().await;
continue;
}
let frame_t = get_time();
let rotation = ship.rot.to_radians();
let mut acc = -ship.vel / 100.; // Friction
// Forward
if is_key_down(KeyCode::Up) {
acc = Vec2::new(rotation.sin(), -rotation.cos()) / 3.;
}
// Shot
if is_key_down(KeyCode::Space) && frame_t - last_shot > 0.5 {
let rot_vec = Vec2::new(rotation.sin(), -rotation.cos());
bullets.push(Bullet {
pos: ship.pos + rot_vec * SHIP_HEIGHT / 2.,
vel: rot_vec * 7.,
shot_at: frame_t,
collided: false,
});
last_shot = frame_t;
}
// Steer
if is_key_down(KeyCode::Right) {
ship.rot += 5.;
} else if is_key_down(KeyCode::Left) {
ship.rot -= 5.;
}
// Euler integration
ship.vel += acc;
if ship.vel.length() > 5. {
ship.vel = ship.vel.normalize() * 5.;
}
ship.pos += ship.vel;
ship.pos = wrap_around(&ship.pos);
// Move each bullet
for bullet in bullets.iter_mut() {
bullet.pos += bullet.vel;
}
// Move each asteroid
for asteroid in asteroids.iter_mut() {
asteroid.pos += asteroid.vel;
asteroid.pos = wrap_around(&asteroid.pos);
asteroid.rot += asteroid.rot_speed;
}
// Bullet lifetime
bullets.retain(|bullet| bullet.shot_at + 1.5 > frame_t);
let mut new_asteroids = Vec::new();
for asteroid in asteroids.iter_mut() {
// Asteroid/ship collision
if (asteroid.pos - ship.pos).length() < asteroid.size + SHIP_HEIGHT / 3. {
gameover = true;
break;
}
// Asteroid/bullet collision
for bullet in bullets.iter_mut() {
if (asteroid.pos - bullet.pos).length() < asteroid.size {
asteroid.collided = true;
bullet.collided = true;
// Break the asteroid
if asteroid.sides > 3 {
new_asteroids.push(Asteroid {
pos: asteroid.pos,
vel: Vec2::new(bullet.vel.y, -bullet.vel.x).normalize()
* rand::gen_range(1., 3.),
rot: rand::gen_range(0., 360.),
rot_speed: rand::gen_range(-2., 2.),
size: asteroid.size * 0.8,
sides: asteroid.sides - 1,
collided: false,
});
new_asteroids.push(Asteroid {
pos: asteroid.pos,
vel: Vec2::new(-bullet.vel.y, bullet.vel.x).normalize()
* rand::gen_range(1., 3.),
rot: rand::gen_range(0., 360.),
rot_speed: rand::gen_range(-2., 2.),
size: asteroid.size * 0.8,
sides: asteroid.sides - 1,
collided: false,
})
}
break;
}
}
}
// Remove the collided objects
bullets.retain(|bullet| bullet.shot_at + 1.5 > frame_t && !bullet.collided);
asteroids.retain(|asteroid| !asteroid.collided);
asteroids.append(&mut new_asteroids);
// You win?
if asteroids.len() == 0 {
gameover = true;
}
if gameover {
continue;
}
clear_background(LIGHTGRAY);
for bullet in bullets.iter() {
draw_circle(bullet.pos.x, bullet.pos.y, 2., BLACK);
}
for asteroid in asteroids.iter() {
draw_poly_lines(
asteroid.pos.x,
asteroid.pos.y,
asteroid.sides,
asteroid.size,
asteroid.rot,
2.,
BLACK,
)
}
let v1 = Vec2::new(
ship.pos.x + rotation.sin() * SHIP_HEIGHT / 2.,
ship.pos.y - rotation.cos() * SHIP_HEIGHT / 2.,
);
let v2 = Vec2::new(
ship.pos.x - rotation.cos() * SHIP_BASE / 2. - rotation.sin() * SHIP_HEIGHT / 2.,
ship.pos.y - rotation.sin() * SHIP_BASE / 2. + rotation.cos() * SHIP_HEIGHT / 2.,
);
let v3 = Vec2::new(
ship.pos.x + rotation.cos() * SHIP_BASE / 2. - rotation.sin() * SHIP_HEIGHT / 2.,
ship.pos.y + rotation.sin() * SHIP_BASE / 2. + rotation.cos() * SHIP_HEIGHT / 2.,
);
draw_triangle_lines(v1, v2, v3, 2., BLACK);
next_frame().await
}
}
sourcepub fn try_normalize(self) -> Option<Vec2>
pub fn try_normalize(self) -> Option<Vec2>
Returns self
normalized to length 1.0 if possible, else returns None
.
In particular, if the input is zero (or very close to zero), or non-finite,
the result of this operation will be None
.
See also Self::normalize_or_zero
.
sourcepub fn normalize_or_zero(self) -> Vec2
pub fn normalize_or_zero(self) -> Vec2
Returns self
normalized to length 1.0 if possible, else returns zero.
In particular, if the input is zero (or very close to zero), or non-finite, the result of this operation will be zero.
See also Self::try_normalize
.
sourcepub fn is_normalized(self) -> bool
pub fn is_normalized(self) -> bool
Returns whether self
is length 1.0
or not.
Uses a precision threshold of 1e-6
.
sourcepub fn project_onto(self, rhs: Vec2) -> Vec2
pub fn project_onto(self, rhs: Vec2) -> Vec2
Returns the vector projection of self
onto rhs
.
rhs
must be of non-zero length.
§Panics
Will panic if rhs
is zero length when glam_assert
is enabled.
sourcepub fn reject_from(self, rhs: Vec2) -> Vec2
pub fn reject_from(self, rhs: Vec2) -> Vec2
Returns the vector rejection of self
from rhs
.
The vector rejection is the vector perpendicular to the projection of self
onto
rhs
, in rhs words the result of self - self.project_onto(rhs)
.
rhs
must be of non-zero length.
§Panics
Will panic if rhs
has a length of zero when glam_assert
is enabled.
sourcepub fn project_onto_normalized(self, rhs: Vec2) -> Vec2
pub fn project_onto_normalized(self, rhs: Vec2) -> Vec2
Returns the vector projection of self
onto rhs
.
rhs
must be normalized.
§Panics
Will panic if rhs
is not normalized when glam_assert
is enabled.
sourcepub fn reject_from_normalized(self, rhs: Vec2) -> Vec2
pub fn reject_from_normalized(self, rhs: Vec2) -> Vec2
Returns the vector rejection of self
from rhs
.
The vector rejection is the vector perpendicular to the projection of self
onto
rhs
, in rhs words the result of self - self.project_onto(rhs)
.
rhs
must be normalized.
§Panics
Will panic if rhs
is not normalized when glam_assert
is enabled.
sourcepub fn round(self) -> Vec2
pub fn round(self) -> Vec2
Returns a vector containing the nearest integer to a number for each element of self
.
Round half-way cases away from 0.0.
sourcepub fn floor(self) -> Vec2
pub fn floor(self) -> Vec2
Returns a vector containing the largest integer less than or equal to a number for each
element of self
.
sourcepub fn ceil(self) -> Vec2
pub fn ceil(self) -> Vec2
Returns a vector containing the smallest integer greater than or equal to a number for
each element of self
.
sourcepub fn fract(self) -> Vec2
pub fn fract(self) -> Vec2
Returns a vector containing the fractional part of the vector, e.g. self - self.floor()
.
Note that this is fast but not precise for large numbers.
sourcepub fn exp(self) -> Vec2
pub fn exp(self) -> Vec2
Returns a vector containing e^self
(the exponential function) for each element of
self
.
sourcepub fn powf(self, n: f32) -> Vec2
pub fn powf(self, n: f32) -> Vec2
Returns a vector containing each element of self
raised to the power of n
.
sourcepub fn recip(self) -> Vec2
pub fn recip(self) -> Vec2
Returns a vector containing the reciprocal 1.0/n
of each element of self
.
sourcepub fn lerp(self, rhs: Vec2, s: f32) -> Vec2
pub fn lerp(self, rhs: Vec2, s: f32) -> Vec2
Performs a linear interpolation between self
and rhs
based on the value s
.
When s
is 0.0
, the result will be equal to self
. When s
is 1.0
, the result
will be equal to rhs
. When s
is outside of range [0, 1]
, the result is linearly
extrapolated.
sourcepub fn abs_diff_eq(self, rhs: Vec2, max_abs_diff: f32) -> bool
pub fn abs_diff_eq(self, rhs: Vec2, max_abs_diff: f32) -> bool
Returns true if the absolute difference of all elements between self
and rhs
is
less than or equal to max_abs_diff
.
This can be used to compare if two vectors contain similar elements. It works best when
comparing with a known value. The max_abs_diff
that should be used used depends on
the values being compared against.
For more see comparing floating point numbers.
sourcepub fn clamp_length(self, min: f32, max: f32) -> Vec2
pub fn clamp_length(self, min: f32, max: f32) -> Vec2
Returns a vector with a length no less than min
and no more than max
§Panics
Will panic if min
is greater than max
when glam_assert
is enabled.
sourcepub fn clamp_length_max(self, max: f32) -> Vec2
pub fn clamp_length_max(self, max: f32) -> Vec2
Returns a vector with a length no more than max
sourcepub fn clamp_length_min(self, min: f32) -> Vec2
pub fn clamp_length_min(self, min: f32) -> Vec2
Returns a vector with a length no less than min
sourcepub fn mul_add(self, a: Vec2, b: Vec2) -> Vec2
pub fn mul_add(self, a: Vec2, b: Vec2) -> Vec2
Fused multiply-add. Computes (self * a) + b
element-wise with only one rounding
error, yielding a more accurate result than an unfused multiply-add.
Using mul_add
may be more performant than an unfused multiply-add if the target
architecture has a dedicated fma CPU instruction. However, this is not always true,
and will be heavily dependant on designing algorithms with specific target hardware in
mind.
sourcepub fn from_angle(angle: f32) -> Vec2
pub fn from_angle(angle: f32) -> Vec2
Creates a 2D vector containing [angle.cos(), angle.sin()]
. This can be used in
conjunction with the rotate
method, e.g. Vec2::from_angle(PI).rotate(Vec2::Y)
will
create the vector [-1, 0] and rotate Vec2::Y
around it returning -Vec2::Y
.
sourcepub fn angle_between(self, rhs: Vec2) -> f32
pub fn angle_between(self, rhs: Vec2) -> f32
Returns the angle (in radians) between self
and rhs
.
The input vectors do not need to be unit length however they must be non-zero.
sourcepub fn perp_dot(self, rhs: Vec2) -> f32
pub fn perp_dot(self, rhs: Vec2) -> f32
The perpendicular dot product of self
and rhs
.
Also known as the wedge product, 2D cross product, and determinant.
Trait Implementations§
source§impl AddAssign<f32> for Vec2
impl AddAssign<f32> for Vec2
source§fn add_assign(&mut self, rhs: f32)
fn add_assign(&mut self, rhs: f32)
+=
operation. Read moresource§impl AddAssign for Vec2
impl AddAssign for Vec2
source§fn add_assign(&mut self, rhs: Vec2)
fn add_assign(&mut self, rhs: Vec2)
+=
operation. Read moresource§impl DivAssign<f32> for Vec2
impl DivAssign<f32> for Vec2
source§fn div_assign(&mut self, rhs: f32)
fn div_assign(&mut self, rhs: f32)
/=
operation. Read moresource§impl DivAssign for Vec2
impl DivAssign for Vec2
source§fn div_assign(&mut self, rhs: Vec2)
fn div_assign(&mut self, rhs: Vec2)
/=
operation. Read moresource§impl MulAssign<f32> for Vec2
impl MulAssign<f32> for Vec2
source§fn mul_assign(&mut self, rhs: f32)
fn mul_assign(&mut self, rhs: f32)
*=
operation. Read moresource§impl MulAssign for Vec2
impl MulAssign for Vec2
source§fn mul_assign(&mut self, rhs: Vec2)
fn mul_assign(&mut self, rhs: Vec2)
*=
operation. Read moresource§impl PartialEq for Vec2
impl PartialEq for Vec2
source§impl RemAssign<f32> for Vec2
impl RemAssign<f32> for Vec2
source§fn rem_assign(&mut self, rhs: f32)
fn rem_assign(&mut self, rhs: f32)
%=
operation. Read moresource§impl RemAssign for Vec2
impl RemAssign for Vec2
source§fn rem_assign(&mut self, rhs: Vec2)
fn rem_assign(&mut self, rhs: Vec2)
%=
operation. Read moresource§impl SubAssign<f32> for Vec2
impl SubAssign<f32> for Vec2
source§fn sub_assign(&mut self, rhs: f32)
fn sub_assign(&mut self, rhs: f32)
-=
operation. Read moresource§impl SubAssign for Vec2
impl SubAssign for Vec2
source§fn sub_assign(&mut self, rhs: Vec2)
fn sub_assign(&mut self, rhs: Vec2)
-=
operation. Read more