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

Add tags to airplanes and airports #44

Merged
merged 5 commits into from
Mar 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/atc/v1/airplane.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ syntax = "proto3";
package atc.v1;

import "atc/v1/map.proto";
import "atc/v1/tag.proto";

message Airplane {
string id = 1;
Point point = 2;
repeated Node flight_plan = 3;
Tag tag = 4;
}

message GetAirplaneRequest {
Expand Down
9 changes: 7 additions & 2 deletions api/atc/v1/event.proto
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ message FlightPlanUpdated {
repeated Node flight_plan = 2;
}

message LandingAborted {
string id = 1;
}

message GameStarted {
Map map = 1;
}
Expand All @@ -45,8 +49,9 @@ message StreamResponse {
AirplaneLanded airplane_landed = 3;
AirplaneMoved airplane_moved = 4;
FlightPlanUpdated flight_plan_updated = 5;
GameStarted game_started = 6;
GameStopped game_stopped = 7;
LandingAborted landing_aborted = 6;
GameStarted game_started = 7;
GameStopped game_stopped = 8;
}
}

Expand Down
5 changes: 4 additions & 1 deletion game/src/api/airplane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ mod tests {
use crate::api::airplane::AirplaneService;
use crate::api::AsApi;
use crate::command::CommandReceiver;
use crate::components::{AirplaneId, FlightPlan, Location};
use crate::components::{AirplaneId, FlightPlan, Location, Tag};
use crate::map::{Node, MAP_HEIGHT_RANGE, MAP_WIDTH_RANGE};
use crate::{Command, Store};

Expand All @@ -132,6 +132,7 @@ mod tests {
id: id.as_api(),
point: Some(location.as_api()),
flight_plan: flight_plan.as_api(),
tag: Tag::Red.as_api().into(),
};

store.airplanes().insert("AT-4321".into(), airplane);
Expand Down Expand Up @@ -225,6 +226,7 @@ mod tests {
id: id.as_api(),
point: Some(location.as_api()),
flight_plan: flight_plan.as_api(),
tag: Tag::Red.as_api().into(),
};

store.airplanes().insert("AT-4321".into(), airplane);
Expand All @@ -250,6 +252,7 @@ mod tests {
id: id.as_api(),
point: Some(location.as_api()),
flight_plan: flight_plan.as_api(),
tag: Tag::Red.as_api().into(),
};

store.airplanes().insert("AT-4321".into(), airplane);
Expand Down
2 changes: 2 additions & 0 deletions game/src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub use self::flight_plan::*;
pub use self::landing::*;
pub use self::location::*;
pub use self::speed::*;
pub use self::tag::*;
pub use self::travelled_route::*;

mod airplane;
Expand All @@ -14,4 +15,5 @@ mod flight_plan;
mod landing;
mod location;
mod speed;
mod tag;
mod travelled_route;
37 changes: 37 additions & 0 deletions game/src/components/tag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use bevy::prelude::*;

use atc::v1::Tag as ApiTag;

use crate::api::AsApi;

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Component)]
pub enum Tag {
Red,
}

impl AsApi for Tag {
type ApiType = ApiTag;

fn as_api(&self) -> Self::ApiType {
match self {
Tag::Red => ApiTag::Red,
}
}
}

#[cfg(test)]
mod tests {
use super::Tag;

#[test]
fn trait_send() {
fn assert_send<T: Send>() {}
assert_send::<Tag>();
}

#[test]
fn trait_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Tag>();
}
}
13 changes: 9 additions & 4 deletions game/src/event/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use atc::v1::stream_response::Event as ApiEvent;
use atc::v1::{
Airplane, AirplaneCollided, AirplaneDetected, AirplaneLanded, AirplaneMoved, FlightPlanUpdated,
GameStarted, GameStopped,
GameStarted, GameStopped, LandingAborted,
};

use crate::api::AsApi;
use crate::components::{AirplaneId, FlightPlan, Location};
use crate::components::{AirplaneId, FlightPlan, Location, Tag};
use crate::map::Map;
use crate::resources::Score;

