diff --git a/assets/parallax/01_far_city.png b/assets/parallax/01_far_city.png index 94195a7..a076100 100644 Binary files a/assets/parallax/01_far_city.png and b/assets/parallax/01_far_city.png differ diff --git a/assets/parallax/02_middle.png b/assets/parallax/02_middle.png index c37b680..fbe0fcf 100644 Binary files a/assets/parallax/02_middle.png and b/assets/parallax/02_middle.png differ diff --git a/src/base.rs b/src/base.rs index 7d5b628..e528cd7 100644 --- a/src/base.rs +++ b/src/base.rs @@ -1,10 +1,14 @@ +use crate::block::BLOCK_SIZE; use bevy::prelude::*; +use bevy::sprite::Anchor; use bevy_rapier2d::geometry::Collider; +use bevy_rapier2d::plugin::systems::apply_scale; use bevy_rapier2d::prelude::{Friction, RigidBody, Velocity}; use crate::cursor_system::CursorCoords; use crate::level::{Level, LevelLifecycle}; use crate::state::LevelState; +use crate::HORIZONTAL_VIEWPORT_SIZE; pub struct BasePlugin; @@ -14,21 +18,73 @@ impl Plugin for BasePlugin { } } +#[derive(Debug, Clone)] +pub enum BaseType { + T2, + T3, + T4, + T7, + T9, +} + +impl BaseType { + pub fn name(&self) -> &str { + match self { + BaseType::T2 => "t-2", + BaseType::T3 => "t-3", + BaseType::T4 => "t-4", + BaseType::T7 => "t-7", + BaseType::T9 => "t-9", + } + } + + pub fn width(&self) -> f32 { + let image_width = self.image_width(); + let _4k_width = 3840.0; + let scale = HORIZONTAL_VIEWPORT_SIZE / _4k_width; + image_width * scale + } + + pub fn image_width(&self) -> f32 { + match self { + BaseType::T2 => 466.0, + BaseType::T3 => 636.0, + BaseType::T4 => 762.0, + BaseType::T7 => 1324.0, + BaseType::T9 => 1652.0, + } + } + + pub fn asset(&self) -> String { + format!("bases/{}.png", self.name()) + } +} + #[derive(Component)] pub struct Base; pub fn setup_base(mut commands: Commands, mut assets: ResMut, mut level: Res) { - let height = 20.0; - let width = level.bases[0].width; + let height = BLOCK_SIZE; + + // Since the spot in the bg image is not centered, we need to offset the base a bit + let additional_transform = Vec2::new(0.5, 0.0); for base in level.bases { + let width = base.base_type.width(); + + let image_width = base.base_type.image_width(); + + let image_scale = width / image_width; + + let texture = assets.load(base.base_type.asset()); + commands .spawn(( Base, LevelLifecycle, SpatialBundle::from( Transform::from_translation(Vec3::from(( - base.translation + Vec2::new(0.0, height / 2.0), + base.translation + additional_transform + Vec2::new(0.0, height / 2.0), 0.0, ))) .with_rotation(Quat::from_rotation_z(base.rotation)), @@ -41,8 +97,13 @@ pub fn setup_base(mut commands: Commands, mut assets: ResMut, mut l .with_children(|parent| { parent.spawn(SpriteBundle { // transform: Transform::from_xyz(0.0, 0.0, 0.0), - texture: assets.load("fortress.png"), - transform: Transform::from_xyz(0.0, 0.0, 0.0).with_scale(Vec3::splat(0.1)), + texture, + transform: Transform::from_xyz(0.0, height / 2.0, -7.0) + .with_scale(Vec3::splat(image_scale)), + sprite: Sprite { + anchor: Anchor::TopCenter, + ..Default::default() + }, ..Default::default() }); }); diff --git a/src/block.rs b/src/block.rs index 48acc3b..7a059dc 100644 --- a/src/block.rs +++ b/src/block.rs @@ -50,7 +50,7 @@ pub enum BlockType { L, } -pub const BLOCK_SIZE: f32 = 20.0; +pub const BLOCK_SIZE: f32 = 1.0; pub const BLOCKS: [BlockType; 7] = [ BlockType::I, diff --git a/src/camera_movement.rs b/src/camera_movement.rs index 8c1cb75..23f644f 100644 --- a/src/camera_movement.rs +++ b/src/camera_movement.rs @@ -1,5 +1,6 @@ -use crate::block::Falling; -use crate::MainCamera; +use crate::block::{Block, Falling}; +use crate::launch_platform::LaunchPlatform; +use crate::{MainCamera, HORIZONTAL_VIEWPORT_SIZE}; use bevy::prelude::*; #[derive(Resource)] @@ -17,24 +18,28 @@ impl Default for CameraMovement { // Camera is only moving up, not down pub fn camera_movement_system( mut camera_movement: ResMut, - mut camera_query: Query<&mut Transform, With>, - mut query: Query<( + mut camera_query: Query<(&mut Transform, &GlobalTransform, &Camera), With>, + mut query: Query< &Transform, - &crate::block::Block, - Without, - Without, - )>, + ( + Without, + Without, + Or<(With, With)>, + ), + >, ) { - let mut highest = 100.0; - for (transform, block, ..) in query.iter_mut() { + let start_move_at = 20.0; + + let mut highest = start_move_at; + for transform in query.iter_mut() { if transform.translation.y > highest { highest = transform.translation.y; } } - let target_height = highest - 100.0; + let target_height = highest - start_move_at; - let increase = 1.0; + let increase = 0.1; if target_height > camera_movement.height { camera_movement.height += increase; @@ -42,8 +47,12 @@ pub fn camera_movement_system( camera_movement.height -= increase; } - for mut transform in camera_query.iter_mut() { - transform.translation.y = camera_movement.height; + for (mut transform, global_transform, camera) in camera_query.iter_mut() { + let viewport = camera.logical_viewport_size().unwrap(); + + let scene_height = HORIZONTAL_VIEWPORT_SIZE * viewport.y / viewport.x; + + transform.translation.y = camera_movement.height + scene_height / 2.0; // camera should slowly zoom out as we get higher //transform.scale = Vec3::new(1.0, 1.0, 1.0) * (1.0 + camera_movement.height / 1000.0); } diff --git a/src/effect/magnetic.rs b/src/effect/magnetic.rs index 63439f4..0715549 100644 --- a/src/effect/magnetic.rs +++ b/src/effect/magnetic.rs @@ -21,7 +21,7 @@ pub struct MagneticEffect { impl Default for MagneticEffect { fn default() -> Self { Self { - range: 200.0, + range: 10.0, force: 2.0, } } diff --git a/src/effect/mod.rs b/src/effect/mod.rs index 2357de5..56bc281 100644 --- a/src/effect/mod.rs +++ b/src/effect/mod.rs @@ -62,7 +62,7 @@ impl EffectType { parent.spawn(SpriteBundle { texture: assets.load(texture), sprite: Sprite { - custom_size: Some(Vec2::new(24.0, 24.0)), + custom_size: Some(Vec2::new(1.0, 1.0)), ..Default::default() }, ..Default::default() diff --git a/src/environment/beam.rs b/src/environment/beam.rs index a2be7ef..d8e605e 100644 --- a/src/environment/beam.rs +++ b/src/environment/beam.rs @@ -40,7 +40,7 @@ pub fn spawn_beam_system(mut commands: Commands, mut beam_events: EventReader) { )); commands.spawn(( AutoWidth { - aspect_ratio, + aspect_ratio: 1465.0 / 3840.0, open_top: true, parallax: -0.2, }, @@ -87,7 +88,7 @@ pub fn setup_city(mut commands: Commands, assets: Res) { transform: Transform::from_xyz(0.0, 0.0, -20.0), texture: assets.load("parallax/02_middle.png"), sprite: Sprite { - custom_size: Some(Vec2::new(1.0, aspect_ratio)), + custom_size: Some(Vec2::new(1.0, 1465.0 / 3840.0)), anchor: Anchor::BottomCenter, ..Default::default() }, @@ -96,7 +97,7 @@ pub fn setup_city(mut commands: Commands, assets: Res) { )); commands.spawn(( AutoWidth { - aspect_ratio, + aspect_ratio: 1810.0 / 3840.0, open_top: true, parallax: -0.4, }, @@ -104,7 +105,7 @@ pub fn setup_city(mut commands: Commands, assets: Res) { transform: Transform::from_xyz(0.0, 0.0, -30.0), texture: assets.load("parallax/01_far_city.png"), sprite: Sprite { - custom_size: Some(Vec2::new(1.0, aspect_ratio)), + custom_size: Some(Vec2::new(1.0, 1810.0 / 3840.0)), anchor: Anchor::BottomCenter, ..Default::default() }, @@ -134,6 +135,7 @@ pub fn setup_city(mut commands: Commands, assets: Res) { pub fn update_auto_width( mut query: Query<(&AutoWidth, &mut Transform)>, transform: Query<(&GlobalTransform, &Camera), With>, + movement: Res, ) { let (camera_transform, camera) = transform.single(); let viewport = camera.logical_viewport_size().unwrap(); @@ -158,8 +160,7 @@ pub fn update_auto_width( for (auto_width, mut transform) in &mut query.iter_mut() { // the images should be scaled so they always fill the screen - transform.translation.y = - -VERTICAL_VIEWPORT_SIZE / 2.0 - camera_transform.translation().y * auto_width.parallax; + transform.translation.y = -movement.height * auto_width.parallax; if world_aspect_ratio > auto_width.aspect_ratio || auto_width.open_top { // the world is wider than the image diff --git a/src/environment/tow_truck.rs b/src/environment/tow_truck.rs index b8217c1..9b7d8e4 100644 --- a/src/environment/tow_truck.rs +++ b/src/environment/tow_truck.rs @@ -4,6 +4,7 @@ use bevy_rapier2d::prelude::*; use crate::environment::beam::BeamEvent; use crate::environment::car::{Car, CarCrashedEvent}; use crate::level::LevelLifecycle; +use crate::HORIZONTAL_VIEWPORT_SIZE; pub struct TowTruckPlugin; @@ -31,7 +32,7 @@ pub fn spawn_tow_truck_system( mut car_crashed_events: EventReader, ) { for event in car_crashed_events.read() { - let size = Vec2::new(60.0, 30.0); + let size = Vec2::new(8.0, 4.0); commands.spawn(( TowTruck { @@ -39,10 +40,10 @@ pub fn spawn_tow_truck_system( phase: TowTruckPhase::MovingToTarget, }, LevelLifecycle, - SpatialBundle::from(Transform::from_xyz(-1000.0, 0.0, 0.0)), + SpatialBundle::from(Transform::from_xyz(-HORIZONTAL_VIEWPORT_SIZE, 5.0, 0.0)), RigidBody::KinematicVelocityBased, Collider::cuboid(size.x / 2.0, size.y / 2.0), - Velocity::linear(Vec2::new(50.0, 0.0)), + Velocity::linear(Vec2::new(5.0, 0.0)), Sensor, )); } @@ -66,12 +67,12 @@ pub fn tow_car_system( .translation .distance(car_transform.translation); - if distance < 100.0 { + if distance < 5.0 { tow_truck.phase = TowTruckPhase::RaisingCar; beam_event_writer.send(BeamEvent { source: tow_truck_entity, target: car_entity, - source_offset: Vec3::new(15.0, 0.0, 0.0), + source_offset: Vec3::new(1.5, 0.0, 0.0), }); commands .entity(tow_truck_entity) @@ -79,7 +80,7 @@ pub fn tow_car_system( commands.entity(car_entity).insert(( RigidBody::KinematicVelocityBased, - Velocity::linear(Vec2::new(0.5, 15.0)), + Velocity::linear(Vec2::new(0.05, 1.5)), )); tow_truck_velocity.linvel = Vec2::ZERO; @@ -88,14 +89,14 @@ pub fn tow_car_system( } } TowTruckPhase::RaisingCar => { - if car_transform.translation.y > -30.0 { + if car_transform.translation.y > 1.6 { tow_truck.phase = TowTruckPhase::TowingTarget; commands .entity(car_entity) .insert((RigidBody::Fixed, Velocity::linear(Vec2::new(0.0, 0.0)))); car_velocity.linvel = Vec2::ZERO; - tow_truck_velocity.linvel = Vec2::new(50.0, 0.0); + tow_truck_velocity.linvel = Vec2::new(5.0, 0.0); } } TowTruckPhase::TowingTarget => {} diff --git a/src/launch_platform.rs b/src/launch_platform.rs index e9cf336..176a746 100644 --- a/src/launch_platform.rs +++ b/src/launch_platform.rs @@ -25,7 +25,7 @@ pub fn spawn_launch_platform_system(mut commands: Commands, mut assets: ResMut>, ) { for mut velocity in query.iter_mut() { - let max_velocity = 250.0; - let increment = 5.0; - let decrement = 5.0; + let max_velocity = 25.0; + let increment = 0.5; + let decrement = 0.5; /// WASD for launch platform if key_code.pressed(KeyCode::A) { diff --git a/src/level.rs b/src/level.rs index 7b3e9ac..865d2c1 100644 --- a/src/level.rs +++ b/src/level.rs @@ -1,5 +1,6 @@ use std::time::Duration; +use crate::base::BaseType; use bevy::prelude::*; use bevy_rapier2d::prelude::Velocity; @@ -50,7 +51,7 @@ pub enum UpdateLevelStats { #[derive(Debug, Clone)] pub struct LevelBase { - pub width: f32, + pub base_type: BaseType, pub translation: Vec2, pub rotation: f32, } @@ -70,8 +71,8 @@ pub struct LaunchPlatform { const fn default_level_base() -> LevelBase { LevelBase { - width: 100.0, - translation: Vec2::ZERO, + base_type: BaseType::T7, + translation: Vec2::new(0.0, 10.0), rotation: 0.0, } } @@ -93,11 +94,11 @@ pub const DEFAULT_EFFECTS: [(EffectType, f32); 2] = pub const DEFAULT_LEVEL: Level = Level { level: 0, - goal: LevelGoal::ReachHeight(200.0), + goal: LevelGoal::ReachHeight(20.0), time_limit: Some(Duration::from_secs(60)), max_blocks: None, bases: &[LevelBase { - width: 160.0, + base_type: BaseType::T9, ..default_level_base() }], enabled_effects: &DEFAULT_EFFECTS, @@ -121,11 +122,11 @@ pub static LEVELS: [Level; 6] = [ Level { level: 0, intro_text: "Test Level", - goal: LevelGoal::ReachHeight(200.0), + goal: LevelGoal::ReachHeight(15.0), time_limit: Some(Duration::from_secs(60)), max_blocks: None, bases: &[LevelBase { - width: 10000.0, + base_type: BaseType::T9, ..default_level_base() }], ..DEFAULT_LEVEL @@ -135,11 +136,11 @@ pub static LEVELS: [Level; 6] = [ intro_text: "Welcome to your first day at Big Bad Buildings, Inc. Your job is to operate the Tower Thrower 3000, a state-of-the-art machine that constructs buildings by throwing blocks.\ For your first building, reach a target height of 200m.\ ", - goal: LevelGoal::ReachHeight(200.0), + goal: LevelGoal::ReachHeight(20.0), time_limit: Some(Duration::from_secs(60)), max_blocks: None, bases: &[LevelBase { - width: 160.0, + base_type: BaseType::T9, ..default_level_base() }], ..DEFAULT_LEVEL @@ -150,18 +151,18 @@ pub static LEVELS: [Level; 6] = [ time_limit: Some(Duration::from_secs(60)), max_blocks: Some(13), bases: &[LevelBase { - width: 80.0, + base_type: BaseType::T4, ..default_level_base() }], ..DEFAULT_LEVEL }, Level { level: 3, - goal: LevelGoal::ReachHeight(200.0), + goal: LevelGoal::ReachHeight(20.0), time_limit: Some(Duration::from_secs(60)), max_blocks: Some(30), bases: &[LevelBase { - width: 120.0, + base_type: BaseType::T4, ..default_level_base() }], ..DEFAULT_LEVEL @@ -172,24 +173,24 @@ pub static LEVELS: [Level; 6] = [ time_limit: Some(Duration::from_secs(60)), max_blocks: Some(25), bases: &[LevelBase { - width: 100.0, + base_type: BaseType::T4, ..default_level_base() }], ..DEFAULT_LEVEL }, Level { level: 5, - goal: LevelGoal::ReachHeight(350.0), + goal: LevelGoal::ReachHeight(35.0), time_limit: Some(Duration::from_secs(60)), max_blocks: Some(25), bases: &[ LevelBase { - width: 60.0, + base_type: BaseType::T2, translation: Vec2::new(80.0, 0.0), ..default_level_base() }, LevelBase { - width: 60.0, + base_type: BaseType::T2, translation: Vec2::new(-80.0, 0.0), ..default_level_base() }, diff --git a/src/main.rs b/src/main.rs index ec764f8..39fc008 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,17 +43,17 @@ mod ui; #[derive(Component)] pub struct MainCamera; -pub const PIXELS_PER_METER: f32 = 100.0; -pub const GRAVITY: f32 = -9.81 * PIXELS_PER_METER; +pub const PIXELS_PER_METER: f32 = 1.0; +pub const GRAVITY: f32 = -9.81 * PIXELS_PER_METER * 2.0; pub const PHYSICS_DT: f32 = 1.0 / 60.0; -pub const VERTICAL_VIEWPORT_SIZE: f32 = 400.0; -pub const FLOOR_HEIGHT: f32 = -VERTICAL_VIEWPORT_SIZE / 2.0 + 10.0; +pub const HORIZONTAL_VIEWPORT_SIZE: f32 = 45.0; +pub const FLOOR_HEIGHT: f32 = 1.0; -pub const CAR_MIN_HEIGHT: f32 = FLOOR_HEIGHT + 20.0; +pub const CAR_MIN_HEIGHT: f32 = FLOOR_HEIGHT + 2.0; -pub const CAR_MAX_HEIGHT: f32 = FLOOR_HEIGHT / 2.0; +pub const CAR_MAX_HEIGHT: f32 = 7.0; fn main() { App::new() @@ -72,7 +72,11 @@ fn main() { }), RapierPhysicsPlugin::::pixels_per_meter(PIXELS_PER_METER) .in_fixed_schedule(), - RapierDebugRenderPlugin::default(), + { + let mut debug = RapierDebugRenderPlugin::default(); + debug.style.rigid_body_axes_length = 0.3; + debug + }, EguiPlugin, // Game plugins ( @@ -122,7 +126,7 @@ pub fn setup_graphics(mut commands: Commands, mut assets: ResMut) { projection: OrthographicProjection { far: 1000.0, near: -1000.0, - scaling_mode: ScalingMode::FixedVertical(VERTICAL_VIEWPORT_SIZE), + scaling_mode: ScalingMode::FixedHorizontal(HORIZONTAL_VIEWPORT_SIZE), ..OrthographicProjection::default() }, ..default() diff --git a/src/target_height_indicator.rs b/src/target_height_indicator.rs index ca11bd2..70b1952 100644 --- a/src/target_height_indicator.rs +++ b/src/target_height_indicator.rs @@ -33,7 +33,7 @@ pub fn setup_target_height_indicator( LevelLifecycle, SpriteBundle { sprite: Sprite { - custom_size: Some(Vec2::new(10000.0, 1.0)), + custom_size: Some(Vec2::new(1000.0, 0.1)), color: Color::rgb(1.0, 0.0, 0.0), ..Default::default() }, diff --git a/src/throw.rs b/src/throw.rs index 8fd610f..b9c694f 100644 --- a/src/throw.rs +++ b/src/throw.rs @@ -232,7 +232,7 @@ pub fn simulate_throw_system( transform: step, texture: assets.load("aim.png"), sprite: Sprite { - custom_size: Some(Vec2::new(2.0, 2.0)), + custom_size: Some(Vec2::new(0.2, 0.2)), ..Default::default() }, ..Default::default() @@ -247,7 +247,7 @@ pub fn simulate_throw_system( transform, texture: assets.load("aim.png"), sprite: Sprite { - custom_size: Some(Vec2::new(10.0, 10.0)), + custom_size: Some(Vec2::new(1.0, 1.0)), ..Default::default() }, ..Default::default() @@ -276,7 +276,7 @@ pub fn create_aiming_block( block_type, Vec2::new( launch_platform_transform.translation.x, - launch_platform_transform.translation.y + 35.0, + launch_platform_transform.translation.y + 0.0, ), &mut assets, ); @@ -291,7 +291,7 @@ pub fn update_aiming_block_position( let launch_platform_transform = launch_platform_query.single(); for (entity, mut transform) in query.iter_mut() { transform.translation.x = launch_platform_transform.translation.x; - transform.translation.y = launch_platform_transform.translation.y + 35.0; + transform.translation.y = launch_platform_transform.translation.y + 0.0; } } @@ -392,7 +392,7 @@ pub fn update_aim_from_mouse_position_system( direct_aim, ); if shot.is_none() { - min_force += 0.1; + min_force += 0.002; } else { break; }