How to add gravity to pygame? - python

I've tried to add gravity using the quadratic formula but didn't seem to work and I tried to turn it into a function and that still didn't seem to work. I tried using a class but I don't quite understand how they work so can someone help me add gravity to my platformer. I've tried many videos but didn't seem to help so any help would be much appreciated
import pygame
from pygame.locals import *
from pygame import mixer
from typing import Tuple
import pickle
from os import path
import time
import sys
import os
pygame.init()
white = 255,255,255
black = 0,0,0
green = 0, 255, 0
blue = 0,0,255
font = pygame.font.SysFont('Comic Sans MS', 50, 70)
screen_width = 650
screen_height = 800
screen = pygame.display.set_mode([screen_width,screen_height])
screen.fill((white))
pygame.display.set_caption("Darsh's Game")
pygame.display.update()
pygame.draw.rect(screen,white,(200,150,100,50))
running = 1
speed = 1
x = 25
y = 669
isJump = False
jumpCount = 10
left = False
right = True
def draw_text(text, font, text_col, x, y):
img = font.render(text, True, text_col)
screen.blit(img, (x, y))
def draw_rect():
rect1 = pygame.Rect(0, 0, 25, 800)
pygame.draw.rect(screen, black, rect1)
rect2 = pygame.Rect(625, 0, 25, 800)
pygame.draw.rect(screen, black, rect2)
rect3 = pygame.Rect(0, 775, 650, 25)
pygame.draw.rect(screen, green, rect3)
pygame.display.flip()
def direction(left, right):
if left == True:
screen.blit(mainleft_img, (x, y))
elif right == True:
screen.blit(mainright_img, (x, y))
draw_rect()
draw_text("George is dumb", font, green, 100, 400)
pygame.display.update()
mainright_img = pygame.image.load('newgameimg/mainright.png')
mainleft_img = pygame.image.load('newgameimg/mainleft.png')
screen.blit(mainright_img, (300, 400))
run = True
while run:
draw_text("George is dumb", font, green, 100, 400)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_a] and x > speed - 16:
x -= speed
left = True
right = False
draw_text("George is dumb", font, green, 100, 400)
pygame.display.update()
if keys[pygame.K_d] and x < screen_width - speed - 89:
x += speed
left = False
right = True
draw_text("George is dumb", font, green, 100, 400)
pygame.display.update()
if keys[pygame.K_ESCAPE]:
pygame.quit()
if not (isJump):
if keys[pygame.K_SPACE]: # jumping code
isJump = True
else:
if jumpCount >= -10:
time.sleep(0.02)
y -= (jumpCount * abs(jumpCount)) * 0.5
jumpCount -= 1
else:
jumpCount = 10
isJump = False # jumping code
screen.fill(white)
direction(left, right)
draw_text("George is dumb", font, green, 100, 400)
draw_rect()
pygame.display.update()

You don't need the quadratic formula to get a simple gravity going; a simple gravity variable increasing every frame should do the trick.
...
gravity = 0
while run:
...
...
if keys[pygame.K_SPACE]:
gravity += 1
y -= gravity
...
Note that I don't speak your language; I mainly code in JavaScript, but I did try python once and I got the syntax down pretty quick. Hopefully this suits your needs, with a bit of tweaking of course.