Expand All @@ -16,10 +16,11 @@ mod bus;
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub enum Event {
AirplaneCollided(AirplaneId, AirplaneId),
AirplaneDetected(AirplaneId, Location, FlightPlan),
AirplaneDetected(AirplaneId, Location, FlightPlan, Tag),
AirplaneLanded(AirplaneId),
AirplaneMoved(AirplaneId, Location),
FlightPlanUpdated(AirplaneId, FlightPlan),
LandingAborted(AirplaneId),
GameStarted(Map),
GameStopped(Score),
}
Expand All @@ -35,12 +36,13 @@ impl AsApi for Event {
id2: airplane_id2.as_api(),
})
}
Event::AirplaneDetected(id, location, flight_plan) => {
Event::AirplaneDetected(id, location, flight_plan, tag) => {
ApiEvent::AirplaneDetected(AirplaneDetected {
airplane: Some(Airplane {
id: id.as_api(),
point: Some(location.as_api()),
flight_plan: flight_plan.as_api(),
tag: tag.as_api().into(),
}),
})
}
Expand All @@ -57,6 +59,9 @@ impl AsApi for Event {
flight_plan: flight_plan.as_api(),
})
}
Event::LandingAborted(id) => {
ApiEvent::LandingAborted(LandingAborted { id: id.as_api() })
}
Event::GameStarted(map) => ApiEvent::GameStarted(GameStarted {
map: Some(map.as_api()),
}),
Expand Down
18 changes: 12 additions & 6 deletions game/src/map/airport.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
use atc::v1::{Airport as ApiAirport, Tag};
use atc::v1::Airport as ApiAirport;

use crate::api::AsApi;
use crate::map::Node;
use crate::components::Tag;
use crate::map::{Direction, Node};

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Airport {
node: Node,
runway: Direction,
tag: Tag,
}

