Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
To Nest or Not to Nest Else
#21
hmm... I wonder if that InRange% Function might simplify this:
Code: (Select All)
_Title "Box Intersect" 'b+ 2019-12-26
' 2023-01-27 rewrote CollisionIntersect2Boxes to Intersect2Boxes, renamed Collision% to BoxCollision%
' 2024-08-20 remove old CollisionIntersect2Boxes stuff start toggle ON

Const xmax = 800, ymax = 600, nBoxes = 250
Screen _NewImage(xmax, ymax, 32)
_ScreenMove 300, 40
Type boxType
    x As Single
    y As Single
    dx As Single
    dy As Single
    w As Single
    h As Single
    c As _Unsigned Long
End Type
Dim testbx As boxType, mousebx As boxType
newBox 300, 200, 200, 200, &HFFFFFFFF, testbx
newBox 100, 100, 300, 50, &HFFFFFF00, mousebx
_Title "Mouse around to check intersect of two boxes, PRESS Escape for Tons of floating box collisions..."
'Mouse test for building collisionIntersect2Boxes sub

While _KeyHit <> 27
    Cls
    ix = -1
    Line (testbx.x, testbx.y)-Step(testbx.w, testbx.h), testbx.c, B
    While _MouseInput: Wend
    mousebx.x = _MouseX: mousebx.y = _MouseY
    Line (mousebx.x, mousebx.y)-Step(mousebx.w, mousebx.h), mousebx.c, B
    If BoxCollision%(testbx.x, testbx.y, testbx.w, testbx.h, mousebx.x, mousebx.y, mousebx.w, mousebx.h) Then Locate 1, 1: Print "Collision" Else Print "No Collision"
    Intersect2Boxes testbx.x, testbx.y, testbx.w, testbx.h, mousebx.x, mousebx.y, mousebx.w, mousebx.h, ix, iy, iw, ih
    If ix <> -1 Then
        Line (ix, iy)-Step(iw, ih), &HFFFF0000, BF
    End If
    _Display
    _Limit 100
Wend
_KeyClear

Dim bxs(nBoxes) As boxType, scrnbx As boxType
newBox 0, 0, xmax, ymax, &HFF000000, scrnbx
For i = 0 To nBoxes
    newBox Rnd * (xmax - 50) + 25, Rnd * (ymax - 50) + 25, Rnd * 70 + 10, Rnd * 50 + 10, _RGB32(0, 255 * Rnd, 205 * Rnd + 50), bxs(i)
Next
_Title "Intersections are red boxes, press spacebar to toggle box edges, press a to toggle alpha mode on/off"
'OK now let's  run a test
toggle = 1
While _KeyHit <> 27
    Cls
    k$ = InKey$
    If k$ = " " Then
        toggle = 1 - toggle
    ElseIf k$ = "a" Then
        alpha = 1 - alpha
    End If
    For i = 0 To nBoxes
        If alpha = 1 Then
            Line (bxs(i).x, bxs(i).y)-Step(bxs(i).w, bxs(i).h), &H55FF0000, BF
        Else
            For j = i + 1 To nBoxes
                If i <> j Then
                    Intersect2Boxes bxs(i).x, bxs(i).y, bxs(i).w, bxs(i).h, bxs(j).x, bxs(j).y, bxs(j).w, bxs(j).h, ix, iy, iw, ih
                    If ix <> -1 Then Line (ix, iy)-Step(iw, ih), &HFFFF0000, BF
                    'collisionIntersect2Boxes bxs(j).x, bxs(j).y, bxs(j).w, bxs(j).h, bxs(i).x, bxs(i).y, bxs(i).w, bxs(i).h, ix, iy, iw, ih
                    'IF ix <> -1 THEN LINE (ix, iy)-STEP(iw, ih), &HFFFF0000, BF
                End If
            Next
        End If
    Next

    For i = 0 To nBoxes
        If toggle Then Line (bxs(i).x, bxs(i).y)-Step(bxs(i).w, bxs(i).h), bxs(i).c, B
        bxs(i).x = bxs(i).x + bxs(i).dx: bxs(i).y = bxs(i).y + bxs(i).dy

        'bounce boxes back if they hit an edge
        If bxs(i).x < 0 Then bxs(i).dx = -bxs(i).dx: bxs(i).x = 0
        If bxs(i).x + bxs(i).w > xmax Then bxs(i).dx = -bxs(i).dx: bxs(i).x = xmax - bxs(i).w
        If bxs(i).y < 0 Then bxs(i).dy = -bxs(i).dy: bxs(i).y = 0
        If bxs(i).y + bxs(i).h > ymax Then bxs(i).dy = -bxs(i).dy: bxs(i).y = ymax - bxs(i).h
    Next
    _Display
    _Limit 30
