1

This is more of a curiosity question, because I went back and managed to do what I wanted to do. The title was originally going to be something like 'Checking if an ordered tuple is in a tuple of ranges?'

Until now I've been checking mouse clicks using this code -

pos = pygame.mouse.get_pos()

if pos[0] > X and pos[0] < X2 and pos[1] > Y and pos[1] < Y2:
    #Do this

#Separate function with same XY's
if pos[0] > X and pos[0] < X2 and pos[1] > Y and pos[1] < Y2:
    #Do something else - could be used for mouse hover rather than click.  

I was wondering how other people go about button detection, since sometimes more than one check is needed (in separate functions for example). Sometimes I will trigger an outside function, boolean or timer, or something along those lines. I've done that in the example below. But this can get messy too and I feel like there must be a simpler way.

for event in pygame.event.get():
    if event.type == pygame.MOUSEBUTTONDOWN:
        gp = game.pos
        #Initial gbh declaration
        gbh = game.button_health = range(391, 527), range(179, 253)

        if gp[0] in gbh[0] and gp[1] in gbh[1]:
        player.skillpoints -= 1
        player.health += 10
        player.healthmax += 10

#Separate func.
gp = game.pos
gbh = game.button_health

if gp[0] in gbh[0] and gp[1] in gbh[1]:
    blit(font.render(str(Z), True, BLACK), (X, Y))
TheJack
  • 111
  • 1
  • 8
  • The question is kind of unclear. Please clarify what you're trying to achieve and what the problems are. If you want to implement some callback functions for buttons, take a look at [this answer](https://stackoverflow.com/a/47664205/6220679) (addendum 1 and 2). – skrx May 16 '18 at 20:52
  • Hm I'm not sure how to clarify any further. I was wondering if there's a cleaner way to check the same thing (such as whether or not the cursor is in a box area) multiple times? – TheJack May 16 '18 at 21:42
  • That sounds like you just want a function. Do you know how to define one? I'm not sure how experienced you are, but that is something you should learn very early. Better search for tutorials if you haven't learned that yet. – skrx May 17 '18 at 07:50

2 Answers2

2

If you have repetitive code, then you can put it into a function and call it where the code was. That makes it easier to modify the code later, since you just have to change it in one place. Testing the code is easier as well.

Here's an example (I've also added a Google style docstring):

def collided(pos, X, X2, Y, Y2):
    """Check if a point `pos` collides with an area.

    Args:
        pos (tuple): The point.
        X (int, float): The left coordinate of the area.
        etc.

    Returns:
        bool: True if it collides, otherwise False.
    """
    return pos[0] > X and pos[0] < X2 and pos[1] > Y and pos[1] < Y2


# Call the function and pass the needed arguments.
if collided(pg.mouse.get_pos(), X, X2, Y, Y2):
    print('collision')
skrx
  • 19,980
  • 5
  • 34
  • 48
1

Since your question is tagged performance, the best place to start is a famous quote:

"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%" (D. Knuth, "Structured Programming with go to Statements", emphasize mine)

Are you sure this has an impact on the global performance of your application? I would be very surprised if 4 comparisons had an impact. So let's assume that it's not a performance issue.

First of all, note that in Python you can write:

if X < pos[0] < X2 and Y < pos[1] < Y2:
     ....

But there's more important: make what you are testing clear. How will you make it clear? Simply by naming it:

if pos[0] > X and pos[0] < X2 and pos[1] > Y and pos[1] < Y2: 
    # Do this

becomes:

if area_contains(X, X2, Y, Y2, pos):
    # Do this

or with a custom class:

area = Area(X, X2, Y, Y2)
if area.contains(pos):
    # Do this

You should do this even if you have only one test, for the sake of clarity. Functions are not just made to reduce duplicate code (DRY: don't repeat yourself) but also to improve readability. Look at this:

player.skillpoints -= 1
player.health += 10
player.healthmax += 10

Why not:

player.increase_health()

?

Don't use objects only as structures: they provide you a convenient way to express what you are doing without disclosing the implementation detail. Now, you can change what increase_health means without looking for all events that lead to it.

jferard
  • 7,835
  • 2
  • 22
  • 35