From 4ee53b19900fc4795865fea633be1d0dc11069d4 Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Thu, 21 Oct 2021 22:13:18 +1300 Subject: [PATCH 1/8] Simple 2d rotation example --- CREDITS.md | 1 + Cargo.toml | 4 + assets/textures/simplespace/License.txt | 22 +++ assets/textures/simplespace/enemy_A.png | Bin 0 -> 1151 bytes assets/textures/simplespace/enemy_B.png | Bin 0 -> 1095 bytes assets/textures/simplespace/ship_C.png | Bin 0 -> 615 bytes examples/2d/rotation.rs | 253 ++++++++++++++++++++++++ examples/README.md | 1 + 8 files changed, 281 insertions(+) create mode 100644 assets/textures/simplespace/License.txt create mode 100644 assets/textures/simplespace/enemy_A.png create mode 100644 assets/textures/simplespace/enemy_B.png create mode 100644 assets/textures/simplespace/ship_C.png create mode 100644 examples/2d/rotation.rs diff --git a/CREDITS.md b/CREDITS.md index cefd08df93ad4..40ae5c0852b8b 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -16,3 +16,4 @@ * Generic RPG Pack (CC0 license) by [Bakudas](https://twitter.com/bakudas) and [Gabe Fern](https://twitter.com/_Gabrielfer) * Environment maps (`.hdr` files) from [HDRIHaven](https://hdrihaven.com) (CC0 license) +* Simple Space by [Kenny](https://www.kenney.nl/assets/simple-space) (CC0 license) diff --git a/Cargo.toml b/Cargo.toml index 51565942113cd..58d2c9ea1dd7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -112,6 +112,10 @@ path = "examples/2d/mesh.rs" name = "many_sprites" path = "examples/2d/many_sprites.rs" +[[example]] +name = "2d_rotation" +path = "examples/2d/rotation.rs" + [[example]] name = "sprite" path = "examples/2d/sprite.rs" diff --git a/assets/textures/simplespace/License.txt b/assets/textures/simplespace/License.txt new file mode 100644 index 0000000000000..bdba93fb4f136 --- /dev/null +++ b/assets/textures/simplespace/License.txt @@ -0,0 +1,22 @@ + + + Simple Space + + Created/distributed by Kenney (www.kenney.nl) + Creation date: 03-03-2021 + + ------------------------------ + + License: (Creative Commons Zero, CC0) + http://creativecommons.org/publicdomain/zero/1.0/ + + This content is free to use in personal, educational and commercial projects. + Support us by crediting Kenney or www.kenney.nl (this is not mandatory) + + ------------------------------ + + Donate: http://support.kenney.nl + Patreon: http://patreon.com/kenney/ + + Follow on Twitter for updates: + http://twitter.com/KenneyNL \ No newline at end of file diff --git a/assets/textures/simplespace/enemy_A.png b/assets/textures/simplespace/enemy_A.png new file mode 100644 index 0000000000000000000000000000000000000000..7db03b81a33201386cefb16ea6d919f2021e1b5e GIT binary patch literal 1151 zcmXAneM}Q~7{`Bw3Zsa;jmVf;mw*TZEZG~nu>uP^iGaYsmkj85$z(H?y1-b5(6S{E z{$QP`3pntQIm2cEH_Xr=6lGHr!4_yK(3ZPWD1E!$L9gxg4fb>Xa`!yX@9w$h_x*fx z?FIRtgs@^*0DzF3W7$P8XTG>!@rSW@w8a7w^K4dL765;WgS{2I0AO4#$SpqNc6%KT zH(U+}?eX|1%IWp)*lZ4&Y*{8#lcas;|7Ed|27{F#D1`!5D6~qYc5~AXw{khUvZ6;( zz16z2wq`b&2!jD%T{Yr3xwd98nQ$Dp&CO{jih^T|M(fs=9lp}*34(CybY{4PXL-F| zjb@#qXjs4q2g0N0=2ULC2NpC<%Va9GdToAwWqw{Gmt$}g{8p_I9%)NW|zz3_4;Vq z?Q*$El7h0~Scn4|p*af+7^GWYx9D^xkH-rgK+z4Wb!%e-UtC;WTGByUD@r5VpldEls;1EX0&bRnRmHGb}IbpzPw*hfXN{ zcwJHcr>K|*FP<1dP|2_a<)8=;+`kPs(eqm+;g z6P#flFBC!82<+vBf(JDRssZrh=459TpPs^%8x3;>(E$Q=Bf-}+)~ZkDlU()t#K>5u75TknJ zOj*oiP+!sSmMZ}QztlY2z`LSI5nt6-&A0|wUE`e~4~%sAUZnlg;W?ssk+aMHYw!!u zCtOGr;wT z2*$MB?&U=nqRb&|qJAf(QYeWGv*%&y^#ZKYQro&%gf<9iPDZ literal 0 HcmV?d00001 diff --git a/assets/textures/simplespace/enemy_B.png b/assets/textures/simplespace/enemy_B.png new file mode 100644 index 0000000000000000000000000000000000000000..fbc35f06bf6a6955c53f6b1882e110a543f7fe72 GIT binary patch literal 1095 zcmYk4drXs87{<#*!K!Nw)4Bmc6WDMoLM98sa4k?bU|0}{vLP4e219f@0a3$NE;?$a zLjs6#KoNtZFf3Rd+b~pvbD3aUTA)Dt^($@ZmG8+dmvvUF1N0$i*JLez};?-NVE*tAxLF3TIT0v zYPDfz1_G&kKA%#lSE*KKXJLSYAXdHJWH6XP__;Y57>?bJn$0$V1~M-!ETgDPF4qDO zFhhxCWob#lekTtbBmzoEYXe=0J(O5JXK}aNo1ml1Pg~Ne)vDvW*E+V3Y z#b9ta92}C(<8Vq?91<&*#fV@qXfTU}!(0yg=uZsBKQV)nl3y@s=&Yy}kau4BhFQaO zPZZV;j~9hJ7?}HvkaIZY`oQVdBbR^8*yU8asb#shucWoPqMdoFTHpn=Itw%-(=M+R2l`u50y4r{c3V`PFFl ziz5SPkKY+7N+pMLdB_d?SLELx?;EdAqKp>Aj}dQmP1t3=mwG}%4gJVa%>zP9@LSpI zC->`Vg)iZ9?wM+O8T;a60&a6wjBLuzzMIk<-I4j%CG!Xwu`J2+`MZfzNs=F$12-yI zU724(gE4y-6n$yLydNX2Bc-=p@aUfFx<-Q(AKphzY@eQN+$P_S?hzYbRPn5Xr%Vlk zdr#SMq@5unaL~5ee&|kO)Ol}@T(IlK3IF+Qlb^gY{^uw6huR78bjz*M2)mxnO0WCd zTD;c8BUbe!gsR^Dys`4(hc`bW`6g+RcKsnnme8%v;>3P(|rA{R6N!eoC zv%8_%W8K5C`eyXND2^F-6Us<_=eIiM6f#Z!Hn{GK#h;#?NDy`~>$9f=-FQ@0PUNIq5_TvCA1)8#QBF2!@T7~>{vFY&GV_48^Y9`uhaGl0^Js6`2caG0-m(M7 zw(rehMt<8 literal 0 HcmV?d00001 diff --git a/assets/textures/simplespace/ship_C.png b/assets/textures/simplespace/ship_C.png new file mode 100644 index 0000000000000000000000000000000000000000..4f5e493701a1a54afea9bdaaac0f2ea726892d20 GIT binary patch literal 615 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijM2l#}z z{`m3p?b{C@K79H5_4|t#?_R(D`0Ux+-@ku<{`~Ff(^v1`fByFE*OxCq^yU5gFE3xd z|MlzFlPB*VJb3Zw(W}3I|2}#0@;?lmKY#1|`P)DQH2dn+`xh_Xy?XV*?b}a)%C20w zcm4Xq3m5L(y!q(j#XFZT-~0Xh&(EK~E?v6&{rgX#)mN_E|MTY$(9&zy9^AY4?BhqE zb)RqCc=Y=9hg-KE10DAK`P(~po<4p0`q878_wPS{`}QNy4M3ZL)?L3Z*$=c*wj{_e z_&x~q0|AiG2ZQ_l_x11h>(77h&rox9n>Yglqnf9SV@Sl|x7Wg*4;hHGJ=Eem!l{wE zLvn2(%N_35|Nn=|NJ(FwGx=gs=Dpirs?X&%Ul!%IdBDj3M_hp?oaxruC$DzI%5h9q z>3m$VTZQ5ILTL>PEoPnb&f7D0w=&kr?Rp>&4I0^M#&aTNxD2IrA_2S{wf0z0DVm z&|;=1pD)DZy*xjiH48_Eo%`mWU)R1_UyGgLntf*A|4*{1%tvM&*K5=N+0(G;+1&o${y|j@F`wNo z-Zb%MmbkWuvHMu2NJ4D-i4MayhU=wbOefawnj5$NvM%?5S@sj#cm=ZOCbCR1&3wUF y)XU485TVV+8gYG7Bg65n27l})u>*a(l~vVI@3B7zcMmXV89ZJ6T-G@yGywofz+Nc; literal 0 HcmV?d00001 diff --git a/examples/2d/rotation.rs b/examples/2d/rotation.rs new file mode 100644 index 0000000000000..0a6b49fb26be6 --- /dev/null +++ b/examples/2d/rotation.rs @@ -0,0 +1,253 @@ +use bevy::{ + core::FixedTimestep, + math::{const_vec2, Vec3Swizzles}, + prelude::*, +}; + +const TIME_STEP: f32 = 1.0 / 60.0; +const BOUNDS: Vec2 = const_vec2!([1200.0, 640.0]); + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_startup_system(setup) + .add_system_set( + SystemSet::new() + .with_run_criteria(FixedTimestep::step(TIME_STEP as f64)) + .with_system(player_movement_system) + .with_system(snap_to_player_system) + .with_system(rotate_to_player_system), + ) + .add_system(bevy::input::system::exit_on_esc_system) + .run(); +} + +/// player component +#[derive(Component)] +struct Player { + /// linear speed in meters per second + movement_speed: f32, + /// rotation speed in radians per second + rotation_speed: f32, +} + +/// snap to player ship behavior +#[derive(Component)] +struct SnapToPlayer; + +/// rotate to face player ship behavior +#[derive(Component)] +struct RotateToPlayer { + /// rotation speed in radians per second + rotation_speed: f32, +} + +fn setup( + mut commands: Commands, + mut materials: ResMut>, + asset_server: Res, +) { + // Add the game's entities to our world + + let ship_handle = asset_server.load("textures/simplespace/ship_C.png"); + let enemy_a_handle = asset_server.load("textures/simplespace/enemy_A.png"); + let enemy_b_handle = asset_server.load("textures/simplespace/enemy_B.png"); + + // cameras + commands.spawn_bundle(OrthographicCameraBundle::new_2d()); + + let horizontal_margin = BOUNDS.x / 4.0; + let vertical_margin = BOUNDS.y / 4.0; + + // ship + commands + .spawn_bundle(SpriteBundle { + material: materials.add(ship_handle.into()), + ..Default::default() + }) + .insert(Player { + movement_speed: 500.0, // metres per second + rotation_speed: f32::to_radians(360.0), // degrees per second + }); + + // snap to player enemy spawns on the bottom and left + commands + .spawn_bundle(SpriteBundle { + material: materials.add(enemy_a_handle.clone().into()), + transform: Transform::from_xyz(0.0 - horizontal_margin, 0.0, 0.0), + ..Default::default() + }) + .insert(SnapToPlayer); + commands + .spawn_bundle(SpriteBundle { + material: materials.add(enemy_a_handle.into()), + transform: Transform::from_xyz(0.0, 0.0 - vertical_margin, 0.0), + ..Default::default() + }) + .insert(SnapToPlayer); + + // rotate to player enemy spawns on the top and right + commands + .spawn_bundle(SpriteBundle { + material: materials.add(enemy_b_handle.clone().into()), + transform: Transform::from_xyz(0.0 + horizontal_margin, 0.0, 0.0), + ..Default::default() + }) + .insert(RotateToPlayer { + rotation_speed: f32::to_radians(45.0), // degrees per second + }); + commands + .spawn_bundle(SpriteBundle { + material: materials.add(enemy_b_handle.into()), + transform: Transform::from_xyz(0.0, 0.0 + vertical_margin, 0.0), + ..Default::default() + }) + .insert(RotateToPlayer { + rotation_speed: f32::to_radians(90.0), // degrees per second + }); +} + +/// Demonstrates applying rotation and movement based on keyboard input. +fn player_movement_system( + keyboard_input: Res>, + mut query: Query<(&Player, &mut Transform)>, +) { + let (ship, mut transform) = query.single_mut(); + + let mut rotation_factor = 0.0; + let mut movement_factor = 0.0; + + if keyboard_input.pressed(KeyCode::Left) { + rotation_factor += 1.0; + } + + if keyboard_input.pressed(KeyCode::Right) { + rotation_factor -= 1.0; + } + + if keyboard_input.pressed(KeyCode::Up) { + movement_factor += 1.0; + } + + // create the change in rotation around the Z axis (pointing through the 2d plane of the screen) + let rotation_delta = Quat::from_rotation_z(rotation_factor * ship.rotation_speed * TIME_STEP); + // update the ship rotation with our rotation delta + transform.rotation *= rotation_delta; + + // get the ship's forward vector by applying the current rotation to the ships initial facing vector + let movement_direction = transform.rotation * Vec3::Y; + // get the distance the ship will move based on direction, the ship's movement speed and delta time + let movement_distance = movement_factor * ship.movement_speed * TIME_STEP; + // create the change in translation using the new movement direction and distance + let translation_delta = movement_direction * movement_distance; + // update the ship translation with our new translation delta + transform.translation += translation_delta; + + // bound the ship within the invisible level bounds + let extents = Vec3::from((BOUNDS / 2.0, 0.0)); + transform.translation = transform.translation.min(extents).max(-extents); +} + +/// Demonstrates snapping the enemy ship to face the player ship immediately. +fn snap_to_player_system( + mut query: Query<&mut Transform, (With, Without)>, + player_query: Query<&Transform, With>, +) { + let player_transform = player_query.single(); + // get the player translation in 2d + let player_translation = player_transform.translation.xy(); + + for mut enemy_transform in query.iter_mut() { + // get the enemy ship forward vector in 2d (already unit length) + let enemy_forward = (enemy_transform.rotation * Vec3::Y).xy(); + // get the vector from the enemy ship to the player ship in 2d and normalize it. + let to_player = (player_translation - enemy_transform.translation.xy()).normalize(); + + // get the quaternion to rotate from the current enemy facing direction to the direction + // facing the player + let rotate_to_player = Quat::from_rotation_arc( + Vec3::from((enemy_forward, 0.0)), + Vec3::from((to_player, 0.0)), + ); + + // rotate the enemy to face the player + enemy_transform.rotation *= rotate_to_player; + } +} + +/// Demonstrates rotating an enemy ship to face the player ship at a given rotation speed. +/// +/// This method uses the vector dot product to determine if the enemy is facing the player and +/// if not, which way to rotate to face the player. The dot product on two unit length vectors +/// will return a value between -1.0 and +1.0 which tells us the following about the two vectors: +/// +/// * If the result is 1.0 the vectors are pointing in the same direction, the angle between them +/// is 0 degrees. +/// * If the result is 0.0 the vectors are perpendicular, the angle between them is 90 degrees. +/// * If the result is -1.0 the vectors are parallel but pointing in opposite directions, the angle +/// between them is 180 degrees. +/// * If the result is positive the vectors are pointing in roughly the same direction, the angle +/// between them is greater than 0 and less than 90 degrees. +/// * If the result is negative the vectors are pointing in roughly opposite directions, the angle +/// between them is greater than 90 and less than 180 degrees. +/// +/// It is possible to get the angle by taking the arc cosine (`acos`) of the dot product. It is +/// often unnecessary to do this though. Beware than `acos` will return `NaN` if the input is less +/// than -1.0 or greater than 1.0. This can happen even when working with unit vectors due to +/// floating point precision loss, so it pays to clamp your dot product value before calling +/// `acos`. +fn rotate_to_player_system( + mut query: Query<(&RotateToPlayer, &mut Transform), Without>, + player_query: Query<&Transform, With>, +) { + let player_transform = player_query.single(); + // get the player translation in 2d + let player_translation = player_transform.translation.xy(); + + for (config, mut enemy_transform) in query.iter_mut() { + // get the enemy ship forward vector in 2d (already unit length) + let enemy_forward = (enemy_transform.rotation * Vec3::Y).xy(); + + // get the vector from the enemy ship to the player ship in 2d and normalize it. + let to_player = (player_translation - enemy_transform.translation.xy()).normalize(); + + // get the dot product between the enemy forward vector and the direction to the player. + let forward_dot_player = enemy_forward.dot(to_player); + + // if the dot product is approximately 1.0 then the enemy is already facing the player and + // we can early out. + if (forward_dot_player - 1.0).abs() < f32::EPSILON { + continue; + } + + // get the right vector of the enemy ship in 2d (already unit length) + let enemy_right = (enemy_transform.rotation * Vec3::X).xy(); + + // get the dot product of the enemy right vector and the direction to the player ship. + // if the dot product is negative them we need to rotate counter clockwise, if it is + // positive we need to rotate clockwise. Note that `copysign` will still return 1.0 if the + // dot product is 0.0 (because the player is directly behind the enemy, so perpendicular + // with the right vector). + let right_dot_player = enemy_right.dot(to_player); + + // determine the sign of rotation from the right dot player. We need to negate the sign + // here as the 2D bevy co-ordinate system rotates around +Z, which is pointing out of the + // screen. Due to the right hand rule, positive rotation around +Z is counter clockwise and + // negative is clockwise. + let rotation_sign = -f32::copysign(1.0, right_dot_player); + + // limit rotation so we don't overshoot the target. We need to convert our dot product to + // an angle here so we can get an angle of rotation to clamp against. + let max_angle = forward_dot_player.min(1.0).max(-1.0).acos(); // clamp acos for safety + + // calculate angle of rotation with limit + let rotation_angle = rotation_sign * (config.rotation_speed * TIME_STEP).min(max_angle); + + // get the quaternion to rotate from the current enemy facing direction towards the + // direction facing the player + let rotation_delta = Quat::from_rotation_z(rotation_angle); + + // rotate the enemy to face the player + enemy_transform.rotation *= rotation_delta; + } +} diff --git a/examples/README.md b/examples/README.md index 7796afdb16223..860be2c658a4c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -90,6 +90,7 @@ Example | File | Description `text2d` | [`2d/text2d.rs`](./2d/text2d.rs) | Generates text in 2d `sprite_flipping` | [`2d/sprite_flipping.rs`](./2d/sprite_flipping.rs) | Renders a sprite flipped along an axis `texture_atlas` | [`2d/texture_atlas.rs`](./2d/texture_atlas.rs) | Generates a texture atlas (sprite sheet) from individual sprites +`rotation` | [`2d/rotation.rs`](./2d/rotation.rs) | Demonstrates rotating entities in 2D with quaternions ## 3D Rendering From d3442f658bf4eaf6b3951d787b81b414b8c1bcaa Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Mon, 29 Nov 2021 09:36:34 +1100 Subject: [PATCH 2/8] Switch min(1.0).max(-1.0) to clamp(-1.0, 1.0) Co-authored-by: Jerome Humbert --- examples/2d/rotation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/2d/rotation.rs b/examples/2d/rotation.rs index 0a6b49fb26be6..1ec6fbe221a3f 100644 --- a/examples/2d/rotation.rs +++ b/examples/2d/rotation.rs @@ -238,7 +238,7 @@ fn rotate_to_player_system( // limit rotation so we don't overshoot the target. We need to convert our dot product to // an angle here so we can get an angle of rotation to clamp against. - let max_angle = forward_dot_player.min(1.0).max(-1.0).acos(); // clamp acos for safety + let max_angle = forward_dot_player.clamp(-1.0, 1.0).acos(); // clamp acos for safety // calculate angle of rotation with limit let rotation_angle = rotation_sign * (config.rotation_speed * TIME_STEP).min(max_angle); From f73d50bc97e466b08bd3da5395540fff531160fc Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Mon, 29 Nov 2021 22:14:01 +1300 Subject: [PATCH 3/8] Absolute rotation to snap to enemy. Clarified some comments. --- examples/2d/rotation.rs | 52 +++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/examples/2d/rotation.rs b/examples/2d/rotation.rs index 1ec6fbe221a3f..a194c58262daa 100644 --- a/examples/2d/rotation.rs +++ b/examples/2d/rotation.rs @@ -42,24 +42,31 @@ struct RotateToPlayer { rotation_speed: f32, } +/// Add the game's entities to our world and creates an orthographic camera for 2D rendering. +/// +/// The Bevy coordinate system is the same for 2D and 3D, in terms of 2D this means that: +/// +/// * X axis goes from left to right (+X points right) +/// * Y axis goes from bottom to top (+Y point up) +/// * Z axis goes from far to near (+Z points towards you, out of the screen) +/// +/// The origin is at the center of the screen. fn setup( mut commands: Commands, mut materials: ResMut>, asset_server: Res, ) { - // Add the game's entities to our world - let ship_handle = asset_server.load("textures/simplespace/ship_C.png"); let enemy_a_handle = asset_server.load("textures/simplespace/enemy_A.png"); let enemy_b_handle = asset_server.load("textures/simplespace/enemy_B.png"); - // cameras + // 2D orthographic camera commands.spawn_bundle(OrthographicCameraBundle::new_2d()); let horizontal_margin = BOUNDS.x / 4.0; let vertical_margin = BOUNDS.y / 4.0; - // ship + // player controlled ship commands .spawn_bundle(SpriteBundle { material: materials.add(ship_handle.into()), @@ -70,7 +77,7 @@ fn setup( rotation_speed: f32::to_radians(360.0), // degrees per second }); - // snap to player enemy spawns on the bottom and left + // enemy that snaps to face the player spawns on the bottom and left commands .spawn_bundle(SpriteBundle { material: materials.add(enemy_a_handle.clone().into()), @@ -86,7 +93,7 @@ fn setup( }) .insert(SnapToPlayer); - // rotate to player enemy spawns on the top and right + // enemy that rotates to face the player enemy spawns on the top and right commands .spawn_bundle(SpriteBundle { material: materials.add(enemy_b_handle.clone().into()), @@ -129,7 +136,7 @@ fn player_movement_system( movement_factor += 1.0; } - // create the change in rotation around the Z axis (pointing through the 2d plane of the screen) + // create the change in rotation around the Z axis (perpendicular to the 2D plane of the screen) let rotation_delta = Quat::from_rotation_z(rotation_factor * ship.rotation_speed * TIME_STEP); // update the ship rotation with our rotation delta transform.rotation *= rotation_delta; @@ -154,24 +161,19 @@ fn snap_to_player_system( player_query: Query<&Transform, With>, ) { let player_transform = player_query.single(); - // get the player translation in 2d + // get the player translation in 2D let player_translation = player_transform.translation.xy(); for mut enemy_transform in query.iter_mut() { - // get the enemy ship forward vector in 2d (already unit length) - let enemy_forward = (enemy_transform.rotation * Vec3::Y).xy(); - // get the vector from the enemy ship to the player ship in 2d and normalize it. + // get the vector from the enemy ship to the player ship in 2D and normalize it. let to_player = (player_translation - enemy_transform.translation.xy()).normalize(); - // get the quaternion to rotate from the current enemy facing direction to the direction + // get the quaternion to rotate from the initial enemy facing direction to the direction // facing the player - let rotate_to_player = Quat::from_rotation_arc( - Vec3::from((enemy_forward, 0.0)), - Vec3::from((to_player, 0.0)), - ); + let rotate_to_player = Quat::from_rotation_arc(Vec3::Y, Vec3::from((to_player, 0.0))); // rotate the enemy to face the player - enemy_transform.rotation *= rotate_to_player; + enemy_transform.rotation = rotate_to_player; } } @@ -182,14 +184,14 @@ fn snap_to_player_system( /// will return a value between -1.0 and +1.0 which tells us the following about the two vectors: /// /// * If the result is 1.0 the vectors are pointing in the same direction, the angle between them -/// is 0 degrees. +/// is 0 degrees. /// * If the result is 0.0 the vectors are perpendicular, the angle between them is 90 degrees. /// * If the result is -1.0 the vectors are parallel but pointing in opposite directions, the angle -/// between them is 180 degrees. +/// between them is 180 degrees. /// * If the result is positive the vectors are pointing in roughly the same direction, the angle -/// between them is greater than 0 and less than 90 degrees. +/// between them is greater than 0 and less than 90 degrees. /// * If the result is negative the vectors are pointing in roughly opposite directions, the angle -/// between them is greater than 90 and less than 180 degrees. +/// between them is greater than 90 and less than 180 degrees. /// /// It is possible to get the angle by taking the arc cosine (`acos`) of the dot product. It is /// often unnecessary to do this though. Beware than `acos` will return `NaN` if the input is less @@ -201,14 +203,14 @@ fn rotate_to_player_system( player_query: Query<&Transform, With>, ) { let player_transform = player_query.single(); - // get the player translation in 2d + // get the player translation in 2D let player_translation = player_transform.translation.xy(); for (config, mut enemy_transform) in query.iter_mut() { - // get the enemy ship forward vector in 2d (already unit length) + // get the enemy ship forward vector in 2D (already unit length) let enemy_forward = (enemy_transform.rotation * Vec3::Y).xy(); - // get the vector from the enemy ship to the player ship in 2d and normalize it. + // get the vector from the enemy ship to the player ship in 2D and normalize it. let to_player = (player_translation - enemy_transform.translation.xy()).normalize(); // get the dot product between the enemy forward vector and the direction to the player. @@ -220,7 +222,7 @@ fn rotate_to_player_system( continue; } - // get the right vector of the enemy ship in 2d (already unit length) + // get the right vector of the enemy ship in 2D (already unit length) let enemy_right = (enemy_transform.rotation * Vec3::X).xy(); // get the dot product of the enemy right vector and the direction to the player ship. From fc40b11fb403da185e895a788fae44094936bfda Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Tue, 25 Jan 2022 23:15:58 +1300 Subject: [PATCH 4/8] Messed up previous merge. --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 785596f9333b5..9e0b659358b7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -123,6 +123,7 @@ path = "examples/2d/many_sprites.rs" name = "2d_rotation" path = "examples/2d/rotation.rs" +[[example]] name = "mesh2d" path = "examples/2d/mesh2d.rs" From c304302c1830eb876a2f99c72631d6b542f18ee5 Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Wed, 26 Jan 2022 00:04:53 +1300 Subject: [PATCH 5/8] Fixed compilation errors. --- examples/2d/rotation.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/2d/rotation.rs b/examples/2d/rotation.rs index a194c58262daa..481f5beb23fa1 100644 --- a/examples/2d/rotation.rs +++ b/examples/2d/rotation.rs @@ -53,7 +53,6 @@ struct RotateToPlayer { /// The origin is at the center of the screen. fn setup( mut commands: Commands, - mut materials: ResMut>, asset_server: Res, ) { let ship_handle = asset_server.load("textures/simplespace/ship_C.png"); @@ -69,7 +68,7 @@ fn setup( // player controlled ship commands .spawn_bundle(SpriteBundle { - material: materials.add(ship_handle.into()), + texture: ship_handle.into(), ..Default::default() }) .insert(Player { @@ -80,14 +79,14 @@ fn setup( // enemy that snaps to face the player spawns on the bottom and left commands .spawn_bundle(SpriteBundle { - material: materials.add(enemy_a_handle.clone().into()), + texture: enemy_a_handle.clone().into(), transform: Transform::from_xyz(0.0 - horizontal_margin, 0.0, 0.0), ..Default::default() }) .insert(SnapToPlayer); commands .spawn_bundle(SpriteBundle { - material: materials.add(enemy_a_handle.into()), + texture: enemy_a_handle.into(), transform: Transform::from_xyz(0.0, 0.0 - vertical_margin, 0.0), ..Default::default() }) @@ -96,7 +95,7 @@ fn setup( // enemy that rotates to face the player enemy spawns on the top and right commands .spawn_bundle(SpriteBundle { - material: materials.add(enemy_b_handle.clone().into()), + texture: enemy_b_handle.clone().into(), transform: Transform::from_xyz(0.0 + horizontal_margin, 0.0, 0.0), ..Default::default() }) @@ -105,7 +104,7 @@ fn setup( }); commands .spawn_bundle(SpriteBundle { - material: materials.add(enemy_b_handle.into()), + texture: enemy_b_handle.into(), transform: Transform::from_xyz(0.0, 0.0 + vertical_margin, 0.0), ..Default::default() }) From 74bf9485e75d5d34fba9f6d617ae3c788f9609f7 Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Wed, 26 Jan 2022 00:16:45 +1300 Subject: [PATCH 6/8] cargo fmt --- examples/2d/rotation.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/2d/rotation.rs b/examples/2d/rotation.rs index 481f5beb23fa1..0df5c340fc7a3 100644 --- a/examples/2d/rotation.rs +++ b/examples/2d/rotation.rs @@ -51,10 +51,7 @@ struct RotateToPlayer { /// * Z axis goes from far to near (+Z points towards you, out of the screen) /// /// The origin is at the center of the screen. -fn setup( - mut commands: Commands, - asset_server: Res, -) { +fn setup(mut commands: Commands, asset_server: Res) { let ship_handle = asset_server.load("textures/simplespace/ship_C.png"); let enemy_a_handle = asset_server.load("textures/simplespace/enemy_A.png"); let enemy_b_handle = asset_server.load("textures/simplespace/enemy_B.png"); From fc656a83bb40c49613d73b1cf3681d570b23dc8a Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Wed, 26 Jan 2022 10:20:13 +1300 Subject: [PATCH 7/8] Fixed lints. --- CREDITS.md | 3 ++- examples/2d/rotation.rs | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index 5b10c3f39122c..92d429212d838 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -20,4 +20,5 @@ * Cake from [Kenney's Food Kit](https://www.kenney.nl/assets/food-kit) (CC0 1.0 Universal) * Ground tile from [Kenney's Tower Defense Kit](https://www.kenney.nl/assets/tower-defense-kit) (CC0 1.0 Universal) * Game icons from [Kenney's Game Icons](https://www.kenney.nl/assets/game-icons) (CC0 1.0 Universal) -* Space ships from [Kenny's Simple Space Kit](https://www.kenney.nl/assets/simple-space) (CC0 1.0 Universal) \ No newline at end of file +* Space ships from [Kenny's Simple Space Kit](https://www.kenney.nl/assets/simple-space) (CC0 1.0 Universal) + diff --git a/examples/2d/rotation.rs b/examples/2d/rotation.rs index 0df5c340fc7a3..9ca891fd116c9 100644 --- a/examples/2d/rotation.rs +++ b/examples/2d/rotation.rs @@ -65,7 +65,7 @@ fn setup(mut commands: Commands, asset_server: Res) { // player controlled ship commands .spawn_bundle(SpriteBundle { - texture: ship_handle.into(), + texture: ship_handle, ..Default::default() }) .insert(Player { @@ -76,14 +76,14 @@ fn setup(mut commands: Commands, asset_server: Res) { // enemy that snaps to face the player spawns on the bottom and left commands .spawn_bundle(SpriteBundle { - texture: enemy_a_handle.clone().into(), + texture: enemy_a_handle.clone(), transform: Transform::from_xyz(0.0 - horizontal_margin, 0.0, 0.0), ..Default::default() }) .insert(SnapToPlayer); commands .spawn_bundle(SpriteBundle { - texture: enemy_a_handle.into(), + texture: enemy_a_handle, transform: Transform::from_xyz(0.0, 0.0 - vertical_margin, 0.0), ..Default::default() }) @@ -92,7 +92,7 @@ fn setup(mut commands: Commands, asset_server: Res) { // enemy that rotates to face the player enemy spawns on the top and right commands .spawn_bundle(SpriteBundle { - texture: enemy_b_handle.clone().into(), + texture: enemy_b_handle.clone(), transform: Transform::from_xyz(0.0 + horizontal_margin, 0.0, 0.0), ..Default::default() }) @@ -101,7 +101,7 @@ fn setup(mut commands: Commands, asset_server: Res) { }); commands .spawn_bundle(SpriteBundle { - texture: enemy_b_handle.into(), + texture: enemy_b_handle, transform: Transform::from_xyz(0.0, 0.0 + vertical_margin, 0.0), ..Default::default() }) From 801e4f628b65d77ad76ff679a059082f9fec90c9 Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Wed, 26 Jan 2022 11:01:12 +1300 Subject: [PATCH 8/8] Update CREDITS.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François --- CREDITS.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CREDITS.md b/CREDITS.md index 92d429212d838..da6c38d6a8ba1 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -21,4 +21,3 @@ * Ground tile from [Kenney's Tower Defense Kit](https://www.kenney.nl/assets/tower-defense-kit) (CC0 1.0 Universal) * Game icons from [Kenney's Game Icons](https://www.kenney.nl/assets/game-icons) (CC0 1.0 Universal) * Space ships from [Kenny's Simple Space Kit](https://www.kenney.nl/assets/simple-space) (CC0 1.0 Universal) -