aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/client.rs45
-rw-r--r--src/main.rs5
-rw-r--r--src/protocol.rs8
-rw-r--r--src/server.rs95
-rw-r--r--src/shared.rs4
-rw-r--r--src/shared/champion.rs39
-rw-r--r--src/shared/projectile.rs2
-rw-r--r--src/shared/stats.rs16
8 files changed, 169 insertions, 45 deletions
diff --git a/src/client.rs b/src/client.rs
index 174d615..fff18af 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -1,5 +1,6 @@
use crate::client::network::*;
use crate::protocol::*;
+use crate::shared::champion::*;
use crate::shared::health::*;
use crate::shared::imperative::*;
use crate::shared::projectile::*;
@@ -17,13 +18,19 @@ const PLAYER_RADIUS: f32 = 10.;
const PLAYER_HOVER_INDICATOR_RADIUS: f32 = 13.;
const PLAYER_HOVER_RADIUS: f32 = 20.;
-pub fn main(server_addr: Option<SocketAddr>, client_id: u64, transport: TransportConfig) {
+pub fn main(
+ server_addr: Option<SocketAddr>,
+ client_id: u64,
+ transport: TransportConfig,
+ champion: Champion,
+) {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(ClientPlugin {
server_addr,
client_id,
transport,
+ champion,
})
.run();
}
@@ -31,15 +38,20 @@ pub fn main(server_addr: Option<SocketAddr>, client_id: u64, transport: Transpor
#[derive(Resource)]
struct ClientId(pub u64);
+#[derive(Resource)]
+struct MyChampion(pub Champion);
+
struct ClientPlugin {
pub server_addr: Option<SocketAddr>,
pub client_id: u64,
pub transport: TransportConfig,
+ pub champion: Champion,
}
impl Plugin for ClientPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(ClientId(self.client_id))
+ .insert_resource(MyChampion(self.champion))
.add_plugins(NetworkPlugin {
server_addr: self.server_addr.clone(),
client_id: self.client_id,
@@ -63,9 +75,12 @@ impl Plugin for ClientPlugin {
}
}
-fn setup(mut client: ClientMut, mut commands: Commands) {
+fn setup(mut client: ClientMut, mut commands: Commands, champion: Res<MyChampion>) {
commands.spawn(Camera2dBundle::default());
client.connect().unwrap();
+ client
+ .send_message::<Channel1, SelectChampion>(SelectChampion(champion.0))
+ .unwrap();
}
fn render_players(
@@ -200,14 +215,22 @@ fn gizmos_attack_indicator(
client_id: Res<ClientId>,
hoverables: Query<(&PlayerId, &PlayerPosition)>,
mut gizmos: Gizmos,
- players: Query<(&PlayerId, &PlayerPosition)>,
+ player_positions: Query<(&PlayerId, &PlayerPosition)>,
+ player_champions: Query<(&PlayerId, &Champion)>,
windows: Query<&Window>,
) {
- let Some(position) = player_position(&client_id, &players) else {
+ let Some(position) = player_position(&client_id, &player_positions) else {
+ return;
+ };
+ let Some(champion) = player_champion(&client_id, &player_champions) else {
return;
};
if hovered_other_player(&cameras, &client_id, &hoverables, &windows).is_some() {
- gizmos.circle_2d(position.0, ATTACK_RANGE, Color::YELLOW);
+ gizmos.circle_2d(
+ position.0,
+ Stats::from_champion(champion).attack_range,
+ Color::YELLOW,
+ );
}
}
@@ -223,6 +246,18 @@ fn player_position(
None
}
+fn player_champion(
+ client_id: &Res<ClientId>,
+ players: &Query<(&PlayerId, &Champion)>,
+) -> Option<Champion> {
+ for (id, champion) in players.iter() {
+ if id.0 == client_id.0 {
+ return Some(*champion);
+ }
+ }
+ None
+}
+
const HEALTH_OFFSET: f32 = 4.;
fn render_health(players: Query<(&Health, &PlayerPosition)>, mut gizmos: Gizmos) {
diff --git a/src/main.rs b/src/main.rs
index b615ddc..2326310 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,4 @@
+use crate::shared::champion::*;
use clap::Parser;
use lightyear::transport::io::TransportConfig;
use rand::Rng;
@@ -17,6 +18,8 @@ struct Cli {
connect_to: Option<SocketAddr>,
#[arg(long, num_args = 0)]
server: bool,
+ #[arg(long, default_value = "meele")]
+ champion: Champion,
}
fn main() {
@@ -38,6 +41,7 @@ fn main() {
Some(server_addr),
client_id as u64,
TransportConfig::UdpSocket(client_addr),
+ cli.champion,
);
} else {
let (from_server_send, from_server_recv) = crossbeam_channel::unbounded();
@@ -57,6 +61,7 @@ fn main() {
recv: from_server_recv,
send: to_server_send,
},
+ cli.champion,
);
}
}
diff --git a/src/protocol.rs b/src/protocol.rs
index 3d4567d..7ec3dcb 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -1,3 +1,4 @@
+use crate::shared::champion::*;
use crate::shared::cooldown::*;
use crate::shared::health::*;
use crate::shared::imperative::*;
@@ -16,11 +17,11 @@ pub enum Inputs {
impl UserAction for Inputs {}
#[derive(Message, Serialize, Deserialize, Clone, Debug, PartialEq)]
-pub struct Message1(pub usize);
+pub struct SelectChampion(pub Champion);
#[message_protocol(protocol = "MyProtocol")]
pub enum Messages {
- Message1(Message1),
+ SelectChampion(SelectChampion),
}
#[component_protocol(protocol = "MyProtocol")]
@@ -33,10 +34,11 @@ pub enum Components {
ProjectilePosition(ProjectilePosition),
Cooldown(Cooldown),
Health(Health),
+ Champion(Champion),
}
#[derive(Channel)]
-struct Channel1;
+pub struct Channel1;
protocolize! {
Self = MyProtocol,
diff --git a/src/server.rs b/src/server.rs
index fab529f..1b9b7ef 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -1,5 +1,6 @@
use crate::protocol::*;
use crate::server::network::*;
+use crate::shared::champion::*;
use crate::shared::cooldown::*;
use crate::shared::health::*;
use crate::shared::imperative::*;
@@ -9,6 +10,7 @@ use bevy::prelude::*;
use bevy::utils::Duration;
use bevy::utils::HashMap;
use lightyear::prelude::*;
+use lightyear::server::events::MessageEvent;
use rand::Rng;
mod network;
@@ -47,6 +49,7 @@ impl Plugin for ServerPlugin {
})
.add_systems(Startup, setup)
.add_systems(Update, (connects, disconnects))
+ .add_systems(Update, receive_message)
.add_systems(Update, timers_ticket)
.add_systems(Update, health_regen.after(timers_ticket))
.add_systems(
@@ -94,6 +97,21 @@ fn connects(
}
}
+fn receive_message(
+ entity_map: Res<EntityMap>,
+ mut commands: Commands,
+ mut reader: EventReader<MessageEvent<SelectChampion>>,
+) {
+ for event in reader.read() {
+ let client_id = event.context();
+ let SelectChampion(champion) = event.message();
+ let Some(entity) = entity_map.0.get(client_id) else {
+ return;
+ };
+ commands.entity(*entity).insert(*champion);
+ }
+}
+
fn disconnects(
mut commands: Commands,
mut disconnects: EventReader<server::DisconnectEvent>,
@@ -175,47 +193,54 @@ fn imperative_attack(
mut cooldowns: Query<&mut Cooldown>,
mut players: Query<(&PlayerId, &mut Imperative)>,
mut positions: Query<&mut PlayerPosition>,
+ champions: Query<&Champion>,
time: Res<Time>,
) {
for (id, mut imperative) in players.iter_mut() {
match *imperative {
Imperative::Attack(target_player) => {
- if let Some(entity) = entity_map.0.get(&id.0) {
- if let Some(target_entity) = entity_map.0.get(&target_player.0) {
- if let Ok([mut position, target_position]) =
- positions.get_many_mut([*entity, *target_entity])
- {
- let distance = target_position.0.distance(position.0);
- if distance > ATTACK_RANGE {
- let (new_position, _) = move_to_target(
- position.0,
- target_position.0,
- MOVEMENT_SPEED * time.delta().as_secs_f32(),
- );
- position.0 = new_position;
- } else {
- if let Ok(mut cooldown) = cooldowns.get_mut(*entity) {
- if cooldown.a_cooldown.is_zero() {
- cooldown.a_cooldown = Duration::from_secs_f32(1.5);
- commands.spawn(ProjectileBundle {
- projectile: Projectile {
- target_player,
- source_player: *id,
- damage: 4.,
- },
- position: ProjectilePosition(position.0),
- replicate: Replicate::default(),
- });
- }
- } else {
- }
- *imperative = Imperative::Idle;
- }
- } else {
- *imperative = Imperative::Idle;
- }
- } else {
+ let Some(entity) = entity_map.0.get(&id.0) else {
+ *imperative = Imperative::Idle;
+ return;
+ };
+ let Ok(champion) = champions.get(*entity) else {
+ *imperative = Imperative::Idle;
+ return;
+ };
+ let Some(target_entity) = entity_map.0.get(&target_player.0) else {
+ *imperative = Imperative::Idle;
+ return;
+ };
+ let Ok([mut position, target_position]) =
+ positions.get_many_mut([*entity, *target_entity])
+ else {
+ *imperative = Imperative::Idle;
+ return;
+ };
+ let distance = target_position.0.distance(position.0);
+ if distance > Stats::from_champion(*champion).attack_range {
+ let (new_position, _) = move_to_target(
+ position.0,
+ target_position.0,
+ MOVEMENT_SPEED * time.delta().as_secs_f32(),
+ );
+ position.0 = new_position;
+ } else {
+ let Ok(mut cooldown) = cooldowns.get_mut(*entity) else {
*imperative = Imperative::Idle;
+ return;
+ };
+ if cooldown.a_cooldown.is_zero() {
+ cooldown.a_cooldown = Duration::from_secs_f32(1.5);
+ commands.spawn(ProjectileBundle {
+ projectile: Projectile {
+ target_player,
+ source_player: *id,
+ damage: 4.,
+ },
+ position: ProjectilePosition(position.0),
+ replicate: Replicate::default(),
+ });
}
}
}
diff --git a/src/shared.rs b/src/shared.rs
index 92b6a5b..16cea60 100644
--- a/src/shared.rs
+++ b/src/shared.rs
@@ -1,4 +1,5 @@
use crate::protocol::Replicate;
+use crate::shared::champion::*;
use crate::shared::cooldown::*;
use crate::shared::health::*;
use crate::shared::imperative::*;
@@ -8,6 +9,7 @@ use serde::Deserialize;
use serde::Serialize;
use std::default::Default;
+pub mod champion;
pub mod cooldown;
pub mod health;
pub mod imperative;
@@ -28,6 +30,7 @@ pub struct PlayerBundle {
imperative: Imperative,
cooldown: Cooldown,
health: Health,
+ champion: Champion,
}
#[derive(Component, Message, Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
@@ -49,6 +52,7 @@ impl PlayerBundle {
imperative: Imperative::Idle,
cooldown: Cooldown::default(),
health: Health::default(),
+ champion: Champion::default(),
}
}
}
diff --git a/src/shared/champion.rs b/src/shared/champion.rs
new file mode 100644
index 0000000..ec27c62
--- /dev/null
+++ b/src/shared/champion.rs
@@ -0,0 +1,39 @@
+use crate::shared::*;
+use std::str::FromStr;
+
+#[derive(Component, Message, Clone, Copy, Serialize, Deserialize, PartialEq, Debug)]
+pub enum Champion {
+ Meele,
+ Ranged,
+}
+
+impl Default for Champion {
+ fn default() -> Champion {
+ Champion::Meele
+ }
+}
+
+impl FromStr for Champion {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Champion, String> {
+ match s {
+ "ranged" => Ok(Champion::Ranged),
+ "meele" => Ok(Champion::Meele),
+ _ => Err(format!("unknown champion: {}", s)),
+ }
+ }
+}
+
+pub struct Stats {
+ pub attack_range: f32,
+}
+
+impl Stats {
+ pub fn from_champion(champion: Champion) -> Self {
+ match champion {
+ Champion::Meele => Stats { attack_range: 25. },
+ Champion::Ranged => Stats { attack_range: 60. },
+ }
+ }
+}
diff --git a/src/shared/projectile.rs b/src/shared/projectile.rs
index c42173a..2e9c6c3 100644
--- a/src/shared/projectile.rs
+++ b/src/shared/projectile.rs
@@ -1,7 +1,5 @@
use crate::shared::*;
-pub const ATTACK_RANGE: f32 = 60.;
-
#[derive(Bundle)]
pub struct ProjectileBundle {
pub projectile: Projectile,
diff --git a/src/shared/stats.rs b/src/shared/stats.rs
new file mode 100644
index 0000000..278a19f
--- /dev/null
+++ b/src/shared/stats.rs
@@ -0,0 +1,16 @@
+use crate::shared::champion::*;
+use crate::shared::*;
+
+#[derive(Component, Message, Clone, Serialize, Deserialize, PartialEq)]
+pub struct Stats {
+ pub attack_range: f32,
+}
+
+impl Stats {
+ pub fn from_champion(champion: Champion) -> Self {
+ match champion {
+ Champion::Meele => Stats { attack_range: 35. },
+ Champion::Ranged => Stats { attack_range: 60. },
+ }
+ }
+}