//! A basic implementation of a character controller for a dynamic rigid body. //! //! This showcases the following: //! //! - Basic directional movement and jumping //! - Support for both keyboard and gamepad input //! - A configurable maximum slope angle for jumping //! //! The character controller logic is contained within the `plugin` module. //! //! For a kinematic character controller, see the `kinematic_character_2d` example. mod plugin; use bevy::{ prelude::*, render::{render_asset::RenderAssetUsages, render_resource::PrimitiveTopology}, sprite::MaterialMesh2dBundle, }; use bevy_xpbd_2d::{math::*, prelude::*}; use plugin::*; fn main() { App::new() .add_plugins(( DefaultPlugins, PhysicsPlugins::default(), CharacterControllerPlugin, )) .insert_resource(ClearColor(Color::srgb(0.05, 0.05, 0.1))) .insert_resource(Gravity(Vector::NEG_Y * 1000.0)) .add_systems(Startup, setup) .run(); } fn setup( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, ) { // Player commands.spawn(( MaterialMesh2dBundle { mesh: meshes.add(Capsule2d::new(12.5, 20.0)).into(), material: materials.add(Color::srgb(0.2, 0.7, 0.9)), transform: Transform::from_xyz(0.0, -100.0, 0.0), ..default() }, CharacterControllerBundle::new(Collider::capsule(20.0, 12.5)).with_movement( 1250.0, 0.92, 400.0, (30.0 as Scalar).to_radians(), ), Friction::ZERO.with_combine_rule(CoefficientCombine::Min), Restitution::ZERO.with_combine_rule(CoefficientCombine::Min), ColliderDensity(2.0), GravityScale(1.5), )); // A cube to move around commands.spawn(( SpriteBundle { sprite: Sprite { color: Color::srgb(0.0, 0.4, 0.7), custom_size: Some(Vec2::new(30.0, 30.0)), ..default() }, transform: Transform::from_xyz(50.0, -100.0, 0.0), ..default() }, RigidBody::Dynamic, Collider::rectangle(30.0, 30.0), )); // Platforms commands.spawn(( SpriteBundle { sprite: Sprite { color: Color::srgb(0.7, 0.7, 0.8), custom_size: Some(Vec2::new(1100.0, 50.0)), ..default() }, transform: Transform::from_xyz(0.0, -175.0, 0.0), ..default() }, RigidBody::Static, Collider::rectangle(1100.0, 50.0), )); commands.spawn(( SpriteBundle { sprite: Sprite { color: Color::srgb(0.7, 0.7, 0.8), custom_size: Some(Vec2::new(300.0, 25.0)), ..default() }, transform: Transform::from_xyz(175.0, -35.0, 0.0), ..default() }, RigidBody::Static, Collider::rectangle(300.0, 25.0), )); commands.spawn(( SpriteBundle { sprite: Sprite { color: Color::srgb(0.7, 0.7, 0.8), custom_size: Some(Vec2::new(300.0, 25.0)), ..default() }, transform: Transform::from_xyz(-175.0, 0.0, 0.0), ..default() }, RigidBody::Static, Collider::rectangle(300.0, 25.0), )); commands.spawn(( SpriteBundle { sprite: Sprite { color: Color::srgb(0.7, 0.7, 0.8), custom_size: Some(Vec2::new(150.0, 80.0)), ..default() }, transform: Transform::from_xyz(475.0, -110.0, 0.0), ..default() }, RigidBody::Static, Collider::rectangle(150.0, 80.0), )); commands.spawn(( SpriteBundle { sprite: Sprite { color: Color::srgb(0.7, 0.7, 0.8), custom_size: Some(Vec2::new(150.0, 80.0)), ..default() }, transform: Transform::from_xyz(-475.0, -110.0, 0.0), ..default() }, RigidBody::Static, Collider::rectangle(150.0, 80.0), )); // Ramps let mut ramp_mesh = Mesh::new( PrimitiveTopology::TriangleList, RenderAssetUsages::default(), ); ramp_mesh.insert_attribute( Mesh::ATTRIBUTE_POSITION, vec![[-125.0, 80.0, 0.0], [-125.0, 0.0, 0.0], [125.0, 0.0, 0.0]], ); let ramp_collider = Collider::triangle( Vector::new(-125.0, 80.0), Vector::NEG_X * 125.0, Vector::X * 125.0, ); commands.spawn(( MaterialMesh2dBundle { mesh: meshes.add(ramp_mesh).into(), material: materials.add(Color::srgb(0.4, 0.4, 0.5)), transform: Transform::from_xyz(-275.0, -150.0, 0.0), ..default() }, RigidBody::Static, ramp_collider, )); let mut ramp_mesh = Mesh::new( PrimitiveTopology::TriangleList, RenderAssetUsages::default(), ); ramp_mesh.insert_attribute( Mesh::ATTRIBUTE_POSITION, vec![[20.0, -40.0, 0.0], [20.0, 40.0, 0.0], [-20.0, -40.0, 0.0]], ); let ramp_collider = Collider::triangle( Vector::new(20.0, -40.0), Vector::new(20.0, 40.0), Vector::new(-20.0, -40.0), ); commands.spawn(( MaterialMesh2dBundle { mesh: meshes.add(ramp_mesh).into(), material: materials.add(Color::srgb(0.4, 0.4, 0.5)), transform: Transform::from_xyz(380.0, -110.0, 0.0), ..default() }, RigidBody::Static, ramp_collider, )); // Camera commands.spawn(Camera2dBundle::default()); }