Skip to main content
GameDev.net gamedev.net

Finaly back to coding new features, I have a particle simulation!!!!

Started by TooOld2rock-nRoll Aug 26 at 1:14 PM 8 replies 750+ views
Original Post
TooOld2rock-nRoll
TooOld2rock-nRoll

I just need to share this with people that will understand the struggle hahahha

Damn fuck Jizo on a bicycle! Regretting something in a game engine is sure a heavy burden!

Jumping head first using just C++ was not my best idea, yes inheritance and templates helped a lot at the beginning, but things got so interlocked that every little refactoring was costing me a week of hard work.

I started porting the base layers and dependencies to C23 and I thought I could do it slowly, but nop! Had to spend a few months painstakingly breaking those dependencies and finding alternatives for things like XML parsing and GLM libraries.

And finally, after grueling months, I have pushed to master the first steps of the physics simulation for my engine!

It's just the particle simulation, which is very simple (particles have no volume), but it's there and everything is now moving only by the forces of the universe!!! It is very satisfying and elegant!

If anyone cares to take a look: https://codeberg.org/TooOld2Rock-nRoll/ArcadeFighterDemo/src/branch/master/lib/ArcadeFighter/inc/physics

(source is at the src directory)


By the way, what is the usual way to have a floor line in a fighting platform game???

I have been using an artificial line declared in the level class itself, the update method keeps the players above it, but it seams lazy coding.....

Was thinking it would be better to have an invisible and immovable object that works as the bottom line and stops gravity from taking the players off screen.

Anyway, next thing is adding mass and working on inertia, any pointers on how to implement progressive acceleration? (yes, I can research it, but chatting is much better)

"No, you're never too old to rock and roll
If you're too young to die"
frob
frob

what is the usual way to have a floor line in a fighting platform game?

If the game is physics driven, floors are physics objects, like a mesh, volume, or similar bounding shape. If it is 2D tiles it could be data indicating each tile has a solid top. Both could have additional data attached indicating things like water/puddles, deeper pools with different physics responses, or other effects like fire doing damage over time, sticky / slow areas, slippery areas, or similar.

It could be a parameter to a hard coded floor to the physics if it was specifically built for it rather than a general purpose engine, but it would not be typical.

Anyway, next thing is adding mass and working on inertia, any pointers on how to implement progressive acceleration?

For gravity and falling Newtonian physics boils down to four kinematics equations for that type of motion, allowing continuous results even if you are not perfectly ticking time at exact ideal intervals. Constant acceleration like gravity isn't affected by mass, the one you probably want is initial velocity times elapsed time, plus half the acceleration times time squared.

Alternatively, just apply additional velocity at regular updates and apply the velocity to the position each update. A different approach, gravity volumes allow setting regional values to gravity which can give creative / fun effects like the Super Mario Galaxy series.

Inertia gets more difficult, especially as things move in multiple ways, or are non-uniform when forces are applied. Torque and the mix of both linear and angular momentum are even more math. Hitting the middle of a bat in the center of mass causes different motion than hitting an endpoint making it spin. Something with uneven weight like a bat or wrench, heavy on one side and light on the other, get complicated. If you assume a non-rotating object of uniform density, like a sprite that is always oriented up, you can simplify it.

There are physics engines like ODE that are reasonably understandable.

raynmetal
raynmetal

Congratulations on making progress on your particle simulation!

Anyway, next thing is adding mass and working on inertia, any pointers on how to implement progressive acceleration?

So say you've got some basic Newtonian equations:

  • f = m * a,

  • a = d_v / t

  • v = d_p / t

where

  • f is force

  • m is mass

  • a is acceleration

  • v is velocity

  • p is position

  • t is time

  • d_ stands for delta, standing for a change in some associated quantity

Your game objects store their own current v, p, and m, as well as any external forces acting on them at present f -- this will be a single value, since for a rigid body acceleration only depends on net force.

Every frame, or tick, or iteration, your game loop gives you t. Your basic physics update then looks like:

  1. for each tick, given timestep t:

    1. for each body:

      1. a = m / f

      2. v = v + a * t

      3. p = p + v * t

    2. search for all collisions in your scene. If your particles are circular, and if the distance between their centers is less than the sum of their radii, you have a collision.

    3. resolve your collisions.

