Moving rectange using pygame keeps flickering - python

import pygame
import random
black = (0,0,0)
white = (255,255,255)
green = (0,255,0)
red = (255,0,0)
screen = pygame.display.set_mode((1200, 600))
title = pygame.display.set_caption("Speeding cars")
clock = pygame.time.Clock()
clock.tick(60)
class Car:
def __init__(self, x, y, height, width):
self.x = x
self.y = y
self.height = height
self.width = width
def drive(self, change):
self.change = random.randint(1, 3)
self.x += self.change
pygame.draw.rect(screen, black, (self.x, self.y, self.height, self.width))
pygame.display.flip()
car1 = Car(30, 100, 50, 15)
car2 = Car(30, 200, 50, 15)
car3 = Car(30, 300, 50, 15)
car4 = Car(30, 400, 50, 15)
car5 = Car(30, 500, 50, 15)
driving = True
while driving:
screen.fill(white)
car1.drive(0)
car2.drive(0)
car3.drive(0)
car4.drive(0)
car5.drive(0)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
pygame.display.flip()
When i try to run this code everything works fine but the rectanges keeps flickering. I tried changing flip to update and adding or removing pygame.display.flip() at different points in code but it dosent seem to work.
Edit: I also just realised that when i comment out the rest of the cars and only run the first one, it runs fine. The problem starts with the second car.
Thanks for help.

Instead of updating the screen in the drive() method, do it at the end of your main loop.
Also, try not to use repetitive code for each new object that is created, but use a for loop instead.
Here you go:
import pygame
import random
black = (0,0,0)
white = (255,255,255)
green = (0,255,0)
red = (255,0,0)
screen = pygame.display.set_mode((1200, 600))
title = pygame.display.set_caption("Speeding cars")
clock = pygame.time.Clock()
clock.tick(60)
class Car:
def __init__(self, x, y, height, width):
self.x = x
self.y = y
self.height = height
self.width = width
def drive(self, change):
self.change = random.randint(1, 1)
self.x += self.change
pygame.draw.rect(screen, black, (self.x, self.y, self.height, self.width))
cars = []
for i in range(1,6):
cars.append(Car(30, 100*i, 50, 15))
driving = True
while driving:
screen.fill(white)
for car in cars:
car.drive(0)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
pygame.display.update()

There should be only one flip()/update() which is executed after you draw all shapes and blit all image. It sends buffer screen to video card which display it on monitor.
If you use after every drive then it send screen to monitor with only one car and later it send screen only with second car, etc.
import pygame
import random
black = (0,0,0)
white = (255,255,255)
green = (0,255,0)
red = (255,0,0)
screen = pygame.display.set_mode((1200, 600))
title = pygame.display.set_caption("Speeding cars")
clock = pygame.time.Clock()
clock.tick(60)
class Car:
def __init__(self, x, y, height, width):
self.x = x
self.y = y
self.height = height
self.width = width
def drive(self, change):
self.change = random.randint(1, 3)
self.x += self.change
pygame.draw.rect(screen, black, (self.x, self.y, self.height, self.width))
# pygame.display.flip() # don't use it
car1 = Car(30, 100, 50, 15)
car2 = Car(30, 200, 50, 15)
car3 = Car(30, 300, 50, 15)
car4 = Car(30, 400, 50, 15)
car5 = Car(30, 500, 50, 15)
driving = True
while driving:
screen.fill(white)
car1.drive(0)
car2.drive(0)
car3.drive(0)
car4.drive(0)
car5.drive(0)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
pygame.display.flip() # after `for event`, not inside `for event`

Related

Why is it stopping when it is not supposed to

