Skip to content

Commit

Permalink
First look at players window
Browse files Browse the repository at this point in the history
  • Loading branch information
spectria-limina committed Dec 9, 2024
1 parent f552f20 commit 11426e1
Show file tree
Hide file tree
Showing 8 changed files with 496 additions and 109 deletions.
21 changes: 6 additions & 15 deletions src/drag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use bevy::ecs::world::DeferredWorld;
use bevy::prelude::*;

use crate::color::AlphaScale;
use crate::ecs::{EntityExts, EntityExtsOf};
use crate::Layer;

/// The factor to apply to a sprite's alpha channel when it is dragged out of bounds.
Expand Down Expand Up @@ -125,10 +126,6 @@ pub fn on_drag_end(
/// Will automatically add the necessary hooks when added to an entity.
pub struct Draggable;

/// Marker component for drag observer hooks added by [`Draggable`].
#[derive(Component, Copy, Clone, Default, Debug)]
pub struct DragHook;

/// Marker component for entities currently being dragged.
#[derive(Component, Copy, Clone, Default, Debug)]
#[component(storage = "SparseSet")]
Expand All @@ -147,21 +144,15 @@ impl Draggable {
debug!("Adding drag hooks to {id:?}");
let mut commands = world.commands();
let mut entity = commands.entity(id);
entity.observe(on_drag_start).insert(DragHook);
entity.observe(on_drag).insert(DragHook);
entity.observe(on_drag_end).insert(DragHook);
let mut of = entity.of::<Self>();
of.observe(on_drag_start);
of.observe(on_drag);
of.observe(on_drag_end);
}

pub fn remove_observers(mut world: DeferredWorld, id: Entity, _: ComponentId) {
debug!("Removing drag hooks from {id:?}");
world.commands().run_system_cached_with(
|In(id): In<Entity>, q: Query<&Children, With<DragHook>>, mut commands: Commands| {
for hook in q.iter_descendants(id) {
commands.entity(hook).despawn();
}
},
id,
);
world.commands().entity(id).of::<Self>().despawn_observers();
}
}

Expand Down
99 changes: 99 additions & 0 deletions src/ecs.rs
Original file line number Diff line number Diff line change
@@ -1 +1,100 @@
use std::marker::PhantomData;

use bevy::{ecs::system::IntoObserverSystem, prelude::*};

/// Marker component for observer hooks added by a specific component.
#[derive(Component, Copy, Clone, Default, Debug)]
pub struct ObserverFor<C: Component>(PhantomData<C>);

impl<C: Component> ObserverFor<C> {
pub fn new() -> Self {
ObserverFor(PhantomData)
}

pub fn despawn_for(
In(id): In<Entity>,
q: Query<&Children, With<Self>>,
mut commands: Commands,
) {
for observer in q.iter_descendants(id) {
commands.entity(observer).despawn();
}
}
}

pub struct EntityCommandsOf<'a, 'w: 'a, C: Component> {
entity: &'a mut EntityCommands<'w>,
_ph: PhantomData<C>,
}
impl<'a, 'w: 'a, C: Component> EntityCommandsOf<'a, 'w, C> {
pub fn new(entity: &'a mut EntityCommands<'w>) -> Self {
Self {
entity,
_ph: PhantomData,
}
}
}
impl<'a, 'w: 'a, C: Component> From<&'a mut EntityCommands<'w>> for EntityCommandsOf<'a, 'w, C> {
fn from(entity: &'a mut EntityCommands<'w>) -> Self {
Self::new(entity)
}
}

pub trait EntityExtsOf<'w, C: Component> {
fn observe<E, B, M>(
&mut self,
system: impl IntoObserverSystem<E, B, M>,
) -> &mut EntityCommands<'w>
where
E: Event,
B: Bundle;

fn despawn_observers(&mut self) -> &mut Self;
}

impl<'w, C: Component> EntityExtsOf<'w, C> for EntityCommandsOf<'_, 'w, C> {
fn observe<E, B, M>(
&mut self,
system: impl IntoObserverSystem<E, B, M>,
) -> &mut EntityCommands<'w>
where
E: Event,
B: Bundle,
{
self.entity.observe(system)
}

fn despawn_observers(&mut self) -> &mut Self {
let id = self.entity.id();
self.entity
.commands()
.run_system_cached_with(ObserverFor::<C>::despawn_for, id);
self
}
}

pub trait EntityExts<'w> {
type Of<'a, C: Component>
where
Self: 'a,
'w: 'a;

fn of<'a, C: Component>(&'a mut self) -> Self::Of<'a, C>
where
'w: 'a;
}

impl<'w> EntityExts<'w> for EntityCommands<'w> {
type Of<'a, C: Component>
= EntityCommandsOf<'a, 'w, C>
where
Self: 'a,
'w: 'a;

fn of<'a, C: Component>(&'a mut self) -> Self::Of<'a, C>
where
'w: 'a,
{
Self::Of::from(self)
}
}
9 changes: 6 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ mod debug;
mod drag;
mod ecs;
mod hitbox;
mod player;
mod spawner;
mod waymark;
mod widget;
Expand Down Expand Up @@ -94,14 +95,16 @@ fn start(args: Args, primary_window: Window) -> eyre::Result<()> {
.disable::<SleepingPlugin>(),
*/
)
.insert_resource(WinitSettings::desktop_app())
.add_plugins(asset::lifecycle::plugin())
.add_plugins(arena::menu::plugin())
.add_plugins(arena::plugin())
.add_plugins(color::plugin())
.add_plugins(drag::plugin())
.add_plugins(player::plugin())
.add_plugins(player::window::plugin())
.add_plugins(waymark::plugin())
.add_plugins(waymark::window::plugin())
.add_plugins(arena::plugin())
.add_plugins(arena::menu::plugin())
.insert_resource(WinitSettings::desktop_app())
.add_systems(Startup, spawn_camera);

