' Sprite engine with movement and collision detection
#COMPILE EXE
#DIM ALL

CONST SCREEN_W = 640
CONST SCREEN_H = 480
TYPE Sprite
    x AS LONG
    y AS LONG
    w AS LONG
    h AS LONG
    vx AS LONG
    vy AS LONG
    active AS LONG
    kind AS LONG
END TYPE

SUB InitSprite(BYREF s AS Sprite, BYVAL kind AS LONG, BYVAL x AS LONG, BYVAL y AS LONG, BYVAL w AS LONG, BYVAL h AS LONG)
    s.kind = kind
    s.x = x
    s.y = y
    s.w = w
    s.h = h
    s.vx = 0
    s.vy = 0
    s.active = 1
END SUB

SUB MoveSprite(BYREF s AS Sprite)
    s.x = s.x + s.vx
    s.y = s.y + s.vy
    IF s.x < 0 THEN s.x = 0: s.vx = -s.vx
    IF s.x + s.w > SCREEN_W THEN s.x = SCREEN_W - s.w: s.vx = -s.vx
    IF s.y < 0 THEN s.y = 0: s.vy = -s.vy
    IF s.y + s.h > SCREEN_H THEN s.y = SCREEN_H - s.h: s.vy = -s.vy
END SUB

FUNCTION CheckOverlap(BYVAL ax AS LONG, BYVAL ay AS LONG, BYVAL aw AS LONG, BYVAL ah AS LONG, BYVAL bx AS LONG, BYVAL by AS LONG, BYVAL bw AS LONG, BYVAL bh AS LONG) AS LONG
    IF ax + aw < bx THEN FUNCTION = 0
    IF ay + ah < by THEN FUNCTION = 0
    IF bx + bw < ax THEN FUNCTION = 0
    IF by + bh < ay THEN FUNCTION = 0
    FUNCTION = 1
END FUNCTION

SUB BounceSprites(BYREF a AS Sprite, BYREF b AS Sprite)
    LOCAL tx AS LONG
    tx = a.vx: a.vx = b.vx: b.vx = tx
    tx = a.vy: a.vy = b.vy: b.vy = tx
    PRINT "  BOUNCE!"
END SUB

SUB PrintSprite(BYREF s AS Sprite)
    PRINT "  kind="; s.kind; " pos=("; s.x; ","; s.y; ")"
    PRINT "  size="; s.w; "x"; s.h; " vel=("; s.vx; ","; s.vy; ")"
END SUB

FUNCTION RunSimulation() AS LONG
    DIM sx(4) AS LONG
    DIM sy(4) AS LONG
    DIM sw(4) AS LONG
    DIM sh(4) AS LONG
    DIM svx(4) AS LONG
    DIM svy(4) AS LONG
    DIM sact(4) AS LONG
    DIM skind(4) AS LONG
    LOCAL i  AS LONG
    LOCAL j  AS LONG
    LOCAL t  AS LONG
    FOR i = 0 TO 4
        sx(i) = 10 + i * 100
        sy(i) = 10 + i * 50
        sw(i) = 32 + i * 8
        sh(i) = 32 + i * 4
        svx(i) = 5 - i
        svy(i) = 3 + i
        sact(i) = 1
        skind(i) = i MOD 3
    NEXT i
    PRINT "Initial sprites:"
    FOR i = 0 TO 4
        PRINT "  #"; i; ": ("; sx(i); ","; sy(i); ") v=("; svx(i); ","; svy(i); ")"
    NEXT i
    FOR t = 1 TO 15
        FOR i = 0 TO 4
            IF sact(i) THEN
                sx(i) = sx(i) + svx(i)
                sy(i) = sy(i) + svy(i)
                IF sx(i) < 0 THEN sx(i) = 0: svx(i) = -svx(i)
                IF sx(i) + sw(i) > SCREEN_W THEN sx(i) = SCREEN_W - sw(i): svx(i) = -svx(i)
                IF sy(i) < 0 THEN sy(i) = 0: svy(i) = -svy(i)
                IF sy(i) + sh(i) > SCREEN_H THEN sy(i) = SCREEN_H - sh(i): svy(i) = -svy(i)
            END IF
        NEXT i
        FOR i = 0 TO 4
            FOR j = i + 1 TO 4
                IF sact(i) AND sact(j) THEN
                    IF CheckOverlap(sx(i), sy(i), sw(i), sh(i), sx(j), sy(j), sw(j), sh(j)) THEN
                        LOCAL tx AS LONG
                        tx = svx(i): svx(i) = svx(j): svx(j) = tx
                        tx = svy(i): svy(i) = svy(j): svy(j) = tx
                        PRINT "  Collision #"; i; " vs #"; j
                    END IF
                END IF
            NEXT j
        NEXT i
        IF t MOD 5 = 0 THEN
            PRINT "Step "; t; ":"
            FOR i = 0 TO 4
                PRINT "  #"; i; ": ("; sx(i); ","; sy(i); ")"
            NEXT i
        END IF
    NEXT t
    FUNCTION = 0
END FUNCTION

FUNCTION TestCollision() AS LONG
    PRINT "Collision tests:"
    PRINT "  overlap(0,0,20,20,15,15,20,20) = "; CheckOverlap(0, 0, 20, 20, 15, 15, 20, 20)
    PRINT "  overlap(0,0,20,20,50,50,20,20) = "; CheckOverlap(0, 0, 20, 20, 50, 50, 20, 20)
    PRINT "  overlap(100,100,50,50,120,120,30,30) = "; CheckOverlap(100, 100, 50, 50, 120, 120, 30, 30)
    FUNCTION = 0
END FUNCTION

SUB TestVelocity()
    LOCAL sp AS Sprite
    InitSprite(sp, 0, 100, 100, 32, 32)
    sp.vx = 10
    sp.vy = 5
    LOCAL i AS LONG
    FOR i = 1 TO 10
        MoveSprite(sp)
        PRINT "  step "; i; ": ("; sp.x; ","; sp.y; ")"
    NEXT i
END SUB

FUNCTION PBMAIN() AS LONG
    PRINT "=== Sprite Engine Demo ==="
    PRINT "Screen: "; SCREEN_W; "x"; SCREEN_H
    TestCollision()
    PRINT ""
    PRINT "Velocity test:"
    TestVelocity()
    PRINT ""
    RunSimulation()
    PRINT ""
    PRINT "=== End Sprite Engine ==="
    FUNCTION = 0
END FUNCTION
