NaaLaa

Full Version: gravity and jump
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi, I have a few more questions.
How can I apply gravity to a character so that it stops when it touches the ground? And how can I make the character jump when I press a key?
Hi, there is a good example from Marcus in the examples folder of n7, which is worth a look in my view:
"examples\games\jumping_on_lines.exe"

Hope this helps - Kevin.
Here's a simpler example than jumping_on_lines, just ask if something is unclear Smile

Code:
' Gravity.

set window "Gravity", 256, 240, false, 3
set redraw off

' Player position.
playerX = 152
playerY = 0
' Size.
playerW = 16
playerH = 24
' Speed.
playerDX = 0
playerDY = 0
playerOnGround = false

' Ground.
groundY = 208

' Game loop, quit with escape key.
while not keydown(KEY_ESCAPE, true)
    ' Increase speed left/right on key left/right or decrease speed if left/right isn't pressed.
    if keydown(KEY_LEFT)        playerDX = max(playerDX - 0.1, -2)
    elseif keydown(KEY_RIGHT)   playerDX = min(playerDX + 0.1, 2)
    elseif playerDX < 0         playerDX = min(playerDX + 0.2, 0)
    elseif playerDX > 0         playerDX = max(playerDX - 0.2, 0)
    
    ' Is player on ground?
    if playerOnGround
        ' Does player want to jump?
        if keydown(KEY_UP, true)
            ' Set players vertical speed to -3 and set playerOnGround to false.
            playerDY = -3
            playerOnGround = false
        endif
    ' Player is in air.
    else
        ' Check if player has hit the ground.
        if playerY + playerH >= groundY
            playerOnGround = true
            playerY = groundY - playerH
            playerDY = 0
        ' Increase vertical speed, this is gravity!
        else
            playerDY = playerDY + 0.1
        endif
    endif
    
    ' Move player.
    playerX = playerX + playerDX
    playerY = playerY + playerDY
    
    ' Draw background.
    set color 0, 0, 0
    cls
    ' Ground.
    set color 192, 128, 0
    draw rect 0, groundY, 320, 8, true
    ' Player.
    set color 255, 200, 0
    draw rect playerX, playerY, playerW, playerH, true
    
    redraw
    fwait 60
wend

Edit: When I write platform games I usually give less "air control" than here, because it's pretty difficult (in reality) to change direction in the air while jumping Big Grin
Here I replace the ground with a list of rectangles. This code is dumb and not optimized. But I do the collision against rectangles in a different (but very clumsy here) way than someone posted in another thread. I prefer not to look at the player's movement to decide where to put him, instead I push the player out of a rectangle in the direction (left, right, up or down) that causes the smallest offset. This would function better when dealing with moving obstacles.

Code:
' Gravity.

' Constants used later to make code more readable.
constant LEFT = 1, RIGHT = 2, UP = 3, DOWN = 4


set window "Gravity", 256, 240, false, 3
set redraw off

' Player position.
playerX = 152
playerY = 0
' Size.
playerW = 16
playerH = 24
' Speed.
playerDX = 0
playerDY = 0
playerOnGround = false

' Obstacles. Each obstacle is represented by an array [x, y, width, height].
obstacles = [
    [0, 0, 8, 240],    ' Left wall.
    [248, 0, 8, 240],  ' Right wall.
    [8, 224, 304, 16],  ' Ground.
    ' Some blocks.
    [100, 180, 32, 16],
    [180, 140, 32, 8],
    [16, 120, 100, 24],
    [64, 60, 128, 8],
    [8,  80, 16, 8]]