Now for point 1.3, you have a couple of options, but they fundamentally rely on conservation of momentum: m_1 * v_1 + m_2 * v_2 = m_1 * v_1' + m_2 + v_2' where left is sum momentum before and right is the sum momentum after the collision.

For each collision pair, you can either:

  1. Compute and apply a separating force on each body involved in the collision, so that the separation occurs on the next simulation step.

  2. Separate the objects immediately by modifying their positions, distributing the total necessary position change (the value representing the overlap b/w the objects) weighted by their inverse masses. You'll also need to modify velocity here, as v = d_p / t for each object.

Approach 1 is what you'll likely find a lot more material on, so it's probably worth going with that, depending on your goals. Rotation, torque, is a little more complicated, but it operates on similar principles. There's nothing for it but to dig in and study.

By the way, what is the usual way to have a floor line in a fighting platform game???

Generally you'd have physics objects like earlier, but whose mass is infinite. You could model these as several joined boxes, or you could have a special polygon collider. You might even attach a constraint to all your physics objects saying "y must always be greater than or equal to 0" or something. Honestly, it depends on what resources you have at hand and what you're trying to achieve.

TooOld2rock-nRoll
TooOld2rock-nRoll

frob wrote:

Alternatively, just apply additional velocity at regular updates and apply the velocity to the position each update. A different approach, gravity volumes allow setting regional values to gravity which can give creative / fun effects like the Super Mario Galaxy series.

Gravity is "easy", it's always there and the first thing I researched when adding vertical movement to the characters. The difference now is that everything is centralized, I don´t have to make the correct calculations on every update method for every character state that requires it.

The logic with delta_t is also very simple, you are always just adding a fraction of whatever you are computing to the target and decreasing from the source.

What I can't find an easy approach is, lets say, one character gets pushed by the other, the force action can be considered atomic, but the character being pushed should "feel" a gradual acceleration (even if very short) for the action to feel realistic to the player. I'm not talking "realistic" as in racing cars realistic, just that little extra attention to game mechanics that helps with immersion.

Yes, an extra "parameter" to the loop that caries what ever force are acting on the obj right now could fix that, but if I consider many forces, it will require a liked list of some kind and I don´t think this is the best way forward. Maybe that is the sensible solution and I have no other option, but still worth the conversation....

raynmetal wrote:

Now for point 1.3, you have a couple of options, but they fundamentally rely on conservation of momentum: m_1 * v_1 + m_2 * v_2 = m_1 * v_1' + m_2 + v_2' where left is sum momentum before and right is the sum momentum after the collision.

Yessss! That is what I'm after! Not just the forces as immediate atomic actions on the objects, generating unrealistic instantaneous velocity.

I'm definitely not implementing volume (this comes next) and rigid body simulation, all objects are ideal particles for this conversation.

What I'm trying to implement right now, is some sort of RPG character builder; The characters will have some base strength and this will be used to calculate how fast it can jump; Or it has some base speed and it will be used to calculate how fast it can walk.

But these actions shouldn't be instantaneous, therefore, the simulation must have some memory of these forces and apply constant acceleration for a period of time.

"No, you're never too old to rock and roll
If you're too young to die"
raynmetal
raynmetal

but if I consider many forces, it will require a liked list of some kind and

You won't need to. Each force is a 2D vector, and each new force acting on the body can just be added to the single net force parameter on your physics object. If your net force earlier was (2, 1), and a new force of (-3, 0) showed up, you would only need to store their sum: (-1, 1) The same principle holds for rotational parameters.

TooOld2rock-nRoll
TooOld2rock-nRoll

@raynmetal just instantaneous force transfer?

Is this how it works in the real world? Not just for perfect spherical chickens in the vacuum?

That makes things easier, lets see how it looks like in the future when we have some hurt boxes in place......

"No, you're never too old to rock and roll
If you're too young to die"
raynmetal
raynmetal

@raynmetal just instantaneous force transfer?

