aboutsummaryrefslogtreecommitdiffstats
path: root/src/client.rs
diff options
context:
space:
mode:
authorLibravatar Alexander Foremny <aforemny@posteo.de>2024-03-17 16:32:22 +0100
committerLibravatar Alexander Foremny <aforemny@posteo.de>2024-03-17 16:32:22 +0100
commit312aa627052c24e0aa1948e584c046bc15f18c96 (patch)
treeff74e110ae4481979352962985e75fb5ae99dfe9 /src/client.rs
parente228208de62f8abf1744f389271168d996a10b25 (diff)
feat: add damage indicators
Diffstat (limited to 'src/client.rs')
-rw-r--r--src/client.rs108
1 files changed, 108 insertions, 0 deletions
diff --git a/src/client.rs b/src/client.rs
index 1805cae..8220047 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -4,6 +4,7 @@ use crate::shared::ability::*;
use crate::shared::champion::*;
use crate::shared::cooldown::*;
use crate::shared::health::*;
+use crate::shared::health_event::*;
use crate::shared::imperative::*;
use crate::shared::projectile::*;
use crate::shared::*;
@@ -11,6 +12,7 @@ use bevy::input::keyboard::*;
use bevy::input::mouse::MouseButton;
use bevy::prelude::*;
use bevy::sprite::{MaterialMesh2dBundle, Mesh2dHandle};
+use lightyear::client::events::*;
use lightyear::client::input::InputSystemSet;
use lightyear::prelude::*;
use std::net::SocketAddr;
@@ -79,6 +81,13 @@ impl Plugin for ClientPlugin {
(
(hotbar_hotbar_display, hotbar_hotbar_highlight),
hotbar_cooldown,
+ (
+ health_indicator_despawn,
+ health_indicator_tick,
+ health_indicator_move_up,
+ health_indicator_spawn,
+ )
+ .chain(),
),
)
.add_systems(
@@ -355,6 +364,11 @@ fn cursor_world_position(
camera.viewport_to_world_2d(camera_transform, cursor_position)
}
+fn world_to_viewport(cameras: &Query<(&Camera, &GlobalTransform)>, position: Vec2) -> Option<Vec2> {
+ let (camera, camera_transform) = cameras.single();
+ camera.world_to_viewport(camera_transform, Vec3::new(position.x, position.y, 0.))
+}
+
fn hovered_other_player(
cameras: &Query<(&Camera, &GlobalTransform)>,
client_id: &Res<ClientId>,
@@ -550,3 +564,97 @@ fn hotbar_hotbar_highlight(attack: Res<Attack>, mut hotbars: Query<(&Hotbar, &mu
}
}
}
+
+#[derive(Component)]
+pub struct HealthIndicator {
+ position: Vec2,
+ timer: Timer,
+}
+
+fn health_indicator_spawn(
+ cameras: Query<(&Camera, &GlobalTransform)>,
+ mut commands: Commands,
+ mut event_reader: EventReader<MessageEvent<HealthChanged>>,
+ players: Query<(&PlayerId, &PlayerPosition)>,
+) {
+ for event in event_reader.read() {
+ let HealthChanged(HealthEvent {
+ target_player,
+ health_gained,
+ }) = event.message();
+ let Some(position) = any_player_position(*target_player, &players) else {
+ continue;
+ };
+ let health_gained_or_lost = health_gained.abs();
+ let Some(mut screen_position) = world_to_viewport(&cameras, position.0) else {
+ continue;
+ };
+ screen_position += Vec2::new(12.5, -12.5);
+ commands.spawn((
+ TextBundle::from_section(
+ format!("{health_gained_or_lost}"),
+ TextStyle {
+ font_size: 6.,
+ color: Color::RED,
+ ..Default::default()
+ },
+ )
+ .with_style(Style {
+ position_type: PositionType::Absolute,
+ top: Val::Px(screen_position.y),
+ left: Val::Px(screen_position.x),
+ ..Default::default()
+ }),
+ HealthIndicator {
+ position: position.0,
+ timer: Timer::from_seconds(1., TimerMode::Once),
+ },
+ ));
+ }
+}
+
+fn any_player_position(
+ player_id: PlayerId,
+ players: &Query<(&PlayerId, &PlayerPosition)>,
+) -> Option<PlayerPosition> {
+ for (id, position) in players.iter() {
+ if *id == player_id {
+ return Some(*position);
+ }
+ }
+ None
+}
+
+fn health_indicator_move_up(
+ cameras: Query<(&Camera, &GlobalTransform)>,
+ mut health_indicators: Query<(&mut Style, &HealthIndicator)>,
+) {
+ for (mut style, health_indicator) in health_indicators.iter_mut() {
+ let Some(mut screen_position) = world_to_viewport(&cameras, health_indicator.position)
+ else {
+ continue;
+ };
+ screen_position += Vec2::new(12.5, -12.5);
+ let s = health_indicator.timer.fraction();
+ style.top = Val::Px((1. - s) * screen_position.y + s * (screen_position.y - 20.));
+ style.left = Val::Px(screen_position.x);
+ }
+}
+
+fn health_indicator_tick(mut health_indicators: Query<&mut HealthIndicator>, time: Res<Time>) {
+ for mut health_indicator in health_indicators.iter_mut() {
+ health_indicator.timer.tick(time.delta());
+ }
+}
+
+fn health_indicator_despawn(
+ health_indicators: Query<(Entity, &HealthIndicator)>,
+ mut commands: Commands,
+) {
+ for (entity, health_indicator) in health_indicators.iter() {
+ if !health_indicator.timer.finished() {
+ continue;
+ }
+ commands.entity(entity).despawn();
+ }
+}