Display Surface quit error when quitting - python

I made a pygame program what is working fine, but when I try to quit it, error occurs: pygame.error: display Surface quit, and show the code part: DS.blit(bg, (back_x - bg.get_rect().width, 0)). I use quit() command in my events and also at the end of the loop. Can't figure out where is the problem.
import pygame, os, random
pygame.init()
pygame.mixer.init()
W, H = 800,600
HW, HH = W/2,H/2
WHITE = (255,255,255)
PURPLE = (139,34,82)
FPS = 60
DS = pygame.display.set_mode((800, 600))
pygame.display.set_caption('Purpleman')
clock = pygame.time.Clock()
#Allalaadimised
bg = pygame.image.load(os.path.join('Pildid', 'Taust3.png'))
bg = pygame.transform.scale(bg, (2000, 600))
startscreen = pygame.image.load(os.path.join('Pildid', 'Start.png'))
startscreen = pygame.transform.scale(startscreen, (800, 600))
endscreen = pygame.image.load(os.path.join('Pildid', 'dead.png'))
endscreen = pygame.transform.scale(endscreen, (800, 600))
PLAYER_SHEET = pygame.image.load(os.path.join('Pildid', 'karakter.png')).convert_alpha()
menuu = pygame.mixer.Sound(os.path.join('Helid', 'Taust_laul.ogg'))
ohno = pygame.mixer.Sound(os.path.join('Helid', 'ohno.ogg'))
sad = pygame.mixer.Sound(os.path.join('Helid', 'sad.ogg'))
pygame.mixer.music.load(os.path.join('Helid', 'taustalaul.ogg'))
pygame.display.set_icon(bg)
# Sprite sheeti loikamine ja lisamine listi
PLAYER_IMAGES = []
width = PLAYER_SHEET.get_width() / 4
height = PLAYER_SHEET.get_height()
for x in range(4):
PLAYER_IMAGES.append(PLAYER_SHEET.subsurface(x*width, 0, width, height))
class Player(pygame.sprite.Sprite):
'''Mangija'''
def __init__(self, x, y, py):
super(Player,self).__init__()
self.x = x
self.y = y
self.jumping = False
self.platform_y = py
self.velocity_index = 0
self.velocity = list([(i/ 1.5)-25 for i in range (0,60)]) #huppe ulatus ja kiirus
self.frame_index = 0
self.image = PLAYER_IMAGES[self.frame_index] #kaadri valimine
self.rect = self.image.get_rect()
self.mask = pygame.mask.from_surface(self.image) #hitbox
def do_jump(self):
'''Huppemehaanika'''
if self.jumping:
self.y += self.velocity[self.velocity_index]
self.velocity_index += 2
if self.velocity_index >= len(self.velocity) - 1: #huppe aeglustus (nagu gravitatsioon)
self.velocity_index = len(self.velocity) - 1
if self.y > self.platform_y: #platvormi tagades ei huppa
self.y = self.platform_y
self.jumping = False
self.velocity_index = 0
def update(self):
'''Kaadrite vahetus ja huppamine'''
self.rect.center = self.x, self.y
self.do_jump()
# Animatsiooni kaadri uuendamine.
self.frame_index += 1
self.frame_index %= len(PLAYER_IMAGES) * 7
# Pildi vahetamine.
self.image = PLAYER_IMAGES[self.frame_index//7]
def keys(player):
'''Mangija inputi saamine'''
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE] or keys[pygame.K_UP] and player.jumping == False:
player.jumping = True
class Obstacle(pygame.sprite.Sprite):
'''Mangu takistused'''
def __init__(self, x, y):
super(Obstacle,self).__init__()
self.image = pygame.image.load(os.path.join('Pildid', 'kivi.png')).convert_alpha()
self.image = pygame.transform.scale(self.image, (90,90))
self.rect = self.image.get_rect(center=(x, y))
self.x = x
self.y = y
self.mask = pygame.mask.from_surface(self.image)
def update(self):
'''Takistuse kustutamine'''
if self.x < -64:
self.kill()
self.x += speed
self.rect.center = self.x, self.y
class Scoring():
'''Punktide lugemine ja menuud'''
def __init__(self):
with open('highscore.txt', 'w') as f: #high score salvestamine
try:
self.highscore = int(f.read())
except:
self.highscore = 0
def score(self,points):
self.font = pygame.font.Font('freesansbold.ttf',30)
self.text = self.font.render('Score: ' + str(points) , True, PURPLE)
DS.blit(self.text, (0,0))
def text_objects(self,text, font):
self.textSurface = font.render(text, True, PURPLE)
return self.textSurface, self.textSurface.get_rect()
def message_display(self,text):
self.largeText = pygame.font.Font('freesansbold.ttf',60)
self.TextSurf, self.TextRect = self.text_objects(text, self.largeText)
self.TextRect.center = ((W/2),(H/4))
DS.blit(self.TextSurf, self.TextRect)
pygame.display.update()
self.waiting = True
def startscreen(self):
'''Algusaken'''
menuu.play(-1)
DS.blit(startscreen, [0,0])
self.draw_text('Purpleman', 48, PURPLE, W/2, H/4)
self.draw_text('Space to jump', 22, PURPLE, W/2, H*3/7)
self.draw_text('Press key to play', 22, PURPLE, W/2, H*5/9)
self.draw_text('High score: ' + str(self.highscore), 22, PURPLE, W/2, 15)
self.draw_text('All made by TaaviR', 14, WHITE, W/2, 570)
pygame.display.update()
self.wait_for_key()
def pause_endscreen(self):
'''Lopuaken'''
sad.play()
DS.blit(endscreen, [0,0])
self.draw_text('GAME OVER', 48, PURPLE, W/2, H/4)
self.draw_text('You ran ' + str(points), 22, PURPLE, W/2, H/2)
self.draw_text('Press key to play again', 22, WHITE, W/2, H*5/6)
if points > self.highscore: #high score mehhanism
self.highscore = points
self.draw_text('NEW HIGH SCORE!', 22, PURPLE, W/2, H/2 + 40)
with open('highscore.txt', 'w') as f:
f.write(str(points))
else:
self.draw_text('Highscore ' + str(self.highscore), 22, PURPLE, W/2, H/2 + 40)
pygame.display.update()
self.wait_for_key()
self.waiting = True
def wait_for_key(self):
'''Mangija input menuu jaoks'''
self.waiting = True
while self.waiting:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
self.waiting = False
pygame.mixer.quit()
elif event.type == pygame.KEYUP:
self.waiting = False
menuu.stop()
pygame.mixer.music.play(-1)
sad.stop()
def draw_text(self,text, size, color, x, y):
self.font = pygame.font.Font('freesansbold.ttf', size)
self.text_surface = self.font.render(text, True, color)
self.text_rect = self.text_surface.get_rect()
self.text_rect.midtop = (x, y)
DS.blit(self.text_surface, self.text_rect)
def crash(self):
self.message_display('Purpleman got hurt')
self.waiting = True
def background():
'''Liikuv taust'''
back_x = x % bg.get_rect().width
# ---Draw everything.---
DS.blit(bg, (back_x - bg.get_rect().width, 0))
if back_x < W:
DS.blit(bg, (back_x, 0))
pygame.time.set_timer(pygame.USEREVENT+2, random.choice([2500, 3000, 1500,1000])) #valjastamaks suvaliselt takistusi
#klassid
obstacle = Obstacle(832, 412)
player = Player(190, 359, 359)
#sprite grupid
all_sprites = pygame.sprite.Group(player, obstacle)
obstacles = pygame.sprite.Group(obstacle)
#vajalikud vaartused
index = 3
points = 0
x = 0
x -= 1
speed = -5
start = Scoring()
start.startscreen()
pygame.mixer.music.play(-1)
running = True
while running:
# ---Mangumootor.---
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.mixer.quit()
pygame.quit()
elif event.type == pygame.USEREVENT+2:
r = random.randrange(0, 2)
if r == 0:
obstacle = Obstacle(832, 412)
# Lisamaks takistuse gruppidesse
obstacles.add(obstacle)
all_sprites.add(obstacle)
# ---Mangu loogika---
all_sprites.update()
collided = pygame.sprite.spritecollide(player, obstacles, True, pygame.sprite.collide_mask) #kokkupuutumine
if collided:
ohno.play()
pygame.mixer.music.stop()
start.crash()
pygame.time.delay(3000)
pygame.event.clear()
obstacles.empty()
start.pause_endscreen()
points = 0
speed = -5
else:
points += 1
#vajalikud vaartused
index += 1
x -= 2
speed += -0.008
#funktsioonid
background()
start.score(points)
all_sprites.draw(DS)
keys(player)
pygame.display.update()
clock.tick(60)
pygame.mixer.quit()
pygame.quit()

