cannon components and systems
This commit is contained in:
parent
71f6b549b7
commit
30412844b8
5 changed files with 253 additions and 2 deletions
46
src/states/linear/components_cannon.rs
Normal file
46
src/states/linear/components_cannon.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
use crate::states::linear::RoundBallType;
|
||||
use bevy::prelude::*;
|
||||
use std::mem;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct LinearCannon;
|
||||
|
||||
#[derive(Resource, Debug, Clone)]
|
||||
pub struct LinearCannonState {
|
||||
pub shot: RoundBallType,
|
||||
pub swap: RoundBallType,
|
||||
}
|
||||
|
||||
impl Default for LinearCannonState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
shot: RoundBallType::random_from_4(),
|
||||
swap: RoundBallType::random_from_4(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LinearCannonState {
|
||||
pub fn fire(&mut self) {
|
||||
self.shot = self.swap;
|
||||
self.swap = RoundBallType::random_from_4();
|
||||
}
|
||||
|
||||
pub fn cycle(&mut self) {
|
||||
mem::swap(&mut self.shot, &mut self.swap);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct RoundBallProjectile {
|
||||
pub velocity: Vec2,
|
||||
pub previous_position: Vec2,
|
||||
pub ball_type: RoundBallType,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct ShotMarker;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct SwapMarker;
|
||||
|
|
@ -11,6 +11,9 @@ pub const SCALE: f32 = 2.0;
|
|||
|
||||
// Z-INDEXES
|
||||
pub const ROUND_BALL_Z: f32 = 10.0;
|
||||
pub const ROUND_SHOT_Z: f32 = 11.0;
|
||||
pub const LINEAR_CANNON_Z: f32 = 20.0;
|
||||
pub const LINEAR_CANNON_BALL_Z: f32 = 15.0;
|
||||
|
||||
// COLORS
|
||||
pub const PINK: Color = Color::srgb_u8(250, 0, 155);
|
||||
|
|
|
|||
|
|
@ -21,5 +21,10 @@ pub use constants::*;
|
|||
|
||||
mod ui;
|
||||
pub use ui::*;
|
||||
mod components_cannon;
|
||||
pub use components_cannon::*;
|
||||
mod systems_cannon;
|
||||
pub use systems_cannon::*;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ pub enum LinearUpdateSet {
|
|||
impl Plugin for LinearPlayPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app
|
||||
.add_systems(OnEnter(LinearPlayState), setup)
|
||||
.add_systems(OnEnter(LinearPlayState), (setup, spawn_linear_cannon).chain())
|
||||
.add_systems(OnEnter(LinearGameRestart), linear_restart)
|
||||
.add_plugins(LinearUIPlugin)
|
||||
.configure_sets(
|
||||
|
|
@ -26,8 +26,14 @@ impl Plugin for LinearPlayPlugin {
|
|||
(
|
||||
draw_track_gizmos,
|
||||
draw_grid,
|
||||
//несколько систем с соблюдением порядка
|
||||
linear_move_projectiles,
|
||||
cycle_cannon_balls,
|
||||
update_linear_cannon_preview,
|
||||
spawn_projectile_from_cannon,
|
||||
spawn_round_ball,
|
||||
move_round_balls,
|
||||
rotate_linear_cannon,
|
||||
)
|
||||
.in_set(LinearUpdateSet::Track),
|
||||
)
|
||||
|
|
@ -41,6 +47,7 @@ fn setup(mut commands: Commands) {
|
|||
|
||||
commands.insert_resource(build_track);
|
||||
commands.insert_resource(precalculated_track);
|
||||
commands.insert_resource(build_linear_cannon_state());
|
||||
}
|
||||
|
||||
fn cleanup(mut commands: Commands, query: Query<Entity, With<LinearStateMarker>>) {
|
||||
|
|
@ -50,8 +57,9 @@ fn cleanup(mut commands: Commands, query: Query<Entity, With<LinearStateMarker>>
|
|||
}
|
||||
|
||||
// зачищаем ресурсы по типу
|
||||
commands.remove_resource::<Track>();
|
||||
commands.remove_resource::<Track>(); //зачистить сразу после калькуляции
|
||||
commands.remove_resource::<PrecalculatedTrack>();
|
||||
commands.remove_resource::<LinearCannonState>();
|
||||
}
|
||||
|
||||
fn linear_restart(mut next_state: ResMut<NextState<AppState>>) {
|
||||
|
|
|
|||
189
src/states/linear/systems_cannon.rs
Normal file
189
src/states/linear/systems_cannon.rs
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
use crate::states::linear::*;
|
||||
use bevy::prelude::*;
|
||||
use bevy::window::PrimaryWindow;
|
||||
use std::f32::consts::FRAC_PI_2;
|
||||
use bevy::asset::ErasedAssetLoader;
|
||||
use crate::{FACTOR, HEIGHT, WIDTH};
|
||||
use crate::states::level::{BallProjectile, BallType, Cannon, CannonState, CurrentPreviewMarker, NextPreviewMarker, CURRENT_SHOT_Z_INDEX, NEXT_SHOT_Z_INDEX, SLOT_SIZE};
|
||||
|
||||
pub fn spawn_linear_cannon(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
let image: Handle<Image> = asset_server.load("sprites/cannon/cannon.png");
|
||||
|
||||
commands.spawn((
|
||||
Sprite {
|
||||
image,
|
||||
custom_size: Some(Vec2::new(STEP * 2.5, STEP * 4.0)),
|
||||
..default()
|
||||
},
|
||||
Transform::from_xyz(6.0 * STEP, 3.0 * STEP, LINEAR_CANNON_Z),
|
||||
LinearStateMarker,
|
||||
LinearCannon,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn rotate_linear_cannon(
|
||||
mut query: Query<&mut Transform, With<LinearCannon>>,
|
||||
window_query: Query<&Window, With<PrimaryWindow>>,
|
||||
camera_query: Query<(&Camera, &GlobalTransform)>,
|
||||
) {
|
||||
let Ok(mut cannon_tf) = query.single_mut() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok(window) = window_query.single() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(cursor_pos) = window.cursor_position() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok((camera, camera_tf)) = camera_query.single() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok(world_cursor_pos) = camera.viewport_to_world_2d(camera_tf, cursor_pos) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let cannon_pos = Vec2::new(cannon_tf.translation.x, cannon_tf.translation.y);
|
||||
let direction = world_cursor_pos - cannon_pos;
|
||||
|
||||
let angle = direction.to_angle() - FRAC_PI_2;
|
||||
cannon_tf.rotation = Quat::from_rotation_z(angle);
|
||||
}
|
||||
|
||||
pub fn spawn_projectile_from_cannon(
|
||||
mut commands: Commands,
|
||||
cannon_query: Query<&Transform, With<LinearCannon>>,
|
||||
mouse_input: Res<ButtonInput<MouseButton>>,
|
||||
asset_server: Res<AssetServer>,
|
||||
mut cannon_state: ResMut<LinearCannonState>
|
||||
) {
|
||||
if !mouse_input.just_pressed(MouseButton::Left) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Ok(cannon_tf) = cannon_query.single() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let ball_type = cannon_state.shot;
|
||||
let image: Handle<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(ROUND_SHOT_Z);
|
||||
|
||||
commands.spawn((
|
||||
Sprite {
|
||||
image,
|
||||
custom_size: Some(Vec2::splat(STEP)),
|
||||
..default()
|
||||
},
|
||||
Transform::from_translation(spawn_pos),
|
||||
RoundBallProjectile {
|
||||
velocity: direction * 800.0,
|
||||
previous_position: spawn_pos_2d,
|
||||
ball_type,
|
||||
},
|
||||
LinearStateMarker,
|
||||
));
|
||||
cannon_state.fire();
|
||||
}
|
||||
|
||||
pub fn build_linear_cannon_state() -> LinearCannonState {
|
||||
LinearCannonState {
|
||||
shot: RoundBallType::random_from_4(),
|
||||
swap: RoundBallType::random_from_4(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_linear_cannon_preview(
|
||||
mut commands: Commands,
|
||||
cannon_state: Res<LinearCannonState>,
|
||||
asset_server: Res<AssetServer>,
|
||||
cannon_query: Query<Entity, With<LinearCannon>>,
|
||||
shot_query: Query<Entity, With<ShotMarker>>,
|
||||
swap_query: Query<Entity, With<SwapMarker>>,
|
||||
) {
|
||||
let Ok(cannon_entity) = cannon_query.single() else { return };
|
||||
|
||||
let shot_image: Handle<Image> = asset_server.load(cannon_state.shot.asset_path());
|
||||
|
||||
if let Ok(shot_entity) = shot_query.single() {
|
||||
// усли шарик у дула есть, то обновляем спрайт
|
||||
commands.entity(shot_entity).insert(
|
||||
Sprite{
|
||||
image: shot_image,
|
||||
custom_size: Some(Vec2::splat(STEP)),
|
||||
..default()
|
||||
}
|
||||
);
|
||||
} else {
|
||||
//иначе создаем
|
||||
let preview_entity = commands.spawn((
|
||||
Sprite{
|
||||
image: shot_image,
|
||||
custom_size: Some(Vec2::splat(STEP)),
|
||||
..default()
|
||||
},
|
||||
Transform::from_xyz(0.0, STEP * 2.2, LINEAR_CANNON_BALL_Z),
|
||||
ShotMarker
|
||||
)).id();
|
||||
commands.entity(cannon_entity).add_child(preview_entity);
|
||||
}
|
||||
|
||||
// следующий шарик в хвосте
|
||||
let swap_image = asset_server.load(cannon_state.swap.asset_path());
|
||||
|
||||
if let Ok(swap_entity) = swap_query.single() {
|
||||
commands.entity(swap_entity).insert(Sprite{
|
||||
image: swap_image,
|
||||
custom_size: Some(Vec2::splat(STEP)),
|
||||
..default()
|
||||
});
|
||||
} else {
|
||||
let preview_entity = commands.spawn((
|
||||
Sprite{
|
||||
image: swap_image,
|
||||
custom_size: Some(Vec2::splat(STEP)),
|
||||
..default()
|
||||
},
|
||||
Transform::from_xyz(0.0, -STEP * 1.5, LINEAR_CANNON_BALL_Z),
|
||||
SwapMarker,
|
||||
)).id();
|
||||
commands.entity(cannon_entity).add_child(preview_entity);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cycle_cannon_balls(
|
||||
mut cannon_state: ResMut<LinearCannonState>,
|
||||
mouse_input: Res<ButtonInput<MouseButton>>,
|
||||
) {
|
||||
if mouse_input.just_pressed(MouseButton::Right) {
|
||||
cannon_state.cycle();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn linear_move_projectiles(
|
||||
mut commands: Commands,
|
||||
mut projectiles: Query<(Entity, &mut RoundBallProjectile, &mut Transform)>,
|
||||
time: Res<Time>,
|
||||
) {
|
||||
for (entity, mut proj, mut transform) in projectiles.iter_mut() {
|
||||
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;
|
||||
|
||||
// удаляем снаряды, улетевшие за экран
|
||||
if new_pos.x.abs() > 1.5 * (WIDTH * FACTOR) as f32 || new_pos.y.abs() > 1.5 * (HEIGHT * FACTOR) as f32 {
|
||||
commands.entity(entity).despawn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn detect_track_hit(){} //TODO
|
||||
Loading…
Add table
Add a link
Reference in a new issue