Add a variable fall = 0. Increment the variable if the player does not jump (fall += 0.2). Change the y coordinate of the player through the variable fall in each frame. Get the bounding rectangle of the player with pygame.Surface.get_rect(). If the bottom of the rectangle reaches the floor then stop falling, and restricting the bottom of the rectangle on the floor. Set fall = 0 if the player starts to jump:
while run:
# [...]
if not (isJump):
fall += 0.2
y += fall
player_rect = mainleft_img.get_rect(topleft = (x, y))
if player_rect.bottom > 775:
player_rect.bottom = 775
y = player_rect.top
fall = 0
if keys[pygame.K_SPACE]: # jumping code
isJump = True
fall = 0
else:
# [...]
Multiple calls to pygame.display.update() or pygame.display.flip() cause flickering. Remove all calls to pygame.display.update() from your code, but call it once at the end of the application loop.
In addition, draw each object only once.
Do not delay, wait or sleep. Use pygame.time.Clock to control the frames per second and thus the game speed.
The method tick() of a pygame.time.Clock object, delays the game in that way, that every iteration of the loop consumes the same period of time. See pygame.time.Clock.tick():
This method should be called once per frame.
That means that the loop:
clock = pygame.time.Clock()
run = True
while run:
clock.tick(60)
runs 60 times per second.
See pygame.time.Clock.tick():
This method should be called once per frame. It will compute how many milliseconds have passed since the previous call.
Complete example:
import pygame
from pygame.locals import *
pygame.init()
white = 255,255,255
black = 0,0,0
green = 0, 255, 0
blue = 0,0,255
screen_width = 650
screen_height = 800
screen = pygame.display.set_mode([screen_width,screen_height])
pygame.display.set_caption("Darsh's Game")
font = pygame.font.SysFont('Comic Sans MS', 50, 70)
running = 6
speed = 2
fall = 0
x = 25
y = 669
isJump = False
jumpCount = 10
left = False
right = True
def draw_text(text, font, text_col, x, y):
img = font.render(text, True, text_col)
screen.blit(img, (x, y))
def draw_rect():
rect1 = pygame.Rect(0, 0, 25, 800)
pygame.draw.rect(screen, black, rect1)
rect2 = pygame.Rect(625, 0, 25, 800)
pygame.draw.rect(screen, black, rect2)
rect3 = pygame.Rect(0, 775, 650, 25)
pygame.draw.rect(screen, green, rect3)
def direction(left, right):
if left == True:
screen.blit(mainleft_img, (x, y))
elif right == True:
screen.blit(mainright_img, (x, y))
draw_text("George is dumb", font, green, 100, 400)
mainright_img = pygame.image.load('newgameimg/mainright.png')
mainleft_img = pygame.image.load('newgameimg/mainleft.png')
clock = pygame.time.Clock()
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_a] and x > speed - 16:
x -= speed
left = True
right = False
if keys[pygame.K_d] and x < screen_width - speed - 89:
x += speed
left = False
right = True
if keys[pygame.K_ESCAPE]:
pygame.quit()
if not (isJump):
fall += 0.2
y += fall
player_rect = mainleft_img.get_rect(topleft = (x, y))
if player_rect.bottom > 775:
player_rect.bottom = 775
y = player_rect.top
fall = 0
if keys[pygame.K_SPACE]: # jumping code
isJump = True
fall = 0
else:
if jumpCount >= -10:
y -= (jumpCount * abs(jumpCount)) * 0.5
jumpCount -= 1
else:
jumpCount = 10
isJump = False # jumping code
screen.fill(white)
draw_rect()
direction(left, right)
pygame.display.update()

Related

Making Flappy Bird but how do I implement the pipes generating offscreen then going across the screen and despawning

