Skip to content

Commit

Permalink
Merge pull request #17 from regnarock/inventory
Browse files Browse the repository at this point in the history
inventory embryo
  • Loading branch information
regnarock authored Dec 15, 2023
2 parents 4fd546a + 791d8ff commit 4698b2d
Show file tree
Hide file tree
Showing 11 changed files with 475 additions and 11 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 5 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[package]
name = "bevy_game" # ToDo
name = "bevy_game" # ToDo
version = "0.1.0"
publish = false
authors = ["Niklas Eicker <[email protected]>"] # ToDo: you are the author ;)
authors = ["Niklas Eicker <[email protected]>"] # ToDo: you are the author ;)
edition = "2021"
exclude = ["dist", "build", "assets", "credits"]

Expand All @@ -22,14 +22,12 @@ inherits = "release"
lto = "thin"

[features]
dev = [
"bevy/dynamic_linking",
]
dev = ["bevy/dynamic_linking"]

# All of Bevy's default features exept for the audio related ones, since they clash with bevy_kira_audio
# and android_shared_stdcxx, since that is covered in `mobile`
[dependencies]
bevy = { version="0.12", default-features = false, features = [
bevy = { version = "0.12", default-features = false, features = [
"animation",
"bevy_asset",
"bevy_gilrs",
Expand All @@ -56,6 +54,7 @@ bevy = { version="0.12", default-features = false, features = [
bevy_kira_audio = { version = "0.18" }
bevy_asset_loader = { version = "0.18" }
rand = { version = "0.8.3" }
rand_chacha = "0.3"

# keep the following in sync with Bevy's dependencies
winit = { version = "0.28", default-features = false }
Expand Down
1 change: 1 addition & 0 deletions src/actions/game_control.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use bevy::prelude::{Input, KeyCode, Res};

#[allow(dead_code)]
pub enum GameControl {
Up,
Down,
Expand Down
2 changes: 0 additions & 2 deletions src/actions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ use bevy::prelude::*;
pub mod cursor;
mod game_control;

pub const FOLLOW_EPSILON: f32 = 5.;

pub struct ActionsPlugin;

// This plugin listens for keyboard input and converts the input into Actions
Expand Down
2 changes: 1 addition & 1 deletion src/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn start_audio(mut commands: Commands, audio_assets: Res<AudioAssets>, audio: Re
commands.insert_resource(FlyingAudio(handle));
}

fn control_flying_sound(
fn _control_flying_sound(
actions: Res<Actions>,
audio: Res<FlyingAudio>,
mut audio_instances: ResMut<Assets<AudioInstance>>,
Expand Down
296 changes: 296 additions & 0 deletions src/buildings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
use crate::inventory::{self};
use crate::inventory::{Inventory, SpawnInventory};
use crate::random::RandomDeterministic;
use crate::window::WindowSize;
use crate::GameState;
use bevy::ecs::system::{EntityCommand, SystemParam, SystemState};

use bevy::prelude::*;
use bevy::render::mesh::Indices;
use bevy::render::render_resource::PrimitiveTopology;
use bevy::sprite::MaterialMesh2dBundle;
use bevy::sprite::Mesh2dHandle;
use bevy::utils::HashMap;
use rand::seq::SliceRandom;

pub struct Plugin;

impl bevy::prelude::Plugin for Plugin {
fn build(&self, app: &mut App) {
app.add_plugins(inventory::InventoryPlugin::<Building>::default())
.init_resource::<BuildingInventory>()
.add_systems(
OnEnter(GameState::Playing),
(create_assets, spawn_layout).chain(),
)
.add_systems(
Update,
update_anchor_position
.run_if(resource_changed::<WindowSize>())
.run_if(in_state(GameState::Playing)),
);
}
}

#[derive(Resource)]
pub struct BuildingInventory {
pub(crate) state: SystemState<GetNextBuildingParams<'static, 'static>>,
}

#[derive(SystemParam)]
pub(crate) struct GetNextBuildingParams<'w, 's> {
command: Commands<'w, 's>,
q_inventory: Query<
'w,
's,
(
&'static mut RandomDeterministic,
&'static mut crate::inventory::Inventory<Building>,
),
>,
q_buildings: Query<'w, 's, &'static Building>,
}

impl FromWorld for BuildingInventory {
fn from_world(world: &mut World) -> Self {
BuildingInventory {
state: SystemState::new(world),
}
}
}

impl BuildingInventory {
pub fn next(&mut self, world: &mut World) -> Option<Building> {
let mut params = self.state.get_mut(world);
let (mut rng, mut inventory) = params.q_inventory.single_mut();

let Some(first_item) = inventory.items.front().cloned() else {
return None;
};
let Ok(_item_to_build) = params.q_buildings.get(first_item) else {
return None;
};
// TODO: check if we can build item_to_build (cooldown, space available, currency, ...)
// TODO: send an event if not possible.
// TODO: pay "price" ?
inventory.items.pop_front();

let new_building = get_random_building(&mut rng);
let new_item = params.command.spawn(new_building).id();

inventory.items.push_back(new_item);

// TODO: reuse that entity to merge it with turret entity ?
world.despawn(first_item);

self.state.apply(world);
Some(new_building)
}
}

#[derive(Resource)]
pub struct VisualAssets {
pub mesh_def: HashMap<BuildingMesh, Mesh2dHandle>,
pub size_def: HashMap<BuildingSize, f32>,
pub color_def: HashMap<BuildingColor, Handle<ColorMaterial>>,
}

pub(crate) fn create_assets(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
commands.insert_resource(VisualAssets {
mesh_def: [
(
BuildingMesh::Triangle,
meshes
.add(
Mesh::new(PrimitiveTopology::TriangleList)
.with_inserted_attribute(
Mesh::ATTRIBUTE_POSITION,
vec![[-0.5, -0.5, 0.0], [0.0, 0.5, 0.0], [0.5, -0.5, 0.0]],
)
.with_indices(Some(Indices::U32(vec![0, 1, 2]))),
)
.into(),
),
(
BuildingMesh::Circle,
meshes.add(Mesh::from(shape::Circle::default())).into(),
),
(
BuildingMesh::Quad,
meshes.add(Mesh::from(shape::Quad::default())).into(),
),
]
.into(),
size_def: [
(BuildingSize::Big, 1f32),
(BuildingSize::Medium, 0.75f32),
(BuildingSize::Small, 0.5f32),
]
.into(),
color_def: [
(
BuildingColor::Black,
materials.add(ColorMaterial::from(Color::BLACK)),
),
(
BuildingColor::White,
materials.add(ColorMaterial::from(Color::WHITE)),
),
(
BuildingColor::Pink,
materials.add(ColorMaterial::from(Color::PINK)),
),
(
BuildingColor::Blue,
materials.add(ColorMaterial::from(Color::BLUE)),
),
]
.into(),
});
}

const ITEM_VISUAL_SIZE: f32 = 64f32;
const PADDING: f32 = 10f32;

pub(crate) fn spawn_layout(mut commands: Commands, window_size: ResMut<WindowSize>) {
let mut rng = crate::random::RandomDeterministic::new_from_seed(0);
let inventory = vec![
commands.spawn(get_random_building(&mut rng)).id(),
commands.spawn(get_random_building(&mut rng)).id(),
commands.spawn(get_random_building(&mut rng)).id(),
commands.spawn(get_random_building(&mut rng)).id(),
commands.spawn(get_random_building(&mut rng)).id(),
commands.spawn(get_random_building(&mut rng)).id(),
];
let anchor_point = Vec3::new(
-window_size.size.x / 2f32 + ITEM_VISUAL_SIZE / 2f32 + PADDING,
-window_size.size.y / 2f32 + (ITEM_VISUAL_SIZE + PADDING) * 5.5f32 + PADDING,
0f32,
);

commands
.spawn_empty()
.add(SpawnInventory::<Building>::new(
inventory,
inventory::InventoryConfiguration {
positions: positions_from_anchor_point(anchor_point),
},
))
.insert(RandomDeterministic::new_from_seed(0));
}

fn positions_from_anchor_point(anchor_point: Vec3) -> Vec<Vec3> {
vec![
anchor_point - Vec3::new(0f32, (ITEM_VISUAL_SIZE + PADDING) * 5f32, 0f32),
anchor_point - Vec3::new(0f32, (ITEM_VISUAL_SIZE + PADDING) * 4f32, 0f32),
anchor_point - Vec3::new(0f32, (ITEM_VISUAL_SIZE + PADDING) * 3f32, 0f32),
anchor_point - Vec3::new(0f32, (ITEM_VISUAL_SIZE + PADDING) * 2f32, 0f32),
anchor_point - Vec3::new(0f32, ITEM_VISUAL_SIZE + PADDING, 0f32),
anchor_point,
]
}

pub(crate) fn update_anchor_position(
window_size: ResMut<WindowSize>,
mut q_inventory: Query<&mut Inventory<Building>>,
) {
let anchor_point: Vec3 = Vec3::new(
-window_size.size.x / 2f32 + ITEM_VISUAL_SIZE / 2f32 + PADDING,
-window_size.size.y / 2f32 + (ITEM_VISUAL_SIZE + PADDING) * 5.5f32 + PADDING,
0f32,
);
q_inventory.for_each_mut(|mut inventory| {
inventory.positions = positions_from_anchor_point(anchor_point);
});
}

#[derive(Component, Clone, Copy, Hash, Eq, PartialEq)]
pub struct Building {
mesh: BuildingMesh,
size: BuildingSize,
color: BuildingColor,
}

#[derive(Clone, Copy, Hash, Eq, PartialEq)]
pub enum BuildingMesh {
Triangle,
Circle,
Quad,
}
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
pub enum BuildingSize {
Small,
Medium,
Big,
}
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
pub enum BuildingColor {
Black,
White,
Pink,
Blue,
}

impl inventory::ItemSpriteBuilder for Building {
type C = BuildingItemSpriteBuilder;
fn build_sprite(&self) -> Self::C {
BuildingItemSpriteBuilder { building: *self }
}
}

pub struct BuildingItemSpriteBuilder {
pub building: Building,
}

impl EntityCommand for BuildingItemSpriteBuilder {
fn apply(self, id: Entity, world: &mut World) {
let assets = world.get_resource::<VisualAssets>().unwrap();
let visual = MaterialMesh2dBundle {
mesh: assets.mesh_def[&self.building.mesh].clone(),
transform: Transform::default().with_scale(Vec3::splat(
ITEM_VISUAL_SIZE * assets.size_def[&self.building.size],
)),
material: assets.color_def[&self.building.color].clone(),
..default()
};
world.entity_mut(id).insert(visual);
}
}

pub fn get_random_building(rng: &mut crate::random::RandomDeterministic) -> Building {
let choices_mesh = [
(BuildingMesh::Triangle, 2),
(BuildingMesh::Circle, 2),
(BuildingMesh::Quad, 2),
];
let choices_size = [
(BuildingSize::Big, 1),
(BuildingSize::Medium, 2),
(BuildingSize::Small, 1),
];
let choices_color = [
(BuildingColor::Black, 5),
(BuildingColor::White, 5),
(BuildingColor::Pink, 1),
(BuildingColor::Blue, 1),
];
let building = Building {
mesh: choices_mesh
.choose_weighted(&mut rng.random, |i| i.1)
.unwrap()
.0,
size: choices_size
.choose_weighted(&mut rng.random, |i| i.1)
.unwrap()
.0,
color: choices_color
.choose_weighted(&mut rng.random, |i| i.1)
.unwrap()
.0,
};
building
}
Loading

0 comments on commit 4698b2d

Please sign in to comment.