Jump to content
nitekram

Looking for a GUI - objects and lines in the window

Recommended Posts

I don't think I'm using an offset (but I have not created any code). The zero point of the coordinate system corresponds to the zero point of the window. And then I'm using coordinates relative to the window.

Share this post


Link to post
Share on other sites

I mean, as for the dotted lines, they are outside of the main rectangle, so is that half of the solid rectangle added to the the outside. IE solid rectangle is width = 100, height = 50, so dotted line rectangle, in your example: X1 = 50, X2 = 150, Y1 = 25, Y2 = 75?


All by me:

"Sometimes you have to go back to where you started, to get to where you want to go." 

"Everybody catches up with everyone, eventually" 

"As you teach others, you are really teaching yourself."

From my dad

"Do not worry about yesterday, as the only thing that you can control is tomorrow."

 

WindowsError.gif

WIKI | Tabs; | Arrays; | Strings | Wiki Arrays | How to ask a Question | Forum Search | FAQ | Tutorials | Original FAQ | ONLINE HELP | UDF's Wiki | AutoIt PDF

AutoIt Snippets | Multple Guis | Interrupting a running function | Another Send

StringRegExp | StringRegExp Help | RegEXTester | REG TUTOR | Reg TUTOT 2

AutoItSetOption | Macros | AutoIt Snippets | Wrapper | Autoit  Docs

SCITE | SciteJump | BB | MyTopics | Programming | UDFs | AutoIt 123 | UDFs Form | UDF

Learning to script | Tutorials | Documentation | IE.AU3 | Games? | FreeSoftware | Path_Online | Core Language

Programming Tips

Excel Changes

ControlHover.UDF

GDI_Plus

Draw_On_Screen

GDI Basics

GDI_More_Basics

GDI Rotate

GDI Graph

GDI  CheckExistingItems

GDI Trajectory

Replace $ghGDIPDll with $__g_hGDIPDll

DLL 101?

Array via Object

GDI Swimlane

GDI Plus French 101 Site

GDI Examples UEZ

GDI Basic Clock

GDI Detection

Ternary operator

Share this post


Link to post
Share on other sites

I have created the code, but have the same issues as I had with my posted code - the corners seem to be off on my example as well as yours and UEZ.

Func _CheckLocation($iCtrl, $iX, $iY)
    Local $xOffSet = 30
    Static $wtf
    Local $aCtrlPos = ControlGetPos($g_hGUI, "", $g_aCtrls[$iCtrl][0])
    For $x = 0 To UBound($g_aCtrls) - 1
        If $iCtrl = $x Then ContinueLoop
        ;
        For $y = 0 To 4
            #cs
            If _WinAPI_PtInRectEx($iX, $iY, $g_aCtrls[$x][10] - $aCtrlPos[2] - $xOffSet, $g_aCtrls[$x][11] - $aCtrlPos[3] - $xOffSet, $g_aCtrls[$x][10] + $aCtrlPos[2] + $xOffSet, $g_aCtrls[$x][11] + $aCtrlPos[3] + $xOffSet) Then ;_
                Return False
            EndIf
            #ce
            $xOffSet = 20
            Local $__X1, $__X2, $__Y1, $__Y2, $__Mx, $__My
            ; If $x1 < $mx And $mx < $x2 And $y1 < $my And $my < $y2 Then ; Collision
            $__X1 = $g_aCtrls[$x][10] - $g_aCtrls[$x][12] - $xOffSet
            $__X2 = $g_aCtrls[$x][10] + $g_aCtrls[$x][12] + $xOffSet
            $__Y1 = $g_aCtrls[$x][11] - $g_aCtrls[$x][13] - $xOffSet
            $__Y2 = $g_aCtrls[$x][11] + $g_aCtrls[$x][13] + $xOffSet

            $__Mx = $iX
            $__My = $iY

            If $__X1 < $__Mx And $__Mx < $__X2 And $__Y1 < $__My And $__My < $__Y2 Then Return False
            ;If $g_aCtrls[$x][10] - $g_aCtrls[$x][12] / 2  < $iX And $iX < $g_aCtrls[$x][10] + $g_aCtrls[$x][12] * 2 And  $g_aCtrls[$x][13] - < $iY And $iY < $y2 Then ; Collision
        Next
        ;
    Next
    Return True
EndFunc   ;==>_CheckLocation

 

.

.EDIT

I do not know what my thoughts were, so I cleared it up

Edited by nitekram
cleared it up

All by me:

"Sometimes you have to go back to where you started, to get to where you want to go." 

"Everybody catches up with everyone, eventually" 

"As you teach others, you are really teaching yourself."

From my dad

"Do not worry about yesterday, as the only thing that you can control is tomorrow."

 

WindowsError.gif

WIKI | Tabs; | Arrays; | Strings | Wiki Arrays | How to ask a Question | Forum Search | FAQ | Tutorials | Original FAQ | ONLINE HELP | UDF's Wiki | AutoIt PDF

AutoIt Snippets | Multple Guis | Interrupting a running function | Another Send

StringRegExp | StringRegExp Help | RegEXTester | REG TUTOR | Reg TUTOT 2

AutoItSetOption | Macros | AutoIt Snippets | Wrapper | Autoit  Docs

SCITE | SciteJump | BB | MyTopics | Programming | UDFs | AutoIt 123 | UDFs Form | UDF

Learning to script | Tutorials | Documentation | IE.AU3 | Games? | FreeSoftware | Path_Online | Core Language

Programming Tips

Excel Changes

ControlHover.UDF

GDI_Plus

Draw_On_Screen

GDI Basics

GDI_More_Basics

GDI Rotate

GDI Graph

GDI  CheckExistingItems

GDI Trajectory

Replace $ghGDIPDll with $__g_hGDIPDll

DLL 101?

Array via Object

GDI Swimlane

GDI Plus French 101 Site

GDI Examples UEZ

GDI Basic Clock

GDI Detection

Ternary operator

Share this post


Link to post
Share on other sites

Actually, I think I had the your code wrong, as I was taking it from the upper left hand corner and not the middle, but now I am unable to get the conditions correct?

 


All by me:

"Sometimes you have to go back to where you started, to get to where you want to go." 

"Everybody catches up with everyone, eventually" 

"As you teach others, you are really teaching yourself."

From my dad

"Do not worry about yesterday, as the only thing that you can control is tomorrow."

 

WindowsError.gif

WIKI | Tabs; | Arrays; | Strings | Wiki Arrays | How to ask a Question | Forum Search | FAQ | Tutorials | Original FAQ | ONLINE HELP | UDF's Wiki | AutoIt PDF

AutoIt Snippets | Multple Guis | Interrupting a running function | Another Send

StringRegExp | StringRegExp Help | RegEXTester | REG TUTOR | Reg TUTOT 2

AutoItSetOption | Macros | AutoIt Snippets | Wrapper | Autoit  Docs

SCITE | SciteJump | BB | MyTopics | Programming | UDFs | AutoIt 123 | UDFs Form | UDF

Learning to script | Tutorials | Documentation | IE.AU3 | Games? | FreeSoftware | Path_Online | Core Language

Programming Tips

Excel Changes

ControlHover.UDF

GDI_Plus

Draw_On_Screen

GDI Basics

GDI_More_Basics

GDI Rotate

GDI Graph

GDI  CheckExistingItems

GDI Trajectory

Replace $ghGDIPDll with $__g_hGDIPDll

DLL 101?

Array via Object

GDI Swimlane

GDI Plus French 101 Site

GDI Examples UEZ

GDI Basic Clock

GDI Detection

Ternary operator

Share this post


Link to post
Share on other sites

@LarsJ

Any ideas, if I leave the conditions the way they are, the image never moves. So I added your idea to the existing code - using the center as the condition, and the _WinAPI_PtInRectEx(), as with using your initial condition, the images never moved? (I think I am doing it right), but the issue with the corners is worse than it was with the other examples.

 

