Giter Site home page Giter Site logo

heron's People

Contributors

aceeri avatar agg23 avatar apastushenka avatar canleskis avatar claby2 avatar dependabot[bot] avatar edgarssilva avatar elegaanz avatar elsid avatar eragoneq avatar faassen avatar github-actions[bot] avatar irate-devil avatar jcornaz avatar liamgallagher737 avatar mglolenstine avatar mozgiii avatar neo97online avatar nicopap avatar renovate[bot] avatar ryo33 avatar shatur avatar tqwewe avatar wdhwg001 avatar xkonti avatar yaymalaga avatar zicklag avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

heron's Issues

Revaluate distinction between heron and bevy_rapier

rapier and bevy_rapier just published some awesome improvements that will make the user-experience of using rapier in a bevy game much nicer.

If theses changes are awesome, they also makes the distinction between bevy_rapier and heron a bit thinner and blurry than before.

I think there is still room for both projects as they still have slightly different approaches, and it is likely that they are both useful to a different type of user.

Neverthelless, I have to make sure that efforts in the developement of heron are well spent by making sure that:

  • The distinction between heron and bevy_rapier is big enough and clearily communicated (in the readme).
  • Future development of heron go in a right direction to keep heron being a relevant alternative to bevy_rapier.

Publish collision events

As a User, I want to subscribe to collision events, so that I can execute logic when two bodies collides (or stop to collide).

Ray cast

It'd be nice to be able to easily raycast from a system.

How it could look like

fn ray_cast_system(world: Res<PhysicsWorld>) {
  match world.ray_cast(Vec3::default(), Vec3::unit_x()) {
    Some(entity) => { println!("raycast found: {:?}", entity) }
    None => { println!("raycast found nothing") }
  }
}

Use cases

  • ground-check
  • fast-bullet hit check
  • check what object the mouse is hovering

Avoid copying the full `IntegrationParameters` type in step system

Since #88 the step system copy the IntegrationParameters each time. Which sounds wasteful to me. Even though, I admit, haven't measured the perfs...

Instead there could be a private resource struct PhysicsStepPerSecond(f32) that would remember how many steps per second are run. Then a system can update IntegrationParameters based on the data in PhysicsStepPerSecond and PhysicsTime.

Extended collision shape support

Currently Heron supports these bodies, based on Rapier shapes:

  • Sphere (circle)

  • Capsule

  • Cuboid (rectangle)

Here's my analysis of what useful other things exist in Rapier. The Heron body names would typically be the names in Rapier but converted to CamelCase. Ideally all shapes supported by at least 2d would have an implementation in the debug renderer as well.

I think the following have relatively straightforward implementations:

  • convex_hull creates a hull around the given points. See #59

  • round_convex_hull does a convex hull with rounded corners.

  • round_cuboid: a cuboid with rounded corners.

  • segment: a line segment shape from one point to another

  • triangle. I imagine this is a flat triangle in 3d.

These I'm not entirely sure about what they do.

  • polyline: polyline shape defined by vertex and optional index buffers. Without index buffers it's assumed to describe a line strip.

  • trimesh: triangle mesh shape defined by vertex and index buffers. See #41

  • convex_decomposition: creates a compound shape obtained from the decomposition of the given trimesh (in 3d) and polyline (in 2d) into convex parts

  • round_convex_decomposition: the same, but with rounded corners

  • convex_decomposition_with_params: control the decomposition using a set of parameters for the VHACD algorithm.

  • round_convex_decomposition_with_params: control the decomposition using a set of parameters for the VHACD algorithm.

  • heightfield: a heightfield shape

  • compound: a compound shape defined by subshapes

Then there are shapes that only exist in either 2d or 3d. The question is what Heron should do with these as it aims to offer a unified API. The simplest would be to have particular Body types to be only constructable in 2d or 3d.

Only exist in 2d:

  • convex_polyline assumes the given points already form a convex polygon, no convex hull is computed automatically.

  • round_convex_polyline does a convex polyline with rounded corners.

Only exists in 3d:

  • cylinder

  • round_cylinder

  • cone

  • round_cone

