WHAT HAPPENED AFTER A LONG STREAM
Player movement :D Uh..miguel not paralysed Failed to flip miguel when turning Please help
This commit is contained in:
66
Cargo.lock
generated
66
Cargo.lock
generated
@@ -826,6 +826,19 @@ version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61baa1bdc1f4a7ac2c18217570a7cc04e1cd54d38456e91782f0371c79afe0a8"
|
||||
|
||||
[[package]]
|
||||
name = "bevy_rapier2d"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17d82b9cbb851249a8859647ae3a2c5d17664df1da27ccd43fddd1faa66b58a6"
|
||||
dependencies = [
|
||||
"bevy",
|
||||
"bitflags 2.6.0",
|
||||
"log",
|
||||
"nalgebra",
|
||||
"rapier2d 0.21.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bevy_reflect"
|
||||
version = "0.14.2"
|
||||
@@ -2548,6 +2561,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"glam",
|
||||
"matrixmultiply",
|
||||
"nalgebra-macros",
|
||||
"num-complex",
|
||||
@@ -3061,6 +3075,30 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parry2d"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8aa1c304489b71ab35ad4080c5a333a5fc24b2a5f244f197dedb93276c9a05"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"arrayvec",
|
||||
"bitflags 2.6.0",
|
||||
"downcast-rs",
|
||||
"either",
|
||||
"log",
|
||||
"nalgebra",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"ordered-float",
|
||||
"rustc-hash 2.0.0",
|
||||
"simba",
|
||||
"slab",
|
||||
"smallvec",
|
||||
"spade",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parry2d"
|
||||
version = "0.17.1"
|
||||
@@ -3261,6 +3299,29 @@ version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab"
|
||||
|
||||
[[package]]
|
||||
name = "rapier2d"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a9a115cec2cd9533e376e23c87a7869508691a7b38ab078cc8a8e1cd24d9d1b"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"arrayvec",
|
||||
"bit-vec 0.6.3",
|
||||
"bitflags 2.6.0",
|
||||
"crossbeam",
|
||||
"downcast-rs",
|
||||
"log",
|
||||
"nalgebra",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"ordered-float",
|
||||
"parry2d 0.16.1",
|
||||
"rustc-hash 2.0.0",
|
||||
"simba",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rapier2d"
|
||||
version = "0.22.0"
|
||||
@@ -3278,7 +3339,7 @@ dependencies = [
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"ordered-float",
|
||||
"parry2d",
|
||||
"parry2d 0.17.1",
|
||||
"rustc-hash 2.0.0",
|
||||
"simba",
|
||||
"thiserror",
|
||||
@@ -3538,7 +3599,8 @@ dependencies = [
|
||||
"bevy",
|
||||
"bevy_ecs_ldtk",
|
||||
"bevy_ecs_tilemap",
|
||||
"rapier2d",
|
||||
"bevy_rapier2d",
|
||||
"rapier2d 0.22.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -8,3 +8,4 @@ bevy = "0.14.2"
|
||||
bevy_ecs_tilemap = "0.14"
|
||||
bevy_ecs_ldtk = "0.10"
|
||||
rapier2d = "0.22.0"
|
||||
bevy_rapier2d = "0.27.0"
|
||||
|
||||
@@ -391,7 +391,7 @@
|
||||
},
|
||||
{
|
||||
"__type": "IntGrid",
|
||||
"identifier": "Walls",
|
||||
"identifier": "Collisions",
|
||||
"type": "IntGrid",
|
||||
"uid": 4,
|
||||
"doc": null,
|
||||
@@ -794,7 +794,7 @@
|
||||
"limitScope": "PerLevel",
|
||||
"limitBehavior": "MoveLastOne",
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"pivotY": 1,
|
||||
"fieldDefs": []
|
||||
},
|
||||
{
|
||||
@@ -1256,21 +1256,21 @@
|
||||
{
|
||||
"__identifier": "Goal",
|
||||
"__grid": [34,12],
|
||||
"__pivot": [0.5,0.5],
|
||||
"__pivot": [0.5,1],
|
||||
"__tags": [],
|
||||
"__tile": { "tilesetUid": 36, "x": 0, "y": 0, "w": 16, "h": 16 },
|
||||
"__smartColor": "#EAD4AA",
|
||||
"iid": "ee9001c0-9b00-11ef-a60d-5b17cba2b0bd",
|
||||
"iid": "265d9ca0-9b00-11ef-8557-9dc0be7be55f",
|
||||
"width": 16,
|
||||
"height": 24,
|
||||
"defUid": 15,
|
||||
"px": [552,200],
|
||||
"px": [552,208],
|
||||
"fieldInstances": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"__identifier": "Walls",
|
||||
"__identifier": "Collisions",
|
||||
"__type": "IntGrid",
|
||||
"__cWid": 35,
|
||||
"__cHei": 20,
|
||||
@@ -1912,7 +1912,7 @@
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1
|
||||
],
|
||||
"autoLayerTiles": [
|
||||
@@ -1937,6 +1937,20 @@
|
||||
{ "px": [0,144], "src": [0,16], "f": 0, "t": 2, "d": [31,144], "a": 1 },
|
||||
{ "px": [240,144], "src": [0,0], "f": 0, "t": 0, "d": [31,159], "a": 1 },
|
||||
{ "px": [0,160], "src": [0,0], "f": 0, "t": 0, "d": [31,160], "a": 1 },
|
||||
{ "px": [16,160], "src": [0,16], "f": 0, "t": 2, "d": [31,161], "a": 1 },
|
||||
{ "px": [32,160], "src": [0,0], "f": 0, "t": 0, "d": [31,162], "a": 1 },
|
||||
{ "px": [48,160], "src": [0,16], "f": 0, "t": 2, "d": [31,163], "a": 1 },
|
||||
{ "px": [64,160], "src": [0,16], "f": 0, "t": 2, "d": [31,164], "a": 1 },
|
||||
{ "px": [80,160], "src": [0,0], "f": 0, "t": 0, "d": [31,165], "a": 1 },
|
||||
{ "px": [96,160], "src": [0,16], "f": 0, "t": 2, "d": [31,166], "a": 1 },
|
||||
{ "px": [112,160], "src": [0,16], "f": 0, "t": 2, "d": [31,167], "a": 1 },
|
||||
{ "px": [128,160], "src": [0,16], "f": 0, "t": 2, "d": [31,168], "a": 1 },
|
||||
{ "px": [144,160], "src": [0,0], "f": 0, "t": 0, "d": [31,169], "a": 1 },
|
||||
{ "px": [160,160], "src": [0,16], "f": 0, "t": 2, "d": [31,170], "a": 1 },
|
||||
{ "px": [176,160], "src": [0,0], "f": 0, "t": 0, "d": [31,171], "a": 1 },
|
||||
{ "px": [192,160], "src": [0,16], "f": 0, "t": 2, "d": [31,172], "a": 1 },
|
||||
{ "px": [208,160], "src": [0,0], "f": 0, "t": 0, "d": [31,173], "a": 1 },
|
||||
{ "px": [224,160], "src": [0,16], "f": 0, "t": 2, "d": [31,174], "a": 1 },
|
||||
{ "px": [240,160], "src": [0,16], "f": 0, "t": 2, "d": [31,175], "a": 1 }
|
||||
],
|
||||
"seed": 9045717,
|
||||
@@ -1992,22 +2006,7 @@
|
||||
"seed": 9284298,
|
||||
"overrideTilesetUid": null,
|
||||
"gridTiles": [],
|
||||
"entityInstances": [
|
||||
{
|
||||
"__identifier": "Player",
|
||||
"__grid": [1,9],
|
||||
"__pivot": [0.5,1],
|
||||
"__tags": [],
|
||||
"__tile": { "tilesetUid": 27, "x": 0, "y": 0, "w": 32, "h": 32 },
|
||||
"__smartColor": "#D77643",
|
||||
"iid": "8b5bc310-73f0-11ef-83af-53f2d18f6592",
|
||||
"width": 16,
|
||||
"height": 16,
|
||||
"defUid": 14,
|
||||
"px": [16,160],
|
||||
"fieldInstances": []
|
||||
}
|
||||
]
|
||||
"entityInstances": []
|
||||
},
|
||||
{
|
||||
"__identifier": "Player",
|
||||
@@ -2033,10 +2032,24 @@
|
||||
"overrideTilesetUid": null,
|
||||
"gridTiles": [],
|
||||
"entityInstances": [
|
||||
{
|
||||
"__identifier": "Player",
|
||||
"__grid": [1,9],
|
||||
"__pivot": [0.5,1],
|
||||
"__tags": [],
|
||||
"__tile": { "tilesetUid": 27, "x": 0, "y": 0, "w": 32, "h": 32 },
|
||||
"__smartColor": "#D77643",
|
||||
"iid": "8b5bc310-73f0-11ef-83af-53f2d18f6592",
|
||||
"width": 16,
|
||||
"height": 16,
|
||||
"defUid": 14,
|
||||
"px": [24,160],
|
||||
"fieldInstances": []
|
||||
},
|
||||
{
|
||||
"__identifier": "Goal",
|
||||
"__grid": [7,1],
|
||||
"__pivot": [0.5,0.5],
|
||||
"__grid": [13,6],
|
||||
"__pivot": [0.5,1],
|
||||
"__tags": [],
|
||||
"__tile": { "tilesetUid": 36, "x": 0, "y": 0, "w": 16, "h": 16 },
|
||||
"__smartColor": "#EAD4AA",
|
||||
@@ -2044,13 +2057,13 @@
|
||||
"width": 16,
|
||||
"height": 24,
|
||||
"defUid": 15,
|
||||
"px": [120,24],
|
||||
"px": [216,112],
|
||||
"fieldInstances": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"__identifier": "Walls",
|
||||
"__identifier": "Collisions",
|
||||
"__type": "IntGrid",
|
||||
"__cWid": 16,
|
||||
"__cHei": 11,
|
||||
@@ -2908,7 +2921,7 @@
|
||||
{
|
||||
"__identifier": "Goal",
|
||||
"__grid": [1,5],
|
||||
"__pivot": [0.5,0.5],
|
||||
"__pivot": [0.5,1],
|
||||
"__tags": [],
|
||||
"__tile": { "tilesetUid": 36, "x": 0, "y": 0, "w": 16, "h": 16 },
|
||||
"__smartColor": "#EAD4AA",
|
||||
@@ -2922,7 +2935,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"__identifier": "Walls",
|
||||
"__identifier": "Collisions",
|
||||
"__type": "IntGrid",
|
||||
"__cWid": 85,
|
||||
"__cHei": 14,
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use bevy::prelude::*;
|
||||
use bevy_ecs_ldtk::prelude::*;
|
||||
|
||||
use crate::player::Player;
|
||||
|
||||
|
||||
pub struct CameraPlugin;
|
||||
|
||||
impl Plugin for CameraPlugin {
|
||||
|
||||
11
src/goal.rs
11
src/goal.rs
@@ -17,13 +17,16 @@ pub struct GoalBundle {
|
||||
|
||||
pub fn check_goal(
|
||||
level_selection: ResMut<LevelSelection>,
|
||||
players: Query<&GridCoords, (With<Player>, Changed<GridCoords>)>,
|
||||
goals: Query<&GridCoords, With<Goal>>,
|
||||
players: Query<&Transform, (With<Player>, Changed<Transform>)>,
|
||||
goals: Query<&Transform, With<Goal>>,
|
||||
) {
|
||||
if players
|
||||
.iter()
|
||||
.zip(goals.iter())
|
||||
.any(|(player_grid_coords, goal_grid_coords)| player_grid_coords == goal_grid_coords)
|
||||
.any(|(player_grid_coords, goal_grid_coords)| {
|
||||
((player_grid_coords.translation.x - goal_grid_coords.translation.x).abs() <= 3.)
|
||||
&& ((player_grid_coords.translation.y - goal_grid_coords.translation.y).abs() <= 3.)
|
||||
})
|
||||
{
|
||||
let indices = match level_selection.into_inner() {
|
||||
LevelSelection::Indices(indices) => indices,
|
||||
@@ -32,4 +35,4 @@ pub fn check_goal(
|
||||
|
||||
indices.level += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
use bevy::prelude::*;
|
||||
use bevy::{
|
||||
prelude::*,
|
||||
utils::{HashMap, HashSet},
|
||||
};
|
||||
use bevy_ecs_ldtk::prelude::*;
|
||||
use bevy_rapier2d::{
|
||||
dynamics::RigidBody,
|
||||
geometry::{Collider, Friction},
|
||||
};
|
||||
|
||||
#[derive(Default, Component)]
|
||||
pub struct Wall;
|
||||
@@ -8,3 +15,148 @@ pub struct Wall;
|
||||
pub struct WallBundle {
|
||||
wall: Wall,
|
||||
}
|
||||
pub fn spawn_wall_collision(
|
||||
mut commands: Commands,
|
||||
wall_query: Query<(&GridCoords, &Parent), Added<Wall>>,
|
||||
parent_query: Query<&Parent, Without<Wall>>,
|
||||
level_query: Query<(Entity, &LevelIid)>,
|
||||
ldtk_projects: Query<&Handle<LdtkProject>>,
|
||||
ldtk_project_assets: Res<Assets<LdtkProject>>,
|
||||
) {
|
||||
/// Represents a wide wall that is 1 tile tall
|
||||
/// Used to spawn wall collisions
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Default, Hash)]
|
||||
struct Plate {
|
||||
left: i32,
|
||||
right: i32,
|
||||
}
|
||||
|
||||
/// A simple rectangle type representing a wall of any size
|
||||
struct Rect {
|
||||
left: i32,
|
||||
right: i32,
|
||||
top: i32,
|
||||
bottom: i32,
|
||||
}
|
||||
let mut level_to_wall_locations: HashMap<Entity, HashSet<GridCoords>> = HashMap::new();
|
||||
wall_query.iter().for_each(|(&grid_coords, parent)| {
|
||||
if let Ok(grandparent) = parent_query.get(parent.get()) {
|
||||
level_to_wall_locations
|
||||
.entry(grandparent.get())
|
||||
.or_default()
|
||||
.insert(grid_coords);
|
||||
}
|
||||
});
|
||||
|
||||
if !wall_query.is_empty() {
|
||||
level_query.iter().for_each(|(level_entity, level_iid)| {
|
||||
if let Some(level_walls) = level_to_wall_locations.get(&level_entity) {
|
||||
let ldtk_project = ldtk_project_assets
|
||||
.get(ldtk_projects.single())
|
||||
.expect("Project has to be loaded at this point");
|
||||
|
||||
let level = ldtk_project
|
||||
.as_standalone()
|
||||
.get_loaded_level_by_iid(&level_iid.to_string())
|
||||
.expect("Spawned level should exist in LDtk project");
|
||||
|
||||
let LayerInstance {
|
||||
c_wid: width,
|
||||
c_hei: height,
|
||||
grid_size,
|
||||
..
|
||||
} = level.layer_instances()[0];
|
||||
|
||||
let mut plate_stack: Vec<Vec<Plate>> = Vec::new();
|
||||
|
||||
for y in 0..height {
|
||||
let mut row_plates: Vec<Plate> = Vec::new();
|
||||
let mut plate_start = None;
|
||||
|
||||
for x in 0..width + 1 {
|
||||
match (plate_start, level_walls.contains(&GridCoords { x, y })) {
|
||||
(Some(s), false) => {
|
||||
row_plates.push(Plate {
|
||||
left: s,
|
||||
right: x - 1,
|
||||
});
|
||||
plate_start = None;
|
||||
}
|
||||
(None, true) => plate_start = Some(x),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
plate_stack.push(row_plates);
|
||||
}
|
||||
// combine "plates" into rectangles across multiple rows
|
||||
let mut rect_builder: HashMap<Plate, Rect> = HashMap::new();
|
||||
let mut prev_row: Vec<Plate> = Vec::new();
|
||||
let mut wall_rects: Vec<Rect> = Vec::new();
|
||||
|
||||
// an extra empty row so the algorithm "finishes" the rects that touch the top edge
|
||||
plate_stack.push(Vec::new());
|
||||
|
||||
for (y, current_row) in plate_stack.into_iter().enumerate() {
|
||||
for prev_plate in &prev_row {
|
||||
if !current_row.contains(prev_plate) {
|
||||
//remove rect so the same plate starts a new rectangle
|
||||
if let Some(rect) = rect_builder.remove(prev_plate) {
|
||||
wall_rects.push(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
for plate in ¤t_row {
|
||||
rect_builder
|
||||
.entry(plate.clone())
|
||||
.and_modify(|e| e.top += 1)
|
||||
.or_insert(Rect {
|
||||
bottom: y as i32,
|
||||
top: y as i32,
|
||||
left: plate.left,
|
||||
right: plate.right,
|
||||
});
|
||||
}
|
||||
prev_row = current_row;
|
||||
}
|
||||
commands.entity(level_entity).with_children(|level| {
|
||||
// Spawn colliders for every rectangle..
|
||||
// Making the collider a child of the level serves two purposes:
|
||||
// 1. Adjusts the transforms to be relative to the level for free
|
||||
// 2. the colliders will be despawned automatically when levels unload
|
||||
for wall_rect in wall_rects {
|
||||
level
|
||||
.spawn_empty()
|
||||
.insert(Collider::cuboid(
|
||||
(wall_rect.right as f32 - wall_rect.left as f32 + 1.)
|
||||
* grid_size as f32
|
||||
/ 2.,
|
||||
(wall_rect.top as f32 - wall_rect.bottom as f32 + 1.)
|
||||
* grid_size as f32
|
||||
/ 2.,
|
||||
))
|
||||
.insert(RigidBody::Fixed)
|
||||
.insert(Friction::new(1.0))
|
||||
.insert(Transform::from_xyz(
|
||||
(wall_rect.left + wall_rect.right + 1) as f32 * grid_size as f32
|
||||
/ 2.,
|
||||
(wall_rect.bottom + wall_rect.top + 1) as f32 * grid_size as f32
|
||||
/ 2.,
|
||||
0.,
|
||||
//this averages xy so it in center yes )
|
||||
))
|
||||
.insert(GlobalTransform::default());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
pub struct WallPlugin;
|
||||
|
||||
impl Plugin for WallPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(Update, spawn_wall_collision)
|
||||
.register_ldtk_int_cell::<WallBundle>(1) //dirt
|
||||
.register_ldtk_int_cell::<WallBundle>(3); //stone
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::player::Player;
|
||||
use crate::{goal::Goal, player::Player};
|
||||
|
||||
// Yes I used chatgpt for this
|
||||
// sue me, it's a mundane task :P
|
||||
@@ -8,6 +8,7 @@ use crate::player::Player;
|
||||
pub fn log_positions(
|
||||
camera_query: Query<&Transform, With<Camera2d>>,
|
||||
player_query: Query<&Transform, With<Player>>,
|
||||
goals: Query<&Transform, With<Goal>>,
|
||||
) {
|
||||
// Log camera position
|
||||
if let Ok(camera_transform) = camera_query.get_single() {
|
||||
@@ -22,4 +23,9 @@ pub fn log_positions(
|
||||
} else {
|
||||
info!("Player not found or multiple players detected.");
|
||||
}
|
||||
if let Ok(goal_transform) = goals.get_single() {
|
||||
info!("Player Position: {:?}", goal_transform.translation);
|
||||
} else {
|
||||
info!("Player not found or multiple players detected.");
|
||||
}
|
||||
}
|
||||
|
||||
41
src/main.rs
41
src/main.rs
@@ -1,29 +1,49 @@
|
||||
use bevy::prelude::*;
|
||||
use bevy_ecs_ldtk::prelude::*;
|
||||
use bevy_rapier2d::plugin::{NoUserData, RapierConfiguration, RapierPhysicsPlugin, TimestepMode};
|
||||
use camera::CameraPlugin;
|
||||
use goal::{check_goal, GoalBundle};
|
||||
use ground_detection::GroundDetectionPlugin;
|
||||
use level_structure::{WallBundle, WallPlugin};
|
||||
use logging::log_positions;
|
||||
use player::PlayerPlugin;
|
||||
use goal::{GoalBundle, check_goal};
|
||||
use level_structure::WallBundle;
|
||||
|
||||
mod camera;
|
||||
mod colliders;
|
||||
mod goal;
|
||||
mod ground_detection;
|
||||
mod level_structure;
|
||||
mod logging;
|
||||
mod player;
|
||||
mod goal;
|
||||
mod level_structure;
|
||||
|
||||
pub const GRID_SIZE: i32 = 16;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
|
||||
.add_plugins(LdtkPlugin)
|
||||
.add_plugins((
|
||||
LdtkPlugin,
|
||||
RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(100.0),
|
||||
))
|
||||
.insert_resource(RapierConfiguration {
|
||||
gravity: Vec2::new(0.0, -2000.0),
|
||||
physics_pipeline_active: true,
|
||||
query_pipeline_active: true,
|
||||
timestep_mode: TimestepMode::Variable {
|
||||
max_dt: 1.0 / 60.0,
|
||||
time_scale: 1.0,
|
||||
substeps: 1,
|
||||
},
|
||||
scaled_shape_subdivision: 10,
|
||||
force_update_from_transform_changes: false,
|
||||
})
|
||||
.add_plugins(PlayerPlugin)
|
||||
.add_plugins(WallPlugin)
|
||||
.add_plugins(GroundDetectionPlugin)
|
||||
.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)
|
||||
@@ -33,14 +53,10 @@ fn main() {
|
||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
commands.spawn(LdtkWorldBundle {
|
||||
ldtk_handle: asset_server.load("shocked-miguel.ldtk"),
|
||||
level_set: LEVEL_SET,
|
||||
// transform: Transform::from_xyz(-256., -144., 0.),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn translate_grid_coords_entities(
|
||||
mut grid_coords_entities: Query<(&mut Transform, &GridCoords), Changed<GridCoords>>,
|
||||
) {
|
||||
@@ -50,8 +66,3 @@ fn translate_grid_coords_entities(
|
||||
.extend(transform.translation.z);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Component)]
|
||||
struct Wall;
|
||||
|
||||
|
||||
|
||||
176
src/player.rs
176
src/player.rs
@@ -1,11 +1,28 @@
|
||||
use bevy::{prelude::*, utils::HashSet};
|
||||
use bevy::prelude::*;
|
||||
use bevy_ecs_ldtk::prelude::*;
|
||||
use bevy_rapier2d::dynamics::Velocity;
|
||||
|
||||
use crate::level_structure::Wall;
|
||||
use crate::{colliders::ColliderBundle, ground_detection::GroundDetection, level_structure::Wall};
|
||||
use std::f32::consts::PI;
|
||||
|
||||
#[derive(Default)]
|
||||
enum Facing {
|
||||
LEFT,
|
||||
#[default]
|
||||
RIGHT,
|
||||
}
|
||||
#[derive(Default, Component)]
|
||||
pub(crate) struct Player;
|
||||
|
||||
pub(crate) struct Player {
|
||||
direction: Facing,
|
||||
}
|
||||
impl Player {
|
||||
fn swap_direction(&mut self) {
|
||||
match self.direction {
|
||||
Facing::RIGHT => self.direction = Facing::LEFT,
|
||||
Facing::LEFT => self.direction = Facing::RIGHT
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Default, Bundle, LdtkEntity)]
|
||||
struct PlayerBundle {
|
||||
player: Player,
|
||||
@@ -13,85 +30,112 @@ struct PlayerBundle {
|
||||
sprite_bundle: LdtkSpriteSheetBundle,
|
||||
#[grid_coords]
|
||||
grid_coords: GridCoords,
|
||||
pub ground_detection: GroundDetection,
|
||||
#[from_entity_instance]
|
||||
pub collider_bundle: ColliderBundle,
|
||||
}
|
||||
|
||||
#[derive(Default, Resource)]
|
||||
struct LevelWalls {
|
||||
wall_locations: HashSet<GridCoords>,
|
||||
level_width: i32,
|
||||
level_height: i32,
|
||||
}
|
||||
impl LevelWalls {
|
||||
fn in_wall(&self, grid_coords: &GridCoords) -> bool {
|
||||
grid_coords.x < 0
|
||||
|| grid_coords.y < 0
|
||||
|| grid_coords.x >= self.level_width
|
||||
|| grid_coords.y >= self.level_height
|
||||
|| self.wall_locations.contains(grid_coords)
|
||||
}
|
||||
}
|
||||
// #[derive(Default, Resource)]
|
||||
// struct LevelWalls {
|
||||
// wall_locations: HashSet<GridCoords>,
|
||||
// level_width: i32,
|
||||
// level_height: i32,
|
||||
// }
|
||||
// impl LevelWalls {
|
||||
// fn in_wall(&self, grid_coords: &GridCoords) -> bool {
|
||||
// grid_coords.x < 0
|
||||
// || grid_coords.y < 0
|
||||
// || grid_coords.x >= self.level_width
|
||||
// || grid_coords.y >= self.level_height
|
||||
// || self.wall_locations.contains(grid_coords)
|
||||
// }
|
||||
// }
|
||||
|
||||
fn move_player_from_input(
|
||||
mut players: Query<&mut GridCoords, With<Player>>,
|
||||
fn player_movement(
|
||||
mut query: Query<(&mut Velocity, &GroundDetection, &Player), With<Player>>,
|
||||
input: Res<ButtonInput<KeyCode>>,
|
||||
level_walls: Res<LevelWalls>,
|
||||
) {
|
||||
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)
|
||||
} else if input.just_pressed(KeyCode::KeyS) {
|
||||
GridCoords::new(0, -1)
|
||||
} else if input.just_pressed(KeyCode::KeyD) {
|
||||
GridCoords::new(1, 0)
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
// 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)
|
||||
// } else if input.just_pressed(KeyCode::KeyS) {
|
||||
// GridCoords::new(0, -1)
|
||||
// } else if input.just_pressed(KeyCode::KeyD) {
|
||||
// GridCoords::new(1, 0)
|
||||
// } else {
|
||||
// return;
|
||||
// };
|
||||
for (mut velocity, ground_detection, player) in &mut query {
|
||||
// let right = if input.pressed(KeyCode::KeyD) { 1. } else { 0. };
|
||||
// let left = if input.pressed(KeyCode::KeyA) { 1. } else { 0. };
|
||||
|
||||
for mut player_grid_coords in players.iter_mut() {
|
||||
let destination = *player_grid_coords + movement_direction;
|
||||
if !level_walls.in_wall(&destination) {
|
||||
*player_grid_coords = destination;
|
||||
let right = if input.pressed(KeyCode::KeyD) {
|
||||
// match player.direction {
|
||||
// Facing::LEFT => player.direction = Facing::RIGHT,
|
||||
// Facing::RIGHT => (),
|
||||
|
||||
// }
|
||||
1.
|
||||
|
||||
} else {
|
||||
0.
|
||||
};
|
||||
let left = if input.pressed(KeyCode::KeyA) {
|
||||
1.
|
||||
} else {
|
||||
0.
|
||||
};
|
||||
velocity.linvel.x = (right - left) * 200.;
|
||||
|
||||
if input.just_pressed(KeyCode::Space) && ground_detection.on_ground {
|
||||
velocity.linvel.y = 500.;
|
||||
}
|
||||
}
|
||||
|
||||
// for mut player_grid_coords in players.iter_mut() {
|
||||
// let destination = *player_grid_coords + movement_direction;
|
||||
// if !level_walls.in_wall(&destination) {
|
||||
// *player_grid_coords = destination;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
pub struct PlayerPlugin;
|
||||
|
||||
impl Plugin for PlayerPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(Update, (move_player_from_input, cache_wall_locations))
|
||||
.register_ldtk_entity::<PlayerBundle>("Player")
|
||||
.init_resource::<LevelWalls>();
|
||||
app.add_systems(Update, player_movement)
|
||||
.register_ldtk_entity::<PlayerBundle>("Player");
|
||||
}
|
||||
}
|
||||
|
||||
fn cache_wall_locations(
|
||||
mut level_walls: ResMut<LevelWalls>,
|
||||
mut level_events: EventReader<LevelEvent>,
|
||||
walls: Query<&GridCoords, With<Wall>>,
|
||||
ldtk_project_entities: Query<&Handle<LdtkProject>>,
|
||||
ldtk_project_assets: Res<Assets<LdtkProject>>,
|
||||
) {
|
||||
for level_event in level_events.read() {
|
||||
if let LevelEvent::Spawned(level_iid) = level_event {
|
||||
let ldtk_project = ldtk_project_assets
|
||||
.get(ldtk_project_entities.single())
|
||||
.expect("LdtkProject should be loaded when level is spawned");
|
||||
let level = ldtk_project
|
||||
.get_raw_level_by_iid(level_iid.get())
|
||||
.expect("spawned level should exist in project");
|
||||
// fn cache_wall_locations(
|
||||
// mut level_walls: ResMut<LevelWalls>,
|
||||
// mut level_events: EventReader<LevelEvent>,
|
||||
// walls: Query<&GridCoords, With<Wall>>,
|
||||
// ldtk_project_entities: Query<&Handle<LdtkProject>>,
|
||||
// ldtk_project_assets: Res<Assets<LdtkProject>>,
|
||||
// ) {
|
||||
// for level_event in level_events.read() {
|
||||
// if let LevelEvent::Spawned(level_iid) = level_event {
|
||||
// let ldtk_project = ldtk_project_assets
|
||||
// .get(ldtk_project_entities.single())
|
||||
// .expect("LdtkProject should be loaded when level is spawned");
|
||||
// let level = ldtk_project
|
||||
// .get_raw_level_by_iid(level_iid.get())
|
||||
// .expect("spawned level should exist in project");
|
||||
|
||||
let wall_locations = walls.iter().copied().collect();
|
||||
// let wall_locations = walls.iter().copied().collect();
|
||||
|
||||
let new_level_walls = LevelWalls {
|
||||
wall_locations,
|
||||
level_width: level.px_wid / crate::GRID_SIZE,
|
||||
level_height: level.px_hei / crate::GRID_SIZE,
|
||||
};
|
||||
// let new_level_walls = LevelWalls {
|
||||
// wall_locations,
|
||||
// level_width: level.px_wid / crate::GRID_SIZE,
|
||||
// level_height: level.px_hei / crate::GRID_SIZE,
|
||||
// };
|
||||
|
||||
*level_walls = new_level_walls;
|
||||
}
|
||||
}
|
||||
}
|
||||
// *level_walls = new_level_walls;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user