Wend

Sub newBox (x, y, w, h, c As _Unsigned Long, bx As boxType)
    bx.x = x
    bx.y = y
    bx.w = w
    bx.h = h
    bx.c = c
    bx.dx = Rnd * 8 - 4
    bx.dy = Rnd * 6 - 3
End Sub

Function BoxCollision% (b1x, b1y, b1w, b1h, b2x, b2y, b2w, b2h)
    ' x, y represent the box left most x and top most y
    ' w, h represent the box width and height which is the usual way sprites / tiles / images are described
    ' such that boxbottom = by + bh
    '        and boxright = bx + bw

    If (b1y + b1h < b2y) Or (b1y > b2y + b2h) Or (b1x > b2x + b2w) Or (b1x + b1w < b2x) Then
        BoxCollision% = 0
    Else
        BoxCollision% = 1
    End If
End Function

' this needs max, min functions as well as BoxCollision%
Sub Intersect2Boxes (b1x, b1y, b1w, b1h, b2x, b2y, b2w, b2h, bix, biy, biw, bih)
    If b2x >= b1x And b2x <= b1x + b1w And b2y >= b1y And b2y <= b1y + b1h Then 'top left corner in 2nd box
        bix = b2x: biy = b2y
        If b2x + b2w <= b1x + b1w Then biw = b2w Else biw = b1x + b1w - b2x
        If b2y + b2h <= b1y + b1h Then bih = b2h Else bih = b1y + b1h - b2y
    ElseIf b2x >= b1x And b2x <= b1x + b1w And b2y + b2h >= b1y And b2y + b2h <= b1y + b1h Then 'bottom left corner of 2nd box in first
        bix = b2x
        If b2x + b2w <= b1x + b1w Then biw = b2w Else biw = b1x + b1w - b2x
        If b2y <= b1y Then biy = b1y: bih = b2y + b2h - b1y Else biy = b2y: bih = b2h
    ElseIf b2x + b2w >= b1x And b2x + b2w <= b1x + b1w And b2y >= b1y And b2y <= b1y + b1h Then 'right top corner 2nd box in first
        If b2x >= b1x Then bix = b2x: biw = b2w Else bix = b1x: biw = b2x + b2w - b1x
        biy = b2y
        If b2y + b2h <= b1y + b1h Then bih = b2h Else bih = b1y + b1h - b2y
    ElseIf b2x + b2w >= b1x And b2x + b2w <= b1x + b1w And b2y + b2h >= b1y And b2y + b2h <= b1y + b1h Then 'left bottom corners in first box
        If b2x >= b1x Then bix = b2x: biw = b2w Else bix = b1x: biw = b2x + b2w - b1x
        If b2y >= b1y Then biy = b2y: bih = b2h Else biy = b1y: bih = b2y + b2h - b1y
    ElseIf BoxCollision%(b1x, b1y, b1w, b1h, b2x, b2y, b2w, b2h) Then
        bix = max(b1x, b2x): biy = max(b1y, b2y)
        biw = min(b1x + b1w, b2x + b2w) - bix: bih = min(b1y + b1h, b2y + b2h) - biy
    Else 'no intersect
        bix = -1: biy = -1: biw = 0: bih = 0
    End If
End Sub

Function max (a, b)
    If a > b Then max = a Else max = b
End Function

Function min (a, b)
    If a < b Then min = a Else min = b
