#Avian Physics
1 messages · Page 45 of 1
Do the entities have CollisionEventsEnabled?
app.add_plugins((DefaultPlugins, PhysicsPlugins::default()));
or two separate add_plugins calls, should have the same effect
is there a way to add a plane collider
or should i just have a cuboid with 0.0 height
There's Collider::half_space which can be used for something like an infinite ground plane. But it's not an actual thin plane, everything below the plane is solid
Otherwise I'd probably use a cuboid
can also use a really big triangle
IIRC really big triangles can have some stability issues in Parry, though I don't remember if that was specifically trimeshes or convex hulls (or both)
how do I query a rigidbody?
it says rigidbodyqueryitem is not implemented for avian3d::prelude::rigidbody
hey! Is there a way I can allow 2 static colliders overlapping each other without making it glitches out?
in 3D
I believe the answer to this is to use CollisionLayers. So your static level meshes wouldn't interact with each other.
ohhh tysm!
man I've been reading the docs for 3 hours without a solution
static colliders shouldn't really be interacting with each other
might be able to help more if you could describe "glitches out" further
I got these two from playtesters, what could be the cause?
(Sending here because it's in parry2d)
The giant number is just -1 in u64
the trait bevy::prelude::Component is not implemented for avian3d::prelude::RigidBodyQueryItem<'_, '_>
= note: consider annotating avian3d::prelude::RigidBodyQueryItem<'_, '_> with #[derive(Component)]
mut car_rb : Single<&mut RigidBodyQueryItem , With<Car>>
I'm guessing this is Avian 0.4 or 0.5? Avian 0.6-rc doesn't use Parry's BVHs so this shouldn't be a problem anymore
unless it's in some internal BVH for a trimesh shape or compound shape, but that I don't have any control over since it's internal for Parry
this should be Single<RigidBodyQuery, With<Car>>
however I generally don't recommend using RigidBodyQuery, it's not reeaally meant for users and will likely be removed in the future
QueryData types like this are considered somewhat non-idiomatic for library APIs, and RigidBodyQuery in particular is very inefficient
What is the approach you would reccomend ??
just query for the components you need, like you normally would
So just query for force or position?
how would I query for something like velocity_at_point() ?
0.5
Alright, happy to hear that the crate where the problem happens will no longer be used
Though I must wonder if it's a crate thing or I just made an illegal request somewhere
But that's a problem for future me hehe
Is there any tool to draw a mesh to use as a collider on top of an asset (which I'm using as a sprite) for 2d physics?? It seems like there should be an easier way than manually typing out all of the components to get a right approximation ?
could use the voxels shape, could try a convex decomposition of the outline
I noticed that CollisionLayers are now immutable, so I assume I should just try_insert() new ones
(In 0.6.0-rc1)
I'm getting a funny
I managed to reproduce my crash in 0.6.0-rc.1
https://github.com/sphinxc0re/avian_06_bug_repro
And added an issue: https://github.com/avianphysics/avian/issues/946
Feel free to edit the title and description. Idk what the actual cause is 🤔
Child entities I think
Don't understand
When you spawn an entity, you can spawn children off of it, with one ray per child
And each ray can have its own transform
Ok but where's the syntax, the application
Perhaps see https://github.com/bevyengine/bevy/blob/v0.18.0/examples/ecs/hierarchy.rs for child spawning and https://github.com/avianphysics/avian/blob/main/crates/avian3d/examples/cast_ray_predicate.rs for the raycast.
That's the thing, calling a ray component is less effective if you need more data than casting a ray from spatialquery
Like for a spring arm, it would be easier if you could just grab the distance if it hit
Are you aware of https://docs.rs/avian3d/latest/avian3d/spatial_query/struct.RayCaster.html ?
Or instead, if your spring arm and any relevant world objects have Colliders (which they should!), you could use event-driven detection, i.e. a callback when the arm hits something, rather than always casting rays each frame (not cheap!). See the CollisionStart and CollisionEnd events (and remember to add CollisionEventsEnabled component to collider entities!) and use ordinary Bevy Observers or MessageReaders to process the events. They'll tell you the entities with the colliders that touched -- but you have to identify both entities somehow (they're collider1 and collider2 with an arbitrary order).
If you prefer polling instead of handling events -- be warned it's a bit harder -- be sure to use the RayCaster system parameter. proves similar information, more efficiently for large numbers of Collider entities., Look up ContactGraph and ContactPairs diving down to find ContactPoint::penetration.
A component used for raycasting.
Also https://docs.rs/avian3d/latest/avian3d/index.html is where I learned all this 🙂
Avian Physics
For a spring arm, wouldn't a RayCaster be better?
Thanks for the info btw
Reread, guess not.
Or rather, it seems like you're implying that I should use RayCaster alongside the methods you reccomended.
How do I get a ContactPoint from a ContactPair?
manifolds[].points[]
This doesn't seem to work.
fn spring_arm(
contact_graph: Res<ContactGraph>,
spring_arm: Single<Entity, With<PlayerSpringArm>>,
mut camera: Single<&mut Transform, With<PlayerCamera>>,
player: Single<Entity, With<Player>>,
) {
if let Some(contact_pair) = contact_graph.contact_pairs_with(*spring_arm).filter(|contact_pair|contact_pair.body2.unwrap() != *player).nth(0) {
camera.translation.z = contact_pair.manifolds[0].points[0].penetration;
}
}
I know what i'm doing wrong but I don't know the solution.
singles skip (annoyingly), or maybe your contact filter's not hitting, but idk which
What contact filter?
I'll go with the former. What should I do?
use Queries directly
the iterator adapters in your if let
wdym by "skip"?
the system made from fn qwe(_:Single<&Asd>){} will not run if there isn't an entity with an Asd component
I don't understand fully
But I have to add an asd component to the thing i'm queuing for queuing to work?
I'm confused, that seems counterintuitive
it's vaguely similar to fn qwe(q:Query<&Asd>){let Ok(_)=q.single_inner() else {return}}
Oh sorry I misread
The behavior is expected
No it's not skipping
In which case It's this issue in which I don't know what you mean by this sentence
The first body is always the closest right?
Along with the first manifold and manifold point?
collisions_with doesn't make body1 the given entity
Sorry I meant first contact pair
in which is the farthest right?
It says it returns the contact with the largest penetration depth
Which isn't helpful for a spring arm
Might just take the event approach, if this is more efficient then the devs would probably implement it soon
Oh wait I just realized what sorbitol was saying
Though How do I apply a RayCaster query into ContactGraph?
@snow urchin Sorry for the confusion. Raycasting and events/contacts are two different approaches to collision checking. The RayCaster-like approach seems to be what you started with. It's a fully manual way of finding entities with Colliders in the world from an arbitrary point and direction. AFAICT, all you need is Colliders on the entities you want to detect. You'd use the world position of the camera or spring arm to start the ray,camera.rotation * Vec3::NEG_Z for the ray direction (I.e. "stuff in front of the camera"), and iterate the RayHits after casting to see if you found something. (I haven't used this approach and am just going by the docs and examples.)
On the other hand, the event-driven approaches will let Avian do all the work for you -- more useful in scenes with more Collider entities. It's a similar scene setup (adding Colliders to things you want to detect) but also: (1) add Collider to your spring arm or camera, (2) add CollisionEventsEnabled to the camera/arm and things you want to hit (I'm unsure if you need to tag both, but I usually do), and then (3) process any generated events. Use either (a) On<CollisionStart>/On<CollisionEnd> events which are detected using observers in e.g. commands.spawn(...., Collider.... ).observe(event: On<CollisionStart>, ...) or (b) systems in the FixedUpdate schedule that iterate all events using MessageReader<CollisionStart>/etc.
The contact graph approach might be overkill here since it has all the potential and actual collisions for everything in the world (more useful in scenarios with a lot of colliders, for efficiency, but not likely useful here). I only mentioned it since it provided one method of detecting the amount of penetration between two colliders. There may be other ways of computing this in the raycaster or event driven methods.
tl;dr: check the docs.rs/avian3d pages, since they include a lot of more informed explanations and examples than I am doing here 🙂
Hello, is there a way to have multiple "physics scenes" (or something like that) to have separate physics simulations that don't interact with each-other?
as if the objects from those scenes were infinitely far away or something
can't use collision layers, each "scene" requires 20+ of them already
Overkill for a springarm? Yes. There shouldn't be a situation where the springarm is colliding with tons of colliders in one tiny space.
This seems to work well without event handling unless there's a specific reason to use it.
fn spring_arm(
spring_arm: Single<&RayHits, With<PlayerSpringArm>>,
mut camera: Single<&mut Transform, With<PlayerCamera>>,
player: Single<Entity, With<Player>>,
) {
if !spring_arm.0.is_empty() {
camera.translation.z = spring_arm.0[0].distance;
}
}
It removes the performance cost of observers in theory.
This part of the RayCaster docs is confusing:
Note that when there are more hits than max_hits, some hits will be missed. To guarantee that the closest hit is included, you should set max_hits to one or a value that is enough to contain all hits.
This implies that max_hits = 2 doesn't guarantee the closest is included when there's more than 2, but max_hits = 1 does (even when there's more than 1)
It's not clear why that would be
Does max_hits = 1 have special-cased different behavior from all other values? If so, that should probably be documented, like "If set to 1, the resulting hit will always be the closest one (if there are any hits)"
Can you define gravity direction on a per entity basis?
only with the constant force components et c
how would I rotate with forces api
Quat::to_scaled_axis?
how do you want it to act
you can either directly add rotational inertia (around CoM):
apply_{torque/angular_impulse/angular_acceleration}
apply_local_{torque/angular_impulse/angular_acceleration}
or cause it with a non-centered force:
apply_{force/linear_impulse/linear_acceleration}_at_point
or non-physically modify it:
angular_velocity_mut
Is there a terminal velocity component?
there's a max velocity (iirc) and a drag
Is there any way to disable rotation for a dynamic rigidbody?
Any reason dynamic rigidbodies don't stop against static ones?
they should
Forgot to add static bodies to the meshes in question, my bad.
Can spatial queries be made in parallel (on 6.0.0-rc.1)? Take a function like this:
fn apply_tension(
spatial_query: SpatialQuery,
spatial_input_query: Query<(&Transform, &Tension)>,
mut query: Query<(&Transform, Forces), With<Tension>>,
) {
query.par_iter_mut().for_each(|(transform, mut forces)| {
let collision_entities = spatial_query.shape_intersections(
...
does that not work?
@vestal minnow gm, why does jumping on the cube with a kinematic body (kinematic_character_3d example) makes the cube go through the plane ? how to prevent this
Works fine, I’m asking if those threads are competing for an atomic reference to the underlying spatial storage or not
no, the spatial query methods just use regular reading
only atomic in there is the Arc<dyn QueryDispatcher> afaict
I have a question, I want to make stuff grabbable which is already constrained by a joint.
In this concrete case, I have a string from a lamp to pull which is already constrained by a PrismaticJoint.
Then, when interacting with it, I thought I'd spawn a DistantJoint with the anchor at the interaction point with a "3d cursor" and then move it accordingly. The problem is tho that even tho the 3d cursor (kinematic rigidbody)'s dominance is way lower, it completely ignores the prismatic joint. What can I do to say "respect the PrismaticJoint more but when it's respected, still do the DistantJoint" or can I somehow apply a force to the string "to pull in the direction of the cursor" instead of a joint?
Thanks 😄
turn up the compliance?
Why doesn't CollisionHooks::modify_contacts get called when I have the collider as a child? Collision detection/resolution still works with the child collider but the hooks don't.
Does the collider have ActiveCollisionHooks::MODIFY_CONTACTS?
not the rigid body
Yes I tried putting it both next to the child and next to the rigid body (which works if the collider is next to the rigid body)
#[derive(Component)]
#[require(ActiveCollisionHooks::MODIFY_CONTACTS)]
pub struct RockCollider;
...
children![Collider::cylinder(0.28, 0.15), RockCollider]
Oh wait...
Forgot the tuple :/
yeah it's really footgunny, I debugged a similar problem for hours during the jam haha
Thanks for the help @vestal minnow ! I should have my eyes checked lol
I think the documentation could be improved to mention #[require(ActiveCollisionHooks::MODIFY_CONTACTS)]. From what I can tell it isn't part of https://docs.rs/avian3d/latest/avian3d/collision/hooks/trait.CollisionHooks.html. I took it from an example I found in the repo.
TBF I didn't actually read the Activating Hooks section either lol
mm yeah using required components isn't really Avian's concern to document, but it could still be worth demonstrating with a small code example in the docs since it might be a pretty common pattern for these hooks
That's what happens when an unstoppable force meets an immovable object :)
The collision algorithm for the KCC in that example is pretty hacky and not what you should typically use for actual games. It lets the physics solver handle the actual movement and collisions, and because kinematic bodies effectively have infinite mass, it just dominates any dynamic objects and can exert massive forces on them. KCCs shouldn't really use the normal physics solver for movement.
The KCC should really be using the new MoveAndSlide functionality, the example just hasn't been updated to use it yet. With move-and-slide, the KCC won't actually exert any forces during movement since it essentially stops right at the surface and slides along it. To apply forces to dynamic bodies, KCCs typically have some custom logic, see for example what bevy_ahoy does (though this isn't perfect as it only applies a force one way).
If you want a more complete KCC for 3D, then I'd probably recommend just using bevy_ahoy directly, or vendoring and modifying it to match your game-specific needs
We will eventually (hopefully soon) have examples of different kinds of KCCs using move-and-slide in Avian's repo too, no one has just made examples for it yet
tbh i'm leaning toward just not using the macro
Children::spawn((Spawn((..)),..)) is just a little paren heavy, perfectly readable
How come this exists if rapier works fine
That's like asking why Unity exists when Unreal Engine works just fine.
Avian is built to work natively with Bevy, that's just one difference between the crates. Rapier is a good physics engine as well.
How so?
Cuz it's basically the same thing
If u wanted ECS so bad, why not just add it on top of rapier?
Hey folks, I have a third person camera pointing at a moving entity - upon camera rotation around the vertical axis, I want to apply centrifugal force to a particular set of entities in the world, as if the camera is stable and the geometry is rotating. What is the best approach to this in avian? Is it to detect collisions for these entities and apply an impulse force? Surely it isn't to actually just rotate everything in the world, right?
- Some different APIs and features
- Different architecture and design choices
- Different priorities (Rapier seems to focus more on commercial users and industry than general users and indie game devs)
- Avian is more Bevy-focused, integrates with it better, and follows Bevy's conventions more
- Having more options in the ecosystem gives people more freedom, and drives improvements for everyone involved, e.g. if Rapier implements something cool, we may try to adopt it too, and vice versa
- I like making it, it's not like I'm getting paid to do this as my full-time job (though I do have some lovely sponsors <3)
You could also expand the question to other physics engines: why does C/C++ have PhysX, Havok, Jolt, Rubikon, and soon Box3D? Why does Unity DOTS have its own physics? Why does Roblox have its own physics? Why does anyone make anything if there's already an "okay" alternative?
Every engine has different design choices and tradeoffs, and has different ways to solve problems, what works best for a given project depends on what they need or want
How come you didn't fork rapier instead tho
so I have this force I want to apply, that is locked to +45 or -45 degrees of the main body
how would I apply the force so angular velocity also is applied
I.E. the main body turns towards the force direction
(but not snaps towards the force)
Have my current setup here
(relevant code is on line 86)
Hmm, I think you might want some kind of PD controller setup like this:
let forward = global_transform.forward();
let force_dir = force.normalize_or_zero();
// PD controller parameters, feel free to tune
let stiffness = 10.0; // higher -> turns faster
let damping = 2.0; // higher -> less oscillation/wobble
let torque = forward.cross(force_dir) * stiffness - ang_vel.0 * damping;
forces.apply_torque(torque);
(the names aren't from your code of course, so you'll have to change those)
I haven't tested the above, so no promise it works first try :P
but i should apply this along with the force, or will the torque also provide forward propulsion?
Yeah, apply both the force and the torque, separately
cool
force = linear
torque = angular
(also I know Swedish but having a FART constant is still funny to me haha)
Regarding this, I now have experimented with some compliances between "doesn't move at all" and "now it just randomly goes everywhere again" and seem to have found a sweet spot, but when I don't fully push it down it does this spring like thing. And I think it does that because of the compliance (?) but I need that because with a compliance of 0 it lets me just drag the thing everywhere on screen I want to. How can I make it respect the PrismaticJoint but still be as strict to the DistantJoint as possible? thanks
is the ang_vel.0 supposed to be angular_velocity() ?
Bumping my question, any thoughts?
Ah, it is yeah
weird, I'm not getting any rotation
I was thinking that you'd query for AngularVelocity, but since you have Forces too, the query would conflict. So yeah you need to access it through the .angular_velocity() helper
I would maybe log what values you're getting, and try bumping up the torque strength (stiffness in this case)
if the angular inertia is large compared to the torque then it might look like it has no effect
hmm wait is force supposed to be the resulting force?
force is the force (in Newtons) that you're applying to move in some direction
if you want acceleration in m/s², use apply_linear_acceleration instead
(and apply_angular_acceleration for turning)
or alternatively just don't use the Forces API, and manually modify LinearVelocity and AngularVelocity
let z : i32 = input.any_pressed([KeyCode::KeyW , KeyCode::KeyJ , KeyCode::ArrowUp]) as i32 - input.any_pressed([KeyCode::KeyS , KeyCode::KeyK , KeyCode::ArrowDown]) as i32;
for mut kraft in &mut force_query {
let forward = hjulen.local_z();
let force = *forward * z as f32 * FART;
let ang_vel = kraft.angular_velocity();
let styv = 100.0;
let damp = 0.5;
let tork = forward.cross(force.normalize_or_zero()) * styv - ang_vel * dämp;
kraft.apply_angular_acceleration( tork );
kraft.apply_linear_acceleration( force ) ;
// got these values from println!(tork);
// Vec3(6.2881384e-8, -3.8403947e-8, -8.940707e-8)
// Vec3(-5.4124694e-8, -6.233105e-8, -1.4677661e-7)
}
tried this and apply_force / torque and can't seem to get any rotation
seem to be getting a super tiny piece of torque
forward is meant to be the forward direction of the car
and force should be in the direction you're trying to move
right now I think they point in the same direction, so the angle difference is zero and the torque ends up being near-zero
oh something is wonky with the coordinates too
so the camera is looking from -x towards +x, and it looks like that is assumed to be the forward direction for the car too, but the wheels have their forward direction along the z axis
the wheels and car basically seem to be at a 90 degree angle
this seems to work for the forward direction and force, kinda
let forward = bilen.local_x();
let force = *hjulen.local_z() * z as f32 * FART;
set styv way lower to 1.0 or something
however I would strongly recommend fixing up the coordinates lol, the car and wheels should have the same forward direction (ideally towards -z)
or not the same forward direction, but that when the wheels are in the neutral position, they should line up with the car
I wonder if I should change from a ConstantForce to a force only when the player doesn’t hold it after reading this here, but I still worry that the stiffness then will just make it slide down
excellent mischief, I approve 
doing this lets it turn but it gets a bit funky
it only turns towards the right despite wheel direction
are there any good crates for car physics in avian?
depends on how they're differentiated
Do you mean how the objects are different from the rest of the scene? Or (I promise I am not taking the piss, I have a math degree and this is a physics engine channel) do you mean the change in their position over time? I assume the first, so they are some number of spheres that are attracted to each other via some forces applied by a system. My thought process with the “detect collision and apply impulse force” was that since they are spheres applying it to the center of mass when contacting the scene is fairly easy? I think this might be unphysical though?
i meant something like, are they experiencing the centrifugal force according to an arbitrary flag or because they're touching something
or third option, everything's doing it but you don't want to deal with a rotating scene
Because they are touching anything else - I don't think it makes sense to try to make everything else rotate? That seems much more complex, though I could be wrong... At least I think "this is touching an object that is rotating, so it should get some centrifugal force applied" is a good first pass at this, but it might be missing the complexities of friction, etc
free floating objects in a rotating reference frame experience virtual forces
What I want is effectively to emulate rotating the world and camera at the same rate around a vertical axis, without having to do the work of actually rotating every body - I think that means these forces aren’t applied to free floating bodies?
if there wasn't gravity, you'd expect a still object to look like it's moving in a circle to a spinning camera, yeah? means in the rotating frame, there're virtual forces keeping it going around
// very unexpected behavior but IG multiplication with quaternions is directional
let foo : Quat;
let bar : Vec3;
foo * bar // no error
bar * foo // no implementation for `bevy::prelude::Vec3 * bevy::prelude::Quat`
Correct: quaternions are non-commutative
That also means that Quat A * Quat B is different from Quat B * Quat A
Hello, I would like to use the move and slide from the release candidate but i'm getting build errors around glam types. Anyone know why ?
run cargo update
Cargo doesn't like that OBVHS uses a different version of Glam and gets confused without the update
Thanks
Wait, update fixes that?
I didn't need to edig the Cargo.lock????
yup
are there any fixes for ghost collisions?
using bevy trenchbroom & ig I could just merge all the meshes into one
Is your ground not just a single brush?
could make it
But yes, if you search for it here, you will find settings that help
oh
only found ppl talking about it
ColliderConstructor::TrimeshFromMeshWithConfig(TrimeshFlags::FIX_INTERNAL_EDGES)
@heady oasis this is what I was referring to
(If what you’re experiencing are really ghost collisions; it’s hard to tell from the video)
so speculativemargin on the player or the map
Player
Would you mind taking a video with the physics debug view on?
how do I enable that?
yeah that works
there are still edgecases though
but that's specifically when hitting a 3 way corner
Hi everyone, hope you are doing great 🙂 I was wondering what would be "cheaper" to do to get some measurement from a Collider. Let's say I have a Collider::circle(25.0). Should I do something like collider.shape().as_circle().radius or take it from collider.aabb(...)? Sorry if this is a super obvious question...
Hello, I'm making a custom constraint on 0.6.0-rc1, but I can't seem to get the angular correction working. I want to use MotorModel to drive the rotation and angular velocity of a body to some target values, but it has some instability and slow convergence that I can't figure out. I'm also doing a similar thing for positonal corrections, and that seems to work just fine, so I reckon it must be something with my angular correction code.
This is the code I currently have for the angular correction: https://github.com/BigWingBeat/birdthing/blob/58886eb208469c1ab20bf56fac64b86641c5af82/src/character_controller/joint.rs#L124-L199, a lot of it is from copying and modifying code from Avian's own joint impls.
was there a logical change to PhysicsDebugPlugin ? I just upgraded bevy 16 -> 18 including all plugins and things work fine (e.g. physics themselves) but it no longer renders the debug info.
ah nvm found it, had to add bevy_ui_render feature
It's better to use shapecast and mass-spring-damper model for car suspension, you will need only the distance to the ground
No contact normals - no ghost collisions at all
if you look at the aabb() implementation, you will find that it's specialized for every kind of shape. As such, doing .aabb() on e.g. a circle is almost free
yeah I went and made custom springs for the car
Thanks a lot for confirming this 😄
hehe, I had the same issue at some point (related to getting the radius of the player collider in the general case) and got worried about the cost
but since the player is always a simple primitive like a capsule or cylinder, it's dirt cheap 🙂
How do I make the player not slide around like this? I tried many different things apart from directly modifying velocity, including setting linear velocity, accel, various forces/accels, etc. Increasing friction just makes it slide around a little slower, and makes acceleration annoying. This is my latest attempt.
pub fn process_player_inputs_fixedupdate(
mut player: Query<
(
&Transform,
&DesiredMovements,
&GroundEntityMoveStats,
&mut ConstantForce,
&mut AdvMobility,
),
(With<Player>, Without<Camera3d>),
>,
) {
let (transform, desired_dirs, stats, mut speedcontrol, mut a_mobility) = player
.single_mut()
.expect("Multiplayer is not supported yet");
let wants_jump = desired_dirs
.modifiers
.contains(DesiredMobilityModifiers::JUMP);
if wants_jump {
// TODO: Double jumps in the air with a powerup
a_mobility.jump_ticks += 1;
} else {
if a_mobility.is_grounded {
a_mobility.jump_ticks = 0;
}
}
if desired_dirs
.modifiers
.contains(DesiredMobilityModifiers::CROUCH)
{
a_mobility.crouch_ticks += 1;
// TODO: Handle crouching
} else {
a_mobility.crouch_ticks = 0;
}
const TROUBLESHOOTING_VECTOR_MULTIPLICAND: Vec3A = Vec3A::new(4., 1., 4.);
let move_vector = stats.get_vector_for_desired_movements(
desired_dirs.horizontal,
desired_dirs.modifiers.determine_state(),
transform.forward().to_vec3a(),
transform.right().to_vec3a(),
transform.up().to_vec3a(),
a_mobility.jump_ticks as f32,
wants_jump,
) * TROUBLESHOOTING_VECTOR_MULTIPLICAND;
let move_vector = move_vector.to_vec3(); // saves 3 __m128 unpacks
speedcontrol.x = move_vector.x;
speedcontrol.y = move_vector.y;
speedcontrol.z = move_vector.z;
}
(Also I have no idea how to stop the random rotation, and I would use a capsule collider if it could stand upright, but those aren't as pressing)
My take on this:
ConstantForcemight be incorrect here. I think it's causing the sliding since that component is meant for e.g. wind, gravity, etc. where you want Avian to smoothly move and accelerate stuff over time. It's the wrong dimension for player movement, which is applying instantaneous nudges to velocity, which increases to some maximum then decays after inputs cease. I'd recommend usingLinearVelocityinstead, with a similar increase/decay over time corresponding to activity on inputs for each axis.- Jumping can be a single application of a large (mass-based) change to
LinearVelocity.y. Use a flag likejump_just_pressed: boolto avoid (or limit) multiple jumps. (Seeavian3d::prelude::Forces::apply_linear_impulsefor an example.) - For friction, I use
Friction::ZERO.with_dynamic_coefficient(0.0).with_static_coefficient(0.5), on the player. That makes the player stop smoothly when no more movement is desired but apply no friction when it's moving. - To make your player capsule stand up, add
LockedAxes::new().lock_rotation(). Then you're in control of all the rotation.
The other stuff you mentioned did help, but when I set LinearVelocity directly, the player never falls to the ground. Any change in Y is in hundredths of units (or up because I haven't gotten around to fixing my jump logic for pre-ground contact yet)
I just tried only setting Y velocity when the player wants jump, now friction doesn't work at all, it just stops abruptly
Oh, I think I see. The LinearVelocity will accumulate y changes over time due to Gravity/GravityScale. So just be sure not to overwrite it. I.e. add to the y. Or to all the components, actually
I had problems adding it to linearvelocity as well a bit ago, the player would shoot off into the aether
It feels like to solve the problem, I would need to be able to modify a separate velocity layer entirely that only applies/scales with the player's linear velocity, sort of like "desired" vs actual
if I just added it in steps, the player would most likely have herky-jerky motion
It slides around because in your impl, a zero move vector means you apply zero force to the body, so inertia takes over and it continues moving in the same direction. If you want a zero move vector to stop the body from moving, you'll need to then apply a force opposite to its current velocity, until the velocity drops to zero.
Should I have a separate bitflags struct that tracks the previous movement state so I can determine whether the key was just released, so as to manually maintain a layer on top of whatever force I use?
I think this is the case. In my instance I have a velocity_ramp and velocity_ramp_scale which acts as the rising/falling multiplier for the LinearVelocity adjustment while movement inputs are active. And a manual clamping layer, at least while you're debugging.
Or should I simulate actual bipedal walking? Would be difficult to implement with my limited understanding of inverse kinematics
Yes, but I recommend using something like leafwing-input-manager or bevy_enhanced_input -- it'll track these states for you (i.e. LIM has "just_pressed" and "just_released")
The way I did this was by interpreting the movement vector as a target velocity, then instead of applying that as a force directly, the force you apply is target_velocity - current_velocity, which will accelerate the body to whatever the target velocity is, including if the target is zero velocity.
nooo, unless you're implementing QWOP 🙂
See: https://github.com/BigWingBeat/birdthing/blob/4491297c0993e4a7c2550546546254976c2ca10b/src/character_controller.rs#L80-L113 (Although this is an old impl that I've since replaced)
This is my current input code, it uses a custom subcrate I made called directionlib and inside the filter_event function it just determines what to do based on which keybind I have bound. This is the player logic.
pub fn keyboard_input_event(
mut player: Query<&mut DesiredMovements, With<Player>>,
controls: Res<Controls>,
mut keyboard_input_events: MessageReader<KeyboardInput>,
mut exit: MessageWriter<AppExit>,
) {
let mut desired_movements = player.single_mut().expect("No multiplayer yet sorry :(");
for ev in keyboard_input_events
.read()
.filter_map(|e| controls.filter_event(e.key_code, e.state))
{
match ev {
ControlResult::Exit => {
exit.write(AppExit::Success);
}
ControlResult::MoveOn(m) => {
desired_movements.horizontal = desired_movements.horizontal.union_direction(m);
}
ControlResult::MoveOff(m) => {
desired_movements.horizontal = desired_movements.horizontal.difference_direction(m);
}
ControlResult::CrouchOn => {
desired_movements.modifiers = desired_movements
.modifiers
.union(DesiredMobilityModifiers::CROUCH);
}
ControlResult::CrouchOff => {
desired_movements.modifiers = desired_movements
.modifiers
.difference(DesiredMobilityModifiers::CROUCH);
}
ControlResult::JumpOn => {
desired_movements.modifiers = desired_movements
.modifiers
.union(DesiredMobilityModifiers::JUMP);
}
ControlResult::JumpOff => {
desired_movements.modifiers = desired_movements
.modifiers
.difference(DesiredMobilityModifiers::JUMP);
}
}
}
}
This is my player now.
impl PlayerBundle {
pub fn new(pos: Vec3, mesh: Handle<Mesh>, material: Handle<StandardMaterial>) -> Self {
let transform = Transform::from_translation(pos);
Self {
transform,
locked_axes: LockedAxes::new()
.lock_rotation_x()
.lock_rotation_y()
.lock_rotation_z(),
mesh: Mesh3d(mesh),
material: MeshMaterial3d(material),
rigid_body: RigidBody::Dynamic,
collider: Collider::round_cuboid(1., 1., 1., 0.25),
friction: Friction::ZERO
.with_dynamic_coefficient(0.0)
.with_static_coefficient(0.5),
restitution: Restitution::ZERO.with_combine_rule(CoefficientCombine::Min),
center_of_mass: CenterOfMass::new(0., -1., 0.),
gravity: GravityScale(1.),
move_stats: GroundEntityMoveStats {
jump_impulses: GroundEntityMoveStateArray::new(4.2, 6.5, 6.2, 5.6),
step_velocity_multipliers: GroundEntityMoveStateArray::new(2.5, 7., 9.3, 12.),
transition_ticks: GroundEntityMoveStateArray::default(),
max_jump_ticks: GroundEntityMoveStateArray::new(40., 40., 40., 40.),
},
..Default::default()
}
}
}
(Had to truncate the output bc Discord yelled at me), that's what the ..Default::default() thing in there is for. I actually initialize everything in code
OK, I think you can add a step in your movement processing where if desired_movements.horizontal is empty, clear out accumulated velocity. I have this kind of logic, along similar lines, for planar movement (the jumping code adds a lot of complexity):
PlayerInput::Move(_, input) => {
instant_thrust.x = Into::<f32>::into(input.right_left) * input_settings.move_scale.x;
instant_thrust.y = Into::<f32>::into(input.up_down) * input_settings.move_scale.y;
instant_thrust.z = Into::<f32>::into(input.forward_back) * input_settings.move_scale.z;
instant_thrust = instant_thrust.clamp_length_max(1.0);
if instant_thrust == Vec3::ZERO {
movement.velocity_ramp = 0.0;
}
movement.velocity_ramp = (movement.velocity_ramp
+ input_settings.velocity_ramp_scale)
.clamp(0.0, 1.0);
let dir_velocity = transform.rotation * instant_thrust * movement.velocity_ramp;
(sorry, left out the important part)
accumulated velocity?
That's like I mentioned (and like you inferred was necessary) -- a side data structure that tracks how fast the player should be going, based on continuously-pressed movements.
To be honest I would try to mess with accel first because that is the derivative of velocity, so it would make the code less manual if it worked out
it feels weird because we are sidestepping the physics engine
I want to work with the tool, not against it
You're not, though. Applying changes to linear velocity is the key to the issue for responsive FPS-like behavior. That's the kind of control you need for a player controller. Adjusting force would work if you account for mass and the time delta, but it gets finicky real fast.
add damping when there's no input
There is a LinearDamping component mentioned in the docs, I will try that out
(I guess I'm using acceleration to a degree, on the side -- don't take my word for any of this. I have spaghetti code which works but likely isn't the best way to do anything 🙂
just do it manually and only on 1 plane so that it doesn't affect jump/fall
you basically only have your XY velocity and desired XY velocity, so there's not much you have to work with but you can make a curve to adjust the feel, you can even combine it with acceleration/speed/velocity, which is what i'm assuming @wet niche is doing there
How do you lock it on one plane? I don't see any impl blocks for that component, and it just derefs into a float
i'm talking about manual, built-in one is just bad for this purpose because you'll just make it feel like you're walking through water
If the player gets hit with a comically large baseball bat, it should go spinning off and flying into the abyss like a gmod or roblox character
hmm that's an idea...
Right, but that's why you want to add to LinearVelocity based on the desired movement, not completely replace it.
I recommend looking at BigWingBeat's source reference above if you want to work based on forces (and use the handy Forces parameter instead of handling a long list of components).
oh, i didn't even notice it was applied to constant force, yeah you need to add to LV unless it's kinematic
constant force is for things like rockets/bullets
Idea: I use LV. Store the unmodified velocity as well as the modified velocity from the last tick. Compute differences to determine how much velocity is there that I didn't cause. Add that to my desired velocities, then directly set LV to the result.
This has the benefit of just doing some SSE2 float manips instead of pulling several unrelated strings
Heh, don't worry about the performance until it works. Player controller is the least impact to performance.
But otherwise, tracking all the velocity manually is overkill. Just add to LV.x and LV.z based on how much the player wants to move.
But then if I add velocity, I get the same problem I had with one of my older projects where the player kept shooting off into infinity
And also I might want to set accel instead if I am doing that
About the perf thing, really I'm just trying to describe code complexity
The going-into-infinity may just be a scaling issue. Be sure to scale down by Time::delta_secs(), for example.
Also, I think any player controller will need a vel = vel.clamp_length_max(max_speed) somewhere. The player will have a key pressed for a long time but that doesn't mean they go faster and faster -- just faster up to the maximum speed you want.
Wait why use delta_secs if we're talking about FixedUpdate? (Sry I named my function that above but I didn't ever mention the schedule)
FixedUpdate is done e.g. 60/120/whatever times a second, even if that's a constant value. IMO it's safer to use Time whereever you can, so it doesn't break when switching schedules.
Maybe I'll add a scalar for that but just define it in const
Plus time delta is variable because even if our process has realtime sched priority, the actual electronic components are inherently analog so it would not be as good as if we just assume a constant time and go from there. Clocks have jitter. Some instructions are hardwired to take variable amounts of time. Don't get me started on the ludicrous timing discrepancies I've had to deal with in embedded dev
There's also probably some way to get the tickrate. If not at compile time, maybe through an engine system. The benefit is that if I need to change the tickrate because this is an exploration game and not an FPS, I would be free to do so.
Just use Time::delta_secs. Then you're not coupled to whatever system sets the rate.
I don't trust computer clocks. I've been burned too many times
Monotonic clocks are specifically designed to not change if the CPU frequency changes. That's specifically why I would never want to rely on it for something that moves in lockstep with the schedulers, which are all running on the CPU
Good news, these are not CPU-based clocks.
I am told fixedupdate is fixed. It cannot be truly fixed because of the fundamental nature of electronics, so in this case, we have to implicitly trust the engine's promise, since any number of systems are interacting behind the scenes.
So that's why I don't want to use delta secs. I have no idea if it counts its own internal schedulers too
shooting off into infinity is an indicator of another bug, it doesn't mean that adding to LV is wrong
and fixed updates are usually used as turns, so multiplying by delta would just break that
it just makes it slidier
tried it just now
did you add damping?
yes, my linear damping is 0.8\
manual.
oh not yet
linear damping = walking in water
manual damping = applying a counterforce to slow down
games like titanfall 2 go a step further to retain momentum using essentially the same thing
Maybe if the player is grounded and no movement keys are pressed, a pulse of accel in the opposite direction of the previous velocity vector slows it to a stop. If the player is grounded and presses a movement key, I either manually add some accel to the vector I would be adding to the velocity or try to use avian3d for that
that's exactly what i was talking about for 1 hour now 🫠
whether you want it only when grounded or in air too is up to you
and previous velocity is just linear velocity
fixedupdate has a fixed delta
it only runs on an update, but the time will never change step
say fixed dt is .1
starts with 0 elapsed time and 0 fixed elapsed time
there's an update, +0.05, so now Time<Virtual> has 0.05 elapsed
another update, +0.05, total 0.1, so it runs a fixed timestep, bringing elapsed Time<Fixed> to 0.1
+0.08, v=0.18, f=0.1
+0.10, v=0.28, +fixed, f=0.2
+0.12, v=0.4, +2fixed, f=0.4
etc
the way i set up my player movement was to add the control direction to the velocity, then also nudge the velocity so its direction is much closer to the control direction (also decelerating for zero control)
Update: I got much more satisfying movement results with the following logic
// in process_player_inputs_fixedupdate
speedcontrol.x = flt_signed_abs_maxof(speedcontrol.x, move_vector.x);
speedcontrol.y = flt_signed_abs_maxof(speedcontrol.y, move_vector.y);
speedcontrol.z = flt_signed_abs_maxof(speedcontrol.z, move_vector.z);
}
fn flt_signed_abs_maxof(control: f32, test: f32) -> f32 {
let isneg = control.is_sign_negative();
if isneg == test.is_sign_negative() {
if isneg {
control.min(test)
} else {
control.max(test)
}
} else {
control + test
}
}
I haven't really found any damping values I like yet, but I am still searching
you're really overcomplicating it
I might also simplify my input system so it adds the move vectors directly to a swap buffer vector. Shouldn't make a noticeable difference in perf because it is a sse add, but it would simplify my other code a lot.
well wait it would recalculate view directions
I might just keep what I have, because it is well-separated from the rest of the implementation, and I wouldn't have to care about yet another place that modifies the player rigidbody state
making a git commit before I break everything all over again lmao
are you vibe coding this
I have been trying to get AI to generate decent stuff but every single time I ask for anything, the results disappoint me
plus this is the kind of logic that requires actual playtesting, which is what I am doing
I know, it feels like it too. The problem is that a lot of this stuff is either stuff I already tried, or stuff that is too predictable and not enough like gmod
I honestly have no idea what I am going to do when it comes time to turn this into a ragdoll.
you'll probably end up cutting it in half after working on it for the next year
well if I can cut it in half today, it will make it a lot nicer to work with, and it would also improve performance in multiplayer if I ever go that route (because packets)
is it currently kinematic?
no, it is still dynamic
then it should be simple enough, just remove your component and let physics take over
A detailed look at how we built our physics-based character controller in Unity for our game Very Very Valet - available for Nintendo Switch, PS5, and Steam
BUY NOW!! https://toyful.games/vvv-buy
~ More from Toyful Games ~
- Animation Deep Dive mentioned in the video - https://toyful.games/blog/character-animations
- Custom Car Physics in Unity...
I can disable regular movement if the player is either in the air, or is grounded but lying down (in that case you would press any key to get back up)
thanks I will watch that
Update: I finally got around to implementing airjumps, the jump code is longer but now it's a lot better than syncing 2 booleans. I am going to do the key state thing (it is a couple bit manipulations don't worry) and manually damp horizontal velocity. I tried doing this with accel but it was just too weird, so I'm giving up that idea. I still need to test with other rigid bodies as well as with jetpack force applied with ConstantForce
they have a second video they made for vehicles that shows how to do horizontal damping/velocity/accel
FYI you will want to use 0.6's MoveAndSlide for that 
Except if this is jetpack movement
Then disregard what I said
the car video is great! I used it build a car controller. My version is ...ok at the moment. But needs work.
can't tell what's going on without code and knowing more about when this happens 😅
That's actually why I abandoned cylinders very early on. They seem to be pretty buggy in avian3d
have made a working raycast based car controller from that video 😁
got that exact same bug when following along
its because avian is a bit more "stuff" to walk around
assuming your code looks something like this:
for wheels in wheel_query:
let raycast = spacial_query.cast_ray(at the wheel, pointing downwards) {
let new_height = SPRING_REST - raycast.distance;
let damping = SPRING_DAMPING * forces.get_velocity_at_point(where the wheel is);
let spring_force = new_height * SPRING_STRENGTH - damping;
forces.apply_force_at_point(spring_force * 5.0 , where the wheels are);
// calculate the steering force
// calculate the gas/break force
}
this code would make vibrations resonate with themselves
as you are multiplying the force (which includes the current speed)
then again this is why my code didnt work as expected
but for you it just looks like the car is struggling to find a right position for the wheels
hehehehe
damn @spare lily that gif looks cool
thanks for the PR, I'm super excited to review it later 😄
Yes sorry @sleek thicket I was a bit light on details. @heady oasis I too had a double strength force. But mainly my mass + gravity scale was to high, I compensated with high spring stiffness which caused the tap dancer. The springs are a bit soft at the moment but I think I can tweak this to right place.
@smoky sand I use shape casts with spheres for my distance check. I shrunk the chassis collider to allow the body to flow over terrain easier.
This is a really great talk on the subject of car physics controller too https://www.youtube.com/watch?v=ueEmiDM94IE - I like the start fun, don’t over simulate approach
In this 2018 GDC talk, Psyonix's Jared Cone takes viewers through an inside look at the specific game design decisions and implementation details that made the networked physics of Rocket League so successful.
about this again, what is a way to make such spring-like thing where I still have the option to attach it to a "3d cursor" without it behaving so weird?
you could try the ```rust
offset * strength - ( speed * damping )
I'm sorry, was that referring to my problem or the message above?
yeah
then just put in offset as the wanted length - the current length
and clamp it to the max and min lengths of the rope
so you mean I shouldn't use avian for this at all but directly move it? I'm sorry I can't quite follow
no do force.add_force ( that value)
ohh so no constant force
constant force?
My rope has a constant upward force via the ConstantForce component currently
as it automatically goes up
when I do the offset, I'd use abs(cursor.y - rope.y), right? Do I even need the DistantJoint then?
that should give you a wrong wanted position
or the wanted "length"
you'll rather want the distance from the cursor and the lamp joint
so where the rope starts
then take that -whatever length the rope currently has
ohh i see
though that will only take care of y direction
the rope will then not swing left nor right..
and that isn't possible?
no you could simulate that separately
just that this formula doesnt include x or z
so it wont move in either x or z from this script (as of now)
essencially you should have something like this
let rope_length = joint.y - rope.y;
(cursor.y - joint.y - rope_length) * rope_strength - ( forces.get_velocity_at_point(rope) * rope_damping
as joint.y cancels out itself here your earlier code snipped actually works here too
okay let me try that 😄
so this would be the simplified expression ```rust
let force = (cursor.y - rope.y) * rope_strength - ( forces.velocity_at_point(rope) * rope_damping;
forces.apply_force(force); // either this if that works out, forces api takes care of delta time so dont worry about it too much
forces.apply_local_force(force); // this is the code I think would work best, as the above doesnt take where the rope is into account
forces.apply_force_at_point(force , rope) // this might work best but unsure if local cordinates work here aswell, as the force value you calculate above isn't in global space
for a first test something like 10 for the strength and 2 for the damping seems to work fine
a higher value would mean the spring is stronger
or damping is more powerfull
ohh okay since the stiffness I hesitate before putting anything over 1.0 in anything in avian 😄
you'll need to query the forces api
nvm it's named without the get
I usually just do update but I dont think it matters with force api
I forgot to remove the ConstantForce, I'm stupid
no worries
it get's better, but I have to drag more before it even starts and still jaggs
this is with apply_local_force and apply_force
maybe try 100 on the spring strength
heh that's even funnier
oh?
hmm
huh
there's something else what's weird
I'm getting avian3d::dynamics::rigid_body::mass_properties: Dynamic rigid body 166v0 has no mass or inertia. This can cause NaN values. Consider adding a MassPropertiesBundle or a Collider with mass.
oh
you could also add
Mass(1.0)
this doesn't make sense
I now add a ColliderConstructor::Sphere(0.1)
same error message
did you add a mass?
doesn't ColliderConstructor do that itself?
I've removed all 3 manual ones for the Collider
even with a Mass it's the same error
just do Collider::sphere( 0.1 ),
with or without explicit mass?
try either
same result
I use skein btw
but it doesn't matter if I first add the rigidbody or first all the other components
are you adding this in blender or in code?
the mass and rigid body are added in blender
add them inside code maybe?
so
commands.spawn((
Rigidbody::dynamic,
Collider::Sphere(0.1), // or just Mass(1.0) if you don't need a collider for this entity
//other components
));
also here is the code I used in my car game```rust
let speed : Vec3 = forces.velocity_at_point(current_pos);
let offset : f32 = wanted - current;
let new_pos: Vec3 = current_pos + Vec3::new( 0.0 , offset , 0.0);
let local_up : Vec3 = *Dir3::Y;
let power : f32 = strength * offset;
let relative_speed : f32 = local_up.dot(speed);
let dampening : f32 = DÄMP * relative_speed;
let resulting_force : Vec3 = ( power - dampening ) * local_up;
forces.apply_force_at_point( resulting_force , new_pos );
to get a stable spring force (upwards)
you got it working?
now the problem is that it's too heavy
how are you setting the y for the rope?
blender likes to export it in its .blend directory after every reboot, so I didn't overwrite the asset ._.
oh
let force = (cursor.y - rope.y) * 100.0 - (rope_force.velocity_at_point(rope) * 2.0);
rope_force.apply_local_force(force);
no like somewhere the height is clamped
fn ready(
_: On<SceneInstanceReady>,
mut commands: Commands,
a: Single<Entity, With<desk_lamp::Rope>>,
b: Single<Entity, With<desk_lamp::TheBase>>,
) {
println!("Spawning PrismaticJoint!");
commands.spawn(
PrismaticJoint::new(*a, *b)
.with_slider_axis(Vec3::Y)
.with_limits(0.0, 0.1),
);
}
oh
force here is a vec3
try saying
let force : f32 = ...
you might want to get the speed in the y direction
so velocity_at_point(rope).y
wait yeah, how would it even go up by default
because the speed points downwards
like when I don't press then there's no cursor so no force will be applied
yeah
wait I'll change that
even then, as long as I don't click, the system won't run as theres no cursor.y
oh?
then you just set the wanted height to 0
so it should still run but wobble to 0 instead
so 0 - rope.y or just 0 directly?
cursor.y here represents the wanted length
and rope.y represents the current
so eventually, as you set the wanted length to 0 you'll get the height 0
so 0 - rope.y
becomes 0 over time
you also need to change
forces.apply_force(force * *Dir3::Y) // as apply force takes a vector
do I then apply Vec3::new(0.0, force, 0.0)?
btw
ah perfect timing 😄
:c
you need to increase the damping and you might want to look over the "offset" part of the code
let cursor_length = joint.y - cursor.y;
let rope_length = joint.y - rope.y;
let offset = cursor_length.clamp( 0.0 , rope_max) - rope_length // cursor_length - rope_length or wanted - current
well I do let cursor = if let Some(cursor) = cursor { cursor.translation() } else { Vec3::ZERO }; currently
that should work
hmm
yeah no the offset code is wrong
the joint.y doesnt cancel out
wait that makes no sense
this should work instead
because when my cursor is at the most top position it's still not 0
also I want to not move it directly to the cursor but with the offset of where the joint is
yeah
whats rope_min and rope_max tho
and joint is the base of the lamp, not the joint between cursor and rope, right?
therefore rope_min is redundant (just use 0)
now I don't even have to drag LUL
yeah maybe try a strength of 10 or 20
hm
so with a strength of 1.0 it was constantly down
with 5.0 it jaggs when not being touched but still goes down completely
just wouldnt go down or just wouldnt got up?
how does your code look rn?
wait I'll try once more with a lower mass
okay
with 0.05 Mass it looks okay
tho it feels too smooth idk
also, maybe a silly question, but why did "just adding PrismaticJoint for the locking and DistantJoint for the cursor" not work?
sry but kinda know nothing about prismaticjoint tbh
I don't have much (any) experience with physics engines but from a quick docs read it looks like that would be the normal solution, this feels more like manually setting a position
it's an axis locked distantjoint
yeah there should be some sort of in-engine implementation of springs
but this code is just the formula for springs
offset * strength - ( speed * damping )
hmm
what if I always make it retract to the offset but let the DistantJoint handle the dragging?
I fear that this will make it go up and down again tho
if you want it less smooth just bumping up the spring strength should work
what still bugs me is that this isn't like a normal spring
it's a spring where the retraction point is dynamic via my cursor
but I have modified the code again so that cursor is always 0 and now it jaggs again when I drag it down 😭
what code do you have?
let wanted_length = joint.y;
let rope_length = joint.y - rope.y;
let offset = wanted_length - rope_length; // cursor_length - rope_length or wanted - current
println!("{offset}");
let force = offset * 1.0 - (rope_force.velocity_at_point(rope).y * 2.0);
rope_force.apply_local_force(force * Dir3::Y);
and then a DistantJoint which connects the rope and the cursor
to "drag it down"
wanted_length should be joint.y - cursor.y
yeah it was before
but I don't understand why the spring's wanted center should move here
like don't I want the spring to still be forced to go up, just that my distantjoint makes that impossible as I grab it?
like when I grab a spring in real life it still gives force upwards, it just cant move as I'm stronger (most of the time)
sure but that code wont react to the cursor
yeah that's what the DistantJoint is for, like the "I grab you now, you cant move"
and the cursor is a kinematic rigidbody so the spring has to move
it'll just snap to the new position, right?
as long as the cursor applies velocity it will affect the spring script
the cursor doesn't apply velocity I think
I just have a kinematic rigidbody (my cursor) and a joint between it and the rope at the point where I clicked
then you kinda have to " delta length over time" and get the speed from there
huh why
doesnt the joint already do that?
like I thought a joint would mean that infinite force is used to minimaly comply to it
but here, as it jaggs, the joint isn't really treated corretly
try reading the speed
if it changes then the joint thing applies speed
otherwise you need to add it manually
(in that case you are "teleporting" the spring around - so it jaggs)
am I misunderstanding joints?
how do I even read the speed
Velocity component?
whut ._.
this looks somewhat better
like essentially I want to first respect the prismaticjoint and as long as that is fulfilled I want to respect the distantjoint with the cursor, but it seems like that's not now physics engines work?
just print the velocity_at_point
okay so I have thought a bit about it and am replacing the cursor joint with a system that just tries to "drag"/apply velocity at the point clicked towards the cursor.
now my question: how do I make it apply a force towards one point?
do I even use force or linear acceleartion?
this is one approach
otherwise you just apply a force in that direction
that has a chance to overshoot but if you smooth it a bit it might not do much
both are the same
just different ways of accessing them
angular acceleration is torque
linear is force
:P
the vector from A to B is the same as B - A
so
let force_direction = point - position;
yeah I tried that before but that made it directly go down
or maybe I just made something stupid because I did apply_force_at_point
hmmm
let force_direction : Vec3 = Vec3::normalize(cursor - rope);
let force : f32 = power / rope.distance(cursor);
forces.apply_force( force * force_direction)
don't I need to normalize the direction?
yes
mehh
it would be so cool to have a "apply_force_towards_point" function
now either I have a smaller strength and the spring is strong enough to pull it up
or I give it a stronger strength and then it goes over the goal and back
Hi, when I add a voxel to a compound, the voxel stops colliding. Is this a regression? Collider::compound(vec![( // calculates to Vec3::splat(8.0) Vec3::splat(-((HEKAT_SIZE+1) as f32 / 2.0)), Quat::IDENTITY, Collider::voxels(Vec3::ONE, &collider ))]) however, this works Collider::voxels(Vec3::ONE, &collider ))])
That's not something we can fix on Avian's side, it's a current Parry limitation
https://github.com/dimforge/parry/pull/336
(they have since added shape casting support, but no non-convex collisions for voxels still)
im getting very poor performance when i set transforms for 15 kinematic rigidbodies every tick. i make a set of hitboxes for my character and i just sync them to skeletal bone positions in FixedUpdate. this causes fps to drop to 12-15, for only 1 character. it is definitely coming from setting the transform. if i comment out the line setting the transform, performance goes back up to 60fps. They have kinematic rb, Sensor, CollisionEventsEnabled and SleepingDisabled.
why does the CollisionEnd event not trigger when i remove a collider from an entity that was colliding before?
is there another event that i can hook in that notifies me of this?
So the hitboxes of your character are independent rigid bodies? Do they have joints between them? Is one of their parents also a rigid body?
Do the individual hitboxes collide with each other?—i.e. does their CollisionFilters mask include their own layers?
I'm curious whether you'd see better behavior using 0.6-rc.1's CustomPositionIntegration
haven't put any explicit collision filters yet. they are independent kinematic rigidbodies, no joints. they do overlap a bit in some places but it's only 15 and only on one character. should not be this big of performance impact.
I agree that it shouldn't have such a big impact
I'd suggest either trying to isolate a minimal reproduction (e.g. can you observe the same without collision events, with simpler? collider shapes, driving transforms by something more specific/simpler than skeletal animation, with fewer other things in the world), or using Bevy's Tracy support to see what systems are taking more frame time—whether it's truly in the physics update or if this indirectly is slowing something else down
Avian also has a debug profiling UI (behind a feature?) that you could use to see how long different steps are taking
try making them static bodies, could determine if intercollisions are the problem
is that with cuboid/capsule colliders?
Hello all, I was wondering if I could get some input on a little avian issue I'm having.
I'm making a little vehicle sim, and doing the standard "ray cast for suspension" thing, however I recently refactored to instead use a ShapeCaster, with some issues.
When I was using the RayCaster approach, the simulation was very steady. The vehicle would happily settle and "sit still" if no input was provided.
After converting to use a ShapeCaster, I'm getting some strange "jitter" when the vehicle is sitting still.
Checking the physics gizmos, I've noticed the hit point for the ShapeCast will sit nicely under the "wheel" for some time, until suddenly the hit starts happening some point further up the shape.
I'm trying this with spheres currently, but the same is present using a cylinder.
It's difficult to describe so I've attached a really rough drawing of what I mean.
It will bounce rapidly between these two states, causing the suspension to act unpredictably and the vehicle will then "jitter" and "walk" around.
Any help would be super appreciated!
cuboid, capsule and sphere
@fathom cedar and @heady oasis had the exact same issue so i'm summoning them for help
that's really strange then, can you send minimal repro code?
oh I got it working in the end, just had faulty code on my part
honestly was thinking of making a proper tutorial on the subject but there are just soo many quirks that just dont make sence at first
hey, do you know how i can model this?
in gameplay thsi should end up in the player draging on the mass-object. smaler objects should just be yeetet towards the target while heavy objects should not budge to the pull of the player cursor instead requiring the palyer to move the player cahracter.
basicaly this rope and spring setup should be a way to model interpolating between these 2 effects
did you already try joints?
im fairly new to using avian
or modeling more complex behaviour than colision
ill google it
Hello there, quick question. I want to build a 2d platformer but using a Camera3d, mainly for light and parallax. Will avian2d work the same or should I expect some issue ?
it doesn't know anything about the camera
only problem might be preserving z position on bodies, but i think it does already
Okay, nice ! Thank you !
Were there any big "aha!" things that might help me in the right direction?
avian documentation is great
but i still cant peace it together
btu its also prety late where i live so probably tomorow ill find a way
it uses internal position + rotation components so i think it should be fine? either way you can just parent everything that needs Z
It is really good
though I still often find myself hopping over to parry's shape docs because the visual/diagram they have is just that helpful
it'd be even nicer if the avian docs included it or a similar visual for collider/sharedshape
AI is really good for learning stuff like that, you just need to figure out how to word your question correctly
oh I was just multiplying the outgoing force by 5 because I thought it was too small - instead of buffing up the spring strength variable
have a git repo but I was wayy to sporadic with the commits so I dont have that moment captured, sorry
other then that I think I still have a bunch of aha's ahead of me
everything just operates awkwardly
trying to read forward velocity for the car but when applying torque that velocity shoots away into negatives
rlly cant use that data for consistent "throttle" using a curve
like it's "working"
but nowhere near a best-practice and intuative tutorial level
I think my drive system works pretty well. The biggest issue I'm having is the spring force (only using a shapecaster though) and the slip force.
I can share my engine code if you'd like?
sure
I shifted the physics to run in PostUpdate (and all my FixedUpdate schedules to Update), but that causes a panic caused by NaN values:
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is NaN. Encountered a panic in system `car_suspension::apply_acceleration`!
Has anybody come across this?
It feels like it shouldn't behave any differently whether I'm using PostFixedUpdate + FixedUpdate or PostUpdate + Update
log the delta time every frame
nonfixed timestep'll make your physics harder to keep solid
id say it can be of good utility but human guids mostly better guide u. as u cant ask about what u dont know exists
is anyone willing to help me implement a small poc of this?
im a bit bafled
all i can come up with seems crazy complicated. rn my idea is to solve in 2 steps. first comput the position of R then use that to compute the forces between P M and T. does that make sense? or is thera a way easier solution?
i wish that were the case, but humans are usually either absent, too busy, misunderstand the question, or just don't know the answer (and occasionally give you a wrong one anyway).
@knotty thicket was here though, so maybe he'll make a video about joints for you soon 😄
i meant for initial exploration. afterwards chat gpt is great
at elast to point u to the docs
i just noticed this would be a cool featur but its totaly not gameplay relevant rn
i get way to sidetracked XD
you might burn out if you don't let yourself sidetrack though (especially if you have ADHD), just keep irrelevant things in plugins/mods so that you can disable them when you drop them half-finished
yee
but overall making cuts of too important tangents is prety important
else i get burned out on a tangent and dont even continue the main path XD
wich is the worst of both worlds XD
and this entire tangent is for interpolating between a dynamic player controler pulling and a kindematic player cursor pulling on a dynamic mass
while in my game i rn dont even have a plan for large masses. and even if i could just make it 2 seperate actions that arent interpolated (E connect to mass and bull with body. LMB+ drag move mass to cursor)
everyone knows ai exists. telling people to use it like you do is like telling people they should use google. if you don't know the answer, its ok, you don't have to constantly suggest people use an automatic word generator instead when they don't have the expertise to validate the information.
i'm suggesting it because many people (including me) had bad experiences with older models and proceeded to ignore it when it could've solved many of my problems and nobody pointed me to it, so you don't have to be so rude about it
I don't think what I said is any ruder than pinging me to make a video because someone didn't like your ai suggestion
i dont think there was any ill intent
i also think both sides of the ai argument are valid but its starting to become something religeous in the extrems (vibe codesr vs people that ignore ai exists)
think about it like this. if someone was constantly responding "Google is your friend" to questions, that is not a great way to interact with people asking for help.
as we all use google extensively this is rude
ur right
but io know a lot of people that havent learned to use chat gpt properly yet and maybe still sometime google in cases where chat gpt is more efective
don't compare something that used to be reliable and only recently turned to shit, to something that used to be shit and only recently turned reliable 😂
so i see it more of a friendly hint that there is a good tool to learn that might help in this cases
- in this case @sleek thicket also pointed me straigt to the docs wich is more than a LMGTFU
i think this is no topic we must fight about lots XD
I believe you've missed the point here, so will take my leave, since this isn't even the right channel to be hosting this discussion
@knotty thicket would you make a video about all things joints though? that could be very eductaional and looks quite intresting too so it makes great content?
I can put it on my list. I have a few other things to get through first though
i kinda expected there to be a list
but thats cool
I think it's wrong to assume LLMs are going to be helpful learning how Avian works, since any training data it has on it is very sparse and likely outdated compared to more general topics. So it will just make stuff up to fill in the gaps. Asking questions in the channel where the literal author of the library can see them makes sense
partialy. newer models are prety good at reading the docs though. so that is less of an issue for situations where u know what concepts need to be applied but dont know how. if u dont knwo the concept it can be a bit more beneficial readin the docs and talking to knowledgeable people first. overall i think its a tool worth learning.
but i think thats enough yapping about ai. we prob should make a chanel / thread for this if we want to discus this more
i think it's wrong to assume LLMs are not going to be helpful learning how anything works 😅 training data from other engines gets translated, so it's not as sparse as you expect, and i'll take a chance of hallucination over complete silence any day. and look, nobody else even replied to the original question 😔
friends, #machine-learning is that way 😉
I'm encountering some strange behaviour with ShapeCasters for my little vehicle sim, which is causing some bizarre behaviour.
For context, I initally built this sim using RayCasters for the suspension, which is pretty standard (as far as I understand), but wanted to move over to using ShapeCasters as this allows for a wheel to react to uneven surfaces (where a RayCaster has to pass over the "step" entirely before reacting to it).
I've tried with several different Collider shapes as well but get similar results regardless.
It appears as though the contact point for the ShapeCaster changes every tick, resulting in inconsistent distance values, which then gives unpredictable spring forces.
Has anyone used ShapeCasters in anger and had a similar experience?
To test, I built a stripped down version containing a single mass with a similarly configured ShapeCaster setup, however the behaviour here is very predictable, so it seems odd to me that in the main sim things are so... wobbly.
For a little additional info, the ground is a Plane3d with a trimesh_from_mesh collider.
I noticed the severe jitter as the hit point crosses the triangle boundary and thought it might be something to do with that, but then the test setup uses the same ground, just smaller.
Look for "ghost collisions" in this channel for potential answers. Also, what Avian version are you on?
Large triangles or hull faces are known to have some accuracy problems in Parry (the collision detection lib currently used by both Avian and Rapier). So using more but smaller triangles could help a bit
the accuracy and robustness of my WIP collision detection library Peck seems to be a lot better, so hopefully it'll improve things once it's ready for real-world usage
Is it possible to emulate something like ColliderOf{body: None}? I have two collider children on my parent, but one only serves as a proximity sensor (and has a Sensor component). For this reason I'd like to exclude it from RigidBodyColliders so that ahoy doesn't see it as a collider. Is this possible?
I was hoping something like this would work:
player_commands.with_child((
Transform::from_xyz(0.0, 0.0, 0.4),
Collider::cuboid(0.8, 1.2, 1.0),
CollisionEventsEnabled,
PlayerInteractionSensor { offset: -0.5 },
Sensor,
ColliderOf {
body: Entity::PLACEHOLDER,
},
))
but sadly it doesn't
shouldn't Sensor work already?
could use a custom relationship to sync transforms without ChildOf
Not easily, you'd probably have to manually move it with the "parent" without having it as an actual child. The actual problem is a question for @visual sparrow though, I think ahoy doesn't officially support more than one collider on a CharacterController right now, and most likely also doesn't consider sensors properly
yeah everything expects exactly a single collider, though it is allowed to be a child
you're also right, I should change it to ignore sensors for that
at least allowing exactly one read collider and an arbitrary amount of sensors should be easy
is this about ahoy though?
I don't see any indication of that 
so that ahoy doesn't see it as a collider
I can fix this in like an hour
watch out for the release 
As another workaround, you can also use spatial queries like SpatialQuery::shape_intersections instead of a sensor for figuring out which entities are in a given area, depending on your needs
ofc a sensor might be more convenient since it'd automatically follow the character and can also trigger collision events
Why static bodies cam collide with other static bodies?
My game crashes if yhey collide (if they placed very near more like to z fighting)
But if i set collision layers directly for collision only with player
Then all works
does avian plan to add support for cloth/spring physics?
or can i already do that with joints?
Amazing, thanks. Btw I'm also the person who made the issue about gravity direction. I'm still interested in working on it but life happened and I will probably be busy for a week but afterwards I hope to take a look
You can kinda do it with joints, but dedicated cloth and/or soft bodies would likely be more efficient and robust
It's not planned for the near future, but once I'm happy with where were at in terms of the core rigid body dynamics engine (collisions, joints, APIs, performance), I'd love to explore cloth and soft bodies and maybe fluid sim
Note that there is already bevy_silk for CPU cloth, though they seem to be at Bevy 0.17 still
yes; that was actually what prompted me to ask if there would be a native support in avian 😅
i could probably just fork bevy_silk and port to 0.18 and hope there aren't too many breaking changes that i don't know how to fix
there's a PR
https://github.com/ManevilleF/bevy_silk/pull/29
unfortunately the author seems...inactive for the time being
yeahh
thread 'main' (105300) panicked at /home/noviui/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/avian3d-0.5.0/src/dynamics/solver/constraint_graph.rs:173:9:
assertion failed: !is_static1 || !is_static2
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `<Enable the debug feature to see the name>`!
Encountered a panic in system `<Enable the debug feature to see the name>`!
Encountered a panic in system `<Enable the debug feature to see the name>`!
Encountered a panic in system `<Enable the debug feature to see the name>`!
Encountered a panic in system `<Enable the debug feature to see the name>`!
are you changing what type of body they are at a weird time
Maybe
I can fast add and remove static body and collider
Any thoughts on compiling avian for the GPU via https://renderling.xyz/articles/introducing-wgsl-rs.html ?
last time this was discussed, the general mood was that this is not terribly useful for the things people use Bevy today, like gaming
since you need all that physics stuff on the CPU in the end, and GPU readback slow enough that it would in the end probably end up slower than our CPU implementation
And for something like cutscenes you can pre-bake the physics as animations anyways
Thanks for sharing that info, appreciated 🙂
GPU physics can be great iff you need to optimize for maximal throughput, don't have game code tied too tightly to physics, and are not GPU bound on rendering. In general, game code needs to be quite close to physics code though (ex: read back simulation data, use collision hooks, etc.), and with Bevy having a GPU-driven tenderer the GPU may not even have much bandwidth available for large and detailed scenes
Bepu's article on GPU physics is pretty good
https://www.bepuentertainment.com/blog/2019/1/16/-but-gpus-arent-always-the-right-choice
In the last post , the fictional Toilet Toilers Interactive found themselves in a bit of a pickle with their GPU physics-and-everything-else pipeline. They might be regretting some of their technical choices, but it’s worth looking back at some of the things they might have considered during develop
That being said, Rapier is working on some cool stuff for GPU physics, it definitely has its uses too
I have tried to use avian "v0.6.0-rc.1" but I have compilation error:
error[E0277]: cannot subtract glam::Vec3A from bevy_math::Vec3A
--> /home/pc/.cargo/git/checkouts/avian-4150e49b684ad442/8012ac0/crates/avian3d/../../src/collider_tree/obvhs_ext.rs:481:34
|
481 | let point_min = self.min - point;
| ^ no implementation for bevy_math::Vec3A - glam::Vec3A
bevy 0.18.1
Any idea what is going on?
if you have just switched try a cargo clean, cargo update and build again
That worked, Thanks!
v0.6.0-rc.1 solved for me a problem where avian was slow when on scene was 20k static objects 🙂
Out of curiousity is there any way to “simulate” an entity manually for a few ticks for example a projectiles flight path projection with avian?
I'm trying to get a character controller with rudimentary ground detection to work on 0.6.0-rc.1; here's what the scene looks like right now:
(the ball is the ground detector sensor, the capsule is the player, and the trapezoid is a static ground rigid body)
For some reason, the ground detector is currently reporting no collisions (CollidingEntities is an empty set, and Collisions::collisions_with(detector) is an empty iterator)
Is there any way I could debug that?
(besides the debug render I'm actively using, which seems to show the sensor overlapping the ground platform)
what are its collision layers?
I didn't set collision layers for anything
The other detail is that it sometimes detects the platform
(also, the sensor is a child of the entity that has the capsule rigid body)
Including, when I start up the scene and let the capsule fall for the first time, it doesn't detect the ground, but when I move left or right, it starts detecting the ground plane again
And just about any time it stops detecting the ground, I can get it to detect again by moving left or right and waiting a bit
what's the ground detector? a Sensor collider?
you could check all the collisions on the graph and print the relevant entities' ids
The ground detector is a Sensor, yeah
The complete list of collisions when the sensor sees nothing is empty, and the list when the sensor sees something appears to only contain that one collision
Is avian rerecast still recommended to be used with Avian?
@vestal minnow
Hello! Why does ShapeHitData's distance occasionally (quite often actually, like 10% of the time) shows wrong (much smaller) values, while the difference between point1 and point2 shows correct results?
Also, the docs for point2 (and for normal2 iirc) say they are in world space, but they are in fact in local space. I have to add a position to it to get actually world space coordinates.
And one more question, why does the distance in Avian's KCC gets truncated on walkable slopes, while even in the aforementioned algorithm (video about KCC for Unity) it preserves the distance?
Thanks!
i havent bevy'd in a while, but wolud avian be suitable for just handling collision while my movement code is basically custom?
yep, with a dynamic RB
Why not kinematic?
kinematic is for handling collision yourself too
what's the difference again? i'm a bit rusty
haha rusty

e.g. when you add velocity to move your character into a wall, with dynamic RB you'd be stopped by (or bounce off) it, with kinematic you'd just pass through
ah i probably want dynamic then
i'm already using dynamic
maybe it's tnua that's the problem
last time i looked at it, it seemed overcomplicated so i just made my own 🫠
Are you making a character controller? If so, then kinematic is the best choice. Dynamic character controllers are wonky.
Every major game engine uses KCC. Think about it. 🧠
it might be the best choice when you have an expert working on it, but suggesting beginners to make their own KCC is just sadistic 😅
Well, I am suggesting the best practice, and I also don't know his developer level.
cool how do i handle collision?
im not super inexperienced and id like a challenge, but what is kcc lol
Btw, Avian is getting its own KCC. Or already have got.
kinematic character controller?
Yeah.
yeah that's what i want
how do i prevent clipping?
and just handle collision at all
I am not really sure dynamic CC would be any easier, since you have to constantly fight various forces.
im using tnua and it feels really bad
it also didnt feel good when i wrote the dynamic controller
i reckon ill write the kcc
idk if the game will ever be finished lol so may as well have some fun with it
Same when I tried one.
floating collider is easier, otherwise yeah
floating has gross bouncing for me
and it clips through the floor with/without floating
with dynamic
clipping sounds weird, bouncing can be configured
the floating still felt really weird
i didnt feel like i could make it feel snappy at all
which i want for a metroidvania
btw doubling physics ticks fixed the clipping but hurt performance
i have no idea how you configured it, but that doesn't sound right
alright ill look into it again
Wait, are you making it in 2D or 3D?
does it work well with pixel art?
2d
Oh, well... I thought you are talking about 3D. 😅
ah
oh i remember now; the reason i decided to move from it is that it was not working very well after i transitioned to pixel art
But generally you just cast the shape of your character controller, and if it hits smth, you bend your vector along the surface. And then there go different cases, like if the slope is too steep, or if it's stairs...
is that with a kcc?
Yeah.
cool
It's generally just tons of geometry and algebra.
sounds fun
how do you deal with wall collisions? when you say cast i imagine a ray pointing straight down
I think it should be much easier in 2D than in 3D. And there are probably tons of algorithm on the internet, since there are tons of 2D platformers out there.
You should cast your shape, e.g. capsule or whatever you use for your character.
do you check with like corner coordinates?
you have just as much control as with KCC, you just lose the advantages of dynamic RB as you tighten control over it, until there's basically no difference between the two
In 3D we need clearance between character and the ground, because otherwise it will instantly hit the ground. I think it might be the case in 2D as well.
im remembering now i think. polygons get weird but circles especially and also rectangles should be easy
im imagining more like hollow kinght
which i dont think has slopes
but isn't exactly blocky
the physical design is all straight lines iirc, though the decoration ofc isnt
im using ldtk, so it'll have to be blocky i think. unless i used something else
an annoying thing with dynamic controllers is that the character would lose all horizontal speed on a vertical collision, and vice versa
from friction? you can just disable it
ah cool
as you can tell i didnt get far before giving up lol
a bunch of stuff broke when i chnaged to pixel art, and i lost motivation. also school started up again
hidden defaults are a reasonable issue though 🤔
ill see if i can get stuff working, ill ask people here to help if not, and otherwise ill rewrite as a kcc. do you recommend tnua or writing my own dynamic one?
A detailed look at how we built our physics-based character controller in Unity for our game Very Very Valet - available for Nintendo Switch, PS5, and Steam
BUY NOW!! https://toyful.games/vvv-buy
~ More from Toyful Games ~
- Animation Deep Dive mentioned in the video - https://toyful.games/blog/character-animations
- Custom Car Physics in Unity...
i don't know enough about tnua, but i recommend learning how it works if you decide to use it
iirc i dont think you could customise the pivot speed
ill have to check again though
writing a kcc sounds like a fun project as well...
Either way, if you hit smth, you get the surface normal from hit data, and then compare the angle to Y axis. If you have slopes, then you also should come up with some max_slope_angle and compare to it, e.g. if it's more than 50°, then it works as a wall. 90° means a vertical wall, 0° means ground. You get user's input, cast your shape in that direction, deal with what you hit, if anything. Use a loop within a function, so if you hit smth and want to bend your vector, you make a new shape cast in the next iteration, all during the same frame. But limit the number of iterations, or you can get into a endless loop.
you can just use dot to check if it's wall/floor/ceiling
I've heard this advice to write systems, not projects. So instead of tons of abandoned projects you would have tons of working systems. 😆
What is the other vector?
oh yeah true
collision normal and up/down
i've also seen people hyperfixated on making everything modular to the point it slows them down to a crawl
Is there a way to implement CollisionEvents between Scenes (as in Gltf's) nowadays? I could find few messages about it (e.g. the one this message responds to) but @vestal minnow suggestion back then still doesn't work and it seems that it still doesn't work out of the box.
Hmm, this should work today (and in the past).
(1) glTF loads asynchronously, so when you spawn a SceneRoot(your_gltf_handle), you need to watch for On<SceneInstanceReady> to know when the model is fully loaded and spawned.
(2) In the event handler for SceneInstanceReady, traverse the hierarchy of the scene (use e.g. child_q: Query<&Children> and child_q.iter_descendants(...) starting at SceneInstanceReady::entity) and insert any Collider or ColliderConstructor components to the appropriate entities -- usually those with Mesh -- or if your model is simple and has homogenous colliders, add ColliderConstructorHierarchy component to that scene root.
(3) You need to have CollisionEventsEnabled on any entity with a Collider. Either add these in step (2) if adding Collider/ColliderConstructor. If you use the Hierarchy version, you'll need to add a system that watches for a query like Query<Entity, Added<Collider>>, which should fire some time after (2) and then use that entity to add this component.
If you're using Blender to make the glTFs, the easier way to get all this set up is to use Bevy Skein and just directly add these components at the appropriate locations (e.g. the Mesh portions of your model).
I currently have
commands.spawn((
SceneRoot(handle),
RigidBody::Static,
CollisionEventsEnabled,
ColliderConstructorHierarchy::new(ColliderConstructor::TrimeshFromMesh)
));
So the CollisionEventsEnabled should be added to the descendant that has Collider? Makes total sense but seems counter intuitive that it isn't either propagated or added automatically.
Yes, CollisionEventsEnabled needs to be next to (each) Collider you care to check. The reason the component exists is, event propagation is expensive, so it's opt-in by default. See https://joonaa.dev/blog/08/avian-0-3#opt-in-contact-reporting
Oh! And I see there's a mechanism in that post for automatically adding these components: app.register_required_components::<Collider, CollisionEventsEnabled>(); -- but that's application-wide, so caveat emptor.
Okay that explains! I however still can't get it working o_O I can't however produce collisions even with Collisions SystemParam so there must be something other that I'm doing very very wrong. Have to continue on this later, now's the time to close laptop for today 🙂
EDIT: For context; I’m building a strategy game and until now I’ve determined the validity of new buildings placements by representing the map as a grid (for pathfinding and placements) and checking whether n-adjacent cells are not occupied. I decided to make buildings rotatable and figured I could simplify the validity determination with colliders.
It's possible then that the colliders are not the right shape or not actually intersecting. Have you tried configuring the physics gizmos to get an on-screen visualization of their shape and activity?
Yeah PhysicsDebugPlugin shows them just as how you’d expect. I’ll post some screenshots when I’m back at it
Okay even as I'm total beginner in this physics stuff.... I still feel embarassed... The problem was that I attached RigidBody::Static to all scenes/meshes. I ended up reading Avian source until I realised that "oh, two static rigid bodies can't collide" 😄
Still I can't get Observers working with the Collision events as I'm observing the root entity, but the collider is nested deep within the scene. Is there any workaround for propagating the events?
This is what I came up
fn prepare_colliding_scene(
mut commands: Commands,
q: Query<Entity, (Added<Collider>, With<GltfMeshName>)>,
child_of_q: Query<&ChildOf>,
) {
for entity in &q {
let mut current = entity;
while let Ok(ChildOf(parent)) = child_of_q.get(current) {
current = *parent;
}
commands
.entity(entity)
.insert(CollisionEventsEnabled)
.observe(move |trigger: On<CollisionStart>, mut commands: Commands| {
commands.trigger(CollisionStart {
collider1: current,
..*trigger
});
})
.observe(move |trigger: On<CollisionEnd>, mut commands: Commands| {
commands.trigger(CollisionEnd {
collider1: current,
..*trigger
});
});
}
}
Not easily right now, other than observing the entities deeper in the hierarchy and potentially manually triggering events (like you did now 😄)
We could consider propagating collision events from child colliders to the parent rigid body by default
Well this seems to get the job done! Is there any particular reason for it not to be supported out of the box or did I just find such a niche use case? 😄
Mostly it just hasn't been implemented, I think it's probably a good idea to propagate to the root body in principle
More generally there are some other cases too where usability could be improved for hierarchies
Oftentimes you only want to configure the body and have it affect all child colliders too, unless overridden for those entities
Some components already work like that, some don't, so it's maybe a bit inconsistent
Not easily. We could probably expose some more helpers for this, though not really in a collision-aware way, since collisions go both ways and would therefore require simulating the entities hit along the way as well. So you often can't fully simulate just a single entity without effectively simulating "everything", as they could all technically interact with each other in some way
I would probably just manually estimate the trajectory by manually stepping through the movement, taking into account initial velocity and gravity, and if you need to consider collisions, using shape casts or something to detect hits, and reflecting velocity accordingly
We should probably make this a bit easier with some helpers and maybe have an example to demonstrate this sort of thing
Thanks for the response and assistance @vestal minnow and @wet niche !
Np :)
Why does ShapeHitData's distance occasionally (quite often actually, like 10% of the time) shows wrong (much smaller) values, while the difference between point1 and point2 shows correct results?
Not sure, that data comes from Parry (the underlying collision detection lib) so I don't have too much control over it. I haven't personally noticed this or issues caused by it, but it's possible something is off there
Also, the docs for point2 (and for normal2 iirc) say they are in world space, but they are in fact in local space. I have to add a position to it to get actually world space coordinates.
What version is this on? In 0.6.0-rc they seem to all be in world space based on quickly rendering some shape cast results with gizmos. I think we might've fixed an issue here recently
why does the distance in Avian's KCC gets truncated on walkable slopes, while even in the aforementioned algorithm (video about KCC for Unity) it preserves the distance?
This depends on the behavior you want. In Godot for example, this is controlled by floor_constant_speed, which is false by default (i.e. going up slopes is slower, going down slopes is faster). Avian has no official KCC yet, it just has kinematic_character_2d and kinematic_character_3d examples (which were updated recently) to demonstrate how you could use the MoveAndSlide functionality to implement some basic KCC movement and collisions. A more complete KCC may want this sort of behavior to be configurable.
It will get more KCC functionality in future releases, right now there's just MoveAndSlide and some related utilities
yw! I wonder, though, if a review of the code shows a few misunderstandings instead.
(1) ~~Double-check that collider1 is the same entity -- I don't think the order of collider1 or collider2 is reliable in relation to the observe'd entity. ~~ (clarified below)
(2) Are you sure entity != current? before registering the observers?
(3) Do you know about MessageReader<CollisionStart/End>. They see the "global" set of events. I usually go this route for large-scale filtering of events.
I Imagine what you want is a cascading event system for collisions, perhaps where you collect all this data in a big observer at the root?
See if MessageReader better fits your needs? It'll avoid a lot of overhead.
That's for @visual sparrow, but rerecast is the core crate for generating nav meshes, and it can be used without Bevy or Avian. bevy_rerecast is the Bevy integation. avian_rerecast just adds a backend to automatically generate navmeshes for static rigid bodies in Avian. So yeah if you want navmeshes for Avian, you should use bevy_rerecast together with avian_rerecast
and if you want to use rerecast with something other than Avian (ex: Rapier), you'll just have to write your own backend for it
(1) Double-check that collider1 is the same entity -- I don't think the order of collider1 or collider2 is reliable in relation to the observe'd entity.
In the context of observers,collider1andcollider2do actually have a specified order, this is briefly mentioned in a code example in the docs (link)
fn on_player_stepped_on_plate(event: On<CollisionStart>, player_query: Query<&Player>) {
// `colider1` and `body1` refer to the event target and its body.
// `collider2` and `body2` refer to the other collider and its body.
let pressure_plate = event.collider1;
let other_entity = event.collider2;
if player_query.contains(other_entity) {
println!("Player {other_entity} stepped on pressure plate {pressure_plate}");
}
}
However for messages there is no event target, so there the order is unspecified
Absolutely right, thanks for the correction. Given that, a downside to MessageReader is that unorderedness. (I tend to (over-)use that pattern so am used to its need to validate order.)
I’d want to emphasize that the snippet I posted will definitely need a more thorough thought! I already encountered a stack overflow without the GltfMeshName QueryFilter and colliding something against a regular Mesh3d 😂 That QueryFilter could use some thought I think. But about the points in your message;
2) you’re right that should be double checked. I also don’t (yet) have enough knowledge of these concepts to determine what entity the body1 field should point to. With those last nights brief tests it seemed to always be the same entity as collider1 but I suspect there are cases where it’s not that simple.
3) yes I’m aware of global Messages! Imo observers just make a lot more sense in this feature that I’m currently developing. You could of course achieve the same behavior with global Messages but determining the root ancestor would still be nescessary at one point.
What version is this on?
Yeah, I haven't updated it for a month or more. It's not even a “number” version, but it was always like this. (Although I've started to use Rust and Bevy not too long ago in general.)
I haven't personally noticed this or issues caused by it, but it's possible something is off there
When my custom character controller floats over a perfectly flat surface and casts its shape every frame, the difference between points is always consistent, but thedistancesometimes shows like a 5 times smaller numbers.
I think I found a possible bug related to the character controller
I don't feel like I have enough info to file a full issue about it
But it's related to what I saw earlier
The sensor ball and the platform are definitely colliding, but no collision is detected
I went down to broad phase to figure out if the problem was there, and sure enough, the ball never enters MovedProxies until after I move left or right
I'm wondering if this has something to do with it being the child of a CustomPositionIntegration entity?
That feels odd though
If someone more knowledgeable has more tips for tracking this down, I'd very much appreciate it; I don't know what I'm doing in physics engines
Hm, do you happen to have a minimal repro you could share? That seems strange
I really don't have anything remotely minimal; I have a 200-line blurb I can throw in a gist
That would be fine
Thanks!
Let me know if there's anything else I can do to help on my end (partially because I want to be less useless at diagnosing these things when they do happen)
unfortunately I have to go afk for ~40 min but I'll try to figure out what's happening after
Sounds good 😄
Any update? (I'm available for a little while)
I found a fix but need to clean things up a bit more
Basically the broad phase creates contact pairs for colliders whose enlarged AABBs overlap, and the narrow phase removes contact pairs when the AABBs stop overlapping, but the narrow phase was actually using the tight-fitting AABB instead of the enlarged AABB, so it would sometimes create and then immediately remove the contact pair
There's also some other inconsistencies in the tolerances used for AABB updates
should be able to get things fixed and PRd tonight
@surreal junco This should fix it!
https://github.com/avianphysics/avian/pull/952
Objective
Right now, the broad phase queries trees using the tight-fitting AABB. The narrow phase also removes contact pairs when ColliderAabbs no longer overlap. However, the actual trees use enla...
I'll merge it tomorrow
I was also playing around with making ColliderAabb actually tight-fitting (right now it's expanded based on velocity to account for speculative contacts), but that'll require a larger rework of our CCD logic, so I left it for now
I'll come back to that eventually, I'd really like to try Box2D's approach to CCD, it should be super fast but still quite reliable
Merged @surreal junco
yipee
easier to debug with #[cfg()] let v = a(); #[cfg()] let v = b(); v
but it looks like you have both features enabled and avian's resolving to 32
ill recheck what features I use
Would you consider adding modifier functions to CollisionLayers now that it's immutable?
(Sending here the extensions I made so far so others may use them)
Getting a panic:
no element at index 33 in StableVec::index_mut
Encountered a panic in system `avian2d::collider_tree::update::update_moved_collider_aabbs<avian2d::collision::collider::parry::Collider>`!
Encountered a panic in system `avian2d::schedule::run_physics_schedule`!
Encountered a panic in system `bevy_app::main_schedule::FixedMain::run_fixed_main`!
Encountered a panic in system `bevy_time::fixed::run_fixed_main_schedule`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
Aren't you supposed to overwrite immutable components by just calling insert on a new copy of them?
Exactly
So now instead of layers.memebership.add_layer you need to clone it, add layer to the clone, insert that clone
It's more convenient to write with these
how does big space work with avian?
PhysicsPicking is going haywire
The graphics are from the PhysicsDebugPlugin, as per usual
Look at the entity in the picking debug; it keeps alternating between entities 104 and 105 when the player entity jumps and moves around, even when the mouse is nowhere near the entities
If anyone has any ideas on how to debug this further, I'm all ears; I know I have a bit of an odd system for drawing the scene, so that could feasibly be part of the problem, but I don't know
I'm having some issues where the fixedupdate seems to be ireggular (at least that's what i think is happening)
The car in the video is either accelerating at a fixed rate, or moving at a fixed speed. Yet i get these jumps.
It's much less noticable in release mode, but you can still see it if you look for it.
All gizmos are drawn in FixedUpdate along with my physics calculations and forces.
I'm on the newest 0.6 version
Is there a way to make a collider that's the boolean intersection of some other colliders? I'm trying to compile Source maps, and I think that some of the collision is represented as the intersection of a bunch of half-spaces (i.e. infinite-extent planes). I'd like to try that out, I tried to figure out a meshing algorithm but haven't been able to make it work.
Ok never mind, my meshing algorithm was actually fine
I just wasn't using it in the right places
Is there a way to disable the physics debug gizmos on specific cameras?
or opt in only
I guess this is more of a bevy gizmos issue
gizmos have visibility layers
What's the most idiomatic/efficient way to modify a collider that's actively being used on a character?
Specifically, I have a character whose collider stretches and shrinks to fit the model during its animations. I could use the Transform on it to translate/scale/rotate it, which was my first instinct, or I could directly modify the collider itself; what do you think would be the best option?
(also still wondering about how to effectively debug PhysicsPicking)
I'm no Avian expert so take this with a grain of salt and some extra research:
My understanding is that any modification to a collider will cause a recalculation of things like the AABB; different physics engines cache more or less information about colliders. Avian's BVH implementation is brand spanking new so I don't know if it's rebuilt every iteration or if it is retained, I assume it's retained, so I imagine any collider change is also a BVH recalculation.
Most physics engines absolutely freak out if your scale is anything but identity on the transform, but my understanding is Avian handles scaled colliders and bodies correctly. I recall using scale to work with colliders in Skein before and it was fine. Maybe check if your masses are what you expect them to be, idk if Avian calculates mass from densities in world space or local space.
To give the lame answer, I don't think it matters unless character collider changes are a performance bottleneck for you. If that's the case, my guess would actually be that maintaining separate colliders that you enable/disable is most efficient. But that is 100% a guess.
An even lamer answer: Games like Silksong never change the character colliders for any characters. Hornet is just an ultra skinny stick whose collider doesn't even remotely match up with her sprites in most animation states. So you might be being too pedantic, unless your game is one where the characters grow and shrink a lot and that is a core mechanic.
I personally would avoid scaling just because I am allergic to altering scales on my transforms unless I have an extremely good reason to, from prior experiences in other engines.
As for physics picking- Does your character have sensors attached? Raycasts hit sensors. I had a weird issue where my units wouldn't be selected if I clicked on them dead center and it's because they had sensors in the middle for detecting other bodies on a different layer.
You may need to set the layer mask for the raycast to just the layer your character is on.
That makes perfect sense honestly; I think I can get away with not changing the hitbox size (this is specifically for the terrain hitbox of a platform fighter character; I can almost certainly keep it a constant shape
The character has one sensor attached, and it's that tiny ball at the bottom. That's it though; the only other colliders in the scene are the rigid bodies of the capsule and the ground trapezoid
Hmm- Is your collider a child of your rigidbody?
Would explain why the entity ids are neighbors
I can also guarantee that the characters that are being selected include the capsule and... something else? not sure what... but they're being selected no matter where my cursor is
The ground detector is a child of the rigid body, yeah
I wonder if the picker is ping ponging between both for some reason
are you using a query to filter the result or just printing the raw entity ids
Considering I was having issues with the BVH right before release and they were also patched just before release, I wonder if that has something to do with it
I'm using Bevy's built-in PickingDebugPlugin IIRC
Avian's BVH is new as of 0.6 tho, so unless you were using the crate from gituub you weren't using it
There was a sweep and mark broad phase but that's distinct from BVH
I was using the master branch
Oh okay yeah nvm
(main? i forget which Avian uses)
I was using it to have access to the move-and-slide before release
I found a bug with colliders being excluded; it was an incompatibility between broad phase and narrow phase which presumably cropped up during the switch to BVH
might be a dumb question but you're using Avian's PhysicsPickingPlugin and not Bevy's built-in mesh picking backend?
If so you can try adding Pickable::IGNORE to your child collider or the rigidbody
See if that changes the behavior
I suspect PickingDebugPlugin is logging all picking events, both for the collider and rigidbody
I'm using the PhysicsPickingPlugin, yeah (I had no meshes at the time of that video)
I may add Pickable::IGNORE to the child collider, but I'm still concerned that the plugin doesn't even seem to be remotely indicating what's actually under my cursor
Yeah that I'm not sure on :/
If it was point query based my guess would be not checking for the inside bool but rays shouldn't have that issue.
Another random idea would be some issue with the camera setup? But I've gotta imagine bevy_picking is designed to smooth over stuff like camera transforms
yeah
One slightly odd thing is that it's 2D physics in a 3D world with a 3D camera
... But the gizmos are rendering fine
I'd have to go and read the source code but I can totally see this messing with picking logic
yeah
That's kinda what I figured could be the issue
I'll take a closer look soonish; I'm currently trying to get bounding boxes (or, as the case may be, diamonds) set up so I start using the correct shapes in my tests
I should also get bevy_inspector_egui set up; the VS Code inspector has been flaky
instead of using picking you could use a point query or raycast by doing viewport_to_world
That feels like it'd be the same problem though
Like, if viewport_to_world works, that's probably what PhysicsPicking uses under the hood, or something like it
yeah but you could lead with drawing a gizmo at the position of viewport_to_world
would at least give you an idea if the 2d physics/3d camera are clashing
True
... wait, but viewport_to_world is probably what Bevy normally uses
hmmmmmmm
Or maybe not
Maybe I'm thinking of the wrong function
No, yeah, it's Bevy's function; there's no way that's wrong
I'm a few minutes away from being able to test with the new bounding boxes, one sec
also, i'm dumb, i do have to change the hitbox size because the characters can have noticeably different shapes in different animations (particular, a certain penguin might be belly-sliding, which definitely can't reuse the standing hitbox)
Ahh true. Unless you have tens of thousands of them I don't think it will matter at all. I also think you can't really avoid it.
AABB/BVH rebuilds aren't that expensive. And, again, not an Avian SME so it's possible it's zero cost in this particular physics engine.
Finally got around to reading the code, and yes, this is the problem.
The picking code truncates the picking ray's origin, which works perfectly fine with an orthographic camera and breaks with a perspective camera. Essentially, screen space is zoomed in because a perspective divide is not attempted, and the ray direction is never checked.
A potential solution would be to follow the ray to z=0, where the 2D objects are effectively being rendered, and then do the point check. I can imagine this could matter for other games, such as if a platformer has a 2D layer with the player and enemies but has 3D-placed scenery
I don't think performance is an issue in this case, since this bit of the picking code is only run once for every cursor on the screen (usually one). I'll make a PR
Thank you for coming along with me on this journey! 
Journey isn't over
So, as far as I can tell, the right point in world space is being found. That's completely okay now
... And yet, the actual picking is still completely broken
I made an example to test it, and even though I can prove that the ray is being converted to 2D world space correctly, the objects are still not getting highlighted how I'd expect
I shouldn't say completely broken; when I'm hovering over a ball, one of the nearby balls will highlight, it just might not be the one I'm actually hovering over
