NaaLaa

Full Version: collision with walls
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hello, how are you doing. I would like to know how it can be done so that a character when colliding with walls, either vertically or horizontally, cannot go through those walls. I would like to know if there are different methods from easier to more difficult.
here is the code for the Level 1 (AABB) method.
made by ZAI

Code:
REM --- COLLISION DEMO ---
REM Assumes a standard BASIC interpreter (QBASIC/FreeBASIC style)

REM -- VARIABLES --
REM Player
PX = 50 : PY = 50  ' Position X and Y
PS = 20            ' Player Size (Width and Height)
VX = 0 : VY = 0    ' Velocity X and Y
SPEED = 2          ' Movement Speed

REM Wall
WX = 150 : WY = 50  ' Wall Position X and Y
WW = 20  : WH = 100 ' Wall Width and Height

REM -- MAIN LOOP --
DO
   
    REM 1. HANDLE INPUT
    REM Reset Velocity
    VX = 0 : VY = 0
   
    REM Check Keys (Change KEY/INKEY$ based on your specific interpreter)
    IF KEYDOWN(203) THEN VX = -SPEED  ' Left Arrow
    IF KEYDOWN(205) THEN VX = SPEED  ' Right Arrow
    IF KEYDOWN(200) THEN VY = -SPEED  ' Up Arrow
    IF KEYDOWN(208) THEN VY = SPEED  ' Down Arrow


    REM 2. MOVE HORIZONTALLY (X)
    PX = PX + VX

    REM Check for Wall Collision on X Axis
    REM (Right Side > Wall Left) AND (Left Side < Wall Right) AND ...
    IF (PX + PS > WX) AND (PX < WX + WW) AND (PY + PS > WY) AND (PY < WY + WH) THEN
       
        REM Collision Detected! Undo movement.
        REM We move the player exactly to the wall's edge.
       
        IF VX > 0 THEN
            REM Moving Right: Snap player to the left side of the wall
            PX = WX - PS
        ELSE
            REM Moving Left: Snap player to the right side of the wall
            PX = WX + WW
        END IF
       
        REM Stop horizontal movement
        VX = 0
    END IF


    REM 3. MOVE VERTICALLY (Y)
    PY = PY + VY

    REM Check for Wall Collision on Y Axis
    IF (PX + PS > WX) AND (PX < WX + WW) AND (PY + PS > WY) AND (PY < WY + WH) THEN
       
        REM Collision Detected! Undo movement.
       
        IF VY > 0 THEN
            REM Moving Down: Snap player to the top of the wall
            PY = WY - PS
        ELSE
            REM Moving Up: Snap player to the bottom of the wall
            PY = WY + WH
        END IF
       
        REM Stop vertical movement
        VY = 0
    END IF


    REM 4. DRAWING (Basic text output)
    CLS
    PRINT "Player Pos: "; PX; ","; PY
    PRINT "Wall Pos  : "; WX; ","; WY
   
    REM Draw simple boxes (Syntax varies by interpreter)
    REM BOX PX, PY, PX+PS, PY+PS, 5  ' Example player (Green)
    REM BOX WX, WY, WX+WW, WY+WH, 4  ' Example wall (Red)
   
    REM Wait a frame (Adjust for your CPU speed)
    SLEEP 50
   
LOOP UNTIL KEYDOWN(1) ' Exit on ESC key

here is FreeBasic fbgfx code

Code:
' Include the graphics library to access MultiKey and Scancodes
#include "fbgfx.bi"

' --- Constants ---
Const SCREEN_W = 640
Const SCREEN_H = 480
Const SPEED = 4

' --- Types ---
Type Rect
    x As Integer
    y As Integer
    w As Integer
    h As Integer
End Type

' --- Variables ---
Dim Shared player As Rect
Dim Shared wall As Rect

Dim As Integer vx, vy ' Velocity X and Y

' --- Initialization ---
' Set Player position and size
player.x = 50
player.y = 50
player.w = 30
player.h = 30

' Set Wall position and size (Block in the middle)
wall.x = 300
wall.y = 100
wall.w = 40
wall.h = 280

