Skip to content

Commit

Permalink
Port to Bevy main
Browse files Browse the repository at this point in the history
Requires a separate branch for now.
Also egui hasn't been ported yet.
  • Loading branch information
Shatur committed Nov 4, 2024
1 parent e2746d8 commit 59af103
Show file tree
Hide file tree
Showing 22 changed files with 316 additions and 452 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Rename `Press` into `JustPress`.
- Rename `Down` into `Press` to avoid collision with `Down` from `bevy_picking`.
- Replace `ContextInstance::with_gamepad` builder with just `ContextInstance::set_gamepad` setter.

## [0.2.0] - 2024-11-03

Expand Down
15 changes: 9 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ include = ["/src", "/tests", "/examples", "/LICENSE*"]

[dependencies]
bevy_enhanced_input_macros = { path = "macros", version = "0.2" }
bevy = { version = "0.14", default-features = false, features = ["serialize"] }
bevy_egui = { version = "0.30", default-features = false, optional = true }
bevy = { git = "https://github.com/projectharmonia/bevy", branch = "gamepad-improvements", default-features = false, features = [
"serialize",
] }
# bevy_egui = { version = "0.30", default-features = false, optional = true }
serde = "1.0"
bitflags = { version = "2.6", features = ["serde"] }

[dev-dependencies]
bevy = { version = "0.14", default-features = false, features = [
bevy = { git = "https://github.com/projectharmonia/bevy", branch = "gamepad-improvements", default-features = false, features = [
"bevy_gilrs",
"bevy_gizmos",
"x11",
Expand All @@ -32,15 +34,16 @@ default = ["ui_priority"]
ui_priority = ['bevy/bevy_ui']

# Prioritizes 'egui' over actions when processing inputs.
egui_priority = ['dep:bevy_egui']
# egui_priority = ['dep:bevy_egui']
egui_priority = []

[[example]]
name = "ui_priority"
required-features = [
"ui_priority",
"egui_priority",
"bevy_egui/render",
"bevy_egui/default_fonts",
# "bevy_egui/render",
# "bevy_egui/default_fonts",
"bevy/default_font",
]

Expand Down
18 changes: 9 additions & 9 deletions examples/context_layering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::f32::consts::FRAC_PI_4;
use bevy::{color::palettes::tailwind::INDIGO_600, prelude::*};
use bevy_enhanced_input::prelude::*;

use player_box::{PlayerBox, PlayerBoxBundle, PlayerBoxPlugin, PlayerColor, DEFAULT_SPEED};
use player_box::{PlayerBox, PlayerBoxPlugin, PlayerColor, DEFAULT_SPEED};

fn main() {
App::new()
Expand All @@ -27,19 +27,19 @@ impl Plugin for GamePlugin {
app.add_input_context::<PlayerBox>()
.add_input_context::<Swimming>()
.add_systems(Startup, Self::spawn)
.observe(Self::apply_movement)
.observe(Self::rotate)
.observe(Self::exit_water)
.observe(Self::enter_water)
.observe(Self::start_diving)
.observe(Self::end_diving);
.add_observer(Self::apply_movement)
.add_observer(Self::rotate)
.add_observer(Self::exit_water)
.add_observer(Self::enter_water)
.add_observer(Self::start_diving)
.add_observer(Self::end_diving);
}
}

impl GamePlugin {
fn spawn(mut commands: Commands) {
commands.spawn(Camera2dBundle::default());
commands.spawn(PlayerBoxBundle::default());
commands.spawn(Camera2d);
commands.spawn(PlayerBox);
}

fn apply_movement(trigger: Trigger<Fired<Move>>, mut players: Query<&mut Transform>) {
Expand Down
18 changes: 6 additions & 12 deletions examples/context_sharing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::f32::consts::FRAC_PI_4;
use bevy::prelude::*;
use bevy_enhanced_input::prelude::*;

use player_box::{PlayerBox, PlayerBoxBundle, PlayerBoxPlugin, DEFAULT_SPEED};
use player_box::{PlayerBox, PlayerBoxPlugin, DEFAULT_SPEED};

fn main() {
App::new()
Expand All @@ -28,24 +28,18 @@ impl Plugin for GamePlugin {
fn build(&self, app: &mut App) {
app.add_input_context::<PlayerBox>()
.add_systems(Startup, Self::spawn)
.observe(Self::apply_movement)
.observe(Self::rotate);
.add_observer(Self::apply_movement)
.add_observer(Self::rotate);
}
}

impl GamePlugin {
fn spawn(mut commands: Commands) {
commands.spawn(Camera2dBundle::default());
commands.spawn(Camera2d);

// Spawn two entities with the same context.
commands.spawn(PlayerBoxBundle {
transform: Transform::from_translation(Vec3::X * 50.0),
..Default::default()
});
commands.spawn(PlayerBoxBundle {
transform: Transform::from_translation(-Vec3::X * 50.0),
..Default::default()
});
commands.spawn((PlayerBox, Transform::from_translation(Vec3::X * 50.0)));
commands.spawn((PlayerBox, Transform::from_translation(-Vec3::X * 50.0)));
}

fn apply_movement(trigger: Trigger<Fired<Move>>, mut players: Query<&mut Transform>) {
Expand Down
14 changes: 7 additions & 7 deletions examples/context_switch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::f32::consts::FRAC_PI_4;
use bevy::{color::palettes::tailwind::FUCHSIA_400, prelude::*};
use bevy_enhanced_input::prelude::*;

use player_box::{PlayerBoxBundle, PlayerBoxPlugin, PlayerColor, DEFAULT_SPEED};
use player_box::{PlayerBox, PlayerBoxPlugin, PlayerColor, DEFAULT_SPEED};

fn main() {
App::new()
Expand All @@ -27,17 +27,17 @@ impl Plugin for GamePlugin {
app.add_input_context::<OnFoot>()
.add_input_context::<InCar>()
.add_systems(Startup, Self::spawn)
.observe(Self::apply_movement)
.observe(Self::rotate)
.observe(Self::enter_car)
.observe(Self::exit_car);
.add_observer(Self::apply_movement)
.add_observer(Self::rotate)
.add_observer(Self::enter_car)
.add_observer(Self::exit_car);
}
}

impl GamePlugin {
fn spawn(mut commands: Commands) {
commands.spawn(Camera2dBundle::default());
commands.spawn((PlayerBoxBundle::default(), OnFoot));
commands.spawn(Camera2d);
commands.spawn((PlayerBox, OnFoot));
}

fn apply_movement(trigger: Trigger<Fired<Move>>, mut players: Query<&mut Transform>) {
Expand Down
84 changes: 56 additions & 28 deletions examples/local_multiplayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ use std::f32::consts::FRAC_PI_4;

use bevy::{
color::palettes::tailwind::{BLUE_600, RED_600},
input::gamepad::{GamepadConnection, GamepadConnectionEvent},
prelude::*,
};
use bevy_enhanced_input::prelude::*;

use player_box::{PlayerBox, PlayerBoxBundle, PlayerBoxPlugin, PlayerColor, DEFAULT_SPEED};
use player_box::{PlayerBox, PlayerBoxPlugin, PlayerColor, DEFAULT_SPEED};

fn main() {
App::new()
Expand All @@ -28,32 +29,29 @@ struct GamePlugin;
impl Plugin for GamePlugin {
fn build(&self, app: &mut App) {
app.add_input_context::<PlayerBox>()
.add_observer(Self::apply_movement)
.add_observer(Self::rotate)
.add_systems(Startup, Self::spawn)
.observe(Self::apply_movement)
.observe(Self::rotate);
.add_systems(Update, Self::update_gamepads);
}
}

impl GamePlugin {
fn spawn(mut commands: Commands) {
commands.spawn(Camera2dBundle::default());
commands.spawn(Camera2d);

// Spawn two players with different assigned indices.
commands.spawn((
PlayerBoxBundle {
transform: Transform::from_translation(Vec3::X * 50.0),
color: PlayerColor(RED_600.into()),
..Default::default()
},
PlayerIndex(0),
PlayerBox,
Transform::from_translation(Vec3::X * 50.0),
PlayerColor(RED_600.into()),
Player::First,
));
commands.spawn((
PlayerBoxBundle {
transform: Transform::from_translation(-Vec3::X * 50.0),
color: PlayerColor(BLUE_600.into()),
..Default::default()
},
PlayerIndex(1),
PlayerBox,
Transform::from_translation(-Vec3::X * 50.0),
PlayerColor(BLUE_600.into()),
Player::Second,
));
}

Expand All @@ -67,43 +65,73 @@ impl GamePlugin {
let mut transform = players.get_mut(trigger.entity()).unwrap();
transform.rotate_z(FRAC_PI_4);
}

fn update_gamepads(
mut commands: Commands,
mut connect_events: EventReader<GamepadConnectionEvent>,
mut gamepads: ResMut<Gamepads>,
) {
for event in connect_events.read() {
match event.connection {
GamepadConnection::Connected(_) => gamepads.push(event.gamepad),
GamepadConnection::Disconnected => {
if let Some(index) = gamepads.iter().position(|&entity| entity == event.gamepad)
{
gamepads.swap_remove(index);
}
}
}
}

// Trigger contexts rebuild to update associated gamepads.
commands.trigger(RebuildInputContexts);
}
}

#[derive(Component, Deref)]
struct PlayerIndex(usize);
#[derive(Component, Clone, Copy, PartialEq, Eq, Hash)]
enum Player {
First,
Second,
}

/// A resource that tracks all connected gamepads to pick them by index.
#[derive(Resource, Default, Deref, DerefMut)]
struct Gamepads(Vec<Entity>);

impl InputContext for PlayerBox {
fn context_instance(world: &World, entity: Entity) -> ContextInstance {
let mut ctx = ContextInstance::default();

// Could be stored in the context itself, but it's usually
// better to have a separate component that is shared
// across all contexts.
let index = **world.get::<PlayerIndex>(entity).unwrap();
let player = *world.get::<Player>(entity).unwrap();

// By default context read inputs from all gamepads,
// but for local multiplayer we need assign specific
// gamepad index.
let mut ctx = ContextInstance::with_gamepad(index);
let gamepads = world.resource::<Gamepads>();
if let Some(&entity) = gamepads.get(player as usize) {
ctx.set_gamepad(entity);
}

// Assign different mappings based player index.
match index {
0 => {
match player {
Player::First => {
ctx.bind::<Move>()
.with_wasd()
.with_stick(GamepadStick::Left);
ctx.bind::<Rotate>()
.with(KeyCode::Space)
.with(GamepadButtonType::South);
.with(GamepadButton::South);
}
1 => {
Player::Second => {
ctx.bind::<Move>()
.with_arrows()
.with_stick(GamepadStick::Left);
ctx.bind::<Rotate>()
.with(KeyCode::Numpad0)
.with(GamepadButtonType::South);
}
_ => {
panic!("game expects only 2 players");
.with(GamepadButton::South);
}
}

Expand Down
12 changes: 2 additions & 10 deletions examples/player_box/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ impl PlayerBoxPlugin {
if visibility != Visibility::Hidden {
const DEFAULT_SCALE: Vec2 = Vec2::splat(50.0);
gizmos.rect(
transform.translation,
transform.rotation,
Isometry3d::new(transform.translation, transform.rotation),
DEFAULT_SCALE + transform.scale.xy(),
color.0,
);
Expand All @@ -31,15 +30,8 @@ impl PlayerBoxPlugin {

pub(super) const DEFAULT_SPEED: f32 = 10.0;

#[derive(Bundle, Default)]
pub(super) struct PlayerBoxBundle {
pub(super) color: PlayerColor,
pub(super) visibility: Visibility,
pub(super) player: PlayerBox,
pub(super) transform: Transform,
}

#[derive(Component, Default)]
#[require(PlayerColor, Visibility, Transform)]
pub(super) struct PlayerBox;

#[derive(Component, Default, Deref, DerefMut)]
Expand Down
12 changes: 6 additions & 6 deletions examples/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::f32::consts::FRAC_PI_4;
use bevy::prelude::*;
use bevy_enhanced_input::prelude::*;

use player_box::{PlayerBox, PlayerBoxBundle, PlayerBoxPlugin, DEFAULT_SPEED};
use player_box::{PlayerBox, PlayerBoxPlugin, DEFAULT_SPEED};

fn main() {
App::new()
Expand All @@ -26,17 +26,17 @@ impl Plugin for GamePlugin {
fn build(&self, app: &mut App) {
app.add_input_context::<PlayerBox>() // All input contexts should be registered inside the app.
.add_systems(Startup, Self::spawn)
.observe(Self::apply_movement)
.observe(Self::rotate);
.add_observer(Self::apply_movement)
.add_observer(Self::rotate);
}
}

impl GamePlugin {
fn spawn(mut commands: Commands) {
commands.spawn(Camera2dBundle::default());
commands.spawn(Camera2d);

// Spawn an entity with a component that implements `InputContext`.
commands.spawn(PlayerBoxBundle::default());
commands.spawn(PlayerBox);
}

fn apply_movement(trigger: Trigger<Fired<Move>>, mut players: Query<&mut Transform>) {
Expand Down Expand Up @@ -75,7 +75,7 @@ impl InputContext for PlayerBox {

ctx.bind::<Rotate>()
.with(KeyCode::Space)
.with(GamepadButtonType::South);
.with(GamepadButton::South);

ctx
}
Expand Down
Loading

0 comments on commit 59af103

Please sign in to comment.