Python - Pygame. How can I disable/root mouse movement when sprites collide? - python

I have this snippet of code:
end_hist_list = pygame.sprite.spritecollide(self, end_walls, False)
for end in end_hist_list:
end_sound.play()
#now need to root position of mouse/or disable mouse movement
So when that sprite (player) collides with end_wall, I need for mouse to not be able to move, to just root in that position (when that collision happened). But I can't find any function that would let disable or root mouse. I tried reseting position to end_walls coordinates, but then it resets near that sprite, but not on top of it. I think there should be some simple way to do that, I just might not see it. Any suggestions?
P.S. mouse controls player sprite (in end spritecollide it is self) like this:
def update(self):
""" Update player position """
pos = pygame.mouse.get_pos()
self.rect.x = pos[0]
self.rect.y = pos[1]

As well as mouse.get_pos, there is a mouse.set_pos. You could use this to keep returning the mouse to the appropriate position when the player tries to move it away. Effectively, you reverse the current update:
pygame.mouse.set_pos(self.rect.x, self.rect.y)
Alternatively, you could just stop dealing with mouse events. If the cursor is visible it will still move around, but the game will ignore it.

Related

How can I find out if the mouse is hovering/clicking on a pygame sprite (not shaped as a rectangle or circle)

So I am making this button and I need to find out two things
1 - When is the user hovering over it?
2 - When is the user clicking on it?
As you can see these buttons are oddly shaped
I have tried looking on the pygame forums but those only state how to find out if two sprites are colliding.
Just handle the MOUSEBUTTONDOWN event, and check the event.pos against the rect of each of your sprites. If there's a collision, that's the one that was clicked on.
It's the same for hovering, except you need to grab the mouse position each frame via the pygame.mouse.get_pos() function.
If you put all your button sprites into a SpriteGroup, it will be easy to do these checks.
For oddly shaped sprites, it may help to use a Sprite mask. This is an extra-check made (after the rectangle collision shows true) at the per-pixel level. So while the mouse may have done some action within the bounds of the Sprite's rectangle, maybe it was not truly over the visible part of the Sprite's image.
Luckily the PyGame Sprite library makes the creation of a mask easy, and if defined, it will automatically be used as part of the collision detection.
class MaskedSprite( pygame.sprite.Sprite ):
def __init__( self, image, x, y ):
pygame.sprite.Sprite.__init__( self )
self.image = image.convert_alpha()
self.mask = pygame.mask.from_surface( self.image ) # <<-- HERE
self.rect = self.image.get_rect()
self.rect.center = ( x, y )
There are a few simple rules around mask creation. If the image has a transparent background, that will be used to determine what is part/not-part of the sprite-collision.
Otherwise there needs to be a difference in colour between the background/foreground of 127 colour units (the default). This can be changed with the threshold parameter to pygame.mask.from_surface().
There is also the pygame.mask.from_threshold() function.
To be honest, just use a transparent background, and everything will be OK.
Everything.

Pygame - maintain playing speed of game when keys are pressed

I've got a Space invaders style game which works okay but when I press a key to move my player's ship, the aliens slow down until the key is released. This is because there's more code being run when a key is pressed than if there isn't (obviously). Here's the code that's run when I press a key
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
objShip.move(1)
elif keys[pygame.K_RIGHT]:
objShip.move(2)
elif keys[pygame.K_DOWN]:
objShip.move(3)
elif keys[pygame.K_LEFT]:
objShip.move(4)
which calls the following code
def move(self, d):
self.direction = d
if self.direction == 1:
self.image = pygame.image.load("shipu.png").convert()
if self.yco >= 0:
self.yco -= 1
if self.xco >= 884:
self.xco = 860
Is there a way of way of equalising the speed of the aliens which doesn't involve putting a wait command (or an empty loop or whatever) into the else statement to act as a make-work delay?
I can put all the code here but it's a bit lengthy at the moment so thought I'd try without incase there's something obvious I'm missing.
self.image = pygame.image.load("shipu.png").convert()
You're reloading the ships image every single time it moves. Don't do this.
Loading the image returns a surface, store that surface in the ship's object, and render that surface at the ship's coordinates every frame, never having to load the image again.
Loading files is very slow, and this is why you're seeing such a dramatic slowdown.
Considering you have multiple graphics for different movement states, load all the images at once, when you create the ship, and store their resulting surfaces in separate variables, or a dictionary. When you need to swap between graphics, just swap out the surfaces to the needed one.
Whatever you do, load all images only ONCE!
The slow down is still going to happen when you change it to the way I just suggested, but it will at least be imperceptible.
To even out movement over time, you need to use 'delta time'. Which is basically basing the distance moved off the render time.

