Reputation: 111
I need help deleting an object, and I mean delete, not draw over or other things. My code so far:
def detect_collision(player_pos, enemy_pos):
p_x = player_pos[0]
p_y = player_pos[1]
e_x = enemy_pos[0]
e_y = enemy_pos[1]
if (e_x >= p_x and e_x < (p_x + player_size)) or (p_x >= e_x and p_x < (e_x+enemy_size)):
if (e_y >= p_y and e_y < (p_y + player_size)) or (p_y >= e_y and p_y < (e_y+enemy_size)):
return True
return False
def bullets():
b_x = player_pos[0]
b_y = player_pos[1]
keep_going = True
pygame.draw.rect(screen, TEAL, (b_x, b_y, 15, 50))
while keep_going:
b_y += 75
if detect_collision(player_pos, enemy_pos):
# deleting part here
Here is what makes my player and enemy:
enemy_size = 50
enemy_pos = [random.randint(0,WIDTH-enemy_size), 0]
enemy_list = [enemy_pos]
def drop_enemies(enemy_list):
delay = random.random()
if len(enemy_list) < 10 and delay < 0.1:
x_pos = random.randint(0,WIDTH-enemy_size)
y_pos = 0
enemy_list.append([x_pos, y_pos])
def draw_enemies(enemy_list):
for enemy_pos in enemy_list:
pygame.draw.rect(screen, RED, (enemy_pos[0], enemy_pos[1],
enemy_size, enemy_size))
def update_enemy_positions(enemy_list, score):
for idx, enemy_pos in enumerate(enemy_list):
if enemy_pos[1] >= 0 and enemy_pos[1] < HEIGHT:
enemy_pos[1] += SPEED
else:
enemy_list.pop(idx)
score += 1
return score
Player part:
player_size = 50
player_pos = [WIDTH/2, HEIGHT-2*player_size]
pygame.draw.rect(screen, TEAL, (player_pos[0], player_pos[1], player_size,
player_size))
Upvotes: 3
Views: 3716
Reputation: 65
I'm assuming there's only one bullet in screen at a time since you didn't mention a bullet list. You probably create bullet by hitting space or something which I'll leave out here. One thing to consider in you bullets()
function is your doing moving, drawing and checking for collision in the same function. Note, it is always a good idea to make a function do only one thing.
def draw_bullet():
move_bullet()
pygame.draw.rect(screen, TEAL, (b_x, b_y, 15, 50))
def move_bullet():
if b_y < HEIGHT:
b_y += 75
else:
create_bullet = False # explained below
So to create a bullet, you should have a Boolean create_bullet
variable. So:
# mainloop
if user hits spacebar (or the key used to create bullet) :
create_bullet = true
b_x = player_pos[0] # initialise bullet
b_y = player_pos[1]
if create_bullet:
draw_bullet()
if detect_collision((b_x, b_y), enemy_pos):
# assuming b_x, b_y are global variable or something, so that they are actually defined and equal to bullet's x and y pos
# if bullet and enemy collide, remove them both
enemy_list.remove(enemy)
create_bullet = False
if detect_collision(player_pos, enemy_pos):
# reset player pos, or whatever you want to do
you say you want to delete it and not just draw over it. However the way pygame generates a 'moving/ video-like' screen is by continuously drawing over. E.g: player is drawn at (10, 10) and then is drawn at (20, 10) so it appears like player moved. However, this is done very fast so you don't see him 'disappear' and 'reappear'. So here's what the above code does.
When spacebar is hit, it 'creates' the bullet by setting it's x and y value to the current player position and sets create_bullet = true. Then, on each iteration of the main loop, if create_bullet is true, it moves then draws the bullet. If the bullet moves outside the screen or collides with enemy, create_bullet = False, so it will stop drawing it and on the next iteration of main loop, bullet will be drawn over by the background and would 'disappear'.
Upvotes: 0
Reputation: 14906
Right, so you have a list of enemy positions in enemy_list
. That's a good start. I don't see a bullet_list
, so I will assume only a single bullet at a time, positioned at b_x
,b_y
.
So a main loop for this program might look something like:
### Main Loop
while not game_over:
# handle user input
# move the player
# move the bullet (if any)
# move the enemies
# if there's a bullet, did it hit an enemy?
# remove enemy hit from enemy_list
# Did an enemy in enemy_list, hit the player?
# do game-over
# clear the screen
# paint the player
# paint the bullet (if any)
# paint every enemy in enemy_list
Where the enemy collision, and list removal might look something like the below. (I've tried to match the look of your code as much as possible.)
# if a bullet is on-screen (non 0,0), see if it hits an enemy
if ( b_x != 0 and b_y != 0 ):
hit_enemy_idx = None
for idx, enemy_pos in enumerate( enemy_list ):
# check for collision
if detect_collision( ( b_x, b_y ), enemy_pos ):
hit_enemy = idx # note the enemy index
b_x, b_y = 0, 0 # erase the bullet
break # exit the loop when hit found
# If the bullet hit an enemy, remove from list
if hit_enemy_idx != None:
del( enemy_list[ hit_enemy_idx ] ) # delete hit enemy from list
We do an iteration through the enemy list, checking for a collision. Once a hit is found, it save the index of which enemy was hit, and stops the loop.
The next step is to delete the enemy from the list. I have written this in a separate block, rather than placing it before the break
in the loop. This is because unexpected results can happen when you change a list as you're iterating over it. In this particular case it would have been OK, but it's something to be wary of as a beginner.
Upvotes: 0
Reputation: 3245
It would be beneficial to look into Sprites and SpriteGroups to track entities in your game. They have a bunch of functionality built in that will make things easier.
Here's a demo I have that groups sprites, removing those that collide with the mouse pointer:
import random
import pygame
screen_width, screen_height = 640, 480
def get_random_position():
"""return a random (x,y) position in the screen"""
return (
random.randint(0, screen_width - 1), # randint includes both endpoints.
random.randint(0, screen_height - 1),
)
color_list = ["red", "orange", "yellow", "green", "cyan", "blue", "blueviolet"]
colors = [pygame.color.Color(c) for c in color_list]
class PowerUp(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
width, height = 64, 32
self.color = random.choice(colors)
self.image = pygame.Surface([width, height])
self.image.fill(self.color)
# Fetch the rectangle object that has the dimensions of the image
self.rect = self.image.get_rect()
# then move to a random position
self.update()
def update(self):
# move to a random position
self.rect.center = get_random_position()
if __name__ == "__main__":
pygame.init()
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Sprite Group Collision Demo")
clock = pygame.time.Clock() # for limiting FPS
FPS = 60
exit_demo = False
# create a sprite group to track the power ups.
power_ups = pygame.sprite.Group()
for _ in range(10):
power_ups.add(PowerUp()) # create a new power up and add it to the group.
# main loop
while not exit_demo:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit_demo = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
exit_demo = True
elif event.key == pygame.K_SPACE:
power_ups.update()
elif event.type == pygame.MOUSEBUTTONUP:
for _ in range(10):
power_ups.add(PowerUp())
# Update State: check for collisions
for p in power_ups:
if p.rect.collidepoint(pygame.mouse.get_pos()):
power_ups.remove(p)
# draw background
screen.fill(pygame.Color("black")) # use black background
# draw sprites
power_ups.draw(screen)
# update screen
pygame.display.update()
clock.tick(FPS)
pygame.quit()
quit()
Clicking a mouse button creates more sprites and pressing the space bar randomises their position.
The update()
method of a bullet sprite would adjust the sprite position by its speed, e.g. self.rect.x += SPEED
and you would need to call the bullet sprite group .update()
method every game loop.
Upvotes: 0
Reputation: 104712
The best way to solve your issue is to learn how to use Sprite
objects in pygame. Together with Group
objects, they can already do what you want, right out of the box.
In brief, your "enemy" should be an instance of some Sprite
subclass, and you'd add it to an instance of Group
(rather than building your own enemy_list
). When you want the enemy to die, you can call the kill()
method on it, which will remove it from the Group
. This serves to delete it from the game, since you should be using methods on the Group
object to update and draw all the sprites it contains (but not ones that have been killed).
Upvotes: 2