Skip to content

Commit

Permalink
Merge pull request #1 from moreirayokoyama/feat/coins-hp-ui
Browse files Browse the repository at this point in the history
feat: coins and hp interface
  • Loading branch information
empix authored Jul 27, 2024
2 parents ab4d21b + edfc5d0 commit 3edf499
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 2 deletions.
Binary file added assets/fonts/courneuf-family/Courneuf-Regular.ttf
Binary file not shown.
1 change: 1 addition & 0 deletions assets/fonts/courneuf-family/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://fontlibrary.org/en/font/courneuf-family
28 changes: 26 additions & 2 deletions src/character.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use bevy::{
app::{Plugin, Startup, Update},
asset::{AssetServer, Assets},
math::{UVec2, Vec2},
prelude::{default, Commands, Component, Deref, DerefMut, Local, Query, Res, ResMut},
prelude::*,
reflect::Reflect,
sprite::{Sprite, SpriteBundle, TextureAtlas, TextureAtlasLayout},
time::{Time, Timer, TimerMode},
transform::components::Transform,
Expand Down Expand Up @@ -47,11 +48,31 @@ pub struct Character {
state: CharacterState,
}

#[derive(Component, Reflect)]
pub struct CoinPouch(pub u64);

#[derive(Component, Reflect)]
pub struct HealthPoints {
pub max_full_hearts: u8,
pub current: u8,
}

impl HealthPoints {
fn full(hearts: u8) -> Self {
HealthPoints {
max_full_hearts: hearts,
current: hearts * 2,
}
}
}

pub struct CharacterPlugin;

impl Plugin for CharacterPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
app.add_systems(Startup, startup)
app.register_type::<CoinPouch>()
.register_type::<HealthPoints>()
.add_systems(Startup, startup)
.add_systems(Update, (movement, animate));
}
}
Expand All @@ -65,6 +86,7 @@ fn startup(
let atlas_layout = TextureAtlasLayout::from_grid(UVec2::new(16, 16), 8, 5, None, None);
let atlas_layout_handle = texture_atlases.add(atlas_layout);
let texture = asset_server.load("bgp_catdev/player_and_ui/Basic_Player.png");

commands.spawn((
Character {
movement_speed: CHARACTER_MOVEMENT_SPEED as f32,
Expand Down Expand Up @@ -113,6 +135,8 @@ fn startup(
},
//LockedAxes::ROTATION_LOCKED,
AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
CoinPouch(50),
HealthPoints::full(5),
PIXEL_PERFECT_LAYERS,
));
}
Expand Down
2 changes: 2 additions & 0 deletions src/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use bevy::app::{PluginGroup, PluginGroupBuilder};

use crate::{
camera::CameraPlugin, character::CharacterPlugin, control::ControlPlugin, map::MapPlugin,
ui::UIPlugin,
};

pub struct GamePlugins;
Expand All @@ -12,6 +13,7 @@ impl PluginGroup for GamePlugins {
.add(MapPlugin)
.add(CameraPlugin)
.add(ControlPlugin)
.add(UIPlugin)
//.add(PhysicsPlugin)
.add_after::<MapPlugin, CharacterPlugin>(CharacterPlugin)
}
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ mod game;
mod game_world;
mod map;
mod physics;
mod ui;
mod utils;

use bevy::asset::AssetMetaCheck;
Expand Down
212 changes: 212 additions & 0 deletions src/ui.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
use bevy::{
app::{Plugin, Startup},
prelude::*,
};

use crate::{
character::{Character, CoinPouch, HealthPoints},
HIGH_RES_LAYERS,
};

pub struct UIPlugin;

impl Plugin for UIPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
app.add_systems(Startup, (load_assets, startup).chain())
.add_systems(FixedUpdate, (update_coins, update_health_points));
}
}

#[derive(Component)]
struct CoinPouchNodeUI;

#[derive(Component)]
struct CoinPouchTextUI;

#[derive(Component)]
struct HealthPointsNodeUI;

#[derive(Component)]
struct HealthPointIconUI;

#[derive(Resource)]
struct TextFont(Handle<Font>);

#[derive(Resource)]
struct HeartsAndCoinsTexture(Handle<Image>);

#[derive(Resource)]
struct HeartsAndCoinsTextureAtlas(Handle<TextureAtlasLayout>);

