How to get rect of a pygame Surface without transparent parts?












1















I am implementing collision detection and want to check if a rectangular object is touching the player. My wall uses .set_colorkey(background) where background is the specified background colour. The problem is that when I get my wall's rectangle with .get_rect(), it gets the full image's size which includes the transparent parts instead of just the opaque parts.



I thought about making the wall image file smaller in size to remove the background but that would be inconvenient as I would need to do this for each partially transparent image I have. I also thought about using arrays to get the colour and checking if it matches the background colour and getting the rectangle's size from there but that would be slow and cumbersome.



for x, y in ((i, j) for i in land_x for j in land_y):
# land_x, land_y hold the tiles to be checked
try:
tx1, ty1, tx2, ty2 =
texture[land[y][x]].get_rect()
# tx1, ty1 coordinates of top-left corner
# tx2, ty2 width and height respectively
if tx2 == 0 and ty2 == 0:
continue # skip to other objects
tx1 = x*64 - tx2/2
ty1 = y*64 - ty2/2
px1, py1, px2, py2 =
PLAYER.get_rect()
px1 = player_x - px2/2
py1 = -player_y - py2/2
if p.Rect(px1, py1, px2, py2).colliderect(
p.Rect(tx1, ty1, tx2, ty2)
):
player_x -= direction_x
break # go outside loop to start checking y
except IndexError: # incase player is outside map
pass # skip to other objects


The .get_rect() outputs a rectangle the size of the whole image whereas I want a rectangle that doesn't include the transparent parts.



Example:
texture is a 64x64 image with a 48x48 block in the centre.
The background colour is removed and a 48x48 solid coloured block is left (even though the image size is still 64x64).



Expected Output:
texture.get_rect() should output a rectangle of size 48x48.



Actual Output:
texture.get_rect() instead outputs a rectangle of size 64x64.



Any help on this would be appreciated :D










