PyGame: why isn't collision working well? - python

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.

Related

How can I check collisions between actors in pygame using "actor.collidepoint(pos)"

I'm very new to pygame and am trying to make a game where the actor try's to hit the gem, but I cant figure out how to use the "actor.collidepoint(pos)" function for that! Answers are greatly appreciated!
See Actor:
Actors have all the same attributes and methods as Rect, including methods like .colliderect() which can be used to test whether two actors have collided.
Supposing you have to Actor objects:
player = Actor("player_image.png")
gem = Actor("gem_image.png")
Use colliderect method to detect the collision between the actors:
if player.colliderect(gem):
print("hit")
For more information about collisions in Pygame, see the answers to the questions:
How do I detect collision in pygame?
How to detect collisions between two rectangular objects or images in pygame

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.

remove object after collision

I have two objects troll and pig. I'm detecting collisions between these two characters with Pygame's colliderect function. collisions for this works perfectly, however I am unable to remove the object from the screen when a collision occurs. When a troll collideswith a pig, I want the pig to disappear from the screen. I set an image for both of these and bit them, is there a way to un-blit? Ive tried pygame.image.set_alpha(255) (which set full transparency of an image) function to no avail.
Any suggestions?
Can't you just stop drawing the pig? Each frame you fill the screen with the background, so it won't be visible.

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