' Set graphics mode (640x480, 32-bit color)
ScreenRes SCREEN_W, SCREEN_H, 32
WindowTitle "FreeBASIC Collision Demo"

' --- Main Game Loop ---
Do
   
    ' 1. Handle Input (Using MultiKey for smooth movement)
    vx = 0
    vy = 0
   
    If MultiKey(FB.SC_RIGHT) Then vx =  SPEED
    If MultiKey(FB.SC_LEFT)  Then vx = -SPEED
    If MultiKey(FB.SC_DOWN)  Then vy =  SPEED
    If MultiKey(FB.SC_UP)    Then vy = -SPEED
   
   
    ' 2. Move HORIZONTALLY (X)
    player.x += vx
   
    ' Check for Collision with Wall
    ' AABB Logic: (Right > Left) AND (Left < Right) AND ...
    If (player.x + player.w > wall.x) And (player.x < wall.x + wall.w) And _
       (player.y + player.h > wall.y) And (player.y < wall.y + wall.h) Then
       
        ' Collision Detected! Resolve X.
        If vx > 0 Then
            ' Moving Right: Snap player to left side of wall
            player.x = wall.x - player.w
        ElseIf vx < 0 Then
            ' Moving Left: Snap player to right side of wall
            player.x = wall.x + wall.w
        End If
    End If
   
   
    ' 3. Move VERTICALLY (Y)
    player.y += vy
   
    ' Check for Collision with Wall again (after X move)
    If (player.x + player.w > wall.x) And (player.x < wall.x + wall.w) And _
       (player.y + player.h > wall.y) And (player.y < wall.y + wall.h) Then
       
        ' Collision Detected! Resolve Y.
        If vy > 0 Then
            ' Moving Down: Snap player to top of wall
            player.y = wall.y - player.h
        ElseIf vy < 0 Then
            ' Moving Up: Snap player to bottom of wall
            player.y = wall.y + wall.h
        End If
    End If
   
   
    ' 4. Drawing
    Cls ' Clear Screen
   
    ' Draw Wall (Gray)
    Line (wall.x, wall.y) - (wall.x + wall.w, wall.y + wall.h), RGB(150, 150, 150), BF
   
    ' Draw Player (Red)
    Line (player.x, player.y) - (player.x + player.w, player.y + player.h), RGB(255, 50, 50), BF
   
    ' Draw Instructions
    Draw String (10, 10), "Arrow Keys to Move. ESC to Quit."
   
    ' Limit framerate and allow OS events
    Sleep 1, 1
   
    ' Exit if Escape is pressed
Loop Until MultiKey(FB.SC_ESCAPE)
Hey Aurel,

I had a few minutes to spare... Here is your example coded for Naalaa 7. Very little of your original program needed to be changed. Screen settings. Text positioning. Drawing commands. Deliberately "filled" the "player" to show the difference.

Code:
set window "AABB", 320, 240, false, 2
set redraw off

' --- COLLISION DEMO ---
' Assumes a standard BASIC interpreter (QBASIC/FreeBASIC style)

' -- VARIABLES --
' Player
PX = 50 ; PY = 50  ' Position X and Y
PS = 20            ' Player Size (Width and Height)
VX = 0 ; VY = 0    ' Velocity X and Y
SPEED = 2          ' Movement Speed

' Wall
WX = 150 ; WY = 50  ' Wall Position X and Y
WW = 20  ; WH = 100 ' Wall Width and Height

