Can't stop my character to fly around when jumping

Hello !
I'm creating a game as a project for my Bachelor's Degree using the SDL lib and a simple implementation of an ECS I'm also making. The game will be a simple platformer-shooter 2D. I was trying to make my character jump, but he doesn't want to fall to the ground, as long as I keep the jump key pressed, he fly away, and only start falling after I release the key. I don't really understand what I'm doing wrong, I created a boolean "jumping" which change to true whenever the key is pressed, and turn back to false when the character touch the ground, but that didn't solve the problem... Here are my physics function, my rigidbody class, and my key handling for the jumping character :

RigidBody :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma once

#include "ECS.h"
#include "Vec2.h"

//TODO: mettre ça dans PhysicSystem vu que c'est utilisé que là-bas
constexpr float GRAVITY = 9.8f;

struct RigidBody : public IComponent<RigidBody> {
    RigidBody() {}
    RigidBody(Entity e, float _mass = 0.0f, float _gravScale = 0.0f, Vec2 _force = ZEROS, Vec2 _drag = ZEROS, Vec2 _velocity = ZEROS) 
        : IComponent<RigidBody>(e), mass(_mass), gravScale(_gravScale), force(_force), drag(_drag), velocity(_velocity), jumping(false) {}
    ~RigidBody() = default;

    float mass;
    float gravScale;
    Vec2 force;
    Vec2 drag;
    Vec2 velocity;

    bool jumping;
};


PhysicSystem :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#pragma once

#include "ECS.h"
#include "Manager.h"
#include "Transform.h"
#include "RigidBody.h"

struct PhysicSystem : public ISystem {
    PhysicSystem() {
        systemSignature[getComponentTypeID<Transform>()] = true;
        systemSignature[getComponentTypeID<RigidBody>()] = true;
    }

    bool isUpdatable(Signature entitySignature) override {
        bool updatable = true;
        for(int i = 0 ; i < systemSignature.size() ; i++) {
            if(systemSignature[i]) {
                updatable &= systemSignature[i] && entitySignature[i];
            }
        }
        return updatable;
    }

    void update() override {
        SignatureArray& signArr = Manager::get().getSignatureArray();
        for(Entity i = 0 ; i < MAX_ENTITIES ; i++) {
            if(isUpdatable(signArr[i])) {
                Transform& t = Manager::get().getComponent<Transform>(i);
                RigidBody& r = Manager::get().getComponent<RigidBody>(i);

                r.velocity.x = r.force.x - r.drag.x;
                r.velocity.y = r.force.y + r.drag.y + r.gravScale * GRAVITY * r.mass;

                if(r.velocity.y > r.gravScale * GRAVITY * r.mass) {
                    r.velocity.y = r.gravScale * GRAVITY * r.mass; //not sure about that
                }
                
                t.position.x += r.velocity.x;
                t.position.y += r.velocity.y;
            }
        }
    }
};


InputSystem :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#pragma once

#include "ECS.h"
#include "Input.h"
#include "Engine.h"
#include "Transform.h"
#include "RigidBody.h"

struct InputSystem : public ISystem {
    InputSystem() {
        systemSignature[getComponentTypeID<Input>()] = true;
        systemSignature[getComponentTypeID<Transform>()] = true;
        systemSignature[getComponentTypeID<RigidBody>()] = true;
    }

    bool isUpdatable(Signature entitySignature) override {
        bool updatable = true;
        for(int i = 0 ; i < systemSignature.size() ; i++) {
            if(systemSignature[i]) {
                updatable &= (systemSignature[i] && entitySignature[i]);
            }
        }
        return updatable;
    }

    void update() override {
        SignatureArray& signArr = Manager::get().getSignatureArray();
        for(Entity i = 0 ; i < MAX_ENTITIES ; i++) {
            if(isUpdatable(signArr[i])) {
                Input& in = Manager::get().getComponent<Input>(i);
                Transform& t = Manager::get().getComponent<Transform>(i);
                RigidBody& rb = Manager::get().getComponent<RigidBody>(i);

                SDL_Event& ev = in.e;
                while(SDL_PollEvent(&ev)) {
                    switch (ev.type) {
                        case SDL_QUIT:
                            Engine::get().setRunning(false);
                            break;
                        case SDL_KEYDOWN:
                            keyDown(ev.key.keysym.sym, in, t, rb);
                            break;
                        case SDL_KEYUP:
                            keyUp(ev.key.keysym.sym, in, t, rb);
                            break;
                        case SDL_MOUSEBUTTONDOWN:
                            Engine::get().setRunning(false);
                            break;
                        default:
                            break;
                    }
                }
            }
        }
    }

    void keyDown(SDL_Keycode k, Input& in, Transform& tf, RigidBody& rb) {
        if(k == in.moveRight) {
            if(rb.force.x < 10) {
                rb.force.x += 10;
            }
        }
        if(k == in.moveLeft) {
            if(rb.force.x > -10) {
                rb.force.x -= 10;
            }
        }
        if(k == in.moveUp) {
            if(!rb.jumping) {
                if(rb.force.y > -50) {
                    rb.force.y -= 50;
                    rb.jumping = true;
                }
            }
        }
        if(k == in.moveDown) {
            if(rb.force.y < 10) {
                rb.force.y += 10;
            }
        }
        if(k == in.shoot);

        if(k == SDLK_ESCAPE) {
            Engine::get().setRunning(false);
        }
    }

    void keyUp(SDL_Keycode k, Input& in, Transform& tf, RigidBody& rb) {
        if(k == in.moveRight) {
            rb.force.x = 0;
        }
        if(k == in.moveLeft)
            rb.force.x = 0;
        if(k == in.moveUp)
            rb.force.y = 0;
        if(k == in.moveDown)
            rb.force.y = 0;
        if(k == in.shoot);   
    }
};


