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
Related
I am new to stackoverflow.
My code has a problem which the screen turns completely black.
The error.
I need the answer quickly so any help will be good.
Heres the code:
import pygame, sys
import pymunk
import pymunk.pygame_util
from pymunk.vec2d import Vec2d
size = (800, 800)
FPS = 120
space = pymunk.Space()
space.gravity = (0,250)
pygame.init()
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
class Ball:
global space
def __init__(self, pos):
self.body = pymunk.Body(1,1, body_type = pymunk.Body.DYNAMIC)
self.body.position = pos
self.radius = 60
self.shape = pymunk.Circle(self.body, self.radius)
space.add(self.body, self.shape)
def draw(self):
x = int(self.body.position.x)
y = int(self.body.position.y)
pygame.draw.circle(screen, (255,0,0), (x,y), self.radius)
balls = []
balls.append(Ball((400,0)))
balls.append(Ball((100,0)))
balls.append(Ball((600,100)))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screeen.fill(217,217,217)
for ball in balls:
ball.draw()
space.step(1/50)
pygame.display.update()
clock.tick(FPS)
Any help on what to do???
Thanks.
screeen.fill(217,217,217) should be screen.fill((217,217,217))
The Indentation is not correct. In particular, the scene must be pulled in the application loop and not in the bleed loop:
import pygame, sys
import pymunk
import pymunk.pygame_util
from pymunk.vec2d import Vec2d
size = (800, 800)
FPS = 120
space = pymunk.Space()
space.gravity = (0,250)
pygame.init()
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
class Ball:
global space
def __init__(self, pos):
self.body = pymunk.Body(1,1, body_type = pymunk.Body.DYNAMIC)
self.body.position = pos
self.radius = 60
self.shape = pymunk.Circle(self.body, self.radius)
space.add(self.body, self.shape)
# INDENTATION
#<--|
def draw(self):
x = int(self.body.position.x)
y = int(self.body.position.y)
pygame.draw.circle(screen, (255,0,0), (x,y), self.radius)
balls = []
balls.append(Ball((400,0)))
balls.append(Ball((100,0)))
balls.append(Ball((600,100)))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# INDENTATION
#<------|
screen.fill((217,217,217))
for ball in balls:
ball.draw()
space.step(1/50)
pygame.display.update()
clock.tick(FPS)
This question already has answers here:
Pygame is running slow
(1 answer)
Why my pygame game with a tiled map is lagging?
(1 answer)
Closed 1 year ago.
I am trying to make a 2D Platformer with Pygame and it starts out fine running at 25 fps that i capped it at with clock.tick(25), and then after 10 seconds or so it starts slowing down.
I have tried to add a deltatime function that didnt work and i have tried switching out pygame.display.flip() with pygame.display.update() but to no help.
I am not sure what the problem is since there are no error messages so i will show all 3 python files.
This is my main file called main.py
import pygame
import player
import environment
def run_game():
pygame.init()
winW, winH = 900, 650
screen = pygame.display.set_mode((winW, winH))
pygame.display.set_caption(" ")
icon = pygame.Surface((32, 32))
icon.fill((255, 255, 255))
pygame.display.set_icon(icon)
character = player.Player()
clock = pygame.time.Clock()
FPS = 25
running = True
while running:
clock.tick(FPS)
FPS = 25
print(clock.get_fps())
screen.fill((50, 100, 100))
screen.blit(character.surf, character.rect)
character.jump()
# Make The Environment
environment.make_block(1000, 32, 50, 500, (255, 255, 255))
environment.make_sprite(64, 64, 200, 100, "Grass Block 16x.png")
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
# Get Pressed Keys
keys = pygame.key.get_pressed()
# Check if the player should be moving
if keys[pygame.K_LEFT]:
character.rect.move_ip(-6, 0)
if keys[pygame.K_RIGHT]:
character.rect.move_ip(6, 0)
if keys[pygame.K_UP] and character.on_ground:
character.jumping = True
else:
character.jumping = False
for i in range(len(environment.block_surf_list)):
screen.blit(environment.block_surf_list[i], environment.block_rect_list[i])
for i in range(len(environment.sprite_list)):
screen.blit(environment.sprite_list[i], environment.sprite_rect_list[i])
pygame.display.flip()
if __name__ == "__main__":
run_game()
This is my player file called player.py
import pygame
import environment
from main import *
class Player(pygame.sprite.Sprite):
def __init__(self, w=32, h=32):
super(Player, self).__init__()
self.surf = pygame.Surface((w, h))
self.rect = self.surf.get_rect()
self.surf.fill((255, 0, 0))
self.jumping = False
self.on_ground = False
self.fall_speed = 3
self.air_time = 0
self.jump_height = 30
def jump(self):
if self.jumping and self.air_time <= 5:
self.rect.y -= self.jump_height
self.fall_speed = 0
self.air_time += 1
else:
for i in range(len(environment.block_rect_list)):
if self.rect.colliderect(environment.block_rect_list[i]):
self.on_ground = True
self.air_time = 0
else:
self.on_ground = False
if not self.on_ground:
self.rect.y += self.fall_speed
self.fall_speed += 2
This is my environment file called environment.py
import pygame
block_surf_list = []
block_rect_list = []
def make_block(width, height, x_pos, y_pos, block_color):
block_surf = pygame.Surface((width, height))
block_surf.fill(block_color)
block_rect = block_surf.get_rect()
block_rect.move_ip(x_pos, y_pos)
block_surf_list.append(block_surf)
block_rect_list.append(block_rect)
sprite_list = []
sprite_rect_list = []
test_size_1 = 32
def make_sprite(width, height, x_pos, y_pos, sprite):
block_image = pygame.image.load(sprite)
block_image = pygame.transform.scale(block_image, (width, height))
block_image_rect = block_image.get_rect()
block_image_rect.move_ip(x_pos, y_pos)
sprite_list.append(block_image)
sprite_rect_list.append(block_image_rect)
You appear to be making a new block every frame. Instead of making a new block and drawing it every frame, you could make one block and a seperate function to draw it.
This question already has an answer here:
Why is the PyGame animation is flickering
(1 answer)
Closed 2 years ago.
So below there is my code and Whenever I try to run it and the balloons spawn, I always get glitching which increase as we go down the line. Please see if there is anything I can do to fix this. The only part that I really would like to know is hot to make it smooth. Also I am Beginner so there are many things I would not understand. If you have any improvements for me, please feel free to tell me.
Balloon Pic('Logo.png')
import pygame
import sys
import os
import random
import time
pygame.init()
WIDTH, HEIGHT = 800,600
win = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("My Game")
clock = pygame.time.Clock()
bg_music = []
for r,d,f in os.walk("Music"):
bg_music.append(f)
i = 0
balloon_sprite = pygame.image.load("Logo.png")
round_num = 1
bloons = []
def music_play():
global i
if not(pygame.mixer.music.get_busy()):
pygame.mixer.music.load('Music/'+bg_music[0][i])
pygame.mixer.music.play()
i = random.randint(0,len(bg_music)-1)
class Button:
def __init__(self, x_center, y_center, text, size, text_col, bg_col):
self.x = x_center
self.y = y_center
self.size = size
self.text_col = text_col
self.bg_col = bg_col
self.hit = False
font = pygame.font.Font('freesansbold.ttf', self.size)
self.text = font.render(text, True, self.text_col, self.bg_col)
self.textRect = self.text.get_rect()
self.textRect.center = (self.x, self.y)
win.blit(self.text, self.textRect)
def Check_Collision(self, event):
if event.type == pygame.MOUSEBUTTONDOWN:
pos_mouse = event.pos
if self.textRect.collidepoint(pos_mouse):
self.hit = True
def Start(self):
global run1
if (self.hit):
run1 = False
def Quit(self):
if (self.hit):
sys.exit()
class Balloon:
def __init__(self, x,y,health, dests):
self.health = health
self.dests = dests
self.x = x
self.y = y
self.count = 0
def draw_Balloon(self):
global balloon_sprite
win.blit(balloon_sprite, pygame.Rect((self.x, self.y), (balloon_sprite.get_width(), balloon_sprite.get_height())))
pygame.display.update()
if not(self.count==len(self.dests)):
if self.x == self.dests[self.count][0]:
if self.y== self.dests[self.count][1]:
self.count+=1
else:
if self.y< self.dests[self.count][1]:
self.y+=1
else:
self.y-=1
else:
if self.x< self.dests[self.count][0]:
self.x+=1
else:
self.x-=1
def Main():
def Check_Close(event):
if event.type == pygame.QUIT:
sys.exit()
global run1
running = True
run1 = run2 = True
while running:
while run1:
start_bt = Button(WIDTH//2, HEIGHT//2, "Start", 32, (255,255,0), (0,0,0))
quit_bt = Button(WIDTH-25, HEIGHT-25, "QUIT", 16, (255,255,0), (0,0,0))
clock.tick(60)
for event in pygame.event.get():
Check_Close(event)
start_bt.Check_Collision(event)
start_bt.Start()
quit_bt.Check_Collision(event)
quit_bt.Quit()
pygame.display.update()
music_play()
win.fill((255,255,255))
for i in range(10):
bloons.append('balloon'+str(i))
bloons[i] = Balloon(0,(-30*i) ,5, ([0,50], [528,50], [528,500], [150,500], [150,300], [700,300], [700,-100]))
while run2:
win.fill((0,0,0))
clock.tick(60)
for i in range(10):
bloons[i].draw_Balloon()
for event in pygame.event.get():
Check_Close(event)
music_play()
pygame.display.update()
Main()
Only perform a display update at the end of the application loop, not multiple updates during the frame. Multiple updates of the display cause flickering. One single pygame.display.update() or pygame.display.flip() at the end of the frame is sufficient.
Just remove pygame.display.update() from Balloon.draw_Balloon:
class Balloon:
# [...]
def draw_Balloon(self):
global balloon_sprite
win.blit(balloon_sprite, pygame.Rect((self.x, self.y), (balloon_sprite.get_width(), balloon_sprite.get_height())))
# pygame.display.update() <--- DELETE
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`
I have an array with all the sprites inside of them, and in the loop, if the sprite is clicked then the sprite is killed.
If I click the sprites from left to right, everything is fine. They are cleared one by one independent of each other. But, if I click the sprite most right of the screen, it kills everything to the left of it.
Full code because I've no idea where the important region might be.
import pygame
from pygame.locals import *
import random
pygame.init()
level = 1
cooldown = 1000
class test(pygame.sprite.Sprite):
def __init__(self, w):
super().__init__()
self.image = pygame.Surface([600,600])
self.rect = self.image.get_rect()
self.image = pygame.image.load("index.png")
self.image = pygame.transform.scale(self.image, (w,w))
self.last = pygame.time.get_ticks()
screen = pygame.display.set_mode([600,600])
clock = pygame.time.Clock()
background = pygame.Surface(screen.get_size())
background.fill([0,0,0])
rX = random.randint(0, 500)
rX2 = random.randint(0, 500)
screen.blit(background, (0,0))
sp = []
all_sprites_list = pygame.sprite.Group()
a_1 = test(random.randint(40,60))
a_1.rect.x = rX
a_1.rect.y = -400
sp.append(a_1)
all_sprites_list.add(a_1)
#The steps for a_1 is repeated to make variables a_2, a_3, a_4...
Running = True
while Running:
now = pygame.time.get_ticks()
for x in sp:
x.rect.y+=level
m_pos = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == QUIT:
Running = False
if event.type == MOUSEBUTTONDOWN:
for s in sp:
if s.rect.collidepoint(m_pos):
s.kill()
pygame.display.flip()
all_sprites_list.clear(screen, background)
all_sprites_list.draw(screen)
all_sprites_list.update()
clock.tick(60)
Problem is because in class you create Surface with size (600, 600) and you assign this size to self.rect. After that you load image but you forgot to assign its size to self.rect so program always check mouse click with size (600, 600) and when you click most right item then all rect (600, 600) are in area of click.
But you don't have to create Surface if you load image.
My version with many changes.
I removed list sp because I can use all_sprites_list
When it sends MOUSEBUTTONDOWN event then mouse position is in event.pos so I don't need pygame.mouse.get_pos()
import pygame
import random
# --- classes --- (UpperCaseNames)
class Test(pygame.sprite.Sprite):
def __init__(self, w):
super().__init__()
self.image = pygame.image.load("index.png")
self.image = pygame.transform.scale(self.image, (w, w))
self.rect = self.image.get_rect()
self.last = pygame.time.get_ticks()
# --- main ----
level = 1
cooldown = 1000
# - init -
pygame.init()
screen = pygame.display.set_mode((600, 600))
# - items -
background = pygame.Surface(screen.get_size())
background.fill((0, 0, 0))
screen.blit(background, (0,0))
all_sprites_list = pygame.sprite.Group()
for x in range(10):
item = Test(random.randint(40, 60))
item.rect.x = 40 * random.randint(0, 10)
item.rect.y = 0
all_sprites_list.add(item)
# - mainloop -
clock = pygame.time.Clock()
running = True
while running:
now = pygame.time.get_ticks()
for item in all_sprites_list:
item.rect.y += level
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
for item in all_sprites_list:
if item.rect.collidepoint(event.pos):
item.kill()
pygame.display.flip()
all_sprites_list.clear(screen, background)
all_sprites_list.draw(screen)
all_sprites_list.update()
clock.tick(30)
pygame.quit()