impl Airport {
pub fn new(node: Node, tag: Tag) -> Self {
Self { node, tag }
pub fn new(node: Node, runway: Direction, tag: Tag) -> Self {
Self { node, runway, tag }
}

pub fn node(&self) -> &Node {
&self.node
}

pub fn runway(&self) -> Direction {
self.runway
}

#[allow(dead_code)] // TODO: Remove when tags are introduced to flight plans
pub fn tag(&self) -> Tag {
self.tag
Expand All @@ -30,7 +36,7 @@ impl AsApi for Airport {
fn as_api(&self) -> Self::ApiType {
ApiAirport {
node: Some(self.node.as_api()),
tag: self.tag.into(),
tag: self.tag.as_api().into(),
}
}
}
Expand Down
9 changes: 4 additions & 5 deletions game/src/map/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::ops::RangeInclusive;

use atc::v1::{Map as ApiMap, Tag};
use atc::v1::Map as ApiMap;

use crate::api::AsApi;
use crate::components::Tag;
use crate::{SCREEN_HEIGHT, SCREEN_WIDTH, TILE_SIZE};

pub use self::airport::*;
Expand Down Expand Up @@ -52,7 +53,7 @@ impl Map {

impl Default for Map {
fn default() -> Self {
let airport = Airport::new(Node::new(0, 0), Tag::Red);
let airport = Airport::new(Node::new(0, 0), Direction::West, Tag::Red);
let routing_grid = generate_routing_grid(&airport);

Self {
Expand All @@ -74,8 +75,6 @@ impl AsApi for Map {
}

fn generate_routing_grid(airport: &Airport) -> Vec<Node> {
let direction_of_runway = Direction::West;

let airport_node = airport.node();
let mut nodes = Vec::with_capacity(MAP_WIDTH * MAP_HEIGHT - 7);

Expand All @@ -87,7 +86,7 @@ fn generate_routing_grid(airport: &Airport) -> Vec<Node> {

if airport_node != &node
&& airport_node.is_neighbor(&node)
&& direction_to_airport != direction_of_runway
&& direction_to_airport != airport.runway()
{
continue;
}
Expand Down
15 changes: 11 additions & 4 deletions game/src/store/watcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use atc::v1::get_game_state_response::GameState;
use atc::v1::Airplane;

use crate::api::AsApi;
use crate::components::{AirplaneId, FlightPlan, Location};
use crate::components::{AirplaneId, FlightPlan, Location, Tag};
use crate::event::EventReceiver;
use crate::map::Map;
use crate::{Event, Store};
Expand All @@ -23,8 +23,8 @@ impl StoreWatcher {
pub async fn connect(&mut self) {
while let Ok(event) = self.event_bus.recv().await {
match event {
Event::AirplaneDetected(id, location, flight_plan) => {
self.insert_airplane(id, location, flight_plan)
Event::AirplaneDetected(id, location, flight_plan, tag) => {
self.insert_airplane(id, location, flight_plan, tag)
}
Event::AirplaneLanded(id) => self.remove_airplane(id),
Event::AirplaneMoved(id, location) => self.move_airplane(id, location),
Expand All @@ -38,13 +38,20 @@ impl StoreWatcher {
}
}

fn insert_airplane(&self, id: AirplaneId, location: Location, flight_plan: FlightPlan) {
fn insert_airplane(
&self,
id: AirplaneId,
location: Location,
flight_plan: FlightPlan,
tag: Tag,
) {
self.store.airplanes().insert(
id.get().into(),
Airplane {
id: id.as_api(),
point: Some(location.as_api()),
flight_plan: flight_plan.as_api(),
tag: tag.as_api().into(),
},
);
}
Expand Down
48 changes: 42 additions & 6 deletions game/src/systems/despawn_airplane.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
use bevy::prelude::*;

use crate::components::{AirplaneId, Landing};
use crate::components::{AirplaneId, FlightPlan, Landing, Tag};
use crate::event::{Event, EventBus};
use crate::map::Map;
use crate::map::{Airport, Map, Node};
use crate::resources::Score;

pub fn despawn_airplane(
mut commands: Commands,
map: Res<Map>,
mut score: ResMut<Score>,
query: Query<(Entity, &AirplaneId, &Transform), With<Landing>>,
mut query: Query<(Entity, &AirplaneId, &mut FlightPlan, &Tag, &Transform), With<Landing>>,
event_bus: Local<EventBus>,
) {
let airport = map.airport().node().as_vec3(2.0);
let airport_location = map.airport().node().as_vec3(2.0);
let airport_tag = map.airport().tag();

for (entity, airplane_id, transform) in query.iter() {
if transform.translation == airport {
for (entity, airplane_id, mut flight_plan, tag, transform) in query.iter_mut() {
let airplane_location = transform.translation;

if airplane_location != airport_location {
continue;
}

if tag == &airport_tag {
commands.entity(entity).despawn_recursive();

score.increment();
Expand All @@ -24,6 +31,35 @@ pub fn despawn_airplane(
.sender()
.send(Event::AirplaneLanded(airplane_id.clone()))
.expect("failed to send event"); // TODO: Handle error
} else {
let go_around = go_around_procedure(map.airport());

*flight_plan = FlightPlan::new(vec![go_around]);

commands.entity(entity).remove::<Landing>();

event_bus
.sender()
.send(Event::LandingAborted(airplane_id.clone()))
.expect("failed to send event"); // TODO: Handle error

event_bus
.sender()
.send(Event::FlightPlanUpdated(
airplane_id.clone(),
flight_plan.clone(),
))
.expect("failed to send event"); // TODO: Handle error
}
}
}

fn go_around_procedure(airport: &Airport) -> Node {
let runway_direction = airport.runway().to_vec3();
let next_hop_in_direction = runway_direction * Vec3::splat(-2.0);

Node::new(
next_hop_in_direction.x as i32,
next_hop_in_direction.y as i32,
)
}
4 changes: 3 additions & 1 deletion game/src/systems/spawn_airplane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use bevy::prelude::*;
use rand::Rng;

use crate::components::{
Airplane, AirplaneIdGenerator, Collider, Location, Speed, TravelledRoute, AIRPLANE_SIZE,
Airplane, AirplaneIdGenerator, Collider, Location, Speed, Tag, TravelledRoute, AIRPLANE_SIZE,
};
use crate::map::{Map, Node, MAP_HEIGHT_RANGE, MAP_WIDTH_RANGE};
use crate::{generate_random_plan, Event, EventBus};
Expand Down Expand Up @@ -50,6 +50,7 @@ pub fn spawn_airplane(
.insert(Collider)
.insert(flight_plan.clone())
.insert(Speed::new(32.0))
.insert(Tag::Red)
.insert(travelled_route);

event_bus
Expand All @@ -58,6 +59,7 @@ pub fn spawn_airplane(
airplane_id,
Location::from(&spawn),
flight_plan,
Tag::Red,
))
.expect("failed to send event"); // TODO: Handle error
}
Expand Down
Loading