How to see if a sprite has touched a rectangle? - python

I am creating a program using pygame and was wondering if there was a command which worked out if a sprite touched a rectangle. So I have a sprite moving around a maze, and at the end, there is a rectangle. The rectangle doesn't do anything, if the sprite touches it, they will win. I know that there are if sprite touches another sprite commands, but I don't want to create another sprite. The code for the rectangle is as follows:
pygame.draw.rect(screen, pink, [1005, 505, 19, 19])

Not having full access to your code, but I think you can use the colliderect to do the collision check. This function test if two rectangles overlap.
colliderect()
colliderect(Rect) -> bool
Returns true if any portion of either rectangle overlap (except the
top+bottom or left+right edges).
Minimal example:
your_sprite.get_rect().colliderect(your_goal_rect)

Related

PyGame: why isn't collision working well?

It detects collision most of times, but sometimes it doesn't. Here is collision checker:
def collide_check(this, object_1):
bullet_rect = this.image.get_rect().move(this.bullet_x, this.bullet_y)
object_1_rect = object_1.image.get_rect().move(object_1.ice_x, object_1.ice_y)
if bullet_rect.colliderect(object_1_rect):
#consequences of collision
Looks like your typical 'Bullet through paper'-problem.
Since .move() doesn't sub-step you are simply not overlapping the other rect, and therefor do not fulfil the colliderect condition.
Simply put: You 'erase' the original rect, and draw it anew in the new position. Same for the other rect. They do not overlap, because the movement was too great, therefore no collision is detected.
If you're calling collide_check() multiple times on the same object, I may have found the reason for your problem.
For unknown reasons, .colliderect() won't detect collisions if it's being called on an object that has already had collisions detected upon it.
For more information, see this similar question.

Barrier shield collision detection for Space Invaders game in Python with pygame

I'm currently making the Space Invaders game in Python with pygame.
I currently have 3 base barriers that are all built with 1 x 1 pixel blocks (that 'extend' the pygame.sprite.Sprite class). For collision detection, I check if a missile has collided with the barrier.
For now, everything works, when I fire and hit one of the barriers, the pixel that was hit is eliminated.
Now the thing that bothers me is that in the original Space Invaders, when the ship's missile (or an alien's missile for that matter)
hits the barrier, it causes an 'explosion' that affects multiple pixels of the barrier. I would like to implement this
in my python/pygame code. How would I go about this?
Here is my collision detection code in my missile class (that 'extends' the pygame.sprite.Sprite):
baseBarrier_hit_list = pygame.sprite.spritecollide(self, all_baseBarrier_group, True)
for pixel in baseBarrier_hit_list:
self.kill() # I kill the missile after collision so that the other barrier pixels are unaffected.
break #so that the other pixels in the column are unaffected.
I thought of 'artificially' adding 'random' pixels to the baseBarrier_hit_list but I'm unable to add elements to the baseBarrier_hit_list.
Here is a video link of the original space invaders to see what I mean:
https://www.youtube.com/watch?v=axlx3o0codc
Here is also a link to a python/pygame version of Space Invaders that shows that only one pixel is affected when collision occurs between missile and base barrier. (Note that this is not MY version of the game). https://www.youtube.com/watch?v=_2yUP3WMDRc
EDIT: (see comment for picture explanation)
EDIT: TemporalWolf's suggestion worked. This is the code I added to my function.
shield_hit_list_random = pygame.sprite.spritecollide(self, all_blockShields_group, False, pygame.sprite.collide_rect_ratio(2))
Passing a False to the function prevents the killing of the sprites. Then, I randomly kill the some sprites in the shield_hit_list_random group like this:
for shield in shield_hit_list_random:
pourcentage =randint(0,3)
if pourcentage == 2:
shield.kill()
I would try using the scaled collision rect or the circle equivalent:
pygame.sprite.collide_rect_ratio() Collision detection between two
sprites, using rects scaled to a ratio.
collide_rect_ratio(ratio) -> collided_callable
A callable class that checks for collisions between
two sprites, using a scaled version of the sprites rects.
Is created with a ratio, the instance is then intended to be passed as
a collided callback function to the *collide functions.
A ratio is a floating point number - 1.0 is the same size, 2.0 is
twice as big, and 0.5 is half the size.
New in pygame 1.8.1
which would be given as the 4th parameter to your spritecollide function

