3

So, i am trying to create a game where aliens spawn from 3 specific places. Each Alien will spawn randomly in one of the 3. But there will always be at least one alien, that will spawn on top of another one. I want to delete that alien and spawn him randomly in another spawn point. If it is empty he will stay if not the process will be repeated. The thing is that i cannot find a way to detect collision of 2 objects that are in the same group.

I just started learning pygame so 1) My question may be stupid 2) My way of spawning probably is very inefficient

Here is the Alien class:

class Alien(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((80,60)) self.image.fill(GREY) self.rect = self.image.get_rect() spawn_point1 = x1,y1 = -30, 70 spawn_point2 = x2,y2 = -30, 150 spawn_point3 = x3,y3 = -30, 230 random_spawn = random.choice([spawn_point1,spawn_point2,spawn_point3]) self.rect.center = random_spawn self.speedx = 10 def update(self): spawn_point1 = x1,y1 = -30, 70 spawn_point2 = x2,y2 = -30, 150 spawn_point3 = x3,y3 = -30, 230 self.speedx = 10 random_spawn = random.choice([spawn_point1,spawn_point2,spawn_point3]) self.rect.x += self.speedx if self.rect.x > WIDTH + 20: self.rect.center = random_spawn 

And here is the part where i detect collision(This part doesnt work)

aliens_col = pygame.sprite.groupcollide(aliens, aliens, True, False) for i in aliens_col: alien = Alien() aliens.add(alien) all_sprites.add(aliens) 
7
  • 1
    Please show us the code (a minimal, complete and verifiable example). Commented Jun 6, 2018 at 17:13
  • I put it in. As i say above the second part doesnt work Commented Jun 6, 2018 at 18:24
  • Here is a good article on collision detection. When I implemented a while back I used the Bounding box test. devmag.org.za/2009/04/13/basic-collision-detection-in-2d-part-1 Commented Jun 6, 2018 at 18:28
  • Should there be only one alien sprite per lane or can there be multiple sprites per lane and you only want to avoid that two spawn directly on top of each other? Commented Jun 6, 2018 at 18:57
  • There should be one alien sprite per lane and yes i want to avoid them spawning on top of each other Commented Jun 6, 2018 at 19:04

3 Answers 3

0

Here is an implementation of the Bounding Box test.

import random class Rectangle: def __init__(self, height, width, x, y): self.height = height self.width = width self.x = x self.y = y def collided_with_another_rectangle(self, rect): """ Assumes rectangles are same size or that this rectangle is smaller than the other rectangle""" if self.x > (rect.x + rect.width): # Is to the right of the other rectangle return False elif (self.x + self.width) < rect.x: # is to the left of the other rectangle return False elif (self.y + self.height) < rect.y: # is above the other rectangle return False elif self.y > (rect.y + rect.height): # is below the other rectangle return False else: return True collision_count = 0 for i in range(0, 1000): # Here I pick random locations on a 1000X1000 screen for the first rectangle x1 = random.randint(0, 1000) y1 = random.randint(0, 1000) # Here I pick random locations on a 1000X1000 screen for the second rectangle rect1 = Rectangle(100, 100, x1, y1) x2 = random.randint(0, 1000) y2 = random.randint(0, 1000) rect2 = Rectangle(100, 100, x2, y2) """ I use the collided with another rectangle function to test if the first rectangle is above,below, to the right or to the left of the other rectangle. If neither of these are true then the rectangles have collided. """ if rect1.collided_with_another_rectangle(rect2): collision_count += 1 print("Rect1 X and Y:" + str(x1) + " " + str(y1)) print("Rect2 X and Y:" + str(x2) + " " + str(y2)) print("collided") print("Collision Count:" + str(collision_count)) 
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for you answer. Can you explain what happens at the last part? Im a noobie
Sure, this is just my implementation, so imagine that you are 1000 X 1000 pixel screen. I randomly pick a (x,y) coordinate for rect1 and rect2. Then I test if if rect1 collided with rect2. I just wanted to show you how to implement collision. The important part really is the "collided_with_another_rectangle method" if you want to tell if two rectangles collided.
Oh ok i got it :) Just one thing. After they collide how do i delete one of them?
Is there a .remove() method?
0

