Skip to content

Commit

Permalink
Very basic image-based collision!
Browse files Browse the repository at this point in the history
  • Loading branch information
bas-ie committed Jan 12, 2025
1 parent c877474 commit a6dcb71
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 482 deletions.
403 changes: 47 additions & 356 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ edition = "2024"
version = "0.1.0"

[dependencies]
avian2d = { git = "https://github.com/Jondolf/avian", branch = "main" }
bevy = "0.15.0"
bevy = "0.15"
bevy_asset_loader = { features = ["2d", "standard_dynamic_assets"], version = "0.22.0" }
bevy-inspector-egui = { optional = true, version = "0.28.0" }
bevy_sparse_tilemap = "0.4.0"
Expand Down
Binary file added assets/textures/level.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/textures/yup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 16 additions & 2 deletions src/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,22 @@ use bevy_asset_loader::prelude::*;
use crate::screens::Screen;

pub fn plugin(app: &mut App) {
app.add_loading_state(LoadingState::new(Screen::Loading).continue_to_state(Screen::Title));
app.add_loading_state(
LoadingState::new(Screen::Loading)
.continue_to_state(Screen::Title)
.load_collection::<Characters>()
.load_collection::<Levels>(),
);
}

#[derive(AssetCollection, Resource)]
pub struct Textures {}
pub struct Levels {
#[asset(path = "textures/level.png")]
pub level: Handle<Image>,
}

#[derive(AssetCollection, Resource)]
pub struct Characters {
#[asset(path = "textures/yup.png")]
pub yup: Handle<Image>,
}
14 changes: 1 addition & 13 deletions src/dev_tools.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use avian2d::prelude::*;
use bevy::{
dev_tools::{
states::log_transitions,
ui_debug_overlay::{DebugUiPlugin, UiDebugOptions},
},
diagnostic::FrameTimeDiagnosticsPlugin,
input::common_conditions::{input_just_pressed, input_toggle_active},
prelude::*,
};
Expand All @@ -22,20 +20,10 @@ pub(super) fn plugin(app: &mut App) {

// bevy_inspector_egui
app.add_plugins(WorldInspectorPlugin::default().run_if(input_toggle_active(false, TOGGLE_KEY)));

// Avian
app.add_plugins((FrameTimeDiagnosticsPlugin, PhysicsDebugPlugin::default()));
app.insert_gizmo_config(PhysicsGizmos::default(), GizmoConfig {
// Off by default, enables with toggle key
enabled: false,
..default()
});
}

const TOGGLE_KEY: KeyCode = KeyCode::Backquote;