fn load_assets(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut texture_atlases: ResMut<Assets<TextureAtlasLayout>>,
) {
let font_handle: Handle<Font> = asset_server.load("fonts/courneuf-family/Courneuf-Regular.ttf");
commands.insert_resource(TextFont(font_handle));

let texture_handle: Handle<Image> =
asset_server.load("bgp_catdev/player_and_ui/Basic_HeartsAndCoins.png");
commands.insert_resource(HeartsAndCoinsTexture(texture_handle));

let texture_atlas = TextureAtlasLayout::from_grid(UVec2::splat(16), 5, 2, None, None);
let texture_atlas_handle: Handle<TextureAtlasLayout> = texture_atlases.add(texture_atlas);
commands.insert_resource(HeartsAndCoinsTextureAtlas(texture_atlas_handle));
}

fn startup(
mut commands: Commands,
text_font_handle: Res<TextFont>,
texture_handle: Res<HeartsAndCoinsTexture>,
texture_atlas_handle: Res<HeartsAndCoinsTextureAtlas>,
) {
commands
.spawn((
Name::new("Main UI node"),
NodeBundle {
style: Style {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
align_items: AlignItems::FlexStart,
justify_content: JustifyContent::FlexStart,
flex_direction: FlexDirection::Column,
padding: UiRect::axes(Val::Px(20.0), Val::Px(10.0)),
..default()
},
..default()
},
HIGH_RES_LAYERS,
))
.with_children(|parent| {
parent.spawn((
Name::new("Health points UI"),
HealthPointsNodeUI,
NodeBundle {
style: Style {
width: Val::Percent(100.0),
align_items: AlignItems::Center,
..default()
},
..default()
},
));

parent
.spawn((
Name::new("Coins UI"),
CoinPouchNodeUI,
NodeBundle {
style: Style {
width: Val::Percent(100.0),
align_items: AlignItems::Center,
..default()
},
..default()
},
))
.with_children(|parent| {
parent.spawn((
ImageBundle {
style: Style {
width: Val::Px(64.),
height: Val::Px(64.),
..default()
},
image: UiImage::new(texture_handle.0.clone()),
..default()
},
TextureAtlas {
layout: texture_atlas_handle.0.clone(),
index: 5,
},
));

parent.spawn((
CoinPouchTextUI,
TextBundle::from_sections([TextSection::new(
"0",
TextStyle {
font_size: 42.0,
font: text_font_handle.0.clone(),
..default()
},
)]),
));
});
});
}

fn update_coins(
coin_pouch_query: Query<&CoinPouch, With<Character>>,
mut coin_pouch_style_query: Query<&mut Style, With<CoinPouchNodeUI>>,
mut coin_pouch_text_query: Query<&mut Text, With<CoinPouchTextUI>>,
) {
let mut coin_pouch_style = coin_pouch_style_query.single_mut();
let mut coin_pouch_text = coin_pouch_text_query.single_mut();

match coin_pouch_query.get_single() {
Ok(CoinPouch(amount)) => {
coin_pouch_text.sections[0].value = amount.to_string();
}
Err(_) => {
coin_pouch_style.display = Display::None;
}
};
}

fn update_health_points(
mut commands: Commands,
health_points_query: Query<&HealthPoints, With<Character>>,
mut health_points_ui_query: Query<(Entity, &mut Style), With<HealthPointsNodeUI>>,
texture_handle: Res<HeartsAndCoinsTexture>,
texture_atlas_handle: Res<HeartsAndCoinsTextureAtlas>,
) {
let (health_points_ui_entity, mut health_points_style) = health_points_ui_query.single_mut();

match health_points_query.get_single() {
Ok(health_points) => {
let mut children = vec![];

let full_hearts = health_points.current / 2;
let half_hearts = health_points.current % 2;

for index in 0..health_points.max_full_hearts {
let texture_atlas_index = if index < full_hearts {
0
} else if index < full_hearts + half_hearts {
1
} else {
2
};

let heart_point_entity = commands
.spawn((
HealthPointIconUI,
ImageBundle {
style: Style {
width: Val::Px(64.),
height: Val::Px(64.),
..default()
},
image: UiImage::new(texture_handle.0.clone()),
..default()
},
TextureAtlas {
layout: texture_atlas_handle.0.clone(),
index: texture_atlas_index,
},
))
.id();
children.push(heart_point_entity);
}

let mut health_points_ui_entity_commands = commands.entity(health_points_ui_entity);
health_points_ui_entity_commands.despawn_descendants();
health_points_ui_entity_commands.push_children(&children);
}
Err(_) => {
health_points_style.display = Display::None;
}
};
}

0 comments on commit 3edf499

Please sign in to comment.