components and systems refactor

This commit is contained in:
nquidox 2026-04-11 18:09:30 +03:00
parent 04754db916
commit 4da000f1c8
10 changed files with 283 additions and 98 deletions

View file

@ -1,20 +1,23 @@
use crate::states::level::components::{
Ball, BallProjectile, BallType, Cannon, LevelMarker, TrackPath, WaveState,
};
use crate::states::level::system::SLOT_SIZE;
use bevy::prelude::*;
use crate::states::level::*;
use bevy::window::PrimaryWindow;
const CANNON_Z_INDEX: f32 = 10.0;
const PROJECTILE_Z_INDEX: f32 = 11.0;
const CURRENT_SHOT_Z_INDEX: f32 = 12.0;
const NEXT_SHOT_Z_INDEX: f32 = 12.0;
pub fn setup_cannon(mut commands: Commands, asset_server: Res<AssetServer>) {
let texture: Handle<Image> = asset_server.load("cannon/cannon.png");
commands.spawn((
LevelMarker,
Cannon,
Transform::from_xyz(579.0 - (1280.0 / 2.0), (768.0 / 2.0) - 150.0, 1.0),
Transform::from_xyz(579.0 - (1280.0 / 2.0), (768.0 / 2.0) - 150.0, CANNON_Z_INDEX),
Sprite::from_image(texture),
Visibility::Visible,
));
println!("Cannon visuals is set up");
}
pub fn rotate_cannon(
@ -54,6 +57,7 @@ pub fn spawn_projectile_from_cannon(
cannon_query: Query<&Transform, With<Cannon>>,
mouse_input: Res<ButtonInput<MouseButton>>,
asset_server: Res<AssetServer>,
mut cannon_state: ResMut<CannonState>
) {
if !mouse_input.just_pressed(MouseButton::Left) {
return;
@ -63,13 +67,13 @@ pub fn spawn_projectile_from_cannon(
return;
};
let ball_type = BallType::First; // TODO: рандом/цикл
let ball_type = cannon_state.current_type;
let image = asset_server.load(ball_type.asset_path());
let offset = 100.0; // сдвиг от центра к дулу пушки
let direction = cannon_tf.rotation.mul_vec3(Vec3::Y).truncate().normalize();
let spawn_pos_2d = cannon_tf.translation.truncate() + direction * offset;
let spawn_pos = spawn_pos_2d.extend(10.0); // z=10, чтобы было поверх трека
let spawn_pos = spawn_pos_2d.extend(PROJECTILE_Z_INDEX);
commands.spawn((
LevelMarker,
@ -86,6 +90,7 @@ pub fn spawn_projectile_from_cannon(
ball_type,
},
));
cannon_state.fire();
}
pub fn move_projectiles(
@ -97,7 +102,7 @@ pub fn move_projectiles(
// Обновляем позицию
let delta = proj.velocity * time.delta_secs();
let new_pos = proj.previous_position + delta;
transform.translation = new_pos.extend(transform.translation.z);
proj.previous_position = new_pos;
@ -147,14 +152,14 @@ pub fn detect_projectile_hit(
target_progress = target_ball.slot_progress;
// Определяем индекс вставки
insert_idx = if target_progress <= 0.5 {
nearest_idx_any
insert_idx = if target_progress <= 0.5 { //TODO check correction
nearest_idx_any - 1
} else {
nearest_idx_any + 1
nearest_idx_any
};
} else {
// Слот пуст — снаряд пролетает мимо
commands.entity(proj_entity).despawn();
// commands.entity(proj_entity).despawn();
continue;
}
@ -163,8 +168,8 @@ pub fn detect_projectile_hit(
// сдвигаем очередь
let max_idx = track.points.len() - 1;
let mut to_despawn = Vec::new();
for (entity, mut ball) in balls.iter_mut() {
if ball.slot_index >= insert_idx {
if ball.slot_index < max_idx {
@ -174,11 +179,11 @@ pub fn detect_projectile_hit(
};
}
}
for entity in to_despawn {
commands.entity(entity).despawn();
}
commands.entity(proj_entity).insert({
Ball {
ball_type: proj.ball_type,
@ -191,3 +196,68 @@ pub fn detect_projectile_hit(
// Разблокировка (структурные изменения завершены)
wave.is_queue_locked = false;
}
pub fn cycle_cannon_type(
mut cannon_state: ResMut<CannonState>,
mouse_input: Res<ButtonInput<MouseButton>>,
) {
if mouse_input.just_pressed(MouseButton::Right) {
cannon_state.cycle_next();
}
}
pub fn update_cannon_preview(
mut commands: Commands,
cannon_state: Res<CannonState>,
asset_server: Res<AssetServer>,
cannon_query: Query<Entity, With<Cannon>>,
muzzle_query: Query<Entity, With<CurrentPreviewMarker>>,
next_query: Query<Entity, With<NextPreviewMarker>>,
) {
let Ok(cannon_entity) = cannon_query.single() else { return };
let muzzle_image = asset_server.load(cannon_state.current_type.asset_path());
if let Ok(muzzle_entity) = muzzle_query.single() {
// усли шарик у дула есть, то обновляем спрайт
commands.entity(muzzle_entity).insert(Sprite::from_image(muzzle_image));
} else {
//иначе создаем
let preview_entity = commands.spawn((
CurrentPreviewMarker,
Sprite{
image: muzzle_image,
custom_size: Some(Vec2::splat(SLOT_SIZE)),
..default()
},
Transform::from_xyz(0.0, 100.0, CURRENT_SHOT_Z_INDEX),
Visibility::Visible,
)).id();
commands.entity(cannon_entity).add_child(preview_entity);
}
let next_image = asset_server.load(cannon_state.next_type.asset_path());
if let Ok(next_entity) = next_query.single() {
commands.entity(next_entity).insert(Sprite::from_image(next_image));
} else {
let preview_entity = commands.spawn((
NextPreviewMarker,
Sprite{
image: next_image,
custom_size: Some(Vec2::splat(SLOT_SIZE)),
..default()
},
Transform::from_xyz(0.0, -50.0, NEXT_SHOT_Z_INDEX),
Visibility::Visible,
)).id();
commands.entity(cannon_entity).add_child(preview_entity);
}
}
pub fn build_cannon_state() -> CannonState {
CannonState {
current_type: BallType::random(),
next_type: BallType::random(),
}
}