In my game I am trying to make it so when you walk into a object, it displays an image.
I'm pretty sure that pygame.display.update() is being called every frame because otherwise the game would be perfectly still.
However when I draw my new rect upon collision it doesn't appear, unless I put another pygame.display.update(rect) with it after it being drawn. This means that update is being called twice at one time, in the main game loop and after drawing the rect. This causes the rect (which has been drawn now) to flicker because of the multiple update calls.
I cannot figure it out why it doesn't get drawn without the second update call.
Main game loop call:
def events(self):
#game loop events
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.playing = False
self.running = False
def update(self):
self.all_sprites.update()
def main(self):
while self.playing:
self.events()
self.update()
self.draw()
self.running = False
def draw(self):
self.screen.fill(black)
self.all_sprites.draw(self.screen)
self.clock.tick(FPS)
pygame.display.update()
#create game instance
g= Game()
g.new()
while g.running:
#main gameloop
g.main()
pygame.quit()
sys.exit()
Here is when I call to draw the rect after collision with my object:
def update(self):
self.hitbox.center = numpy.add(self.rect.center,(8,22))
self.interactionhitbox.center = numpy.add(self.rect.center, (8,16))
if(self.showPopup):
# Initialwzng Color
color = (255,0,0)
# Drawing Rectangle
rect = pygame.Rect((0,0,60,60))
pygame.display.update(rect) # WITHOUT THIS LINE IT DOES NOT GET DRAWN, WITH IT IT FLICKERS
pygame.draw.rect(self.game.screen, color, rect)
So basically with the second pygame.display.update(rect) call it appears but flickers, and without it it doesn't show up at all
Any help is appreciated sorry if this is a bad question or not formatted right I haven't been here since 2017!
The rectangle is not drawn because the screen will later be cleared with self.screen.fill(black) later. You must draw the rectangle after self.screen.fill(black) and before pygame.display.update().
Create 2 images and choose the image to be drawn in update:
def __init__(self, ...)
# [...]
self.image = ...
self.original_image = self.image
self.image_and_rect = self.image.copy()
pygame.draw.rect(self.image_and_rect, (255,0,0), self.image_and_rect.get_rect(), 5)
def update(self):
self.hitbox.center = numpy.add(self.rect.center,(8,22))
self.interactionhitbox.center = numpy.add(self.rect.center, (8,16))
if self.showPopup:
self.image = self.image_and_rect
else:
self.image = self.original_image
Related
I'm building a pong game trying to get better at programming but Im having trouble moving the ball. When the move_right method is called the ellipse stretches to the right instead of moving to the right. I've tried putting the ball variable in the init method but that just makes it not move at all even though the variables should be changing on account of the move_right method. I have also tried setting the x and y positions as parameters in the Ball class,but that just stretches it also.
I don't understand why when I run the following code the ball I'm trying to move stretches to the right instead of moves to the right. Can someone explain why this is happening? I have tried everything I can think of but i can't get it to do what I want.
import pygame,sys
import random
class Ball:
def __init__(self):
self.size = 30
self.color = light_grey
self.x_pos = width/2 -15
self.y_pos = height/2 -15
self.speed = 1
#self.ball = pygame.Rect(self.x_pos, self.y_pos,self.size,self.size)
def draw_ball(self):
ball = pygame.Rect(self.x_pos, self.y_pos,self.size,self.size)
pygame.draw.ellipse(screen,self.color,ball)
def move_right(self):
self.x_pos += self.speed
class Player:
def __init__(self,x_pos,y_pos,width,height):
self.x_pos = x_pos
self.y_pos = y_pos
self.width = width
self.height = height
self.color = light_grey
def draw_player(self):
player = pygame.Rect(self.x_pos,self.y_pos,self.width,self.height)
pygame.draw.rect(screen,self.color,player)
class Main:
def __init__(self):
self.ball=Ball()
self.player=Player(width-20,height/2 -70,10,140)
self.opponent= Player(10,height/2-70,10,140)
def draw_elements(self):
self.ball.draw_ball()
self.player.draw_player()
self.opponent.draw_player()
def move_ball(self):
self.ball.move_right()
pygame.init()
size = 30
clock = pygame.time.Clock()
pygame.display.set_caption("Pong")
width = 1000
height = 600
screen = pygame.display.set_mode((width,height))
bg_color = pygame.Color('grey12')
light_grey = (200,200,200)
main = Main()
#ball = pygame.Rect(main.ball.x_pos, main.ball.y_pos,main.ball.size,main.ball.size)
#player = pygame.Rect(width-20,height/2 -70,10,140)
#opponent = pygame.Rect(10,height/2-70,10,140)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
#ball = pygame.Rect(main.ball.x_pos, main.ball.y_pos,main.ball.size,main.ball.size)
#pygame.draw.rect(screen,light_grey,player)
#pygame.draw.rect(screen,light_grey,opponent)
#pygame.draw.ellipse(screen,light_grey,ball)
main.draw_elements()
main.move_ball()
main.ball.x_pos += main.ball.speed
pygame.display.flip()
clock.tick(60)
You have to clear the display in every frame with pygame.Surface.fill:
while True:
# [...]
screen.fill(0) # <---
main.draw_elements()
main.move_ball()
main.ball.x_pos += main.ball.speed
pygame.display.flip()
# [...]
Everything that is drawn is drawn on the target surface. The entire scene is redraw in each frame. Therefore the display needs to be cleared at the begin of every frame in the application loop. The typical PyGame application loop has to:
handle the events by 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 either pygame.display.update() or pygame.display.flip()
This question already has an answer here:
Why is my pygame application loop not working properly?
(1 answer)
Closed 2 years ago.
All I get is a black screen.
Not sure if I can't find the image in the directory or, if some if I'm not calling something right... But it's not giving me an error so I'm not sure what to work off of.
import pygame
# Intialize the pygame
pygame.init()
# Create the screen
screen = pygame.display.set_mode((300, 180))
#Title and Icon
pygame.display.set_caption("Fighting Game")
# Add's logo to the window
# icon = pygame.image.load('')
# pygame.display.set_icon(icon)
# Game Loop
running = True
while running:
# screen.fill((0, 0, 0))
# screen.blit(BackGround.image, BackGround.rect)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
class Background(pygame.sprite.Sprite):
def __init__(self, image_file, location):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image = pygame.image.load("images/image.png")
self.rect = self.image.get_rect(300,180)
self.rect.left, self.rect.top = location
BackGround = Background('image.png', [0,0])
screen.fill((0, 0, 0))
screen.blit(BackGround.image, BackGround.rect)
You have to blit the image in the main application loop and you have to update the display by pygame.display.flip.
Furthermore it is not necessary to pass any parameters to self.image.get_rect(). Anyway the arguments to get_rect() have to be keyword arguments.
What you can do is to set the location by the keyword argument topleft.
class Background(pygame.sprite.Sprite):
def __init__(self, image_file, location):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image = pygame.image.load("images/image.png")
self.rect = self.image.get_rect(topleft = location)
BackGround = Background('image.png', [0,0])
# Game Loop
running = True
while running:
# screen.fill((0, 0, 0))
# screen.blit(BackGround.image, BackGround.rect)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
#screen.fill((0, 0, 0)) # unnecessary because of the background image
screen.blit(BackGround.image, BackGround.rect)
pygame.display.flip()
Note, the main application loop has to:
handle the events
clear the display or blit the backgrond image
draw the scene
update the display
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
I am trying to build a game in which combining images (pygame sprites) is an essential tool.
I have set up my code such that I can move sprites across x,y with the mouse and rotate them. The sprites are blitted to the display surface and so this motion can be seen on screen.
Once the user has arranged two sprites as they wish within a square zone, I need them to be able to save this whole zone as a new sprite.
I cannot see a way currently on pygame to capture a region of the display and store this as a sprite. Is this possible? What functions should I use for this purpose?
You could check which sprites collide with the square area and pass them to a Combined sprite class, combine the rects with the union_ip method and create a new surface with the necessary size to blit the surfaces of the single sprites onto it. (Press C to combine the sprites.)
import pygame as pg
BLUE = pg.Color('dodgerblue1')
SIENNA = pg.Color('sienna1')
GREEN = pg.Color('green')
class Entity(pg.sprite.Sprite):
def __init__(self, pos, color):
super().__init__()
self.image = pg.Surface((42, 68))
self.image.fill(color)
self.rect = self.image.get_rect(topleft=pos)
def move(self, velocity):
self.rect.move_ip(velocity)
class Combined(pg.sprite.Sprite):
def __init__(self, sprites):
super().__init__()
# Combine the rects of the separate sprites.
self.rect = sprites[0].rect.copy()
for sprite in sprites[1:]:
self.rect.union_ip(sprite.rect)
# Create a new transparent image with the combined size.
self.image = pg.Surface(self.rect.size, pg.SRCALPHA)
# Now blit all sprites onto the new surface.
for sprite in sprites:
self.image.blit(sprite.image, (sprite.rect.x-self.rect.left,
sprite.rect.y-self.rect.top))
def move(self, velocity):
self.rect.move_ip(velocity)
def main():
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
entity = Entity((50, 80), BLUE)
entity2 = Entity((50, 180), SIENNA)
all_sprites = pg.sprite.Group(entity, entity2)
area = pg.Rect(200, 50, 200, 200)
selected = None
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
return
elif event.type == pg.MOUSEBUTTONDOWN:
for sprite in all_sprites:
if sprite.rect.collidepoint(event.pos):
selected = sprite
elif event.type == pg.MOUSEBUTTONUP:
selected = None
elif event.type == pg.MOUSEMOTION:
if selected:
selected.move(event.rel)
elif event.type == pg.KEYDOWN:
if event.key == pg.K_c:
# A 'list comprehension' to find the colliding sprites.
colliding_sprites = [sprite for sprite in all_sprites
if sprite.rect.colliderect(area)]
combined = Combined(colliding_sprites)
all_sprites.add(combined)
# Kill the colliding sprites if they should be removed.
# for sprite in colliding_sprites:
# sprite.kill()
all_sprites.update()
screen.fill((30, 30, 30))
pg.draw.rect(screen, SIENNA, area, 2)
all_sprites.draw(screen)
for sprite in all_sprites: # Outlines.
pg.draw.rect(screen, GREEN, sprite.rect, 1)
pg.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
pg.quit()
Alternatively, you could try to add the combined sprites to another sprite group or a list and blit and move them together.
I am attempting to use pygame to draw a map to a screen, but cannot understand why it won't. I'm not getting a traceback. The screen is initializing, then the image is not being drawn. I've attempted with other .bmp images with the same result, so there must be something in my code that is not ordered/written correctly.
Here is the main module of the game:
import pygame
import sys
from board import Board
def run_game():
#Launch the screen.
screen_size = (1200, 700)
screen = pygame.display.set_mode(screen_size)
pygame.display.set_caption('Horde')
#Draw the board.
game_board = Board(screen)
game_board.blit_board()
#Body of the game.
flag = True
while flag == True:
game_board.update_board()
run_game()
Here is the board module that you see being used. Specifically, the blit_board() function, which is silently failing to draw the map.bmp file I ask it to (file is in the same directory).
import pygame
import sys
class Board():
def __init__(self, screen):
"""Initialize the board and set its starting position"""
self.screen = screen
#Load the board image and get its rect.
self.image = pygame.image.load('coll.bmp')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
#Start the board image at the center of the screen.
self.rect.centerx = self.screen_rect.centerx
self.rect.centery = self.screen_rect.centery
def blit_board(self):
"""Draw the board on the screen."""
self.screen.blit(self.image, self.rect)
def update_board(self):
"""Updates the map, however and whenever needed."""
#Listens for the user to click the 'x' to exit.
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
#Re-draws the map.
self.blit_board()
All I get is a black screen. Why will the map.bmp image not draw?
As Dan MaĊĦek stated you need to tell PyGame to update the display after drawing the image.
To achieve this simply modify your 'board' loop to the following:
def update_board(self):
"""Updates the map, however and whenever needed."""
#Listens for the user to click the 'x' to exit.
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
#Re-draws the map.
self.blit_board()
pygame.display.update()