' -- MAIN LOOP --
do
   
    ' 1. HANDLE INPUT
    ' Reset Velocity
    VX = 0 ; VY = 0
   
    ' Check Keys (Change KEY/INKEY$ based on your specific interpreter)
    if keydown(KEY_LEFT)    VX = -SPEED  ' Left Arrow
    if keydown(KEY_RIGHT)   VX = SPEED  ' Right Arrow
    if keydown(KEY_UP)      VY = -SPEED  ' Up Arrow
    if keydown(KEY_DOWN)    VY = SPEED  ' Down Arrow


    ' 2. MOVE HORIZONTALLY (X)
    PX = PX + VX

    ' Check for Wall Collision on X Axis
    ' (Right Side > Wall Left) AND (Left Side < Wall Right) AND ...
    if (PX + PS > WX) and (PX < WX + WW) and (PY + PS > WY) and (PY < WY + WH)
       
        ' Collision Detected! Undo movement.
        ' We move the player exactly to the wall's edge.
       
        if VX > 0
            ' Moving Right: Snap player to the left side of the wall
            PX = WX - PS
        else
            ' Moving Left: Snap player to the right side of the wall
            PX = WX + WW
        endif
       
        ' Stop horizontal movement
        VX = 0
    endif


    ' 3. MOVE VERTICALLY (Y)
    PY = PY + VY

    ' Check for Wall Collision on Y Axis
    if (PX + PS > WX) and (PX < WX + WW) and (PY + PS > WY) and (PY < WY + WH)
       
        ' Collision Detected! Undo movement.
       
        if VY > 0
            ' Moving Down: Snap player to the top of the wall
            PY = WY - PS
        else
            ' Moving Up: Snap player to the bottom of the wall
            PY = WY + WH
        endif
       
        ' Stop vertical movement
        VY = 0
    endif


    ' 4. DRAWING (Basic text output)
    set color 0, 0, 0 ; cls
    set color 255, 255, 255
    set caret 0, 0; wln "Player Pos: " + str(PX) + "," + str(PY)
    set caret 0, 20; wln "Wall Pos  : " + str(WX) + "," + str(WY)
   
    ' Draw simple boxes (Syntax varies by interpreter)
    set color 0, 255, 0 ; draw rect PX, PY, PS, PS, true  ' Example player (Green)
    set color 255, 0, 0 ; draw rect WX, WY, WW, WH, false  ' Example wall (Red)
   
    ' Wait a frame (Adjust for your CPU speed)
    redraw
   fwait 60
until keydown(KEY_ESCAPE, true) ' Exit on ESC key

I deleted my previous post as I had mistakenly inserted the code as "PHP"... Left's try this dance again, shall we?  LOL

I hope this helps...

J

[attachment=567]
hi john
i try with naalaa translation but zai don0t know it
The simplest way is probably used by games like bomberman and sokoban, where you can only move one tile at a time. Here's an example, press esc to switch to smooth movement:

Code:
' Walls for something like bomberman or sokoban.

set window "Walls 1", 256, 240, false, 3
set redraw off