Don't call pygame.mixer.quit() and pygame.quit() in the event loop when a pygame.QUIT event occurs. When you call pygame.quit(), you can't use some pygame functions like pygame.display.update anymore because all modules have been uninitialized, and since the while loop is still running, this exception gets raised.
So just remove the pygame.quit and pygame.mixer.quit() in the event loop and call them at the end of the program (as you already do).
Actually, you don't even have to call these functions and can just let the program finish as any other program. I think pygame.quit is only needed to close the window if you run your game with the IDLE IDE (and maybe with other tkinter based applications).

Related

Im stuck in my pygame project, i dont know how to add sprites, scroll, and animated backgrounds

Context: Im trying to add something and i dont know, scroll, animated background and sprites.
And with the sound im confuse, other thing is that i dont know how to add time to my game, like for example a counter, or to add some time between an action in the game, i had working in this my project since last week, and stay stuck at this point, i search on google or anywhere and doesnt find what i want.
import pygame
import random
from pygame.locals import *
import pickle
from os import path
from pygame import mixer
import time
pygame.mixer.pre_init(44100, -16, 2, 512)
pygame.init()
mixer.init()
clock = pygame.time.Clock()
fps = 60
ancho = 1000
alto = 1000
bg = pygame.image.load("img/Background/inicio.jpg")
segu = pygame.image.load("img/Iconos/juega.png")
salgan = pygame.image.load("img/Iconos/quit.png")
jugador = pygame.image.load(f"img/player/Idle/0.png")
pantalla = pygame.display.set_mode((ancho, alto))
icon = pygame.display.set_caption("You")
opciones = pygame.image.load("img/Iconos/pauson.png")
resumen = pygame.image.load("img/Iconos/restart.png")
pygame.mixer.music.load("snd/feel.wav")
pygame.mixer.music.set_volume(0.1)
coin_fx = pygame.mixer.Sound("snd/coins.wav")
coin_fx.set_volume(0.5)
flip = pygame.mixer.Sound("snd/flip.wav")
# define font
font = pygame.font.SysFont("freesansbold", 104)
font_score = pygame.font.SysFont("freesansbold", 30)
# variables
money = 0
pressed = False
mantener = False
scroll = 0
pausa = False
pablo = False
def draw_text(text, font, text_col, x, y):
img = font.render(text, True, text_col)
pantalla.blit(img, (x, y))
class Button():
def __init__(self, x, y, image):
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.clicked = False
def draw(self):
action = False
# get mouse position
pos = pygame.mouse.get_pos()
# check mouseover and clicked conditions
if self.rect.collidepoint(pos):
if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
action = True
self.clicked = True
if pygame.mouse.get_pressed()[0] == 0:
self.clicked = False
# draw button
pantalla.blit(self.image, self.rect)
# pygame.draw.rect(pantalla, (255, 255, 255), self.rect, 2)
return action
class Pausa:
def __init__(self, x, y, image):
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def draw(self):
pantalla.blit(self.image, self.rect)
class Player:
def __init__(self, x, y, image):
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def update(self): # update se utiliza para la posicion del jugador y su movilidad
dx = 0
dy = 0
key = pygame.key.get_pressed()
if key[pygame.K_a]:
dx -= 5
self.direction = -1
if key[pygame.K_d]:
dx += 5
self.direction = 1
if key[pygame.K_w]:
dy -= 5
if key[pygame.K_s]:
dy += 5
if key[pygame.K_z]:
pygame.mixer.music.play(-1, 0.0, 5000)
draw_text("Tienes " + str(money) + " monedas", font_score, (0, 0, 0), 800, 10)
# update player coordinates
self.rect.x += dx
self.rect.y += dy
def draw(self):
pantalla.blit(self.image, self.rect)
class Player2:
def __init__(self, x, y, image):
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def update(self): # update se utiliza para la posicion del jugador y su movilidad
dx = 0
dy = 0
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
dx -= 5
self.direction = -1
if key[pygame.K_RIGHT]:
dx += 5
self.direction = 1
if key[pygame.K_UP]:
dy -= 5
if key[pygame.K_DOWN]:
dy += 5
if key[pygame.K_z]:
pygame.mixer.music.play(-1, 0.0, 5000)
draw_text("Tienes " + str(money) + " monedas", font_score, (0, 0, 0), 800, 10)
# update rectangle position
self.rect.x += dx
self.rect.y += dy
def draw(self):
pantalla.blit(self.image, self.rect)
jugador1 = Player(500, 500, jugador)
jugador2 = Player2(0, 0, jugador)
seguro = Button(500, 500, segu)
pausaoff = Pausa(0,0, opciones)
salir = Button(20, 420, salgan)
continuar = Button(20, 20, segu)
returno = Button(20, 300, resumen)
run = True
while run:
clock.tick(fps)
pantalla.blit(bg, (0, 0))
if pablo == True:
if seguro.draw():
pass
mantener = True
pygame.mixer.music.play(-1, 0.0, 5000)
if mantener == True:
Player.draw(jugador1)
Player.update(jugador1)
Player2.draw(jugador2)
Player2.update(jugador2)
pablo = False
if pausa == True:
pausaoff.draw()
mantener = False
if salir.draw():
flip.play()
pass
if returno.draw():
flip.play()
mantener = True
pausa = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_v:
money += 1
if money >= 10:
if event.key == pygame.K_x:
money -= 10
if event.key == pygame.K_r:
pausa = True
flip.play()
if event.key == pygame.K_ESCAPE:
pausa = False
if event.key == pygame.K_b:
pablo = True
if event.key == pygame.K_ESCAPE:
pablo = False
if event.type == pygame.KEYUP:
pass
pygame.display.update()
pygame.quit()
I can help you with sprites, but scrolling and animated backgrounds are way out of my league. So I see you have loaded the images, and assuming you have no error images, in the while run loop, simply type this:
pantalla.blit(sprite loading variable,(spriteX,SpriteY))
pantalla is your screen, pantalla.blit() is needed to "blit" or put one image on top of another, sprite loading variable is something like jagudor because you wrote pygame.image.load(), then SpriteX and SpriteY are the x and y coordinates of the image. I recommend you start reading some pygame books because blitting an image is like the first thing you learn in pygame.

