Pygame. Sprite is still drawing after killing itself - python

I want to remove the sprite and not display it on screen after click. The screenshot show that the sprite is successfully removed from the group, but it is still drawn on the screen. I would be happy to get help on this matter.
import pygame as pg
class Figure1(pg.sprite.Sprite):
def __init__(self, width: int, height: int):
super().__init__()
self.image = pg.Surface((width, height))
self.image.fill((0,0,0))
self.rect = self.image.get_rect()
class Game:
def __init__(self, main_surface: pg.Surface):
self.main_surface = main_surface
self.group = pg.sprite.Group()
self.main_sprite = Figure1(40,40)
self.group.add(self.main_sprite)
self.group.draw(self.main_surface)
self.selected = None
def btn_down(self, pos, btn):
if btn == 1:
if self.main_sprite.rect.collidepoint(pos):
print(self.group.sprites())
print(self.main_sprite.alive())
self.main_sprite.kill()
print(self.group.sprites())
print(self.main_sprite.alive())
self.group.draw(self.main_surface)
pg.init()
clock = pg.time.Clock()
screen = pg.display.set_mode((200,200))
screen.fill((100,100,100))
pg.display.update()
g = Game(screen)
run = True
while run:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
run = False
if event.type == pg.MOUSEBUTTONDOWN:
g.btn_down(event.pos, event.button)
clock.tick(60)
pg.display.update()

The sprite doesn't disappear just because you stop drawing it. Of course, you need to clear the screen. You have to clear the screen in every frame. The typical PyGame application loop has to:
limit the frames per second to limit CPU usage with pygame.time.Clock.tick
handle the events by calling either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by calling either pygame.display.update() or pygame.display.flip()
import pygame as pg
class Figure1(pg.sprite.Sprite):
def __init__(self, width: int, height: int):
super().__init__()
self.image = pg.Surface((width, height))
self.image.fill((0,0,0))
self.rect = self.image.get_rect()
class Game:
def __init__(self, main_surface: pg.Surface):
self.main_surface = main_surface
self.group = pg.sprite.Group()
self.main_sprite = Figure1(40,40)
self.group.add(self.main_sprite)
self.selected = None
def btn_down(self, pos, btn):
if btn == 1:
if self.main_sprite.rect.collidepoint(pos):
self.main_sprite.kill()
def draw(self):
self.group.draw(self.main_surface)
pg.init()
clock = pg.time.Clock()
screen = pg.display.set_mode((200,200))
g = Game(screen)
run = True
while run:
# limit the frames per second
clock.tick(60)
# handle the events and update objects
for event in pg.event.get():
if event.type == pg.QUIT:
run = False
if event.type == pg.MOUSEBUTTONDOWN:
g.btn_down(event.pos, event.button)
# clear the screen
screen.fill((100,100,100))
# draw the objects
g.draw()
# update the display
pg.display.update()
pg.quit()

Related

how to animate the sprite?

