Angle Collisions
#77
A few refinements later...

I haven't seen it jump out of bounds nearly as much and have tried to implement an algorithm to handle bounces off of points. It seems to work most of the time.

I also added a mouse driven paddle. Tilting the paddle is done with the mouse wheel. Yes, the paddle acts really hinky, and I'm considering an air hockey-like round impactor instead.

Code: (Select All)
'Janky wall bouncy ball
TYPE V2 '                                                       Vector type 2D contains
    x AS SINGLE '                                               x component
    y AS SINGLE '                                               y component
END TYPE

TYPE wall '                                                     Wall type contains
    v AS V2 '                                                   direction vector
    n AS V2 '                                                   normalized {orthogonal} vector
    s AS V2 '                                                   start point
    e AS V2 '                                                   end point
    m AS V2 '                                                   midpoint
    l AS INTEGER '                                              length
END TYPE

TYPE ball '                                                     Ball type contains
    p AS V2 '                                                   position
    d AS V2 '                                                   displacement (speed)
    n AS V2 '                                                   normalized displacement vector
    r AS INTEGER '                                              radius
END TYPE

DIM SHARED AS wall w(40)

DIM AS ball b(0)
DIM AS V2 bisect, reflec, halfv, npnt
DIM SHARED scrw%, scrh%
DIM wloss!, rfric!
wloss! = 1 '                                                    change to <1 if speed loss in wall bounce
rfric! = 1 '                                                    change to <1 if speed loss in rolling friction
scrw% = _DESKTOPWIDTH: scrh% = _DESKTOPHEIGHT - 80 '            Create screen
SCREEN _NEWIMAGE(scrw%, scrh%, 32)
DO UNTIL _SCREENEXISTS: LOOP
_SCREENMOVE 0, 0

RANDOMIZE TIMER
Make_wall '                                                     create wall space
FOR x% = 1 TO 40 '                                              draw walls
    LINE (w(x%).s.x, w(x%).s.y)-(w(x%).e.x, w(x%).e.y)
    R2_Norm w(x%).n, w(x%).n, 20 '                              create and display orthogonals, 20 length
    LINE (w(x%).m.x, w(x%).m.y)-(w(x%).m.x + w(x%).n.x, w(x%).m.y + w(x%).n.y), &H9FFF0000
    R2_Norm w(x%).n, w(x%).n, 1 '                               reset to unit size
NEXT x%

'initialize ball size, position and velocity
b(0).p.x = _SHR(scrw%, 1): b(0).p.y = _SHR(scrh%, 1): b(0).r = 20
b(0).d.x = INT(RND * 20) - 10: b(0).d.y = INT(RND * 20) - 10 '  random initial direction
'b(0).d.x = INT(RND * 40) - 20: b(0).d.y = INT(RND * 40) - 20 '  random initial direction
'b(0).d.x = 19: b(0).d.y = 19 '  full speed

back& = _COPYIMAGE(0, 33) '                                     save background

