Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing substep leads to weird behavior #478

Open
roman-holovin opened this issue Feb 11, 2024 · 0 comments
Open

Changing substep leads to weird behavior #478

roman-holovin opened this issue Feb 11, 2024 · 0 comments
Labels
A-Dynamics bug Something isn't working D-Difficult Needs strong technical background, domain knowledge, or impacts are high, needs testing... P-High arbitrary important item S-not-started Work has not started

Comments

@roman-holovin
Copy link

I have a small project with a ball inside 4 walls. All parameters are set in such way so ball should move indefinitely. It works properly when substep is set to 1, but as soon I increase it ball starts to slow down and change direction after a collision incorrectly.

Repro:

use bevy::{prelude::*, render::camera::ScalingMode, sprite::MaterialMesh2dBundle};
use bevy_rapier2d::prelude::*;

const PIXELS_PER_METER: f32 = 30.;
const TICKS_PER_SECOND: f32 = 100.;

const BALL_STARTING_POSITION: Vec3 = Vec3::new(0.0, 0.0, 1.0);
const BALL_SIZE: Vec3 = Vec3::new(1.0, 1.0, 0.0);
const BALL_SPEED: f32 = 150.0;
const INITIAL_BALL_DIRECTION: Vec2 = Vec2::new(0.5, -0.5);

const WALL_THICKNESS: f32 = 0.5;

const LEFT_WALL: f32 = -15.;
const RIGHT_WALL: f32 = 15.;
const BOTTOM_WALL: f32 = -10.;
const TOP_WALL: f32 = 10.;

const BACKGROUND_COLOR: Color = Color::rgb(0.9, 0.9, 0.9);
const BALL_COLOR: Color = Color::rgb(1.0, 0.5, 0.5);
const WALL_COLOR: Color = Color::rgb(0.8, 0.8, 0.8);

#[derive(Component)]
struct Ball;

#[derive(Bundle)]
struct WallBundle {
    sprite_bundle: SpriteBundle,
    collider: Collider,
    friction: Friction,
    restitution: Restitution,
    rigid_body: RigidBody,
    ccd: Ccd,
    location: WallLocation,
}

#[derive(Component, Eq, PartialEq)]
enum WallLocation {
    Left,
    Right,
    Bottom,
    Top,
}

impl WallLocation {
    fn position(&self) -> Vec2 {
        match self {
            WallLocation::Left => Vec2::new(LEFT_WALL, 0.),
            WallLocation::Right => Vec2::new(RIGHT_WALL, 0.),
            WallLocation::Bottom => Vec2::new(0., BOTTOM_WALL),
            WallLocation::Top => Vec2::new(0., TOP_WALL),
        }
    }

    fn size(&self) -> Vec2 {
        let arena_height = TOP_WALL - BOTTOM_WALL;
        let arena_width = RIGHT_WALL - LEFT_WALL;

        assert!(arena_height > 0.0);
        assert!(arena_width > 0.0);

        match self {
            WallLocation::Left | WallLocation::Right => {
                Vec2::new(WALL_THICKNESS, arena_height + WALL_THICKNESS)
            }
            WallLocation::Bottom | WallLocation::Top => {
                Vec2::new(arena_width + WALL_THICKNESS, WALL_THICKNESS)
            }
        }
    }
}

impl WallBundle {
    fn new(location: WallLocation) -> WallBundle {
        WallBundle {
            sprite_bundle: SpriteBundle {
                transform: Transform {
                    translation: location.position().extend(0.0) * PIXELS_PER_METER,
                    scale: location.size().extend(1.0) * PIXELS_PER_METER,
                    ..default()
                },
                sprite: Sprite {
                    color: WALL_COLOR,
                    ..default()
                },
                ..default()
            },
            rigid_body: RigidBody::Fixed,
            ccd: Ccd::enabled(),
            collider: Collider::cuboid(0.5, 0.5),
            friction: Friction::new(0.0),
            restitution: Restitution::new(1.0),
            location,
        }
    }
}

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(
            PIXELS_PER_METER,
        ))
        .insert_resource(RapierConfiguration {
            timestep_mode: TimestepMode::Interpolated {
                dt: 1. / TICKS_PER_SECOND,
                time_scale: 1.0,
                substeps: 10,
            },
            gravity: Vec2::ZERO,
            ..default()
        })
        .add_event::<CollisionEvent>()
        .insert_resource(ClearColor(BACKGROUND_COLOR))
        .add_systems(Startup, setup)
        .add_systems(Update, bevy::window::close_on_esc)
        .run();
}

fn setup(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<ColorMaterial>>,
) {
    commands.spawn(Camera2dBundle {
        projection: OrthographicProjection {
            near: -1000.,
            far: 1000.,
            scaling_mode: ScalingMode::AutoMin {
                min_width: 1024.,
                min_height: 768.,
            },
            ..default()
        },
        ..default()
    });

    commands.spawn((
        MaterialMesh2dBundle {
            mesh: meshes
                .add(shape::Circle::new(BALL_SIZE.x / 2.0 * PIXELS_PER_METER).into())
                .into(),
            material: materials.add(ColorMaterial::from(BALL_COLOR)),
            transform: Transform::from_translation(BALL_STARTING_POSITION),
            ..default()
        },
        RigidBody::Dynamic,
        Ccd::enabled(),
        LockedAxes::ROTATION_LOCKED,
        Collider::ball(BALL_SIZE.x / 2.0 * PIXELS_PER_METER),
        Damping {
            angular_damping: 0.0,
            linear_damping: 0.0,
        },
        GravityScale(0.),
        Friction::new(0.0),
        Restitution::new(1.0),
        Ball,
        Velocity {
            linvel: (INITIAL_BALL_DIRECTION.normalize() * BALL_SPEED),
            angvel: 0.,
        },
    ));

    commands.spawn(WallBundle::new(WallLocation::Left));
    commands.spawn(WallBundle::new(WallLocation::Right));
    commands.spawn(WallBundle::new(WallLocation::Bottom));
    commands.spawn(WallBundle::new(WallLocation::Top));
}
@Vrixyz Vrixyz added bug Something isn't working D-Difficult Needs strong technical background, domain knowledge, or impacts are high, needs testing... P-High arbitrary important item S-not-started Work has not started A-Dynamics labels May 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Dynamics bug Something isn't working D-Difficult Needs strong technical background, domain knowledge, or impacts are high, needs testing... P-High arbitrary important item S-not-started Work has not started
Projects
None yet
Development

No branches or pull requests

2 participants