Func _CheckLocation($iCtrl, $iX, $iY)
    If $iCtrl < 0 Then Return
    Local $xOffSet = 30
    Static $wtf
    Local $aCtrlPos = ControlGetPos($g_hGUI, "", $g_aCtrls[$iCtrl][0])
    For $x = 0 To UBound($g_aCtrls) - 1
        If $iCtrl = $x Then ContinueLoop
        ;
        For $y = 0 To 4
            $__X1 = $g_aCtrls[$x][10] - $g_aCtrls[$x][12] - $xOffSet
            $__X2 = $g_aCtrls[$x][10] + $g_aCtrls[$x][12] + $xOffSet
            $__Y1 = $g_aCtrls[$x][11] - $g_aCtrls[$x][13] - $xOffSet / 2
            $__Y2 = $g_aCtrls[$x][11] + $g_aCtrls[$x][13] + $xOffSet / 2

            $__Mx = $aCtrlPos[0] + $aCtrlPos[2] / 2; $iX
            $__My = $aCtrlPos[1] + $aCtrlPos[3] / 2; $iY


            If _WinAPI_PtInRectEx($iX, $iY, $__X1, $__Y1, $__X2, $__Y2) Then ;_
                Return False
            EndIf

        Next
        ;
    Next
    Return True
EndFunc   ;==>_CheckLocation
;

EDIT

Nothing to edit...I was checking if I could edit it - yeah, no more period after all my code, as that was the only way I could edit it since the last update (if my code was the last entry FF)

Edited by nitekram

All by me:

"Sometimes you have to go back to where you started, to get to where you want to go." 

"Everybody catches up with everyone, eventually" 

"As you teach others, you are really teaching yourself."

From my dad

"Do not worry about yesterday, as the only thing that you can control is tomorrow."

 

WindowsError.gif

WIKI | Tabs; | Arrays; | Strings | Wiki Arrays | How to ask a Question | Forum Search | FAQ | Tutorials | Original FAQ | ONLINE HELP | UDF's Wiki | AutoIt PDF

AutoIt Snippets | Multple Guis | Interrupting a running function | Another Send

StringRegExp | StringRegExp Help | RegEXTester | REG TUTOR | Reg TUTOT 2

AutoItSetOption | Macros | AutoIt Snippets | Wrapper | Autoit  Docs

SCITE | SciteJump | BB | MyTopics | Programming | UDFs | AutoIt 123 | UDFs Form | UDF

Learning to script | Tutorials | Documentation | IE.AU3 | Games? | FreeSoftware | Path_Online | Core Language

Programming Tips

Excel Changes

ControlHover.UDF

GDI_Plus

Draw_On_Screen

GDI Basics

GDI_More_Basics

GDI Rotate

GDI Graph

GDI  CheckExistingItems

GDI Trajectory

Replace $ghGDIPDll with $__g_hGDIPDll

DLL 101?

Array via Object

GDI Swimlane

GDI Plus French 101 Site

GDI Examples UEZ

GDI Basic Clock

GDI Detection

Ternary operator

Share this post


Link to post
Share on other sites

This is the way I would implement rectangle collision detection.

I have changed the strategy a little bit. Instead of using the midpoint for collision detection I'm using upper/left corner. But I'm still only using one point. When you divide by two to calculate the midpoint, you have to deal with half pixels every second time. Half a pixel is not a good thing. Using upper/left corner all calculations are simple integer calculations.

Using upper/left corner the dotted rectangle to test collisions looks like this:

tst00_zpsu1bh6207.png

And this is the example code to illustrate the method:

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>

AutoItSetOption( "GUIOnEventMode",  1 )
AutoItSetOption( "MouseCoordMode",  2 ) ; Relative to window
AutoItSetOption( "MustDeclareVars", 1 )
AutoItSetOption( "WinWaitDelay",   10 )

; Only used to draw debug info
Global Const $iTitleBarHeight = 30
Global Const $iBorderWidth    = _WinAPI_GetSystemMetrics( $SM_CXFRAME )

Global $hGui, $iGuiWidth, $iGuiHeight, $aInfo, $fRedraw = False
Global $idGuiMenuItem0, $idGuiMenuItem1, $idGuiMenuItem2, $idGuiMenuItem3, $idGuiMenuItem4, _
       $idGuiMenuItem5, $idGuiMenuItem6, $idGuiMenuItem7, $idGuiMenuItem8, $idGuiMenuItem9

; Information about the rectangles
Global $aRects[1000][8], $iRects = 0
;     0: $idLabel
; 1 - 4: $x, $y, $w, $h ; Pos, size
; 5 - 6: $wx, $wy       ; Window collision boundaries
;     7: $iColor

Example()