Not directly implemented in Rapier but would be nice to implement in Heron is a regular polygon shape defined by the amount of sides.

Provide 2d oriented constructors for CollisionShape

Here are some proposed convenience shapes for 2d that mostly don't exist directly in Rapier but are easy to implement. The argument to have them is because when dealing with 2d, people think in 2d terms. It's weird to refer to a circle as a "sphere", for instance. We can also use Vec2 instead of Vec3 to define them where vecs are involved.

I think we can make them in a special Body2 enum that gets translated into Body underneath.

// alias for Sphere
Body2::Circle {
   radius: f32
}

// like Cuboid, but with Vec2
Body2::Rectangle {
   half_extends: Vec2
}

// Convenience over Body2::Rectangle
Body2::Square {
   size: f32 // size of side. Or should this be half_side?
}

// Parry has a specific triangle shape
Body2::Triangle {
   a: Vec2,
   b: Vec2,
   c: Vec2
}

// Stadium is the geometric name for a 2d capsule. Since this is such an obscure name, the name Capsule still works too
Body2::Stadium {
  half_segment: f32, 
  radius: f32  // radius of the half circles
}

// A convex polygon defined exactly by its points (convex_polyline in Rapier)
Body2::ConvexPolygon {
   points: Vec<Vec2>
}

// This requires some code but it's convenient to have
Body2::RegularPolygon {
  sides: int; // amount of sides
  radius: f32; // distance from center for each point
}

Write a initial guide

I create this issue issue to track the biggest missing pieces of documentation that are required to publish an "initial version" of the guide.

