jumpy
                                
                                
                                
                                    jumpy copied to clipboard
                            
                            
                            
                        Corpse physics (faux-ragdoll)
Upon death, a character should turn into a limp rag doll. So instead of playing a full death animation, player death results in death-face combined with a ragdoll-drop in whichever direction the player character got pushed by a killing force.
This also has implications on our art assets. We’ll want our character assets divided up into a few different body parts that can flail around with the rag doll system.
Some deaths however have special outcomes (new issue coming). E.g. getting killed by curse has its own special animation & effects.
On manually activated rag doll: While this is a fun thing to play around with for advanced players, it doesn’t bring a whole lot to the core game experience. It’s also much harder to avoid all sorts of bugs/exploits if the rag doll state can be manually activated.
This is not very easy to implement, if we want to keep the pixel art aesthetics. We would have to animate the ragdoll effects by hand, making it predetermined and, in essence, not ragdoll physics... Personally, I'd vote for some cool explosions or something similar, for death animations
Rag-doll is already a thing in DG, which seems to have found a pixel-friendly solution. It may well still be a complicated thing to do, but at least there’s promising prior art out there.
Haven't seen how duck game does it but I'll check it out. Making skeletal animations with pixel art introduces all kinds of problems with the graphics, as can be seen, to some extent, when we rotate weapons (sub-pixels, aliasing etc)
From what I can see, they just apply physics to the corpse sprites, without rag-doll physics (ie. no flailing limbs, etc.). This is not difficult to implement. Just add linear and angular momentum to the corpse. I can make a PR for this
Aha, so I was just using the rag-doll term a bit too broadly. Renamed to the rather grim “Corpse physics” 😬💀
As was discussed on discord, Duck Game actually utilizes skeletal pixel animations. They seem, to me, to rely, firstly, on rotations in 90 deg steps, which mitigates the problems mentioned above, as well as procedural redraws of sprites, to mitigate the need for "rotated pixels" and other problems connected with rotational translation of low resolution bitmaps.
I asked @TheFlyingFoool from DGR how this works in Duck Game.
the ragdoll in DG is composed of 3 parts, the upper part the bottom part, and the joint and all of them are in the update order as physics objects, separately, but still refreneced from the main ragdoll class also neat thing to note the order in which things do physics or updates for things inside of a level are not always in the same order as the game uses a hash map to store things and doesnt keep order in mind
 public virtual void Solve(PhysicsObject body1, PhysicsObject body2, float dist)
 {
     float allowedDistance = dist;
     Vec2 axis = body2.position - body1.position;
     float currentDistance = axis.length;
     if (currentDistance < 0.0001f)
         currentDistance = 0.0001f;
     Vec2 unitAxis = axis * (1 / currentDistance);
     Vec2 vel1 = new Vec2(body1.hSpeed, body1.vSpeed);
     Vec2 vel2 = new Vec2(body2.hSpeed, body2.vSpeed);
     float relVel = Vec2.Dot(vel2 - vel1, unitAxis);
     float relDist = currentDistance - allowedDistance;
     float invMass1 = 2.1f;
     float invMass2 = 2.1f;
     if (body1 == part1 && jetting)
         invMass1 = 6.0f;
     else if (body2 == part1 && jetting)
         invMass2 = 6.0f;
     float remove = relVel + relDist;
     float impulse = remove / (invMass1 + invMass2);
     Vec2 impulseVector = unitAxis * impulse;
     vel1 += (impulseVector * invMass1);
     vel2 -= (impulseVector * invMass2);
     if (body1.owner == null)
     {
         body1.hSpeed = vel1.x;
         body1.vSpeed = vel1.y;
     }
     if (body2.owner == null)
     {
         body2.hSpeed = vel2.x;
         body2.vSpeed = vel2.y;
     }
 }
                                    
                                    
                                    
                                
We now have a "ragdoll" in the sense player is a dynamic body in rapier, but no joints on body or limbs, just a sprite change and single body.
Experimenting if we want to move this forward into a real ragdoll, and what that means for us will be the next steps. Rapier has support for bodies with joints, can use their constructs for the physics side of this. The meat of the work is implementing a proof of concept for what we might want joints to be, and seeing what our options are in terms of splitting sprites.
Duck Game has lower resolution / simpler assets than we do, so will have to see how things look with what we have. Best way to figure out if it works or not or path forward is probably to just prototype it.
I'm happy to take this work when we decide it's our next priority, but if anyone wants to dig into this I'm also very happy to support with figuring out the rapier bits, point towards their API / where stuff may need to be hooked up in our code and discuss things we can try in more detail.