Func Example()
  ; Create GUI
  $hGui = GUICreate( "Rectangle collision detection", 800, 600, -1, -1, $WS_OVERLAPPEDWINDOW - $WS_MAXIMIZEBOX + $WS_CLIPCHILDREN )
  GUISetOnEvent( $GUI_EVENT_RESIZED, "Resized" )
  GUISetOnEvent( $GUI_EVENT_CLOSE, "Close" )

  ; Window context menu
  Local $idGuiMenu = GUICtrlCreateContextMenu()
  $idGuiMenuItem0 = GUICtrlCreateMenuItem( "Create rectangle", $idGuiMenu )
  $idGuiMenuItem1 = GUICtrlCreateMenuItem( "Create 5 rects",  $idGuiMenu )
  $idGuiMenuItem2 = GUICtrlCreateMenuItem( "Create 10 rects", $idGuiMenu )
  $idGuiMenuItem3 = GUICtrlCreateMenuItem( "Create 20 rects", $idGuiMenu )
  $idGuiMenuItem4 = GUICtrlCreateMenuItem( "Create 30 rects", $idGuiMenu )
  $idGuiMenuItem5 = GUICtrlCreateMenuItem( "Create 40 rects", $idGuiMenu )
  $idGuiMenuItem6 = GUICtrlCreateMenuItem( "Create 50 rects", $idGuiMenu )
  $idGuiMenuItem7 = GUICtrlCreateMenuItem( "Create 100 rects", $idGuiMenu )
  $idGuiMenuItem8 = GUICtrlCreateMenuItem( "Create 1000 rects", $idGuiMenu )
  $idGuiMenuItem9 = GUICtrlCreateMenuItem( "Delete all rectangles", $idGuiMenu )
  GUICtrlSetOnEvent( $idGuiMenuItem0, "CreateRectangle" )
  GUICtrlSetOnEvent( $idGuiMenuItem1, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem2, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem3, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem4, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem5, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem6, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem7, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem8, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem9, "DeleteAllRects" )

  ; Window size
  Local $aSize = WinGetClientSize( $hGui )
  $iGuiWidth = $aSize[0]
  $iGuiHeight = $aSize[1]

  ; Show GUI
  GUISetState()

  MsgBox( 0, "Rectangle collision detection", _
          "Secondary click to open context menu with items to create rectangles (random colored labels)." & @CRLF & _
          "Click and drag with primary mouse button to define size of rectangle (limited to 4x4 - 200x200)." & @CRLF & @CRLF & _
          "Click and drag a rectangle with primary mouse button to check collisions against window borders" & @CRLF & _
          "and stationary rectangles." & @CRLF & @CRLF & _
          "Secondary click a rectangle to open context menu to draw lines that shows collision boundaries." & @CRLF & _
          "Collisions against window borders and stationary rectangles are detected with moving rectangle" & @CRLF & _
          "upper/left corner. Click in free area to erase the red dotted lines that shows collision boundaries.", 0, $hGui )

  Local $idLabel, $iCurRect, $aDotRects[1000][4]

  While 1
    ; Wait for primary mouse click
    $aInfo = GUIGetCursorInfo()
    While Sleep(10) And IsArray( $aInfo ) And Not $aInfo[2]
      $aInfo = GUIGetCursorInfo()
    WEnd
    If Not IsArray( $aInfo ) Then ContinueLoop

    ; Redraw window?
    ; (Erase dotted rectangles)
    If $fRedraw Then
      ; Erase dotted rectangles
      _WinAPI_RedrawWindow( $hGui, 0, 0, $RDW_INVALIDATE + $RDW_ERASE )
      ; Repaint labels
      For $i = 0 To $iRects - 1
        GUICtrlSetState( $aRects[$i][0], $GUI_HIDE ) ; Force a label repaint
        GUICtrlSetState( $aRects[$i][0], $GUI_SHOW )
      Next
      $fRedraw = False
    EndIf

    ; Current label
    $idLabel = $aInfo[4]
    If Not $idLabel Then ContinueLoop

    ; Current rectangle (moving rectangle)
    $iCurRect = ( $idLabel - $aRects[0][0] ) / 5
    ConsoleWrite( "Current rectangle: " & $iCurRect & @CRLF )

    ; Calculate boundaries (red dotted lines) for all stationary rectangles to detect collisions.
    ; Collisions against stationary rectangles are detected with moving rectangle upper/left corner.
    Local $iStatRects = 0, $j = 0
    For $i = 0 To $iRects - 1
      If $i = $iCurRect Then ContinueLoop
      $aDotRects[$j][0] = $aRects[$i][1] - $aRects[$iCurRect][3] ; $x1
      $aDotRects[$j][1] = $aRects[$i][2] - $aRects[$iCurRect][4] ; $y1
      $aDotRects[$j][2] = $aRects[$i][1] + $aRects[$i][3]        ; $x2
      $aDotRects[$j][3] = $aRects[$i][2] + $aRects[$i][4]        ; $y2
      $j += 1
    Next
    $iStatRects = $j

    ; Calculate boundaries (red dotted lines) to detect collisions against window edges.
    ; Collisions against window edges are detected with moving rectangle upper/left corner.
    Local $wx = $aRects[$iCurRect][5] + 2, $wy = $aRects[$iCurRect][6] + 2

    ; Variables to calculate upper/left corner ($x,$y) of moving rectangle
    Local $x0 = $aInfo[0], $y0 = $aInfo[1], $x, $y
    Local $x1 = $aRects[$iCurRect][1] - $x0, $y1 = $aRects[$iCurRect][2] - $y0

    ; Variables for collision action (flashing black/white rectangle)
    Local $hTimer = 0, $iCollRect, $idLblCollision, $idLblColor, $iColor = 0xFFFFFF

    ; Move current rectangle
    While $aInfo[2]
      $aInfo = GUIGetCursorInfo()
      $x = $x1 + $aInfo[0]
      $y = $y1 + $aInfo[1]

      ; Collision against window edges?
      ; (Collision if upper/left corner of moving rectangle ($x,$y) is outside the (0,0,$wx,$wy) rectangle)
      If Not ( 0 <= $x And $x < $wx And 0 <= $y And $y < $wy ) Then ContinueLoop

      ; Collision against stationary rectangles?
      ; (Collision if upper/left corner of moving rectangle ($x,$y) is inside the $aDotRects rectangles)
      For $i = 0 To $iStatRects - 1
        If $aDotRects[$i][0] < $x And $x < $aDotRects[$i][2] And $aDotRects[$i][1] < $y And $y < $aDotRects[$i][3] Then ExitLoop
      Next

      If $i < $iStatRects Then
        ; Collision ($i < $iStatRects => ExitLoop has been executed)
        If Not $hTimer Then
          ; Information about the collision
          $iCollRect = $i < $iCurRect ? $i : $i + 1
          CollisionInfo( $x, $y, $iCurRect, $iCollRect )
          ; Start collision action (flashing rectangle)
          $idLblCollision = $aRects[$iCollRect][0]
          $idLblColor = $aRects[$iCollRect][7]
          GUICtrlSetBkColor( $idLblCollision, $iColor )
          GUICtrlSetState( $idLblCollision, $GUI_HIDE ) ; Force a label repaint
          GUICtrlSetState( $idLblCollision, $GUI_SHOW )
          $iColor = $iColor ? 0x000000 : 0xFFFFFF
          $hTimer = TimerInit()
        ElseIf TimerDiff( $hTimer ) > 200 Then
          ; Continue flashing the rectangle
          GUICtrlSetBkColor( $idLblCollision, $iColor )
          GUICtrlSetState( $idLblCollision, $GUI_HIDE ) ; Force a label repaint
          GUICtrlSetState( $idLblCollision, $GUI_SHOW )
          $iColor = $iColor ? 0x000000 : 0xFFFFFF
          $hTimer = TimerInit()
        EndIf
        ; Add code to execute on collision here
        ;ContinueLoop ; Skip GUICtrlSetPos below
      ElseIf $hTimer Then
        ; No collision
        ; If collision action is started then stop it
        $hTimer = 0
        GUICtrlSetBkColor( $idLblCollision, $idLblColor )
        GUICtrlSetState( $idLblCollision, $GUI_HIDE )        ; Flashing rectangle
        GUICtrlSetState( $idLblCollision, $GUI_SHOW )        ; Force a label repaint
        GUICtrlSetBkColor( $idLabel, $aRects[$iCurRect][7] ) ; Moving rectangle
        GUICtrlSetState( $idLabel, $GUI_HIDE )               ; Force a label repaint
        GUICtrlSetState( $idLabel, $GUI_SHOW )
      EndIf

      ; Set new position of current rectangle
      GUICtrlSetPos( $idLabel, $x, $y )
    WEnd

    ; Store new position of current rectangle
    $aRects[$iCurRect][1] += $aInfo[0] - $x0
    $aRects[$iCurRect][2] += $aInfo[1] - $y0
  WEnd
EndFunc

Func CollisionInfo( $x, $y, $iCurRect, $iCollRect )
  ConsoleWrite( "Collision against rect: " & $iCollRect & @CRLF )
  Select
    Case $x + $aRects[$iCurRect][3] - $aRects[$iCollRect][1] < 4      ; Left edge
      Select
        Case $y + $aRects[$iCurRect][4] - $aRects[$iCollRect][2] < 4  ; Upper edge
          ConsoleWrite( "    At upper/left corner" & @CRLF )
        Case $aRects[$iCollRect][2] + $aRects[$iCollRect][4] - $y < 4 ; Lower edge
          ConsoleWrite( "    At lower/left corner" & @CRLF )
        Case Else
          ConsoleWrite( "    At left edge" & @CRLF )
      EndSelect
    Case $y + $aRects[$iCurRect][4] - $aRects[$iCollRect][2] < 4      ; Upper edge
      Select
        Case $x + $aRects[$iCurRect][3] - $aRects[$iCollRect][1] < 4  ; Left edge
          ConsoleWrite( "    At upper/left corner" & @CRLF )
        Case $aRects[$iCollRect][1] + $aRects[$iCollRect][3] - $x < 4 ; Right edge
          ConsoleWrite( "    At upper/right corner" & @CRLF )
        Case Else
          ConsoleWrite( "    At upper edge" & @CRLF )
      EndSelect
    Case $aRects[$iCollRect][1] + $aRects[$iCollRect][3] - $x < 4     ; Right edge
      Select
        Case $y + $aRects[$iCurRect][4] - $aRects[$iCollRect][2] < 4  ; Upper edge
          ConsoleWrite( "    At upper/right corner" & @CRLF )
        Case $aRects[$iCollRect][2] + $aRects[$iCollRect][4] - $y < 4 ; Lower edge
          ConsoleWrite( "    At lower/right corner" & @CRLF )
        Case Else
          ConsoleWrite( "    At right edge" & @CRLF )
      EndSelect
    Case $aRects[$iCollRect][2] + $aRects[$iCollRect][4] - $y < 4     ; Lower edge
      Select
        Case $x + $aRects[$iCurRect][3] - $aRects[$iCollRect][1] < 4  ; Left edge
          ConsoleWrite( "    At lower/left corner" & @CRLF )
        Case $aRects[$iCollRect][1] + $aRects[$iCollRect][3] - $x < 4 ; Right edge
          ConsoleWrite( "    At lower/right corner" & @CRLF )
        Case Else
          ConsoleWrite( "    At lower edge" & @CRLF )
      EndSelect
  EndSelect
EndFunc

