pygame health display issue - python

so i'm watching Teach with Tim pygame in 90 min and i'm at 1:24:39. When i run the code the red ship health keep decrasing when i shoot it(by yellow ship and when the red ship hit the yellow ship) until i move one of the ship or press shoot when i just shoot the other ship once. what went wrong can anyone help?
i think the issue is this part but i'm not sure:
if event.type == red_hit:
red_health -= 1
if event.type == yellow_hit:
yellow_health -= 1
import pygame
import os
import time
pygame.font.init()
width , height = 900 , 500
dispay_surface = pygame.display.set_mode((width, height))
pygame.display.set_caption("first game")
teal = (153,255,255)
light_green = (102,255,102)
BLACK = (0,0,0)
RED = (255,0,0)
YELLOW = (255,255,0)
BORDER = pygame.Rect(width//2,0,10,height)
health_font = pygame.font.SysFont('comicsans', 40)
fps = 60
VEL = 5
BULLET_VEL = 7
max_bullet = 10
spaceship_width, spaceship_height = 55, 40
yellow_hit = pygame.USEREVENT +1
red_hit = pygame.USEREVENT +2
#making the space ship and rotating it correctly
yellow_spaceship_image = pygame.image.load(
os.path.join('Assets','spaceship_yellow.png'))
yellow_spaceship_nr = pygame.transform.scale(
yellow_spaceship_image, (spaceship_width, spaceship_height))
yellow_spaceship = pygame.transform.rotate(yellow_spaceship_nr, 90)
red_spaceship_image = pygame.image.load(
os.path.join('Assets','spaceship_red.png'))
red_spaceship_nr= pygame.transform.scale(
red_spaceship_image, (spaceship_width, spaceship_height))
red_spaceship = pygame.transform.rotate(red_spaceship_nr, -90)
space_background = pygame.transform.scale(pygame.image.load(os.path.join('Assets','space.png')),(width,height))
def draw_window(red,yellow,red_bullet,yellow_bullet,red_health,yellow_health):
dispay_surface.blit(space_background,(0,0))
#showing the health
red_health_text = health_font.render("health: " + str(red_health), 1 , teal)
yellow_health_text = health_font.render("health: " + str(yellow_health), 1, teal)
dispay_surface.blit(red_health_text,(width - red_health_text.get_width()- 10 , 10))
dispay_surface.blit(yellow_health_text, (10 , 10))
#use to draw the ship
dispay_surface.blit(yellow_spaceship,(yellow.x, yellow.y))
dispay_surface.blit(red_spaceship,(red.x, red.y))
#drawing a border so the 2 spaceship can't go on top of each other
pygame.draw.rect(dispay_surface,BLACK,BORDER)
for bullet in red_bullet:
pygame.draw.rect(dispay_surface,RED,bullet)
for bullet in yellow_bullet:
pygame.draw.rect(dispay_surface,YELLOW,bullet)
pygame.display.update()
#getting yellow ship to move when player input
def yellow_mov(keys_pressed,yellow):
if keys_pressed[pygame.K_d] and yellow.x + VEL + yellow.width < BORDER.x: #right
yellow.x += VEL
if keys_pressed[pygame.K_a] and yellow.x - VEL > 0: #left
yellow.x -= VEL
if keys_pressed[pygame.K_w] and yellow.y - VEL > 0: #up
yellow.y -= VEL
if keys_pressed[pygame.K_s] and yellow.y - VEL + yellow.height < height - 15 : #down
yellow.y += VEL
#getting red to move
def red_mov(keys_pressed,red):
if keys_pressed[pygame.K_RIGHT] and red.x + VEL + red.width < width: #right
red.x += VEL
if keys_pressed[pygame.K_LEFT] and red.x - VEL >BORDER.x + BORDER.width: #left
red.x -= VEL
if keys_pressed[pygame.K_UP] and red.y - VEL > 0: #up
red.y -= VEL
if keys_pressed[pygame.K_DOWN] and red.y - VEL + red.height < height - 15: #down
red.y += VEL
def handle_bullet(yellow_bullet,red_bullet,yellow,red):
for bullet in yellow_bullet:
bullet.x += BULLET_VEL
if red.colliderect(bullet):
pygame.event.post(pygame.event.Event(red_hit))
yellow_bullet.remove(bullet)
elif bullet.x > width:
yellow_bullet.remove(bullet)
for bullet in red_bullet:
bullet.x -= BULLET_VEL
if yellow.colliderect(bullet):
pygame.event.post(pygame.event.Event(red_hit))
red_bullet.remove(bullet)
elif bullet.x < 0 :
red_bullet.remove(bullet)
#keep window running
def main():
#determin the player position
red = pygame.Rect(700,300,spaceship_width,spaceship_height)
yellow = pygame.Rect(100,300,spaceship_width,spaceship_height)
red_bullet = []
yellow_bullet = []
red_health = 10
yellow_health = 10
clock = pygame.time.Clock()
run = True
while run:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#Shoot the bullet
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LCTRL and len(yellow_bullet) < max_bullet:
bullet = pygame.Rect(yellow.x + yellow.width, yellow.y + yellow.height//2 , 10 ,5)
yellow_bullet.append(bullet)
if event.key == pygame.K_RCTRL and len(red_bullet) < max_bullet:
bullet = pygame.Rect(red.x , red.y + red.height//2 , 10 ,5)
red_bullet.append(bullet)
if event.type == red_hit:
red_health -= 1
if event.type == yellow_hit:
yellow_health -= 1
if red_health <=0:
winner_text = "yellow wins"
if yellow_health <=0:
winner_text = "red wins"
keys_pressed = pygame.key.get_pressed()
yellow_mov(keys_pressed,yellow)
red_mov(keys_pressed,red)
handle_bullet(yellow_bullet,red_bullet,yellow,red)
draw_window(red,yellow,red_bullet,yellow_bullet,red_health,yellow_health)
pygame.quit()
if __name__ == '__main__':
main()

I went over your code, and I believe the issue is that this snippet of code:
if event.type == red_hit:
red_health -= 1
if event.type == yellow_hit:
yellow_health -= 1
is in your main loop instead of your
for event in pygame.event.get():
loop.
Try changing the format to this:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#Shoot the bullet
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LCTRL and len(yellow_bullet) < max_bullet:
bullet = pygame.Rect(yellow.x + yellow.width, yellow.y + yellow.height // 2, 10, 5)
yellow_bullet.append(bullet)
if event.key == pygame.K_RCTRL and len(red_bullet) < max_bullet:
bullet = pygame.Rect(red.x, red.y + red.height // 2, 10 ,5)
red_bullet.append(bullet)
if event.type == red_hit:
red_health -= 1
if event.type == yellow_hit:
yellow_health -= 1

There is an issue in your code here.
def handle_bullet(yellow_bullet,red_bullet,yellow,red):
for bullet in yellow_bullet:
bullet.x += BULLET_VEL
if red.colliderect(bullet):
pygame.event.post(pygame.event.Event(red_hit))
yellow_bullet.remove(bullet)
elif bullet.x > width:
yellow_bullet.remove(bullet)
for bullet in red_bullet:
bullet.x -= BULLET_VEL
if yellow.colliderect(bullet):
pygame.event.post(pygame.event.Event(red_hit))
red_bullet.remove(bullet)
elif bullet.x < 0 :
red_bullet.remove(bullet)
You have considered both events for red_hit. Change as follows.
def handle_bullet(yellow_bullet,red_bullet,yellow,red):
for bullet in yellow_bullet:
bullet.x += BULLET_VEL
if red.colliderect(bullet):
pygame.event.post(pygame.event.Event(red_hit))
yellow_bullet.remove(bullet)
elif bullet.x > width:
yellow_bullet.remove(bullet)
for bullet in red_bullet:
bullet.x -= BULLET_VEL
if yellow.colliderect(bullet):
pygame.event.post(pygame.event.Event(yellow_hit))
red_bullet.remove(bullet)
elif bullet.x < 0 :
red_bullet.remove(bullet)
There is an indentation issue as well.Change as follows.
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#Shoot the bullet
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LCTRL and len(yellow_bullet) < max_bullet:
bullet = pygame.Rect(yellow.x + yellow.width, yellow.y + yellow.height//2 , 10 ,5)
yellow_bullet.append(bullet)
if event.key == pygame.K_RCTRL and len(red_bullet) < max_bullet:
bullet = pygame.Rect(red.x , red.y + red.height//2 , 10 ,5)
red_bullet.append(bullet)
if event.type == red_hit:
red_health-= 1
if event.type == yellow_hit:
yellow_health-= 1
Found another issue with your code. The health of spaceships keep decreasing below 0. It has something to do with here.
if red_health <=0:
winner_text = "yellow wins"
You have to stop the game when health becomes less than or equal zero.Use break to stop.
Change as follows=>
if red_health <=0:
winner_text = "yellow wins"
print(winner_text)
break
if yellow_health <=0:
winner_text = "red wins"
print(winner_text)
break

Related

Why are my variables not updating on screen?

# DONT CHANGE THIS
import pygame, os
pygame.init()
pygame.font.init()
WIDTH, HEIGHT = 450, 250
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Space Spar")
# VARIABLES
HEALTH_FONT = pygame.font.SysFont('comicsans', 20)
WINNER_FONT = pygame.font.SysFont('comicsans', 50)
WINCOUNT_FONT = pygame.font.SysFont('comicsans', 20)
SPACE = pygame.transform.scale(pygame.image.load(os.path.join("Assets", "space.png")), (WIDTH, HEIGHT))
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
WHITE = (255, 255, 255)
BORDER = pygame.Rect(WIDTH//2 - 5, 0, 5, HEIGHT)
FPS = 60
VEL = 3.5
SHIP_WIDTH, SHIP_HEIGHT, = 25, 20
BULLETS_VEL = 10
MAX_BULLETS = 1
YELLOW_HIT = pygame.USEREVENT + 1
RED_HIT = pygame.USEREVENT + 2
YELLOW_SPACESHIP_IMAGE = pygame.image.load(os.path.join('Assets', "spaceship_yellow.png"))
YELLOW_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(YELLOW_SPACESHIP_IMAGE, (SHIP_HEIGHT, SHIP_WIDTH)), 90)
RED_SPACESHIP_IMAGE = pygame.image.load(os.path.join('Assets', "spaceship_red.png"))
RED_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(RED_SPACESHIP_IMAGE, (SHIP_WIDTH, SHIP_HEIGHT)), 270)
# PLACE ANYTHING ON THE WINDOW HERE
# +y = down from top left
# +x = right from top left
def draw_window(red, yellow, red_bullets, yellow_bullets, red_health, yellow_health, red_win_count, yellow_win_count):
WIN.blit(SPACE, (0, 0))
pygame.draw.rect(WIN, BLACK, BORDER)
red_health_text = HEALTH_FONT.render("Health: " + str(red_health), 1, WHITE)
yellow_health_text = HEALTH_FONT.render("Health: " + str(yellow_health), 1, WHITE)
WIN.blit(red_health_text, (WIDTH - red_health_text.get_width() - 10, 10))
WIN.blit(yellow_health_text, (10, 10))
yellow_win_text = WINCOUNT_FONT.render('Wins: ' + str(yellow_win_count), 1, WHITE)
red_win_text = WINCOUNT_FONT.render('Wins: ' + str(red_win_count), 1, WHITE)
WIN.blit(red_win_text, (WIDTH - red_health_text.get_width() - 70, 10))
pygame.display.update()
WIN.blit(yellow_win_text, (70, 10))
pygame.display.update()
WIN.blit(YELLOW_SPACESHIP, (yellow.x, yellow.y))
WIN.blit(RED_SPACESHIP, (red.x, red.y))
for bullet in red_bullets:
pygame.draw.rect(WIN, RED, bullet)
for bullet in yellow_bullets:
pygame.draw.rect(WIN, RED, bullet)
pygame.display.update()
# MOVEMENT
def yellow_movement(keys_pressed, yellow):
if keys_pressed[pygame.K_a] and yellow.x - VEL > 0: #left
yellow.x -= VEL
if keys_pressed[pygame.K_d] and yellow.x + VEL + yellow.width < BORDER.x: #right
yellow.x += VEL
if keys_pressed[pygame.K_w] and yellow.y - VEL > 0: #up
yellow.y -= VEL
if keys_pressed[pygame.K_s] and yellow.y + VEL + yellow.height < HEIGHT: #dowm
yellow.y += VEL
def red_movement(keys_pressed, red):
if keys_pressed[pygame.K_LEFT] and red.x - VEL > BORDER.x + BORDER.width: #left
red.x -= VEL
if keys_pressed[pygame.K_RIGHT] and red.x + VEL + red.width < WIDTH: #right
red.x += VEL
if keys_pressed[pygame.K_UP] and red.y - VEL > 0: #up
red.y -= VEL
if keys_pressed[pygame.K_DOWN] and red.y + VEL + red.height < HEIGHT: #dowm
red.y += VEL
def handle_bullets(yellow_bullets, red_bullets, yellow, red):
for bullet in yellow_bullets:
bullet.x += BULLETS_VEL
if red.colliderect(bullet):
pygame.event.post(pygame.event.Event(RED_HIT))
yellow_bullets.remove(bullet)
elif bullet.x > WIDTH:
yellow_bullets.remove(bullet)
for bullet in red_bullets:
bullet.x -= BULLETS_VEL
if yellow.colliderect(bullet):
pygame.event.post(pygame.event.Event(YELLOW_HIT))
red_bullets.remove(bullet)
elif bullet.x < 0:
red_bullets.remove(bullet)
def draw_winner(text):
draw_text = WINNER_FONT.render(text, 1, WHITE)
WIN.blit(draw_text, (WIDTH//2 - draw_text.get_width()/2, HEIGHT/2 - draw_text.get_height()/2))
pygame.display.update()
pygame.time.delay(1000)
# MAIN LOOP
def main():
red = pygame.Rect(350, 150,SHIP_WIDTH, SHIP_HEIGHT)
yellow = pygame.Rect(50, 150, SHIP_WIDTH, SHIP_HEIGHT)
red_bullets = []
yellow_bullets = []
red_health = 1
yellow_health = 1
red_win_count = 0
yellow_win_count = 0
clock = pygame.time.Clock()
run = True
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and len(yellow_bullets) < MAX_BULLETS:
bullet = pygame.Rect(yellow.x + yellow.width, yellow.y + yellow.height//2 - 1, 15, 4)
yellow_bullets.append(bullet)
if event.key == pygame.K_LCTRL and len(red_bullets) < MAX_BULLETS:
bullet = pygame.Rect(red.x, red.y + red.height//2 - 1, 15, 4)
red_bullets.append(bullet)
if event.type == RED_HIT:
red_health -= 1
if event.type == YELLOW_HIT:
yellow_health -= 1
winner_text = ""
if red_health <= 0:
yellow_win_count += 1
pygame.display.update()
winner_text = "Yellow is cooler"
if yellow_health <= 0:
winner_text = "Red is cooler"
red_win_count += 1
pygame.display.update()
if winner_text != "":
draw_winner(winner_text)
main()
keys_pressed = pygame.key.get_pressed()
yellow_movement(keys_pressed, yellow)
red_movement(keys_pressed, red)
handle_bullets(yellow_bullets, red_bullets, yellow, red)
draw_window(red, yellow, red_bullets, yellow_bullets, red_health, yellow_health, red_win_count, yellow_win_count)
pygame.quit()
# this is to make sure its opening the right thing blah blaho
if __name__ == "__main__":
main()
I'm trying to display a win count through a variable but the variable isn't updating on the screen, why?
I took a look at the Github version of this game and determined that what you are wanting to do is add an enhancement that shows wins on the screen. The issue at the moment is that once a spaceship wins and the program again starts "main()", the win variables get reset to "0" before the screen is redisplayed.
red_health = 1
yellow_health = 1
red_win_count = 0
yellow_win_count = 0
As a quick tweak, instead of constantly restarting the game by calling "main" at the end of the "while" block, I revised the last "if" block to just do the resetting of the player health and then continue on with the while loop function.
if winner_text != "":
draw_winner(winner_text)
red_health = 4
yellow_health = 4
continue
#main()
That then allowed for viewing the win count on the screen.
You might want to check to see if any other variables need to be reset, but you can give that a try.

How to remove the drawn bullet and add image as a bullet fire the bullet one at a time? [duplicate]

This question already has answers here:
How do I stop more than 1 bullet firing at once?
(1 answer)
How can i shoot a bullet with space bar?
(1 answer)
Closed 2 years ago.
I am a kind of big noob in coding! I actually has 3 thing in it to ask! I had watched some tutorials on making a game using python and from that i have made a game type thing! In which i have draw bullets to which i want to change to image and it fires all at a click i also wnat to fire 1 bullet a time abd also i want my character to do a double jump.Thanks for visit!Please help me out!
import pygame
pygame.init()
class projectile(object):
def __init__(self,x,y,radius,color,facing):
self.x = x
self.y = y
self.radius = radius
self.color = color
self.facing = facing
self.vel = 8 * facing
def draw(self,win):
pygame.draw.circle(win, self.color, (self.x,self.y), self.radius)
def redrawGameWindow():
win.blit(bg, (0,0))
man.draw(win)
for bullet in bullets:
bullet.draw(win)
pygame.display.update()
#mainloop
man = player(200, 410, 64,64)
bullets = []
run = True
while run:
clock.tick(27)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
for bullet in bullets:
if bullet.x < 500 and bullet.x > 0:
bullet.x += bullet.vel
else:
bullets.pop(bullets.index(bullet))
keys = pygame.key.get_pressed()
if keys[pygame.K_c]:
if man.left:
facing = -1
else:
facing = 1
if len(bullets) < 3:
bullets.append(projectile(round(man.x + man.width //2), round(man.y + man.height//2), 6, (0,0,0), facing))
if keys[pygame.K_a] and man.x > man.vel:
man.x -= man.vel
man.left = True
man.right = False
man.standing = False
elif keys[pygame.K_d] and man.x < 500 - man.width - man.vel:
man.x += man.vel
man.right = True
man.left = False
man.standing = False
else:
man.standing = True
man.walkCount = 0
if not(man.isJump):
if keys[pygame.K_SPACE]:
man.isJump = True
if man.left:
facing = -1
else:
facing = 1
man.walkCount = 0
else:
if man.jumpCount >= -8:
neg = 1
if man.jumpCount < 0:
neg = -1
man.y -= (man.jumpCount ** 2) * 0.5 * neg
man.jumpCount -= 1
else:
man.isJump = False
man.jumpCount = 8
redrawGameWindow()
pygame.quit()
If you want to fire just 1 bullet when c is pressed, then implement a KEYDOWN event (see pygame.event):
while run:
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_c:
facing = -1 if man.left else 1
if len(bullets) < 3:
startPos = round(man.x + man.width //2), round(man.y + man.height//2)
bullets.append(projectile(startPos, 6, (0,0,0), facing))
# [...]
# DELETE
#if keys[pygame.K_c]:
# if man.left:
# facing = -1
# else:
# facing = 1
#
# if len(bullets) < 3:
# bullets.append(...)
The state keys[pygame.K_c] is True as long the key is hold down. This causes that 1 bullet is fired in every frame as long the key is pressed. The KEYDOWN event is executed only once when a key is pressed.

Pygame - collision between two objects not working

I'm making trying to recreate 'Pong' and I'm struggling to figure out what is wrong with the collision. Here's the code:
ball_x += ball_x_change
collide = player_collision(player_x, ball_x, player_y, ball_y)
if collide:
ball_x -= ball_x_change
ball(ball_x, ball_y)
This is meant to move the ball from its starting position towards the player and check if the player icon and the ball has collided. If its has, it will change the direction of the ball. It then renders the ball on the screen.
Here's the whole thing:
import pygame
import math
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Pong")
icon = pygame.image.load("ping-pong.png")
pygame.display.set_icon(icon)
player_icon = pygame.image.load("vertical-line.png")
player_x = 800 - (64 + 32)
player_y = 236
player_y_change = 0
cpu_icon = pygame.image.load("vertical-line.png")
cpu_x = 0 - 32
cpu_y = 236
cpu_y_change = 0
ball_icon = pygame.image.load("oval.png")
ball_x = 384
ball_y = 284
ball_x_change = 0.5
ball_y_change = 0
def player(player_x, player_y):
screen.blit(player_icon, (player_x, player_y))
def cpu(cpu_x, cpu_y):
screen.blit(cpu_icon, (cpu_x, cpu_y))
def ball(ball_x, ball_y):
screen.blit(ball_icon,(ball_x, ball_y))
def player_collision(ball_x, ball_y, player_x, player_y):
bump = math.hypot(player_x - ball_x, player_y - ball_y)
if bump < 20:
return True
else:
return False
running = True
while running:
screen.fill((255, 255, 255))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
player_y_change += 1
if event.key == pygame.K_UP:
player_y_change -= 1
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN or pygame.K_UP:
player_y_change = 0
player_y += player_y_change
if player_y <= 0:
player_y = 0
elif player_y >= 472:
player_y = 472
player(player_x, player_y)
cpu_y += cpu_y_change
if cpu_y <= 0:
player_y = 0
elif player_y >= 472:
player_y = 472
cpu(cpu_x, cpu_y)
ball_x += ball_x_change
collide = player_collision(player_x, ball_x, player_y, ball_y)
if collide:
ball_x -= ball_x_change
ball(ball_x, ball_y)
pygame.display.update()
Thanks for your time.
Updated the code and it still doesn't work:
import pygame
import math
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Pong")
icon = pygame.image.load("ping-pong.png")
pygame.display.set_icon(icon)
player_icon = pygame.image.load("vertical-line.png")
player_x = 672
player_y = 236
player_y_change = 0
cpu_icon = pygame.image.load("vertical-line.png")
cpu_x = 0
cpu_y = 236
cpu_y_change = 0
ball_icon = pygame.image.load("oval.png")
ball_x = 384
ball_y = 284
ball_x_change = 0.8
ball_y_change = 0
def player(player_x, player_y):
screen.blit(player_icon, (player_x, player_y))
def cpu(cpu_x, cpu_y):
screen.blit(cpu_icon, (cpu_x, cpu_y))
def ball(ball_x, ball_y):
screen.blit(ball_icon,(ball_x, ball_y))
def player_collision(ball_x, player_x, ball_y, player_y):
touch = math.hypot(player_x - ball_x, ball_y - player_y)
if touch < 10:
return True
else:
return False
running = True
while running:
screen.fill((255, 255, 255))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
player_y_change += 1
if event.key == pygame.K_UP:
player_y_change -= 1
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN or pygame.K_UP:
player_y_change = 0
player_y += player_y_change
if player_y <= 0:
player_y = 0
elif player_y >= 472:
player_y = 472
player(player_x, player_y)
cpu_y += cpu_y_change
if cpu_y <= 0:
player_y = 0
elif player_y >= 472:
player_y = 472
cpu(cpu_x, cpu_y)
ball_x += ball_x_change
collide = player_collision(ball_x, player_x, ball_y, player_y)
if collide:
ball_x_change = -ball_x_change
ball_x += ball_x_change
ball(ball_x, ball_y)
pygame.display.update()
The function player_collision takes its arguments in (ball_x, ball_y, player_x, player_y), but when you call the function, you give the arguments in the wrong order
collide = player_collision(player_x, ball_x, player_y, ball_y)
#should be
collide = player_collision(ball_x, ball_y, player_x, player_y)
You should also do what #RFairey suggested and add ball_x_change *= -1
Looks like when collision occurs, you only move the ball back one step in x:
if collide:
ball_x -= ball_x_change
To flip its direction you need to negate ball_x_change as well, so that it travels in the other direction after a bounce:
if collide:
ball_x -= ball_x_change
ball_x_change = -ball_x_change

Why doesn't this collision detection apply to objects previously created?

After hours of searching, I still can't figure out why only the most recently spawned circle is affected by the collision detection. I commented out the code in question. I experimented with sprites and that may be the answer but I still got the same results.
import pygame,random
pygame.init()
width,height,radius = 1280,720,20
class Ball():
def __init__(self):
self.x = 0
self.y = 0
self.vx = 0
self.vy = 0
def make_ball():
ball = Ball()
ball.x = random.randrange(radius, width - radius)
ball.y = random.randrange(radius, 100)
ball.vx = random.randint(1,2)
ball.vy = 0
return ball
def main():
rect_x = 60
display = pygame.display.set_mode((width,height))
pygame.display.set_caption("BOUNCE")
running = True
ball_list = []
ball = make_ball()
ball_list.append(ball)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
ball = make_ball()
ball_list.append(ball)
for ball in ball_list:
ball.x += ball.vx
ball.vy += 0.02
ball.y += ball.vy
if ball.y >= height - radius:
ball.vy *= -1
if ball.x >= width - radius or ball.x <= radius:
ball.vx *= -1
display.fill((0,0,0))
for ball in ball_list:
random_color = (random.randint(1,255),random.randint(1,255),random.randint(1,255))
circle = pygame.draw.circle(display,random_color,(int(ball.x), int(ball.y)),radius)
rectangle = pygame.draw.rect(display,(255,255,255),(int(rect_x),660,60,60))
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT and rect_x > 0:
rect_x -= 2
if event.key == pygame.K_RIGHT and rect_x < width - 60:
rect_x += 2
'''if pygame.Rect(circle).colliderect(rectangle) == True: ###THIS IS THE BAD CODE!
print('Your Score:',pygame.time.get_ticks())
running = False'''
text = pygame.font.Font(None,120).render(str(pygame.time.get_ticks()),True,(255,255,255))
display.blit(text,(50,50))
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
Indentation and code organization is the key to this. the offending section is (comments removed):
for ball in ball_list:
random_color = (random.randint(1,255),random.randint(1,255),random.randint(1,255))
circle = pygame.draw.circle(display,random_color,(int(ball.x), int(ball.y)),radius)
rectangle = pygame.draw.rect(display,(255,255,255),(int(rect_x),660,60,60))
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT and rect_x > 0:
rect_x -= 2
if event.key == pygame.K_RIGHT and rect_x < width - 60:
rect_x += 2
if pygame.Rect(circle).colliderect(rectangle) == True:
print('Your Score:',pygame.time.get_ticks())
running = False
You had all the correct pieces, but the order in which you are doing them is off as well as the indentation:
for ball in ball_list:
random_color = (random.randint(1,255),random.randint(1,255),random.randint(1,255))
circle = pygame.draw.circle(display,random_color,(int(ball.x), int(ball.y)),radius)
rectangle = pygame.draw.rect(display,(255,255,255),(int(rect_x),660,60,60))
if pygame.Rect(circle).colliderect(rectangle):
print('Your Score:',pygame.time.get_ticks())
running = False
This will now run through every ball in the list and check each one for collision. notice the colliderect if statement is indented into the for loop. Also notice i removed the KEYDOWN check from in the middle of it all
Speaking of that I would recommend using:
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT] and rect_x > 0:
rect_x -= 2
if pressed[pygame.K_RIGHT] and rect_x < width - 60:
rect_x += 2
for ball in ball_list:
# for loop from above
instead of what you had. This works best for when you want to allow for holding a key down. pygame.key.get_pressed() gets the state of all the keys all the time, not just when an event happens

Pygame - buggy wall collison [duplicate]

This question already has answers here:
How do I detect collision in pygame?
(5 answers)
How to detect collisions between two rectangular objects or images in pygame
(1 answer)
Closed 2 years ago.
So I've been trying to make a simple maze game in pygame. Currently, I'm having problems with wall collision: The current collision system I'm using is buggy and doesn't work as intended:
import pygame
import random
# mazes
mazes = [
[
"wwwwwwwwwwwwwwwwwwwwwww",
"w w",
"w D",
"w D",
"w w",
"wwwwwwwwwwwwwwwwwwwwwww"
]
,
[
"wwwwwwwwwwwwwwwwwwwwwww",
"w w w",
"w w wwwwwwwwwwwwwwwww w",
"w w wD w w",
"w w wwwwwwwwwwwwwww w w",
"w w w w",
"w wwwwwwwwwwwwwwwwwww w",
"w w",
"wwwwwwwwwwwwwwwwwwwwwww"
]
]
pygame.init()
# Asset and text properties
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
blue = (0, 0, 255)
# Display properties
FPS = 30
display_width = 800
display_height = int(display_width * 2 / 3)
clock = pygame.time.Clock()
block_size = display_width / 40
level = 0
def message_to_screen(msg, color, fontSize, x_axis, y_axis):
font = pygame.font.SysFont(None, fontSize)
screen_text = font.render(msg, True, color)
gameDisplay.blit(screen_text, [x_axis, y_axis])
# Create a game display
gameDisplay = pygame.display.set_mode([display_width, display_height])
pygame.display.set_caption("Mazer - Use arrow keys to move")
def gameloop(): # main function
global level
wall_maze, door_maze = buildMaze(mazes[1])
gameExit = False
gameOver = False
movementSpeed_x = 0
movementSpeed_y = 0
player_x = display_width / 10
player_y = display_height / 1.2
speed = block_size / 2
while not gameExit: #running game loop
while gameOver:
gameDisplay.fill(white)
message_to_screen("Press Q to quit",
red, 40, display_width / 7, display_height / 3 )
message_to_screen("Press N for next level", red, 40,
display_width / 7, display_height / 3 + 40)
pygame.display.update()
for event in pygame.event.get():
if event == pygame.QUIT:
gameExit = True
gameOver = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
gameExit = True
gameOver = False
elif event.key == pygame.K_n:
level += 1
gameOver = False
gameloop()
# Event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
# Movement control
if movementSpeed_y == 0:
if event.key == pygame.K_LEFT:
movementSpeed_x = -speed
if event.key == pygame.K_RIGHT:
movementSpeed_x = speed
if movementSpeed_x == 0:
if event.key == pygame.K_DOWN:
movementSpeed_y = speed
if event.key == pygame.K_UP:
movementSpeed_y = -speed
if event.type == pygame.KEYUP and event.type != pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == pygame.K_DOWN or \
event.key == pygame.K_UP or event.key == pygame.K_RIGHT:
movementSpeed_x = 0
movementSpeed_y = 0
if movementSpeed_x > 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_x = 0
player_x -= speed
elif movementSpeed_x < 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_x = 0
player_x += speed
if movementSpeed_y > 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_y = 0
player_y -= speed
elif movementSpeed_y < 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_y = 0
player_y += speed
player_x += movementSpeed_x
player_y += movementSpeed_y
# Movement control
# Rendering
gameDisplay.fill(white)
mazer = player(block_size, player_x, player_y)
movingSprites = pygame.sprite.Group()
movingSprites.add(mazer)
wall_maze.draw(gameDisplay)
door_maze.draw(gameDisplay)
movingSprites.draw(gameDisplay)
pygame.display.update()
clock.tick(FPS) # FPS tick
if pygame.sprite.spritecollideany(mazer, door_maze):
gameOver = True
pygame.quit()
quit()
class asset(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class player(asset): # Class for player
def __init__(self, size, x, y):
# Image properties for player
super().__init__()
self.image = pygame.Surface([size, size])
self.image.fill(red)
self.rect = self.image.get_rect()
# Player's position
self.rect.x = x
self.rect.y = y
class wall(asset): # Class for wall blocks
def __init__(self, size, x , y):
# Image properties for wall
super().__init__()
self.image = pygame.Surface([size, size])
self.image.fill(black)
self.rect = self.image.get_rect()
# Wall's position
self.rect.x = x
self.rect.y = y
class door(asset):
def __init__(self, size, x, y):
super().__init__()
self.image = pygame.Surface([size, size])
self.image.fill(blue)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def buildMaze(Maze):
wall_list = pygame.sprite.Group()
door_list = pygame.sprite.Group()
pos_x = display_width / 10 - block_size
pos_y = display_height / 1.2 + block_size
for row in Maze:
for space in row:
if space == "w":
wall_maze = wall(block_size, pos_x, pos_y)
wall_list.add(wall_maze)
elif space == "D":
door_maze = door(block_size, pos_x, pos_y)
door_list.add(door_maze)
pos_x += block_size
pos_y -= block_size
pos_x = display_width / 10 - block_size
return wall_list, door_list
gameloop()
If you try to run the code and play around with the game, you'll notice that when you move toward a wall, the player will usually stay inside the wall and the control is inverted (move right when pressing left). I suspected that it has to do with how I constructed my collision detector:
if movementSpeed_x > 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_x = 0
player_x -= speed
elif movementSpeed_x < 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_x = 0
player_x += speed
if movementSpeed_y > 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_y = 0
player_y -= speed
elif movementSpeed_y < 0:
if pygame.sprite.spritecollideany(mazer, wall_maze):
movementSpeed_y = 0
player_y += speed
One more thing, I thought that by having this code before pygame.display.update(), it wouldn't show the player hitting the wall because the position is supposed to be updated before that but somehow it doesn't work as intended. Thank you for looking at my code.

Categories

Resources