Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

Commit

Permalink
Fix the rotation of airplanes
Browse files Browse the repository at this point in the history
When airplanes reached the end of their flight plan, some random nodes
were added to the plan to keep the airplane moving. When that happened,
however, the rotation of the airplane's sprite was not updated. This
resulted in airplanes moving sideways for a step in their flight plan,
before being rotated correctly during the next step.

To fix this, a new system has been introduced that checks the rotation
of each airplane on every frame. This can be optimized in the future to
occur only when the flight plan of an airplane is updated.
  • Loading branch information
jdno committed May 19, 2022
1 parent a32e0c8 commit 2de460f
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 25 deletions.
4 changes: 3 additions & 1 deletion game/src/scene/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use crate::rendering::FONT_COLOR;
use crate::resources::Score;
use crate::systems::{
despawn_airplane, detect_collision, follow_flight_plan, generate_flight_plan, land_airplane,
setup_airport, setup_grid, setup_landscape, spawn_airplane, update_flight_plan, SpawnTimer,
rotate_airplane, setup_airport, setup_grid, setup_landscape, spawn_airplane,
update_flight_plan, SpawnTimer,
};
use crate::AppState;

Expand All @@ -33,6 +34,7 @@ impl Plugin for GamePlugin {
.with_system(detect_collision)
.with_system(generate_flight_plan)
.with_system(land_airplane)
.with_system(rotate_airplane)
.with_system(spawn_airplane)
.with_system(update_flight_plan)
.with_system(update_score),
Expand Down
6 changes: 0 additions & 6 deletions game/src/systems/follow_flight_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,6 @@ pub fn follow_flight_plan(
.expect("failed to send event"); // TODO: Handle error

if did_update_flight_plan && !flight_plan.get().is_empty() {
let current_point = travelled_route.get().last().unwrap().as_point();
let next_point = flight_plan.next().unwrap().as_point(); // Safe due to check above

let direction = Direction::between(&next_point, &current_point);
transform.rotation = Quat::from_rotation_z(direction.to_degree().to_radians());

event_bus
.sender()
.send(Event::FlightPlanUpdated(
Expand Down
2 changes: 2 additions & 0 deletions game/src/systems/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub use self::detect_collisions::*;
pub use self::follow_flight_plan::*;
pub use self::generate_flight_plan::*;
pub use self::land_airplane::*;
pub use self::rotate_airplane::*;
pub use self::setup_airport::*;
pub use self::setup_cameras::*;
pub use self::setup_grid::*;
Expand All @@ -17,6 +18,7 @@ mod detect_collisions;
mod follow_flight_plan;
mod generate_flight_plan;
mod land_airplane;
mod rotate_airplane;
mod setup_airport;
mod setup_cameras;
mod setup_grid;
Expand Down
22 changes: 22 additions & 0 deletions game/src/systems/rotate_airplane.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use bevy::prelude::*;

use crate::components::{FlightPlan, TravelledRoute};
use crate::map::Direction;

pub fn rotate_airplane(mut query: Query<(&mut FlightPlan, &mut Transform, &mut TravelledRoute)>) {
for (flight_plan, mut transform, travelled_route) in query.iter_mut() {
let last_point = travelled_route
.get()
.last()
.expect("travelled route must not be empty")
.as_point();

let next_point = match flight_plan.next() {
Some(node) => node.as_point(),
None => continue,
};

let direction = Direction::between(&next_point, &last_point);
transform.rotation = Quat::from_rotation_z(direction.to_degree().to_radians());
}
}
35 changes: 17 additions & 18 deletions game/src/systems/spawn_airplane.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use bevy::prelude::*;
use geo::point;
use rand::{thread_rng, Rng};

use crate::components::{
Expand All @@ -8,7 +7,9 @@ use crate::components::{
use crate::event::{Event, EventBus};
use crate::map::{Direction, Node, MAP_HEIGHT_RANGE, MAP_WIDTH_RANGE};
use crate::rendering::RenderLayer;
use crate::TILE_SIZE;

// Planes are spawned this many nodes outside the map area
const SPAWN_OFFSET: i32 = 3;

pub struct SpawnTimer(Timer);

Expand All @@ -34,13 +35,14 @@ pub fn spawn_airplane(
let texture_atlas_handle = texture_atlases.add(texture_atlas);

if timer.0.tick(time.delta()).just_finished() {
let (spawn, entry) = random_spawn();
let spawn_point = point!(x: spawn.x, y: spawn.y);
let (spawn, first_node) = random_spawn();
let spawn_point = spawn.as_point();

let airplane_id = airplane_id_generator.generate();
let flight_plan = FlightPlan::new(vec![entry]);
let travelled_route = TravelledRoute::new(vec![spawn]);
let flight_plan = FlightPlan::new(vec![first_node]);

let direction = Direction::between(&entry.as_point(), &spawn_point);
let direction = Direction::between(&first_node.as_point(), &spawn_point);

let tag = if rng.gen_bool(0.5) {
Tag::Blue
Expand Down Expand Up @@ -78,7 +80,7 @@ pub fn spawn_airplane(
.insert(flight_plan.clone())
.insert(Speed::new(32.0))
.insert(tag)
.insert(TravelledRoute::new(Vec::new()));
.insert(travelled_route);

event_bus
.sender()
Expand All @@ -92,42 +94,39 @@ pub fn spawn_airplane(
}
}

fn random_spawn() -> (Vec3, Node) {
let mut rng = rand::thread_rng();
fn random_spawn() -> (Node, Node) {
let mut rng = thread_rng();

let (entry, direction) = match rng.gen_range(0u32..4u32) {
let (first_node, spawn) = match rng.gen_range(0u32..4u32) {
0 => {
let x = rng.gen_range(MAP_WIDTH_RANGE);
(
Node::unrestricted(x, *MAP_HEIGHT_RANGE.end()),
Direction::South,
Node::unrestricted(x, *MAP_HEIGHT_RANGE.end() + SPAWN_OFFSET),
)
}
1 => {
let y = rng.gen_range(MAP_HEIGHT_RANGE);
(
Node::unrestricted(*MAP_WIDTH_RANGE.end(), y),
Direction::West,
Node::unrestricted(*MAP_WIDTH_RANGE.end() + SPAWN_OFFSET, y),
)
}
2 => {
let x = rng.gen_range(MAP_WIDTH_RANGE);
(
Node::unrestricted(x, *MAP_HEIGHT_RANGE.start()),
Direction::North,
Node::unrestricted(x, *MAP_HEIGHT_RANGE.start() - SPAWN_OFFSET),
)
}
_ => {
let y = rng.gen_range(MAP_HEIGHT_RANGE);
(
Node::unrestricted(*MAP_WIDTH_RANGE.start(), y),
Direction::East,
Node::unrestricted(*MAP_WIDTH_RANGE.start() - SPAWN_OFFSET, y),
)
}
};

let offset = direction.to_vec3() * Vec3::splat(-3.0 * TILE_SIZE as f32);
let spawn = entry.as_vec3(RenderLayer::Airplane.z()) + offset;

(spawn, entry)
(spawn, first_node)
}

0 comments on commit 2de460f

Please sign in to comment.