Func CreateRectangle()
  If $fRedraw Then
    ; Erase red dotted rectangles if any exists
    _WinAPI_RedrawWindow( $hGui, 0, 0, $RDW_INVALIDATE + $RDW_ERASE )
    $fRedraw = False
  EndIf

  ; Wait max. 2 seconds to start rectangle creation
  WinSetTitle( $hGui, "", "Click and drag rectangle with primary mouse button" )
  Local $iWait = 0
  While Sleep(10)
    $iWait += 1
    If $iWait = 200 Then
      WinSetTitle( $hGui, "", "Rectangle collision detection" )
      Return
    EndIf
    If GUIGetCursorInfo()[2] Then ExitLoop
  WEnd
  WinSetTitle( $hGui, "", "Rectangle collision detection" )

  ; Create rectangle (label control)
  Local $aInfo = GUIGetCursorInfo(), $x = $aInfo[0], $y = $aInfo[1], $w = 0, $h = 0, $dw, $dh
  Local $iColor = Random(0,255,1)*256*256 + Random(0,255,1)*256 + Random(0,255,1)
  Local $idLabel = GUICtrlCreateLabel( "", $x, $y, $w, $h )
  GUICtrlSetResizing( $idLabel, $GUI_DOCKALL )
  GUICtrlSetBkColor( $idLabel, $iColor )
  ; Drag with mouse to define rectangle size until it's at least 4x4 pixels
  While $aInfo[2] And ( $dw < 4 Or $dh < 4 )
    $aInfo = GUIGetCursorInfo()
    $dw = $aInfo[0] - $x
    $dh = $aInfo[1] - $y
    If $dw < 200 Then $w = $dw
    If $dh < 200 Then $h = $dh
    GUICtrlSetPos( $idLabel, $x, $y, $w, $h )
    Sleep(10)
  WEnd
  ; Drag with mouse to define rectangle size between 4x4 and 200x200 pixels
  While $aInfo[2]
    $aInfo = GUIGetCursorInfo()
    $dw = $aInfo[0] - $x
    $dh = $aInfo[1] - $y
    If 4 < $dw And $dw < 200 Then $w = $dw
    If 4 < $dh And $dh < 200 Then $h = $dh
    GUICtrlSetPos( $idLabel, $x, $y, $w, $h )
    Sleep(10)
  WEnd
  ; Cancel if not rectangle size is between 4x4 and 200x200 pixels
  If Not ( 4 < $w And $w < 200 And 4 < $h And $h < 200 And $iRects < 100 ) Then
    GUICtrlDelete( $idLabel )
    Return
  EndIf

  ; Create and store rectangle info in $aRects
  CreateRectInfo( $x, $y, $w, $h, $idLabel, $iColor )
EndFunc

Func CreateMultipleRects()
  If $fRedraw Then
    ; Erase red dotted rectangles if any exists
    _WinAPI_RedrawWindow( $hGui, 0, 0, $RDW_INVALIDATE + $RDW_ERASE )
    $fRedraw = False
  EndIf

  ; Delete all rectangles
  DeleteAllRects()

  ; Number of rectangles
  Local $n, $hw = 200
  Switch @GUI_CtrlId
    Case $idGuiMenuItem1
      $n = 5
    Case $idGuiMenuItem2
      $n = 10
    Case $idGuiMenuItem3
      $n = 20
    Case $idGuiMenuItem4
      $n = 30
    Case $idGuiMenuItem5
      $n = 40
    Case $idGuiMenuItem6
      $n = 50
    Case $idGuiMenuItem7
      $n = 100
      $hw = 100
    Case $idGuiMenuItem8
      $n = 1000
      $hw = 20
  EndSwitch

  ; Create rectangles
  Local $x = 10, $y = 10, $yMax = 0, $w, $h
  For $i = 0 To $n - 1
    ; Rectangle width/height
    $w = Random(4,$hw,1)
    $h = Random(4,$hw,1)
    If $x + $w > $iGuiWidth Then
      ; New row of rectangles
      $x = 10
      $y = $yMax + 10
    EndIf
    If $y + $h > $iGuiHeight Then
      ; Cancel if GUI too small for all rectangles
      ConsoleWrite( "Created rectangles: " & $i & @CRLF )
      Return
    EndIf
    ; Create rectangle
    Local $iColor = Random(0,255,1)*256*256 + Random(0,255,1)*256 + Random(0,255,1)
    Local $idLabel = GUICtrlCreateLabel( "", $x, $y, $w, $h )
    GUICtrlSetResizing( $idLabel, $GUI_DOCKALL )
    GUICtrlSetBkColor( $idLabel, $iColor )
    CreateRectInfo( $x, $y, $w, $h, $idLabel, $iColor )
    GUICtrlSetState( $idLabel, $GUI_HIDE ) ; Force a label repaint
    GUICtrlSetState( $idLabel, $GUI_SHOW )
    ; Update $yMax and $x
    If $y + $h > $yMax Then $yMax = $y + $h
    $x += $w + 10
  Next
  ConsoleWrite( "Created rectangles: " & $n & @CRLF )
EndFunc

; Create and store rectangle info in $aRects
Func CreateRectInfo( $x, $y, $w, $h, $idLabel, $iColor )
  Local $idMenu = GUICtrlCreateContextMenu( $idLabel ) ; Debug menu
  Local $idMenuItem1 = GUICtrlCreateMenuItem( "Rectangle information", $idMenu )
  Local $idMenuItem2 = GUICtrlCreateMenuItem( "Window collision boundaries", $idMenu )
  Local $idMenuItem3 = GUICtrlCreateMenuItem( "Rectangles collision boundaries", $idMenu )
  GUICtrlSetOnEvent( $idMenuItem1, "RectangleInformation" )
  GUICtrlSetOnEvent( $idMenuItem2, "DrawWinCollisionBounds" )
  GUICtrlSetOnEvent( $idMenuItem3, "DrawRectsCollisionBounds" )
  $aRects[$iRects][0] = $idLabel
  $aRects[$iRects][1] = $x ; Pos
  $aRects[$iRects][2] = $y
  $aRects[$iRects][3] = $w ; Size
  $aRects[$iRects][4] = $h
  $aRects[$iRects][5] = $iGuiWidth - $w ; Window collision boundaries
  $aRects[$iRects][6] = $iGuiHeight - $h
  $aRects[$iRects][7] = $iColor
  $iRects += 1
EndFunc

Func DeleteAllRects()
  For $i = 0 To $iRects - 1
    GUICtrlDelete( $aRects[$i][0] )   ; $idLabel
    GUICtrlDelete( $aRects[$i][0]+1 ) ; $idMenu
    GUICtrlDelete( $aRects[$i][0]+2 ) ; $idMenuItem1
    GUICtrlDelete( $aRects[$i][0]+3 ) ; $idMenuItem2
    GUICtrlDelete( $aRects[$i][0]+4 ) ; $idMenuItem3
  Next
  $iRects = 0
EndFunc

; If the window is resized, the col-
; lision boundaries must be recalculated.
Func Resized()
  Local $aSize = WinGetClientSize( $hGui )
  $iGuiWidth = $aSize[0]
  $iGuiHeight = $aSize[1]
  For $i = 0 To $iRects - 1
    $aRects[$i][5] = $iGuiWidth - $aRects[$i][3] ; Window collision boundaries
    $aRects[$i][6] = $iGuiHeight - $aRects[$i][4]
  Next
EndFunc

Func Close()
  GUIDelete()
  Exit
EndFunc

; --- Debug functions --------------------------------------------------------------------------------------------------

; Rectangle information in SciTE console
Func RectangleInformation()
  If Not $aInfo[4] Then Return                                                       ; $idLabel (current rectangle)
  Local $iCurRect = ( $aInfo[4] - $aRects[0][0] ) / 5                                ; Current rectangle as index in $aRects
  If $fRedraw Then _WinAPI_RedrawWindow( $hGui, 0, 0, $RDW_INVALIDATE + $RDW_ERASE ) ; Erase previous red dotted rectangles
  ConsoleWrite( "Current rectangle: " & $iCurRect & @CRLF )
  ConsoleWrite( "    $idLabel: " & $aRects[$iCurRect][0] & @CRLF )
  ConsoleWrite( "    ($x,$y):  (" & $aRects[$iCurRect][1] & "," & $aRects[$iCurRect][2] & ")" & @CRLF )
  ConsoleWrite( "    ($w,$h):  (" & $aRects[$iCurRect][3] & "," & $aRects[$iCurRect][4] & ")" & @CRLF )
  ConsoleWrite( "    $iColor:  " & "0x" & Hex( $aRects[$iCurRect][7], 6 ) & @CRLF )
  $fRedraw = False