fn toggle_debug(mut config_store: ResMut<GizmoConfigStore>, mut options: ResMut<UiDebugOptions>) {
let config = config_store.config_mut::<PhysicsGizmos>().0;
config.enabled = !config.enabled;
fn toggle_debug(mut options: ResMut<UiDebugOptions>) {
options.toggle();
}
9 changes: 4 additions & 5 deletions src/game/movement.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use avian2d::prelude::*;
use bevy::prelude::*;

use crate::screens::ingame::playing::MovementSpeed;
Expand All @@ -7,8 +6,8 @@ pub fn plugin(app: &mut App) {
app.add_systems(FixedUpdate, movement);
}

fn movement(mut moving_objects: Query<(&mut LinearVelocity, &MovementSpeed)>) {
for (mut lv, speed) in &mut moving_objects {
lv.x = speed.0;
}
fn movement(mut moving_objects: Query<(&MovementSpeed)>) {
// for (mut lv, speed) in &mut moving_objects {
// lv.x = speed.0;
// }
}
46 changes: 27 additions & 19 deletions src/game/yup.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
use avian2d::prelude::*;
use bevy::prelude::*;

use crate::screens::ingame::playing::{MovementSpeed, Obstacle};
use crate::{
assets::Characters,
physics::Gravity,
screens::{Screen, ingame::playing},
};

#[derive(Component, Debug, Default, Eq, PartialEq)]
pub enum CharacterState {
#[default]
Falling,
Walking,
}

#[derive(Component, Debug)]
#[require(CharacterState)]
pub struct Yup;

pub fn plugin(app: &mut App) {
app.add_systems(PostProcessCollisions, collision_handler);
// TODO: this .after is a bit cursed, come up with better spawning logic.
app.add_systems(OnEnter(Screen::InGame), init.after(playing::init));
}

fn collision_handler(
mut collisions: ResMut<Collisions>,
obstacles: Query<Entity, With<Obstacle>>,
mut yups: Query<(Entity, &mut MovementSpeed), With<Yup>>,
) {
// For now, we'll ignore all collisions between yups.
// TODO: sometimes blockers will need to be collided with!
collisions.retain(|c| yups.get(c.entity1).is_err() || yups.get(c.entity2).is_err());

for (yup, mut speed) in &mut yups {
for obstacle in &obstacles {
if collisions.contains(yup, obstacle) {
*speed = MovementSpeed(-speed.0);
}
}
}
fn init(mut commands: Commands, characters: Res<Characters>) {
commands.spawn((
Name::new("Yup"),
Yup,
Gravity,
Sprite {
image: characters.yup.clone(),
..default()
},
// TODO: should all yups be spawned on specific Z-value for easy handling?
Transform::from_xyz(500., 200., 1.),
));
}
11 changes: 7 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ mod assets;
#[cfg(feature = "dev")]
mod dev_tools;
pub mod game;
pub mod physics;
pub mod screens;
mod ui;

use avian2d::PhysicsPlugins;
use bevy::{
asset::AssetMetaCheck,
audio::{AudioPlugin, Volume},
Expand Down Expand Up @@ -54,9 +54,12 @@ impl Plugin for GamePlugin {
}),
);

app.add_plugins(PhysicsPlugins::default().with_length_unit(20.0));

app.add_plugins((assets::plugin, screens::plugin, game::plugin));
app.add_plugins((
assets::plugin,
screens::plugin,
game::plugin,
physics::plugin,
));

#[cfg(feature = "dev")]
app.add_plugins(dev_tools::plugin);
Expand Down
61 changes: 61 additions & 0 deletions src/physics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use bevy::prelude::*;

use crate::{
game::yup::{CharacterState, Yup},
screens::ingame::playing::Level,
};

pub fn plugin(app: &mut App) {
app.add_systems(FixedUpdate, (gravity, collision).chain());
}

#[derive(Component, Debug)]
pub struct Gravity;

fn gravity(mut has_gravity: Query<(&CharacterState, &mut Transform), With<Gravity>>) {
for (state, mut t) in &mut has_gravity {
if *state == CharacterState::Falling {
t.translation.y -= 3.;
}
}
}

fn collision(
camera: Single<(&Camera, &GlobalTransform), With<Camera2d>>,
images: Res<Assets<Image>>,
level: Query<&MeshMaterial2d<ColorMaterial>, With<Level>>,
materials: Res<Assets<ColorMaterial>>,
mut yups: Query<(&mut CharacterState, &Transform), With<Yup>>,
) {
let Ok(l) = level.get_single() else {
return;
};

let Some(level_material) = materials.get(&l.0) else {
return;
};

let Some(texture) = &level_material.texture else {
return;
};

let Some(img) = images.get(texture) else {
return;
};

let (camera, camera_transform) = camera.into_inner();
for (mut state, t) in &mut yups {
// TODO: better way to determine this?
let feet = t.translation + Vec3::new(0., -18., 0.);
if let Ok(collision_point) = camera.world_to_viewport(camera_transform, feet) {
let Ok(check) = img.get_color_at(collision_point.x as u32, collision_point.y as u32)
else {
return;
};
if check.alpha() > 0. {
// Hey, we collided with something!
*state = CharacterState::Walking;
}
}
}
}
7 changes: 2 additions & 5 deletions src/screens/ingame/pause.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use avian2d::prelude::*;
use bevy::{input::common_conditions::input_just_pressed, prelude::*};

use crate::screens::Screen;
Expand Down Expand Up @@ -116,12 +115,10 @@ fn init(mut commands: Commands) {
// }
// }

fn pause(mut game: ResMut<NextState<Game>>, mut time: ResMut<Time<Physics>>) {
fn pause(mut game: ResMut<NextState<Game>>) {
game.set(Game::Paused);
time.pause();
}

fn unpause(mut game: ResMut<NextState<Game>>, mut time: ResMut<Time<Physics>>) {
fn unpause(mut game: ResMut<NextState<Game>>) {
game.set(Game::Playing);
time.unpause();
}
Loading

0 comments on commit a6dcb71

Please sign in to comment.