(Thanks @faassen for the list)

  • How to define a body type (Static, Kinematic, Dynamic and Sensor)
  • PhysicMaterial
  • Collision detection
  • 2d gotchaes (incl. rotation in 2d is around the z axis.) (this is more about bevy than heron)
  • Change/Define velocity, acceleration, force and impulse
  • How to acces Rapier directly (#43)

Cuboid collision shape

As a User, I would like to use cuboid collision shape, so that I can define a good collision shape of terrain, platforms, and other rectangular objects.

Report missing required components

As a User, I wan't to get clear and quick feedback when I make a mistake, so that I avoid spending time guessing/debuging in order to make my game work.

For example the Body component needs the entity to also have a GlobalTransoform. And a Velocity works only on dynamic bodies.

When a required components is missing it can be considered a programming mistake of the user of this library, and Heron should at least report the situation, so the user is aware of it.

Sensor

As a User, I would like to define a Sensor that is not affected by forces nor affect any other bodies, but trigger collision events, so that I can setup detection area to trigger logic (ex. The player reached the end of the level)

Execute physics step in-sync with the bevy update

The problem

In a game the time between each frame may vary significantly from frame to frame. The physics simulation should not suffer from that. Its progression should always be at the same "speed" of the real world time (eventually scaled by a user-defined factor).

It is also important to garantee a maximum "delta-time" between each physics step to prevent objects passing through each others at lower frame rate.

For these reasons, the physics step runs at a fixed time-step which makes it out-of-sync of the main frame update. That means the physics step may be executed: 0, 1 or n times during a single bevy update.

But this adds complexity for both usage and design/maintenance of the library:

  • The user has to know and use correctly add_physics_system
  • It isn't possible (ATM) to easily deal with bevy states (see #81)

And it also has a performance cost because it requires a dedicated bevy stage which introduces thread synchronization points and prevent other (non-physics related) systems to run in parallel of the physics.

A potential solution

The most problematic part is that there can be multiple physics step during a single bevy update.

But instead of using the bevy built-in FixedTimeStep there could be a different run criteria to make sure that at each bevy update the physics step runs either exactly once OR doesn't run. But it would never run the physics step multiple times in a single bevy update.

In other words:

  • If the frame rate is higher than the defined physics step rate: The physics step is not executed every frame. (To preserve the defined physics step rate)
  • If the frame rate is lower than the defined physics step rate: The physics step is executed exactly once at each frame. That means the physics simulation will slows down.

Then the physics system could run in the CoreStage::PostUpdate stage and provide labels to allow running user-systems before or after the physics step.

Pros

  • No need for add_physics_system. The user can read and mutate the physics component normally
    • The physics system will catch up when they'll run (Since bevy 0.5, changes can be detected even if they didn't occur during the same frame)
  • Support for bevy state systems comes for free (see #81)
  • Simpler design and developement
  • Some may like that physics simulation slows down in case of low FPS, as it make the game more "fair"
  • Potential performance gain as the physics can run in parallel of others systems defined by the user, bevy or other plugins.
  • Better performance in case of low FPS as the physics step runs only once per update (instead of multiple times per frame)

Cons

  • Some may NOT like that physics simulation slows down in case of low FPS

I think the first point is fine. We cannot please everyone. Some will like that physics simulation slow downs in case of low FPS. And some will not like it. Heron doesn't aim to be a drop-in replacement for rapier and bevy_rapier. It aims to makes things easier for people who do not need advanced physics control. If someone needs a more advanced/different handling of the physics in case of low FPS, they can use rapier/bevy_rapier.

Kinematic bodies

As a User, I would like to define kinematic bodies (not affected by forces, but can move, have velocity and affect other bodies), so that I can create a player character or movable object in the world.

Support Bevy's States V2

As the 0.5 release notes show, we can now add systems to run on the lifecycles of custom states:

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum AppState {
    Menu,
    InGame,
}

fn main() {
    App::build()
        .add_state(AppState::Menu)
        .add_system_set(SystemSet::on_enter(AppState::Menu).with_system(setup_menu.system()))
        .add_system_set(SystemSet::on_update(AppState::Menu).with_system(menu_logic.system()))
        .add_system_set(
            SystemSet::on_update(AppState::InGame)
                .with_system(game_logic.system())
        )
        .run();
}

Ideally, we should be able to run the physics systems just on AppState::InGame, instead of using .add_physics_system():

fn main() {
    App::build()
        .add_system_set(
            SystemSet::on_update(AppState::InGame)
                .with_system(game_logic.system())
                .with_physics_system(game_physics_logic.system())
        )
        .run();
}

Allow to change physics time scale

Following the issue #81, that feature would allow us to run the defined physics_systems only on specific States. However, the physics engine itself will continue to be called.

A common feature for games is the ability to pause it at any time. In order to achieve that, we would need to be able to manually choose in which States the physics step will run.

Another option is exposing a resource for allowing the user to start/stop the physics from any system. For this last option, it could be cool to also allow the user to modify the step used and how often it's called (i.e running the game in slow-motion while in pause to hurry up the player!).

Access to shape data

We have a use case where we want to access shape data in the renderer code. For instance, ConvexHull creates a set of points that defines the convex hull depending on the points you give it. It should be possible to access this data through a Heron API. This issue is to remind us to think about this.

In Rapier, once you have the shape, you can call this:

shape.as_convex_polygon().unwrap().points()

Where as_convex_polygon is a typecast and then points is the method that returns the points to draw.

Do we want to expose some kind of typecast API that can fail like this or is there another pattern that would work better? I know absolutely nothing about the reflection system of Bevy, is that relevant?

We need a Heron version of a convex polygon, that exposes Bevy vectors instead of Rapier points.

See also #43 as a fallback on how to get to the Rapier world. This could be a quick way to implement it without any new Heron APIs for the debug renderer, but in the longer term it would be better to expose this information in some nice Heron API.

Capsule collision shape

As a User, I would like to define a "Capsule" collision shape, so that I can define an appropriate collision shape for my sprite (character, bullet, etc.)

Mass component

Knowing the mass is necessary to calculate an acceleration from a force or a delta-v from an impulse.

Query utility for events

As a User, I want an easy way to query for components of the entities involved in a collision, so that it is easier to read/update components as part of the reaction to the event.

Here is how usage could look like:

fn damage_system(
  mut event_reader: Local<EventReader<CollisionEvent>>,
  events: Res<Events<CollisionEvent>>,
  mut damageables: Query<&mut Hp>,
  bullets: Query<Bullet>,
) {
  event_reader.iter(events)
    .flat_map(|event| event.query(&mut damageables, &bullets))
    .for_each(|(mut hp, bullet)| {
       hp.take_dmg(bullet.dmg());
    });
}

ConvexHull support

I'm looking into extending Heron so it supports ConvexHull as a Body. I'm running into the boundaries of my understanding of Rust as well as some design questions concerning Heron.

As far as I understand it you want to support the same API for 2d and 3d with Heron, meaning that you use Vec3 everywhere, but ignore the Z coordinate if in 2d mode.

So here's my definition of ConvexHull for Body:

    /// A convex polygon/polyhedron shape
    ConvexHull {
        /// A vector of points describing the convex hull
        points: Vec<Vec3>,
    },

This also means I need to extend build_collider:

        Body::ConvexHull { points } => convex_hull_builder(points.as_slice()),

Here I run into my limitations on my knowledge of Rust. I tried to introduce "IntoRapier" traits in convert.rs to gain the ability to convert an array of Vec3 into an array of Point3 (3d) as well as an array of Vec3 into an array of Point2 (2d). But Rust wouldn't accept both traits existing at the same time for some reason. Here's some broken code:

impl IntoRapier<Vec<Point3<f32>>> for &Vec<Vec3> {
    fn into_rapier(self) -> Vec<Point3<f32>> {
        let mut result: Vec<Point3<f32>> = Vec::new();
        for p in self.iter() {
            result.push(p.into_rapier())
        }
        result
    }
}

impl IntoRapier<Vec<Point2<f32>>> for &Vec<Vec3> {
    fn into_rapier(self) -> Vec<Point2<f32>> {
        let mut result: Vec<Point2<f32>> = Vec::new();
        for p in self.iter() {
            result.push(p.into_rapier())
        }
        result
    }
}

In the end I gave up and wrote more direct conversion code instead:

#[inline]
#[cfg(feature = "2d")]
fn convex_hull_builder(points: &[Vec3]) -> ColliderBuilder {
    let mut converted_points: Vec<Point2<f32>> = vec![];
    for point in points.iter() {
        converted_points.push(Point2::new(point.x, point.y));
    }
    ColliderBuilder::convex_hull(converted_points.as_slice()).unwrap()
}

#[inline]
#[cfg(feature = "3d")]
fn convex_hull_builder(points: &[Vec3]) -> ColliderBuilder {
    let mut converted_points: Vec<Point3<f32>> = vec![];
    for point in points.iter() {
        converted_points.push(Point3::new(point.x, point.y, point.z));
    }
    ColliderBuilder::convex_hull(converted_points.as_slice()).unwrap()
}

(the unwrap hints at an interesting design wrinkle; construction of the collider may fail in this case. How to deal with it in Heron?)

So the first question is: how do we successfully convert arrays of vec3 into either point2 and point3 using the traits in convert.rs? Because with this direct approach, body.rs depends directly on rapier types.

Now we move on to the major design issue that arose when I tried to adjust the debug renderer. It should be so simple:

        Body::ConvexHull { points } => {
            builder.add(&shapes::Polygon {
                points: points,
                closed: true,
            });
        }

but this won't work, because Polygon needs an array of Vec2 and points is an array of Vec3.

So I need to do this instead:

        Body::ConvexHull { points } => {
            builder.add(&shapes::Polygon {
                points: points.iter().map(|p| (*p).into()).collect(),
                closed: true,
            });
        }

which I guess is acceptable but hardly pretty. Maybe we need to make it easier to turn an array of Vec3 into an array of Vec2? Perhaps there's one I don't know about.

Position/Rotation offset for collision shape

As a user, I would like to have an offset for the collision shape (relative to its entity GlobalTransform), so that I don't need to use parent-child hierarchy (with shape being parent) when the origin and orientation of the colision shape doesn't match the origin/orientation of my sprite/mesh.

There could be a BodyOffset { translate: Vec3, rotate: Quat } component.

Allow to apply velocity to any entity (not only dynamic/kinematic bodies)

A sensor is NOT an actual physics body. But that doesn't mean we don't want to move or rotate it. There are plenty of use-case where we may want to move some sensor without having to make it a "dynamic" body. It would be much easier if I could simply use the velocity component for them.

Thinking about it, the Velocity could work for any entity. And the behavior would be:

  • For dynamic bodies: Apply the velocity, and let rapier continue the simulation (incl. mutating the velocity)
  • For kinematic bodies: Update the next_position at each steap and let rapier continue the simulation (not mutating the velocity)
  • For static bodies and sensors: Teleport the body each frame at the desired velocity ignoring physics rules.
  • For an entity without the Body component: Update the Transform each frame at the desired velocity.

Layers

In a typical game we don't want to have everything to collide with everything. This is especially true when using sensors.

Using physics layer to simplify/optimize game logic is a standard, useful and powerful technique in game-development.

Use cases

  • I want to create a "hurt-box" (sensor) that only collides only with "hit-boxes" (sensors).
  • I want to create a "finish" sensor that triggers a "victory" when the player enter the zone, but not when an ennemy enther it.
  • I want my character/ennemy to not be blocked by walls under some conditions.

Character controller

Right now, the only way to control kinematic bodies is by manually changing their transform. However, collisions are not taken into account by default, delegating that logic to the final user. This would be really useful to have even in basic games, such as platformers, where the player needs to collide with the floor.

For instance, Godot includes some high-level functions to handle this behavior, as explained in its documentation: Movement and collision and Detecting collisions.

This was discussed a while ago in the Bevy's discord physics channel, where Rapier's developer said:

Almost no physics engines compute contacts between two non-dynamic bodies (however kinematic bodies do affect dynamic bodies). So you are supposed to use shape-casting to detect collision with the static environment.
The godot "move_and_collide" and "move_and_slide" are just higher-level operations which are based on shape-casting.

Body types

There should be a BodyType enum component, that allow to create different type of bodies: dynamic, static, kinematic and senor.

It should be an enum to make impossible to have an conflicting definition in the same entity.

If missing, it should default to dynamic if there is a velocity, or static if there is no velocity.

Add Body::TriMesh definition

Add an Body::TriMesh enum variant that will allow creation of collider meshes based on bevy verteex position and indices data.

Also consider providing an easy interface of constructing those collider meshes from bevy's mesh handles

Compilation issue as a dependency

Hi! First of all, excellent work in this crate :)