share|improve this question



























    1















    I am implementing collision detection and want to check if a rectangular object is touching the player. My wall uses .set_colorkey(background) where background is the specified background colour. The problem is that when I get my wall's rectangle with .get_rect(), it gets the full image's size which includes the transparent parts instead of just the opaque parts.



    I thought about making the wall image file smaller in size to remove the background but that would be inconvenient as I would need to do this for each partially transparent image I have. I also thought about using arrays to get the colour and checking if it matches the background colour and getting the rectangle's size from there but that would be slow and cumbersome.



    for x, y in ((i, j) for i in land_x for j in land_y):
    # land_x, land_y hold the tiles to be checked
    try:
    tx1, ty1, tx2, ty2 =
    texture[land[y][x]].get_rect()
    # tx1, ty1 coordinates of top-left corner
    # tx2, ty2 width and height respectively
    if tx2 == 0 and ty2 == 0:
    continue # skip to other objects
    tx1 = x*64 - tx2/2
    ty1 = y*64 - ty2/2
    px1, py1, px2, py2 =
    PLAYER.get_rect()
    px1 = player_x - px2/2
    py1 = -player_y - py2/2
    if p.Rect(px1, py1, px2, py2).colliderect(
    p.Rect(tx1, ty1, tx2, ty2)
    ):
    player_x -= direction_x
    break # go outside loop to start checking y
    except IndexError: # incase player is outside map
    pass # skip to other objects


    The .get_rect() outputs a rectangle the size of the whole image whereas I want a rectangle that doesn't include the transparent parts.



    Example:
    texture is a 64x64 image with a 48x48 block in the centre.
    The background colour is removed and a 48x48 solid coloured block is left (even though the image size is still 64x64).



    Expected Output:
    texture.get_rect() should output a rectangle of size 48x48.



    Actual Output:
    texture.get_rect() instead outputs a rectangle of size 64x64.



    Any help on this would be appreciated :D










    share|improve this question

























      1












      1








      1








      I am implementing collision detection and want to check if a rectangular object is touching the player. My wall uses .set_colorkey(background) where background is the specified background colour. The problem is that when I get my wall's rectangle with .get_rect(), it gets the full image's size which includes the transparent parts instead of just the opaque parts.



      I thought about making the wall image file smaller in size to remove the background but that would be inconvenient as I would need to do this for each partially transparent image I have. I also thought about using arrays to get the colour and checking if it matches the background colour and getting the rectangle's size from there but that would be slow and cumbersome.



      for x, y in ((i, j) for i in land_x for j in land_y):
      # land_x, land_y hold the tiles to be checked
      try:
      tx1, ty1, tx2, ty2 =
      texture[land[y][x]].get_rect()
      # tx1, ty1 coordinates of top-left corner
      # tx2, ty2 width and height respectively
      if tx2 == 0 and ty2 == 0:
      continue # skip to other objects
      tx1 = x*64 - tx2/2
      ty1 = y*64 - ty2/2
      px1, py1, px2, py2 =
      PLAYER.get_rect()
      px1 = player_x - px2/2
      py1 = -player_y - py2/2
      if p.Rect(px1, py1, px2, py2).colliderect(
      p.Rect(tx1, ty1, tx2, ty2)
      ):
      player_x -= direction_x
      break # go outside loop to start checking y
      except IndexError: # incase player is outside map
      pass # skip to other objects


      The .get_rect() outputs a rectangle the size of the whole image whereas I want a rectangle that doesn't include the transparent parts.



      Example:
      texture is a 64x64 image with a 48x48 block in the centre.
      The background colour is removed and a 48x48 solid coloured block is left (even though the image size is still 64x64).



      Expected Output:
      texture.get_rect() should output a rectangle of size 48x48.



      Actual Output:
      texture.get_rect() instead outputs a rectangle of size 64x64.



      Any help on this would be appreciated :D










      share|improve this question














      I am implementing collision detection and want to check if a rectangular object is touching the player. My wall uses .set_colorkey(background) where background is the specified background colour. The problem is that when I get my wall's rectangle with .get_rect(), it gets the full image's size which includes the transparent parts instead of just the opaque parts.



      I thought about making the wall image file smaller in size to remove the background but that would be inconvenient as I would need to do this for each partially transparent image I have. I also thought about using arrays to get the colour and checking if it matches the background colour and getting the rectangle's size from there but that would be slow and cumbersome.



      for x, y in ((i, j) for i in land_x for j in land_y):
      # land_x, land_y hold the tiles to be checked
      try:
      tx1, ty1, tx2, ty2 =
      texture[land[y][x]].get_rect()
      # tx1, ty1 coordinates of top-left corner
      # tx2, ty2 width and height respectively
      if tx2 == 0 and ty2 == 0:
      continue # skip to other objects
      tx1 = x*64 - tx2/2
      ty1 = y*64 - ty2/2
      px1, py1, px2, py2 =
      PLAYER.get_rect()
      px1 = player_x - px2/2
      py1 = -player_y - py2/2
      if p.Rect(px1, py1, px2, py2).colliderect(
      p.Rect(tx1, ty1, tx2, ty2)
      ):
      player_x -= direction_x
      break # go outside loop to start checking y
      except IndexError: # incase player is outside map
      pass # skip to other objects


      The .get_rect() outputs a rectangle the size of the whole image whereas I want a rectangle that doesn't include the transparent parts.



      Example:
      texture is a 64x64 image with a 48x48 block in the centre.
      The background colour is removed and a 48x48 solid coloured block is left (even though the image size is still 64x64).



      Expected Output:
      texture.get_rect() should output a rectangle of size 48x48.



      Actual Output:
      texture.get_rect() instead outputs a rectangle of size 64x64.



      Any help on this would be appreciated :D







      python pygame pygame-surface






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Dec 31 '18 at 22:55









      GeeTransitGeeTransit

      694215




      694215
























          2 Answers
          2






          active

          oldest

          votes


















          1














          If you want to ignore the transparent pixels in your collision detection, you're talking about pixel-perfect collision.



          To do this in pygame, pygame offers the Mask class. You usually create your masks with pygame.mask.from_surface and use it together with pygame.sprite.spritecollide and pygame.sprite.collide_mask.



          Maybe think about using pygame's Sprite class to make use of all the features it offers.



          Even if you don't want to use pygame's build-in collision detection, you can take a look at the source to see how it works.






          share|improve this answer































            2














            You are making this too hard. You know the size of your objects. Add a smaller collision rect to each of your objects at creation time and use that for collision. Or use a circle if that is better for the object.



            tile.crect = Rect(whatever)


            Or just multiply the existing rect dimensions by some scale factor for your collision rect. Don't do all of these calculations. Store a Rect for each collideable object and have a rect for the player.



                tx1 = x*64 - tx2/2
            ty1 = y*64 - ty2/2
            px1, py1, px2, py2 =
            PLAYER.get_rect()
            px1 = player_x - px2/2
            py1 = -player_y - py2/2


            Then just test collision directly:



            for t in tiles:
            if player.rect.colliderect( t.rect ):


            If the player is a sprite its rect moves around. Look at the example code in the doc.



            https://www.pygame.org/docs/ref/sprite.html






            share|improve this answer
























            • Thanks for answering with clarity. The game I am making will be able to be changed with different textures with different sizes, thus I won't be able to know the sizes beforehand. I will check out the link on sprites, as that looks useful to me. Thanks again :D

              – GeeTransit
              Jan 1 at 0:06











            • I've reevaluated my game and how it works. I am going to have users specify the 'hitbox' for a specified texture. Unfortunately, I am going to leave this question unanswered as I want to have a backup for when the user does not specify a 'hitbox'.

              – GeeTransit
              Jan 1 at 0:20











            • Yeah if the user doesn't specify a hitbox then you would need to check for the transparent pixel and just do that once at the start and create the hitbox Rect or store a ratio like 0.8 and as you are doing multiply the Rect by that before testing collision.

              – MarkReedZ
              Jan 1 at 15:35













            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53991988%2fhow-to-get-rect-of-a-pygame-surface-without-transparent-parts%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            1














            If you want to ignore the transparent pixels in your collision detection, you're talking about pixel-perfect collision.



            To do this in pygame, pygame offers the Mask class. You usually create your masks with pygame.mask.from_surface and use it together with pygame.sprite.spritecollide and pygame.sprite.collide_mask.



            Maybe think about using pygame's Sprite class to make use of all the features it offers.



            Even if you don't want to use pygame's build-in collision detection, you can take a look at the source to see how it works.






            share|improve this answer




























              1














              If you want to ignore the transparent pixels in your collision detection, you're talking about pixel-perfect collision.



              To do this in pygame, pygame offers the Mask class. You usually create your masks with pygame.mask.from_surface and use it together with pygame.sprite.spritecollide and pygame.sprite.collide_mask.



              Maybe think about using pygame's Sprite class to make use of all the features it offers.



              Even if you don't want to use pygame's build-in collision detection, you can take a look at the source to see how it works.






              share|improve this answer


























                1












                1








                1







                If you want to ignore the transparent pixels in your collision detection, you're talking about pixel-perfect collision.



                To do this in pygame, pygame offers the Mask class. You usually create your masks with pygame.mask.from_surface and use it together with pygame.sprite.spritecollide and pygame.sprite.collide_mask.



                Maybe think about using pygame's Sprite class to make use of all the features it offers.



                Even if you don't want to use pygame's build-in collision detection, you can take a look at the source to see how it works.






                share|improve this answer













                If you want to ignore the transparent pixels in your collision detection, you're talking about pixel-perfect collision.



                To do this in pygame, pygame offers the Mask class. You usually create your masks with pygame.mask.from_surface and use it together with pygame.sprite.spritecollide and pygame.sprite.collide_mask.



                Maybe think about using pygame's Sprite class to make use of all the features it offers.



                Even if you don't want to use pygame's build-in collision detection, you can take a look at the source to see how it works.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Jan 2 at 8:49









                slothsloth

                74.1k14127169




                74.1k14127169

























                    2














                    You are making this too hard. You know the size of your objects. Add a smaller collision rect to each of your objects at creation time and use that for collision. Or use a circle if that is better for the object.



                    tile.crect = Rect(whatever)


                    Or just multiply the existing rect dimensions by some scale factor for your collision rect. Don't do all of these calculations. Store a Rect for each collideable object and have a rect for the player.



                        tx1 = x*64 - tx2/2
                    ty1 = y*64 - ty2/2
                    px1, py1, px2, py2 =
                    PLAYER.get_rect()
                    px1 = player_x - px2/2
                    py1 = -player_y - py2/2


                    Then just test collision directly:



                    for t in tiles:
                    if player.rect.colliderect( t.rect ):


                    If the player is a sprite its rect moves around. Look at the example code in the doc.



                    https://www.pygame.org/docs/ref/sprite.html






                    share|improve this answer
























                    • Thanks for answering with clarity. The game I am making will be able to be changed with different textures with different sizes, thus I won't be able to know the sizes beforehand. I will check out the link on sprites, as that looks useful to me. Thanks again :D

                      – GeeTransit
                      Jan 1 at 0:06











                    • I've reevaluated my game and how it works. I am going to have users specify the 'hitbox' for a specified texture. Unfortunately, I am going to leave this question unanswered as I want to have a backup for when the user does not specify a 'hitbox'.

                      – GeeTransit
                      Jan 1 at 0:20











                    • Yeah if the user doesn't specify a hitbox then you would need to check for the transparent pixel and just do that once at the start and create the hitbox Rect or store a ratio like 0.8 and as you are doing multiply the Rect by that before testing collision.

                      – MarkReedZ
                      Jan 1 at 15:35


















                    2














                    You are making this too hard. You know the size of your objects. Add a smaller collision rect to each of your objects at creation time and use that for collision. Or use a circle if that is better for the object.



                    tile.crect = Rect(whatever)


                    Or just multiply the existing rect dimensions by some scale factor for your collision rect. Don't do all of these calculations. Store a Rect for each collideable object and have a rect for the player.



                        tx1 = x*64 - tx2/2
                    ty1 = y*64 - ty2/2
                    px1, py1, px2, py2 =
                    PLAYER.get_rect()
                    px1 = player_x - px2/2
                    py1 = -player_y - py2/2


                    Then just test collision directly:



                    for t in tiles:
                    if player.rect.colliderect( t.rect ):


                    If the player is a sprite its rect moves around. Look at the example code in the doc.



                    https://www.pygame.org/docs/ref/sprite.html






                    share|improve this answer
























                    • Thanks for answering with clarity. The game I am making will be able to be changed with different textures with different sizes, thus I won't be able to know the sizes beforehand. I will check out the link on sprites, as that looks useful to me. Thanks again :D

                      – GeeTransit
                      Jan 1 at 0:06











                    • I've reevaluated my game and how it works. I am going to have users specify the 'hitbox' for a specified texture. Unfortunately, I am going to leave this question unanswered as I want to have a backup for when the user does not specify a 'hitbox'.

                      – GeeTransit
                      Jan 1 at 0:20











                    • Yeah if the user doesn't specify a hitbox then you would need to check for the transparent pixel and just do that once at the start and create the hitbox Rect or store a ratio like 0.8 and as you are doing multiply the Rect by that before testing collision.

                      – MarkReedZ
                      Jan 1 at 15:35
















                    2












                    2








                    2







                    You are making this too hard. You know the size of your objects. Add a smaller collision rect to each of your objects at creation time and use that for collision. Or use a circle if that is better for the object.



                    tile.crect = Rect(whatever)


                    Or just multiply the existing rect dimensions by some scale factor for your collision rect. Don't do all of these calculations. Store a Rect for each collideable object and have a rect for the player.



                        tx1 = x*64 - tx2/2
                    ty1 = y*64 - ty2/2
                    px1, py1, px2, py2 =
                    PLAYER.get_rect()
                    px1 = player_x - px2/2
                    py1 = -player_y - py2/2


                    Then just test collision directly:



                    for t in tiles:
                    if player.rect.colliderect( t.rect ):


                    If the player is a sprite its rect moves around. Look at the example code in the doc.



                    https://www.pygame.org/docs/ref/sprite.html






                    share|improve this answer













                    You are making this too hard. You know the size of your objects. Add a smaller collision rect to each of your objects at creation time and use that for collision. Or use a circle if that is better for the object.



                    tile.crect = Rect(whatever)


                    Or just multiply the existing rect dimensions by some scale factor for your collision rect. Don't do all of these calculations. Store a Rect for each collideable object and have a rect for the player.



                        tx1 = x*64 - tx2/2
                    ty1 = y*64 - ty2/2
                    px1, py1, px2, py2 =
                    PLAYER.get_rect()
                    px1 = player_x - px2/2
                    py1 = -player_y - py2/2


                    Then just test collision directly:



                    for t in tiles:
                    if player.rect.colliderect( t.rect ):


                    If the player is a sprite its rect moves around. Look at the example code in the doc.



                    https://www.pygame.org/docs/ref/sprite.html







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Dec 31 '18 at 23:58









                    MarkReedZMarkReedZ

                    5967




                    5967













                    • Thanks for answering with clarity. The game I am making will be able to be changed with different textures with different sizes, thus I won't be able to know the sizes beforehand. I will check out the link on sprites, as that looks useful to me. Thanks again :D

                      – GeeTransit
                      Jan 1 at 0:06











                    • I've reevaluated my game and how it works. I am going to have users specify the 'hitbox' for a specified texture. Unfortunately, I am going to leave this question unanswered as I want to have a backup for when the user does not specify a 'hitbox'.

                      – GeeTransit
                      Jan 1 at 0:20











                    • Yeah if the user doesn't specify a hitbox then you would need to check for the transparent pixel and just do that once at the start and create the hitbox Rect or store a ratio like 0.8 and as you are doing multiply the Rect by that before testing collision.

                      – MarkReedZ
                      Jan 1 at 15:35





















                    • Thanks for answering with clarity. The game I am making will be able to be changed with different textures with different sizes, thus I won't be able to know the sizes beforehand. I will check out the link on sprites, as that looks useful to me. Thanks again :D

                      – GeeTransit
                      Jan 1 at 0:06











                    • I've reevaluated my game and how it works. I am going to have users specify the 'hitbox' for a specified texture. Unfortunately, I am going to leave this question unanswered as I want to have a backup for when the user does not specify a 'hitbox'.

                      – GeeTransit
                      Jan 1 at 0:20











                    • Yeah if the user doesn't specify a hitbox then you would need to check for the transparent pixel and just do that once at the start and create the hitbox Rect or store a ratio like 0.8 and as you are doing multiply the Rect by that before testing collision.

                      – MarkReedZ
                      Jan 1 at 15:35



















                    Thanks for answering with clarity. The game I am making will be able to be changed with different textures with different sizes, thus I won't be able to know the sizes beforehand. I will check out the link on sprites, as that looks useful to me. Thanks again :D

                    – GeeTransit
                    Jan 1 at 0:06





                    Thanks for answering with clarity. The game I am making will be able to be changed with different textures with different sizes, thus I won't be able to know the sizes beforehand. I will check out the link on sprites, as that looks useful to me. Thanks again :D

                    – GeeTransit
                    Jan 1 at 0:06













                    I've reevaluated my game and how it works. I am going to have users specify the 'hitbox' for a specified texture. Unfortunately, I am going to leave this question unanswered as I want to have a backup for when the user does not specify a 'hitbox'.

                    – GeeTransit
                    Jan 1 at 0:20





                    I've reevaluated my game and how it works. I am going to have users specify the 'hitbox' for a specified texture. Unfortunately, I am going to leave this question unanswered as I want to have a backup for when the user does not specify a 'hitbox'.

                    – GeeTransit
                    Jan 1 at 0:20













                    Yeah if the user doesn't specify a hitbox then you would need to check for the transparent pixel and just do that once at the start and create the hitbox Rect or store a ratio like 0.8 and as you are doing multiply the Rect by that before testing collision.

                    – MarkReedZ
                    Jan 1 at 15:35







                    Yeah if the user doesn't specify a hitbox then you would need to check for the transparent pixel and just do that once at the start and create the hitbox Rect or store a ratio like 0.8 and as you are doing multiply the Rect by that before testing collision.

                    – MarkReedZ
                    Jan 1 at 15:35




















                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53991988%2fhow-to-get-rect-of-a-pygame-surface-without-transparent-parts%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Mossoró

                    Error while reading .h5 file using the rhdf5 package in R

                    Pushsharp Apns notification error: 'InvalidToken'