'Paddle wall initialization
w(0).s.x = scrw% / 2 - 50: w(0).s.y = scrh% / 2 '               start point
w(0).e.x = scrw% / 2 + 50: w(0).e.y = scrh% / 2 '               end point
P2V w(0).v, w(0).s, w(0).e '                                    set paddle vector
Ortho_Norm w(0).n, w(0).v '                                     compute paddle unit orthogonal
w(0).l = Mag(w(0).v)
w(0).m = w(0).v '                                               set midpoint of wall -midpoint = wall vector
R2_Norm w(0).m, w(0).m, w(0).l / 2 '                            divide by 2
R2_Add w(0).m, w(0).s, 1 '                                      add midpoint to start point
_MOUSEHIDE
DO '                                                            main loop
    CLS
    _PUTIMAGE , back& '                                         redraw background
    WHILE _MOUSEINPUT
        'mousewheel ops
        R2_Norm w(0).v, w(0).v, 10 '                            reduce vector granularity (speeds mousewheel changes)
        IF ABS(w(0).v.x) <= ABS(w(0).v.y) THEN
            w(0).v.x = w(0).v.x + SGN(_MOUSEWHEEL)
        ELSE
            w(0).v.y = w(0).v.y + SGN(_MOUSEWHEEL)
        END IF
        R2_Norm w(0).v, w(0).v, 50
        Ortho_Norm w(0).n, w(0).v
        w(0).s = w(0).m: R2_Add w(0).s, w(0).v, -1
        w(0).e = w(0).m: R2_Add w(0).e, w(0).v, 1
        R2_Norm w(0).v, w(0).v, 100
    WEND
    w(0).m.x = _MOUSEX: w(0).m.y = _MOUSEY
    R2_Norm halfv, w(0).v, 50
    w(0).s = w(0).m: R2_Add w(0).s, halfv, -1
    w(0).e = w(0).m: R2_Add w(0).e, halfv, 1
    'IF _MOUSEBUTTON(1) THEN
    '    b(0).p.x = _MOUSEX: b(0).p.y = _MOUSEY
    'END IF
    LINE (w(0).s.x, w(0).s.y)-(w(0).e.x, w(0).e.y) '            draw paddle
    CIRCLE (b(0).p.x, b(0).p.y), b(0).r '                       draw ball
    R2_Add b(0).p, b(0).d, 1 '                                  move ball
    R2_Norm b(0).d, b(0).d, Mag(b(0).d) * rfric! '              apply rolling friction loss (if desired)

    FOR wc% = 0 TO 40 '                                         check all walls for wall strike
        'first check for a reasonable proximity and skip if not true
        IF _HYPOT(w(wc%).m.x - b(0).p.x, w(wc%).m.y - b(0).p.y) > b(0).r + (w(wc%).l / 2) THEN _CONTINUE
        'We're close so check further
        IF NewlineSegCirc(w(wc%), b(0)) = 0 THEN _CONTINUE '    skip if not intersecting
        IF wc% > 0 THEN '                                       if not the paddle
            IF R2_Dot(w(wc%).n, b(0).d) > 0 THEN _CONTINUE '    if it's out, let it back in
        END IF
        'We're close to wc%, but are we closer to wc% + 1?  this might go in the above IF THEN

        SELECT CASE wc% '                                       get adjacent wall indexes
            CASE 1: pre% = 40: sbs% = 2
            CASE 40: pre% = 39: sbs% = 1
            CASE ELSE: pre% = wc% - 1: sbs% = wc% + 1
        END SELECT
        'check hypot of start and end points
        IF _HYPOT(w(wc%).s.x - b(0).p.x, w(wc%).s.y - b(0).p.y) < b(0).r THEN alt% = pre% 'closer to previous wall
        IF _HYPOT(w(wc%).e.x - b(0).p.x, w(wc%).e.y - b(0).p.y) < b(0).r THEN alt% = sbs% 'closer to subsequent wall
        'We're intersecting w(wc%) so we back off until we don't, counting the back ups
        'we check both wc% and alt% walls. Which one goes low on backup first?
        R2_Norm b(0).n, b(0).d, 1 '                             get displacement unit vector
        bk% = 0
        DO
            R2_Add b(0).p, b(0).n, -1 '                         backup by unit vectors, updating ball position
            IF alt% <> 0 AND wc% <> 0 THEN '                    if alternate wall set and not checking paddle
                mainlow% = NewlineSegCirc(w(wc%), b(0)) '       main wall intersect
                altlow% = NewlineSegCirc(w(alt%), b(0)) '       alternate wall intersect
                IF mainlow% = 0 AND altlow% = 0 THEN '          if both walls go low simultaneously
                    'alter the bisecter between wc% & alt%, two step process
                    Vec_Mirror bisect, w(wc%).n, w(alt%).n '    first bisect wc% and alt% orthogonals
                    R2_Norm bisect, bisect, 1 '                 normalize it for next step
                    Vec_Mirror bisect, bisect, b(0).d '         then bisect result with ball displacement vector
                    in% = -1
                ELSEIF mainlow% = 0 AND altlow% <> 0 THEN '     if main wall goes low first
                    Vec_Mirror bisect, w(wc%).n, b(0).d '       use wc% bisecter
                    in% = -1
                ELSEIF mainlow% <> 0 AND altlow% = 0 THEN '     if alternate wall goes low first
                    Vec_Mirror bisect, w(alt%).n, b(0).d '      use alt% bisecter
                    in% = -1
                END IF
            ELSE
                mainlow% = NewlineSegCirc(w(wc%), b(0))
                IF mainlow% = 0 THEN in% = -1
                Vec_Mirror bisect, w(wc%).n, b(0).d
            END IF
            bk% = bk% + 1 '                                     counting number of backups
        LOOP UNTIL in% '                                        until we no longer intersect one or the other
        in% = 0: alt% = 0
        reflec = bisect: R2_Add reflec, b(0).d, -1 '            subtract ball displacement from bisecter to get reflect vector
        R2_Norm reflec, reflec, -bk% '                          invert & recover backed up unit vectors
        R2_Add b(0).p, reflec, 1 '                              and add them to ball position

        m! = Mag(b(0).d) '                                      preserve displacement magnitude
        R2_Norm b(0).d, reflec, m! '                            set ball displacement to new angle
        'R2_Norm b(0).d, b(0).d, m! * wloss! '                  lose energy in wall bounce (if desired)
        EXIT FOR '                                              if we got here no more checks are needed
    NEXT wc%
    'if ball escapes the border prevent it from leaving the screen
    IF b(0).p.x > scrw% OR b(0).p.x < 0 THEN
        b(0).d.x = -b(0).d.x
    END IF
    IF b(0).p.y > scrh% OR b(0).p.y < 0 THEN
        b(0).d.y = -b(0).d.y
    END IF

    IF _KEYDOWN(13) THEN '                                      Press <Enter> to reset ball
        b(0).p.x = _SHR(scrw%, 1): b(0).p.y = _SHR(scrh%, 1)
        b(0).d.x = INT(RND * 20) - 10: b(0).d.y = INT(RND * 20) - 10
    END IF

    _LIMIT 60
    _DISPLAY