So I am a bit stuck on how to implement the pipes spawning offscreen and making them move across the screen so that they can collide the bird and then DE spawning off screen. Do I need to give the pipes acceleration or something else?
I am fairly new to code but I have some ides on how to do it but I don't really know how to implement it or how to make a pipes randomly generate.
#Floppy disk
import sys, pygame
from pygame import mixer
import time
pygame.init()
pygame.mixer.init()
FRAMERATE = 60
clock = pygame.time.Clock()
mixer.music.load('africa-toto.wav')
mixer.music.play(1, 0.0, 3000)
size = width, height = 1000, 1000
speed = [2,2]
power = [0.1, 0.1]
white = 255, 255, 255
black = 0, 0, 0
blue = 0, 255, 200
green = 0, 200, 0
dy = 2
dx =2
screen = pygame.display.set_mode(size)
player1 = pygame.image.load("floppy1.jpg")
pygame.key.set_repeat(1,1)
player = pygame.draw.rect(screen, blue, (500, 500,10, 10))
playerrect = player1.get_rect()
background_image = pygame.image.load("circuit.jpeg").convert()
def obstacles():
obst1 = pygame.draw.rect(screen, green, (500, 600, 100, 450))
obst2 = pygame.draw.rect(screen, green, (500, 0, 100, 450))
obst3 = pygame.draw.rect(screen, green, (700, 0, 100, 400))
obst4 = pygame.draw.rect(screen, green, (700, 550, 100, 500))
obstacles()
while True:
clock.tick(FRAMERATE)
print(dy)
if dy > 0:
dy *= 1.03
if dy < 2:
dy *= 1.03
if dy < 0:
dy *= 0.9
if dy > -1.3:
dy *= 0.95
if dy < 0 and dy > -0.6: #Deceleraiton point
dy *= -1.2
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
## if event.key == pygame.K_LEFT:
## speed[0] -= power[0]
## if event.key == pygame.K_RIGHT:
## speed[0] += power[0]
if event.key == pygame.K_UP:
dy = -10
#speed[1] -= power[1]
if event.key == pygame.K_DOWN:
speed[1] += power[1]
if playerrect.bottom > height:
dy = -20
if playerrect.top < 0:
dy = 15
playerrect = playerrect.move(0, dy)
#screen.fill(white)
screen.blit(background_image, [0,0])
screen.blit(player1, playerrect, obstacles())
pygame.display.flip()
pygame.display.update()
for multiple things that do very similar things i would highly recommend the use of classes: https://docs.python.org/3/tutorial/classes.html
# you don't need to declare those variables globally, it's only one of multiple ways.
# a cleaner way would be to declare those as class variables, you can check out the
# documentation (linked above) for more information.
# random needs to be imported
spawn_timer = 0
movement_speed = 2
x_size = 50
gap_size = 300
pipes = []
# screen, width and height have already been declared
class Pipe:
def __init__(self, x_pos=width):
random_height = random.randint(0, height - gap_size)
self.upper_rect = pygame.Rect(x_pos, 0, x_size, random_height)
self.lower_rect = pygame.Rect(x_pos, random_heigt - gap_size,
x_size, height - random_height - gap_size)
def draw(self):
pygame.draw.rect(screen, green, self.upper_rect)
pygame.draw.rect(screen, green, self.lower_rect)
def collide(self, rect):
return self.lower_rect.colliderect(rect) or self.upper_rect.colliderect(rect)
def update(self)
self.upper_rect.move_ip(-movement_speed, 0)
self.lower_rect.move_ip(-movement_speed, 0)
# in the main loop:
spawn_timer += 1
if spawn_timer >= 200: # use different values for distance between pipes
pipes.append(Pipe())
spawn_timer = 0
for pipe in pipes:
pipe.draw()
pipe.update()
if pipe.collide(playerrect):
print('GAME OVER') # reset the game
if pipes and pipes[0].upper_rect.right < 0: # first pipe will be leftmost pipe.
pipes.pop(0)
also i noticed that the falling was not feeling as clean.
for a more natural movement, i would recommend adding something to the dy value instead of multiplying it.
if you have any questions, please write a comment.
EDIT: fixed list index out of range bug.
EDIT: fixed 'module' object is not callable

Move two rects seperately with wasd and arrow keys in pygame?