I am creating a space Invaders game and have asked the stackoverflow community about it. But this time things are a bit more complicated. There is no visible error but the window just pops up and closes which is not supposed to happen. I created a loop and for some reason it isnt working
import pygame
import os
import time
import random
pygame.font.init()
WIDTH, HEIGHT = 750, 750
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Space Invaders")
# Load Images
RED_SPACE_SHIP = pygame.image.load(os.path.join("assets", "pixel_ship_red_small.png"))
GREEN_SPACE_SHIP = pygame.image.load(os.path.join("assets", "pixel_ship_green_small.png"))
BLUE_SPACE_SHIP = pygame.image.load(os.path.join("assets", "pixel_ship_blue_small.png"))
# Player Ship
RED_SPACE_SHIP = pygame.image.load(os.path.join("assets", "pixel_ship_yellow.png"))
# Lasers
RED_LASER = pygame.image.load(os.path.join("assets", "pixel_laser_red.png"))
GREEN_LASER = pygame.image.load(os.path.join("assets", "pixel_laser_green.png"))
BLUE_LASER = pygame.image.load(os.path.join("assets", "pixel_laser_blue.png"))
YELLOW_LASER = pygame.image.load(os.path.join("assets", "pixel_laser_yellow.png"))
# Background
BG = pygame.transform.scale(pygame.image.load(os.path.join("assets", "background-black.png")), (WIDTH, HEIGHT))
class Ship:
def __init__(self, x, y, health = 100):
self.x = x
self.y = y
self.health = health
self.ship_img = None
self.laser_img = None
self.lasers = []
self.cool_down_counter = 0
def draw(self, window):
pygame.draw.rect(window, (255,0,0), (self.x, self.y, 50, 50))x
def main():
run = True
FPS = 60
level = 1
lives = 5
main_font = pygame.font.SysFont("comicsans", 50)
ship = Ship(300, 650)
clock = pygame.time.Clock()
def redraw_window():
WIN.blit(BG, (0,0))
# draw text
lives_label = main_font.render(f"Lives: {lives}", 1, (255,255,255))
level_label = main_font.render(f"Level: {level}", 1, (255,255,255))
WIN.blit(lives_label, (10, 10))
WIN.blit(level_label,(WIDTH - level_label.get_width() - 10, 10))
ship.draw(WIN)
pygame.display.update()
while run:
clock.tick(FPS)
redraw_window()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
main()
I tried reviewing my code but I couldn't see anything.
The problem is that your infinite while loop doesn't do anything, and runs forever doing that. Your loop needs to be:
while run:
clock.tick(FPS)
redraw_window()
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False

How to create different layer of background for pygame packed into one class