End Function

   
b = b + ...
Reply
#22
Huuuum... so I am out to lunch on Else & ElseIf requiring each new condition to be evaluated until the end of the conditions, unlike the short circuit that Terry's nested If's were providing. Both Steve and Luke are demonstrating Else & ElseIf do not force every Else condition to be considered. I suppose it would need an ElseAll like Select EveryCase.
Reply
#23
Use of Select Case or Else IF is a matter of taste because both those use same code under the hood.

Select Case And/Or Else IF is highly prefered over a gantlet of IF's when you have mutually exclusive set of cases you can isolate out to a single level or 2. That is much preferred both for efficiency and aesthetically over a slew of all over the place nesting of IF and Else's. Those indents can go all the way to the right border of code page and who likes scrolling horizontally to review code or a bunch or inserted _ line continuations that break with formatting by IDE?
b = b + ...
Reply
#24
Who likes scrolling horizontally to view code you say?

I'll take Japanese for $100, Alex!

Pete
Shoot first and shoot people who ask questions, later.
Reply
#25
Code: (Select All)
Screen _NewImage(640, 480, 32)
$Color:32
Do
    Cls
    Line (100, 100)-(200, 200), Red, BF
    Line (300, 100)-(400, 200), Blue, BF
    While _MouseInput: Wend
    x = _MouseX: y = _MouseY
    If x >= 100 And x <= 200 And y >= 100 And y <= 200 Then _PrintString (140, 140), "OK!"
    If x >= 300 And x <= 400 And y >= 100 And y <= 200 Then _PrintString (340, 140), "OK!"

    _Limit 30
    _Display
Loop Until _MouseButton(1)


Let's not forget our little friend 'AND'.  This operator is my friend in sooooo many dark places and dangerous alleys.
Cleans up and shortens the code quite nicely.
Reply
#26
Yep, been there, done that, too!

+1

Pete Smile
Shoot first and shoot people who ask questions, later.
Reply
#27
We don' need no stinking nests... Big Grin 

Code: (Select All)
SCREEN _NEWIMAGE(500, 500, 32)
$COLOR:32
DO
    CLS
    LINE (200, 200)-(300, 300), Green, BF
    WHILE _MOUSEINPUT: WEND
    x = _MOUSEX: y = _MOUSEY
    IF x > 200 THEN IF x < 300 THEN IF y > 200 THEN IF y < 300 THEN _PRINTSTRING (240, 240), "OK!"
    _LIMIT 30
    _DISPLAY
LOOP UNTIL _MOUSEBUTTON(1) OR _KEYDOWN(27)
It seems like really, really bad form to me, but it compiles and runs...
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
Reply
#28
Bad form? didn't know you could even do that!

Nothing beats the And band:
Code: (Select All)
Screen _NewImage(500, 500, 32)
$Color:32
Do
    Cls
    Line (200, 200)-(300, 300), Green, BF
    While _MouseInput: Wend
    x = _MouseX: y = _MouseY
    If x > 200 And x < 300 And y > 200 And y < 300 Then _PrintString (240, 240), "OK!"
    _Limit 30
    _Display
Loop Until _MouseButton(1) Or _KeyDown(27)
b = b + ...
Reply
#29
(08-22-2024, 05:28 PM)OldMoses Wrote: We don' need no stinking nests... Big Grin 

Code: (Select All)
SCREEN _NEWIMAGE(500, 500, 32)
$COLOR:32
DO
    CLS
    LINE (200, 200)-(300, 300), Green, BF
    WHILE _MOUSEINPUT: WEND
    x = _MOUSEX: y = _MOUSEY
    IF x > 200 THEN IF x < 300 THEN IF y > 200 THEN IF y < 300 THEN _PRINTSTRING (240, 240), "OK!"
    _LIMIT 30
    _DISPLAY
LOOP UNTIL _MOUSEBUTTON(1) OR _KEYDOWN(27)
It seems like really, really bad form to me, but it compiles and runs...
Huh, LOL, how did I not know that either? It's a shortened version of the method I posted.
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Reply




Users browsing this thread: 2 Guest(s)