dropped item rotation
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
use crate::entities::item::{Item, ItemBundle, ItemDecorations, ItemType, Material, Quality};
|
use crate::entities::item::{
|
||||||
|
Item, ItemBundle, ItemDecorations, ItemRotationState, ItemType, Material, Quality,
|
||||||
|
};
|
||||||
use crate::world::tiles::tilemap;
|
use crate::world::tiles::tilemap;
|
||||||
use crate::world::VisibleGameEntity;
|
use crate::world::VisibleGameEntity;
|
||||||
|
|
||||||
@@ -48,7 +50,13 @@ pub fn spawn_prefab(
|
|||||||
tilemap
|
tilemap
|
||||||
.item_tiles
|
.item_tiles
|
||||||
.insert(position.as_ivec3(), items.clone());
|
.insert(position.as_ivec3(), items.clone());
|
||||||
return commands.entity(meat).insert(VisibleGameEntity).id();
|
return commands
|
||||||
|
.entity(meat)
|
||||||
|
.insert(VisibleGameEntity)
|
||||||
|
.insert(ItemRotationState {
|
||||||
|
should_be_visible: true,
|
||||||
|
})
|
||||||
|
.id();
|
||||||
}
|
}
|
||||||
MiscPrefab::Coin => {
|
MiscPrefab::Coin => {
|
||||||
let coin = commands
|
let coin = commands
|
||||||
@@ -77,7 +85,13 @@ pub fn spawn_prefab(
|
|||||||
tilemap
|
tilemap
|
||||||
.item_tiles
|
.item_tiles
|
||||||
.insert(position.as_ivec3(), items.clone());
|
.insert(position.as_ivec3(), items.clone());
|
||||||
commands.entity(coin).insert(VisibleGameEntity).id()
|
commands
|
||||||
|
.entity(coin)
|
||||||
|
.insert(VisibleGameEntity)
|
||||||
|
.insert(ItemRotationState {
|
||||||
|
should_be_visible: true,
|
||||||
|
})
|
||||||
|
.id()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use bevy_platform::collections::HashMap;
|
||||||
|
|
||||||
use crate::entities::item::decorations::ItemDecorations;
|
use crate::entities::item::decorations::ItemDecorations;
|
||||||
use crate::entities::item::material::{GemType, Material, MetalType};
|
use crate::entities::item::material::{GemType, Material, MetalType};
|
||||||
@@ -7,6 +8,7 @@ use crate::entities::item::types::ItemType;
|
|||||||
use crate::entities::item::Item;
|
use crate::entities::item::Item;
|
||||||
use crate::entities::item::ItemBundle;
|
use crate::entities::item::ItemBundle;
|
||||||
use crate::entities::item::ItemName;
|
use crate::entities::item::ItemName;
|
||||||
|
use crate::world::tiles::TileMap;
|
||||||
|
|
||||||
pub fn stain_fade_system(time: Res<Time>, mut items: Query<&mut Item>) {
|
pub fn stain_fade_system(time: Res<Time>, mut items: Query<&mut Item>) {
|
||||||
if time.elapsed_secs_f64() as u32 % 10 == 0 {
|
if time.elapsed_secs_f64() as u32 % 10 == 0 {
|
||||||
@@ -16,6 +18,20 @@ pub fn stain_fade_system(time: Res<Time>, mut items: Query<&mut Item>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ensures all items in item_tiles have the ItemRotationState component.
|
||||||
|
/// This handles items that were spawned before the rotation system was added,
|
||||||
|
/// or items that somehow got missing the component.
|
||||||
|
pub fn initialize_item_rotation_state(
|
||||||
|
mut commands: Commands,
|
||||||
|
items_without_state: Query<(Entity, &Item), Without<ItemRotationState>>,
|
||||||
|
) {
|
||||||
|
for (entity, _item) in items_without_state.iter() {
|
||||||
|
commands.entity(entity).insert(ItemRotationState {
|
||||||
|
should_be_visible: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to create a decorated item (DEMO ONLY)
|
// Helper function to create a decorated item (DEMO ONLY)
|
||||||
pub fn create_decorated_item(
|
pub fn create_decorated_item(
|
||||||
commands: &mut Commands,
|
commands: &mut Commands,
|
||||||
@@ -66,3 +82,86 @@ pub fn create_decorated_item(
|
|||||||
.insert(ItemName::new(item_type.name()))
|
.insert(ItemName::new(item_type.name()))
|
||||||
.id()
|
.id()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct ItemRotationTimer {
|
||||||
|
timer: Timer,
|
||||||
|
current_indices: HashMap<IVec3, usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ItemRotationTimer {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
timer: Timer::from_seconds(0.4f32, TimerMode::Repeating),
|
||||||
|
current_indices: HashMap::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct ItemRotationState {
|
||||||
|
pub should_be_visible: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn item_tile_management_system(
|
||||||
|
time: Res<Time>,
|
||||||
|
mut tilemap: ResMut<TileMap>,
|
||||||
|
mut rotation_timer: ResMut<ItemRotationTimer>,
|
||||||
|
mut item_query: Query<&mut ItemRotationState, With<Item>>,
|
||||||
|
) {
|
||||||
|
rotation_timer.timer.tick(time.delta());
|
||||||
|
|
||||||
|
let mut tiles_to_remove = Vec::new();
|
||||||
|
let mut tiles_with_items = Vec::new();
|
||||||
|
|
||||||
|
for (position, items) in tilemap.item_tiles.iter() {
|
||||||
|
if items.is_empty() {
|
||||||
|
tiles_to_remove.push(*position);
|
||||||
|
} else {
|
||||||
|
tiles_with_items.push((*position, items.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for position in tiles_to_remove {
|
||||||
|
tilemap.item_tiles.remove(&position);
|
||||||
|
rotation_timer.current_indices.remove(&position);
|
||||||
|
}
|
||||||
|
|
||||||
|
if rotation_timer.timer.just_finished() {
|
||||||
|
for (position, items) in tiles_with_items {
|
||||||
|
if items.len() <= 1 {
|
||||||
|
if let Some(&entity_id) = items.first() {
|
||||||
|
let entity = Entity::from_raw(entity_id);
|
||||||
|
if let Ok(mut rotation_state) = item_query.get_mut(entity) {
|
||||||
|
rotation_state.should_be_visible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_index = rotation_timer
|
||||||
|
.current_indices
|
||||||
|
.get(&position)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
for &entity_id in &items {
|
||||||
|
let entity = Entity::from_raw(entity_id);
|
||||||
|
if let Ok(mut rotation_state) = item_query.get_mut(entity) {
|
||||||
|
rotation_state.should_be_visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let next_index = (current_index + 1) % items.len();
|
||||||
|
|
||||||
|
if let Some(&next_entity_id) = items.get(next_index) {
|
||||||
|
let next_entity = Entity::from_raw(next_entity_id);
|
||||||
|
if let Ok(mut rotation_state) = item_query.get_mut(next_entity) {
|
||||||
|
rotation_state.should_be_visible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rotation_timer.current_indices.insert(position, next_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+8
-4
@@ -1,9 +1,9 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_rand::prelude::*;
|
use bevy_rand::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::entities::{
|
||||||
entities::livestock::pig::pig_drop_system,
|
item::{initialize_item_rotation_state, item_tile_management_system, ItemRotationTimer},
|
||||||
world::tiles::{item_tile_management_system, ItemRotationTimer},
|
livestock::pig::pig_drop_system,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod camera;
|
mod camera;
|
||||||
@@ -60,6 +60,10 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.add_systems(Update, pig_drop_system)
|
.add_systems(Update, pig_drop_system)
|
||||||
.insert_resource(ItemRotationTimer::default())
|
.insert_resource(ItemRotationTimer::default())
|
||||||
.add_systems(Update, item_tile_management_system)
|
.add_systems(Update, initialize_item_rotation_state)
|
||||||
|
.add_systems(
|
||||||
|
Update,
|
||||||
|
item_tile_management_system.after(initialize_item_rotation_state),
|
||||||
|
)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -49,7 +49,8 @@ impl Plugin for WorldPlugin {
|
|||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
(
|
(
|
||||||
compute_visibility_of_game_entities,
|
compute_visibility_of_game_entities
|
||||||
|
.after(crate::entities::item::item_tile_management_system),
|
||||||
(
|
(
|
||||||
handle_tile_occlusion_updates,
|
handle_tile_occlusion_updates,
|
||||||
build_quilted_terrain_sprites,
|
build_quilted_terrain_sprites,
|
||||||
|
|||||||
@@ -1,94 +1,9 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_platform::collections::hash_map::HashMap;
|
use bevy_platform::collections::hash_map::HashMap;
|
||||||
|
|
||||||
use crate::{entities::item::Item, game};
|
|
||||||
|
|
||||||
#[derive(Resource, Default, Clone)]
|
#[derive(Resource, Default, Clone)]
|
||||||
pub struct TileMap {
|
pub struct TileMap {
|
||||||
pub floor_tiles: HashMap<IVec3, (i32, bool, bool, bool, i32, [u32; 8])>, //id, canStandIn, canStandOn, visiblyTransparent, astar_weight, visible_range
|
pub floor_tiles: HashMap<IVec3, (i32, bool, bool, bool, i32, [u32; 8])>, //id, canStandIn, canStandOn, visiblyTransparent, astar_weight, visible_range
|
||||||
pub fixture_tiles: HashMap<IVec3, (i32, bool, bool, [u32; 8])>, // id, canStandIn, canStandOn, visible_range //TODO - consider moving alot of this into the fixtures components
|
pub fixture_tiles: HashMap<IVec3, (i32, bool, bool, [u32; 8])>, // id, canStandIn, canStandOn, visible_range
|
||||||
pub item_tiles: HashMap<IVec3, Vec<u32>>, // Entity.id's of items on this tile
|
pub item_tiles: HashMap<IVec3, Vec<u32>>, // Entity.id's of items on this tile
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource)]
|
|
||||||
pub struct ItemRotationTimer {
|
|
||||||
timer: Timer,
|
|
||||||
current_indices: HashMap<IVec3, usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ItemRotationTimer {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
timer: Timer::from_seconds(0.4f32, TimerMode::Repeating),
|
|
||||||
current_indices: HashMap::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO - broken, doesnt work with the visibleGameEntity system
|
|
||||||
pub fn item_tile_management_system(
|
|
||||||
time: Res<Time>,
|
|
||||||
mut tilemap: ResMut<TileMap>,
|
|
||||||
mut rotation_timer: ResMut<ItemRotationTimer>,
|
|
||||||
z_index: Res<game::ZIndex>,
|
|
||||||
mut visibility_query: Query<&mut Visibility, With<Item>>,
|
|
||||||
) {
|
|
||||||
rotation_timer.timer.tick(time.delta());
|
|
||||||
|
|
||||||
let mut tiles_to_remove = Vec::new();
|
|
||||||
let mut tiles_with_items = Vec::new();
|
|
||||||
|
|
||||||
for (position, items) in tilemap.item_tiles.iter() {
|
|
||||||
if items.is_empty() {
|
|
||||||
tiles_to_remove.push(*position);
|
|
||||||
} else {
|
|
||||||
tiles_with_items.push((*position, items.clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for position in tiles_to_remove {
|
|
||||||
tilemap.item_tiles.remove(&position);
|
|
||||||
rotation_timer.current_indices.remove(&position);
|
|
||||||
}
|
|
||||||
|
|
||||||
if rotation_timer.timer.just_finished() {
|
|
||||||
for (position, items) in tiles_with_items {
|
|
||||||
if position.z > z_index.0 as i32 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if items.len() <= 1 {
|
|
||||||
if let Some(&entity_id) = items.first() {
|
|
||||||
let entity = Entity::from_raw(entity_id);
|
|
||||||
if let Ok(mut visibility) = visibility_query.get_mut(entity) {
|
|
||||||
*visibility = Visibility::Visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let current_index = rotation_timer
|
|
||||||
.current_indices
|
|
||||||
.get(&position)
|
|
||||||
.copied()
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
if let Some(¤t_entity_id) = items.get(current_index) {
|
|
||||||
let current_entity = Entity::from_raw(current_entity_id);
|
|
||||||
if let Ok(mut visibility) = visibility_query.get_mut(current_entity) {
|
|
||||||
*visibility = Visibility::Hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let next_index = (current_index + 1) % items.len();
|
|
||||||
|
|
||||||
if let Some(&next_entity_id) = items.get(next_index) {
|
|
||||||
let next_entity = Entity::from_raw(next_entity_id);
|
|
||||||
if let Ok(mut visibility) = visibility_query.get_mut(next_entity) {
|
|
||||||
*visibility = Visibility::Visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rotation_timer.current_indices.insert(position, next_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
constants::{ITILE_SIZE, TILE_SIZE},
|
constants::{ITILE_SIZE, TILE_SIZE},
|
||||||
|
entities::item::ItemRotationState,
|
||||||
game,
|
game,
|
||||||
world::{
|
world::{
|
||||||
chunks::{Z_ABOVE, Z_BELOW, Z_TOTAL},
|
chunks::{Z_ABOVE, Z_BELOW, Z_TOTAL},
|
||||||
@@ -14,12 +15,28 @@ use bevy_platform::time::Instant;
|
|||||||
pub struct VisibleGameEntity;
|
pub struct VisibleGameEntity;
|
||||||
|
|
||||||
pub fn compute_visibility_of_game_entities(
|
pub fn compute_visibility_of_game_entities(
|
||||||
mut query: Query<(&Transform, &mut Visibility, &mut Sprite), With<VisibleGameEntity>>,
|
mut query: Query<
|
||||||
|
(
|
||||||
|
&Transform,
|
||||||
|
&mut Visibility,
|
||||||
|
&mut Sprite,
|
||||||
|
Option<&ItemRotationState>,
|
||||||
|
),
|
||||||
|
With<VisibleGameEntity>,
|
||||||
|
>,
|
||||||
z_index: Res<game::ZIndex>,
|
z_index: Res<game::ZIndex>,
|
||||||
) {
|
) {
|
||||||
query
|
query
|
||||||
.par_iter_mut()
|
.par_iter_mut()
|
||||||
.for_each(|(transform, mut visibility, mut sprite)| {
|
.for_each(|(transform, mut visibility, mut sprite, rotation_state)| {
|
||||||
|
// Check if this item should be hidden due to rotation
|
||||||
|
if let Some(rotation_state) = rotation_state {
|
||||||
|
if !rotation_state.should_be_visible {
|
||||||
|
*visibility = Visibility::Hidden;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let entity_z = (transform.translation.z / TILE_SIZE) - 1.0;
|
let entity_z = (transform.translation.z / TILE_SIZE) - 1.0;
|
||||||
// if same z-level, always visible
|
// if same z-level, always visible
|
||||||
if z_index.0 == entity_z {
|
if z_index.0 == entity_z {
|
||||||
@@ -46,7 +63,6 @@ pub fn compute_visibility_of_game_entities(
|
|||||||
((z_index.0 - (transform.translation.z / TILE_SIZE) + 1.) / 8.0).clamp(0.0, 1.0);
|
((z_index.0 - (transform.translation.z / TILE_SIZE) + 1.) / 8.0).clamp(0.0, 1.0);
|
||||||
|
|
||||||
sprite.color = Color::hsv(194.7, saturation, 1.0 - (saturation / 2.0));
|
sprite.color = Color::hsv(194.7, saturation, 1.0 - (saturation / 2.0));
|
||||||
|
|
||||||
sprite.color.set_alpha(1.0 - saturation);
|
sprite.color.set_alpha(1.0 - saturation);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user