#Avian Physics
1 messages · Page 31 of 1
but why
why tf i want a dude stand above other?
because it might be fun? D;
well yes but its a battlegrounds so
i have a lot of stuff i want put on it that i did on roblox
iam hyped as f
like the elemental interactions system i did, so fun
well i think i need make a custom gravity system now xd
otherwise 1 click forward with linear velocity this happens xd
infinite slide xd xd
BTW @vestal minnow review https://github.com/Jondolf/avian/pull/665 pls 🥺
@sleek thicket all did with my own gravity
when there is no floor it will keep moving the character down, checking ofc for a floor on the next translation before set it, if have it will adjust the new y to stand
I ran into a interesting issue, I am trying to make a gltf file collidable. Here is my code logic. SOLVED - Forgot to apply apply rotation and scale
pub struct ClientWorldPlugin;
impl Plugin for ClientWorldPlugin {
fn build(&self, app: &mut App) {
app.add_plugins(ClientSunPlugin);
// app.add_plugins(SceneRenderPlugin);
app.add_observer(map_generate);
}
}
fn map_generate(
trigger: Trigger<OnAdd, MapInformer>,
query: Query<&MapInformer>,
map_collection: Res<MapCollection>,
gltfs: Res<Assets<Gltf>>,
mut commands: Commands,
) {
let base = trigger.entity();
let MapInformer(file_path) = query.get(trigger.entity()).unwrap();
let gltf = map_collection.map.get(file_path.as_str()).unwrap();
let gltf = gltfs.get(gltf).unwrap();
let scene = gltf.scenes[0].clone_weak();
commands
.entity(base)
.insert(SceneRoot(scene))
.observe(make_map_collidable);
}
/// This will replicate only the meshes as from all the entities that we have the only ones who are interesting for client to have are those ones
fn make_map_collidable(
trigger: Trigger<SceneInstanceReady>,
children_query: Query<&Children>,
mesh_3d: Query<&Mesh3d>,
meshes: Res<Assets<Mesh>>,
mut commands: Commands,
) {
let map = trigger.entity();
for child in children_query.iter_descendants(map) {
if let Ok(Mesh3d(handle)) = mesh_3d.get(child) {
let mesh = meshes.get(handle).unwrap();
// Only make meshes collidable
if let Some(collider) = Collider::trimesh_from_mesh(mesh) {
commands.entity(child).insert(collider);
info!("Collider added to map entity {}", child);
} else {
warn!("Info this entity didnt have a mesh {}", child);
}
}
}
}```
The result:
As you can see the generate collider meshes are off scale, any dieas on what might be the cause?
mhm I also have my own version of this from some time ago, with some wrapper types for the context stuff
https://github.com/Jondolf/avian/compare/main...collision-context
I think the docs are outdated there though so I need to update those
@vestal minnow how do you draw the capsule with the PhysicsDebugPlugin?
i want draw the shapecast
to know where its going
i need debug my query.cast_shape_predicate
but a quick Discord review of this is that
- I don't love the
get_prefix, it doesn't imply anything about being more "contextful" than the normal versions. I just use a_with_contextsuffix in my implementation. - The argument order is a bit weird to me, I think ideally the context versions would be the exact same as the contextless versions, but with an additional argument added for the context (hence the wrappers in my implementation to encapsulate it better)
SimpleCollideris pretty nice. I assume the extra params get compiled out if they're not used so it's the same as the old version with no context stuff at all 🤔 (not that a couple extra entities passed as parameters would be meaningful anyway)
Right now I think I'm doing a weird thing where I use Parry's to_polyline method to create a polyline for the capsule's outline, and then draw a line strip with gizmos. But this is a dumb way, you should probably just do this
gizmos.primitive_3d(&Capsule3d::new(radius, height), isometry, color);
(this did not exist when I originally implemented collider debug rendering)
THANKS Brother
Parentless collider act as immovable static objects correct?
let shape_hit_data = query.cast_shape_predicate(collider, transform_translation + vec3(0.0,height,0.0), rotation, Dir3::new(Vec3::new(0.0, -height * 1.3, 0.0)).unwrap(), &ShapeCastConfig{
max_distance: Default::default(),
target_distance: 0.0,
compute_contact_on_penetration: true,
ignore_origin_penetration: true,
}, &SpatialQueryFilter{
mask: LayerMask::from(GameMask::Default),
excluded_entities: ignore_list,
}, &|entity_found| {
true
});
``` so yes i think i did something wrong here, iam trying make it start the cast on top and go down, is the Dir3 wrong? @vestal minnow idk a lot how your shape cast system works
its not detecing the floor
nvm, change the max_distance works
your max_distance is Default::default() which is zero for an f32
yes
so the shape cast won't really go down at all
since the distance it's allowed to move is zero
@sleek thicket to make it float are you using transform.translation.y or linearvelocity?
iam using transform.translation.y
- Yea I didn't like the
get_either, it was just a minimal rename to get the names back forSimpleCollider. I'll copy the_with_contextwhen I have time - The order is definitely a bit weird, I put context in front because it belongs with the collider, but having the
Entityscattered everywhere is definitely kinda of a mess, the wrapper seems like a reasonable compromise there - I'm pretty sure the
Entitys get optimized out since something without context probably won't use them (thought it could in some rare cases be useful for debugging maybe?)
LV, exactly as VVV video explains
@vestal minnow i realized what was bothering me about joints
they're all just different combinations of constraints for translation and rotation, so it feels like they could've just been components that can combine with each other, using joint component for common data
We can and probably will make constraints a bit more composable, but for perf reasons we probably also want to keep joints that directly handle multiple constraints (ex: a revolute joint with both a point-to-point constraint and angular constraint) rather than splitting the constraint solving across multiple different components and having to fetch and prepare things for each of them individually and potentially doing duplicate work. Blindly combining constraints also isn't good for stability in a lot of cases
You can see how Bepu has a lot of different small constraints
https://github.com/bepu/bepuphysics2/tree/master/BepuPhysics/Constraints
In fact I don't think it even has a spherical joint with limits built in, but you can create it by combining a BallSocket with a SwingLimit (and TwistLimit)
yeah that feels more like ecs
But there are cases like the Hinge constraint where it needs to be a combined position and angle constraint to behave well, even though you could get a similar effect with a BallSocket and AngularHinge
Solving constraints together like this can often give better results in cases where the constraints affect each other
plus you can sometimes reuse computations better
So I think ideally you can compose lots of small constraints together, but there are also combined constraints like this for the common cases
i legit dont have any idea how
cause if set linear velocity up it goes up forever
so iam using translation
then spend more time thinking and debugging, using translation will cause even more bugs later
Is there any ragdoll example? I used to use 6dofjoint in Godot to make a ragdoll. Because I wanted to constrain translation and rotation. In bevy with avian, I tried distanceJoint, but I couldn't figure out how to constrain rotaion. Docs say SphericalJoint is for ragdoll. How can I achieve that?
There's no example for this currently, but SphericalJoint attaches two points together, and you can assign a local swing axis and apply limits to constrain the axes of the bodies to be within some relative angle from this axis
I'll note that Avian's joints are probably one of its weaker aspects at the moment, as they're not very polished and are missing quite a few features (motors, easy stiffness configuration, etc.)
So Rapier has a bit more functionality there. But improvements are planned
Right, for ragdoll, distanceJoint and SphericalJoint are to be combined.
Thanks. I'll check rapier too.
This would be nice semantically, but I think it's important to allow joints to live on their own entities separate from the bodies (this is also needed to allow multiple joints of the same type for a given entity, since duplicate components aren't allowed) and I think with the current relationship system the relationship component has to live on the source entity
so it wouldn't work afaik
(with one-to-many relationships)
If we had many-to-many relationships, we could do JointOf(entity1, entity2)
i guess if it would be multiple of same joints with both entities being same, but i'm not sure how often that happens
i was thinking something like entity.Joint(otherentity, JointConstraints)
It doesn't even need both entities to be the same to be problematic. For example imagine a spiderman character shooting two different webs at once, constraining it to two objects via some joint; that's two joints of the same type on the same entity, which isn't allowed
the joints instead need to live on the web entity or some other external entity (or be child entities or something)
it's not allowed in bevy? from flecs relationship blog it'd be same case as multiple ships being docked to 1 planet
The Bevy equivalent of that would be a DockedTo relationship component on each ship, and a DockedShips component on the planet
this is a one-to-many relationship
But with the joint example each entity can be constrained to multiple entities
which requires many-to-many
A character can be jointed to many objects, and many objects can be jointed to it
if the alternative is making each joint into a separate entity, couldn't users just make child entities for each joint instead?
they can yes, but the effect is still the same that each joint is its own entity
oh damn we passed 30k messages here today 😛
Hey just curious, did you look at this? Was this getting stuck on walls? Curious because I have used your method and it worked well, but I had issues with Lightyear, such as infinite rollbacks. So I'm going to try and do it the "correct" way.
https://github.com/Jondolf/avian/blob/main/crates/avian3d/examples/kinematic_character_3d/main.rs
I'm having a lot of trouble with penetration and instability in avian2d. Does anyone have any advice on how I can tune things better? In this example the oblong objects is being given periodic impulses towards the mouse and can quite easily burrow into the solid wall. The last couple of seconds of the video are an example of the instability. In that section there are no external impulses being applied but the object still bounces around uncontrollably.
I can increase SubstepCount and that helps but doesn't completely resolve the issue.
When I was using a simple circle collider for the active object things were much more stable but I was still getting a lot of penetration. I'd like to find a way to tune things so I can continue using trimesh colliders though, because they're very convenient.
I'm using 1px==1unit scale so my forces are quite large. Is rescaling stuff likely to help? I have the length_unit set so that the oval player object is roughly 1 length_unit long.
So this is a Dynamic rigid body right?
Yeah, the moving object is Dynamic and the terrain is a single Static body.
With a single large trimesh collider. So those aren't individual triangle colliders or anything like that.
can you send the code for that dash? if nothing's wrong with it i want to use it to test 3d collisions
Yeah -- hmm. The 1px == 1unit does stand out to me as something that could possibly be the problem but I really dont know for sure
shouldn't be, it's expected size for 2d
Oh ok, maybe dont listen to me then. I havent really done 2D in bevy
.add_plugins((
DefaultPlugins,
// A 2D game with 100 pixels per meter
PhysicsPlugins::default().with_length_unit(100.0),
^ just needs this thing
It's just setting an ExternalImpulse to be normalized_direction_vector * strength where strength is 1006500.0
Yeah, that's what I do. But 40.0 rather than 100.0
ok 1006500.0 seems excessive
Yeah that's a big number, I wonder if this is a floating point precision issue
Ok. That's what it takes to get the object to hope into the air. I've had to set all my forces to big numbers like that, which is why I was curious about the scaling.
that's one heavy ass egg
i didn't touch external impulses so it might be fine, but it might be an issue with weight/density of collider
I've really only been in the kinematic rigid body world so I actually dont know the answer, is there a Mass component?
Hmm. I haven't done anything with collider density. Maybe I've set the scale weirdly someplace else, like in the camera setup, and have forgotten about that.
Oh... oh, crap. I did set a mass. I'd forgotten about that. And it's pretty high. So maybe that's my issue.
mesh vs mesh collision could also be contributing to it
especially if player isn't convex
What if you use a capsule instead of an egg mesh, would that give the desired gameplay feel though?
i'd use composite collider
oh
2 circles and 2 boxes
or even just 3 circles
Fixing the silly mass I had set gets me 90% of the way there.
It still penetrates a little but it's no where near as bad.
I could go to simpler colliders, and maybe that's my best long term solution. But I kind of want to keep the trimesh just so I can have a simple blender->bevy workflow.
Well the world should definitely try and remain a trimesh, I think. But does the player need to be a mesh is the question
primitive/compound for dynamic is usually the best choice in every engine
dynamic bodies definitely shouldn't use a trimesh if you can avoid it, the shape in the video can probably just use a convex hull or some primitive shape
Zero is no good because avian treats that as infinity. Setting it to a low mass, like 0.01 with my dash strength being 1.0-10.0 gives me roughtly the same results as a mass of 1.0. So I think that so long as it's not 1000.0 it's pretty similar.
Hmm. Ok. That oval shape is a placeholder which I intended to replace with something more complex later but now that I'm thinking about it I probably don't actually need anything that I couldn't do with two or three primitives so I guess that's what I'll do.
ah.
Ok well here's my thoughts:
- use a primitive or convex hull for the player as suggested
- absolute worst case you can predict the trajectory and do some shape casts, particularly for the scenario where you're "drilling" into the ground.
Hmm. That's interesting. Detecting the problem with a shape cast is an interesting fallback but I'll see if I can't avoid that, I'd rather leave it to avian's collision resolution.
ya absolutely
can also add the SweptCcd component for the sweep-based continuous collision detection
A component that enables sweep-based Continuous Collision Detection (CCD) for a RigidBody. This helps prevent missed collisions for small and fast-moving objects.
I do have that on the dynamic body.
I'm actually impressed tri-mesh on tri-mesh collision is working at all
that sounds hard to do math wise
It seems fine like 80-90% of the time.
Switching back to a circle collider and fixing my weird masses seems to have fixed all my problems. Thank y'all.
What is the best practice way to set the mass of a body? Mass is ignored if the body has child colliders. I'm currently setting the ColliderDensity of all the children to zero which feels a bit clumsy. It looks like I can modify ComputedMass after it's calculated but it'll be overwritten again if anything about the body changes. It would be nice to have a way to set a canonical mass for cases like mine where I'm trying to get more arcade style physics.
Or, I guess Mass isn't ignored but is instead added to the mass of the children? Either way, it doesn't seem to be possible to use it to set the mass to a fixed value.
set Mass to your desired mass minus the total child mass?
I guess I could have a system that does that after the object is spawned. I was just hoping for a simple way to configure it so that the mass stays the same even if I adjust the player's colliders. So I don't have to retune all the jump strengths and such. Setting the colliders to a density of zero works but it seems like a hack.
I wasn’t able to use the Avian examples as is because they all accounted for gravity which I didn’t want for a 2D top-down. I referenced those examples as part of what I did but I found that vidar was a better example, but in 3D. The Avian examples even say they're not complete examples. I’m also having rollbacks with lightyear but I didn’t have them until I started using the main branch. 0.19 seemed to work fine. I’m still not sure if it’s my code or just the changes on main. I've had a really hard time finding some blessed "correct" way, especially for 2D top-down, hence why I shared that code
the other way around, children add mass to parent and then center of mass is automatically computed if you're not adding the override
That makes sense. Has the same effect for my case.
"there is no way to fully override mass properties on spawn" Well, that's pretty unambiguous.
you're still reading the pre-rework part
fn set_desired(mut q:Query<(&DesiredMass,&mut Mass,&ComputedMass)>){for (d,m,c) in q.iter_mut() {let mass = d-(c-m);if mass != m {*m=mass}}}
or something
Ah, so I am. Missed the "previously" in the intro sentence.
i got confused the first time too tbh, examples should've been in past tense
Ok, so I guess NoAutoMass is what I'm lookng for.
Thanks for that link by the way. That's a super helpful writeup.
hmm yeah those rollbacks are bizarre. Okay I'll let you know, I'm working directly with Periwink to figure this out
Let me know what you find out and I'm happy to help test things as well. I'm debugging on my end as well
The module-level docs here also have a pretty detailed overview of how mass properties work in Avian
https://docs.rs/avian2d/latest/avian2d/dynamics/rigid_body/mass_properties/index.html
Mass property functionality for rigid bodies and colliders.
So it's kiiind of cool but also really annoying 🤣 what could I do to make it slide more instead of trying to roll along the walls? The collider is a sphere.
Maybe use a cube instead?
nah cube felt worse
ok lowering the friction did it
Curious, if colliders have global transform why dynamic rigid bodies, dont require them?
hi, anyone knows when avian updates the physical world with newly added rigit bodies? i spawn my rbs in PreStartup and want to do a raycast for them in PostStartup but they dont seem to actualy "exist" yet. if i run the system in update all is fine.
and by implication does anyone know how i can force this "realisation" step?
I believe it happens in PhysicsSchedule which is run here: https://github.com/Jondolf/avian/blob/main/src/schedule/mod.rs#L240
Maybe you could try to run that schedule yourself but I'm not sure there's an easy way to do that. It's almost certainly easier to wait for it to happen naturally. Why do you need to be running your code in PostStartup?
In my stuff I have systems that query on Added<RigidBody> which lets me react to physics objects as soon as they are created and ignore them afterwards. That might work for you.
thx
i need to run it somewhere in startup as what im doing is using the rigit bodies as terrain and want to shape cast agains them to fill a grid with where obstacles are and where not ( to then run my pathfinding on)
ill try that out soon. i seem to be able to add the PhysicsSchedulePlugin to a given scedule so this might work
a bit jank but better than running a seperate app instance to bake this XD
Ah. That sounds cool. Another way of approaching that might be to use application states (https://github.com/bevyengine/bevy/blob/main/examples/state/states.rs) which would let you transition between a terrain generation phase and the rest of gameplay in a very structured way.
yes later ill use this
but i dont want my code to be dependent on this to make it work
well u cant add the same plugin twice
so addin it with different scedules is not posible
im prety sure this cant be that hard
as this probably is nto such a niche thing?
I think the most common way of doing this kind of thing is to have a marker component like TerrainReady that indicates that the terrain is ready for use and then using things like Added filters on queries to do whatever processing steps are needed over the course of a few ticks and when everything is done you add the TerrainReady component which the rest of the game looks for. That way you don't have to change any schedules or do anything weird to the internals of the physics system.
States are the other way I've seen people do it. You put all your terrain generation systems in one state and all you gameplay in a second state and only transition to the second state once generation is complete.
how can i tell that the physics system did its thing?
I would use something like Query<Entity, Added<RigidBody>>. That query will give you a list of entities which have been added in the current tick.
i think statest prob would be the right aproach but i need to know when physics did its thing
my rigit bodies exits they are just not in avians simulation yet
Right. Hmm.
Maybe it's enough to just wait for a single tick to pass after you add the objects? I don't see an obvious marker component that avian itself uses to indicate it's finished setting up a rigidbody. A bunch of stuff gets added but nothing like RigidBodyReady
probably works but thats awfull XD
having some update steps be different from others already is bad design but having it not as a logical dependency but a timely one is to much XD
but im prety sure there should be some sort of marker
I don't know for sure but I suspect that it always takes avian exactly one tick to finish so the strategy of waiting isn't that bad. If it takes more time, because there's an async process or something, then I agree it's ugly.
But like I said, I don't know. I'm pretty new to avian and haven't looked at the internals much.
all fine. im rly thankfull for u helping me out
rn im trying this
and it actualy worked
somewhat ...
Nice
follow up question. maybe u know that too how do i shapecast exactly in one position? and nto stride in some way?
basicaly im trying to cast a rectangle for each cell to see if it intersects with the terrain
I've not done anything with shapecasts so I'm not sure.
thats the beauy u helped develop @kind moss
Looks cool! So the orange bars are the generated terrain and the red circles are pathfinding around it?
I just want to say congrats to Jondolf. This is a networked dynamic body I'm controlling. I'm purposely bumping into walls at fast speeds to try and desync it. Note I'm just testing it locally but it seems pretty damn deterministic. I've never had this experience with a physics engine before.
orange bars are the rigit bodies adn the underlying grid is used for pathfinding
later we want to put something like pheromones onto the grid to force enemies to not go where they probably die
Can someone give me a quick and dirty dynamic rigidbody vs Kinematic Body for dummies for me? My current understanding is that Kinematic Bodies don't have any forces applied to them without it being programmed to, and they detect collisions but again won't have force applied unless programmed to. Meaning a Kinematic Body will just move through a static Rigidbody unless programmed otherwise, right?
Pretty much yes
It's uncommon to see them outside of character controllers (tho those can be dynamic too ofc), but there are some examples where you want bodies to move and apply forces to other things, but not be affected by forces. One such example would be moving platforms
That makes sense. I'm trying to figure out what to make my characters. I'm starting to think they should be dynamic because any wall or box or anything I want them to collide with. The only other things I won't want them to collide with would be other players and one object, which I can just program to manually ignore yeah?
Then things like projectiles that I want going through walls and only collide with players I can make Kinematic...
You can also use CollisionLayers to control what collides with what.
That's true. If I had a Kinematic Body projectile and it collided with a dynamic rigidbody, would the dynamic rigidbody be pushed by default?
Yep
you can start with dynamic and change to kinematic when you actually need it
probably not what you meant, but now i'm trying to think of applications for runtime switching between dynamic and kinematic on a single rigidbody
changing a kinematic character to a dynamic ragdoll is pretty common
though for a ragdoll you need multiple bodies so it's not necessarily switching a single body
I have a question about animated physics bodies,
if I have a kinematic rigid body that is being animated by an AnimationPlayer, how do i make sure that collision works properly?
As in it doesn't teleport the object which makes collision not work nicely..
@vestal minnow does something reduce the linear velocity y even with gravity scale 0?
the gravity scale is 0 but when i set linear velocity to a number it suddenly set for 0 after a time
@sleek thicket hey bro
i calculate how many studs the player need go up from floor
like 0.1
altought if i do linearvelocity.y = 0.1 it take a big time to go up until 0.1 studs
how calculcate the correctly linearvelocitty to reach the amount i need?
i tryed multiplie by computed_mass.value()
what's your spring strength and damping?
idk, i didnt changed it
iam trying use externalforce now
cause linear velocity is slown as hell
Is there a good way to know if something is inside of another collision meshes geometry?
I saw the Sensor example and have implemented a similar setup in 3D, but the problem I'm having is the CollisionEnded events fire while the colliding object is still within the Sensor's geometry
It seems the the CollisionStarted and CollisionEnd only care about the external geometry collision, once something is completely inside the mesh it's treated the same as if it's left the mesh entirely
Thinking about it this may be due to the TrimeshFromMesh ColliderConstructor I'm using. I'll have to take another look at that and see if there's an internal one too
Otherwise I'll have to switch to using something like big_space's grid system for spatial querys
convex decomposition?
The docs mention that a TriMesh is hollow: https://docs.rs/avian3d/latest/avian3d/collision/collider/struct.Collider.html#method.trimesh
Oh, never mind. That's what you were already saying.
Yep that was indeed it, glad I was on the right track haha
does avian give acceleration data ? like of a character (tnua controller)
there's the ExternalForce/Impulse/Torque components
only works if that's how it's applied though
Is there any distinc difference between the collisions of a entity with a child collider and one with a collider itself?
The only difference I'm aware of is that events like CollisionStarted only reference the collider entity, not the RigidBody. So in the case of a child collider you won't have access to the RigidBody entity in the event handler (without doing some querying).
yes, you can see the default features in the crate's Cargo.toml or on docs.rs
Did I see correctly that there was a branch/fork that added support for big_space?
found #1124043933886976171 message , but there's also more recent mentions
I saw that one, couldn't see any more recent mentions but I'll take another look
@vestal minnow working on this, and it seems to overall work out fine, but I'm kind of annoyed by how clunky the contact manifolds function signature becomes with context, the with_context feels like is hould be immediately followed by the context, but instead there is collider2.shape ... I'd expect it to be a method on (shape, shape) instead of shape.method(shape, ...) 🤔
I'd imagine auto complete would absolutely hate that function signature tho 😂
Well damn that really is a lot cleaner, I especially like how the context simplifies the function signature by dropping the weird trait bounds
https://github.com/Jondolf/avian/pull/665/commits/22e60e808c4e1b23c3ad4670a6d4abaa0e60de1b
is there a simple way to create a dynamic rigidbody that is frozen in place until something hits it?
maybe I just give it zero gravity and then add gravity when it's hit 🤔
just switch from static/kinematic to dynamic on collision
I tried that but.. when it's static it feels like sometimes the object that is colliding into it reacts as if it's running into an unmovable wall... kinematic behaved somewhat inconsistently..
ah, then maybe sleep?
i would suggest just make a collider without rigid body and keep checking is something hitted on it with shape cast
if hitted turn it into a dynamic body
this seems expensive
I suspect sleep + removing gravity might make it behave the way I want
you don't even need to remove gravity
hm, yeah, actually that might work
for what I was doing, I did have to remove gravity but it was because I wanted my colliders to be at a specific height above the ground and stay there
but otherwise, that worked perfectly
How do I get the velocity at a specific point on an object?
I want my character to move with the point they are standing on
so if the platform moves or rotates, they move with it
Automatically generated [WorldQuery](bevy :: ecs::query::WorldQuery) item type for RigidBodyQuery, returned when iterating over query results.
wait no
now I'm getting confused about how to use this
I've just got back to bevy after a break lol
yeah that actually doesn't work for me since I want to do it based on a specific entity ID
Nevermind. I didn't know what worldquery meant
orrr not
I am in need of some handholding I think
how do I get the velocity of a point of a specific entity
I think you can get it by adding the result of velocity_at_point to LinearVelocity but I haven't actually tried that.
But how do I use velocity_at_point
I have an entity id stored in some variable. How do I go from that to running that method
Oh, you mean how to you get the RigidBody?
the RigidBodyQuery
If you know it's entity then you can use Query<&RigidBody> and just call get(entity) on that.
Ah. more systemstate shenanigans
Either way
wait
oh
ohhhhh
are queries lazily evaluated?
as in, is it at instantiation or first call
Normally you would recieve them as the parameter to a system function. It sounds you you aren't using a system? In that case it gets a lot more complicated. You probably should be in a system.
I am, I'm wondering because I don't want Query<RigidBodyQuery> to contain every single rigidbody's rigidbodyquery only for me to use one
get_floor_velocity is the system I'm working on rn
You shouldn't need to worry about that. The ECS is very good at fetching only data that's needed.
also ignore this. this was before it clicked
alr
I said to add it to LinearVelocity but take that with a grain of salt. I'm not what exactly the docs mean by Computes the velocity at the given point relative to the center of the body. Is it the point that's relative to the center or the velocity? It's probably more likely that the point is in local coordinates and the velocity is in global coordinates, in which case you don't need LinearVelocity at all. But I'm not sure.
I know how to use it
but uhh
problem
It doesn't account for rotation since the origin is rotation
that's why I wanted it in the first place 🙃
so I'm stuck
So it's returning the velocity in local coordinates?
is there any way to move relative to a point on an object that takes into account the object's rotation?
I think so
You can use GlobalTransform to turn the local point into a global one.
That should also work with velocity vectors I think?
What I mean is like
we paint a dot on the object
and we're moving relative to that dot
and the object can move around and rotate
well
more accurately I just want to know where the dot is
and I want to know it's velocity
so I can move something with it
what I mean is
idk how to explain it better, I'm sleepy
Can you parent the object to the thing it's supposed to move with? That might just get you all this for free.
but it's important that I have the dot's velocity
I'm trying to avoid that in case someone has the idea of recursively operating on all the children of an entity
(trying to save myself a headache down the road if I do that for whatever reason)
I don't want to modify the "floor" (the entity the dot is on) at all
Since objects are all rigid in avian you only have a problem if the object has angular velocity, right? If it's not currently rotating then the velocity at every point will just be LinearVelocity.
I already have code that does the math to just figure it out using angular velocity and a point but it doesn't work in the event of nested rotating objects and other converted situations
Yeah
I need it to work with rotating objects
It already works with ones that don't rotate
Can rigidbodies even be nested like that? I thought they couldn't.
A rigidbody with rotational velocity and a parent that also has rotational velocity can exist
and rigidbody is just a component, so entities with it can be nested like any entity methinks
Huh, for some reason I thought only the outermost RigidBody actually got simulated. But I guess not. Then can you walk the hierarchy and add up the local velocity_at_point results?
velocity_at_point returns identically to LinearVelocity
It might be a bug
if it accounted for AngularVelocity it would be fine
but it doesn't
That sounds like a bug to me, then.
also the description makes no sense with that behavior. It should return 0 for non-rotating bodies and account for rotation for rotating ones
either way, I want a working velocity_at_point that's in worldspace basically
Unless the "relative'" in the description is refering to the point (as it is in many other avain functions) rather than the velocity. But I agree it's unclear.
It doesn't make sense either way
since the body origin moves with the rest
If you look at the code, it clearly is doing something with angular velocity: https://docs.rs/avian3d/latest/src/avian3d/dynamics/rigid_body/world_query.rs.html#39-48
huh... weird...
wait
ok something is definitely weird one sec
I just realized it doesn't return identically I just misinterpreted something in my sleepy state
gimmie a sec
wait no it is identical
hmm
It might be because I'm asking about a point that's technically above the model by a smidge
since it's the bottom of the player instead of the surface
if raycasts let you see where they hit this would be easier lol
gimmie a sec to try and ask it about where it got hit
yeah no I can't get it to work
fn get_floor_velocity(
mut player_query: Query<&mut PlayerData, With<Player>>,
ray_query: Query<(&mut RayHits, &RayCaster), (With<PlayerFloorCaster>, Without<Player>)>,
floor_query: Query<RigidBodyQuery>,
) {
let mut entity: Option<Entity> = None;
let mut hit_point: Option<Vec3> = None;
for (hits, caster) in &ray_query {
for hit in hits.iter() {
entity = Some(hit.entity);
hit_point = Some(caster.origin + caster.direction * hit.distance);
}
}
let mut floor_velocity = Vec3::ZERO;
if let Some(hit_point) = hit_point {
if let Some(entity) = entity {
if let Ok(floor) = floor_query.get(entity) {
floor_velocity = floor.velocity_at_point(hit_point);
}
}
}
for mut player_data in &mut player_query {
player_data.floor_linear_velocity = floor_velocity;
}
}
The calculation in the code isn't making any reference to the shape of the object, so I don't think that would matter.
yeah, fair point
hmm
Either way, since this is local anyway and not in world space, it's basically a non-functional version of what I had before
and I'd need to recursively do the calculation
at this point, I'll probably just do that
I'm hazy on ray casting but it doesn't look like you're selecting only the nearest hit? Are you sure the floor you end up selecting isn't some distant one?
and @vestal minnow , this looks like a bug with https://docs.rs/avian3d/latest/avian3d/dynamics/rigid_body/struct.RigidBodyQueryItem.html#method.velocity_at_point
Automatically generated [WorldQuery](bevy :: ecs::query::WorldQuery) item type for RigidBodyQuery, returned when iterating over query results.
the max_distance is 0
or something extremely small, I forget
Ok
and as a final thing
do you know if collisions or air resistance are simulated first in the physics schedule
if you don't I'll just check myself
I don't, sorry.
alr
Does anybody know when gravity is simulated?
As in, in what schedule and step?
nevermind
Integrates Newton’s 2nd law of motion, applying forces and moving entities according to their velocities.
I always ask questions just before I find the answer lol
@sleek thicket how'd you know lol
What is? The method computes the linear velocity that a point on a body is moving at, taking into account the body's linear and angular velocity. The point is a world-space offset from the center of mass of the body.
If the offset is zero, the point velocity will be the same as the body's linear velocity, since angular velocity won't have an effect at the center of mass; otherwise, the point speed should be larger if angular velocity is non-zero
This is the exact same as bevy_rapier's linear_velocity_at_point, except the point is given relative to the center of mass to avoid having to compute it in the method every time. Also similar to GetPointVelocity in Unity.
It could be changed to take points in global space, not relative to the center of mass, but this would be useless for Avian internally since we need them to be relative for the contact solver. RigidBodyQuery isn't necessarily intended for users, its main purpose currently is to make internals a bit less annoying
The point velocity is also very simple to compute manually, it's just
lin_vel + ang_vel.cross(offset)
I've considered combining LinearVelocity and AngularVelocity into just Velocity like in Rapier, which would let us add an at_point/at_offset helper for it directly. I'm not entirely sure if I like it otherwise, but I would be open to trying it if people would prefer that
when I checked a while back there was an issue where this crate was using a dependency that couldn't be used for commercial products. I suggested that it was put in a feature flag so we could avoid the issue, just wondering if it's still a thing or can avian now be used for commercial stuff?
It's still a thing in terms of "Avian uses XPBD for joints, and XPBD is technically patented". So it's kind of "use it at your own risk" in that sense.
But (I am not a lawyer) realistically I think the risk is extremely small. XPBD is quite widely used in a number of open source and commercial projects, the inventors of the method have themselves published XPBD implementations under the MIT license, and when we asked about it, they even responded to us saying that there shouldn't be any restrictions in using it. And looking at the patent, it doesn't seem very enforceable, and I don't think it even applies in the EU where I live (but again, I am not a lawyer).
Also, Jolt uses XPBD for soft bodies, and Jolt is officially supported as an option for physics in Godot.
That being said, we do still plan on most likely switching away from XPBD for joints, and I have it partially implemented already; it's just a lot of work and takes time
alright I might give avian a try then, would be interesting to see how it differs from rapier in terms of an end user perspective
Even if it has angular velocity and you specify a non-zero offset it's just linear velocity I think
I can do more testing later today
@sleek thicket
pub fn adjust_collider_float(
mut character_query: Query<(&CharacterController, &Collider, &Transform, &mut ExternalForce, &mut LinearVelocity, &ComputedMass), With<CharacterController>>
){
for (character_controller, collider, transform, mut external_forces, mut linear_velocity, computed_mass) in character_query.iter_mut(){
let capsule_collider= if let Some(capsule) = collider.shape().as_capsule() {capsule} else {continue};
let height: f32 = capsule_collider.height() + (capsule_collider.radius * 2.0);
let half_height = height / 2.0;
let current_translation = transform.translation;
let mass_value = computed_mass.value();
if let Some(ref shape_hit_data) = character_controller.shape_hit_data{
let ground_point = shape_hit_data.point1;
let float_point = (ground_point.y + half_height) + 0.1;
let stand_difference = current_translation.y - float_point;
if stand_difference.abs() <= 0.01 {
if linear_velocity.y != 0.0 {
linear_velocity.y = 0.0;
}
if external_forces.y != 0.0 {
external_forces.y = 0.0;
}
}else if stand_difference > 0.0 {
external_forces.apply_force(Vec3::new(0.0, stand_difference * mass_value, 0.0));
}else {
external_forces.apply_force(Vec3::new(0.0, -stand_difference * mass_value, 0.0));
}
}
}
}
did
and its working
floats 0.1 from ground
i guess you never ended up watching VVV tutorial
no
xd
but
its fine this way?
if you're happy with it then w/e
but it would be 2 lines of code if you watched it
xd
and you'd actually understand what you're doing at the same time
applying as force instead of velocity might be really cool for your game though
like if you have some gravity ability that increases enemies' weight and they start crouching because of it
ah yeah, they shot themselves in the foot by choosing UE for something so complex, didn't they
their problem were: BUGGED UPDATES + THEY USED ALL THEIR MONEY ON JUST ONE STREAMER, like wtf

wdym used all their money on one streamer? 
because they are dumb
proletariat
marketing?
ads just with one streamer bro?
seens the worst stuff possible
Like they spent their whole promotion budget on getting one streamer to stream the content? 🤔
yes
for like 2 days

What even ... Most game developers literally don't even pay streamers for promotion
as i said, proletariat make sick games but have a TRASH ADS TEAM
spellbreak is legit the best game i played so far in 5 years
still, it died cause dumb decisions
and have a big community rn that plays the open source version
that sadly cant keep because copyright
so iam remaking it but with unique stuff to avoid copyright
making like that i will have a big community already xd
huh, what other games did you play
lol, deadlock, valorant, dota
fortnite
talking about competitive games btw
oh, that explains a lot
.
spellbreak was competitive, had tournaments and all
iam talking about competitive category, otherwise ofc have better games but they are not competitive
it had a lot of potential but otherwise it was really mediocre, maybe i was just too early to see it at its' peak though
the problem were the devs
ik cause i followed the game since start
they started get lazy with updates and giving content comunnity didnt want
and again, LACK OF ADS
like 0 ads bro
i don't think ads could help them in the first place
I wonder if Position should required Transform; i've had many issues where i was missing cases where Position was added on an entity but no Transform
so things like position_to_transform sync would not work
how not
Games that don't come from a well-known company or a big franchise need ads
a example is Vaultbreakers, a new game that is on test phase, i found it cause constantly ads on youtube
otherwise i would never find it
now if resident evil 10 releases for example they BARELY neeed ads
since its a big franchise alraedy
because the target audience is the one that's most likely to have adblock installed lmao
youtube ads i mean
youtube ads, trailers, multiple streamers
i never see it on spellbreak
they put all the money on one streamer guy
i never saw ads for vaultbreakers
i never saw ads for vaultbreakers
i did, multiple times
But also this seems pretty unrelated to physics, might be better to move to #off-topic 👀
Seems like a stretch, but you could add this constraint from your own code ... The main thing is that you could have physics entities that aren't visible, and thus don't need (Global)Transform
Yeah, it's just annoying because i'm replicating Position and i keep expecting things to work, but most avian systems do the position<>transform syncs only for RigidBodies
That said the whole situation with Transforms sucks, and ideally we could just have something that avian could use directly and thus eliminate this whole class of problems
yeah it's a huge annoyance
I mean the separation between Position/Transform might be necessary/good though
Ah yes ... The reason my example has this hack ... https://github.com/NiseVoid/bevy_rewind/blob/main/examples/toy_cars/avian.rs#L45-L58
Transform could be modified for various reasons (visual interpolation, etc.) which doesn't mean that you should send a replication update
it's cleaner to have a dedicated component Position for FixedUpdate concerns
ah I see
yeah i already have this hack in, what i was missing is a system that inserts Transform when Position is added
is there a good way to play sounds on each collision, with scaled volume by either applied force or energy loss? Res<Collisions> seems to only ever give non-zero total_normal_impulse when during_previous_frame is also set
anyone know how to impl avian collisions for bevy_voxel_world?
Is it possible to offset a cuboid collider on a gltf model? My buildings are off the ground by 50%. I've searched and it looks like this might be a common issue, but I don't see what the solution is. I tried changing the origin point of the model in Blender (doesn't work), and offsetting all the vertices so half the model is below zero (works, but it's not ideal - I'd have to duplicate/automate models in my project). Here's how I'm spawning the gltf scene:
commands.spawn((
SceneRoot(
asset_server
.load(GltfAssetLabel::Scene(0).from_asset("models/shop.glb")),
Transform::from_xyz(pos.x, pos.y, pos.z),
Collider::cuboid(size.x, size.y, size.z),
RigidBody::Dynamic,
CollisionLayers::new([Layer::Buildings], [Layer::Terrain]))
));
wdym it doesn't work
it seems like the model's origin is at bottom
It seems like the model origin has no effect on the collider. If I change the origin from the base to the center, then it doesn't modify where the collider is (the building floats in the air - the same as if the origin is at the bottom)
But if I move all of the vertices manually below zero, then it does work. I can do that if I have to, but I was hoping there'd be a way to specify a manual offset. (This is using a hand-rolled cuboid collider, not the generated trismesh collider.)
you can put either the model or the collider on a child entity and offset that
via Transform
Thanks, perfect!
In blender
Did you apply transform/scale?
I did apply all transforms... do you think changing the origin should affect the position relative to the collider? I will go with Jondolf's suggesting of offsetting via a child anyway (as I'd like the origin to be the pivot point at the base of the building), but I have no idea what I've messed up if changing the origin /should/ work!
hey @vestal minnow are there any good papers/videos that you found helpful while building avian? I'm working on building a (much simpler) physics engine in zig but I don't have a formal maths education
zig?
all phsycis have formulas online
just use chat gpt to get the math formulas
and examples on how implement on others languages
Someone in the zig discord mentioned The orange book (real-time collision detection), so I'm going to start there
zigs have a game engine
you could contribuit
Probably don't use gpt for math...
zig has several, I will likely contribute to some in the future but I'm building this physics engine largely to teach myself more about game physics so that I am less reliant on external engines
Whatever floats you're boat, I personally don't like to use LLMs ever
easy but not reliable at all
easy for 1 + 1
the more complex the problem the more they will hallucinate
why don't you ask in #math-and-physics ? you, jondolf and others could have great conversation there
also, is there no physics engine built in pure zig?
Didn't see that channel existed, thanks!
There probably are, but I'm trying to build one myself, and I don't believe any of the existing engines will be as mature as avian
oh right, you are trying to learn how it works instead of just using it?
oh, you're spawning the entire scene, with the model as a child
Yup!
Neither do I, beyond high school physics and now a few uni courses 😄 I responded in #math-and-physics message with a proper essay haha
Reading it now, thanks a ton, this is a lot of useful material
is it possible to create "inverse" colliders? e.g. if I wanted to create a sort of game arena, could I do something like .capsule()..invert() where only the inner part would be accessible and everything outside would be a colission?
turn it into trimesh, i guess
Pretty sure (if physics is based on normals) you can invert the collider's normal
Ie try giving a collider negative size values?
That's how I get inverted meshes at least
By making it a trimesh or using convex decomposition. Collision detection algorithms largely rely on shapes being convex, and cannot generally handle inverted cases like that without approximating the boundary with other convex shapes in some way
(excluding NiseVoid's SDF colliders I guess)
is there an example of something like this ?
just do like ten halfspaces
Not quite the same thing, and won't work to prevent things leaving the box, but if the goal is to move things that aren't in the box back into the box then this might work for you
You can use the collision events to add a component to an entity if it leaves the box. Then have a system running that applies a force to push the entity back into the box
@vestal minnow Sorry for ping, but do you think it is a good idea to make a component that stores the contact manifolds of an entity? On that frame
Similar to colliding entities in this case
This would copy all the contact data to multiple places (Collisions resource + components on entities) and require a decent amount of extra bookkeeping. Imo it also wouldn't make much sense semantically, since entities don't "own" collisions, contacts are between entities
the internals wouldn't use the component either way, it'd be way too expensive and make parallelizing the narrow phase much harder / impossible
if you want to access contacts for an entity, use the Collisions resource
Jondolffff
Yes, you are completely right. Could you give me your take on this? Lightyear needs to rewind collisions to the tick rate at server, when a predict rd entity Rollbacks. Right now he can only rollback components sent in the same predicted packet (cant include resources because reasons). My idea - Store collision forces applied to that entity in server tick, on rollback instead of using the new sim forces use server replicated "forces", by overriding the forces in colllisions. This would be a temporary solution, only until resource as entities. Btw lovely documentation, collisions is truly a powerfull struct
I don't think Collisions should ever be networked tbh, it's not a small bit of data
We could also make, so collisions is converted into some sort of pseudo entity. Seems weird tho and unsafe
In rewind, was your approach some sort of rewind entire world, into server safe tick?
I wonder how did you handle collisions?
In the case of Collisions I just roll it back to what it was on that tick, the mispredictions caused by them being out of sync disappear within a frame anyway
Tho disabling warm starting is also an option so it no longer affects determinism 🤔
There are also some annoying edgecases with Collisions where my code ends up removing it because it wasn't there in the history and then avian panics 😂
Yes that is something I wondered. Just go back to server tick when it comes to collisions. But I am almost certain the approach for non networked in lightyear is rewind only 1 predicted tick instead of all.
Interesting
I want the optimization 🙂
I rewind it to whatever it was on the client at the tick I am rolling back to, then leave it alone as I resimulate (same as for predicted-only components, tho unfortunately I have to special case resources so they have more scuffed code)
The tick I roll back to in turn is the oldest tick I received data for
Nise your game looking great
Hmm but them, isnt there a chance you repredict it wrong?
I see
Yes, but if there is state for the next frame I load that, and the mispredictions disappear in no time, since eventually both sides have the same collisions happening on a tick
Ah I see, I dont think I can do that in lightyear the refactor involved,might get me shot by Periwink. I guess the logic is more rewind precise factors
Yea it's really not well suited to lightyear's impl. On the plus side disabling warm starting and upping substeps to compensate is more viable if you don't predict the whole world
Increasing precision, might not fix my problem tho. One slight mis prediction and it is goodbye alignment. I guess although it increases packet size, delta compression could easily avoid redundant big chonky collisions packets
Yea it's removing the non-determinism, and warm starting causes that if it's not replicated
Delta compression definitely could help, but you might also want more locality than the whole resource
I am gonna try that check stability
Non_networked_rollback already does exactly that, it rewinds the Collisions resource to its value at the Prediction tick.
However I do not observe that mispredictions disappear even after that
It should rewind to it Confirmed tick no? In this case scenario
I assume the way it works in lightyear is that you'd have to roll it back to the newest confirmed tick for your predicted entities (often just the player), then resimulate from there ... But thay still gives you less ticks to smooth stuff out + collisions with aything interpolated would always cause it to be wrong
Can you explain more why it would work in your case and not mine?
That's correct, I revert Collisions (which is non-networked) to its last client state at the start of the rollback tick (which is usually slightly different from the state of the resource on the server). Then I do a normal rollback on every predicted entity. There are no interpolated entities, everything is predicted. I don't understand if you're doing anything different than this?
and yes I also had to handle this, it was annoying 🙂
I don't understand what this means: "Yes, but if there is state for the next frame I load that, and the mispredictions disappear in no time, since eventually both sides have the same collisions happening on a tick"
You reload state from two consecutive ticks?
Yes, lets say e1 is at tick 3, e2 is at tick 5, and 3e just got data for tick 2-5, I roll back to tick 2, then resimulate to the present, loading the data for ticks 3-5 when I get to those ticks
While if you don't assume you have to resimulate every frame after changed state anyway, you can just start at 3 in this case, or 5 if e1 wasn't there
In essence that means my client's simulation will almost always resimulate until it is exactly the same as the server
Hm i still don't get it; in my cases all entities are at tick 10, I receive an update from the server with the state of all entity states at tick 3. I revert Collisions to tick 3, I revert all entities to the server-state of tick 3, and resimulate 3-10.
The issue is that since Collisions is slightly different so I end up getting slightly different values at the end again
I need to go to work but i'm interested in discussing further! thanks for sharing this
actually iam trying do it now cause iam having issues with me methods, on my method i have to calculate the gravity my own on y axis, making when you jump and fall you go under the floating point for a time
and its causing me issues
but its defi not two lines of code
iam having problems to implemnt it anyway
can i see your one?
You mean the code for calculating the floating force? 🤔
yep
rn i did it myself, but for that i made it 0 gravity
the proble mis
when iam making the character go down after jump
its go under the floating point and takes a bit time to start floating again cause the forces
let me show the issue to be hoenst
I have 3 lines for the floating force code ... Tho I do also disable gravity (using GravityScale)
fn calculate_float_force(ground_distance: f32, velocity: &LinearVelocity, ground_vel: Vec3) -> f32 {
let relative_vel = velocity.y - ground_vel.y;
let snap = ground_distance - FLOAT_HEIGHT;
-(snap * FLOAT_STRENGTH + relative_vel * FLOAT_DAMPING * TICKRATE as f32)
}
let spring = up * (((target_distance - hit.distance) * spring_strength) - (upward_speed * spring_damping));
yes but you do it with linear velocity or external force?
lv, i've already sent the 2nd part before
you disable gravity too?
yeah
if ray doesn't hit ground you're in air, so you just apply gravity there and add to coyote time counter
what is coyote time counter?
it's a counter for coyote time 👍
what is coyote xd
Omg give me those const values, fine tune is a pain in the ass
my problem is when iam applying gravity down when have no ground it ends up going to far down lol
I wonder how much of a crime my character controller is, I remember it was awful and then I improved it slightly, but then I added features I never tested 🤔
Probably some good nightmare fuel for @sleek thicket at least 🤔
Oh and const values for @vague pebble 😂
well
pub fn adjust_collider_float(
mut character_query: Query<(&CharacterController, &Collider, &Transform, &mut ExternalForce, &mut LinearVelocity, &ComputedMass, &CurrentStates), (With<InteractNetworkAble>,With<CharacterController>)>
){
for (character_controller, collider, transform, mut external_forces, mut linear_velocity, computed_mass, current_states) in character_query.iter_mut(){
if current_states.contains_state(&States::Jumping) || current_states.contains_state(&States::Falling) {
continue;
}
let capsule_collider= if let Some(capsule) = collider.shape().as_capsule() {capsule} else {continue};
let height: f32 = capsule_collider.height() + (capsule_collider.radius * 2.0);
let half_height = height / 2.0;
let current_translation = transform.translation;
let mass_value = computed_mass.value();
if let Some(ref shape_hit_data) = character_controller.shape_hit_data{
let ground_point = shape_hit_data.point1;
let float_point = (ground_point.y + half_height) + FLOAT_DISTANCE;
let stand_difference = current_translation.y - float_point;
if stand_difference.abs() <= 0.005 {
if linear_velocity.y != 0.0 {
linear_velocity.y = 0.0;
}
if external_forces.y != 0.0 {
external_forces.y = 0.0;
}
}else if stand_difference > 0.0 {
external_forces.apply_force(Vec3::new(0.0, stand_difference * mass_value, 0.0));
}else {
external_forces.apply_force(Vec3::new(0.0, -stand_difference * mass_value, 0.0));
}
}
}
this is how i am doing
Wait why do you invert stand_difference in one case? Isn't it supposed to actually go the other way if it becomes negative?
what
OH my god you handled the slope issues
wydm
I was about to do that
Idk if I actually handled them but there is some code for it at least 😂
there is no gravity, if i make it go up than on next frame i need make go down, otherwise it keep going up forever
😭
and when i make going down that is being the problem
This makes it always only go one way no?
}else if stand_difference > 0.0 {
external_forces.apply_force(Vec3::new(0.0, stand_difference * mass_value, 0.0));
}else {
external_forces.apply_force(Vec3::new(0.0, -stand_difference * mass_value, 0.0));
}
```Like if stand_difference is negative you make it positive again 🤔
But also why is the force so small and why is there no damping?
yeah, i try to keep it as simple as possible so that it's easier to keep everything that's happening in mind
idk iam goot with math
plus i never did it
no
1-what is spring_strength, 2-what is spring_damping
how do i get those two values?
consts, same as in video
video doesnt even show it
i think it was explained better in the car one
this is the whole code the video shows
the problem iam having is when i try make the character go down when there is no floor
i keep like
wait let me show
linear_velocity.y -= gravity_force.abs()
every frame
aaa i will try play to show what i mean
when rust over stop bugs
@cinder summit
@sleek thicket
see
it takes a time to keep floating again
when i jump
Cause your forces are absolutely tiny and there is no damping to get rid of existing downward velocity
yes and idk the math for it
linear_velocity.y -= gravity_force.abs() + 0.1; iam reducing the velocity like this every frame when there is no floor detecting
that is the problem probaly
i should get the distance and reduce to go correctly on the floor position
^ math
idk how get FLOAT_DAMPING , not even TICKRATE
is this a const you made i suppose? @cinder summit
Look further down I shared the whole file. TICKRATE is just the number of phyaics ticks per second
The damping is pretty much arbitrary, this was the lowest that felt right iirc
the code is a bit messy xd
Mine or yours?
yours, at least for my defaults
not saying its bad lol, just saying its not the style i like personally
so its bit confusing for me
Oh yeah that file is a mess
yes
How does one increase the amount of substeps in avian?
okie iam all day trying make it float, gonna leave now
still no progess xd
see ya guys
Thanks
😈
.insert_resource(SubstepCount(4));
Rapier and Box2D default to 4 IIRC
Rapier might have some extra stabilization thing though, I don't remember
3 kinda works but doesn't feel as stable, 4 is doable, but maybe one day the performance is good enough that running 60 substeps per frame isn't the bottleneck and I can set it back to the default of 6 again
A substep count of 12 should worry me about f32 imprecision?
Wasn't 12 the default back with XPBD?
uhh I think so
the number of substeps shouldn't meaningfully impact numerical precision unless we're talking like over a hundred substeps or something
those high counts are only really useful for complex joint setups like chains or cloth
for collisions that would typically be very excessive unless you want a very tall perfectly stable stack of boxes or something
(very tall, like hundreds of boxes probably)
Yeah Rapier seems to run relaxation (solve constraints without bias) twice by default, it just calls them "internal stabilization iterations"
Avian and Box2D run it once
Hmm might be worth trying if that's better or worse than our current default, if we used 4 substeps but 2 relaxation iterations, it'd be the same total number of constraint solves as our current 6 substeps and 1 relaxation iteration
(4x solve with bias + 8x relax vs. 6x solve with bias + 6x relax)
In case you missed the context btw, here it's upping the substeps to hopefully get a bit more stability despite disabling warm starting
I think I did this before with no warm starting and 6 (instead of 4)
I don't stack boxes tho 
well iam almost there, the problem now is that iam putting to much force i guess
Thanks for your aid, @cinder summit it seens your tip to increase determinism was good
it's not even a floating collider, why are you trying to copy the homework 😂
and why are you swapping animations when jump ends, instead of when falling starts
heyy, wanna ask how does external impulse works? do i need to add the component to the targetted entity? or do i just spawn it into the world? will it be automatically removed after that? or do i need to clean it up myself?
What, wydm, he is floating 0.1 studs
then you're missing the whole point of it
So increase the float for 0.5? Studs? Its Fine i Just need increase
change the capsule size to fit the torso
But there is not even my problem anymore, this is
Network stuff xe
Xd
Roolbacking a f Lot on client
Lmao
Hey my game rolls back every frame and it sure doesn't jitter
Is your game server + client on same crate?
Well so its Lightyear issue
Client jump First, than server moves it back
Usually mispredictions are caused by scheduling problems in your own code
You mean add.system?
Like FixedPreUpdate
ET
Etc
You saying iam scheduling wrong?
Can you take a look at my current code? @cinder summit
Very small
Yes, but the easiest source of issues is systems not having ordering rules within the same schedule, that causes them to run in a random order each restart
Not atm, am at work :(
Np
In avian should I worry about multypling by mass of the rigidbody? If my game deosnt care that much about contact forces
Managed to cut the combined cost of the narrow phase + constraint generation in nearly half (left is old, right is new)
The labels are a bit misleading now since "Generate Constraints" no longer exists as its own step for contacts. I basically just moved constraint generation into the parallel contact computation loop, which (1) makes constraint creation parallel, (2) lets us reuse all the computed values like the effective speculative margin, and (3) gets rid of the additional ECS queries for body and collider data
I'm not sure if this approach will work once we have SIMD constraints, but for now it seems fine :P
In what context? If you're applying forces or impulses with ExternalForce or ExternalImpulse, those consider mass already. If you're changing velocity directly, it's up to you if you want to take mass into account in some way
I was applying forces
Thanks god to know
Does this affect the collider traits at all? 🤔
it shouldn't, no
So you're saying this is basically free performamce? 👀
For some reason it seems to cause a small solver perf regression at least when single-threaded, even though it shouldn't affect that assuming the generated constraints are the same 🤔 I still need to figure out if there's something going wrong there
But it should be basically free perf, and is especially faster when multi-threaded
Now we just need @bold garnet to make multi-threading worth it below thousands of entities 
I will definitely have to get completely rid of PostProcessCollisions to make it work though, but that was kinda the plan with collision hooks anyway
(the post-processing schedule was previously run in between the narrow phase update and constraint generation, but if they're done in the same loop, that's not possible)
I’m looking for profiling benchmarks
If you want to suggest any
Ideally ones that do not depend on bevy itself
hi. I created a system that works with this query:
#[derive(QueryData)]
#[query_data(mutable)]
struct HydrodynamicsIntegrationQuery {
position: &'static Position,
rotation: &'static Rotation,
collider: &'static Collider,
velocity: &'static LinearVelocity,
impulse: &'static mut ExternalImpulse,
}
fn integrate_hydrodynamics(
time: Res<Time>,
mut bodies: Query<HydrodynamicsIntegrationQuery, With<Hydrodynamic>>,
) {
it should be right before or right after integrate_velocities. how can I put it in these places?
currently, it just lives in fixedpostupdate:
.add_systems(FixedPostUpdate, integrate_hydrodynamics)
hmm why doesnt spatial query raycast have gizmos?
I guess this should work
.add_systems(
FixedPostUpdate,
integrate_hydrodynamics.in_set(IntegrationSet::Velocity),
)
Velocity integration runs in the substepping loop, so if you want to run your fluid dynamics there, it'd be in the SubstepSchedule, in or before IntegrationSet::Velocity
I'm not entirely sure you want fluid sim to be substepped though, it seems like it'd be quite expensive and probably not needed for stability, depending on the implementation
Hmm I am doing a shapecast, to detect the slope of the platform I am on top off I should grab the contact points, and check their degree difference right?
you can compare the angle between the surface normal and up-direction
like
let too_steep = hit.normal1.angle_between(Vec3::Y).abs() > max_slope;
(or something similar)
or dot
yeah dot product works too and is faster
Dot product among the point1 and vec::y?
normal and up-direction
Okay
meaning something like
// The slope is too steep if the normal
// is pointing "away enough" from the up-direction
let too_steep = hit.normal1.dot(Vec3::Y) < 0.9;
Oh my character controller is finally taking shape
You can also define a specific maximum angle with this dot product approach. Mathematically (with pseudo-codey syntax), the angle between two vectors can be described as
cos(angle) = dot(a, b) / (length(a) * length(b))
in our case, we have two normalized vectors, so it gets simplified to this
cos(angle) = dot(a, b)
so if we wanted the maximum angle difference from the up-direction to be e.g. 45 degrees, we can say that the maximum dot product between a and b is cos(45 deg) ≈ 0.707107, resulting in this condition
const COS_45_DEG: f32 = 0.707107;
let too_steep = hit.normal1.dot(Vec3::Y) < COS_45_DEG;
it's highly approximated and not that expensive
just a little bit of organic to my game
I use configurable ray casting and an optimized aabb projection
and also, why are they giggling...
this is default behaviour, I didn't add any fluid dynamics to them
for i in 0..20 {
for j in 0..20 {
let x = i as f32 / 19.0 * 5.0 - 2.5;
let z = j as f32 / 19.0 * 5.0 - 2.5;
commands.spawn((
RigidBody::Dynamic,
Transform::from_xyz(x, 1.0, z),
Mass(0.1),
Collider::cuboid(0.2, 0.2, 0.2),
Mesh3d(meshes.add(Cuboid::new(0.2, 0.2, 0.2))),
MeshMaterial3d(materials.add(Color::srgba(1.0, 1.0, 1.0, 1.0))),
));
}
}
and the ground:
commands.spawn((
RigidBody::Static,
Transform::from_xyz(0.0, -2.0, 0.0),
Collider::cylinder(4.0, 0.1),
Mesh3d(meshes.add(Cylinder::new(4.0, 0.1))),
MeshMaterial3d(materials.add(Color::WHITE)),
));
and a setup:
fn main() {
App::new()
.add_plugins((
DefaultPlugins,
PanOrbitCameraPlugin,
PhysicsPlugins::default(),
))
.add_systems(Startup, setup)
.run();
}
they're alive ig
Could try PhysicsPlugins::default().with_length_unit(0.1) or something? Might not fix it completely though, I think there are currently some stability problems with small objects
IIRC it might be a numerical problem with angular inertia
so you could also try manually specifying some higher AngularInertia
the unit thing didn't work out
damn I hate computers
Hey @vestal minnow was https://github.com/Jondolf/avian/pull/665 okay now? Gonna need that soon, right after I get capsules/spheres working and tested 😂
I'll leave it like that 🤣
lower numbers just slow down the giggles, maybe i'll try to add some stabilization system
Oh it's only with the cylinder shape, and at the edges
A cuboid floor is fine
oh really
Seems like it, just tested both shapes
it is, yeah. why's it like that?
Not sure, I wonder if it could be some inaccuracy with contact computation for small shapes using Parry 🤔 (the collision detection library currently used by Avian and Rapier)
Using a trimesh collider for the cylinder seems to be perfectly stable
with ColliderConstructor::TrimeshFromMesh
One annoying thing about Parry is that it has a lot of hard-coded constants for various epsilon values and tolerances, which could potentially lead to some scenarios being misconfigured. Maybe something like that is happening 🤔
I'd really like if it'd allow passing some config to geometric queries (where relevant), at least for some length unit / expected world scale
indeed
reviewing
reviewed
Btw the changelog and migration guide still mention the get_ prefix, should probably be updated to be the _with_context suffix
Oh right ... PR descriptions are so easy to get outdated :')
If there is any performance regression, worst case we could try to invert the traits, though that could create the weird situation where you could not specify SimpleCollider but still have a () Context, which isn't great
(like have SimpleCollider be it's own trait without Context and the like, then have a impl<C: SimpleCollider> AnyCollider for C)
So I have an interesting issue while climbing slopes
It is a floating character controller, but when he does down it is interesting, how he ups a little bit his force
I guess that in this case scenario I should apply force at a certain point, instead of making it at center mass correct? Or perhaps diminish by the slope factor
love this idea. I've a similar idea of applying "leg force" but for any movement
the direction of the force when walking or running the legs should depend on the direction of the desired movement and the slope of the surface. and if you apply it once in a while to simulate the movement of the legs, you will get a fairly organic walk with a realistic stop when the movement stops
this is the idea
if a character is descending, then you can not only add horizontal speed to it, but also negative vertical, as if it is not just falling, but stretching its foot down. but for large slopes this trick will not work, the character still has to fall
Hmm I guess the way he is climbing is correct
The way he goes dow is just a matter as of as said negative vertiical
Review comments should be fixed now, except empty vs fake cause empty really would be a sus name, tho I think that one isn't pub either way
is that capsule an actual collider?
Yes
could've just gone with a non-floating controller then lmao
I'm trying to make a spring network that is very soft and squishy in response to small disturbances but strongly resists large separations between nodes. What's the best way to achieve that? Right now I'm using DistanceJoints with a fairly high compliance which gives me the effect I want for small motions but let's the nodes separate way too much when there's more force on them.
Maybe two separate joints. One with high compliance and no distance limits and one with low compliance and a distance limit set to about the separation I want to tolerate?
I'm trying to achieve a soft body blob effect.
Can you just recalculate the parameters of the joint every frame based on the separation?
Yeah, that's an option.
how can I query acceleration?
Hmm, yeah having even a single joint per edge in the network with low compliance and length limits gives very glitchy behavior. When I apply an impulse to the entire network (ie. set the ExternalImpulse for each node to the same vector) it starts to move and then jerks to a halt in mid air, starts to fall, twitches and jerks to a stop again, falls again, etc. Like the joints are fighting to keep the network together and end up applying large global forces to the composite system.
How can I get the position of a hit between 2 entities in a collision event?
This'll probably get you what you need: https://docs.rs/avian2d/latest/avian2d/collision/struct.Collisions.html#method.get
This sort of works. I could probably tune it to be more stable but the joints always seem to have trouble maintaining the net without freaking out. I'm not sure if that's because I'm changing the parameters dynamically or if it's just intrinsically unstable.
The motion is done by applying the same impulse to each body in the net. All the bodies are identical.
So it's not like it's yanking on one body an everything else is flayling around to catch up to it.
That ended up being a bit more jello and less liquid goop than I initially wanted, but it's pretty stable so I'll take it.
maybe some cosmetic blob particles that come out when stationary and retract when moving
Yeah, might emphasize the effect. That was actually my first approach but I didn't like how disconnected it seemed from the terrain so this version is an attempt to do it with actual colliders. I might also be able to make the joints more compliant when the body is moving slowly and more rigid when it's moving quickly.
alternative approach, make it more stringy and use a ragdoll
I'm not sure I understand the suggestion. Are you saying to set it up like a mop or a pom-pom or something with strings that connect to the center and can flop around? That's interesting. It would work with the rendering which is already just metaballs so it doesn't really care what the internal structure is.
yeah, basically
more like a mop, how i was imagining it
That would likely work. I might try it when I circle back around to this.
Queued for merge :)
Next I'll probably work on updating to 0.16-0-rc.1 now that it's released
then I'll also be able to try peck in the wild for contacts :P (it has relied on Bevy main so far)
I should theoretically have 2D contact manifolds for arbitrary convex polygons working with it
3D shouldn't be too bad either, just need to implement feature clipping for it
@surreal rune I beat you in no_std support for bevy_transform_interpolation 😈
https://github.com/Jondolf/bevy_transform_interpolation/pull/8
That's so sick. I just saw that @frail robin managed to add no_std support to bevy_replicon with almost no changes too. It's all going way better than I expected
Yeah it's really cool how few changes are needed to support it for crates like this
(though CI seems to be failing now for unrelated reasons :P)
That's been my experience even just with the Bevy subcrates. As long as you can isolate assets and rendering, and you don't have incompatible dependencies, it "just works"
@surreal rune I also updated bevy_heavy to 0.16.0-rc.1, so your no_std PR should work once the actual feature flags are added. Shall I do that quickly, or do you have it done locally already? (edit: link)
ah there's a few failing tests too I think
I can update the PR since I'm working on this anyway, should be quick
So quick I did it too haha
All the features work in no_std (tested on wasm32v1-none). Note that default-features = false will fail to compile though, since you need to have std and/or libm enabled for Glam (but once the new version of Glam releases that'll be resolved)
Awesome, thanks :)
I think the tests in the impls modules are still missing a Vec import
Whoops! Fixed
Technically, bevy_heavy is also one of the few no_alloc Bevy crates too (there's no functionality since you need alloc for 2d and 3d but still :P)
I think that's also only the polygon and polyline types, which could technically be feature-gated 🤔 but idk if it'd actually be useful at all
Oh nvm there's a Sum impl that uses a Vec
I think it's fine to not bother with no_alloc. It's much harder to write and even harder to test
yeah
With avian2d is there a way to disable all rotation/angular movement and only have linear velocity from collisions?
You can use LockedAxes::ROTATION_LOCKED
Alrighty @cinder summit et al, Avian now has a rough migration to the Bevy 0.16 RC on the bevy-0.16 branch
Note that child colliders are currently broken there, but otherwise it seems to work
this is just an initial version to get it to compile and run, I'll clean it up later
https://youtu.be/VmYGPLXvpVY?feature=shared
what’d be the best way to use avian for rbd simulations like this? Or more complex ones with constraints
You probably want to create two models. One of the complete vase, and one for the shattered vase (where each piece it it's own object with it's own collider). And then just swap out the model when you break it, giving each piece some outward velocity.
You could make the shattering procedural but I wouldn't bother.
You could also listen for collisions on the vase and trigger the break when the force is more than X
EDIT: actually I'm not sure how to get the size of the impulse from a collision
I actually am curious about this now
the Collisions resource has a total_normal_impulse
Is that why the character controller examples are broken?
I think so, yeah
Okay fixed the child collider bug
I think it was a thing where I had an OnInsert observer that was also checking if the entity matches a query, but if both components were added at spawn, they didn't exist yet so the query failed
Mmmm the unsafe world cell stuff added in the collider context PR is panicking in debug mode because get_resource_mut doesn't allow mutable access through a read-only cell
need to figure out how to get around that
That's easy actually, just remove the whole AABB computation that uses the world cell 🙈 it doesn't make much sense to have it since the initial positions are likely wrong anyway
Huh, I'm surprised I never hit this while testing it ... I knew that code was somewhat sketchy though, but it shouldn't have resulted in UB unless your Context is intentionally picked to break things rather than load data that's actually useful
That's a nice cleanup 👀
wait I forgot I can also remove the ContextState resource now, lemme do that quickly
boom
yeah the world cell stuff was pretty ugly lol
how's bevy 0.16?
I've been working on main for a while for some networking stuff, it has surprisingly few breaking changes and outside of some messy APIs it seems overall stable
good to know
On the GameBoy Advance it's infinitely better than 0.15 that's for sure
oh dang, no_std is so cool. Might actually get a playdate now
This should compile right?
avian3d = { git = "https://github.com/Jondolf/avian", branch="bevy-0.16", default-features = false, features = ["3d", "f32"] }
```Cause I'm currently getting this error:
error[E0412]: cannot find type SpatialQuery in this scope
--> /home/nisevoid/.cargo/git/checkouts/avian-5a22c167119f3550/6874027/crates/avian3d/../../src/spatial_query/mod.rs:222:24
|
222 | mut spatial_query: SpatialQuery,
| ^^^^^^^^^^^^ not found in this scope
|
Should be fixed now hopefully(?)
idk when that broke, I don't remember touching that in a long time
I mean this is my first time trying to get SDF collisions working again since 0.14, so it had a full cycle to be broken 😂
0.16.0-rc.1 migration PR here
https://github.com/Jondolf/avian/pull/670
I'll merge it once CI passes, I want to get to actually doing stuff with 0.16 :P
@vestal minnow I Hope they fix the Time resource issue on 0.16
PR to change ColliderParent to be a ColliderOf relationship, add a RigidBodyColliders component to track attached colliders, and rework plugin structure a bit
https://github.com/Jondolf/avian/pull/671
@vestal minnow How would you handle cases like 2 perfectly overlapping spheres? What is the normal here? 🤔
If the center difference is zero, just fall back to an arbitrary normal like Vec3::Y
If the normal was a zero vector, physics would get zero overlap and do nothing to resolve the contact, which you probably don't want
Would that still be deterministic? 🤔
as long as the fallback normal is the same, it should be
this is also an edge case anyway, I imagine the only case where you'd get this is if you're spawning several spheres at the same exact position at the same time
Is the entity1 vs entity2 thing deterministic?
Cause depending on which is 1 and 2 the normal would effectively be reversed
But yea it's definitely an edgecase ... Either spawning them on the same position, having some bug that spawns things inside the player/enemy instead of at a more reasonable position, or having exactly the right amount of tunneling (very unlikely, but in theory possible)
It should be I think
If the entity order wasn't deterministic, then I think you'd get vastly different results anyway regardless of the normal, since the contact points would be in a different order and stuff like the relative velocity would be slightly different
Scaling support, in my SDF collisions?!
impl ScalableCollider for SdfCollider {
fn scale(&self) -> Vec3 {
Vec3::splat(self.scale)
}
fn set_scale(&mut self, scale: Vec3, _: u32) {
self.scale = scale.min_element();
}
}
@vestal minnow Are the local points for contact points the local coordinates on the already scaled collider?
So like if something just barely hits the edge of a sphere with radius 0.5, that was scaled by a factor of 3 ... Is the local point a length of ~0.5 or ~1.5?
I think it's on the scaled collider, so -1.5
Hi,
I tried creating a map with ConstructorColliderHierarchy::TrimeshFromMesh, but when my character walk on a edge, it can't move and after some time fall through the ground.
Am I doing something wrong ? or is TrimeshFromMesh not adapted for that kind of uses ?
did you try fix_internal_edges?
tried just now, same result
I will create collider manually, seem safer
@vestal minnow or anyone -
Anyone know why Extrapolation/Interpolation move my transform at different speeds? (videos in issue)
How are you handling movement for your character?
and in what schedule
I'm using leafwing, e.g.
app.add_plugins(InputManagerPlugin::<PlayerMovementAction>::default())
.add_systems(
FixedUpdate,
(systems::local_movement).run_if(in_state(GameState::InGame)),
)
pub fn local_movement(
time: Res<Time>,
mut action_state: Option<
Single<(&ActionState<PlayerMovementAction>, &mut LinearVelocity), With<LocalPlayer>>,
>,
) {
let Some((action, linvel)) = action_state.as_deref_mut() else {
return;
};
let delta_time = time.delta_secs_f64().adjust_precision();
let Vec2 { x, y } = action.axis_pair(&PlayerMovementAction::Move);
let moving = x != 0.0 || y != 0.0;
let dir = (y).atan2(x);
let cos = dir.cos();
let sin = dir.sin();
if moving {
linvel.x += cos * PLAYER_MOVE_SPEED * delta_time;
linvel.y += sin * PLAYER_MOVE_SPEED * delta_time;
}
}
Oh, I also have movement damping. But that's it basically.
don't multiply by delta in fixed updates
Hmm yeah that looks like it should be fine
Why 🤔
the examples do that...
it's only worth it in update
If you don't multiply by delta, behavior will be different if you change the fixed timestep, and units also make less sense
Movement speed would be tied to FPS, then.
The delta in FixedUpdate is literally always the same for every tick, so it doesn't matter
It's the same as making a setting so you can easily change tickrate later
If you want to move at 2 units per second, that's 2.0 * delta_secs regardless of the schedule. 2.0 in FixedUpdate would be... 2 per tick, which is weirder
Yeah so I think this is a red herring, I doubt FixedUpdate is an issue here. Any other ideas why Interpolation/Extrapolation would be different in how fast my character can move?
This looks like it should be fine... I would double-check that you're not directly modifying the transforms of the interpolated entities anywhere outside of the fixed timestep schedules, since that can mess with the interpolation
wouldn't this mean that you'll essentially gain speed when doing slow-mo?
Is there a reason that code isn't something along the lines of this?
let dir = action.axis_pair(&PlayerMovementAction::Move);
if dir != Vec2::ZERO {
linvel += PLAYER_MOVE_SPEED * delta_time;
}
The delta time doesn't change, the ticks would just happen slower 🤔
ticks happening slower doesn't increase delta? 🤔
not if you're doing slow-mo
FixedUpdate doesn't measure the real delta, it just gives you the delta for the tickrate you configured
I'm positive I'm not, I checked all the references in my project.
I'll give this a go!
Ok, I adjusted to
pub fn local_movement(
time: Res<Time>,
mut action_state: Option<
Single<(&ActionState<PlayerMovementAction>, &mut LinearVelocity), With<LocalPlayer>>,
>,
) {
let Some((action, linvel)) = action_state.as_deref_mut() else {
return;
};
let delta_time = time.delta_secs_f64().adjust_precision();
let dir = action.axis_pair(&PlayerMovementAction::Move);
if dir != Vec2::ZERO {
linvel.x += dir.x * PLAYER_MOVE_SPEED * delta_time;
linvel.y += dir.y * PLAYER_MOVE_SPEED * delta_time;
}
}
But it did not solve anything
btw, here how I'm initializing the physics:
pub struct SharedPhysicsPlugin {
pub render_gizmos: bool,
}
impl Plugin for SharedPhysicsPlugin {
fn build(&self, app: &mut bevy::app::App) {
app.add_plugins(PhysicsPlugins::default().with_length_unit(50.0))
.add_plugins(PhysicsDebugPlugin::default())
.insert_resource(Gravity(Vec2::ZERO))
.insert_resource(Time::from_duration(PHYSICS_TICK_RATE));
// Enable or Disable gizmos
let mut store = app.world_mut().resource_mut::<GizmoConfigStore>();
let config = store.config_mut::<PhysicsGizmos>().0;
config.enabled = self.render_gizmos;
}
}
Looks cleaner, not too surprising it didn't fix it, though you never know with atan2 and sin/cos those functions love causing problems 😂
Yeah, fair. Currently I'm convinced this is a problem in avian, not my code. So I'm trying to get the OGs like Jondolf to confirm. 👌🏻
Here's a minimal working example of interpolated movement with damping, for reference
use avian2d::prelude::*;
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins((DefaultPlugins, PhysicsPlugins::default()))
.insert_resource(Gravity::ZERO)
.add_systems(Startup, setup)
.add_systems(Update, movement)
.run();
}
#[derive(Component)]
struct Controllable;
fn setup(
mut commands: Commands,
mut materials: ResMut<Assets<ColorMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
) {
commands.spawn(Camera2d);
// Controllable object
commands.spawn((
RigidBody::Dynamic,
Collider::circle(20.0),
Mesh2d(meshes.add(Circle::new(20.0))),
MeshMaterial2d(materials.add(Color::srgb(0.2, 0.7, 0.9))),
TransformInterpolation,
Controllable,
LinearDamping(1.5),
));
}
fn movement(
time: Res<Time>,
keyboard_input: Res<ButtonInput<KeyCode>>,
mut query: Query<&mut LinearVelocity, With<Controllable>>,
) {
let delta_secs = time.delta_secs();
let up = keyboard_input.any_pressed([KeyCode::KeyW, KeyCode::ArrowUp]);
let down = keyboard_input.any_pressed([KeyCode::KeyS, KeyCode::ArrowDown]);
let left = keyboard_input.any_pressed([KeyCode::KeyA, KeyCode::ArrowLeft]);
let right = keyboard_input.any_pressed([KeyCode::KeyD, KeyCode::ArrowRight]);
let horizontal = right as i8 - left as i8;
let vertical = up as i8 - down as i8;
let direction = Vec2::new(horizontal as f32, vertical as f32).clamp_length_max(1.0);
for mut linear_velocity in &mut query {
linear_velocity.0 += 500.0 * delta_secs * direction;
}
}
I would try to reduce your case to something as minimal as possible, and build up from there to locate the problem
Yes
Ah, ok. Another interesting observation, you have a LinearDamping component?
Automatically slows down a dynamic rigid body, decreasing its linear velocity each frame. This can be used to simulate air resistance.
I was doing it with a system....
pub fn apply_movement_damping(
// TODO: This should only apply to players, With<Player>
mut query: Query<&mut LinearVelocity, Without<Sleeping>>,
time: Res<Time<Physics>>,
) {
if time.is_paused() {
return;
}
let damping_factor = 0.75;
for mut linear_velocity in &mut query {
linear_velocity.x *= damping_factor;
if linear_velocity.x.abs() < 0.01 {
linear_velocity.x = 0.0;
}
linear_velocity.y *= damping_factor;
if linear_velocity.y.abs() < 0.01 {
linear_velocity.y = 0.0;
}
}
}
Maybe this could've been my issue.
I'll switch it out
Ok I'm more convinced this is an avian issue now
I swapped out my damping with LinearDamping and it became better, but then I increased the damping and it became slower
It's directly related to LinearDamping
Jon, can you add these components to your example?
RigidBody(|| RigidBody::Dynamic),
LockedAxes(|| LockedAxes::ROTATION_LOCKED),
LinearDamping(|| LinearDamping(3.0)),
TransformInterpolation,
MaxLinearSpeed(|| MaxLinearSpeed(PLAYER_MOVE_SPEED)),
Restitution(|| Restitution::new(0.0).with_combine_rule(CoefficientCombine::Min)),
Collider(||Collider::ellipse(175.0, 50.0)),
What became slower? LinearDamping is meant to slow bodies down
Yeah I mean higher damping values slow down the object more rapidly, so you need a larger movement velocity (or I guess acceleration in this case) if you want to keep walking around at the same rate
But why would LinearDamping only affect TransformInterpolation and not TransformExtrapolation
Do you know if LinearDamping happening on Update or FixedUpdate?
it does definitely affect both for me
Are you running on wasm? I'm runnign on wasm
it's applied in FixedPostUpdate where physics runs by default
the platform shouldn't matter
Here's how slow Interpolation is moving with LinearDamping(3.0)
and here is Extrapolation: (one sec)
Same damping level
It just makes no sense why this would be faster, they both have the same damping
btw my Time resource is set to Duration::from_millis(50) (20Hz)
I'm 99% sure you're accidentally changing the transform manually somewhere if you're getting that stuttering and speedup with extrapolation
I get the same if changing Transform in Update, even just setting it to itself, since it triggers change detection and messes up extrapolation
Otherwise I'm not getting that
The stuttering is because it's 20Hz, so it looks like it's 20FPS. It's actually 60FPS
I see the same stuttering when I run the interpolation example from avian2d
Ok, this is interesting. Because I am adjusting the Z position of the transform, so that would cause an issue?
Yes that would break it
Fuck. Ok I need a solution then
Because I need to adjust the Z
The game is 2.5D, meaning the player's Z-index is adjusted every frame to apply a painter's algorithm (like Zelda or Pokemon)
One sec, I'll confirm if the Z-index change is the issue though.
YEP! That was it
Can you adjust Z in FixedUpdate or some other fixed schedule?
That won't have the same problem
Hmm... That's
Errgggh
Then things may render out of order slightly, because I would only change what order to render items at 20Hz
Not terrible though... I could probably make adjustments in my render pipeline instead
I think if we had Transform2d, with Z ordering handled by a separate component like ZIndex, this problem wouldn't exist 🤔 another reason to split 2D/3D transforms I guess
Is that something you want to do in Avian or Bevy?
I think there is a ZIndex component in Bevy but its documentation points it towards being used by UI, meaning I probably wouldn't re-use it for my world-space items.
People in #math-dev and elsewhere have been wanting first-party 2D transforms for Bevy for a long time (while keeping the 3D GlobalTransform for rendering)
or more generally, support for transform types and customizability other than just the hierarchical 3D Transform
Yeah. I maintain bevy_vello which is how I'm rendering the graphics here; it's vector graphics. I can probably adjust to an architecture that uses an inhouse Transform2d and ZIndex until that lands in bevy. Either way I have the ownership to fix my own issue here.
Thanks again for the help, Jondolf! Awesome library.
Happy to help 😄
I suppose technically we could also fix this issue on the side of bevy_transform_interpolation by allowing interpolation to be enabled for each of the XYZ components separately
So if you disabled interpolation for the Z component of the translation, it'd just leave that untouched
Does physics even use Z in 2d?
Physics doesn't really, but bevy_transform_interpolation (which Avian uses for interpolation) doesn't distinguish between 2D and 3D, it only sees a Transform
Now if there was a Transform2d...
How can I help push for proper Transform2ds? Can I add my use case somewhere to a GitHub issue?
I agree, this should be a thing.
Well there are at least these issues
- https://github.com/bevyengine/bevy/issues/2548
- https://github.com/bevyengine/bevy/issues/1275
There are also some proposals and write-ups that people have done elsewhere, and it has been discussed numerous times here on Discord
In general, I think we have reasonable consensus that it should be a thing, it just needs to be implemented, and some details around e.g. efficiently handling transform hierarchies and mixing different types of transforms need to be nailed down
@bold garnet had some ideas for this IIRC, but I believe they're focused on the Forte thread pool right now
I think Forte was in some way related to transforms too tho ... Everything nth does always seems to be connected
surely ICBINBSN templates are related to transforms too 
Well .... You never know 
Is there a way to translate the collider a bit to the left, so it aligns with the base of my tree?
why not just fix the origin?
That's difficult and requires changing the asset as well as adding whitespace to part of the image to pad it to be centered
Surely Avian lets you change the collider offset... right?