EndFunc

; Draw red dotted lines that shows the
; collision boundaries to the window edges.
Func DrawWinCollisionBounds()
  If Not $aInfo[4] Then Return                                                       ; $idLabel (current rectangle)
  Local $iCurRect = ( $aInfo[4] - $aRects[0][0] ) / 5                                ; Current rectangle as index in $aRects
  If $fRedraw Then _WinAPI_RedrawWindow( $hGui, 0, 0, $RDW_INVALIDATE + $RDW_ERASE ) ; Erase previous red dotted rectangles
  DrawRedDottedRect( 0, 0, $aRects[$iCurRect][5], $aRects[$iCurRect][6] ) ; 0, 0, $wx, $wy
EndFunc

; Draw red dotted lines that shows the
; collision boundaries to other rectangles.
Func DrawRectsCollisionBounds()
  If Not $aInfo[4] Then Return                                                       ; $idLabel (current rectangle)
  Local $iCurRect = ( $aInfo[4] - $aRects[0][0] ) / 5                                ; Current rectangle as index in $aRects
  If $fRedraw Then _WinAPI_RedrawWindow( $hGui, 0, 0, $RDW_INVALIDATE + $RDW_ERASE ) ; Erase previous red dotted rectangles
  For $i = 0 To $iRects - 1
    If $i = $iCurRect Then ContinueLoop
    DrawRedDottedRect( $aRects[$i][1] - $aRects[$iCurRect][3], _ ; $x1
                       $aRects[$i][2] - $aRects[$iCurRect][4], _ ; $y1
                       $aRects[$i][1] + $aRects[$i][3], _        ; $x2
                       $aRects[$i][2] + $aRects[$i][4] )         ; $y2
  Next
EndFunc

Func DrawRedDottedRect( $p1x, $p1y, $p2x, $p2y )
  Local $x1 = $p1x + $iBorderWidth - 1, $y1 = $p1y + $iTitleBarHeight - 1, $x2 = $p2x + $iBorderWidth, $y2 = $p2y + $iTitleBarHeight
  Local $hDC = _WinAPI_GetWindowDC( $hGui ), $hPen = _WinAPI_CreatePen( $PS_DOT, 1, 0x0000FF ), $hObj = _WinAPI_SelectObject( $hDC, $hPen )
  _WinAPI_DrawLine( $hDC, $x1, $y1, $x2, $y1 )
  _WinAPI_DrawLine( $hDC, $x2, $y1, $x2, $y2 )
  _WinAPI_DrawLine( $hDC, $x2, $y2, $x1, $y2 )
  _WinAPI_DrawLine( $hDC, $x1, $y2, $x1, $y1 )
  _WinAPI_SelectObject( $hDC, $hObj )
  _WinAPI_DeleteObject( $hPen )
  _WinAPI_ReleaseDC( $hGui, $hDC )
  $fRedraw = True
EndFunc

Secondary click in window to create rectangles.
Secondary click a rectangle to draw red dotted collision boundaries.
Primary click and drag to move a rectangle.

The loop to test collisions with the moving rectangle against the stationary rectangles is very simple and very fast:

; Collision against stationary rectangles?
; (Collision if upper/left corner of moving rectangle ($x,$y) is inside the $aDotRects rectangles)
For $i = 0 To $iStatRects - 1
  If $aDotRects[$i][0] < $x And $x < $aDotRects[$i][2] And $aDotRects[$i][1] < $y And $y < $aDotRects[$i][3] Then ExitLoop
Next

On my old XP i can test collisions against 1000 stationary rectangles in about 2.5 milliseconds.

Edited by LarsJ

Share this post


Link to post
Share on other sites

Thanks for your very cool example. I have not been able to figure it all out, but believe I got the basic understanding. But I still have the same issue. I believe your way is probably faster, though I have not tested any for quickness.

The issue, is that the when you stop the interaction, the moving box (rectangle) from hitting the stationary box, the issue arises, where to put the box. If I use your ContinueLoop, in the for loop, it stops the box from hitting, but as in the other examples the box does not always stop at the same place - like there is a lag, and the mouse continues to move across the box, while the box stops short or right next to the collision point. Meaning there is no consistent resting point for the moving box and it will stop anywhere near the collision point. Maybe the issue might be resolved by keeping the mouse stationary during moving (and primary button pressed), and stop moving at point of collision? If not, I am still looking at the conditions being meant to move the moving box, to its final resting point, not to exceed the boundaries of the collision.

I have no clue if I am making it clear what I am seeing.


All by me:

"Sometimes you have to go back to where you started, to get to where you want to go." 

"Everybody catches up with everyone, eventually" 

"As you teach others, you are really teaching yourself."

From my dad

"Do not worry about yesterday, as the only thing that you can control is tomorrow."

 

WindowsError.gif

WIKI | Tabs; | Arrays; | Strings | Wiki Arrays | How to ask a Question | Forum Search | FAQ | Tutorials | Original FAQ | ONLINE HELP | UDF's Wiki | AutoIt PDF

AutoIt Snippets | Multple Guis | Interrupting a running function | Another Send

StringRegExp | StringRegExp Help | RegEXTester | REG TUTOR | Reg TUTOT 2

AutoItSetOption | Macros | AutoIt Snippets | Wrapper | Autoit  Docs

SCITE | SciteJump | BB | MyTopics | Programming | UDFs | AutoIt 123 | UDFs Form | UDF

Learning to script | Tutorials | Documentation | IE.AU3 | Games? | FreeSoftware | Path_Online | Core Language

Programming Tips

Excel Changes

ControlHover.UDF

GDI_Plus

Draw_On_Screen

GDI Basics

GDI_More_Basics

GDI Rotate

GDI Graph

GDI  CheckExistingItems

GDI Trajectory

Replace $ghGDIPDll with $__g_hGDIPDll

DLL 101?

Array via Object

GDI Swimlane

GDI Plus French 101 Site

GDI Examples UEZ

GDI Basic Clock

GDI Detection

Ternary operator

Share this post


Link to post
Share on other sites

There is a lag. The rectangle will always be slightly behind the mouse. This is a consequence of AutoIt as an interpreted language. AutoIt is not fast enough. You need a compiled language to avoid the lag.

You have to set the position of the rectangle when you detect a collision to make sure that the rectangle is in a consistent state.


UEZ, You are welcome.

Share this post


Link to post
Share on other sites

I have had no luck setting the position, as it is still off one way or the other. I think the best bet is to have the mouse attach itself to the object/image/rectangle and then allow the mouse to move the object - this I believe would deal with the lag. I have done it by accident, a couple times, though I have no way to replicate it.

Does anyone know how to make the mouse attach, and then de-attach itself once set in the position (meaning the mouse if released)?


All by me:

"Sometimes you have to go back to where you started, to get to where you want to go." 

"Everybody catches up with everyone, eventually" 

"As you teach others, you are really teaching yourself."

From my dad

"Do not worry about yesterday, as the only thing that you can control is tomorrow."

 

WindowsError.gif

WIKI | Tabs; | Arrays; | Strings | Wiki Arrays | How to ask a Question | Forum Search | FAQ | Tutorials | Original FAQ | ONLINE HELP | UDF's Wiki | AutoIt PDF

AutoIt Snippets | Multple Guis | Interrupting a running function | Another Send

StringRegExp | StringRegExp Help | RegEXTester | REG TUTOR | Reg TUTOT 2

AutoItSetOption | Macros | AutoIt Snippets | Wrapper | Autoit  Docs

SCITE | SciteJump | BB | MyTopics | Programming | UDFs | AutoIt 123 | UDFs Form | UDF

Learning to script | Tutorials | Documentation | IE.AU3 | Games? | FreeSoftware | Path_Online | Core Language

Programming Tips

Excel Changes

ControlHover.UDF

GDI_Plus

Draw_On_Screen

GDI Basics

GDI_More_Basics

GDI Rotate

GDI Graph

GDI  CheckExistingItems

GDI Trajectory

Replace $ghGDIPDll with $__g_hGDIPDll

DLL 101?

Array via Object

GDI Swimlane

GDI Plus French 101 Site

GDI Examples UEZ

GDI Basic Clock

GDI Detection

Ternary operator

Share this post