' Game loop, quit with escape key.
while not keydown(KEY_ESCAPE, true)
    ' Increase speed left/right on key left/right or decrease speed if left/right isn't pressed.
    if keydown(KEY_LEFT)        playerDX = max(playerDX - 0.1, -2)
    elseif keydown(KEY_RIGHT)  playerDX = min(playerDX + 0.1, 2)
    elseif playerDX < 0        playerDX = min(playerDX + 0.2, 0)
    elseif playerDX > 0        playerDX = max(playerDX - 0.2, 0)
 
    ' Is player on ground?
    if playerOnGround
        ' Wants to jump?
        if keydown(KEY_UP, true)
            ' Set players vertical speed to -4 and set playerOnGround to false.
            playerDY = -3
            playerOnGround = false
        endif
    else
        ' Increase vertical speed, this is gravity!
        playerDY = playerDY + 0.1
    endif
 
    ' Move player.
    playerX = playerX + playerDX
    playerY = playerY + playerDY
 
    ' Check for collision with obstacles.
    playerOnGround = false ' This is only set to true if player stands on something.
    foreach o in obstacles
        ' Do player and obstacle overlap?
        if playerX + playerW > o[0] and playerX < o[0] + o[2] and
                playerY + playerH > o[1] and playerY < o[1] + o[3]
            ' On which side of the obstacle do player and obstacle overlap the LEAST? Start with
            ' left side of obstacle. I'm pretty sure this could be done in a nicer way, but I'm
            ' running on fumes right now :D  Also, lots of stuff above and below could be calculated
            ' ONCE.
            minDir = LEFT
            minDist = |o[0] - (playerX + playerW)|
            ' Right of obstacle?
            dist = |o[0] + o[2] - playerX|
            if dist < minDist
                minDist = dist
                minDir = RIGHT
            endif
            ' Above obstacle?
            dist = |o[1] - (playerY + playerH)|
            if dist < minDist
                minDist = dist
                minDir = UP
            endif
            ' Below obstacle?
            dist = |o[1] + o[3] - playerY|
            if dist < minDist
                minDist = dist
                minDir = DOWN
            endif
            ' Move player to the side of the obstacle that requires the least movement.
            if minDir = LEFT
                playerX = o[0] - playerW
                playerDX = 0
            elseif minDir = RIGHT
                playerX = o[0] + o[2]
                playerDX = 0
            elseif minDir = UP
                ' In this case player is standing on an obstacle, so set playerOnGround to true.
                playerY = o[1] - playerH
                playerDY = 0.05
                playerOnGround = true
            else
                playerY = o[1] + o[3]
                playerDY = 0
            endif
        endif
    next
 
 
    ' Draw background.
    set color 0, 0, 0
    cls
    ' Obstacles.
    set color 192, 128, 0
    foreach o in obstacles  draw rect o[0], o[1], o[2], o[3], true
    ' Player.
    set color 255, 200, 0
    draw rect playerX, playerY, playerW, playerH, true
    ' Some output.
    set color 255, 255, 255
    set caret 16, 2
    if playerOnGround  write "player on ground"
 
    redraw
    fwait 60
wend
(01-27-2026, 05:40 PM)Marcus Wrote: [ -> ]Here's a simpler example than jumping_on_lines, just ask if something is unclear Smile

Code:
' Gravity.

set window "Gravity", 256, 240, false, 3
set redraw off

' Player position.
playerX = 152
playerY = 0
' Size.
playerW = 16
playerH = 24
' Speed.
playerDX = 0
playerDY = 0
playerOnGround = false

' Ground.
groundY = 208

' Game loop, quit with escape key.
while not keydown(KEY_ESCAPE, true)
    ' Increase speed left/right on key left/right or decrease speed if left/right isn't pressed.
    if keydown(KEY_LEFT)        playerDX = max(playerDX - 0.1, -2)
    elseif keydown(KEY_RIGHT)   playerDX = min(playerDX + 0.1, 2)
    elseif playerDX < 0         playerDX = min(playerDX + 0.2, 0)
    elseif playerDX > 0         playerDX = max(playerDX - 0.2, 0)
   
    ' Is player on ground?
    if playerOnGround
        ' Does player want to jump?
        if keydown(KEY_UP, true)
            ' Set players vertical speed to -3 and set playerOnGround to false.
            playerDY = -3
            playerOnGround = false
        endif
    ' Player is in air.
    else
        ' Check if player has hit the ground.
        if playerY + playerH >= groundY
            playerOnGround = true
            playerY = groundY - playerH
            playerDY = 0
        ' Increase vertical speed, this is gravity!
        else
            playerDY = playerDY + 0.1
        endif
    endif
   
    ' Move player.
    playerX = playerX + playerDX
    playerY = playerY + playerDY
   
    ' Draw background.
    set color 0, 0, 0
    cls
    ' Ground.
    set color 192, 128, 0
    draw rect 0, groundY, 320, 8, true
    ' Player.
    set color 255, 200, 0
    draw rect playerX, playerY, playerW, playerH, true
   
    redraw
    fwait 60
wend

Edit:  When I write platform games I usually give less "air control" than here, because it's pretty difficult (in reality) to change direction in the air while jumping Big Grin

Thanks for the example, Marcus. Let's continue working on this example, which is simpler than the second one. For now, I don't want to use lists of objects to avoid complicating the code and to make it easier to understand.

How about showing me a second example, but without using the min and max functions so it's easier to understand? And if possible, use the collision function between rectangles to make the example clearer.

