Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
error doing image collision detection with _MemGet
#33
Here's my collision code - see attached "MultiCustomFontsAndCollisions131.bas" for the full working program. 

To run around and shoot things, use the cursor keys and the right Ctrl key. Also it breaks if you choose both the max robots AND max big robots. If you want to see a lot of things moving and colliding, choose 127 robots and 3 or 4 big robots. 

First I'll explain that the graphics / sprites / etc. are all done with custom fixed-width fonts, drawn to the screen with _PrintString. It's possible to do "multicolor" sprites by layering 2 or more characters, so you will see the sprite type has members fgChar, bgChar, fgColor, bgColor, although this demo only really uses fgChar for single color "sprites". All graphics (fonts) are defined in text (makes it easy to edit without ever leaving the code) and are used to generate BDF font files on the fly everytime the program runs (this can be easily changed to only create the files if they're not found in the program folder, but I've been constantly editing and adding graphics so it's just easier to have it regenerate them, and it's fast enough that it doesn't cause any noticeable extra delay when the program starts).

To see the actual graphic definitons for the fonts, search in the code for these routines:

Code: (Select All)
' The base 8x8 font:
Sub GetTileText8x8 (arrTileText() As String)
...
' The special 8x8 character definitionss specific to this program:
Sub GetTileText8x8_Override (arrTileText() As String)
...
' The base 16x16 font:
Sub GetTileText16x16 (arrTileText() As String)
...
' The special 16x16 character definitionss specific to this program:
Sub GetTileText16x16_Override (arrTileText() As String)
...
' The base 32x32 font:
Sub GetTileText32x32 (arrTileText() As String)
...
' The special 32x32 character definitionss specific to this program:
Sub GetTileText32x32_Override (arrTileText() As String)
...
' The base 64x64 font:
Sub GetTileText64x64 (arrTileText() As String)
...
' The special 64x64 character definitionss specific to this program:
Sub GetTileText64x64_Override (arrTileText() As String)

Next, here are a couple UDTs and array definitions the collision detection uses:

Code: (Select All)

' USED BY PlayGame
Type MyFontType
    FontHandle As Long
    Height As Integer
    Width As Integer
    MaxRow As Integer
    MaxCol As Integer
End Type

' USED BY PlayGame
Type PixelInfoType
    pxCount As Long ' pixel count
    x1 As Long ' column first pixel is at
    x2 As Long ' column last pixel is at
    y1 As Long ' row first pixel is at
    y2 As Long ' row last pixel is at
End Type

    ReDim arrFont(0 To 3) As MyFontType '  arrFont(FontIndex) holds font handle, character dimensions, etc., for a custom fixed-width font
    ReDim arrPxInfo(0 To 3, 0 To 255) As PixelInfoType ' arrPxInfo(FontIndex, ChrCode), holds pixel count and edge info for each character 0-255 for 1 or more fonts
    ReDim arrBitMask(0 To 3, 0 To 255, 0 To 63, 0 To 63) As _Byte ' arrBitMask(FontIndex, ChrCode, LocalY, LocalX), holds true/false bitmask array for each character 0-255 for 1 or more fonts

This routine pre-populates the bit mask array for all characters/fonts that gets compared to detect overlapping pixels:

Code: (Select All)
' /////////////////////////////////////////////////////////////////////////////
' GET PIXEL COUNT + POPULATE BIT MASK ARRAY

' RECEIVES
' FontIndex as Integer = which font (index for arrFont, arrBitMask, arrPxInfo) to populate arrPxInfo & arrBitMask for
' arrFont(0 To 3) As MyFontType ' arrFont(FontIndex) holds font handle, character dimensions, etc., for a custom fixed-width font
' arrPxInfo(0 To 3, 0 To 255) As PixelInfoType ' arrPxInfo(FontIndex, ChrCode), holds pixel count and edge info for each character 0-255 for 1 or more fonts
' arrBitMask(0 To 3, 0 To 255, 0 To 63, 0 To 63) As _Byte ' arrBitMask(FontIndex, ChrCode, LocalY, LocalX), holds true/false bitmask array for each character 0-255 for 1 or more fonts

' FOR EACH CHARACTER:
' IMAGE IS BLANK IF: arrPxInfo(FontIndex, iChar).pxCount = 0
' LEFT-MOST   PIXEL: arrPxInfo(FontIndex, iChar).x1 ' NONE = _Width(MyImage)
' RIGHT-MOST  PIXEL: arrPxInfo(FontIndex, iChar).x2 ' NONE = -1
' TOP-MOST    PIXEL: arrPxInfo(FontIndex, iChar).y1 ' NONE = _Height(MyImage)
' BOTTOM-MOST PIXEL: arrPxInfo(FontIndex, iChar).y2 ' NONE = -1

Sub GetBitMask (FontIndex As Integer, arrFont() As MyFontType, arrPxInfo() As PixelInfoType, arrBitMask() As _Byte)
    Dim MyImage As Long
    Dim iChar As Integer
    Dim y As Integer
    Dim x As Integer
    Dim p1 As _Unsigned Long
   
    ' CREATE TEMP IMAGE
    InitImage MyImage, arrFont(FontIndex).Width, arrFont(FontIndex).Height, _RGBA32(0, 0, 0, 0)
    _Font arrFont(FontIndex).FontHandle ' SWITCH FONT
    _MapUnicode 32 To 32 ' FIX CHAR MAPPING (I WAS GETTING WEIRD CHARACTERS FOR SPACE)
    _MapUnicode 255 To 255 ' FIX CHAR MAPPING SO WE GET CHR$(255)

    ' GET BIT MASK ARRAY + PIXEL COUNT FOR ALL CHARACTER CODES 0-255 FOR THIS FONT
    For iChar = 0 To 255
        _Dest MyImage: Cls , _RGBA32(0, 0, 0, 0)
        Color _RGB32(0, 0, 0), _RGBA32(0, 0, 0, 0)
        _PrintString (0, 0), Chr$(iChar), MyImage

        ' INITIALIZE
        arrPxInfo(FontIndex, iChar).pxCount = 0
        arrPxInfo(FontIndex, iChar).x1 = _Width(MyImage)
        arrPxInfo(FontIndex, iChar).x2 = -1
        arrPxInfo(FontIndex, iChar).y1 = _Height(MyImage)
        arrPxInfo(FontIndex, iChar).y2 = -1
        For y = LBound(arrBitMask, 3) To UBound(arrBitMask, 3)
            For x = LBound(arrBitMask, 4) To UBound(arrBitMask, 4)
                arrBitMask(FontIndex, iChar, y, x) = _FALSE
            Next x
        Next y

        ' COUNT PIXELS + POPULATE BITMASK
        _Source MyImage
        For y = 0 To _Height(MyImage) - 1
            For x = 0 To _Width(MyImage) - 1
                p1 = Point(x, y)
                If _Alpha32(p1) > 0 Then
                    ' FIND EDGES (FIRST PIXEL ALONG TOP+LEFT EDGES + LAST PIXEL AT BOTTOM+RIGHT EDGES)
                    If y < arrPxInfo(FontIndex, iChar).y1 Then arrPxInfo(FontIndex, iChar).y1 = y
                    If y > arrPxInfo(FontIndex, iChar).y2 Then arrPxInfo(FontIndex, iChar).y2 = y
                    If x < arrPxInfo(FontIndex, iChar).x1 Then arrPxInfo(FontIndex, iChar).x1 = x
                    If x > arrPxInfo(FontIndex, iChar).x2 Then arrPxInfo(FontIndex, iChar).x2 = x
                   
                    ' COUNT PIXELS
                    arrPxInfo(FontIndex, iChar).pxCount = arrPxInfo(FontIndex, iChar).pxCount + 1
                   
                    ' MARK LOCATION IN BIT MASK ARRAY
                    arrBitMask(FontIndex, iChar, y, x) = _TRUE
                End If
            Next x
        Next y

    Next iChar

    ' FREE MEMORY
    FreeImage MyImage
End Sub ' GetBitMask

And finally, the collision detection routine:

Code: (Select All)

' /////////////////////////////////////////////////////////////////////////////
' Detect collision (regular bounding box test + bit mask overlap)

' Checks if the iSprite1's and iSprite2's bounding boxes overlap,
' if they do, compares bitmask arrays to determine if any pixels overlap,
' and returns _TRUE if collision detected or _FALSE if not.

' RECEIVES:
' iSprite1     = index in arrSprite of object #1 to check for collision
' iSprite2     = index in arrSprite of object #2 to check for collision
' arrSprite()  = array of type SpriteType containing the sprite details
' arrBitMask() = byte array containing _TRUE/_FALSE
'                for all pixels of all characters for all fonts
'                (used to check for pixel-perfect collision)

Function ShapesCollided% (iSprite1 As Integer, iSprite2 As Integer, arrSprite() As SpriteType, arrBitMask() As _Byte)
    Dim bCollision As Integer
    Dim iOverlapLeft As Long
    Dim iOverlapTop As Long
    Dim iOverlapRight As Long
    Dim iOverlapBottom As Long
    Dim iX As Long
    Dim iY As Long
    Dim iLocalX1 As Long
    Dim iLocalY1 As Long
    Dim iLocalX2 As Long
    Dim iLocalY2 As Long

    bCollision = _FALSE

    ' =============================================================================
    ' BEGIN CHECK BOUNDARY OVERLAP
    ' =============================================================================
    if ( _
        ((arrSprite(iSprite1).x1 + arrSprite(iSprite1).width) < arrSprite(iSprite2).x1) or _
        ((arrSprite(iSprite2).x1 + arrSprite(iSprite2).width) < arrSprite(iSprite1).x1) or _
        ((arrSprite(iSprite1).y1 + arrSprite(iSprite1).height) < arrSprite(iSprite2).y1) or _
        ((arrSprite(iSprite2).y1 + arrSprite(iSprite2).height) < arrSprite(iSprite1).y1) _
        ) = _FALSE then

        ' -----------------------------------------------------------------------------
        ' BEGIN SEE IF PIXELS OVERLAP
        ' -----------------------------------------------------------------------------
        ' Calculate the overlapping region
        iOverlapLeft = _Max(arrSprite(iSprite1).x1, arrSprite(iSprite2).x1)
        iOverlapTop = _Max(arrSprite(iSprite1).y1, arrSprite(iSprite2).y1)
        iOverlapRight = _Min(arrSprite(iSprite1).x1 + arrSprite(iSprite1).width, arrSprite(iSprite2).x1 + arrSprite(iSprite2).width)
        iOverlapBottom = _Min(arrSprite(iSprite1).y1 + arrSprite(iSprite1).height, arrSprite(iSprite2).y1 + arrSprite(iSprite2).height)

        ' Loop through the overlapping area
        For iY = iOverlapTop To iOverlapBottom - 1
            For iX = iOverlapLeft To iOverlapRight - 1
                ' Get local coordinates for each sprite
                iLocalX1 = iX - arrSprite(iSprite1).x1
                iLocalY1 = iY - arrSprite(iSprite1).y1
                iLocalX2 = iX - arrSprite(iSprite2).x1
                iLocalY2 = iY - arrSprite(iSprite2).y1
               
                ' Check if pixels are opaque in both masks
                If _
                    ( _
                        arrBitMask(arrSprite(iSprite1).FontIndex, arrSprite(iSprite1).fgChar, iLocalY1, iLocalX1) = _TRUE _
                        or _
                        arrBitMask(arrSprite(iSprite1).FontIndex, arrSprite(iSprite1).bgChar, iLocalY1, iLocalX1) = _TRUE _
                    ) _
                    And _
                    ( _
                        arrBitMask(arrSprite(iSprite2).FontIndex, arrSprite(iSprite2).fgChar, iLocalY2, iLocalX2) = _TRUE _
                        or _
                        arrBitMask(arrSprite(iSprite2).FontIndex, arrSprite(iSprite2).bgChar, iLocalY2, iLocalX2) = _TRUE _
                    ) _
                Then
                   
                    ' Collision detected
                    bCollision = _TRUE
                    Exit For
                End If
            Next iX
            If bCollision = _TRUE Then Exit For
        Next iY
        ' -----------------------------------------------------------------------------
        ' END SEE IF PIXELS OVERLAP
        ' -----------------------------------------------------------------------------
    End If
    ' =============================================================================
    ' END CHECK BOUNDARY OVERLAP
    ' =============================================================================

    ShapesCollided% = bCollision
End Function ' ShapesCollided%

Note that I also started playing with shrinking the boundary box by storing the edges for each character (see Sub FindEdges) but I realized it was redundant as GetBitMask was already storing them in x1, x2, y1, y2, and I saw it would be unwieldy to have to keep recalculating, so in the next version I started developing a 2nd version of GetBitMask that generates the bit mask and finds edges for each unique fgChar / bgChar combination. But I didn't need it for this game, and so it's neither here nor there. The point is that when I get to it, it will use the precalculated edges for each character, for the boundary boxes, and thus avoid having to compare empty rows / columns.

Anyway, I had this checking collisions for a few hundred sprites ranging in size from 8x8 upto 64x64 and it was plenty fast.

Attached also is "MultiCustomFontsAndCollisions144.bas" which is the updated version with more developed logic for shooting and players/robots/bullets being shot, and upto 16 players on the screen, where I started adding the updated "find edges" and collision routines for sprites using both fgChar and bgChar. The current part I'm stuck at is that when a robot gets shot, it's supposed to explode, but that animation isn't displaying. I have similar animation when the player gets shot, and that's visible, so I'm not sure what's going on. Also there's a weird bug that happens every so often, where if a player gets shot by another player's bullet, ALL the players die. Very weird.

Try running it and let me know what you think.


Attached Files
.bas   MultiCustomFontsAndCollisions131.bas (Size: 4.52 MB / Downloads: 23)
.bas   MultiCustomFontsAndCollisions144.bas (Size: 4.54 MB / Downloads: 16)
Reply


Messages In This Thread
RE: error doing image collision detection with _MemGet - by madscijr - 09-27-2025, 06:34 AM

Possibly Related Threads…
Thread Author Replies Views Last Post
  Collision Detection NakedApe 12 332 02-26-2026, 01:01 AM
Last Post: NakedApe
  Mac debugger not connecting, a user error! BlameTroi 0 101 02-07-2026, 06:18 PM
Last Post: BlameTroi
  ERROR MESSAGES COLORS ? aurel 5 393 01-02-2026, 11:26 AM
Last Post: aurel
  Using CONST & _RGB used together seem to error... Dav 12 706 12-12-2025, 12:29 AM
Last Post: Dav
Photo from png tile, create symmetrical screen image hsiangch_ong 11 954 08-23-2025, 01:23 AM
Last Post: bplus

Forum Jump:


Users browsing this thread: 2 Guest(s)