I'm really new to pygame and Python classes. I tried to create a game with different layers.
Layer 1: gameplay
Layer 2: HP: Position:...
It looks a little bit like this:
I think the problem with my code is that i did not know how to use class properly. And I use the wrong method to create a layer for my game.
import pygame
from pygame.locals import *
import sys
pygame.init()
colors = [(255, 255, 255), (204, 229, 255), (0, 0, 0)] #white, light_blue, black
X_AXIS = [x for x in range(11)]
Y_AXIS = ("X A B C D E F G H I").split()
class character:
pass
class Gameplay:
def __init__(self, width, height):
self.width = width
self.height = height
self.display = pygame.display.set_mode((self.width, self.height))
logo = pygame.image.load(r'logo.png')
pygame.display.set_caption("Battle Royale")
pygame.display.set_icon(logo)
def background_layer(self):
self.game_surf = pygame.surface.Surface((800,600))
game_surf.fill(colors[0])
display.blit(game_surf, (0, 0))
gameplay = Gameplay(1300, 760)
while True:
gameplay.background_layer()
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
pass
elif event.type == QUIT:
pygame.quit()
sys.exit()
First few mistakes:
You forgot self. in few places and it should gives you error messages (but you didn't mention it).
You forgot pygame.display.flip() to send from buffer to screen.
If you want other layers then you should add other functions to draw them.
At this moment I see only def background_layer() but you could add other functions for other layers and later execute them in loop - like this:
while True:
self.draw_background()
self.draw_player()
self.draw_grid()
self.draw_info()
pygame.display.flip()
for event in pygame.event.get():
# ... code ...
Minimal working code with other changes.
import sys
import pygame
# --- constants ---- # PEP8: `UPPER_CASE_NAMES` for constants
COLORS = [(255, 255, 255), (204, 229, 255), (0, 0, 0)] #white, light_blue, black
X_AXIS = list(range(11))
Y_AXIS = list("XABCDEFGHI")
# --- classes --- # PEP8: `CamelCaseNames` for classes
class Character:
pass
class Game:
def __init__(self, width, height):
self.width = width
self.height = height
pygame.init()
self.display = pygame.display.set_mode((self.width, self.height))
#self.display_rect = self.display.get_rect()
pygame.display.set_caption("Battle Royale")
#logo = pygame.image.load(r'logo.png')
#pygame.display.set_icon(logo)
self.layer_background = pygame.surface.Surface((800, 600))
self.layer_background.fill(COLORS[0])
self.layer_background_rect = self.layer_background.get_rect()
self.pos = 'X0'
self.hp = 100
self.font = pygame.font.SysFont(None, 40)
def draw_background(self):
self.display.blit(self.layer_background, self.layer_background_rect)
def draw_grid(self):
for x in range(0, 800, 50):
pygame.draw.line(self.display, COLORS[2], (x, 0), (x, 600))
for y in range(0, 600, 50):
pygame.draw.line(self.display, COLORS[2], (0, y), (800, y))
def draw_info(self):
text_image = self.font.render(f"POS: {self.pos}", False, COLORS[0])
text_rect = text_image.get_rect(x=880, y=350)
self.display.blit(text_image, text_rect)
text_image = self.font.render(f"HP: {self.hp}", False, COLORS[0])
text_rect = text_image.get_rect(x=880, y=450)
self.display.blit(text_image, text_rect)
def run(self):
while True:
self.draw_background()
#self.draw_player()
self.draw_grid()
self.draw_info()
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
pass
elif event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# --- functions --- # PEP8: `lower_case_names` for functions
# empty
# --- main ---
game = Game(1300, 760)
game.run()

drawing objects on pygame

I am restarting some code for a covid simulation as I cant use the collide function in my current one. I have been able to draw the basic background, and draw one cell. However, when i try create the cell in a different place on my screen it does not appear for some reason.
My code is as seen below:
import random
import pygame
# import numpy
import time
pygame.init()
GREEN1 = (0, 255, 0) # Healthy cells
RED = (255, 0, 0) # Infected cells
GREEN2 = (0, 100, 0) # Healthy cells not susecptible
BLACK = (0, 0, 0) # Dead cells
WHITE = (255, 255, 255)
Bgcolor = (225, 198, 153)
ScreenSize = (800, 800)
Screen = pygame.display.set_mode(ScreenSize)
pygame.display.set_caption("Covid-19 Simualtion")
clock = pygame.time.Clock()
speed = [0.5, -0.5]
class Cells(pygame.sprite.Sprite):
def __init__(self, color, speed, width, height):
super().__init__()
self.color = color
self.x_cord = random.randint(0, 400)
self.y_cord = random.randint(50, 700)
self.radius = 5
self.speed = speed
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
pygame.draw.circle(self.image, self.color, [30, 70], self.radius, width = 0)
self.rect = self.image.get_rect()
self.radius = 5
#x_number = random.randint(0, 1)
#self.xSpeed = speed[x_number]
#y_number = random.randint(0, 1)
#self.ySpeed = speed[y_number]
allCellsList = pygame.sprite.Group()
Cell1 = Cells(GREEN1, 5, 50, 50)
allCellsList.add(Cell1)
End = False
while not End:
for event in pygame.event.get():
if event.type == pygame.QUIT:
End = True
Screen.fill(Bgcolor)
pygame.draw.rect(Screen, BLACK, (0, 50, 400, 700), 3)
allCellsList.update()
allCellsList.draw(Screen)
pygame.display.flip()
clock.tick(60)
Thanks for any help in advance
The main problem is that your cell has size (50,50) and you try to draw on position (20,70) so it draws outside rectangle (50, 50) and you can't see it. You have to draw inside rectangle (50, 50) - for example in center (25,25). And later you should use self.rect to move it on screen.
Second problem is that you keep position in self.x_coord, self.x_coord but you should use self.rect.x self.rect.y because Sprite use self.image and self.rect to draw it on screen.
And it show third problem - in Cell you need method update which will change values in self.rect to move object.
Minimal working example which move 5 cells in random directions.
I organize code in different way and try to use PEP 8 - Style Guide for Python Code
import random
import pygame
# --- constants --- (UPPER_CASE_NAMES)
GREEN1 = (0, 255, 0) # Healthy cells
RED = (255, 0, 0) # Infected cells
GREEN2 = (0, 100, 0) # Healthy cells not susecptible
BLACK = (0, 0, 0) # Dead cells
WHITE = (255, 255, 255)
BACKGROUND_COLOR = (225, 198, 153)
SCREEN_SIZE = (800, 800)
# --- classes --- (CamelCaseNames)
# class keeep only one cell so it should has name `Cell` instead of `Cells`
class Cell(pygame.sprite.Sprite):
def __init__(self, color, speed, width, height):
super().__init__()
self.color = color
self.speed = speed
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
self.radius = width//2 # 25
center = [width//2, height//2]
pygame.draw.circle(self.image, self.color, center, self.radius, width=0)
self.rect = self.image.get_rect()
self.rect.x = random.randint(0, 400)
self.rect.y = random.randint(50, 700)
def update(self):
self.rect.x += random.randint(-10, 10)
self.rect.y += random.randint(-10, 10)
# --- functions --- (lower_case_names)
# empty
# --- main --- (lower_case_names)
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE)
pygame.display.set_caption("Covid-19 Simualtion")
speed = [0.5, -0.5]
# - objects -
all_cells = pygame.sprite.Group() # PEP8: lower_case_name
for _ in range(5):
cell = Cell(GREEN1, 5, 50, 50) # PEP8: lower_case_name
all_cells.add(cell)
# - loop -
clock = pygame.time.Clock()
end = False
while not end:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
end = True
# - upadates (without draws) -
all_cells.update()
# - draws (without updates) -
screen.fill(BACKGROUND_COLOR)
pygame.draw.rect(screen, BLACK, (0, 50, 400, 700), 3)
all_cells.draw(screen)
pygame.display.flip()
clock.tick(30) # to use less CPU
# - end
pygame.quit() # some system may need it to close window

AttributeError: 'Player' object has no attribute 'collidepoint'

im currently learning to program in python (first language) and im trying to create a clicker game, however, while doing the click function i got this error:
line 73, in <module>
if player.collidepoint(event.pos):
AttributeError: 'Player' object has no attribute 'collidepoint'
it seems that my "player" object (the clickable object) doesnt have a rect ? but after looking it up for hours i could not find an answer
this is my game code
import pygame
from os import path
img_dir = path.join(path.dirname(__file__), "img")
width = 500
height = 600
fps = 30
# Cores
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0 ,0)
green = (0, 255, 0)
blue = (0, 0, 255)
yellow = (255, 255, 0)
# Iniciar o game
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Trojan Clicker")
clock = pygame.time.Clock()
font_name = pygame.font.match_font("arial")
def draw_text(surf, text, size, x , y):
font = pygame.font.Font(font_name, size)
text_surface = font.render(text, True, white)
text_rect = text_surface.get_rect()
text_rect.midtop = (x, y)
surf.blit(text_surface, text_rect)
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((75, 75))
self.image.fill(red)
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
self.rect.centerx = width / 2
self.rect.bottom = height / 2
self.speedx = 0
def update(self):
self.speedx = 0
all_sprites = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
clicks = 0
# Loop
running = True
while running:
# Fps
clock.tick(fps)
# Eventos
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
# 1 is the left mouse button, 2 is middle, 3 is right.
if event.button == 1:
# `event.pos` is the mouse position.
if player.collidepoint(event.pos):
# Increment the number.
number += 1
# Updates
all_sprites.update()
# Draw / render X
screen.fill(black)
all_sprites.draw(screen)
draw_text(screen, str(clicks), 18, width / 2, 10)
# Depois de desenhar tudo, "flip" o display
pygame.display.flip()
pygame.quit()
Some comments are in portuguese btw, sorry about that
Thanks in advance for everyone who helps
Change the line
if player.collidepoint(event.pos):
to
if player.rect.collidepoint(event.pos):