Finding all collisions within 1 group of sprites (efficiently)

I have a method that recieves a Group of sprites. For each sprite, I need to find every other sprite it collides with and call its handle_collision method.
How can I find all the sprites each sprite in the group collides with? Here's my idea for finding all collisions within a group.
#staticmethod
def check_collision_group(most_sprites: pygame.sprite.Group, screen):
for sprite in most_sprites:
most_sprites.remove(sprite)
collided_sprites = pygame.sprite.Group()
for sprite2 in most_sprites:
if pygame.sprite.collide_rect(sprite, sprite2):
collided_sprites.add(sprite2)
sprite.handle_collision(collided_sprites)
most_sprites.add(sprite)
However, this is slow. The amount of collisions this had to check astonished me when I printed them out.
A bit of searching and I've found 2 ideas that are probably a lot faster.
Making the first sprite a Group and using collidegroup from pygame.sprite library.
Only testing the sprites around the sprite you are testing. Idea from https://gamedev.stackexchange.com/questions/45392/how-do-i-detect-multiple-sprite-collisions-when-there-are-10-sprites .
To restate question: What is a fast (but hopefully still relatively simple) way to find every other sprite in the group that each sprite collides with?
To find all collisions between a sprite and everything else in it's group.
def check_collision_group(most_sprites, screen):
single = pygame.sprite.GroupSingle()
for sprite in most_sprites:
most_sprites.remove(sprite)
single.add(sprite)
collided_sprites_dict = pygame.sprite.groupcollide(
single, most_sprites, False, False)
most_sprites.add(sprite)
Note: It's important to use add on the groupsingle, reassignment will keep adding more and more groups to your system and bog down your game. I am not sure why, but changing it to my groupsingle and adding to it fixed the issue.
The speed of this seems to be relatively fast. To calculate all the collisions in a group of ~50 sprites it took about 1.4 milliseconds. I have not tried method 2, which is only checking collisions based on proximity, but I do not see a reason to, as the speed of groupcollide is rather decent.

Collision between Rect and another unknown Rect

I was wondering if it was possible to find out if a Rect is colliding with another Rect. The problem is that I do not know what/where that other Rect is.
I have a Rect which moves around (of which I know where it is).
I have many other Rects on the same "map".
I dont want to make a list of all Rects on the map and then try collideRect with each and every one of them.
Does anyone have an idea under these circumstances for a function that takes a Rect and returns a list of all other Rects with which it collides? (Without using the collideRect function for all existing Rects?)
Can I somehow "scan" only the area of the first Rect and if there is another Rect in the same "spot" I return the other Rect?
I have come up with nothing so far...
At some point, you will need to check to see if the Rect collides with any other Rect. With that in mind, there are some ways to speed things up, basically relying on grouping Rects.
For example, assuming these Rects are objects in the level that don't move around, you could sort them by the X-coordinate, and remember the maximum width. When you want to run collision detection, start at the main Rect's left side minus the maximum width, and loop through until the Rect's right side. Any Rects outside of that range do not have the ability to collide, and so do not need to be checked.
Alternately, you could divide the level into, say, 16 squares, and give each square a list of all Rects within the square. Then, just decide which square the main Rect is in, and just compare with the Rects in there. (With logic for overlaps, of course.)
There's a large number of ways to do this.

Using colliderect in Pygame

How do I tell python to detect whether two objects/ images touch each other? For example when an image of pacman touches an image of a ghost?
http://www.pygame.org/docs/ref/rect.html#pygame.Rect.colliderect
colliderect()
test if two rectangles overlap
colliderect(Rect) -> bool
Returns true if any portion of either rectangle overlap (except the
top+bottom or left+right edges).
If the only collision detection between sprites is between pac-man and other objects, then just call colliderect on every combination of pacman's collision rectangle and every other collision rectangle.
If every single combination of collisions can be meaningful, then produce a big list of all of them and colliderect each rectangle with each rectangle further along in the list.
Every collision that occurs, you can choose to do something - you could even call both objects, passing the other object that collided, and thereby allowing the logic to be contained within one or both of the objects.
I'm assuming you're using Sprites for your pacman and ghost? If so you want one of the sprite collision functions: http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.spritecollide
Otherwise, use the Rect collision Patashu links.

Categories

Resources