Link to post
Share on other sites

When I set the position of the rectangle with this code, I can do it quite accurate and consistent. Even for rapid mouse movements.

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>

AutoItSetOption( "GUIOnEventMode",  1 )
AutoItSetOption( "MouseCoordMode",  2 ) ; Relative to window
AutoItSetOption( "MustDeclareVars", 1 )
AutoItSetOption( "WinWaitDelay",   10 )

; Only used to draw debug info
Global Const $iTitleBarHeight = 30
Global Const $iBorderWidth    = _WinAPI_GetSystemMetrics( $SM_CXFRAME )

Global $hGui, $iGuiWidth, $iGuiHeight, $aInfo, $fRedraw = False
Global $idGuiMenuItem0, $idGuiMenuItem1, $idGuiMenuItem2, $idGuiMenuItem3, $idGuiMenuItem4, _
       $idGuiMenuItem5, $idGuiMenuItem6, $idGuiMenuItem7, $idGuiMenuItem8, $idGuiMenuItem9

; Information about the rectangles
Global $aRects[1000][8], $iRects = 0
;     0: $idLabel
; 1 - 4: $x, $y, $w, $h ; Pos, size
; 5 - 6: $wx, $wy       ; Window collision boundaries
;     7: $iColor

Example()

Func Example()
  ; Create GUI
  $hGui = GUICreate( "Rectangle collision detection", 800, 600, -1, -1, $WS_OVERLAPPEDWINDOW - $WS_MAXIMIZEBOX + $WS_CLIPCHILDREN )
  GUISetOnEvent( $GUI_EVENT_RESIZED, "Resized" )
  GUISetOnEvent( $GUI_EVENT_CLOSE, "Close" )

  ; Window context menu
  Local $idGuiMenu = GUICtrlCreateContextMenu()
  $idGuiMenuItem0 = GUICtrlCreateMenuItem( "Create rectangle", $idGuiMenu )
  $idGuiMenuItem1 = GUICtrlCreateMenuItem( "Create 5 rects",  $idGuiMenu )
  $idGuiMenuItem2 = GUICtrlCreateMenuItem( "Create 10 rects", $idGuiMenu )
  $idGuiMenuItem3 = GUICtrlCreateMenuItem( "Create 20 rects", $idGuiMenu )
  $idGuiMenuItem4 = GUICtrlCreateMenuItem( "Create 30 rects", $idGuiMenu )
  $idGuiMenuItem5 = GUICtrlCreateMenuItem( "Create 40 rects", $idGuiMenu )
  $idGuiMenuItem6 = GUICtrlCreateMenuItem( "Create 50 rects", $idGuiMenu )
  $idGuiMenuItem7 = GUICtrlCreateMenuItem( "Create 100 rects", $idGuiMenu )
  $idGuiMenuItem8 = GUICtrlCreateMenuItem( "Create 1000 rects", $idGuiMenu )
  $idGuiMenuItem9 = GUICtrlCreateMenuItem( "Delete all rectangles", $idGuiMenu )
  GUICtrlSetOnEvent( $idGuiMenuItem0, "CreateRectangle" )
  GUICtrlSetOnEvent( $idGuiMenuItem1, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem2, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem3, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem4, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem5, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem6, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem7, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem8, "CreateMultipleRects" )
  GUICtrlSetOnEvent( $idGuiMenuItem9, "DeleteAllRects" )

  ; Window size
  Local $aSize = WinGetClientSize( $hGui )
  $iGuiWidth = $aSize[0]
  $iGuiHeight = $aSize[1]

  ; Show GUI
  GUISetState()

  MsgBox( 0, "Rectangle collision detection", _
          "Secondary click to open context menu with items to create rectangles (random colored labels)." & @CRLF & _
          "Click and drag with primary mouse button to define size of rectangle (limited to 4x4 - 200x200)." & @CRLF & @CRLF & _
          "Click and drag a rectangle with primary mouse button to check collisions against window borders" & @CRLF & _
          "and stationary rectangles." & @CRLF & @CRLF & _
          "Secondary click a rectangle to open context menu to draw lines that shows collision boundaries." & @CRLF & _
          "Collisions against window borders and stationary rectangles are detected with moving rectangle" & @CRLF & _
          "upper/left corner. Click in free area to erase the red dotted lines that shows collision boundaries.", 0, $hGui )

  Local $idLabel, $iCurRect, $aDotRects[1000][4]

  While 1
    ; Wait for primary mouse click
    $aInfo = GUIGetCursorInfo()
    While Sleep(10) And IsArray( $aInfo ) And Not $aInfo[2]
      $aInfo = GUIGetCursorInfo()
    WEnd
    If Not IsArray( $aInfo ) Then ContinueLoop

    ; Redraw window?
    ; (Erase dotted rectangles)
    If $fRedraw Then
      ; Erase dotted rectangles
      _WinAPI_RedrawWindow( $hGui, 0, 0, $RDW_INVALIDATE + $RDW_ERASE )
      ; Repaint labels
      For $i = 0 To $iRects - 1
        GUICtrlSetState( $aRects[$i][0], $GUI_HIDE ) ; Force a label repaint
        GUICtrlSetState( $aRects[$i][0], $GUI_SHOW )
      Next
      $fRedraw = False
    EndIf

    ; Current label
    $idLabel = $aInfo[4]
    If Not $idLabel Then ContinueLoop

    ; Current rectangle (moving rectangle)
    $iCurRect = ( $idLabel - $aRects[0][0] ) / 5
    ConsoleWrite( "Current rectangle: " & $iCurRect & @CRLF )

    ; Calculate boundaries (red dotted lines) for all stationary rectangles to detect collisions.
    ; Collisions against stationary rectangles are detected with moving rectangle upper/left corner.
    Local $iStatRects = 0, $j = 0
    For $i = 0 To $iRects - 1
      If $i = $iCurRect Then ContinueLoop
      $aDotRects[$j][0] = $aRects[$i][1] - $aRects[$iCurRect][3] ; $x1
      $aDotRects[$j][1] = $aRects[$i][2] - $aRects[$iCurRect][4] ; $y1
      $aDotRects[$j][2] = $aRects[$i][1] + $aRects[$i][3]        ; $x2
      $aDotRects[$j][3] = $aRects[$i][2] + $aRects[$i][4]        ; $y2
      $j += 1
    Next
    $iStatRects = $j

    ; Calculate boundaries (red dotted lines) to detect collisions against window edges.
    ; Collisions against window edges are detected with moving rectangle upper/left corner.
    Local $wx = $aRects[$iCurRect][5] + 2, $wy = $aRects[$iCurRect][6] + 2

    ; Variables to calculate upper/left corner ($x,$y) of moving rectangle
    Local $x0 = $aInfo[0], $y0 = $aInfo[1], $x, $y
    Local $x1 = $aRects[$iCurRect][1] - $x0, $y1 = $aRects[$iCurRect][2] - $y0

    ; Variables for collision action (position moving rectangle at collision edge)
    Local $fCollision = 0, $iCollRect, $iCollEdge, $xColl, $yColl

    ; Move current rectangle
    While $aInfo[2]
      $aInfo = GUIGetCursorInfo()
      $x = $x1 + $aInfo[0]
      $y = $y1 + $aInfo[1]

      ; Collision against window edges?
      ; (Collision if upper/left corner of moving rectangle ($x,$y) is outside the (0,0,$wx,$wy) rectangle)
      If Not ( 0 <= $x And $x < $wx And 0 <= $y And $y < $wy ) Then ContinueLoop

      ; Collision against stationary rectangles?
      ; (Collision if upper/left corner of moving rectangle ($x,$y) is inside the $aDotRects rectangles)
      For $i = 0 To $iStatRects - 1
        If $aDotRects[$i][0] < $x And $x < $aDotRects[$i][2] And $aDotRects[$i][1] < $y And $y < $aDotRects[$i][3] Then ExitLoop
      Next

      If $i < $iStatRects Then
        ; Collision ($i < $iStatRects => ExitLoop has been executed)
        If Not $fCollision Then
          ; Information about the collision
          $iCollRect = $i < $iCurRect ? $i : $i + 1
          $iCollEdge = CollisionInfo( $x, $y, $iCurRect, $iCollRect )
          Switch $iCollEdge
            Case 1 ; Left
              $xColl = $aRects[$iCollRect][1] - $aRects[$iCurRect][3]
            Case 2 ; Upper
              $yColl = $aRects[$iCollRect][2] - $aRects[$iCurRect][4]
            Case 3 ; Right
              $xColl = $aRects[$iCollRect][1] + $aRects[$iCollRect][3]
            Case 4 ; Lower
              $yColl = $aRects[$iCollRect][2] + $aRects[$iCollRect][4]
          EndSwitch
          $fCollision = 1
        EndIf
        Switch $iCollEdge
          Case 1, 3 ; Left, Right
            GUICtrlSetPos( $idLabel, $xColl, $y )
          Case 2, 4 ; Upper, Lower
            GUICtrlSetPos( $idLabel, $x, $yColl )
        EndSwitch
        ContinueLoop
      ElseIf $fCollision Then
        ; No collision
        $fCollision = 0
      EndIf

      ; Set new position of current rectangle
      GUICtrlSetPos( $idLabel, $x, $y )
    WEnd

    ; Store new position of current rectangle
    If $fCollision Then
      Switch $iCollEdge
        Case 1, 3 ; Left, Right
          $aRects[$iCurRect][1] = $xColl
          $aRects[$iCurRect][2] += $aInfo[1] - $y0
        Case 2, 4 ; Upper, Lower
          $aRects[$iCurRect][1] += $aInfo[0] - $x0
          $aRects[$iCurRect][2] = $yColl
      EndSwitch
    Else
      $aRects[$iCurRect][1] += $aInfo[0] - $x0
      $aRects[$iCurRect][2] += $aInfo[1] - $y0
    EndIf
  WEnd