LOOP UNTIL _KEYDOWN(27) '                                       Press <Esc> to quit
_FREEIMAGE back&
END

'VECTOR MATH PROCEDURES
'²²²²²²²²Convert points st & nd to a vector²²²²²²²²²²²²²²²²²²²²
SUB P2V (v AS V2, st AS V2, nd AS V2)
    v.x = nd.x - st.x
    v.y = nd.y - st.y
END SUB 'P2V

'²²²²²²²²Mirror a vector in around a unit bisecter²²²²²²²²²²²²²²
SUB Vec_Mirror (re AS V2, m AS V2, in AS V2)
    R2_Norm re, m, R2_Dot(in, m) * 2
END SUB 'Vec_Mirror

'²²²²²²²²Return result of dot product of two vectors²²²²²²²²²²²²
FUNCTION R2_Dot (v AS V2, v2 AS V2)
    R2_Dot = v.x * v2.x + v.y * v2.y
END FUNCTION 'R3_Dot

'²²²²²²²²Add a scalar multiple of se to re²²²²²²²²²²²²²²²²²²²²²²
SUB R2_Add (re AS V2, se AS V2, m AS INTEGER)
    re.x = re.x + se.x * m
    re.y = re.y + se.y * m
END SUB 'R3_Add

'²²²²²²²²Compute magnitude of vector v²²²²²²²²²²²²²²²²²²²²²²²²²²
FUNCTION Mag (v AS V2)
    Mag = _HYPOT(v.x, v.y)