problems with pygame controller support

import pygame
import os
import random
import time
import json
from pygame import joystick
pygame.font.init()
pygame.init()
WIDTH, HEIGHT = 1920, 1000
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("space invaders")
WHITE = (255, 255, 255)
#load images
RED_SPACE_SHIP = pygame.transform.scale(pygame.image.load(os.path.join("Assets", "pixel_ship_red_small.png")), (125, 100))
GREEN_SPACE_SHIP = pygame.transform.scale(pygame.image.load(os.path.join("Assets", "pixel_ship_green_small.png")), (125, 100))
BLUE_SPACE_SHIP = pygame.transform.scale(pygame.image.load(os.path.join("Assets", "pixel_ship_blue_small.png")), (125, 100))
#player
YELLOW_SPACE_SHIP = pygame.transform.rotate(pygame.transform.scale(pygame.image.load(os.path.join("Assets", "spaceship_yellow.png")), (154, 121)), 180)
#lasers
RED_LASER = pygame.image.load(os.path.join("Assets", "pixel_laser_red.png"))
BLUE_LASER = pygame.image.load(os.path.join("Assets", "pixel_laser_blue.png"))
GREEN_LASER = pygame.image.load(os.path.join("Assets", "pixel_laser_green.png"))
#player laser
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', 'space.png')), (WIDTH, HEIGHT))
class Laser():
def __init__(self, x, y, img):
self.x = x
self.y = y
self.img = img
self.mask = pygame.mask.from_surface(self.img)
def draw(self, window):
window.blit(self.img, (self.x, self.y))
def move(self, vel):
self.y += vel
def off_screen(self, height):
return not(self.y <= height and self.y >= 0)
def collision(self, obj):
return collide(self, obj)
class Ship:
COOLDOWN = 30
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):
window.blit(self.ship_img, (self.x, self.y))
for laser in self.lasers:
laser.draw(window)
def move_lasers(self, vel, obj):
self.cooldown()
for laser in self.lasers:
laser.move(vel)
if laser.off_screen(HEIGHT):
self.lasers.remove(laser)
elif laser.collision(obj):
obj.health -= 10
self.lasers.remove(laser)
def cooldown(self):
if self.cool_down_counter >= self.COOLDOWN:
self.cool_down_counter = 0
elif self.cool_down_counter > 0:
self.cool_down_counter += 1
def shoot(self):
if self.cool_down_counter == 0:
laser = Laser(self.x, self.y, self.laser_img)
self.lasers.append(laser)
self.cool_down_counter = 1
def get_width(self):
return self.ship_img.get_width()
def get_height(self):
return self.ship_img.get_height()
class Player(Ship):
def __init__(self, x, y, health = 100):
super().__init__(x, y, health)
self.ship_img = YELLOW_SPACE_SHIP
self.laser_img = YELLOW_LASER
self.mask = pygame.mask.from_surface(self.ship_img)
self.max_health = health
def shoot(self):
if self.cool_down_counter == 0:
laser = Laser(self.x + 26, self.y - 57, self.laser_img)
self.lasers.append(laser)
self.cool_down_counter = 1
def move_lasers(self, vel, objs):
self.cooldown()
for laser in self.lasers:
laser.move(vel)
if laser.off_screen(HEIGHT):
self.lasers.remove(laser)
else:
for obj in objs:
if laser.collision(obj):
objs.remove(obj)
if laser in self.lasers:
self.lasers.remove(laser)
def draw(self, window):
super().draw(window)
self.healthbar(window)
def healthbar(self, window):
pygame.draw.rect(window, (255, 0, 0), (self.x, self.y + self.ship_img.get_height() + 10, self.ship_img.get_width(), 10))
pygame.draw.rect(window, (0, 255, 0), (self.x, self.y + self.ship_img.get_height() + 10, self.ship_img.get_width()* (self.health/self.max_health),10))
class Enemy(Ship):
COLOR_MAP = {
"red": (RED_SPACE_SHIP, RED_LASER),
"green": (GREEN_SPACE_SHIP, GREEN_LASER),
"blue": (BLUE_SPACE_SHIP, BLUE_LASER)
}
def __init__(self, x, y, color, health = 100):
super().__init__(x, y, health)
self.ship_img, self.laser_img = self.COLOR_MAP[color]
self.mask = pygame.mask.from_surface(self.ship_img)
def move(self, vel):
self.y += vel
def shoot(self):
if self.cool_down_counter == 0:
laser = Laser(self.x - 3, self.y + 20, self.laser_img)
self.lasers.append(laser)
self.cool_down_counter = 1
def collide(obj1, obj2):
offset_x = obj2.x - obj1.x
offset_y = obj2.y - obj1.y
return obj1.mask.overlap(obj2.mask, (offset_x, offset_y)) != None
def main():
run = True
FPS = 60
level = 0
lives = 5
lost = False
lost_count = 0
main_font = pygame.font.SysFont("comicsans", 75)
lost_font = pygame.font.SysFont("comicsans", 500)
enemies = []
wave_length = 5
player_vel = 7
laser_vel = 7
enemy_vel = 1
player = Player(WIDTH // 2, 650)
clock = pygame.time.Clock()
def redraw_window():
WIN.blit(BG, (0,0))
#draw text
level_label = main_font.render(f"Level: {level}", 1, WHITE)
lives_label = main_font.render(f"Lives: {lives}", 1, WHITE)
WIN.blit(lives_label, (10, 10))
WIN.blit(level_label, (WIDTH - level_label.get_width() - 10, 10))
player.draw(WIN)
for enemy in enemies:
enemy.draw(WIN)
if lost:
lost_label = lost_font.render("You Lost!", 1, (WHITE))
WIN.blit(lost_label, (WIDTH/2 - lost_label.get_width()/2, HEIGHT / 2 - lost_label.get_height() / 2))
pygame.display.update()
joysticks = []
for i in range(pygame.joystick.get_count()):
joysticks.append(pygame.joystick.Joystick(i))
for joystick in joysticks:
pygame.joystick.init()
print(pygame.joystick.get_init())
with open(os.path.join("ps4_keys.json"), 'r+') as file:
button_keys = json.load(file)
# 0: Left analog horizonal, 1: left analog verticle, 2: right analog horizonal
# 3: right analog verticle, 4: left Triger, 5: Right Trigger
analog_keys = {0:0, 1:0, 2:0, 3:0, 4:-1, 5:-1}
while run:
clock.tick(FPS)
redraw_window()
if lives <= 0 or player.health <= 0:
lost = True
lost_count += 1
if lost:
if lost_count > FPS * 3:
run = False
else:
continue
if len(enemies) == 0:
level += 1
wave_length += 5
for i in range(wave_length):
enemy = Enemy(random.randrange(100, WIDTH-100), random.randrange(-1500, -100), random.choice(["red", "blue", "green"]))
enemies.append(enemy)
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
if event.type == pygame.JOYAXISMOTION:
analog_keys[event.axis] = event.value
print(analog_keys)
if abs(analog_keys[0]) > .4:
if analog_keys[0] < -.7:
player.x -= 7
else:
continue
if analog_keys[0] < .7:
player.x += 7
for enemy in enemies[:]:
enemy.move(enemy_vel)
enemy.move_lasers(laser_vel, player)
if random.randrange(0, 120) == 1:
enemy.shoot()
if collide(enemy, player):
player.health -= 10
enemies.remove(enemy)
elif enemy.y + enemy.get_height() > HEIGHT:
lives -= 1
enemies.remove(enemy)
player.move_lasers(-laser_vel, enemies)
def main_menu():
title_font = pygame.font.SysFont("comicsans", 150)
run = True
while run:
WIN.blit(BG, (0,0))
title_label = title_font.render("Click the mouse to begin...", 1, WHITE)
WIN.blit(title_label, (WIDTH / 2 - title_label.get_width() / 2, HEIGHT / 2 - title_label.get_height() / 2))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
main()
pygame.quit()
main_menu()
^^^
so this is my code (here is the JSON file as well):
{
"x": 0,
"circle": 1,
"square": 2,
"triangle": 3,
"share": 4,
"PS": 5,
"options": 6,
"left_stick_click": 7,
"right_stick_click": 8,
"L1": 9,
"R1": 10,
"up_arrow": 11,
"down_arrow": 12,
"left_arrow": 13,
"right_arrow": 14,
"touchpad": 15
}
I'm trying to make the player be controlled by the controller left joystick and it returns no errors but my player does not move and it is printing true from the print(pygame.joystick.get_init()) and printing the joystick amounts from: print(analog_keys) but the player does not move. Any idea why?
Do not use the JOYAXISMOTION event. The event does not occur continuously, it only occurs once when the axis changes.
Use pygame.joystick.Joystick.get_axis to get the current position of the axis and move the player depending on the axis:
def main():
# [...]
while run:
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if joysticks:
joystick = joysticks[0]
axis_x, axis_y = (joystick.get_axis(0), joystick.get_axis(1))
if abs(axis_x) > 0.1:
player.x += round(7 * axis_x)
if abs(axis_y) > 0.1:
player.y += round(7 * axis_y)
# [...]
Minimal example:
import pygame
from pygame.locals import *
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
x, y = window.get_rect().center
if pygame.joystick.get_count() > 0:
joystick = pygame.joystick.Joystick(0)
joystick.init()
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
axis_x, axis_y = (joystick.get_axis(0), joystick.get_axis(1))
if abs(axis_x) > 0.1:
x = (x + round(7 * axis_x)) % window.get_width()
if abs(axis_y) > 0.1:
y = (y + round(7 * axis_y)) % window.get_height()
window.fill(0)
pygame.draw.circle(window, (255, 0, 0), (x, y), 10)
pygame.display.flip()
clock.tick(60)
pygame.quit()
exit()

Trying to call multiple sprites to the screen causes glitching?

Im trying to make a game in which rocks fall from the screen and you have to dodge them. I made a class for my rock and I use a list to append the rocks. But when I run it the rocks just glitch around the screen appearing in some frames and not in others while they are also not falling down the screen. I have tried to make a function for the movement but that also did not work. I need help. Thanks
Here's a video of what I mean:
https://streamable.com/xd26w
import pygame
import random
import math
pygame.init()
GOLD = (255, 215, 0)
def text_objects(text, font):
textSurface = font.render(text, True, GOLD)
return textSurface, textSurface.get_rect()
screenwidth = 500
screenheight = 500
win = pygame.display.set_mode((screenwidth, screenheight))
pygame.display.set_caption('First Game')
bkg = pygame.image.load('2.jpg')
bkg = pygame.transform.scale(bkg, (500,500))
char1 = pygame.image.load('guy.png')
char1 = pygame.transform.scale(char1, (100, 100))
walkRight = []
walkLeft = []
HitAnim = []
Howmany = 4
for i in range(1, 13):
walkRight.append(pygame.transform.scale(pygame.image.load('R' + str(i) + '.png'), (100, 100)))
for i in range(1, 13):
walkLeft.append(pygame.transform.scale(pygame.image.load('L' + str(i) + '.png'), (100, 100)))
rockboom = pygame.image.load('b1.png')
rockboom = pygame.transform.scale(rockboom, (100,100))
GameO = pygame.image.load('Gameover.jpg')
rock = pygame.image.load('b.png')
rock = pygame.transform.scale(rock, (100, 100))
clock = pygame.time.Clock()
class player(object):
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.GameOver = False
self.vel = 10
self.walkCount = 0
self.left = False
self.right = False
self.lives = 3
self.hit = 0
self.hit1 = False
def draw(self, win):
if self.walkCount + 1 >= 27:
self.walkCount = 0
if self.left == True:
win.blit(walkLeft[self.walkCount // 3], (self.x, self.y))
self.walkCount += 1
pygame.display.update()
elif self.right == True :
win.blit(walkRight[self.walkCount // 3], (self.x, self.y))
self.walkCount += 1
else:
win.blit(char1, (self.x, self.y))
class rocky():
def __init__(self):
self.x = random.randrange(0, 430)
self.y = -100
def draw(self, win):
win.blit(rock, (self.x, self.y))
if man.hit1 == True:
win.blit (rockboom, (self.x, self.y))
def move(self):
rockk.y += 1
if rockk.y >= 500:
rockk.x = random.randrange(0, 430)
rockk.y = -100
if man.hit1 == True:
rockk.x = random.randrange(0, 430)
rockk.y = -100
def redrawgamewindow():
win.blit(bkg, (0, 0))
man.draw(win)
largeText = pygame.font.Font('freesansbold.ttf', 30)
TextSurf, TextRect = text_objects("Lives: " + str(man.lives), largeText)
TextRect.center = ((100), (470))
win.blit(TextSurf, TextRect)
pygame.display.flip()
def collided (rockx, rocky, manx, many):
man.hit = 0
distance = math.sqrt((math.pow(rockx-manx, 2) + (math.pow(rocky-many, 2))))
if distance < 75:
man.hit += 1
print("we be touched")
man.hit1 = True
else:
man.hit1 = False
my_list= []
for number in range(Howmany):
my_object = rocky()
my_list.append(my_object)
print ("")
drawing = True
man = player(250, 350, 100, 100)
run = True
while run:
# Setting fps
clock.tick(60)
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
# Getting keys pressed
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and man.x > 0:
man.x -= man.vel
man.left = True
man.right = False
elif keys[pygame.K_RIGHT] and man.x < 500 - man.vel - man.width:
man.x += man.vel
man.left = False
man.right = True
else:
man.left = False
man.right = False
man.walkCount = 0
for rockk in my_list:
rockk.draw(win)
rockk.move()
pygame.display.update()
if man.hit == 1:
man.lives -=1
elif man.hit ==2:
man.lives -=1
elif man.lives <= 0:
print("so uh yeah it worked cool ")
drawing = False
win.blit (GameO, (0, 0))
pygame.display.update()
collided(rockk.x, rockk.y, man.x, man.y)
if drawing:
redrawgamewindow()
win.blit(pygame.image.load('R1.png').convert_alpha(), (200, 200))
You need to draw all things together in the redrawgamewindow function. Currently you are drawing the rocks during the loop, and when the redrawgamewindow function is called, they disappear (first thing this function does is drawing the background, deleting everything). From here the flickering effect.
Your function should be:
def redrawgamewindow():
win.blit(bkg, (0, 0))
man.draw(win)
largeText = pygame.font.Font('freesansbold.ttf', 30)
TextSurf, TextRect = text_objects("Lives: " + str(man.lives), largeText)
TextRect.center = ((100), (470))
win.blit(TextSurf, TextRect)
#drawing the rocks
for rockk in my_list:
rockk.draw(win)
pygame.display.flip()
Basically, move all drawing stuff in redrawgamewindow and should work. In the main loop, limit to move the rock, but not draw them. Also, no need to call pygame.display.update() multiple times. The call to pygame.display.flip() (which basically does the same thing of pygame.display.update() in the funcion is enough.

Pygame sprite sheet hitbox broken

I made a simple game, where you have to jump over the stones moving towards you. The problem is that one of those sprites hitboxes is broken, even if the sprite mask is used. The player sprite is generated just dividing the player sprite sheet into 4 columns. Maybe there the problem is hiding?
Pictures for the program:
https://drive.google.com/drive/folders/1We6RDMs3Cwwprf1OY0ow9WCTHF9MHzne?usp=sharing
import pygame, os, random
pygame.init()
W, H = 800,600
HW, HH = W/2,H/2
AREA = W * H
WHITE = (255,255,255)
GREEN = (69,139,0)
FPS = 60
bg = pygame.image.load(os.path.join('Pildid', 'Taust3.png'))
bg = pygame.transform.scale(bg, (2000, 600))
DS = pygame.display.set_mode((W,H))
clock = pygame.time.Clock()
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, py, player, veerg, rida):
super(Player,self).__init__()
'''Mangija huppamine'''
clock.tick(5)
self.x = x
self.y = y
self.jumping = False
self.platform_y = py
self.velocity_index = 0
'''Sprite sheet'''
self.player = pygame.image.load(os.path.join('Pildid', 'karakter.png')).convert_alpha()#pildi uleslaadimine
#self.player = pygame.transform.scale(self.player,(200,100))
self.rect = self.player.get_rect()
'''Sprite sheeti piltide jaotamine pikslite jargi'''
self.veerg = veerg
self.rida = rida
self.kokku = veerg * rida
self.rect = self.player.get_rect()
L = self.veergL = self.rect.width/veerg
K = self.weegK = self.rect.height/rida
PL,PK = self.veergKeskel = (L/2,K/2)
self.veerg = list([(index % veerg * L, int(index/veerg) * K,L,K )for index in range(self.kokku)])
self.handle = list([ #pildi paigutamise voimalikud positsioonid
(0, 0), (-PL, 0), (-L, 0),
(0, -PK), (-PL, -PK), (-L, -PK),
(0, -L), (-PL, -K), (-L, -K),])
self.mask = pygame.mask.from_surface(self.player)
def do_jumpt(self):
'''Huppamine: kiirus, korgus, platvorm'''
global velocity
if self.jumping:
self.y += velocity[self.velocity_index]
self.velocity_index += 1
if self.velocity_index >= len(velocity) - 1:
self.velocity_index = len(velocity) - 1
if self.y > self.platform_y:
self.y = self.platform_y
self.jumping = False
self.velocity_index = 0
def draw(self, DS,veergindex,x,y,handle=0):
DS.blit(self.player,(self.x+self.handle[handle][0], self.y + self.handle[handle][1]),self.veerg[veergindex])
def do(self):
'''Funktsioonide kokkupanek'''
self.do_jumpt()
p.draw(DS,index%p.kokku,190, 359,4)
def update(self):
self.rect.center = self.x, self.y
def keys(player):
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE] or keys[pygame.K_UP] and player.jumping == False:
player.jumping = True
class Obsticles(pygame.sprite.Sprite):
'''Game obsticles: **'''
#img = pygame.image.load(os.path.join('images', 'box.png'))
def __init__(self, x, y):
super(Obsticles,self).__init__()
self.img = pygame.image.load(os.path.join('Pildid', 'kivi.png')).convert_alpha()
self.img = pygame.transform.scale(self.img, (90,90))
self.rect = self.img.get_rect(center=(x, y))
self.x = x
self.y = y
self.mask = pygame.mask.from_surface(self.img)
def draw(self, DS):
'''Obsticle img blitting and hitbox'''
DS.blit(self.img, (self.x, self.y))
def update(self):
if self.x < -64: # Delete the obstacle.
# `kill()` removes this obstacle sprite from all sprite groups.
self.kill()
self.x += speed # Move the obstacle.
# Update the rect because it's used to blit the
# sprite and for the collision detection.
self.rect.center = self.x, self.y
def redrawWindow():
'''Obsticle loop'''
for i in ob:
i.draw(DS)
def text_objects(text, font):
textSurface = font.render(text, True, WHITE)
return textSurface, textSurface.get_rect()
def message_display(text):
largeText = pygame.font.Font('freesansbold.ttf',60)
TextSurf, TextRect = text_objects(text, largeText)
TextRect.center = ((W/2),(H/4))
DS.blit(TextSurf, TextRect)
pygame.display.update()
pygame.time.wait(3000)
def crash():
message_display('Failed')
pygame.time.set_timer(pygame.USEREVENT+2, random.choice([2500, 3000, 1500]))
velocity = list([(i/ 1)-20 for i in range (0,60)]) #Huppe ulatus
index = 3
obsticles = Obsticles(832, 363)
p = Player(190, 359, 359, 'karakter.png', 4, 1)
all_sprites = pygame.sprite.Group(p, obsticles)
ob = pygame.sprite.Group(obsticles)
x = 0
x -= 1
speed = -5
running = True
while running:
# ---Handle the events.---
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.USEREVENT+2:
r = random.randrange(0, 2)
if r == 0:
obsticles = Obsticles(832, 363)
# Add the obstacle to both groups.
ob.add(obsticles)
all_sprites.add(obsticles)
speed += -0.008
# ---Game logic.---
all_sprites.update()
collided = pygame.sprite.spritecollide(p, ob, True,
pygame.sprite.collide_mask)
if collided:
crash()
index += 1
# Background movement.
back_x = x % bg.get_rect().width
x -= 2
# ---Draw everything.---
DS.blit(bg, (back_x - bg.get_rect().width, 0))
if back_x < W:
DS.blit(bg, (back_x, 0))
keys(p)
p.do()
redrawWindow()
pygame.display.update()
clock.tick(60)
pygame.quit()
quit()
The problem is that you use the original image to create the Player.mask. The resulting mask covers all four poses of the character, so even if only one of the sprite sheet frames is visible, the complete original image is used for the collision detection. Your mask looks like the green area in this picture:
You should also use the rect (i.e. the rect.topleft coords) as the blit position, because it is used for the collision detection as well (to find the location of the mask).
I've got a fixed, shortened version of your program in which I've changed a few things to show you how I would solve the problem. First of all, I load the sprite sheet and cut it into several subsurfaces, then I assign the first surface/image to the self.image attribute of the Player. This image can be used to create the rect and the mask.
In the update method I increment the frame_index and assign the current image to self.image in order to animate the sprite. BTW, it would be a good idea to create separate masks for every image and swap them as well during the animation. (I'm just using the first mask here, since the animation frames are so similar.)
Note that if you give your sprites an image and a rect attribute, you can just call all_sprites.update(DS) to blit all sprite images at their corresponding rects.
import random
import pygame
pygame.init()
FPS = 60
DS = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
PLAYER_SHEET = pygame.image.load('karakter.png').convert_alpha()
# Cut the sprite sheet and append the subsurfaces to this list.
PLAYER_IMAGES = []
width = PLAYER_SHEET.get_width() / 4
height = PLAYER_SHEET.get_height()
for x in range(4):
PLAYER_IMAGES.append(PLAYER_SHEET.subsurface(x*width, 0, width, height))
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, py):
super(Player,self).__init__()
self.x = x
self.y = y
self.jumping = False
self.platform_y = py
self.velocity_index = 0
self.velocity = list([(i/ 1)-20 for i in range (0,60)])
self.frame_index = 0
self.image = PLAYER_IMAGES[self.frame_index]
self.rect = self.image.get_rect()
self.mask = pygame.mask.from_surface(self.image)
def do_jump(self):
if self.jumping:
self.y += self.velocity[self.velocity_index]
self.velocity_index += 1
if self.velocity_index >= len(self.velocity) - 1:
self.velocity_index = len(self.velocity) - 1
if self.y > self.platform_y:
self.y = self.platform_y
self.jumping = False
self.velocity_index = 0
def update(self):
self.rect.center = self.x, self.y
self.do_jump()
# Update the animation frame.
self.frame_index += 1
self.frame_index %= len(PLAYER_IMAGES) * 7 # * 7 to slow it down.
# Swap the image.
self.image = PLAYER_IMAGES[self.frame_index//7] # // 7 to slow it down.
def keys(player):
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE] or keys[pygame.K_UP] and player.jumping == False:
player.jumping = True
class Obstacle(pygame.sprite.Sprite):
"""Game Obstacle."""
def __init__(self, x, y):
super(Obstacle,self).__init__()
self.image = pygame.Surface((90, 90), pygame.SRCALPHA)
self.image.fill((100, 150, 0))
self.image = pygame.transform.scale(self.image, (90,90))
self.rect = self.image.get_rect(center=(x, y))
self.x = x
self.y = y
self.mask = pygame.mask.from_surface(self.image)
def update(self):
if self.x < -64:
self.kill()
self.x += speed
self.rect.center = self.x, self.y
pygame.time.set_timer(pygame.USEREVENT+2, random.choice([2500, 3000, 1500]))
index = 3
obstacle = Obstacle(832, 363)
player = Player(190, 359, 359)
all_sprites = pygame.sprite.Group(player, obstacle)
obstacles = pygame.sprite.Group(obstacle)
speed = -5
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.USEREVENT+2:
r = random.randrange(0, 2)
if r == 0:
obstacle = Obstacle(832, 363)
# Add the obstacle to both groups.
obstacles.add(obstacle)
all_sprites.add(obstacle)
keys(player)
# ---Game logic.---
speed += -0.008
all_sprites.update()
collided = pygame.sprite.spritecollide(player, obstacles, True,
pygame.sprite.collide_mask)
if collided:
print('crash')
index += 1
# ---Draw everything.---
DS.fill((30, 30, 30))
all_sprites.draw(DS)
# Here I draw the outline (points) of the player's mask.
px, py = player.rect.topleft
for point in player.mask.outline(8):
x, y = point[0] + px, point[1] + py
pygame.draw.circle(DS, (250, 250, 0), (x, y), 2)
pygame.draw.rect(DS, (0, 0, 250), player.rect, 1)
# Draw the outlines of the obstacles.
for obstac in obstacles:
pygame.draw.rect(DS, (150, 250, 0), obstac.rect, 1)
ox, oy = obstac.rect.topleft
for point in obstac.mask.outline(6):
pygame.draw.circle(DS, (250, 0, 0), (point[0]+ox, point[1]+oy), 2)
pygame.display.update()
clock.tick(60)
pygame.quit()

How do you make the game end when the main player collides with an image (obstacle)?

import math
import random
import pygame
from pygame.locals import *
import sys
def events():
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
pygame.init()
W = 700
H = 400
updater = pygame.time.Clock()
display = pygame.display.set_mode((700, 400))
pygame.display.set_caption("Skating_Game")
x = y = 0
surface = pygame.image.load("man2.png")
pygame.display.set_icon(surface)
class player:
def __init__(self, velocity, maxJumpRange):
self.velocity = velocity
self.maxJumpRange = maxJumpRange
def setLocation(self, x, y):
self.x = x
self.y = y
self.xVelocity = 0
self.jumping = False
self.jumpCounter = 0
self.falling = True
def keys(self):
k = pygame.key.get_pressed()
if k[K_LEFT]:
self.xVelocity = -self.velocity
elif k[K_RIGHT]:
self.xVelocity = self.velocity
else:
self.xVelocity = 0
if k[K_SPACE] and not self.jumping and not self.falling:
self.jumping = True
self.jumpCounter = 0
def move(self):
self.x += self.xVelocity
if self.jumping:
self.y -= self.velocity
self.jumpCounter += 1
if self.jumpCounter == self.maxJumpRange:
self.jumping = False
self.falling = True
elif self.falling:
if self.y <= H - 60 and self.y + self.velocity >= H - 60:
self.y = H - 60
self.falling = False
else:
self.y += self.velocity
def draw(self):
display = pygame.display.get_surface()
character = pygame.image.load("man3.png").convert_alpha()
display.blit(character, (self.x, self.y - 100))
#pygame.draw.circle(display, (255, 255, 255), (self.x, self.y - 25), 25, 0)
def do(self):
self.keys()
self.move()
self.draw()
P = player(3, 50)
P.setLocation(350, 0)
BLACK = ( 0, 0, 0)
g=0
font = pygame.font.SysFont("Plump", 30)
obstacle = pygame.image.load("obstacle.png").convert_alpha()
background = pygame.image.load("Road.png").convert()
x = 0
while True:
events()
rel_x = x % background.get_rect().width
display.blit(background, (rel_x - background.get_rect().width,0))
if rel_x < 700:
display.blit(background, (rel_x, 0))
x -= 1
g += 0.01
pygame.draw.rect(display, (255,255,255,128), [rel_x, 275, 150, 50])
display.blit(obstacle, (rel_x, 250))
text = font.render("Score: "+str(int(g)), True, (255, 255, 255))
display.blit(text, (0,0))
P.do()
if P.rect.collidepoint(self.x,self.y):
pygame.quit()
pygame.display.update()
updater.tick(200)
So if the player collides with the obstacle image the game should stop. How do i do this? I have made a class for the player and the obstacle is just an image which is constantly moving.
I was thinking maybe I could track the x and y coordinate of the player and obstacle and when their radius overlaps the game could stop.
Here's a working (simplified) version of your program with some comments. You have to create rects for the obstacle and the player and then check if the rects collide with the help of the colliderect method.
import sys
import pygame
from pygame.locals import *
pygame.init()
W = 700
H = 400
updater = pygame.time.Clock()
display = pygame.display.set_mode((700, 400))
PLAYER_IMAGE = pygame.Surface((30, 50))
PLAYER_IMAGE.fill(pygame.Color('dodgerblue1'))
class Player:
def __init__(self, x, y, velocity, maxJumpRange):
self.velocity = velocity
self.maxJumpRange = maxJumpRange
self.image = PLAYER_IMAGE # Give the player an image.
# Create a rect with the size of the PLAYER_IMAGE and
# pass the x, y coords as the topleft argument.
self.rect = self.image.get_rect(topleft=(x, y))
self.x = x
self.y = y
self.xVelocity = 0
self.jumping = False
self.jumpCounter = 0
self.falling = True
def keys(self):
k = pygame.key.get_pressed()
if k[K_LEFT]:
self.xVelocity = -self.velocity
elif k[K_RIGHT]:
self.xVelocity = self.velocity
else:
self.xVelocity = 0
if k[K_SPACE] and not self.jumping and not self.falling:
self.jumping = True
self.jumpCounter = 0
def move(self):
self.x += self.xVelocity
if self.jumping:
self.y -= self.velocity
self.jumpCounter += 1
if self.jumpCounter == self.maxJumpRange:
self.jumping = False
self.falling = True
elif self.falling:
if self.y >= H - 160: # Simplified a little.
self.y = H - 160
self.falling = False
else:
self.y += self.velocity
# Update the position of the rect, because it's
# used for the collision detection.
self.rect.topleft = self.x, self.y
def draw(self, display):
# Just draw the image here.
display.blit(self.image, (self.x, self.y))
def do(self):
self.keys()
self.move()
player = Player(350, 0, 3, 50)
obstacle = pygame.Surface((150, 50))
obstacle.fill(pygame.Color('sienna1'))
# Create a rect with the size of the obstacle image.
obstacle_rect = obstacle.get_rect()
g = 0
x = 0
FPS = 60 # Cap the frame rate at 60 or 30 fps. 300 is crazy.
while True:
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
# --- Update the game ---
player.do()
rel_x = x % display.get_width()
x -= 7
g += 0.01
obstacle_rect.topleft = rel_x, 250 # Update the position of the rect.
# --- Draw everything ---
display.fill((30, 30, 30))
display.blit(obstacle, (rel_x, 250))
if g > 30:
display.blit(obstacle, (rel_x+350, 250))
# Check if the obstacle rect and the player's rect collide.
if obstacle_rect.colliderect(player.rect):
print("Game over!") # And call pygame.quit and sys.exit if you want.
# Draw the image/surface of the player onto the screen.
player.draw(display)
# Draw the actual rects of the objects (for debugging).
pygame.draw.rect(display, (200, 200, 0), player.rect, 2)
pygame.draw.rect(display, (200, 200, 0), obstacle_rect, 2)
pygame.display.update()
updater.tick(FPS)
Pygame rectangles include a collidepoint and colliderect method that allows you to check to see if something intersects with a rectangle. So you could have rectangles drawn beneath the obstacle and check to see if the player's coordinates intersect with the rectangle. Like this:
if self.rect.collidepoint(self.x,self.y):
pygame.quit()

Categories

Resources