EndFunc

Func CollisionInfo( $x, $y, $iCurRect, $iCollRect )
  ConsoleWrite( "Collision against rect: " & $iCollRect & @CRLF )
  Select
    Case $x + $aRects[$iCurRect][3] - $aRects[$iCollRect][1] < 20  ; Left edge ; Use a high value (20) to compensate for rapid mouse movements
      ConsoleWrite( "    At left edge" & @CRLF )
      Return 1
    Case $y + $aRects[$iCurRect][4] - $aRects[$iCollRect][2] < 20  ; Upper edge
      ConsoleWrite( "    At upper edge" & @CRLF )
      Return 2
    Case $aRects[$iCollRect][1] + $aRects[$iCollRect][3] - $x < 20 ; Right edge
      ConsoleWrite( "    At right edge" & @CRLF )
      Return 3
    Case $aRects[$iCollRect][2] + $aRects[$iCollRect][4] - $y < 20 ; Lower edge
      ConsoleWrite( "    At lower edge" & @CRLF )
      Return 4
  EndSelect
EndFunc

Func CreateRectangle()
  If $fRedraw Then
    ; Erase red dotted rectangles if any exists
    _WinAPI_RedrawWindow( $hGui, 0, 0, $RDW_INVALIDATE + $RDW_ERASE )
    $fRedraw = False
  EndIf

  ; Wait max. 2 seconds to start rectangle creation
  WinSetTitle( $hGui, "", "Click and drag rectangle with primary mouse button" )
  Local $iWait = 0
  While Sleep(10)
    $iWait += 1
    If $iWait = 200 Then
      WinSetTitle( $hGui, "", "Rectangle collision detection" )
      Return
    EndIf
    If GUIGetCursorInfo()[2] Then ExitLoop
  WEnd
  WinSetTitle( $hGui, "", "Rectangle collision detection" )

  ; Create rectangle (label control)
  Local $aInfo = GUIGetCursorInfo(), $x = $aInfo[0], $y = $aInfo[1], $w = 0, $h = 0, $dw, $dh
  Local $iColor = Random(0,255,1)*256*256 + Random(0,255,1)*256 + Random(0,255,1)
  Local $idLabel = GUICtrlCreateLabel( "", $x, $y, $w, $h )
  GUICtrlSetResizing( $idLabel, $GUI_DOCKALL )
  GUICtrlSetBkColor( $idLabel, $iColor )
  ; Drag with mouse to define rectangle size until it's at least 4x4 pixels
  While $aInfo[2] And ( $dw < 4 Or $dh < 4 )
    $aInfo = GUIGetCursorInfo()
    $dw = $aInfo[0] - $x
    $dh = $aInfo[1] - $y
    If $dw < 200 Then $w = $dw
    If $dh < 200 Then $h = $dh
    GUICtrlSetPos( $idLabel, $x, $y, $w, $h )
    Sleep(10)
  WEnd
  ; Drag with mouse to define rectangle size between 4x4 and 200x200 pixels
  While $aInfo[2]
    $aInfo = GUIGetCursorInfo()
    $dw = $aInfo[0] - $x
    $dh = $aInfo[1] - $y
    If 4 < $dw And $dw < 200 Then $w = $dw
    If 4 < $dh And $dh < 200 Then $h = $dh
    GUICtrlSetPos( $idLabel, $x, $y, $w, $h )
    Sleep(10)
  WEnd
  ; Cancel if not rectangle size is between 4x4 and 200x200 pixels
  If Not ( 4 < $w And $w < 200 And 4 < $h And $h < 200 And $iRects < 100 ) Then
    GUICtrlDelete( $idLabel )
    Return
  EndIf

  ; Create and store rectangle info in $aRects
  CreateRectInfo( $x, $y, $w, $h, $idLabel, $iColor )
EndFunc

Func CreateMultipleRects()
  If $fRedraw Then
    ; Erase red dotted rectangles if any exists
    _WinAPI_RedrawWindow( $hGui, 0, 0, $RDW_INVALIDATE + $RDW_ERASE )
    $fRedraw = False
  EndIf

  ; Delete all rectangles
  DeleteAllRects()

  ; Number of rectangles
  Local $n, $hw = 200
  Switch @GUI_CtrlId
    Case $idGuiMenuItem1
      $n = 5
    Case $idGuiMenuItem2
      $n = 10
    Case $idGuiMenuItem3
      $n = 20
    Case $idGuiMenuItem4
      $n = 30
    Case $idGuiMenuItem5
      $n = 40
    Case $idGuiMenuItem6
      $n = 50
    Case $idGuiMenuItem7
      $n = 100
      $hw = 100
    Case $idGuiMenuItem8
      $n = 1000
      $hw = 20
  EndSwitch

  ; Create rectangles
  Local $x = 10, $y = 10, $yMax = 0, $w, $h
  For $i = 0 To $n - 1
    ; Rectangle width/height
    $w = Random(4,$hw,1)
    $h = Random(4,$hw,1)
    If $x + $w > $iGuiWidth Then
      ; New row of rectangles
      $x = 10
      $y = $yMax + 10
    EndIf
    If $y + $h > $iGuiHeight Then
      ; Cancel if GUI too small for all rectangles
      ConsoleWrite( "Created rectangles: " & $i & @CRLF )
      Return
    EndIf
    ; Create rectangle
    Local $iColor = Random(0,255,1)*256*256 + Random(0,255,1)*256 + Random(0,255,1)
    Local $idLabel = GUICtrlCreateLabel( "", $x, $y, $w, $h )
    GUICtrlSetResizing( $idLabel, $GUI_DOCKALL )
    GUICtrlSetBkColor( $idLabel, $iColor )
    CreateRectInfo( $x, $y, $w, $h, $idLabel, $iColor )
    GUICtrlSetState( $idLabel, $GUI_HIDE ) ; Force a label repaint
    GUICtrlSetState( $idLabel, $GUI_SHOW )
    ; Update $yMax and $x
    If $y + $h > $yMax Then $yMax = $y + $h
    $x += $w + 10
  Next
  ConsoleWrite( "Created rectangles: " & $n & @CRLF )
EndFunc