python: for loops and classes

this program makes boxes move, but i need to make them move randomly and indepensent of each other,
by calling the method "rect.move()" for each of the boxes but i don't know how to do that can u help me.
ex. of how it should not look like: https://youtu.be/D7rkcA0-BR0
import pygame
import random
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
class Rect():
def __init__(self):
self.rectXPos = 0
self.rectYPos = 0
self.height = 0
self.width = 0
self.changeX = 0
self.changeY = 0
self.x = 0
self.y = 0
def move(self):
self.x += self.changeX
self.y += self.changeY
def draw(self,screen):
pygame.draw.rect(screen,RED,[self.x + self.rectXPos, self.y + self.rectYPos, self.height,self.width])
pygame.init()
# Set the width and height of the screen [width, height]
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
myList =[]
for i in range(10):
rect = Rect()
rect.rectXPos = random.randrange(0,700)
rect.rectYPos = random.randrange(0,500)
rect.height = random.randrange(20,70)
rect.width = random.randrange(20,70)
rect.changeX = random.randrange(-3,3)
rect.changeY = random.randrange(-3,3)
myList.append([rect.rectXPos , rect.rectYPos, rect.height, rect.width, rect.changeX, rect.changeY])
# -------- Main Program Loop -----------
while not done:
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# --- Game logic should go here
# --- Screen-clearing code goes here
# Here, we clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
# If you want a background image, replace this clear with blit'ing the
# background image.
screen.fill(WHITE)
for i in range(10):
rect.rectXPos = myList[i][0]
rect.rectYPos = myList[i][1]
rect.height = myList[i][2]
rect.width = myList[i][3]
rect.changeX = myList[i][4]
rect.changeY= myList[i][5]
rect.draw(screen)
rect.move()
# --- Drawing code should go here
# --- Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# --- Limit to 60 frames per second
clock.tick(60)
# Close the window and quit.
pygame.quit()
this is premade code from http://programarcadegames.com/
What you need is for the Rect attributes to be randomly generated with the random module. I have modified the code you gave an made some changes.
Firstly I changed the draw method so that it just draws at the x and y values.
The biggest change was that instead of the big complicated myList list in your code, I just stored 10 Rect objects in a list called myRects which I think is much simpler.
You can fiddle around some more with the number generation from around Line 45-52. You can read a bit more on the random.randrange() function here: https://docs.python.org/3/library/random.html#functions-for-integers
I hope this answer helped you! If you have any further questions please post a comment below!
import pygame
import random
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
class Rect():
def __init__(self):
self.x = 0
self.y = 0
self.height = 0
self.width = 0
self.changeX = 0
self.changeY = 0
def move(self):
self.x += self.changeX
self.y += self.changeY
def draw(self, screen):
pygame.draw.rect(screen, RED, [self.x, self.y, self.width, self.height], 0)
pygame.init()
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
done = False
clock = pygame.time.Clock()
myRects = []
for i in range(10):
rect = Rect()
rect.x = random.randrange(0, 700)
rect.y = random.randrange(0, 700)
rect.width = random.randrange(20, 70)
rect.height = random.randrange(20, 70)
rect.changeX = random.randrange(-3, 3)
rect.changeY = random.randrange(-3, 3)
myRects.append(rect)
print(myRects)
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(WHITE)
for rect in myRects:
rect.draw(screen)
rect.move()
pygame.display.update()
clock.tick(10)
pygame.quit()
quit()

Categories