if args.debug_inspector {
Expand Down
109 changes: 109 additions & 0 deletions src/player/job.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use bevy::prelude::*;

#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
#[derive(Reflect)]
pub enum Job {
// Tanks
Paladin,
Warrior,
DarkKnight,
Gunbreaker,

// Pure healers
WhiteMage,
Astrologian,

// Barrier healers
Scholar,
Sage,

// Melee DPS
Monk,
Dragoon,
Ninja,
Samurai,
Reaper,
Viper,

// Physical ranged DPS
Bard,
Machinist,
Dancer,

// Magical ranged DPS
BlackMage,
Summoner,
RedMage,
Pictomancer,
Fisher,

// Limited jobs
BlueMage,
Beastmaster,
}

impl Job {
pub fn abbrev(self) -> &'static str {
use Job::*;
match self {
Paladin => "PLD",
Warrior => "WAR",
DarkKnight => "DRK",
Gunbreaker => "GNB",
WhiteMage => "WHM",
Astrologian => "AST",
Scholar => "SCH",
Sage => "SGE",
Monk => "MNK",
Dragoon => "DRG",
Ninja => "NIN",
Samurai => "SAM",
Reaper => "RPR",
Viper => "VPR",
Bard => "BRD",
Machinist => "MCH",
Dancer => "DNC",
BlackMage => "BLM",
Summoner => "SMN",
RedMage => "RDM",
Pictomancer => "PCT",
Fisher => "FSH",
BlueMage => "BLU",
Beastmaster => "BSM",
}
}

pub fn icon_asset_path(self) -> &'static str {
use Job::*;
match self {
Paladin => "sprites/jobs/pld.png",
Warrior => "sprites/jobs/war.png",
DarkKnight => "sprites/jobs/drk.png",
Gunbreaker => "sprites/jobs/gnb.png",
WhiteMage => "sprites/jobs/whm.png",
Astrologian => "sprites/jobs/ast.png",
Scholar => "sprites/jobs/sch.png",
Sage => "sprites/jobs/sge.png",
Monk => "sprites/jobs/mnk.png",
Dragoon => "sprites/jobs/drg.png",
Ninja => "sprites/jobs/nin.png",
Samurai => "sprites/jobs/sam.png",
Reaper => "sprites/jobs/rpr.png",
Viper => "sprites/jobs/vpr.png",
Bard => "sprites/jobs/brd.png",
Machinist => "sprites/jobs/mch.png",
Dancer => "sprites/jobs/dnc.png",
BlackMage => "sprites/jobs/blm.png",
Summoner => "sprites/jobs/smn.png",
RedMage => "sprites/jobs/rdm.png",
Pictomancer => "sprites/jobs/pct.png",
Fisher => "sprites/jobs/fsh.png",
BlueMage => "sprites/jobs/blu.png",
Beastmaster => Self::none_asset_path(),
}
}

pub fn none_asset_path() -> &'static str {
"sprites/jobs/none.png"
}
}
73 changes: 73 additions & 0 deletions src/player/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use avian2d::prelude::Collider;
use bevy::prelude::*;
use job::Job;

use crate::{drag::Draggable, spawner::Spawnable};

pub mod job;
pub mod window;

/// The size of a player icon.
const PLAYER_SPRITE_SIZE: f32 = 2.0;

const PLAYER_COLLIDER_SIZE: f32 = 0.001;

#[derive(Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd, Component, Reflect)]
#[require(Draggable)]
#[require(Collider(|| Collider::circle(PLAYER_COLLIDER_SIZE)))]
#[require(PlayerSprite)]
pub struct Player {}

impl Player {}

#[derive(Copy, Default, Clone, Hash, PartialEq, Eq, Ord, PartialOrd, Debug)]
#[derive(Component, Reflect)]
#[require(Sprite(||Sprite{custom_size: Some(Vec2::splat(PLAYER_SPRITE_SIZE)), ..default()}))]
pub struct PlayerSprite {
pub job: Option<Job>,
}

impl PlayerSprite {
pub fn update_sprites(
mut q: Query<(&PlayerSprite, &mut Sprite), Changed<PlayerSprite>>,
asset_server: Res<AssetServer>,
) {
for (player_sprite, mut sprite) in &mut q {
sprite.image = asset_server.load(player_sprite.asset_path());
sprite.custom_size = Some(Vec2::splat(PLAYER_SPRITE_SIZE));
}
}

pub fn asset_path(self) -> &'static str {
self.job
.map_or(Job::none_asset_path(), Job::icon_asset_path)
}
}

impl Spawnable for PlayerSprite {
const UNIQUE: bool = true;

fn spawner_name(&self) -> std::borrow::Cow<'static, str> {
format!("{:#?} Spawner", self.job).into()
}

fn texture_handle(&self, asset_server: &AssetServer) -> Handle<Image> {
asset_server.load(self.asset_path())
}

fn insert(&self, entity: &mut EntityCommands) {
entity.insert((Player {}, *self));
}
}

pub struct PlayerPlugin;

impl Plugin for PlayerPlugin {
fn build(&self, app: &mut App) {
app.add_systems(PostUpdate, PlayerSprite::update_sprites);
}
}

pub fn plugin() -> PlayerPlugin {
PlayerPlugin
}
Loading

0 comments on commit 11426e1

Please sign in to comment.