; Create and store rectangle info in $aRects
Func CreateRectInfo( $x, $y, $w, $h, $idLabel, $iColor )
  Local $idMenu = GUICtrlCreateContextMenu( $idLabel ) ; Debug menu
  Local $idMenuItem1 = GUICtrlCreateMenuItem( "Rectangle information", $idMenu )
  Local $idMenuItem2 = GUICtrlCreateMenuItem( "Window collision boundaries", $idMenu )
  Local $idMenuItem3 = GUICtrlCreateMenuItem( "Rectangles collision boundaries", $idMenu )
  GUICtrlSetOnEvent( $idMenuItem1, "RectangleInformation" )
  GUICtrlSetOnEvent( $idMenuItem2, "DrawWinCollisionBounds" )
  GUICtrlSetOnEvent( $idMenuItem3, "DrawRectsCollisionBounds" )
  $aRects[$iRects][0] = $idLabel
  $aRects[$iRects][1] = $x ; Pos
  $aRects[$iRects][2] = $y
  $aRects[$iRects][3] = $w ; Size
  $aRects[$iRects][4] = $h
  $aRects[$iRects][5] = $iGuiWidth - $w ; Window collision boundaries
  $aRects[$iRects][6] = $iGuiHeight - $h
  $aRects[$iRects][7] = $iColor
  $iRects += 1
EndFunc

Func DeleteAllRects()
  For $i = 0 To $iRects - 1
    GUICtrlDelete( $aRects[$i][0] )   ; $idLabel
    GUICtrlDelete( $aRects[$i][0]+1 ) ; $idMenu
    GUICtrlDelete( $aRects[$i][0]+2 ) ; $idMenuItem1
    GUICtrlDelete( $aRects[$i][0]+3 ) ; $idMenuItem2
    GUICtrlDelete( $aRects[$i][0]+4 ) ; $idMenuItem3
  Next
  $iRects = 0
EndFunc

; If the window is resized, the col-
; lision boundaries must be recalculated.
Func Resized()
  Local $aSize = WinGetClientSize( $hGui )
  $iGuiWidth = $aSize[0]
  $iGuiHeight = $aSize[1]
  For $i = 0 To $iRects - 1
    $aRects[$i][5] = $iGuiWidth - $aRects[$i][3] ; Window collision boundaries
    $aRects[$i][6] = $iGuiHeight - $aRects[$i][4]
  Next
EndFunc

Func Close()
  GUIDelete()
  Exit
EndFunc

; --- Debug functions --------------------------------------------------------------------------------------------------

; Rectangle information in SciTE console
Func RectangleInformation()
  If Not $aInfo[4] Then Return                                                       ; $idLabel (current rectangle)
  Local $iCurRect = ( $aInfo[4] - $aRects[0][0] ) / 5                                ; Current rectangle as index in $aRects
  If $fRedraw Then _WinAPI_RedrawWindow( $hGui, 0, 0, $RDW_INVALIDATE + $RDW_ERASE ) ; Erase previous red dotted rectangles
  ConsoleWrite( "Current rectangle: " & $iCurRect & @CRLF )
  ConsoleWrite( "    $idLabel: " & $aRects[$iCurRect][0] & @CRLF )
  ConsoleWrite( "    ($x,$y):  (" & $aRects[$iCurRect][1] & "," & $aRects[$iCurRect][2] & ")" & @CRLF )
  ConsoleWrite( "    ($w,$h):  (" & $aRects[$iCurRect][3] & "," & $aRects[$iCurRect][4] & ")" & @CRLF )
  ConsoleWrite( "    $iColor:  " & "0x" & Hex( $aRects[$iCurRect][7], 6 ) & @CRLF )
  $fRedraw = False
EndFunc

; Draw red dotted lines that shows the
; collision boundaries to the window edges.
Func DrawWinCollisionBounds()
  If Not $aInfo[4] Then Return                                                       ; $idLabel (current rectangle)
  Local $iCurRect = ( $aInfo[4] - $aRects[0][0] ) / 5                                ; Current rectangle as index in $aRects
  If $fRedraw Then _WinAPI_RedrawWindow( $hGui, 0, 0, $RDW_INVALIDATE + $RDW_ERASE ) ; Erase previous red dotted rectangles
  DrawRedDottedRect( 0, 0, $aRects[$iCurRect][5], $aRects[$iCurRect][6] ) ; 0, 0, $wx, $wy
EndFunc

; Draw red dotted lines that shows the
; collision boundaries to other rectangles.
Func DrawRectsCollisionBounds()
  If Not $aInfo[4] Then Return                                                       ; $idLabel (current rectangle)
  Local $iCurRect = ( $aInfo[4] - $aRects[0][0] ) / 5                                ; Current rectangle as index in $aRects
  If $fRedraw Then _WinAPI_RedrawWindow( $hGui, 0, 0, $RDW_INVALIDATE + $RDW_ERASE ) ; Erase previous red dotted rectangles
  For $i = 0 To $iRects - 1
    If $i = $iCurRect Then ContinueLoop
    DrawRedDottedRect( $aRects[$i][1] - $aRects[$iCurRect][3], _ ; $x1
                       $aRects[$i][2] - $aRects[$iCurRect][4], _ ; $y1
                       $aRects[$i][1] + $aRects[$i][3], _        ; $x2
                       $aRects[$i][2] + $aRects[$i][4] )         ; $y2
  Next
EndFunc

Func DrawRedDottedRect( $p1x, $p1y, $p2x, $p2y )
  Local $x1 = $p1x + $iBorderWidth - 1, $y1 = $p1y + $iTitleBarHeight - 1, $x2 = $p2x + $iBorderWidth, $y2 = $p2y + $iTitleBarHeight
  Local $hDC = _WinAPI_GetWindowDC( $hGui ), $hPen = _WinAPI_CreatePen( $PS_DOT, 1, 0x0000FF ), $hObj = _WinAPI_SelectObject( $hDC, $hPen )
  _WinAPI_DrawLine( $hDC, $x1, $y1, $x2, $y1 )
  _WinAPI_DrawLine( $hDC, $x2, $y1, $x2, $y2 )
  _WinAPI_DrawLine( $hDC, $x2, $y2, $x1, $y2 )
  _WinAPI_DrawLine( $hDC, $x1, $y2, $x1, $y1 )
  _WinAPI_SelectObject( $hDC, $hObj )
  _WinAPI_DeleteObject( $hPen )
  _WinAPI_ReleaseDC( $hGui, $hDC )
  $fRedraw = True
EndFunc

I have been testing with two rectangles like these:

Post51_zpsfnwzsqew.png

The large rectangle is stationary.

nitekram, Have you tried to test collision detection only with the mouse pointer. When the mouse pointer is inside the rectangle, there is a collision. If you move the mouse really fast, you'll probably see, that the mouse pointer can be 20 - 30 pixels inside the rectangle, before the collision is detected. I don't think there is anything to do about this problem. You will need to address the problem in the code.

 

Edited by LarsJ

Share this post


Link to post
Share on other sites

I will have to take a look at this, as it has much better response than anything I tried.


All by me:

"Sometimes you have to go back to where you started, to get to where you want to go." 

"Everybody catches up with everyone, eventually" 

"As you teach others, you are really teaching yourself."

From my dad

"Do not worry about yesterday, as the only thing that you can control is tomorrow."

 

WindowsError.gif

WIKI | Tabs; | Arrays; | Strings | Wiki Arrays | How to ask a Question | Forum Search | FAQ | Tutorials | Original FAQ | ONLINE HELP | UDF's Wiki | AutoIt PDF

AutoIt Snippets | Multple Guis | Interrupting a running function | Another Send

StringRegExp | StringRegExp Help | RegEXTester | REG TUTOR | Reg TUTOT 2

AutoItSetOption | Macros | AutoIt Snippets | Wrapper | Autoit  Docs

SCITE | SciteJump | BB | MyTopics | Programming | UDFs | AutoIt 123 | UDFs Form | UDF

Learning to script | Tutorials | Documentation | IE.AU3 | Games? | FreeSoftware | Path_Online | Core Language

Programming Tips

Excel Changes

ControlHover.UDF

GDI_Plus

Draw_On_Screen

GDI Basics

GDI_More_Basics

GDI Rotate

GDI Graph

GDI  CheckExistingItems

GDI Trajectory

Replace $ghGDIPDll with $__g_hGDIPDll

DLL 101?

Array via Object

GDI Swimlane

GDI Plus French 101 Site

GDI Examples UEZ

GDI Basic Clock

GDI Detection

Ternary operator

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...