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.
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
I'm trying to make a flappy bird AI using OOP, so far everything seem to be working fine except for two problems. First my bird is flapping way to quickly. I created a user event and in the timer I put 200 milliseconds:
birdflap = pygame.USEREVENT
pygame.time.set_timer(birdflap, 200)
but for some reason, the wings are still flapping like crazy and I can't seem to understand what's causing it to do so. Secondly I had a problem with the bird rotating when it falls down. I made a function in my bird class called 'move' that creates gravity for the bird and causes it to turn using rotozoom in pygame to make it turn as it falls down.
def move(self):
self.bird_movement = 8
self.bird_movement += self.gravity
self.bird_rect.centery += self.bird_movement
pygame.transform.rotozoom(self.img[self.bird_index], -self.bird_movement * 3, 1)
The problem is that once the game starts, it falls but doesn't turn. I honestly don't know where to start with solving both of these issues. My full code is down below if anybody wanted to see what I have so far.
import pygame
import neat
import time
import os
import random
import sys
pygame.init()
clock = pygame.time.Clock()
# VARIABLES THAT DEFINE SCREEN SIZE
screen_width = 500
screen_height = 800
# CLOCK TO SET FRAME RATE
clock = pygame.time.Clock()
# VARIABLES THAT CONTAIN GAME IMAGES
bird_imgs = [pygame.transform.scale2x(pygame.image.load(os.path.join('assets', 'yellowbird-upflap.png'))), pygame.transform.scale2x(pygame.image.load(
os.path.join('assets', 'yellowbird-midflap.png'))), pygame.transform.scale2x(pygame.image.load(os.path.join('assets', 'yellowbird-downflap.png')))]
bg_img = pygame.transform.scale2x(pygame.image.load(os.path.join('assets', 'background-day.png' )))
# TIMER FOR BIRD FLAP IMAGES
birdflap = pygame.USEREVENT
pygame.time.set_timer(birdflap, 200)
class Bird:
img = bird_imgs
gravity = 0.25
def __init__(self, x, y):
self.x = x
self.y = y
self.bird_movement = 0
self.bird_index = 0
self.bird_rect = self.img[self.bird_index].get_rect(center = (self.x, self.y))
def bird_animation(self, win):
if self.bird_index < 2:
self.bird_index += 1
else:
self.bird_index = 0
win.blit(self.img[self.bird_index], self.bird_rect)
def move(self):
self.bird_movement = 8
self.bird_movement += self.gravity
self.bird_rect.centery += self.bird_movement
pygame.transform.rotozoom(self.img[self.bird_index], -self.bird_movement * 3, 1)
# FUNCTION TO DRAW THE WINDOW
def draw_window(win, bird):
win.blit(bg_img, (0,0))
bird.bird_animation(win)
pygame.display.update()
# MAIN FUNCTION OF OUR GAME
def main():
win = pygame.display.set_mode((screen_width, screen_height))
bird = Bird(200, 200)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == birdflap:
bird.bird_animation(win)
bird.move()
draw_window(win, bird)
clock.tick(60)
pygame.quit()
sys.exit()
main()
I tried using other modules in pygame, but that doesn't seem to solve my issue either. Right now I'm really lost.
The 1st problem is that bird_animation is called in draw_window so the bird is animated all over the time. The 2nd problem is that pygame.transform.rotozoom returns a new but rotated surface (see How do I rotate an image around its center using PyGame?). The method move has to create an image, that is used in an draw method:
class Bird:
img = bird_imgs
gravity = 0.25
def __init__(self, x, y):
self.x = x
self.y = y
self.bird_movement = 0
self.bird_index = 0
self.image = self.img[self.bird_index]
self.rect = self.image.get_rect(center = (self.x, self.y))
def bird_animation(self):
if self.bird_index < 2:
self.bird_index += 1
else:
self.bird_index = 0
def move(self):
self.bird_movement = 8
self.bird_movement += self.gravity
self.y += self.bird_movement
self.image = pygame.transform.rotozoom(self.img[self.bird_index], -self.bird_movement * 3, 1)
self.rect = self.image.get_rect(center = (self.x, self.y))
def draw(self, win)
win.blit(self.img[self.bird_index], self.bird_rect)
# FUNCTION TO DRAW THE WINDOW
def draw_window(win, bird):
win.blit(bg_img, (0,0))
bird.draw(win)
pygame.display.update()
def main():
win = pygame.display.set_mode((screen_width, screen_height))
bird = Bird(200, 200)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == birdflap:
bird.bird_animation()
bird.move()
draw_window(win, bird)
clock.tick(60)
pygame.quit()
sys.exit()
main()
This question already has answers here:
How can I make a sprite move when key is held down
(6 answers)
How to get keyboard input in pygame?
(11 answers)
Closed 3 months ago.
I am new to Pygame and am facing issues getting the event handler to register my keystrokes to move my player when I call that class under the event handler in the main loop
I run this code and the level and player render correctly but not able to move my player. I've looked at various other answers such as adding pygame.event.pump() but this doesn't work and shouldn't be needed as it should be handled by the main event handler
import pygame, sys
# Settings
size = width, height = (800, 800)
FPS = 60
road_w = width//1.6
roadmark_w = width//80
right_lane = width/2 + road_w/4
left_lane = width/2 - road_w/4
speed = 5
player_start = right_lane, height*0.8
enemy_start = left_lane, height*0.2
# Create Player Class
class Player(pygame.sprite.Sprite):
def __init__(self,pos,groups):
super().__init__(groups)
self.image = pygame.image.load("car.png").convert_alpha()
self.rect = self.image.get_rect(center = pos)
self.direction = pygame.math.Vector2(0,0)
self.speed = 5
def input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
self.direction.y = -1
elif keys[pygame.K_DOWN]:
self.direction.y = 1
else:
self.direction.y = 0
if keys[pygame.K_RIGHT]:
self.direction.x = 1
print(self.direction.x)
elif keys[pygame.K_LEFT]:
self.direction.x = -1
else:
self.direction.x = 0
def move(self, speed):
if self.direction.magnitude() != 0:
self.direction = self.direction.normalize()
self.rect.x += self.direction.x * speed
self.rect.y += self.direction.y * speed
def update(self):
self.input()
self.move(self.speed)
#Create Level Class
class Level:
def __init__(self):
# get display surface
self.display_surface = pygame.display.get_surface()
#Sprite group set up
self.player_sprite = pygame.sprite.Group()
def create_map(self):
pygame.draw.rect(self.display_surface,(50, 50, 50),\
(width/2-road_w/2, 0, road_w, height))
pygame.draw.rect(self.display_surface,(255, 240, 60),\
(width/2 - roadmark_w/2, 0, roadmark_w, height))
pygame.draw.rect(self.display_surface,(255, 255, 255),\
(width/2 - road_w/2 + roadmark_w*2, 0, roadmark_w, height))
pygame.draw.rect(self.display_surface,(255, 255, 255),\
(width/2 + road_w/2 - roadmark_w*3, 0, roadmark_w, height))
def run(self):
# Update and draw level
self.create_map()
self.player = Player(player_start,[self.player_sprite])
self.player_sprite.draw(self.display_surface)
self.player_sprite.update
# Create Game Class
class Game:
def __init__(self):
# Setup
pygame.init()
self.screen = pygame.display.set_mode(size)
pygame.display.set_caption('Car Game')
self.clock = pygame.time.Clock()
self.level = Level()
def run(self):
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
self.screen.fill((60,220,0))
self.level.run()
pygame.display.update()
self.clock.tick(FPS)
# Run Game
if __name__ == '__main__':
game = Game()
game.run()
Car.png
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
I am trying to make a replica for pong in pygame for my first project but when I try to move my paddles they stretch instead. I believe the reason is it creates a new rect every time I try to move it but I can't seem to figure out why. Please review the code and help rectify my mistake.
Here is my code:
import pygame
W, H = 600, 500
screen = pygame.display.set_mode((W, H))
FPS = 30
class Paddle(pygame.sprite.Sprite):
def __init__(self, x, y, width, height):
super(Paddle, self).__init__()
self.x = x
self.y = y
self.width = width
self.height = height
self.surf = pygame.Surface((width, height))
self.surf.fill((255, 255, 255))
self.rect = self.surf.get_rect()
self.rect.center = (x, y)
def move(self, distance):
self.rect.move_ip(0, distance)
paddleA = Paddle(15, 250, 10, 50)
paddleB = Paddle(585, 250, 10, 50)
allSprites = pygame.sprite.Group()
allSprites.add(paddleA)
allSprites.add(paddleB)
run = True
clock = pygame.time.Clock()
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
pressedKeys = pygame.key.get_pressed()
if pressedKeys[pygame.K_UP]:
paddleB.move(-5)
elif pressedKeys[pygame.K_DOWN]:
paddleB.move(5)
elif pressedKeys[pygame.K_w]:
paddleA.move(-5)
elif pressedKeys[pygame.K_s]:
paddleA.move(5)
for sprite in allSprites:
screen.blit(sprite.surf, sprite.rect)
pygame.display.update()
clock.tick(FPS)
pygame.quit()
quit()
Before drawing the new rect you should fill the screen with the background color, to remove the old rect. Otherwise the old one is still drawn there and you are just drawing new over the old one. Its' like painting a new picture on an old one.
screen.fill(color, rect) should do the trick.