function collision_rect(x1,y1,w1,h1,x2,y2,w2,h2)

return x1 + w1 > x2 and x1 < x2 + w2 and

y1 + h1 > y2 and y1 < y2 + h2
endfunc

Another thing you could add to show how it's done is a solid platform that the player can't cross from anywhere, and another platform that can be crossed from below by jumping up.

In other words, a floor and two platforms, without any lists to make it easier to read.
Okay Smile

But I'm keeping the 'min' and 'max' calls, because they reduce the number of 'if' statements so much. They're very simple to use. 'min' returns the smallest of two values, and 'max' returns the largest. I rewrote the push-one-rect-out-from-another a bit.

Code:
' Gravity.

set window "Gravity", 256, 240, false, 3
set redraw off

' Player position.
playerX = 152
playerY = 0
' Size.
playerW = 16
playerH = 24
' Speed.
playerDX = 0
playerDY = 0
playerOnGround = false

' Ground.
groundY = 208

' Solid obstacle
solidX = 96
solidY = 160
solidW = 64
solidH = 16

' Floor obstacle (only top collision).
floorX = 128
floorY = 112
floorW = 64
floorH = 8

' Game loop, quit with escape key.
while not keydown(KEY_ESCAPE, true)
    ' Increase speed left/right on key left/right or decrease speed if left/right isn't pressed.
    if keydown(KEY_LEFT)        playerDX = max(playerDX - 0.1, -2)
    elseif keydown(KEY_RIGHT)  playerDX = min(playerDX + 0.1, 2)
    elseif playerDX < 0        playerDX = min(playerDX + 0.2, 0)
    elseif playerDX > 0        playerDX = max(playerDX - 0.2, 0)
   
    ' Is player on ground?
    if playerOnGround
        ' Wants to jump?
        if keydown(KEY_UP, true)
            ' Set players vertical speed to -3.5 and set playerOnGround to false.
            playerDY = -3.5
            playerOnGround = false
        else
            playerDY = 0.1
        endif
    else
        ' Increase vertical speed, this is gravity!
        playerDY = playerDY + 0.1
    endif
   
    ' Move player.
    playerX = playerX + playerDX
    playerY = playerY + playerDY
   
    ' Set playerOnGround to false.
    playerOnGround = false
   
    ' Check for collision with ground.
    if playerY + playerH > groundY
        playerY = groundY - playerH
        playerOnGround = true
    endif
   
    ' Check for collision with floor (non-solid obstacle) if player is moving downwards.
    if playerDY > 0 and
            playerY + playerH > floorY and                          ' Feet below floor y?
            playerY + playerH - playerDY <= floorY and              ' Old feet NOT below floor y?
            playerX + playerW > floorX and playerX < floorX + floorW ' Overlap x?
        playerY = floorY - playerH
        playerOnGround = true
    endif
   
    ' Check for collision with solid obstacle.
    if RectsOverlap(playerX, playerY, playerW, playerH, solidX, solidY, solidW, solidH)
        ' On which side of the obstacle do player and obstacle overlap the LEAST?
        overlapL = playerX + playerW - solidX
        overlapR = solidX + solidW - playerX
        overlapT = playerY + playerH - solidY
        overlapB = solidY + solidH - playerY

        minOverlap = min(overlapL, min(overlapR, min(overlapT, overlapB)))

        if minOverlap = overlapL
            playerX = playerX - overlapL
        elseif minOverlap = overlapR
            playerX = playerX + overlapR
        elseif minOverlap = overlapT
            playerY = playerY - overlapT
            if playerDY > 0
                playerOnGround = true
            endif
        else
            playerY = playerY + overlapB
            playerDY = 0
        endif
    endif
   
    ' Draw background.
    set color 0, 0, 0
    cls
    ' Ground.
    set color 192, 128, 0
    draw rect 0, groundY, 320, 8, true
    ' Solid obstacle.
    draw rect solidX, solidY, solidW, solidH, true
    ' Floor obstacle.
    draw rect floorX, floorY, floorW, floorH, false
    ' Player.
    set color 255, 200, 0
    draw rect playerX, playerY, playerW, playerH, true
   
    redraw
    fwait 60
wend

function RectsOverlap(ax, ay, aw, ah, bx, by, bw, bh)
    return ax + aw > bx and ax < bx + bw and ay + ah > by and ay < by + bh
endfunc
Thanks Marcus, now it's time to study it calmly. Smile

I'll continue with other questions in another thread so as not to complicate this one further.

Perhaps it would be a good idea to create a small physics library to facilitate the development of this type of game.