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
Related
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
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.
So I am trying to make a tower defense game and I tried to make a back button and before it worked but now when I try it gives me a math domain error. I've seen online it may come if I take something like the root of -1 but that's not possible because the value is being squared. It happens in CheckClicked function under Class Back_Button. Can anybody figure it out?
import pygame, sys, math
from Colors import get
def main():
global run, back
pygame.init()
width, height = 800,600
win = pygame.display.set_mode((width, height))
class Button:
def __init__(self, pos, text, size, tx_col, bg_col, rectangle = True):
self.rectangle = rectangle
self.bg_col = bg_col
self.tx_col = tx_col
self.x = pos[0]
self.y = pos[1]
font = pygame.font.SysFont('timesnewroman', size)
self.text = font.render(text, True, get(self.tx_col), get(self.bg_col))
def Draw_Button(self):
if self.rectangle:
pygame.draw.rect(win, get(self.tx_col), [(self.x - self.text.get_width()//2, self.y-self.text.get_height()//2), (self.text.get_width(), self.text.get_height())])
win.blit(self.text, (self.x - self.text.get_width()//2, self.y-self.text.get_height()//2))
else:
pygame.draw.circle(win, get(self.bg_col), (self.x - self.text.get_width()//2, self.y-self.text.get_height()//2), self.text.get_width())
win.blit(self.text, (self.x - self.text.get_width(), self.y-self.text.get_height()))
class Start_Button(Button):
def CheckClicked(self, pos):
global run
if (self.x-self.text.get_width()//2<=pos[0]<=(self.x+self.text.get_width()//2)) and (self.y-self.text.get_height()//2<=pos[1]<=(self.y+self.text.get_height()//2)):
run = False
class Back_Button(Button):
def CheckClicked(self, pos):
global back, run
if math.sqrt((pos[0]- (self.x - self.text.get_width()))**2 + (pos[1]- (self.y - self.text.get_height())**2))<=self.text.get_width():
back, run = True, False
class Logo:
def __init__(self, x, y, time, img):
self.x = x
self.y = y
self.time = time
self.img = pygame.image.load(img).convert_alpha()
self.img.set_alpha(0)
def Transper(self):
clock = pygame.time.Clock()
for i in range(226):
self.img.set_alpha(i)
win.blit(self.img, [self.x, self.y])
clock.tick(self.time)
print(self.img.get_alpha())
pygame.display.update()
class Ballon:
def __init__(self, path_points, health, speed):
self.path_points = path_points
self.health = health
self.speed = speed
self.img = pygame.image.load(f'{self.health}.png')
class Round:
def __init__(self, list_of_ballons):
self.list_of_ballons = list_of_ballons
def Start_Round(self):
li = []
for i in self.list_of_ballons:
li.append(Ballon(11, 22, 33))
class Game:
def __init__(self, rounds, curr_map, enem_cord):
self.rounds = rounds
self.map = pygame.image.load(curr_map)
self.enem_cord = enem_cord
def display_map(self):
win.blit(pygame.transform.scale(self.map, (width, height)), (0,0))
#Intro
#Logo_Pic = Logo(width//2, height//2, 60, 'Screenshot2020-10-24.png')
#Logo_Pic.Transper()
New_Button = Start_Button([400, 300], 'New Game', 25, 'red', 'white')
BackButton = Back_Button([35, 585], '<-', 25, 'red', 'white', False)
running = True
back = False
while running:
back = False
# Main Menu
run = True
while run:
win.fill(get('black'))
New_Button.Draw_Button()
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
New_Button.CheckClicked(pos)
pygame.display.update()
#Choose Map
run = True
GameA = Game(40, 'MonkeyMeadow_No_UI.png', [])
while run:
win.fill(get('black'))
GameA.display_map()
BackButton.Draw_Button()
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
BackButton.CheckClicked(pos)
pygame.display.update()
if back:
continue
main()
It looks like you misplaced a parenthesis in the second squared term.
This is what you have now:
(pos[1]- (self.y - self.text.get_height())**2)
Instead of that, try moving the closing parenthesis to before the exponential:
(pos[1]- (self.y - self.text.get_height()))**2
Unable to move player in pygame
So, I was trying to create a simple physics system in pygame. My main goal was to add a Y gravity function that would move the player when activated. I have tried several times to make it work, but I guess I am missing something.
Here is the code:
class Physic:
def __init__(self, color, master, type, sizeX, sizeY, pos=[0,0]):
self.master = master
self.color = color
self.type = type
self.sizeX = sizeX
self.sizeY = sizeY
self.x = pos[0]
self.y = pos[1]
self.moveX = 0
self.moveY = 0
self.create_Object()
def create_Object(self):
if self.type == 'rect':
self.rect()
def rect(self):
return pygame.draw.rect(self.master, self.color, (self.x, self.y, self.sizeX, self.sizeY))
def drag(self):
for event in pygame.event.get():
if event.type == pygame.mouse.get_pressed()[0]:
self.x = pygame.mouse.get_pos()
def add_gravity(self):
self.moveY += 3.2
self.update_pos()
def update_pos(self):
self.y += self.moveY
self.x += self.moveX
In the main script I put this:
def game():
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.fill(WHITE)
player = object.Physic(BLUE, screen, 'rect', 50, 50, [POS[0], POS[1]])
player.add_gravity()
# platform = object.rect(screen, RED, [30, 30], 100, 30)
# physics.add_collider(player, platform, POS[0])
pygame.display.update()
game()
Do you know what I am missing?
Your big problem is that you are recreating the player every pass inside the main loop and so it looks like it is frozen in place.
You also need to have a limit on the frame rate so that you control the speed of the game and therefor can properly set the acceleration per frame.
There are a some other minor things that needed to be fixed to run this. I tried to change the minimum possible to run it, since the point was to fix the error rather than rewrite it on you. Obviously I had to add some wrapper code around it
Try this slightly adjusted version:
#!/usr/bin/env python
import traceback
import pygame
import sys
FRAME_RATE = 60
GRAVITY = 32
SCREEN_SIZE = (600, 800)
WHITE = pygame.Color("white")
BLUE = pygame.Color("blue")
POS = (100, 600)
class Physic:
def __init__(self, color, master, type, sizeX, sizeY, pos=(0,0)):
self.master = master
self.color = color
self.type = type
self.sizeX = sizeX
self.sizeY = sizeY
self.x = pos[0]
self.y = pos[1]
self.moveX = 0
self.moveY = 0
self.create_Object()
def create_Object(self):
if self.type == 'rect':
self.draw()
def draw(self):
return pygame.draw.rect(self.master, self.color, (self.x, self.y, self.sizeX, self.sizeY))
def drag(self):
for event in pygame.event.get():
#if event.type == pygame.mouse.get_pressed()[0]: <--- remove this
if event.type == pygame.MOUSEBUTTONDOWN:
self.x = pygame.mouse.get_pos()
def add_gravity(self):
self.moveY += GRAVITY / FRAME_RATE
self.update_pos()
def update_pos(self):
self.y += self.moveY
self.x += self.moveX
def game():
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE)
clock = pygame.time.Clock()
player = Physic(BLUE, screen, 'rect', 50, 50, POS)
# I added this to illustrate the gravity better ... going up and down
player.moveY = -25
player.moveX = 2
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
screen.fill(WHITE)
player.add_gravity()
player.draw()
# platform = object.rect(screen, RED, [30, 30], 100, 30)
# physics.add_collider(player, platform, POS[0])
pygame.display.update()
clock.tick(FRAME_RATE)
def main():
try:
game()
except Exception as ex:
print(traceback.format_exc())
raise
finally:
# game exit cleanup stuff
pygame.quit()
if __name__ == '__main__':
main()
An issue that I want to point out though it is not affecting this code here. You should not use an immutable object (like a list) as an default when defining an optional/named argument in a method. I.e. in the Physic __init__() I changed pos=[0,0] to pos=(0,0). Not a big deal here, but can cause really odd bugs if you had assigned it to a var, then tried to change it. It will have effects on other instances of the object because they actually share the default initialization object and if it gets modified by one of them it happens in all of them!
I'm trying to recreate Agar.io in Python using pygame. So far I've been able to somewhat simulate the player movement, but then I tried to generate some "food cells" at a given interval using the pygame.time.set_timer() method, but even though the rest of the game elements are being drawn, such as the screen and the player, these food cells are only drawn (and added to the "food_list" list) when I drag the game window around. I think this might be an issue of me not really knowing how to deal with the event queue.
main.py, which is where the game loop is located:
import sys, pygame
from player import Player
from food import Food
import random
pygame.init()
SCREEN_SIZE = [1024, 768]
WHITE = (255, 255 , 255)
generate_food = pygame.USEREVENT + 1
screen = pygame.display.set_mode(SCREEN_SIZE)
screen.fill(WHITE)
player = Player()
food_list = []
## TODO: Make a separate GameScreen class.
## TODO: Make a list of constants
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == generate_food:
food_x = random.randrange(0, 760)
food_y = random.randrange(0, 1000)
food_list.append(Food(food_x, food_y))
pygame.time.set_timer(generate_food, 200)
screen.fill(WHITE)
for f in food_list:
f.draw(screen)
player.update()
player.draw(screen)
pygame.display.flip()
food.py:
import pygame
import random
from cell import Cell
DARK_GREEN = (0, 102, 0)
class Food(Cell):
def __init__(self, x, y):
super().__init__()
self.size = 2
self.image = pygame.Surface([2, 2])
self.image.fill(DARK_GREEN)
self.rect = self.image.get_rect()
self.x = x
self.y = y
def draw(self, screen):
pygame.draw.circle(screen, DARK_GREEN, (self.x, self.y), self.size, 0)
def getX(self):
return self.x
def getY(self):
return self.y
Actually the timer is restarted continuously in the application loop. However pygame.time.set_timer() crates a timer that repeatedly create a USEREVENT in the event queue. Hence it is sufficient to start the timer once before the application loop:
pygame.time.set_timer(generate_food, 200) # <--- ADD
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == generate_food:
food_x = random.randrange(0, 760)
food_y = random.randrange(0, 1000)
food_list.append(Food(food_x, food_y))
# pygame.time.set_timer(generate_food, 200) <--- DELTE