Merge branch 'camera-fuckery'

This commit is contained in:
2024-11-06 21:15:46 +02:00
1081 changed files with 1462 additions and 834 deletions

View File

@@ -69,33 +69,57 @@ pub fn camera_fit_inside_current_level(
}
}
}
const CAMERA_DECAY_RATE: f32 = 2.;
fn update_camera(
mut camera_query: Query<
(
&mut bevy::render::camera::OrthographicProjection,
&mut Transform,
),
Without<Player>,
>,
player_query: Query<&Transform, With<Player>>,
time: Res<Time>,
) {
if let Ok(Transform {
translation: player_translation,
..
}) = player_query.get_single()
{
let player_translation = *player_translation;
use crate::player::Player;
let (mut orthographic_projection, mut camera_transform) = camera_query.single_mut();
let Vec3 { x, y, .. } = player_translation;
let direction = Vec3::new(x, y, camera_transform.translation.z);
pub struct CameraPlugin;
// Applies a smooth effect to camera movement using stable interpolation
// between the camera position and the player position on the x and y axes.
camera_transform
.translation += direction;
impl Plugin for CameraPlugin {
fn build(&self, app: &mut App) {
// Spawn in the camera on startup, only 1 instance
app.add_systems(Startup, spawn_camera);
// We're so good..
// Update the camera position ever game loop iteration
app.add_systems(Update, move_camera);
}
}
fn spawn_camera(mut commands: Commands) {
let mut camera = Camera2dBundle::default();
// Bigger decimal, further it zooms in
// 0.5 is closer to level than 1.0
camera.projection.scale = 0.3;
commands.spawn(camera);
}
// THIS NEEDS TO BE IN THE UPDATE LOOP LOL
// We don't need to get player position to snap
// when spawning, it does that here lol
// - Mjork
fn move_camera(
mut camera: Query<&mut Transform, (With<Camera2d>, Without<Player>)>,
player: Query<&Transform, (With<Player>, Without<Camera2d>)>,
time: Res<Time>,
) {
// Get the only instance of camera
let Ok(mut camera) = camera.get_single_mut() else {
return;
};
// Get the only instance of player MIGUEL
let Ok(player) = player.get_single() else {
return;
};
// Smoothly follow the player
let player_position = Vec3::new(
player.translation.x,
player.translation.y,
camera.translation.z,
);
camera.translation = camera
.translation
.lerp(player_position, time.delta_seconds() * 2.0);
}

35
src/goal.rs Normal file
View File

@@ -0,0 +1,35 @@
use bevy::prelude::*;
use bevy_ecs_ldtk::prelude::*;
use crate::player::Player;
#[derive(Default, Component)]
pub struct Goal;
#[derive(Default, Bundle, LdtkEntity)]
pub struct GoalBundle {
goal: Goal,
#[sprite_sheet_bundle]
sprite_sheet_bundle: LdtkSpriteSheetBundle,
#[grid_coords]
grid_coords: GridCoords,
}
pub fn check_goal(
level_selection: ResMut<LevelSelection>,
players: Query<&GridCoords, (With<Player>, Changed<GridCoords>)>,
goals: Query<&GridCoords, With<Goal>>,
) {
if players
.iter()
.zip(goals.iter())
.any(|(player_grid_coords, goal_grid_coords)| player_grid_coords == goal_grid_coords)
{
let indices = match level_selection.into_inner() {
LevelSelection::Indices(indices) => indices,
_ => panic!("level selection should always be Indices in this game"),
};
indices.level += 1;
}
}

10
src/level_structure.rs Normal file
View File

@@ -0,0 +1,10 @@
use bevy::prelude::*;
use bevy_ecs_ldtk::prelude::*;
#[derive(Default, Component)]
pub struct Wall;
#[derive(Default, Bundle, LdtkIntCell)]
pub struct WallBundle {
wall: Wall,
}

25
src/logging.rs Normal file
View File

@@ -0,0 +1,25 @@
use bevy::prelude::*;
use crate::player::Player;
// Yes I used chatgpt for this
// sue me, it's a mundane task :P
// - Mjork
pub fn log_positions(
camera_query: Query<&Transform, With<Camera2d>>,
player_query: Query<&Transform, With<Player>>,
) {
// Log camera position
if let Ok(camera_transform) = camera_query.get_single() {
info!("Camera Position: {:?}", camera_transform.translation);
} else {
info!("Camera not found or multiple cameras detected.");
}
// Log player position
if let Ok(player_transform) = player_query.get_single() {
info!("Player Position: {:?}", player_transform.translation);
} else {
info!("Player not found or multiple players detected.");
}
}

View File

@@ -1,9 +1,18 @@
use bevy::prelude::*;
use bevy_ecs_ldtk::prelude::*;
use player::{Player, PlayerPlugin};
use camera::CameraPlugin;
use logging::log_positions;
use player::PlayerPlugin;
use goal::{GoalBundle, check_goal};
use level_structure::WallBundle;
mod camera;
mod logging;
mod player;
mod goal;
mod level_structure;
pub const GRID_SIZE: i32 = 16;
const LEVEL_SET: [&str; 2] = [
"ee0d1601-73f0-11ef-b8f3-190460ac7628",
@@ -14,43 +23,28 @@ fn main() {
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
.add_plugins(LdtkPlugin)
.add_plugins(PlayerPlugin)
.add_systems(Update, (translate_grid_coords_entities, check_goal))
.insert_resource(LevelSelection::index(0))
.register_ldtk_entity::<GoalBundle>("Goal")
.register_ldtk_int_cell::<WallBundle>(1)
.add_systems(Startup, setup)
.add_systems(Update, camera::camera_fit_inside_current_level)
.add_plugins(CameraPlugin)
.add_systems(Update, (translate_grid_coords_entities, check_goal))
.add_systems(Update, log_positions)
.run();
}
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
let mut camera = Camera2dBundle::default();
let level_set = LevelSet::from_iids(LEVEL_SET);
camera.projection.scale = 1.111;
camera.transform.translation.x += 1280.0 / 4.0;
camera.transform.translation.y += 720.0 / 4.0;
commands.spawn(camera);
commands.spawn(LdtkWorldBundle {
ldtk_handle: asset_server.load("shocked-miguel.ldtk"),
level_set,
level_set: LEVEL_SET,
// transform: Transform::from_xyz(-256., -144., 0.),
..Default::default()
});
}
#[derive(Default, Component)]
struct Goal;
#[derive(Default, Bundle, LdtkEntity)]
struct GoalBundle {
goal: Goal,
#[sprite_sheet_bundle]
sprite_sheet_bundle: LdtkSpriteSheetBundle,
#[grid_coords]
grid_coords: GridCoords,
}
pub const GRID_SIZE: i32 = 16;
fn translate_grid_coords_entities(
mut grid_coords_entities: Query<(&mut Transform, &GridCoords), Changed<GridCoords>>,
) {
@@ -64,33 +58,4 @@ fn translate_grid_coords_entities(
#[derive(Default, Component)]
struct Wall;
#[derive(Default, Bundle, LdtkIntCell)]
struct WallBundle {
wall: Wall,
}
fn check_goal(
level_selection: ResMut<LevelSelection>,
players: Query<&GridCoords, (With<Player>, Changed<GridCoords>)>,
goals: Query<&GridCoords, With<Goal>>,
mut camera_query: Query<
(
&mut bevy::render::camera::OrthographicProjection,
&mut Transform,
),
Without<Player>,
>,
) {
if players
.iter()
.zip(goals.iter())
.any(|(player_grid_coords, goal_grid_coords)| player_grid_coords == goal_grid_coords)
{
let indices = match level_selection.into_inner() {
LevelSelection::Indices(indices) => indices,
_ => panic!("level selection should always be Indices in this game"),
};
indices.level += 1;
}
}

View File

@@ -1,7 +1,7 @@
use bevy::{prelude::*, utils::HashSet};
use bevy_ecs_ldtk::prelude::*;
use crate::{Wall, GRID_SIZE};
use crate::level_structure::Wall;
#[derive(Default, Component)]
pub(crate) struct Player;
@@ -36,7 +36,8 @@ fn move_player_from_input(
input: Res<ButtonInput<KeyCode>>,
level_walls: Res<LevelWalls>,
) {
let movement_direction = if input.just_pressed(KeyCode::KeyW) {
let movement_direction =
if input.just_pressed(KeyCode::KeyW) || input.just_pressed(KeyCode::Space) {
GridCoords::new(0, 1)
} else if input.just_pressed(KeyCode::KeyA) {
GridCoords::new(-1, 0)
@@ -86,8 +87,8 @@ fn cache_wall_locations(
let new_level_walls = LevelWalls {
wall_locations,
level_width: level.px_wid / GRID_SIZE,
level_height: level.px_hei / GRID_SIZE,
level_width: level.px_wid / crate::GRID_SIZE,
level_height: level.px_hei / crate::GRID_SIZE,
};
*level_walls = new_level_walls;