END FUNCTION 'Mag

'²²²²²²²²Normalize v and regrow to scalar, return in re²²²²²²²²²
SUB R2_Norm (re AS V2, v AS V2, scalar AS SINGLE)
    x! = v.x: y! = v.y '                                        preserve vector v from changes (if desired)
    m! = _HYPOT(x!, y!) '                                       compute magnitude of v
    IF m! = 0 THEN '                                            trap division by zero
        re.x = 0: re.y = 0 '                                    by returning a zero vector
    ELSE '                                                      if magnitude not zero
        re.x = (x! / m!) * scalar '                             shrink to unit vector and rescale x component
        re.y = (y! / m!) * scalar '                               "     "       "       "       " y component
    END IF
END SUB 'R2_Norm

'²²²²²²²²Return the unit orthogonal of a vector²²²²²²²²²²²²²²²²²
SUB Ortho_Norm (orth AS V2, vec AS V2)
    orth.x = -vec.y: orth.y = vec.x '                           compute orthogonal
    R2_Norm orth, orth, 1 '                                     and convert it to a unit vector
END SUB 'Ortho_Norm

'OTHER SUBROUTINES
'²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
SUB Make_wall
    lsp% = ((scrw% - 200) + (scrh% - 200)) / 20 '
    trip1% = INT((scrw% - 200) / lsp%) '                        # of horizontal wall sections
    trip2% = 20 - trip1% '                                      # of vertical wall sections
    bs% = 100: dr% = 1 '                                        baseline and direction multiplier
    horz% = -1
    FOR x% = 1 TO 40
        rand% = INT(RND * 80) - 40
        IF x% = 1 THEN '                                        set start point
            w(x%).s.x = bs%
            w(x%).s.y = bs%
        ELSE
            w(x%).s = w(x% - 1).e
        END IF
        IF x% = 40 THEN '                                       set end point
            w(x%).e = w(1).s
        ELSE
            IF horz% THEN
                w(x%).e.x = w(x%).s.x + lsp% * dr%
                w(x%).e.y = bs% + rand%
            ELSE
                w(x%).e.x = bs% + rand%
                w(x%).e.y = w(x%).s.y + lsp% * dr%
            END IF
        END IF
        P2V w(x%).v, w(x%).s, w(x%).e '                         set wall vector
        Ortho_Norm w(x%).n, w(x%).v
        w(x%).l = Mag(w(x%).v) '                                set wall length
        w(x%).m = w(x%).v '                                     set midpoint of wall -midpoint = wall vector
        R2_Norm w(x%).m, w(x%).m, w(x%).l / 2 '                                      -divide by 2
        R2_Add w(x%).m, w(x%).s, 1 '                                                 -add midpoint to start point
        ct% = ct% + 1
        IF horz% AND ct% = trip1% THEN
            horz% = NOT horz%
            ct% = 0: bs% = w(x%).e.x
        END IF
        IF NOT horz% AND ct% = trip2% THEN
            horz% = NOT horz%
            ct% = 0: bs% = w(x%).e.y: dr% = -1
        END IF
    NEXT x%
END SUB 'Make_wall

'²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
FUNCTION NewlineSegCirc (w AS wall, b AS ball)
    'shorthand version of Bplus' lineSegIntersectCircle
    'utilizing vector math SUBs already implemented
    DIM AS V2 d, p
    DIM AS INTEGER rtn, i
    R2_Norm d, w.v, 1 '                                         d is unit vector of wall
    FOR i = 0 TO w.l '
        p = w.s: R2_Add p, d, i '                               add i multiples to wall start position to get p
        'if p within ball radius then intersect true and leave loop
        IF _HYPOT(p.x - b.p.x, p.y - b.p.y) <= b.r THEN rtn = NOT rtn: EXIT FOR
    NEXT
    NewlineSegCirc = rtn
