generated from hheik/bevy-template
Added basic worker components
parent
4e3ac2d268
commit
3ff21d3b83
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 482 B |
92
src/game.rs
92
src/game.rs
|
|
@ -1,84 +1,28 @@
|
||||||
use crate::{debug, game_setup};
|
use crate::{debug, game_setup, util};
|
||||||
use bevy::{prelude::*, sprite::Anchor};
|
use bevy::prelude::*;
|
||||||
use bevy_rapier2d::prelude::*;
|
use bevy_rapier2d::prelude::*;
|
||||||
|
|
||||||
|
mod item;
|
||||||
|
mod prefab;
|
||||||
|
mod systems;
|
||||||
|
mod work;
|
||||||
|
|
||||||
pub fn init(app: &mut App) {
|
pub fn init(app: &mut App) {
|
||||||
let app = app.add_plugins((
|
let app = app.add_plugins((
|
||||||
game_setup::GameSetupPlugin,
|
game_setup::GameSetupPlugin,
|
||||||
RapierPhysicsPlugin::<NoUserData>::default(),
|
RapierPhysicsPlugin::<NoUserData>::default(),
|
||||||
|
util::UtilPlugin,
|
||||||
debug::DebugPlugin,
|
debug::DebugPlugin,
|
||||||
));
|
));
|
||||||
|
|
||||||
app.add_systems(Startup, setup_2d)
|
app.register_type::<item::Item>()
|
||||||
.add_systems(Update, demo_2d);
|
.register_type::<item::ItemSource>()
|
||||||
}
|
.register_type::<item::Inventory>()
|
||||||
|
.register_type::<work::WorkDuration>()
|
||||||
fn setup_2d(mut commands: Commands, assets: Res<AssetServer>) {
|
.register_type::<work::Worker>()
|
||||||
commands.spawn((
|
.register_type::<prefab::Glorb>()
|
||||||
Name::from("Demo 2D camera"),
|
.register_type::<prefab::Tree>()
|
||||||
Camera2d,
|
.add_systems(Startup, systems::setup_2d)
|
||||||
Transform::from_xyz(0.0, 0.0, 10.0),
|
.add_systems(Update, (systems::demo_2d, systems::work_select))
|
||||||
));
|
.add_systems(PostUpdate, item::update_item_sprite);
|
||||||
|
|
||||||
commands.spawn((
|
|
||||||
Name::from("Glorb"),
|
|
||||||
Transform::from_xyz(-200.0, 0.0, 0.0),
|
|
||||||
Sprite {
|
|
||||||
image: assets.load("sprites/glorb.png"),
|
|
||||||
anchor: Anchor::BottomCenter,
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
));
|
|
||||||
|
|
||||||
commands.spawn((
|
|
||||||
Name::from("Box"),
|
|
||||||
Transform::from_xyz(-200.0, -150.0, 0.0),
|
|
||||||
Sprite {
|
|
||||||
image: assets.load("sprites/box.png"),
|
|
||||||
anchor: Anchor::Custom(Vec2 { x: 0.0, y: -0.375 }),
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
));
|
|
||||||
|
|
||||||
commands.spawn((
|
|
||||||
Name::from("Wood"),
|
|
||||||
Sprite {
|
|
||||||
image: assets.load("sprites/wood.png"),
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
));
|
|
||||||
|
|
||||||
commands.spawn((
|
|
||||||
Name::from("Tree"),
|
|
||||||
Transform::from_xyz(200.0, 0.0, 0.0),
|
|
||||||
Sprite {
|
|
||||||
image: assets.load("sprites/tree.png"),
|
|
||||||
anchor: Anchor::Custom(Vec2 { x: 0.0, y: -0.375 }),
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn demo_2d(
|
|
||||||
mut camera_query: Query<(&mut Transform, &mut OrthographicProjection)>,
|
|
||||||
mut mouse_events: EventReader<bevy::input::mouse::MouseMotion>,
|
|
||||||
mut scroll_events: EventReader<bevy::input::mouse::MouseWheel>,
|
|
||||||
mouse_input: Res<ButtonInput<MouseButton>>,
|
|
||||||
) {
|
|
||||||
let raw_mouse_motion: Vec2 = mouse_events.read().map(|e| e.delta).sum();
|
|
||||||
let raw_scroll_motion: f32 = scroll_events
|
|
||||||
.read()
|
|
||||||
.map(|event| match event.unit {
|
|
||||||
bevy::input::mouse::MouseScrollUnit::Line => event.y * -0.1,
|
|
||||||
bevy::input::mouse::MouseScrollUnit::Pixel => event.y * -0.05,
|
|
||||||
})
|
|
||||||
.sum();
|
|
||||||
|
|
||||||
for (mut transform, mut projection) in camera_query.iter_mut() {
|
|
||||||
projection.scale += raw_scroll_motion * projection.scale;
|
|
||||||
let mouse_motion = raw_mouse_motion * projection.scale * Vec2::new(-1.0, 1.0);
|
|
||||||
if mouse_input.pressed(MouseButton::Middle) {
|
|
||||||
transform.translation += mouse_motion.extend(0.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,141 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
#[require(Sprite)]
|
||||||
|
pub enum Item {
|
||||||
|
Wood,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Reflect)]
|
||||||
|
pub struct ItemStack {
|
||||||
|
pub item: Item,
|
||||||
|
pub count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ItemStack {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
item: Item::Wood,
|
||||||
|
count: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct ItemSource(pub ItemStack);
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct Inventory {
|
||||||
|
pub capacity: Option<usize>,
|
||||||
|
pub items: Vec<ItemStack>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum InsertResult {
|
||||||
|
/// Combine to an existing stack. Contains (`index`, `new_count`)
|
||||||
|
Combine(usize, u32),
|
||||||
|
/// No existing stackable stacks, push a new one.
|
||||||
|
Push(ItemStack),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum RemoveResult {
|
||||||
|
/// The stack will get depleted, so it can be removed. Contains the `index` of empty stack.
|
||||||
|
Empty(usize),
|
||||||
|
/// The stack will get only partially depleted. Contains (`index`, `new_count`)
|
||||||
|
Partial(usize, u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Inventory {
|
||||||
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
capacity: Some(capacity),
|
||||||
|
..default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.items.iter().all(|stack| stack.count == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_insert(&self, item_stack: &ItemStack) -> Option<InsertResult> {
|
||||||
|
match self
|
||||||
|
.items
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find(|(_, stack)| stack.item == item_stack.item)
|
||||||
|
{
|
||||||
|
Some((index, stack)) => {
|
||||||
|
Some(InsertResult::Combine(index, stack.count + item_stack.count))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if self
|
||||||
|
.capacity
|
||||||
|
.map_or(true, |capacity| self.items.len() < capacity)
|
||||||
|
{
|
||||||
|
Some(InsertResult::Push(*item_stack))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_remove(&self, item_stack: &ItemStack) -> Option<RemoveResult> {
|
||||||
|
match self
|
||||||
|
.items
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find(|(_, stack)| stack.item == item_stack.item)
|
||||||
|
{
|
||||||
|
Some((index, stack)) => match stack.count.checked_sub(item_stack.count) {
|
||||||
|
Some(new_count) => {
|
||||||
|
if new_count == 0 {
|
||||||
|
Some(RemoveResult::Empty(index))
|
||||||
|
} else {
|
||||||
|
Some(RemoveResult::Partial(index, new_count))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not enough items
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
// No matching items found
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_transfer(
|
||||||
|
&self,
|
||||||
|
to: &Self,
|
||||||
|
item_stack: &ItemStack,
|
||||||
|
) -> Option<(RemoveResult, InsertResult)> {
|
||||||
|
match (self.try_remove(item_stack), to.try_insert(item_stack)) {
|
||||||
|
(Some(remove_result), Some(insert_result)) => Some((remove_result, insert_result)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sanitize(&mut self) {
|
||||||
|
if let Some(capacity) = self.capacity {
|
||||||
|
self.items.truncate(capacity);
|
||||||
|
}
|
||||||
|
self.items.retain(|stack| stack.count > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
#[require(Inventory)]
|
||||||
|
pub struct Stockpile;
|
||||||
|
|
||||||
|
pub fn update_item_sprite(
|
||||||
|
mut query: Query<(&mut Sprite, &Item), Changed<Item>>,
|
||||||
|
assets: Res<AssetServer>,
|
||||||
|
) {
|
||||||
|
for (mut sprite, item) in query.iter_mut() {
|
||||||
|
sprite.image = assets.load(match item {
|
||||||
|
Item::Wood => "sprites/wood.png",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
use bevy::{prelude::*, sprite::Anchor};
|
||||||
|
use bevy_rapier2d::prelude::*;
|
||||||
|
use item::{Inventory, Item, ItemSource, ItemStack, Stockpile};
|
||||||
|
use work::{WorkDuration, Worker};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::util::SpriteLoader;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
#[require(
|
||||||
|
Name(|| Name::from("Glorb")),
|
||||||
|
Sprite(|| Sprite {
|
||||||
|
anchor: Anchor::BottomCenter,
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
|
SpriteLoader(|| SpriteLoader::from("sprites/glorb.png")),
|
||||||
|
Worker,
|
||||||
|
Inventory(|| Inventory::with_capacity(1)),
|
||||||
|
Velocity,
|
||||||
|
RigidBody(|| RigidBody::KinematicVelocityBased),
|
||||||
|
)]
|
||||||
|
pub struct Glorb;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
#[require(
|
||||||
|
Name(|| Name::from("Tree")),
|
||||||
|
Sprite(|| Sprite {
|
||||||
|
anchor: Anchor::Custom(Vec2 { x: 0.0, y: -0.375 }),
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
|
SpriteLoader(|| SpriteLoader::from("sprites/tree.png")),
|
||||||
|
ItemSource(|| ItemSource(ItemStack { item: Item::Wood, count: 1 })),
|
||||||
|
WorkDuration(|| WorkDuration(5.0))
|
||||||
|
)]
|
||||||
|
pub struct Tree;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
#[require(
|
||||||
|
Name(|| Name::from("Chest")),
|
||||||
|
Sprite(|| Sprite {
|
||||||
|
anchor: Anchor::Custom(Vec2 { x: 0.0, y: -0.375 }),
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
|
SpriteLoader(|| SpriteLoader::from("sprites/box.png")),
|
||||||
|
Inventory(|| Inventory::with_capacity(25)),
|
||||||
|
Stockpile,
|
||||||
|
)]
|
||||||
|
pub struct Chest;
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
mod demo;
|
||||||
|
mod worker;
|
||||||
|
|
||||||
|
pub use demo::*;
|
||||||
|
pub use worker::*;
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use crate::game::{item::Item, prefab};
|
||||||
|
|
||||||
|
pub fn setup_2d(mut commands: Commands) {
|
||||||
|
commands.spawn((
|
||||||
|
Name::from("Demo 2D camera"),
|
||||||
|
Camera2d,
|
||||||
|
Transform::from_xyz(0.0, 0.0, 10.0),
|
||||||
|
));
|
||||||
|
|
||||||
|
commands.spawn((Transform::from_xyz(-200.0, 0.0, 0.0), prefab::Glorb));
|
||||||
|
commands.spawn((Transform::from_xyz(-200.0, 100.0, 0.0), prefab::Glorb));
|
||||||
|
commands.spawn((Transform::from_xyz(-200.0, -100.0, 0.0), prefab::Glorb));
|
||||||
|
|
||||||
|
commands.spawn((Transform::from_xyz(200.0, 0.0, 0.0), prefab::Tree));
|
||||||
|
|
||||||
|
commands.spawn((Name::from("Wood"), Item::Wood));
|
||||||
|
|
||||||
|
commands.spawn((Transform::from_xyz(-200.0, -150.0, 0.0), prefab::Chest));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn demo_2d(
|
||||||
|
mut camera_query: Query<(&mut Transform, &mut OrthographicProjection)>,
|
||||||
|
mut mouse_events: EventReader<bevy::input::mouse::MouseMotion>,
|
||||||
|
mut scroll_events: EventReader<bevy::input::mouse::MouseWheel>,
|
||||||
|
mouse_input: Res<ButtonInput<MouseButton>>,
|
||||||
|
) {
|
||||||
|
let raw_mouse_motion: Vec2 = mouse_events.read().map(|e| e.delta).sum();
|
||||||
|
let raw_scroll_motion: f32 = scroll_events
|
||||||
|
.read()
|
||||||
|
.map(|event| match event.unit {
|
||||||
|
bevy::input::mouse::MouseScrollUnit::Line => event.y * -0.1,
|
||||||
|
bevy::input::mouse::MouseScrollUnit::Pixel => event.y * -0.05,
|
||||||
|
})
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
for (mut transform, mut projection) in camera_query.iter_mut() {
|
||||||
|
projection.scale += raw_scroll_motion * projection.scale;
|
||||||
|
let mouse_motion = raw_mouse_motion * projection.scale * Vec2::new(-1.0, 1.0);
|
||||||
|
if mouse_input.pressed(MouseButton::Middle) {
|
||||||
|
transform.translation += mouse_motion.extend(0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use crate::game::{
|
||||||
|
item::{Inventory, ItemSource, Stockpile},
|
||||||
|
work::{Task, WorkType, Worker},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn work_select(
|
||||||
|
mut worker_query: Query<(&mut Worker, &Inventory, &GlobalTransform)>,
|
||||||
|
store_query: Query<(Entity, &Inventory, &GlobalTransform), With<Stockpile>>,
|
||||||
|
gather_query: Query<(Entity, &ItemSource, &GlobalTransform)>,
|
||||||
|
) {
|
||||||
|
for (mut worker, worker_inventory, worker_transform) in worker_query.iter_mut() {
|
||||||
|
// Skip if worker already has a job
|
||||||
|
if worker.0.is_some() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut task_by_distance: Option<(Task, f32)> = None;
|
||||||
|
|
||||||
|
for (stockpile_entity, stockpile_inventory, stockpile_transform) in store_query.iter() {
|
||||||
|
for worker_stack in worker_inventory.items.iter() {
|
||||||
|
if let Some((_, _)) =
|
||||||
|
worker_inventory.try_transfer(stockpile_inventory, worker_stack)
|
||||||
|
{
|
||||||
|
let stockpile_dist_squared = worker_transform
|
||||||
|
.translation()
|
||||||
|
.distance_squared(stockpile_transform.translation());
|
||||||
|
if task_by_distance.map_or(true, |(_, closest_task_dist)| {
|
||||||
|
stockpile_dist_squared < closest_task_dist
|
||||||
|
}) {
|
||||||
|
task_by_distance = Some((
|
||||||
|
Task {
|
||||||
|
target: stockpile_entity,
|
||||||
|
work_type: WorkType::Store(*worker_stack),
|
||||||
|
progress: 0.0,
|
||||||
|
},
|
||||||
|
stockpile_dist_squared,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((task, _)) = task_by_distance {
|
||||||
|
worker.0 = Some(task);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (item_source_entity, item_source, item_source_transform) in gather_query.iter() {
|
||||||
|
if worker_inventory.try_insert(&item_source.0).is_some() {
|
||||||
|
let source_dist_squared = worker_transform
|
||||||
|
.translation()
|
||||||
|
.distance_squared(item_source_transform.translation());
|
||||||
|
if task_by_distance.map_or(true, |(_, closest_task_dist)| {
|
||||||
|
source_dist_squared < closest_task_dist
|
||||||
|
}) {
|
||||||
|
task_by_distance = Some((
|
||||||
|
Task {
|
||||||
|
target: item_source_entity,
|
||||||
|
work_type: WorkType::Gather,
|
||||||
|
progress: 0.0,
|
||||||
|
},
|
||||||
|
source_dist_squared,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
worker.0 = task_by_distance.map(|(task, _)| task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use crate::util::Seconds;
|
||||||
|
|
||||||
|
use super::item::ItemStack;
|
||||||
|
|
||||||
|
/// Total time it takes to finish a task
|
||||||
|
#[derive(Copy, Clone, Debug, Default, Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct WorkDuration(pub Seconds);
|
||||||
|
|
||||||
|
impl WorkDuration {
|
||||||
|
/// Returns the `Some`(`duration_secs`) if the value is above `0.0`, and `None` otherwise
|
||||||
|
pub fn safe_duration(&self) -> Option<Seconds> {
|
||||||
|
if self.0 > 0.0 {
|
||||||
|
Some(self.0)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Reflect)]
|
||||||
|
pub enum WorkType {
|
||||||
|
Gather,
|
||||||
|
Store(ItemStack),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Reflect)]
|
||||||
|
pub struct Task {
|
||||||
|
pub progress: Seconds,
|
||||||
|
pub work_type: WorkType,
|
||||||
|
pub target: Entity,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Task {
|
||||||
|
pub fn add_progress(&mut self, work_duration: &WorkDuration, progress: Seconds) -> u32 {
|
||||||
|
match work_duration.safe_duration() {
|
||||||
|
Some(duration) => (self.progress + progress).div_euclid(duration).max(0.0) as u32,
|
||||||
|
None => 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Default, Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct Worker(pub Option<Task>);
|
||||||
|
|
@ -4,18 +4,19 @@ pub struct GameSetupPlugin;
|
||||||
|
|
||||||
impl Plugin for GameSetupPlugin {
|
impl Plugin for GameSetupPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.insert_resource(ClearColor(Color::BLACK)).add_plugins(
|
app.insert_resource(ClearColor(Color::linear_rgb(0.070, 0.094, 0.071)))
|
||||||
DefaultPlugins
|
.add_plugins(
|
||||||
.set(WindowPlugin {
|
DefaultPlugins
|
||||||
primary_window: Some(Window {
|
.set(WindowPlugin {
|
||||||
resolution: WindowResolution::new(512.0 * 2.0, 320.0 * 2.0),
|
primary_window: Some(Window {
|
||||||
title: "Glorbs <press P to toggle debug mode>".to_string(), // NOTE: Replace this
|
resolution: WindowResolution::new(512.0 * 2.0, 320.0 * 2.0),
|
||||||
resizable: false,
|
title: "Glorbs <press P to toggle debug mode>".to_string(), // NOTE: Replace this
|
||||||
|
resizable: false,
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
..default()
|
..default()
|
||||||
}),
|
})
|
||||||
..default()
|
.set(ImagePlugin::default_nearest()),
|
||||||
})
|
);
|
||||||
.set(ImagePlugin::default_nearest()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use util::create_app_graphs;
|
|
||||||
|
|
||||||
pub mod debug;
|
pub mod debug;
|
||||||
pub mod game;
|
pub mod game;
|
||||||
|
|
@ -9,6 +8,6 @@ pub mod util;
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
game::init(&mut app);
|
game::init(&mut app);
|
||||||
create_app_graphs(&mut app);
|
// util::create_app_graphs(&mut app);
|
||||||
app.run();
|
app.run();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,18 @@ use core::{fmt, ops};
|
||||||
use std::{fs, path::Path};
|
use std::{fs, path::Path};
|
||||||
|
|
||||||
mod basis;
|
mod basis;
|
||||||
|
mod plugin;
|
||||||
mod transform_f64;
|
mod transform_f64;
|
||||||
|
mod types;
|
||||||
mod vector2;
|
mod vector2;
|
||||||
mod vector2_i32;
|
mod vector2_i32;
|
||||||
mod vector3;
|
mod vector3;
|
||||||
mod vector3_i32;
|
mod vector3_i32;
|
||||||
|
|
||||||
pub use basis::*;
|
pub use basis::*;
|
||||||
|
pub use plugin::*;
|
||||||
pub use transform_f64::*;
|
pub use transform_f64::*;
|
||||||
|
pub use types::*;
|
||||||
pub use vector2::*;
|
pub use vector2::*;
|
||||||
pub use vector2_i32::*;
|
pub use vector2_i32::*;
|
||||||
pub use vector3::*;
|
pub use vector3::*;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
pub struct UtilPlugin;
|
||||||
|
|
||||||
|
impl Plugin for UtilPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.register_type::<SpriteLoader>()
|
||||||
|
.add_systems(PostUpdate, load_sprite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Automatically sets the `Sprite` components `image` to given asset path upon being added.
|
||||||
|
///
|
||||||
|
/// Can be used to set default sprite in required components without having access to AssetServer.
|
||||||
|
#[derive(Clone, Debug, Default, Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
#[require(Sprite)]
|
||||||
|
pub struct SpriteLoader(pub String);
|
||||||
|
|
||||||
|
impl SpriteLoader {
|
||||||
|
pub fn from(path: impl Into<String>) -> Self {
|
||||||
|
Self(path.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_sprite(
|
||||||
|
mut sprite_query: Query<(&mut Sprite, &SpriteLoader), Added<SpriteLoader>>,
|
||||||
|
assets: Res<AssetServer>,
|
||||||
|
) {
|
||||||
|
for (mut sprite, loader) in sprite_query.iter_mut() {
|
||||||
|
sprite.image = assets.load(&loader.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
pub type Seconds = f32;
|
||||||
Loading…
Reference in New Issue