' Level map[y][x], 0 = nothing, 1 = obstacle, 2 = player start.
map = [
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],
    [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1],
    [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1],
    [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
    [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 1],
    [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
    [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
    [1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1],
    [1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1],
    [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]

' Width and height of map.
mapHeight = sizeof(map)
mapWidth = sizeof(map[0])
           
' Find player starting position.
playerX = unset
playerY = unset
for y = 0 to mapHeight - 1
    for x = 0 to mapWidth - 1
        if map[y][x] = 2
            playerY = y
            playerX = x
            map[y][x] = 0
            break
        endif
    next
next
' 'assert' stops the program with an runtime error if the first parameter is not true.
assert typeof(playerX), "Player not found in map!"

' Game loop without player movement animation.
moveDelay = 0
while not keydown(KEY_ESCAPE, true)
    ' Only let player move if moveDelay is 0.
    moveDelay = max(moveDelay - 1, 0)
    if moveDelay = 0
        dx = 0
        dy = 0
        ' Check for arrow keys and level bounds.
        if keydown(KEY_LEFT) and playerX > 0                    dx = -1
        elseif keydown(KEY_RIGHT) and playerX < mapWidth - 1    dx = 1
        elseif keydown(KEY_UP) and playerY > 0                  dy = -1
        elseif keydown(KEY_DOWN) and playerY < mapHeight - 1    dy = 1
        ' Can player move to that location, or is it occupied?
        if (dx or dy) and map[playerY + dy][playerX + dx] = 0
            playerX = playerX + dx
            playerY = playerY + dy
            moveDelay = 15
        endif
    endif
   
    ' Draw map.
    set color 0, 0, 0
    cls
    set color 128, 96, 32
    for y = 0 to mapHeight - 1
        for x = 0 to mapWidth - 1
            if map[y][x] = 1
                draw rect x*16, y*16, 16, 16, true
            endif
        next
    next

    ' Draw player.
    set color 16, 255, 32
    draw rect playerX*16, playerY*16, 16, 16, true
   
    ' Instructions.
    set color 255, 255, 255
    set caret width(primary)/2, 2
    center "Move with arrow keys"
    center "Press escape to continue"
   
    redraw
    fwait 60
wend

' Game loop with player movement animation.

' Use screen coordinates for player now.
playerX = playerX*16
playerY = playerY*16
' Player movement.
playerDX = 0
playerDY = 0
playerSteps = 0
while not keydown(KEY_ESCAPE, true)
    ' Only let player start new move if not already moving.
    if playerSteps = 0
        dx = 0
        dy = 0
        ' Check for arrow keys and level bounds.
        mapX = playerX/16
        mapY = playerY/16
        if keydown(KEY_LEFT) and mapX > 0                  dx = -1
        elseif keydown(KEY_RIGHT) and mapX < mapWidth - 1  dx = 1
        elseif keydown(KEY_UP) and mapY > 0                dy = -1
        elseif keydown(KEY_DOWN) and mapY < mapHeight - 1  dy = 1
        ' Can player move to that location, or is it occupied?
        if (dx or dy) and map[mapY + dy][mapX + dx] = 0
            ' Set direction and a counter for 16 steps.
            playerDX = dx
            playerDY = dy
            playerSteps = 16
        endif
    ' Move player.
    else
        playerSteps = playerSteps - 1
        playerX = playerX + playerDX
        playerY = playerY + playerDY
    endif
   
    ' Draw map.
    set color 0, 0, 0
    cls
    set color 32, 96, 192
    for y = 0 to mapHeight - 1
        for x = 0 to mapWidth - 1
            if map[y][x] = 1
                draw rect x*16, y*16, 16, 16, true
            endif
        next
    next

    ' Draw player.
    set color 16, 255, 32
    draw rect playerX, playerY, 16, 16, true
   
    ' Instructions.
    set color 255, 255, 255
    set caret width(primary)/2, 2
    center "Move with arrow keys"
    center "Press escape to exit"
   
    redraw
    fwait 60
wend
Yes John
Your translation of ZAI  FBasic program work
better in naalaa7 than original in FreeBasic Rolleyes

I will ask Z.ai to analyze n7 code

Hey Johnno

Look what z.ai says about your code

This code looks like a solid implementation of Axis-Aligned
Bounding Box (AABB) collision detection,
written For the Naalaa language (based on the set window,
set caret, wln, And fwait commands).

It uses the recommended Separating Axis
approach: moving X, checking collision, resolving it,
And then moving Y And checking again. This prevents the player from getting
stuck in corners.

Here is the code cleaned up with proper comments
And formatting For Naalaa, along with two improvements:
screen boundary checks (so the player doesn't leave the window) and
a fix to ensure the player stays above the text

So ... Z.ai knows that this code is written in NaaLaa
Confused
Thank you all so much for your help, all the examples work very well. Smile

(01-26-2026, 05:24 PM)Marcus Wrote: [ -> ]The simplest way is probably used by games like bomberman and sokoban, where you can only move one tile at a time. Here's an example, press esc to switch to smooth movement:

Code:
' Walls for something like bomberman or sokoban.

set window "Walls 1", 256, 240, false, 3
set redraw off

' Level map[y][x], 0 = nothing, 1 = obstacle, 2 = player start.
map = [
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],
    [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1],
    [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1],
    [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
    [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 1],
    [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1],
    [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
    [1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1],
    [1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1],
    [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]

' Width and height of map.
mapHeight = sizeof(map)
mapWidth = sizeof(map[0])
           
' Find player starting position.
playerX = unset
playerY = unset
for y = 0 to mapHeight - 1
    for x = 0 to mapWidth - 1
        if map[y][x] = 2
            playerY = y
            playerX = x
            map[y][x] = 0
            break
        endif
    next
next
' 'assert' stops the program with an runtime error if the first parameter is not true.
assert typeof(playerX), "Player not found in map!"

' Game loop without player movement animation.
moveDelay = 0
while not keydown(KEY_ESCAPE, true)
    ' Only let player move if moveDelay is 0.
    moveDelay = max(moveDelay - 1, 0)
    if moveDelay = 0
        dx = 0
        dy = 0
        ' Check for arrow keys and level bounds.
        if keydown(KEY_LEFT) and playerX > 0                    dx = -1
        elseif keydown(KEY_RIGHT) and playerX < mapWidth - 1    dx = 1
        elseif keydown(KEY_UP) and playerY > 0                  dy = -1
        elseif keydown(KEY_DOWN) and playerY < mapHeight - 1    dy = 1
        ' Can player move to that location, or is it occupied?
        if (dx or dy) and map[playerY + dy][playerX + dx] = 0
            playerX = playerX + dx
            playerY = playerY + dy
            moveDelay = 15
        endif
    endif
   
    ' Draw map.
    set color 0, 0, 0
    cls
    set color 128, 96, 32
    for y = 0 to mapHeight - 1
        for x = 0 to mapWidth - 1
            if map[y][x] = 1
                draw rect x*16, y*16, 16, 16, true
            endif
        next
    next

    ' Draw player.
    set color 16, 255, 32
    draw rect playerX*16, playerY*16, 16, 16, true
   
    ' Instructions.
    set color 255, 255, 255
    set caret width(primary)/2, 2
    center "Move with arrow keys"
    center "Press escape to continue"
   
    redraw
    fwait 60
wend

' Game loop with player movement animation.

' Use screen coordinates for player now.
playerX = playerX*16
playerY = playerY*16
' Player movement.
playerDX = 0
playerDY = 0
playerSteps = 0
while not keydown(KEY_ESCAPE, true)
    ' Only let player start new move if not already moving.
    if playerSteps = 0
        dx = 0
        dy = 0
        ' Check for arrow keys and level bounds.
        mapX = playerX/16
        mapY = playerY/16
        if keydown(KEY_LEFT) and mapX > 0                  dx = -1
        elseif keydown(KEY_RIGHT) and mapX < mapWidth - 1  dx = 1
        elseif keydown(KEY_UP) and mapY > 0                dy = -1
        elseif keydown(KEY_DOWN) and mapY < mapHeight - 1  dy = 1
        ' Can player move to that location, or is it occupied?
        if (dx or dy) and map[mapY + dy][mapX + dx] = 0
            ' Set direction and a counter for 16 steps.
            playerDX = dx
            playerDY = dy
            playerSteps = 16
        endif
    ' Move player.
    else
        playerSteps = playerSteps - 1
        playerX = playerX + playerDX
        playerY = playerY + playerDY
    endif
   
    ' Draw map.
    set color 0, 0, 0
    cls
    set color 32, 96, 192
    for y = 0 to mapHeight - 1
        for x = 0 to mapWidth - 1
            if map[y][x] = 1
                draw rect x*16, y*16, 16, 16, true
            endif
        next
    next

    ' Draw player.
    set color 16, 255, 32
    draw rect playerX, playerY, 16, 16, true
   
    ' Instructions.
    set color 255, 255, 255
    set caret width(primary)/2, 2
    center "Move with arrow keys"
    center "Press escape to exit"
   
    redraw
    fwait 60
wend

The example is confusing me; I don't understand where you're stopping the player when they collide with the walls. I've noticed that when you're pressing left or right and then up or down while colliding with a wall, the player stops and doesn't slide.

Aurel's example does work when pressing up and right upon colliding with a wall; in that case, the player does slide. This example is easier to understand because it clearly shows where the collision and stopping occurs.

I always have the same problem, even though I've been programming for a long time; if there's a lot of code, I get lost.
well i think that map array is good for levels
so if cell is 1 then object of wall is present there
if is 0 then is not ...seems fine
but confusing to me too arghhh