I'm trying to compile with the provided readme version dependencies over a empty project:

bevy = "^0.5.0"
heron = { version = "0.8.0", features = ["3d"] }

And I get the following error coming from the heron_debug crate:

error[E0433]: failed to resolve: could not find `rapier` in `heron_rapier`
  --> /home/luis/.cargo/registry/src/github.com-1ecc6299db9ec823/heron_debug-0.8.0/src/dim2.rs:10:19
   |                                                                                                                   
10 | use heron_rapier::rapier::geometry::{ColliderHandle, ColliderSet, Shape};
   |                   ^^^^^^ could not find `rapier` in `heron_rapier`

I have this error only when I compile it from another project. Using cargo build --features 2d compiles without problems.

Thanks in advance

Publish the guide

Even if it is too small and far from complete, "some" documentation is better than "none".

Let's publish the guide.

Update to Bevy 0.5

Pretty self explanatory. I think it would be nice if you could also update to the latest version of rapier while you're at it, if its possible.

Store Component Sets in the ECS

If I understand correctly from what I've seen in bevy_rapier2d, it looks like it actually stores all of the simulation data such as rigid body positions, etc. in the bevy ECS, by implementing the ComponentSet trait. With the way we have heron right now we are storing the physics world data in Bevy resources that use arena based storage.

I'm curious if that has any advantages performance or otherwise and if that would be a useful strategy in heron or not. I'm mostly just musing over the possibility, but do you have any ideas why we would want to or not want to do that?

Use a different color for sensors

When debbugging I want to see every sensor and physics collision shapes.

But I also want to easily differentiate the physics collision shapes from the sensors.

By default the colors could be:

  • A light blue for physics (current)
  • A light green for sensors

Ideally, the two colors should be configurable.

Static bodies

As a User, I would like to define a static body that affect other bodies, but is not affected by physic, so that I can create platforms, or other static world objects.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.