I hope you can help me with this problem, if you need to see another chunk of code, I can send it ! Thank you in advance !
it looks like you have a state, possibly line 72 in the last chunk, that says you are jumping or not.
you need instead a timer, such that a jump is an event that launches you with an initial velocity at an angle and off you go. Then every time slice, you do the physics with gravity and all, via components and such. It looks like you have most of that in place, except the concept of TIME. Time is very important to this kind of work, and pardon me if its in there and I am just missing it.

consider the highschool based physics formula ** ...
dist = 0.5(gravity*time*time) + initial velocity

**they make you memorize this early on. Later you see that its the derivative and the calc stuff. But when doing this on a computer, you need it in a form you can code, not textbook calc formulas.
Last edited on
Under constant acceleration:
vf = v0 + a * Δt
sf = s0 + v0 *Δt + (1/2) * a * Δt2


s0 is initial position
v0 is initial velocity
a is the acceleration. a = f/m (force divided by mass). For gravity, the force is proportional to mass, so it's g, the acceleration due to gravity.
Δt is the amount of time elapsed.

sf is final position - the position after Δt elapses
vf is the final velocity - the velocity after Δt elapses.

Be sure to pick your coordinates and stick with them. For example, if up is positive, then acceleration from gravity is -9.8m/s2. It's negative because it pulls in the negative direction (down).
So I should simply add a delta time ? How could I manifest that in my code ?

My calculation should change to something like :
1
2
r.velocity.x = r.force.x + r.drag.x * deltatime;
r.velocity.y = r.force.y + r.drag.y + r.gravScale * GRAVITY * r.mass * deltatime * deltatime;

or else ?

I think I didn't really understand what I should change in my calculations... :p
when you jump, get the time.
until you land, apply falling physics to the Y component, using 'now' since start time for current position.
you need a way to know if you are on the ground, so you can allow jumping again (else attempt to jump ignored).
I've done something but it didn't change anything :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//in InputSystem :
if(k == in.moveUp) {
    if(!rb.jumping) {
        if(rb.force.y > -50) {
            rb.force.y -= 50;
            rb.jumping = true;
            rb.jumpStart = SDL_GetTicks(); //jumpStart is an uint32_t taking time in milliseconds
        }
    }
}

//in PhysicSystem :
Uint32 now = 1;
if(r.jumping) {
    now = SDL_GetTicks() - r.jumpStart;
} else {
    r.jumpStart = 0;
}
r.velocity.y = r.force.y + r.drag.y + r.gravScale * GRAVITY * r.mass * now * now;


The part with the ground detector was already in my CollisionSystem (which needs to be upgraded because it's really rustic, but it's good for now).

But even with these changes the problem is the same :p
units matter too :) now do be in integers where 1 == 1ms not 1s
that aside, the missed units should just change the rate of fall, so if it isnt falling, something else is wrong. I don't see the 1/2 part either.
mass isnt important here. 1/2att is the core of it, with adjustments for initial position and initial velocity.
gravity is a force. but you are computing a change in distance.
look. if you start at the top of a 500m tall building at time = 0 and drop a ball, where is it after 1.23 seconds?
d = 4.9 * 1.23 * 1.23 = 7.41... m .. you move the object that much in pixels towards the ground. How many pixels to a meter?
how long does it take to fall, then? sqrt(500/4.9) = 10.10... sec
do you follow that much? The rest is just minor adjustments until you get into aerodynamics and earth rotation and all that mess for advanced ballistics.

there should not be any forces(other than gravity) or masses in your positional calculation. If there is a force on the thing, you need to turn that into a distance as well, eg if you throw a lit bottle rocket up off the top of a building.
Last edited on
Well it does fall, but only when I release the jump key, so I assume that the problem come from my event handler, but I don't see where can it be :p
Although, I think I didn't understand the calculation at all...
 
Velocity = deplacementForce + (1/2)*gravity*deltatime^2

This is it ? I'm sure I missed something :p

I'm sorry that I have so much difficulties to understand, it looks so simple yet I don't understand at all...
did you have high school or college physics at all :)
the first thing they drill into you is that units ... you can't add different units.
your units version of the equation you gave is
speed = force + distance ?!
no can do.
distance = distance + distance is ok.
that is what we were computing, see my example first equation, I get 7 meters. That is what happened. In the time given, the thing fell 7 meters.

so you need
distance = distance. a jump applies a force, an acceleration to a mass, over a time, and moves it some amount. if you jump straight up, gravity pulls you back down, so you go up a little then fall back.
speed is a distance in an amount of time, 5 miles in an hour, like in a car.
so a speed times the amount of time is a distance, like an initial velocity * time. This is show above in the equations Dhayden gave : v0 *Δt
do you have or can you get the initial velocity from what you have available easily?
Last edited on
Simply, there are 3 basic equations:

v = u + at
s = ut + (1/2)a(t^2)
(v^2) = (u^2) + 2as

v = final velocity
u = initial velocity
s = distance moved
a = acceleration (g for gravity)
t = time

If t is seconds
n, v is metres/second
a is metres/second/second
s is metres

With gravity it's important to decide which direction is negative. If upwards is positive then a will be (-g) in the above.

In Physics there is the concept of dimensions. The fundamental ones involved here being mass(M), length(L), time(T). Each element of a formula (such as v = u + at) is expressed in its fundamental dimensions. Then both sides of the formula should match.

So for v = u + at, v is L/T, u is L/T, a is L / (T^2), t is T. So the RHS is
L/T + LT/(T^2) which is L/T + L/T which is of dimension L/T. The LHS is L/T. Both sides are of the same dimensions so the formula is dimensionally correct.
Topic archived. No new replies allowed.