I'm still not absolutely sure what you want to achieve, but I think this example will be helpful to you.

When a sprite leaves the screen, I call the reset_pos method in which I iterate over the three spawn points to set the position to one spawn after the other and then I use another for loop to iterate over the sprites to check if one collides.

If a sprite collides, I continue with the next spawn point.

If no sprite collides, I just return from the method.

If no spawn is free, I remove the sprite (but you can do something else).

import random import pygame from pygame.math import Vector2 pygame.init() WIDTH, HEIGHT = 640, 480 class Alien(pygame.sprite.Sprite): def __init__(self, aliens): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((80, 60)) self.image.fill((120, random.randrange(255), random.randrange(255))) self.rect = self.image.get_rect() self.spawn_points = [(-30, 70), (-30, 150), (-30, 230)] self.aliens = aliens self.reset_pos() self.speedx = 10 def update(self): self.rect.x += self.speedx if self.rect.x > WIDTH + 20: self.reset_pos() def reset_pos(self): random.shuffle(self.spawn_points) # Shuffle the spawns. for spawn in self.spawn_points: # Set the position to one of the spawns. self.rect.center = spawn # Check if this sprite collides with another one. for sprite in self.aliens: if sprite is self: # Skip self. continue if self.rect.colliderect(sprite.rect): break # Break out of the loop if the spawn is occupied. else: # The else means no 'break' occurred in the for loop above, # so the spawn must be free. return # Break out of the method if the spawn is free. # I just remove the sprite if no spawn is free. You can do something else here. self.kill() def main(): screen = pygame.display.set_mode((640, 480)) clock = pygame.time.Clock() aliens = pygame.sprite.Group() for _ in range(3): # I pass the aliens group to the sprite because we need to # iterate over it to see if a sprite collides. alien = Alien(aliens) aliens.add(alien) all_sprites = pygame.sprite.Group(aliens) done = False while not done: for event in pygame.event.get(): if event.type == pygame.QUIT: done = True elif event.type == pygame.MOUSEBUTTONDOWN: al = Alien(aliens) all_sprites.add(al) aliens.add(al) all_sprites.update() screen.fill((30, 30, 30)) all_sprites.draw(screen) pygame.display.flip() clock.tick(30) if __name__ == '__main__': main() pygame.quit() 

1 Comment

Thanks for the answer! What you did there is basically what i want to do so again thanks!
0

When using the same group in both of the group-paramaters of groupcollide it will always consider the sprite it is checking in group_a as colliding with that same sprite in group_b. This results in groupcollide always returning a collision.

To get around this I created a new function in pygame's sprite.py that ignores single collisions and only returns collisions >= 2. My only change was to add:

if len(collision) >=2: 

And then the required tab for the following line(s).

The code I added to sprite.py is pasted below but the tab for the def intra_groupcollide is one too far:

def intra_groupcollide(groupa, groupb, dokilla, dokillb, collided=None): """detect collision between a group and itself. This is modified from groupcollide but excludes collisions <=1 pygame.sprite.groupcollide(groupa, groupb, dokilla, dokillb): return dict """ crashed = {} # pull the collision function in as a local variable outside # the loop as this makes the loop run faster sprite_collide_func = spritecollide if dokilla: for group_a_sprite in groupa.sprites(): collision = sprite_collide_func(group_a_sprite, groupb, dokillb, collided) if collision: if len(collision) >=2: crashed[group_a_sprite] = collision group_a_sprite.kill() else: for group_a_sprite in groupa: collision = sprite_collide_func(group_a_sprite, groupb, dokillb, collided) if collision: if len(collision) >=2: crashed[group_a_sprite] = collision #print(crashed) return crashed 

Then in my own python program, I simply replaced groupcollide with intra_groupcollide. I set both kill paramaters as 'false' because in my usage I'm bouncing them off each other. I have not tested this code with them set to 'true'.

I found sprite.py in my file system by following this answer: Where are the python modules stored?

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.