from numpy import size
import pygame
import sys
# --- constants --- # PEP8: `UPPER_CASE_NAMES` for constants
WHITE = (255, 255, 255) # PE8: space after `,`
SIZE = (700, 500)
FPS = 120 # there is no need to use `500` because Python can't run so fast,
# and monitors runs with 60Hz (eventually 120Hz) which can display 60 FPS (120 FPS)
# --- classes --- # PEP8: `CamelCaseNames` for classes
class MySprite(pygame.sprite.Sprite):
def __init__(self, x, y, picture, colorkey):
super().__init__()
# you need one of them
# load image
self.image = pygame.image.load(picture)
# OR
# create surface
# self.image = pygame.Surface((10, 10))
# self.image.fill((255, 0, 0))
# ----
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.image.set_colorkey(colorkey)
def update(self):
if event.type == pygame.MOUSEBUTTONDOWN:
mouse = pygame.mouse.get_pos()
print(mouse[:])
# --- main ---
pygame.init()
window_game = pygame.display.set_mode(SIZE)
backGround = pygame.image.load('bg.jpg').convert_alpha(window_game)
backGround = pygame.transform.smoothscale(backGround,SIZE)
backGround.set_colorkey(WHITE)
#placeSP_group = pygame.sprite.Group()
placeSP_group = pygame.sprite.OrderedUpdates() # Group which keep order
sprite1 = [MySprite(0, 0, 'crossHair.png', WHITE),MySprite(0, 0, 'crossHair_2.png', WHITE)]
placeSP_group.add([sprite1[0],sprite1[1]])
pygame.mouse.set_visible(False)
clock = pygame.time.Clock() # PEP8: `lower_case_names` for variables
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
#running = False
pygame.quit()
exit()
# create new Sprite
global x,y
x, y = pygame.mouse.get_pos()
new_sprite = sprite1[:]
# add new Sprite at the end of OrderedUpdates()
placeSP_group.add([new_sprite])
# remove Sprite at the beginning of OrderedUpdates()
placeSP_group.sprites()[0].kill()
placeSP_group.update()
# ---
pygame.display.flip()
window_game.fill('white')
window_game.blit(backGround,(0,0)).size
placeSP_group.draw(window_game)
clock.tick(FPS)
when i assignee new_sprite to all the assigned sprites in placeSP
it dosen't show any thing can you help me with that i am not sure why is that happening but can you fix it ... this an edited question. And i didn't got any answer .... but i have the concept in my head can and i also don't wan't to modify my code that much can you help me with that...
Create a sprite class with a list of images. Add an attribute that counts the frames. Get image from image list in the update method based on number of frames:
class MySprite(pygame.sprite.Sprite):
def __init__(self, x, y, image_list):
super().__init__()
self.frame = 0
self.image_list = image_list
self.image = self.image_list[0]
self.rect = self.image.get_rect()
self.rect.center = (x, y)
def update(self, event_list):
animation_interval = 20
self.frame += 1
if self.frame // animation_interval >= len(self.image_list):
self.frame = 0
self.image = self.image_list[self.frame // animation_interval]
for event in event_list:
if event.type == pygame.MOUSEBUTTONDOWN:
mouse = event.pos
print(mouse[:])
However, instead of constantly creating and killing the sprite every frame, you need to create the sprite once before the application loop. Change the position of the sprite and update the sprite in the application loop:
file_list = ['crossHair.png', 'crossHair_2.png', 'crossHair_3.png']
image_list = []
for name in file_list:
image = pygame.image.load(name)
image.set_colorkey(WHITE)
image_list.append(image)
# create sprite
sprite1 = MySprite(0, 0, image_list)
placeSP_group = pygame.sprite.OrderedUpdates()
placeSP_group.add([sprite1])
clock = pygame.time.Clock()
running = True
while running:
# handle events
event_list = pygame.event.get()
for event in event_list:
if event.type == pygame.QUIT:
running = False
# update sprite
x, y = pygame.mouse.get_pos()
placeSP_group.sprites()[0].rect.center = (x, y)
placeSP_group.update(event_list)
# draw scene
window_game.fill('white')
window_game.blit(backGround,(0,0)).size
placeSP_group.draw(window_game)
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
exit()
See also:
how to create an illusion of animations in pygame
Animated sprite from few images
How do I create animated sprites using Sprite Sheets in Pygame?

Cannot Collide in Pygame

Im trying to make pin pon game, one rectangle is right side of the screen and other one is left side of the screen of course. When the ball hits the second rectangle it needs to be collide but in the update method there is a hits1 variable which supposed to be collide the stuffs but in same line
hits1 = pg.sprite.spritecollide(self.player,self.balls,False)
pygame gives me this error:
AttributeError: 'pygame.math.Vector2' object has no attribute 'colliderect'
import pygame as pg
import random
from settings import *
from sprites import *
from os import path
class Game:
def __init__(self):
# initialize game window, etc
pg.init()
pg.mixer.init()
self.screen = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption(TITLE)
self.clock = pg.time.Clock()
self.running = True
def new(self):
# start a new game
self.all_sprites = pg.sprite.Group()
self.balls = pg.sprite.Group()
self.player = Player(self)
self.player2 = Player2(self)
self.ball = Ball(self.player.pos.x + 10, self.player.pos.y + 20,self)
self.all_sprites.add(self.player,self.player2)
self.all_sprites.add(self.ball)
self.balls.add(self.ball)
self.run()
def run(self):
# Game Loop
self.playing = True
while self.playing:
self.clock.tick(FPS)
self.events()
self.update()
self.draw()
def update(self):
# Game Loop - Update
self.all_sprites.update()
hits1 = pg.sprite.spritecollide(self.player,self.balls,False)
if hits1:
self.player2.throw_back()
def events(self):
# Game Loop - events
for event in pg.event.get():
# check for closing window
if event.type == pg.QUIT:
if self.playing:
self.playing = False
self.running = False
def draw(self):
# Game Loop - draw
self.screen.fill(BLACK)
self.all_sprites.draw(self.screen)
# *after* drawing everything, flip the display
pg.display.flip()
def show_start_screen(self):
# game splash/start screen
pass
def show_go_screen(self):
# game over/continue
pass
g = Game()
g.show_start_screen()
while g.running:
g.new()
g.show_go_screen()
pg.quit()
You didn't show all relevant code but my educated guess is somewhere you have a Sprite class (either Player and/or Ball) where you assing a Vector2 instance to the rect attribute instead of a Rect instance.
I don't know how the code actually looks like but instead of something like this:
self.rect = some_vector
alter the existing Rect like this instead:
self.rect.topleft = some_vector

Insert score in a button game function

I have this code for a button that is pressable:
def button(msg,xloc,yloc,xlong,ylong,b1,b2,action=None):
hover = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if xloc < hover [0] < xloc+xlong and yloc< hover [1] < yloc+ylong:
pygame.draw.rect(display, b1, (xloc ,yloc ,xlong,ylong))
if click [0]==1 and action != None:
action()
else:
pygame.draw.rect(gameDisplay, inactiveButton, (xloc ,yloc ,xlong,ylong))
label = pygame.font.SysFont("arial",16)
textSurf, textBox = textMsg(msg, label)
textBox.center = ((xloc +(300)),((yloc +(150))
gameDisplay.blit(textSurf,textBox)
and the code for the scoring is:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN:
score+=1
print (score)
I would like have a score that – upon pressing the correct button in the choices in order to answer in a quiz game – will be displayed and incremented by 1. How can I do that?
Here's the simplest way to implement a button that I know. Create a rect for the button and draw it with pygame.draw.rect (or blit an image). For the collision detection, check if the event.pos of a pygame.MOUSEBUTTONDOWN event collides with the rect and then just increment the score variable.
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
GRAY = pg.Color('gray15')
BLUE = pg.Color('dodgerblue1')
def main():
clock = pg.time.Clock()
font = pg.font.Font(None, 30)
button_rect = pg.Rect(200, 200, 50, 30)
score = 0
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1:
if button_rect.collidepoint(event.pos):
print('Button pressed.')
score += 1
screen.fill(GRAY)
pg.draw.rect(screen, BLUE, button_rect)
txt = font.render(str(score), True, BLUE)
screen.blit(txt, (260, 206))
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
main()
pg.quit()
Addendum: Actually, I would implement a button with the help of classes, sprites and sprite groups. If you don't know how classes and sprites work, I'd recommend to check out Program Arcade Games (chapter 12 and 13).
import pygame as pg
pg.init()
GRAY= pg.Color('gray12')
BLUE = pg.Color('dodgerblue1')
FONT = pg.font.Font(None, 30)
# The Button is a pygame sprite, that means we can add the
# instances to a sprite group and then update and render them
# by calling `sprite_group.update()` and `sprite_group.draw(screen)`.
class Button(pg.sprite.Sprite):
def __init__(self, pos, callback):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((50, 30))
self.image.fill(BLUE)
self.rect = self.image.get_rect(topleft=pos)
self.callback = callback
def handle_event(self, event):
"""Handle events that get passed from the event loop."""
if event.type == pg.MOUSEBUTTONDOWN:
if self.rect.collidepoint(event.pos):
print('Button pressed.')
# Call the function that we passed during the
# instantiation. (In this case just `increase_x`.)
self.callback()
class Game:
def __init__(self):
self.screen = pg.display.set_mode((800, 600))
self.clock = pg.time.Clock()
self.x = 0
self.button = Button((200, 200), callback=self.increase_x)
self.buttons = pg.sprite.Group(self.button)
self.done = False
# A callback function that we pass to the button instance.
# It gets called if a collision in the handle_event method
# is detected.
def increase_x(self):
"""Increase self.x if button is pressed."""
self.x += 1
def run(self):
while not self.done:
self.handle_events()
self.run_logic()
self.draw()
self.clock.tick(30)
def handle_events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
self.done = True
for button in self.buttons:
button.handle_event(event)
def run_logic(self):
self.buttons.update()
def draw(self):
self.screen.fill(GRAY)
self.buttons.draw(self.screen)
txt = FONT.render(str(self.x), True, BLUE)
self.screen.blit(txt, (260, 206))
pg.display.flip()
if __name__ == "__main__":
Game().run()
pg.quit()

Screen resizing pygame

I am trying to resize my game from a menu but I am stuck. I am trying to scale the size of the screen the menu has to be when I click on new game. Does anyone have an idea on how to fix this since I cant find anything else.
import pygame
import runpy
import webbrowser, os
from Game import *
pygame.init()
class Option:
hovered = False
def __init__(self, text, pos):
self.text = text
self.pos = pos
self.set_rect()
self.draw()
def draw(self):
self.set_rend()
screen.blit(self.rend, self.rect,)
def set_rend(self):
self.rend = menu_font.render(self.text, True, self.get_color())
def get_color(self):
if self.hovered:
return (255,255,255)
else:
return (100,100,100)
def set_rect(self):
self.set_rend()
self.rect = self.rend.get_rect()
self.rect.topleft = self.pos
def onSelect(self):
if self.text == "Quit":
pygame.quit()
quit()
if self.text == "Instructions":
webbrowser.open_new("file://" + os.path.realpath("Manual.pdf"))
**if self.text == "New game":
Main()**
class Background(pygame.sprite.Sprite):
def __init__(self, image_file,):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
pygame.init()
pygame.mixer.music.load('Really Slow Motion - Fjord Keeper (Epic Intense Uplifting).mp3')
pygame.mixer.music.play(-1)
BackGround = Background('bg.png')
screen = pygame.display.set_mode((480, 320))
menu_font = pygame.font.Font(None, 40)
options = [Option("New game", (2, 195)), Option("Instructions", (2, 245)),
Option("Quit", (2, 295))]
while True:
pygame.event.pump()
screen.fill((0, 0, 0))
screen.blit(BackGround.image, BackGround.rect)
ev = pygame.event.get()
for event in ev:
if event.type == pygame.QUIT:
pygame.quit()
for option in options:
if option.rect.collidepoint(pygame.mouse.get_pos()):
option.hovered = True
else:
option.hovered = False
if option.hovered:
for event in ev:
if event.type == pygame.MOUSEBUTTONDOWN:
option.onSelect()
option.draw()
pygame.display.update()
This is my menu so far, but I'm trying to scale it so it will be 1300x1000.
I'm on mobile and I don't know how to do the code thing so I'll just type it out, k? K....
screen = pygame.display.set_mode((1300, 1300))
Put this where you want it to change. So lets say you put it as the f key. Then when you press f it should change the screen res to the set_mode.
just reset the display:
screen=pg.display.set_mode((1300,1000))
If you put this wherever you want the screen size to change, it'll work :)

Python Pygame image not displaying

I am trying to display a game in pygame. But it won't work for some reason, any ideas? Here is my code:
import pygame, sys
from pygame.locals import *
pygame.init()
screen=pygame.display.set_mode((640,360),0,32)
pygame.display.set_caption("My Game")
p = 1
green = (0,255,0)
pacman ="imgres.jpeg"
pacman_x = 0
pacman_y = 0
while True:
pacman_obj=pygame.image.load(pacman).convert()
screen.blit(pacman_obj, (pacman_x,pacman_y))
blue = (0,0,255)
screen.fill(blue)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type==KEYDOWN:
if event.key==K_LEFT:
p=0
pygame.display.update()
Just a guess, as I haven't actually ran this:
Is the screen just showing up blue and you're missing the pacman image? What might be happening is that you are blitting pacman onto the screen, and then doing a screen.fill(blue), which is essentially overwriting your pacman image with blue. Try reversing these steps in your code (that is, filling the screen blue, then blitting pacman after).
if the screen shows up blue, it is because you need to "blit" the image after you do screen.fill
also, blue has to be defined at the top, and it should be in a different loop. here is how i would do it:
import pygame, sys
from pygame.locals import *
pygame.init()
screen=pygame.display.set_mode((640,360),0,32)
pygame.display.set_caption("My Game")
p = 1
green = (0,255,0)
blue = (0,0,255)
pacman ="imgres.jpeg"
pacman_x = 0
pacman_y = 0
pacman_obj=pygame.image.load(pacman).convert()
done = False
clock=pygame.time.Clock()
while done==False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done=True
if event.type==KEYDOWN:
if event.key==K_LEFT:
p=0
screen.fill(blue)
screen.blit(pacman_obj, (pacman_x,pacman_y))
pygame.display.flip()
clock.tick(100)
pygame.quit()
Note:
You are creating a new image every frame. This is slow.
Coordinates for blit can be Rect()s
Here's updated code.
WINDOW_TITLE = "hi world - draw image "
import pygame
from pygame.locals import *
from pygame.sprite import Sprite
import random
import os
class Pacman(Sprite):
"""basic pacman, deriving pygame.sprite.Sprite"""
def __init__(self, file=None):
"""create surface"""
Sprite.__init__(self)
# get main screen, save for later
self.screen = pygame.display.get_surface()
if file is None: file = os.path.join('data','pacman.jpg')
self.load(file)
def draw(self):
"""draw to screen"""
self.screen.blit(self.image, self.rect)
def load(self, filename):
"""load file"""
self.image = pygame.image.load(filename).convert_alpha()
self.rect = self.image.get_rect()
class Game(object):
"""game Main entry point. handles intialization of game and graphics, as well as game loop"""
done = False
color_bg = Color('seagreen') # or also: Color(50,50,50) , or: Color('#fefefe')
def __init__(self, width=800, height=600):
"""Initialize PyGame window.
variables:
width, height = screen width, height
screen = main video surface, to draw on
fps_max = framerate limit to the max fps
limit_fps = boolean toggles capping FPS, to share cpu, or let it run free.
color_bg = backround color, accepts many formats. see: pygame.Color() for details
"""
pygame.init()
# save w, h, and screen
self.width, self.height = width, height
self.screen = pygame.display.set_mode(( self.width, self.height ))
pygame.display.set_caption( WINDOW_TITLE )
# fps clock, limits max fps
self.clock = pygame.time.Clock()
self.limit_fps = True
self.fps_max = 40
self.pacman = Pacman()
def main_loop(self):
"""Game() main loop.
Normally goes like this:
1. player input
2. move stuff
3. draw stuff
"""
while not self.done:
# get input
self.handle_events()
# move stuff
self.update()
# draw stuff
self.draw()
# cap FPS if: limit_fps == True
if self.limit_fps: self.clock.tick( self.fps_max )
else: self.clock.tick()
def draw(self):
"""draw screen"""
# clear screen."
self.screen.fill( self.color_bg )
# draw code
self.pacman.draw()
# update / flip screen.
pygame.display.flip()
def update(self):
"""move guys."""
self.pacman.rect.left += 10
def handle_events(self):
"""handle events: keyboard, mouse, etc."""
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT: self.done = True
# event: keydown
elif event.type == KEYDOWN:
if event.key == K_ESCAPE: self.done = True
if __name__ == "__main__":
game = Game()
game.main_loop()
First you blit the image and then fill it with BLUE ,so it might show only blue screen ,
Solution: First fill screen blue and then blit it.
import pygame, sys
from pygame.locals import *
pygame.init()
screen=pygame.display.set_mode((640,360),0,32)
pygame.display.set_caption("My Game")
p = 1
green = (0,255,0)
pacman ="imgres.jpeg"
pacman_x = 0
pacman_y = 0
while True:
pacman_obj=pygame.image.load(pacman).convert()
blue = (0,0,255)
screen.fill(blue) # first fill screen with blue
screen.blit(pacman_obj, (pacman_x,pacman_y)) # Blit the iamge
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type==KEYDOWN:
if event.key==K_LEFT:
p=0
pygame.display.update()

Categories

Resources