I am new to programming with pygame and python itself. I was trying to make a simple local multiplayer game using pygame. I wrote my code while watching a tutorial on moving only one rectangle because I did not find anything on what I am trying to do. When I finished, I copied the part of the script with the variables and the movement for the rectangle and then pasted it and changed the variable names so it does not crash or something. Now, here comes my problem: because the movement is simple, it would print a new rectangle, if I press the buttons to move. Because of that, the background is refreshing its color all the time (or something like that) so only the one rectangle I want to move is shown. But if there is a second rect, the color covers it, and only one is visible all the time. How can I fix that?
Here is the code:
import pygame
pygame.init()
win = pygame.display.set_mode((500, 500))
pygame.display.set_caption("local multiplayer")
#variables player 1
X = 200
Y = 200
Width = 40
Height = 60
Vel = 5
#variables player 2
x = 50
y = 50
width = 40
height = 60
vel = 5
run = True
while run:
pygame.time.delay(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
#player 1
if keys[pygame.K_a]:
X -= Vel
if keys[pygame.K_d]:
X += Vel
if keys[pygame.K_w]:
Y -= Vel
if keys[pygame.K_s]:
Y += Vel
win.fill((0, 0, 0))
pygame.draw.rect(win, (255, 255, 255), (X, Y, Width, Height))
pygame.display.update()
#player 2
if keys[pygame.K_LEFT]:
x -= vel
if keys[pygame.K_RIGHT]:
x += vel
if keys[pygame.K_UP]:
y -= vel
if keys[pygame.K_DOWN]:
y += vel
win.fill((0, 0, 0))
pygame.draw.rect(win, (255, 255, 255), (x, y, width, height))
pygame.display.update()
pygame.quit()
When you call win.fill((0, 0, 0)) the entire display is cleared. You have to draw the rectangles at once after clearing the display.
Update of the display at the end of the application loop. Multiple calls to pygame.display.update() or pygame.display.flip() cause flickering (see Why is the PyGame animation is flickering).
Simplify the code and use pygame.Rect objects to represent the players. Use pygame.Rect.clamp_ip to prevent the player from leaving the screen.
import pygame
pygame.init()
win = pygame.display.set_mode((500, 500))
pygame.display.set_caption("local multiplayer")
clock = pygame.time.Clock()
player1 = pygame.Rect(200, 200, 40, 60)
vel1 = 1
player2 = pygame.Rect(50, 40, 40, 60)
vel2 = 1
run = True
while run:
clock.tick(50)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
player1.x += (keys[pygame.K_d] - keys[pygame.K_a]) * vel1
player1.y += (keys[pygame.K_s] - keys[pygame.K_w]) * vel1
player2.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * vel2
player2.y += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * vel2
player1.clamp_ip(win.get_rect())
player2.clamp_ip(win.get_rect())
win.fill((0, 0, 0))
pygame.draw.rect(win, (255, 255, 255), player1)
pygame.draw.rect(win, (255, 255, 255), player2)
pygame.display.update()
pygame.quit()
The typical PyGame application loop has to:
limit the frames per second to limit CPU usage with pygame.time.Clock.tick
handle the events by calling either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by calling either pygame.display.update() or pygame.display.flip()
You are doing win.fill((0, 0, 0)) right after displaying player 1. Remove this code before you display the second character. Also, keep the fill line at the top of your app loop. This would give:
pygame.init()
win = pygame.display.set_mode((500, 500))
pygame.display.set_caption("local multiplayer")
#variables player 1
X = 200
Y = 200
Width = 40
Height = 60
Vel = 5
#variables player 2
x = 50
y = 50
width = 40
height = 60
vel = 5
run = True
while run:
win.fill((0, 0, 0))
pygame.time.delay(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
#player 1
if keys[pygame.K_a]:
X -= Vel
if keys[pygame.K_d]:
X += Vel
if keys[pygame.K_w]:
Y -= Vel
if keys[pygame.K_s]:
Y += Vel
pygame.draw.rect(win, (255, 255, 255), (X, Y, Width, Height))
#player 2
if keys[pygame.K_LEFT]:
x -= vel
if keys[pygame.K_RIGHT]:
x += vel
if keys[pygame.K_UP]:
y -= vel
if keys[pygame.K_DOWN]:
y += vel
pygame.draw.rect(win, (255, 255, 255), (x, y, width, height))
pygame.display.update()
pygame.quit()
It is also good practice to only update the screen once per loop. Another thing I would do is put the input all in the same if block (but that is not necessary). To further improve your code- consider making a player class that has a render function to display itself, along with an update function to handle control.

PyGame Collisions does only work on one side of the rectangle [duplicate]

This question already has an answer here:
How to detect collisions between two rectangular objects or images in pygame
(1 answer)
Closed 2 years ago.
I'm just trying something with collisions and found the way to check one side of the rectangle with the other side.
I have the following problem:
If I move my game character (pink box) from the left against the object, my game character just moves through it:
If I come from the other side, everything works and my game character stops.
I mean to say that I need the same code for both sides but have to change the sides from if not player_rect.left == other_rect.right: to if not player_rect.right == other_rect.left:. But this does not work for one side.
import pygame
import sys
pygame.init()
clock = pygame.time.Clock()
window = pygame.display.set_mode([1200, 800])
pygame.display.set_caption("Collision Test")
x = 300
y = 300
width = 48
height = 96
velocity = 5
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
is_pressed = pygame.key.get_pressed()
player_rect = pygame.Rect(x, y, width, height)
other_rect = pygame.Rect(400, 300, 50, 50)
if is_pressed[pygame.K_d]:
if not player_rect.right == other_rect.left:
x += velocity
if is_pressed[pygame.K_a]:
if not player_rect.left == other_rect.right:
x -= velocity
window.fill((100, 150, 50))
pygame.draw.rect(window, (255, 50, 100), player_rect)
pygame.draw.rect(window, (255, 100, 50), other_rect)
pygame.display.update()
clock.tick(60)
Use collideRect().
Move the object and test if the rectangles are colliding. When a collision is detected, change the position of the object according to the moving direction:
is_pressed = pygame.key.get_pressed()
move_right = is_pressed[pygame.K_d]
move_left = is_pressed[pygame.K_a]
if move_right:
x += velocity
if move_left:
x -= velocity
player_rect = pygame.Rect(x, y, width, height)
other_rect = pygame.Rect(400, 300, 50, 50)
if player_rect.colliderect(other_rect):
if move_right:
player_rect.right = other_rect.left
x = player_rect.left
if move_left:
player_rect.left = other_rect.right
x = player_rect.left
For a smooth movement you've to do evaluate pygame.key.get_pressed() in the application loop rather than the event loop.
See also What all things happens inside pygame when I press a key? When to use pygame.event==KEYDOWN.
import pygame
import sys
pygame.init()
clock = pygame.time.Clock()
window = pygame.display.set_mode([1200, 800])
pygame.display.set_caption("Collision Test")
x = 300
y = 300
width = 48
height = 96
velocity = 5
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
is_pressed = pygame.key.get_pressed()
move_right = is_pressed[pygame.K_d]
move_left = is_pressed[pygame.K_a]
if move_right:
x += velocity
if move_left:
x -= velocity
player_rect = pygame.Rect(x, y, width, height)
other_rect = pygame.Rect(400, 300, 50, 50)
if player_rect.colliderect(other_rect):
if move_right:
player_rect.right = other_rect.left
x = player_rect.left
if move_left:
player_rect.left = other_rect.right
x = player_rect.left
window.fill((100, 150, 50))
pygame.draw.rect(window, (255, 50, 100), player_rect)
pygame.draw.rect(window, (255, 100, 50), other_rect)
pygame.display.update()
clock.tick(60)

How to create a play again button in pygame

So i created space invaders with pygame and wanted to create a Quit and play again button when the player died. The quit button works but the play again button isn't working. I have not used a def for the button instead i have made it inside the code.This is my code:
import pygame
import random
import math
pygame.init()
screen = pygame.display.set_mode((800, 600)) # CREATING SCREEN
background = pygame.image.load('background.jpg')
pygame.display.set_caption("Space invaders") # Title of the game
icon = pygame.image.load('spaceship.png') # A variable for the icon of the game
pygame.display.set_icon(icon) # to display the icon
player_icon = pygame.image.load('space-invaders.png') # A variable for player's icon
playerX = 365 # X coordinate
playerY = 500 # Y coordinate
playerX_change = 0
def player(x, y):
screen.blit(player_icon,(x, y)) # Function to display player_icon {there is supposed to be a comma after image name}
enemy_icon = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change =[]
num_of_enemies = 5
for i in range(num_of_enemies):
enemy_icon.append(pygame.image.load('alien.png')) # A variable for enemy's's icon
enemyX.append(random.randint(0,736)) # X coordinate
enemyY.append(random.randint(50 ,150)) # Y coordinate
enemyX_change.append(2)
enemyY_change.append(40)
def enemy(x, y, i):
screen.blit(enemy_icon[i], (x, y)) # Function to display enemy_icon {there is supposed to be a comma after image name}
bullet_icon = pygame.image.load('bullet.png') # A variable for enemy's's icon
bulletX = 0 # X coordinate
bulletY = 480 # Y coordinate
bulletX_change = 0
bulletY_change = 5
bullet_state = "ready"
score_value = 0
font = pygame.font.Font('freesansbold.ttf',32)
textX = 10
textY = 10
red = (200, 0, 0)
brigth_red = (255,0 ,0)
green = (0, 200, 0)
brigth_green = (0, 255, 0)
blue = (0, 0, 255)
white = (255,255,255)
black = (0, 0 ,0)
def show_score(x,y):
score = font.render('Score: ' + str(score_value), True, (255, 255, 255))
screen.blit(score, (x, y))
over_text = pygame.font.Font('freesansbold.ttf',128)
def game_over_text():
over_text = font.render('GAME OVER !!' , True, (255, 255, 255))
screen.blit(over_text, (300, 150))
def on_button(x,y,text =''):
button_text = pygame.font.Font('freesansbold.ttf', 5)
button_text = font.render(text, True, (black))
screen.blit(button_text, ((x + 5), (y + 5)))
def bullet(x, y):
screen.blit(bullet_icon, (x, y)) # Function to display enemy_icon {there is supposed to be a comma after image name}
def fire_bullet(x,y):
global bullet_state
bullet_state = "fire"
screen.blit(bullet_icon, (x+19, y+10))
def iscoalision(bulletX,bulletY,enemyX,enemyY):
distance = math.sqrt(math.pow(enemyX - bulletX,2) + math.pow(enemyY-bulletY,2))
if distance < 25:
return True
else:
return False
running = True
game_state = "not working"
while running :
screen.fill((0, 0, 0)) # to fill the screen with some color RGB = (red,green,blue)
screen.blit(background, (0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
round = 11
if event.type == pygame.KEYDOWN: # If arrow key is pressed change value of playerX_change
if event.key == pygame.K_LEFT:
playerX_change = -3
if event.key == pygame.K_RIGHT:
playerX_change = 3
if event.key == pygame.K_SPACE:
if bullet_state is "ready":
bulletX = playerX
fire_bullet(bulletX,bulletY)
if event.type == pygame.KEYUP: # If arrow key is released stop changing value of playerX_change
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
playerX_change = 0
playerX += playerX_change #player movement
if playerX <= 0: #(The boundary)
playerX = 0
elif playerX >= 736: #( " )
playerX = 736
for i in range(num_of_enemies):
if enemyY[i] > 440:
for j in range(num_of_enemies):
enemyY[j] = 2000
game_over_text()
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if 100 + 200 > mouse[0] > 100 and 300 + 50 > mouse[1] > 300: # This is where i try to make play again button
pygame.draw.rect(screen, brigth_green, (100, 300, 200, 50)) # inside the bracket(x-axis , y-axis , width, hieght)
if click[0] == 1: #the tuple for clicks is (0,0,0) [0] = left click ,[1]= middle click. if clicked [0] or [1] or [2] = 1
pass
else:
pygame.draw.rect(screen, green, (100, 300, 200, 50))
on_button(100,300,'play again?')
if 500+ 200 >mouse[0] > 500 and 300 +50 >mouse[1] > 300:
pygame.draw.rect(screen, brigth_red, (500, 300, 200, 50))
if click[0] == 1:
running = False
break
else:
pygame.draw.rect(screen, red, (500, 300, 200, 50))
on_button((500 + 50),(300 + 5),"I QUIT")
enemyX[i] += enemyX_change[i] #enemy movement
if enemyX[i] <= 0: #(The boundary two and fro movement)
enemyX_change[i] = 2
enemyY[i] += enemyY_change[i]
elif enemyX[i] >= 736: #( " )
enemyX_change[i] = -2
enemyY[i] += enemyY_change[i]
coalision = iscoalision(bulletX, bulletY, enemyX[i], enemyY[i])
if coalision:
bullet_state = "ready"
bulletY = 480
score_value += 1
enemyX[i] = random.randint(0, 736)
enemyY[i] = random.randint(50, 150)
enemy(enemyX[i], enemyY[i], i)
if bulletY <= 0:
bullet_state = "ready"
bulletY = 480
if bullet_state is "fire":
fire_bullet(bulletX,bulletY)
bulletY -= bulletY_change
player(playerX, playerY)
show_score(textX, textY)
pygame.display.update()
Till now i have tried to put the entire while loop i an if condition that if condition is satisfied then run the while loop but that isn't working. I've also tried to put the entire code in a def and call out the def when i needed to play again and that worked but that made the bullets bug which i couldn't fix. Here is the play agin button and function.
for i in range(num_of_enemies):
if enemyY[i] > 440:
for j in range(num_of_enemies):
enemyY[j] = 2000
game_over_text()
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if 100 + 200 > mouse[0] > 100 and 300 + 50 > mouse[1] > 300:
pygame.draw.rect(screen, brigth_green, (100, 300, 200, 50))
if click[0] == 1:
pass
for now i filled the place for the button function with a pass. Hope this much info helps.
Firstly, make your code object oriented. If you don't know what that is, there are plenty of tutorials on youtube, but just looking at your code, I can see that you are going to run into a bunch of headache in the future if you continue without any type of classes and objects. You should make a class for player, enemy and bullets and then define their attributes and call methods on them such as move() or draw().
To answer you question, you can create a simple button class:
class Buttons(object):
def __init__(self, x, y, width, height, colour1, text='', func=None, arg=None): # pink buttons
self.x = x
self.y = y
self.width = width
self.height = height
self.colour1 = colour1
self.text = text
self.func = func
self.arg = arg
def draw(self, win): # draws centralised buttons and text
font = pygame.font.SysFont('comicsans', 30, True)
text = font.render(self.text, 1, colours["black"])
pygame.draw.rect(win, self.colour1,
(int(self.x - self.width // 2), int(self.y - self.height // 2), int(self.width), int(self.height)))
win.blit(text, (int(self.x - text.get_width() // 2), int(self.y - text.get_height() // 2)))
def isover(self, pos): # detects if mouse positions is above buttons'
if self.x < pos[0] < (self.x + self.width) and self.y < pos[1] < (self.y + self.height):
return True
return False
def isclicked(self, pos): # pos here is mouse position
if self.isover(pos):
if self.arg is not None:
self.func(*self.arg):
else:
self.func():
def quit(your_quit_args):
# this is your quit function. You might want to close any files, etc before quitting
def play_again(your_play_again_args):
# here, you should reset all values, clear queues, lists etc
With that then, to create a button, all you would need to do is just create a new button object:
# use the x, y, width, height, colour and text you want
btn_play_again = Button(x, y, width, height, colour, text=your_text, func=quit, args=your_quit_args)
btn_quit = Button(x, y, width, height, colour, text=your_text, func=play_again, args=your_play_again_args)
the above will create the button objects, but you have to actually draw them and check if they are clicked, which you should do in your main loop:
while running:
# everything else
btn_quit.draw(screen)
btn_play_again.draw(screen)
pos = pygame.mouse.get_pos()
btn_quit.isclicked(pos)
btn_play_Again.draw(pos)
pygame.display.update()
Note, if you have many buttons, it may be worth to put them all in a button list and iterate through it to avoid repeating code.

Why doesn't PyGame draw in the window before the delay or sleep?

I am working on a pong game. When either of the scores hit 10, it is supposed to put up some text on the screen and say the right player has won or left player has won. However, in my program, it isn't working. When it has to show the text that the right or left player has won, it doesn't show it. But it works for everything else. Here is the code:
# Importing libraries
import pygame
import random
import time
# Initializing PyGame
pygame.init()
# Setting a window name
pygame.display.set_caption("Ping Pong")
# Creating a font
pygame.font.init()
font = pygame.font.SysFont(None, 30)
pong_font = pygame.font.SysFont("comicsansms", 75)
# Set the height and width of the screen
window_width = 700
window_height = 500
size = [window_width, window_height]
game_win = pygame.display.set_mode(size)
game_win2 = pygame.display.set_mode(size)
# Creating a messaging system
def message(sentence, color, x, y, font_type, display):
sentence = font_type.render(sentence, True, color)
display.blit(sentence, [x, y])
# Creating colors
white = (225, 225, 225)
black = (0, 0, 0)
gray = (100, 100, 100)
# Setting up ball
ball_size = 25
class Ball:
"""
Class to keep track of a ball's location and vector.
"""
def __init__(self):
self.x = 0
self.y = 0
self.change_x = 0
self.change_y = 0
def make_ball():
ball = Ball()
# Starting position of the ball.
ball.x = 350
ball.y = 250
# Speed and direction of rectangle
ball.change_x = 5
ball.change_y = 5
return ball
def main():
# Scores
left_score = 0
right_score = 0
pygame.init()
# Loop until the user clicks the close button.
done = False
ball_list = []
ball = make_ball()
ball_list.append(ball)
# Right paddle coordinates
y = 200
y_change = 0
x = 50
# Left paddle coordinates
y1 = 200
y1_change = 0
x1 = 650
while not done:
# --- Event Processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
y_change = -7
elif event.key == pygame.K_s:
y_change = 7
elif event.key == pygame.K_UP:
y1_change = -7
elif event.key == pygame.K_DOWN:
y1_change = 7
elif event.type == pygame.KEYUP:
y_change = 0
y1_change = 0
y += y_change
y1 += y1_change
# Preventing from letting the paddle go off screen
if y > window_height - 100:
y -= 10
if y < 50:
y += 10
if y1 > window_height - 100:
y1 -= 10
if y1 < 50:
y1 += 10
# Logic
for ball in ball_list:
# Move the ball's center
ball.x += ball.change_x
ball.y += ball.change_y
# Bounce the ball if needed
if ball.y > 500 - ball_size or ball.y < ball_size:
ball.change_y *= -1
if ball.x > window_width - ball_size:
ball.change_x *= -1
left_score += 1
if ball.x < ball_size:
ball.change_x *= -1
right_score += 1
ball_rect = pygame.Rect(ball.x - ball_size, ball.y - ball_size, ball_size * 2, ball_size * 2)
left_paddle_rect = pygame.Rect(x, y, 25, 75)
if ball.change_x < 0 and ball_rect.colliderect(left_paddle_rect):
ball.change_x = abs(ball.change_x)
right_paddle_rect = pygame.Rect(x1, y1, 25, 75)
if ball.change_x > 0 and ball_rect.colliderect(right_paddle_rect):
ball.change_x = -abs(ball.change_x)
# Here is the where the messaging system doesn't work, I don't know why! It works fine for everything else
if right_score == 10:
message("RIGHT PLAYER HAS WON!!", white, 300, 200, font, game_win)
time.sleep(5)
pygame.quit()
quit()
elif left_score == 10:
message("LEFT PLAYER HAS WON!!", white, 300, 200, font, game_win)
time.sleep(5)
pygame.quit()
quit()
# Drawing
# Set the screen background
game_win.fill(black)
# Draw the balls
for ball in ball_list:
pygame.draw.circle(game_win, white, [ball.x, ball.y], ball_size)
# Creating Scoreboard
message("Left player score: " + str(left_score), white, 10, 10, font, game_win)
message("Right player score: " + str(right_score), white, 490, 10, font, game_win)
# Drawing a left paddle
pygame.draw.rect(game_win, white, [x, y, 25, 100])
# Drawing a right paddle
pygame.draw.rect(game_win, white, [x1, y1, 25, 100])
# Setting FPS
FPS = pygame.time.Clock()
FPS.tick(60)
# Updating so actions take place
pygame.display.flip()
while True:
game_win2.fill(black)
pygame.event.get()
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
message("Pong", white, 280, 100, pong_font, game_win2)
if 150 + 100 > mouse[0] > 150 and 350 + 50 > mouse[1] > 350:
pygame.draw.rect(game_win, gray, [150, 350, 100, 50])
if click[0] == 1:
break
else:
pygame.draw.rect(game_win, white, [150, 350, 100, 50])
if 450 + 100 > mouse[0] > 450 and 350 + 50 > mouse[1] > 350:
pygame.draw.rect(game_win, gray, [450, 350, 100, 50])
if click[0] == 1:
pygame.quit()
quit()
else:
pygame.draw.rect(game_win, white, [450, 350, 100, 50])
message("Start", black, 175, 367, font, game_win2)
message("Quit", black, 475, 367, font, game_win2)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Wrap-up
# Limit to 60 frames per second
clock = pygame.time.Clock()
clock.tick(60)
if __name__ == "__main__":
main()
I have added a little comment, it is: "# Here is the where the messaging system doesn't work, I don't know why! It works fine for everything else". Now when someone scores 10 points, Nothing happens. Its= wait for a couple of seconds. That is so you can read the "Left player has won" or "Right player has won" before the program closes. But it simply doesn't show up! I don't know why! Can someone help with this?
The display is updated only if either pygame.display.update() or pygame.display.flip()
is called. See pygame.display.flip():
This will update the contents of the entire display.
Further you've to handles the events with pygame.event.pump(), before the update of the display becomes visible in the window.
See pygame.event.pump():
For each frame of your game, you will need to make some sort of call to the event queue. This ensures your program can internally interact with the rest of the operating system.
If you want to display a text and delay the game, then you've to update the display and handle the events.
Write a function which delays the game and updates the display. I recommend to use the pygame.time module to implement the delay (e.g. pygame.time.delay())
def update_and_wait(delay):
pygame.display.flip()
pygame.event.pump()
pygame.time.delay(delay * 1000) # 1 second == 1000 milliseconds
Or even implement a function which its own event loop to keep the application responding. Measure the time by pygame.time.get_ticks():
def update_and_wait(delay):
start_time = pygame.time.get_ticks()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
print("auit")
pygame.quit()
return False
if pygame.time.get_ticks() >= start_time + delay * 1000:
break
return True
Use the function in the application:
def main():
# [...]
while not done:
# [...]
for ball in ball_list:
# [...]
if right_score == 0:
message_wait("RIGHT PLAYER HAS WON!!", white, 300, 200, font, game_win)
update_and_wait(5)
quit()
elif left_score == 0:
message_wait("LEFT PLAYER HAS WON!!", white, 300, 200, font, game_win)
update_and_wait(5)
quit()

Categories