END FUNCTION 'NewlineSegCirc
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
Reply


Messages In This Thread
Angle Collisions - by james2464 - 10-15-2022, 01:39 AM
RE: Angle Collisions - by bplus - 10-15-2022, 02:16 AM
RE: Angle Collisions - by james2464 - 10-15-2022, 04:01 AM
RE: Angle Collisions - by James D Jarvis - 10-15-2022, 10:39 PM
RE: Angle Collisions - by Pete - 10-15-2022, 10:46 PM
RE: Angle Collisions - by James D Jarvis - 10-15-2022, 11:24 PM
RE: Angle Collisions - by james2464 - 10-16-2022, 12:17 AM
RE: Angle Collisions - by OldMoses - 10-16-2022, 01:14 PM
RE: Angle Collisions - by james2464 - 10-16-2022, 07:11 PM
RE: Angle Collisions - by OldMoses - 10-18-2022, 08:20 PM
RE: Angle Collisions - by james2464 - 10-18-2022, 10:47 PM
RE: Angle Collisions - by OldMoses - 10-19-2022, 12:23 AM
RE: Angle Collisions - by Pete - 10-16-2022, 12:13 AM
RE: Angle Collisions - by Pete - 10-16-2022, 12:50 AM
RE: Angle Collisions - by bplus - 10-16-2022, 01:01 PM
RE: Angle Collisions - by bplus - 10-16-2022, 01:27 PM
RE: Angle Collisions - by OldMoses - 10-16-2022, 04:02 PM
RE: Angle Collisions - by bplus - 10-16-2022, 06:46 PM
RE: Angle Collisions - by bplus - 10-16-2022, 07:45 PM
RE: Angle Collisions - by james2464 - 10-16-2022, 08:04 PM
RE: Angle Collisions - by James D Jarvis - 10-16-2022, 08:07 PM
RE: Angle Collisions - by bplus - 10-16-2022, 08:47 PM
RE: Angle Collisions - by James D Jarvis - 10-16-2022, 08:55 PM
RE: Angle Collisions - by bplus - 10-17-2022, 10:07 AM
RE: Angle Collisions - by bplus - 10-17-2022, 12:26 PM
RE: Angle Collisions - by OldMoses - 10-17-2022, 12:58 PM
RE: Angle Collisions - by bplus - 10-17-2022, 01:11 PM
RE: Angle Collisions - by james2464 - 10-17-2022, 01:57 PM
RE: Angle Collisions - by OldMoses - 10-17-2022, 02:19 PM
RE: Angle Collisions - by bplus - 10-17-2022, 02:49 PM
RE: Angle Collisions - by james2464 - 10-17-2022, 03:46 PM
RE: Angle Collisions - by bplus - 10-17-2022, 04:53 PM
RE: Angle Collisions - by james2464 - 10-17-2022, 05:27 PM
RE: Angle Collisions - by Dav - 10-18-2022, 02:22 AM
RE: Angle Collisions - by james2464 - 10-18-2022, 03:25 AM
RE: Angle Collisions - by Pete - 10-17-2022, 04:10 PM
RE: Angle Collisions - by bplus - 10-17-2022, 04:55 PM
RE: Angle Collisions - by james2464 - 10-17-2022, 05:23 PM
RE: Angle Collisions - by james2464 - 10-18-2022, 02:00 AM
RE: Angle Collisions - by Pete - 10-18-2022, 02:10 AM
RE: Angle Collisions - by Pete - 10-18-2022, 03:20 AM
RE: Angle Collisions - by james2464 - 10-18-2022, 03:57 AM
RE: Angle Collisions - by bplus - 10-18-2022, 03:27 PM
RE: Angle Collisions - by james2464 - 10-18-2022, 04:11 PM
RE: Angle Collisions - by bplus - 10-18-2022, 08:27 PM
RE: Angle Collisions - by Pete - 10-18-2022, 08:44 PM
RE: Angle Collisions - by bplus - 10-18-2022, 10:10 PM
RE: Angle Collisions - by Pete - 10-18-2022, 10:19 PM
RE: Angle Collisions - by james2464 - 10-20-2022, 12:30 AM
RE: Angle Collisions - by bplus - 10-20-2022, 02:36 AM
RE: Angle Collisions - by james2464 - 10-20-2022, 01:51 PM
RE: Angle Collisions - by Pete - 10-20-2022, 03:48 AM
RE: Angle Collisions - by bplus - 10-20-2022, 02:52 PM
RE: Angle Collisions - by james2464 - 10-20-2022, 04:21 PM
RE: Angle Collisions - by bplus - 10-20-2022, 04:37 PM
RE: Angle Collisions - by james2464 - 10-21-2022, 07:10 PM
RE: Angle Collisions - by Pete - 10-21-2022, 07:20 PM
RE: Angle Collisions - by bplus - 10-21-2022, 09:05 PM
RE: Angle Collisions - by OldMoses - 10-22-2022, 12:09 AM
RE: Angle Collisions - by james2464 - 10-22-2022, 10:29 PM
RE: Angle Collisions - by bplus - 10-22-2022, 10:59 PM
RE: Angle Collisions - by justsomeguy - 10-22-2022, 11:45 PM
RE: Angle Collisions - by Pete - 10-23-2022, 12:37 AM
RE: Angle Collisions - by OldMoses - 10-23-2022, 12:46 AM
RE: Angle Collisions - by james2464 - 10-24-2022, 04:57 PM
RE: Angle Collisions - by james2464 - 10-24-2022, 11:14 PM
RE: Angle Collisions - by bplus - 10-25-2022, 12:37 AM
RE: Angle Collisions - by james2464 - 10-25-2022, 03:25 AM
RE: Angle Collisions - by OldMoses - 10-25-2022, 10:47 PM
RE: Angle Collisions - by james2464 - 10-25-2022, 10:52 PM
RE: Angle Collisions - by OldMoses - 10-26-2022, 03:39 AM
RE: Angle Collisions - by james2464 - 10-26-2022, 03:51 PM
RE: Angle Collisions - by OldMoses - 10-26-2022, 04:18 PM
RE: Angle Collisions - by james2464 - 10-26-2022, 08:41 PM
RE: Angle Collisions - by OldMoses - 10-27-2022, 12:33 AM
RE: Angle Collisions - by james2464 - 10-27-2022, 03:36 PM
RE: Angle Collisions - by OldMoses - 10-29-2022, 12:05 AM
RE: Angle Collisions - by james2464 - 10-29-2022, 01:45 AM
RE: Angle Collisions - by james2464 - 10-30-2022, 04:41 PM
RE: Angle Collisions - by bplus - 10-30-2022, 06:16 PM
RE: Angle Collisions - by james2464 - 10-30-2022, 06:25 PM
RE: Angle Collisions - by bplus - 10-30-2022, 06:31 PM
RE: Angle Collisions - by james2464 - 10-30-2022, 06:37 PM
RE: Angle Collisions - by bplus - 10-30-2022, 06:45 PM
RE: Angle Collisions - by james2464 - 10-31-2022, 01:27 AM
RE: Angle Collisions - by bplus - 10-31-2022, 01:52 AM
RE: Angle Collisions - by TempodiBasic - 11-01-2022, 02:38 AM
RE: Angle Collisions - by bplus - 11-01-2022, 11:31 AM
RE: Angle Collisions - by james2464 - 11-01-2022, 04:15 PM
RE: Angle Collisions - by triggered - 11-01-2022, 03:03 AM
RE: Angle Collisions - by james2464 - 11-03-2022, 06:53 PM
RE: Angle Collisions - by OldMoses - 11-04-2022, 12:56 AM



Users browsing this thread: 12 Guest(s)