Ah there's no transfer per-se. It's just that you can treat all the forces acting on an object's centre of mass, as a singular force given by the sum of the individual forces, each force represented by a vector. It's a mathematical property you have for objects in this condition (i.e., acting on a rigid body's center of mass).

Things get a little more complicated if there's an offset between where the force is applied, and the center of mass of the object. But luckily, there, you can split the force into its component in the direction towards the center of mass, and the component tangential to it. You can then treat the to-center-of-mass component as in the preceding paragraph. This holds true regardless of how many forces are acting on an object at a particular instant.

The tangential component works on similar principles, but for angular motion.

edit: Here's how I do this in my engine. Forget the specifics of the math, the important part is that ultimately we need only store a single cumulative value per body for the forces gathered in this timestep, even for rotation. Note that I clear all forces after each physics update, so any scripts will need to reapply the force before the update.

void PhysicsState::applyForceGlobal(const glm::vec3& force, const glm::vec3& atPosition, const ObjectBounds& bounds) {
    // no force, nothing to do
    if(force == glm::vec3 { 0.f }) {
        return;
    }

    const glm::vec3 position { bounds.getPositionWorld() };
    const glm::vec3 forceOffset { atPosition - position };

    // calculate force being applied to the center of mass of the object
    const glm::vec3 toCenter { forceOffset != glm::vec3 { 0.f }?
        -glm::normalize(forceOffset) : glm::normalize(force)
    };
    const glm::vec3 centerForce { glm::dot(force, toCenter) * glm::normalize(force) };

    // calculate torque being applied tangentially
    const glm::vec3 axialTorque { forceOffset != glm::vec3 { 0.f }?
        glm::cross(forceOffset, force) : glm::vec3 { 0.f }
    };

    mForce += centerForce;
    mTorque += axialTorque;
}


JoeJ
JoeJ

TooOld2rock-nRoll wrote:

I'm definitely not implementing volume (this comes next) and rigid body simulation, all objects are ideal particles for this conversation.

That's some bad terminology if i can read between the lines, which maybe is worth to fix to prevent confusion:

If you are working in 2D not 3D, 'volume' does not exist, but 'area' does and is the right word.
But neither term has a role in rigid body physics. Instead, think of the density of matter in said volume or area, which gives us the 'mass' we do you use in such simulations.
And there is little need to avoid having mass just to keep things simpler, because involving mass is always easy and allows to control which object is heavier than the other.

If all your objects are 'particles', i assume you mean it's point masses, eventually extruded by a circle to give a collision shape. So they have mass and a radius, but no rotation and moment of inertia.
Such definition is often used in particle based fluid simulation, but it can give rigid bodies too, where 'rigid bodies' could mean characters in a 2D platformer game for example.

Though, if you keep it 2D, notice that handling rotation and moment of inertia is still relatively easy to add as well.
In 3D this angular part is indeed much harder than the linear part, because moment of inertia is not a scalar and depends on 3D axis of rotation. But in 2D inertia is scalar, and thus just as easy to model as mass.
I'd say keep this in mind in case you want to add inertia later.
The behavior you get is, thinking of two rectangles, one is sized 3x3 and the other is 1x9. Both would have the same mass (because their area is 9 for both and i assume equal density), but the 1x9 rectangle would be harder to rotate than the 3x3 one. (It depends on the game if having such behavior is needed or not.)

Anyway. It sounds you want to keep it simple. And maybe i can help with a proposal:
Avoid dynamic objects having a convex polygon as collision shape, as rigid body simulators usually do.
Calculating the intersections and collision responses using polygons is difficult and computationally expensive.
Instead, model your dynamic objects from spheres and '2D-capsules', which is fine for characters.
Idk the proper term for a capsule in 2D, but to make it you could join two particles with a fixed distance constraint, where the line between the particles also becomes a collision primitive. And if both particles and the line have the same radius, we get this capsule shape:

(should be upright for a character ofc.)

This approach has some hidden advantage: The effect of inertia is simulated without actually coding it explicitly. It is modeled by having two particles joint by the distance constraint.

There is a related paper which discusses this approach in more detail, as used for ragdolls in the very first Hitman game:
https://www.cs.cmu.edu/afs/cs/academic/class/15462-s13/www/lec_slides/Jakobsen.pdf

It also proposes an alternative to standard Euler integration (as explained by raynmetal), called Verlet integration.
Instead of having velocity and acceleration you just take the difference from the current to the previous positions and assume things to tend travelling the same path in the next frame. Which is a bit easier to understand than Euler.
However, the choice of integration method is independent from the choice of how to model your objects.

I remember when i was young, rigid body simulation did just came up, and i wanted to have this too.
I found some tutorials and got it working for collision detection and collision response.
But ugh, this was lots of code. Too difficult and complicated. Jakobsens Paper helped me out. Adopting it i could progress much faster. In the end i got stable stacks of capsules with friction, e.g. to build Jenga towers. I also had angular constraints to make detailed ragdolls, but their joints were not stiff enough. They were too squishy to keep a pose under some stress. So i gave up and used Havok instead, which became somewhat free at the time.
Still, i think the paper was perfect to learn simulation basics, so i keep recommending it.

Though, notice all i've said so far is still about modeling real world physics and complex interaction of many bodies. Where each body is dynamic and may affect each other body. That's always a hard problem to solve, no matter if you affect the future with forces, or if you apply corrections to the positions of the current frame. If you don't want to spend a lot of time on reinventing wheels, consider using a library such as Box2D.

But there also is another way around that problem, which i would call 'fake physics' maybe, as seen in games like Super Mario. In Super Mario i can build a stack of boxes on a moving platform. I can do anything i could do in Half Life 2, and it all works without any solver.
I imagine it somehow works like this: When I put a box on the moving platform, it becomes parented by the platform. When i put a second box on the first box, it becomes parented by the first box and so on. This way the movement of the platform propagates to the entire stack of boxes so they move along. There is no need to solve for contact forces from gravity either, instead we only prevent interpenetration with the parent object. Or something like that.
Ofc. such approach has its failure cases, but it enables a lot of mechanics and is predictable to players even it's not realistic, since the logic is usually common sense.
Personally i would not call this 'simulation', but i also don't know any proper search term about this topic.

Still, i hope those topics help you to figure out what you actually want to prevent some trial and error.

frob wrote:

Constant acceleration like gravity isn't affected by mass, the one you probably want is initial velocity times elapsed time, plus half the acceleration times time squared.

This can be initially confusing i remember. I would use the math you describe to predict the trajectory of a projectile under gravity for example, but i would not use it to calculate the next frames position of the projectile itself, where i would use integration like Euler or Verlet. The reason is: The projectile may collide with something along its way, or it may be affected by other external forces like changing wind, etc. So we can rarely use those precise analytical methods which assume a constant external force like gravity.
So it's good to know about both those methods, but keep them separated and don't confuse them with each other.
I still have this code snippet showing both options side by side, which may help on this detail:

float p = start; // start is initial position
	float v = 0; // initial velocity is zero for the example
	float a = -5.0f; // constant acceleration, e.g. gravity
	for (float t = 0; t <= 2; t += timestep) 
	{
// integrate over the previous state, like physics engines do, accepting some integration error
		v += a * timestep;
		p += v * timestep;
// analytical solution to get the precise position at any time, useful e.g. to predict the future
		float pA = start + 0.5f * a * t*t;
		float vA = a * t;
	}

If we graph p and pA, both would show the same trajectory of a parabola.

TooOld2rock-nRoll
TooOld2rock-nRoll

Thank you both for the input, it will definitely be useful o/

@JoeJ you inadvertently caught a conflict in my strategy.

I'm trying to make everything 2.5D friendly and keeping a foot in 3D if I care to expand later.

So everything is vec3 (position, size, etc), therefore I always think in volume.

To be honest, I really don't know how far I want to take this feature, just aabb tests and simple hit/no hit scenarios may well be enough and the user can add to the complexity in their own games, if desired.

I usually start things not by researching game mechanics, in this case I went for: https://en.wikipedia.org/wiki/Particle

(and down the rabbit hole we go :D)

@raynmetal The physics classes are slowly coming back to mind, I believe I'm making some confusion regarding friction and air resistance.

Forces act on bodies just for the time they exist, once the influence is removed, the action is also removed and inertia will keep it moving until (in real world) external forces make it stop.

What we are simplifying is that, something like a punch, for instance, happens instantaneous and the bodies are perfectly elastic.

And that is all very cool, but I REALLY don't want to simulate air drag for a jump kick and how much rubber there is on a fighter's shoes hahahahha

So all your math makes a lot more sense for a simple project like mine.

"No, you're never too old to rock and roll
If you're too young to die"
Sign in to reply to this topic.