How do I make a rectangular sprite stop when it collides with another rectangular sprite using pygame?

I'm trying to create some obstacles for the player in my program. I can't figure out how to make the sprite stop when it comes in contact with it from all sides.
I tried to use pygame.sprite.collide_rect and pygame.sprite.spritecollide, but couldn't figure out how to do it.
If you could just try to explain the concept, I'd rather try to figure the rest out myself. Thanks in advance!
def move_rect():
new_pos = player_rect.pos
new_pos = new_pos[0]+dx,new_pos[1]+dy
new_rect = rect(new_pos,player_rect.size)
for enemy in enemy_rects:
if new_rect.colliderect(enemy):
dx,dy=dx*-1,dy*-1 #reverse direction to "bounce"
#alternatively you could just return here probably
player_rect.move(dx,dy) #do the move, no collisions
something like that at least ... (I doubt it will work, its more to give you the concept)

Python Mouse over image not working

I am trying to detect when a Sprite has been hovered over by the mouse. However it is not working, it is never detecting the mouse over.
Code for Tile:
#!/usr/bin/python
import pygame
class Tile(pygame.sprite.Sprite):
def __init__(self, img_sprite, init_position):
pygame.sprite.Sprite.__init__(self)
self.position=init_position
self.image=pygame.image.load(img_sprite)
self.rect = self.image.get_rect()
Code for event
for event in pygame.event.get():
for tile in tiles:
if tile.image.get_rect().collidepoint(pygame.mouse.get_pos()):
print 'tile hovered'
You are checking if your mouse is over the rect that is the image rect. Since the rect returned by image.get_rect() is always in the form (0,0,width,height), then your check only works if the position of your tile is at (0,0).
To fix this your can keep the position in the rect, or create a new rect that will describe the actual position.
You can also filter the events, and only check for a MOUSEMOTION event type.

Moving a sprite when mouse is pressed in Python

I'm making a Pong clone for learning purposes, and need to get the ball moving from the middle of the screen (it's sent there when it goes past a paddle) when the mouse is pressed. I've tried the following code, but it does nothing, so I probably don't understand the syntax. Try to keep it as simple as possible please, and explain it, I'd rather not have 50 lines of code for this (I want to understand everything I'm using here). I think this is all the relevant code, sorry if it isn't. Thanks.
def middle(self):
"""Restart the ball in the centre, waiting for mouse click. """
# puts ball stationary in the middle of the screen
self.x = games.screen.width/2
self.y = games.screen.height/2
self.dy = 0
self.dx = 0
# moves the ball if mouse is pressed
if games.mouse.is_pressed(1):
self.dx = -3
It's impossible to know exactly what's happening based on that code fragment, but it looks like you are using the wrong function to detect whether or not the mouse button is pressed.
Screen.is_pressed from the games module wraps pygame.key.get_pressed, which only detects the state of keyboard keys, not mouse buttons. You probably want the function Screen.mouse_buttons, which wraps pygame.mouse.get_pressed. You could use it within a loop like this (I'll pretend you have an instance of games.Screen called 'screen'):
left, middle, right = screen.mouse_buttons()
# value will be True if button is pressed
if left:
self.dx = -3
I am looking at the same issue as a beginner Python coder - Games.py (revision 1.7) includes several is_pressed methods in various classes, including both keyboard and mouse.
class Mouse(object):
#other stuff then
def is_pressed(self, button_number):
return pygame.mouse.get_pressed()[button_number] == 1
since pygame is a compiled module (I have 1.9.1) referring to the documentation rather than source code, I find here that there is a pygame.mouse.get_pressed():
the will get the state of the mouse buttons
get_pressed() -> (button1, button2, button3)
So I think the issue is the use of this in (y)our code rather than the use of the wrong function.....
OK GOT THIS TO WORK - MY FIX:
class myClass(games.Sprite):
def update(self):
if games.mouse.is_pressed(0)==1:
self.x=games.mouse.x
self.y=games.mouse.y
invoking the in Main() causes the selected sprite to move to the mouse location. HTH

Categories