I was following a pygame tutorial, tested to see if the player blit was working and it wasnt, checked for problems but there were none that I could find, and then I tested a .blit() directly in the game loop and that didnt work so I've been stumped for a good bit now.
player class below, "Player_Down" should be irrelevant rn since its just an image
class Player():
def __init__(self, x, y):
direction = "down"
self.image = player_down
self.rect = self.image.get_rect()
self.rect.center = (x, y)
def draw(self):
screen.blit(self.image, self.rect)
ply = Player(SCREEN_WIDTH // 2 , SCREEN_HEIGHT - 150)
Game loop with draw function called
running = True
while running:
screen.fill((83,90,83))
ply.draw()
#event handler
for event in pygame.event.get():
if event.type == pygame.QUIT:
print("Game quit via X button")
running = False
pygame.display.update()
There is no problem with the code in the question. Your suspicion that blit does not work is wrong (alos see How to draw images and sprites in pygame?). The code works fine.
However, I suggest passing the screen Surface as an argument to draw method. See the minimal and working example:
import pygame
pygame.init()
SCREEN_WIDTH, SCREEN_HEIGHT = 400, 400
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
player_down = pygame.Surface((30, 30))
player_down.fill((255, 0, 0))
class Player():
def __init__(self, x, y):
direction = "down"
self.image = player_down
self.rect = self.image.get_rect()
self.rect.center = (x, y)
def draw(self, surf):
surf.blit(self.image, self.rect)
ply = Player(SCREEN_WIDTH // 2 , SCREEN_HEIGHT - 150)
running = True
while running:
#event handler
for event in pygame.event.get():
if event.type == pygame.QUIT:
print("Game quit via X button")
running = False
screen.fill((83,90,83))
ply.draw(screen)
pygame.display.update()
pygame.quit()
exit()
Related
I'm trying to learn OOP but my pygame window wont update with the background I'm trying to put in. The gameObject class is in another file. Filling it with white color also isn't working and I don't know why. I was able to display a background on another project I did but I cant now and I have no idea what's different. I have compared the code and they seem like they should be doing the same thing.
gameObject.py
import pygame
class GameObject:
def __init__(self, x, y, width, height, image_path):
self.background= pygame.image.load(image_path)
self.background = pygame.transform.scale(self.background, (width, height))
self.x = x
self.y = y
self.width = width
self.height = height
main.py
import pygame
from gameObject import GameObject
pygame.init()
class Player(GameObject):
def __init__(self, x, y, width, height, image_path, speed):
super().__init__(x, y, width, height, image_path)
self.speed = speed
def move(self, direction, max_height):
if (self.y >= max_height - self.height and direction > 0) or (self.y <= 0 and direction < 0):
return
self.y += (direction * self.speed)
class Game:
def __init__(self):
self.width = 800
self.height = 800
self.color = (255, 255, 255)
self.game_window = pygame.display.set_mode((self.width, self.height))
self.clock = pygame.time.Clock()
self.background = GameObject(0, 0, self.width, self.height, 'assets/background.png')
self.player1 = Player(375, 700, 50, 50, 'assets/player.png', 10)
self.level = 1.0
def draw_objects(self):
self.game_window.fill(self.white_color)
self.game_window.blit(self.background.image, (self.background.x, self.background.y))
pygame.display.update()
def run_game_loop(self):
gameRunning = True
while gameRunning:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameRunning = False
if gameRunning == False:
pygame.quit()
self.draw_objects()
self.clock.tick(60)
game = Game()
game.run_game_loop()
quit()
I have tried basic research on it and looking at other code that uses a custom background with pygame
It is a matter of indentation. self.draw_objects() must be called in the application loop not after the application loop:
class Game:
# [...]
def run_game_loop(self):
gameRunning = True
while gameRunning:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameRunning = False
if gameRunning == False:
pygame.quit()
# INDENTATION
#-->|
self.draw_objects()
self.clock.tick(60)
Your loop never actually does anything but clear the event queue looking for pygame.QUIT.
You need to indent the calls to self.draw_objects() and self.clock.tick(60) so they are inside the loop.
So I've been trying to make a game and the TypeError: invalid destination position for blit error popped up, I have no idea how to solve it.
Here's the problematic code:
import pygame, sys
pygame.init()
# screen settings
screen_width = 1000
screen_height = 800
screen = pygame.display.set_mode((screen_width, screen_height))
class Player(pygame.sprite.Sprite):
"""
player character
"""
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.x = screen_width / 2
self.y = screen_height / 2
self.image = pygame.image.load('img/player.png').convert_alpha()
self.rect = self.image.get_rect
player = Player()
player_list = pygame.sprite.Group()
player_list.add(player)
# game loop
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
player_list.draw(screen) # traceback thinks this is where the error is
pygame.display.flip()
pygame.display.update()
The code example in here isn't actually the game code, but just the part related to my problem.
I'd appreciate some help.
The problem with your code was not the player_list.draw, rather is was the pygame.display.update() messing up your code.
the other problem was the self.rect = self.image.get_rect, it should be self.rect= self.image.get_rect()
and just for future work, you should add an update function to your player class with player_list.update inside your while loop!
#fixed code
import pygame, sys
pygame.init()
# screen settings
screen_width = 1000
screen_height = 800
screen = pygame.display.set_mode((screen_width, screen_height))
class Player(pygame.sprite.Sprite):
"""player"""
def __init__(self, window):
pygame.sprite.Sprite.__init__(self)
self.window = window
self.x = screen_width / 2
self.y = screen_height / 2
self.image = pygame.image.load('sprites/NewGumbo.png').convert_alpha()
self.rect = self.image.get_rect()
player = Player(screen)
player_list = pygame.sprite.Group()
player_list.add(player)
# game loop
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
player_list.draw(screen) # traceback thinks this is where the error is
player_list.update()
pygame.display.flip()
My friend made most of this and I was going to do the movement part and everywhere I place it, I get the same:
TypeError for "'builtin_function_or_method' object is not subscriptable"
import pygame
WIDTH = 800
HEIGHT = 600
BACKGROUND = (0, 0, 0)
screen = pygame.display.set_mode ((600, 400))
class Player:
def __init__(self):
self.image = pygame.image.load("Player.png")
self.rect = self.image.get_rect()
def main():
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
player = Player()
while True:
screen.fill(BACKGROUND)
screen.blit(player.image, player.rect)
pygame.display.flip()
clock.tick(60)
if pygame.key.get_pressed [pygame.K_w]:
Player.y +=5
if pygame.key.get_pressed [pygame.K_s]:
Player.y -=5
if __name__ == "__main__":
main()
pygame.QUIT()
quit()
pygame.key.get_pressed is a function! Call the function in the application loop. Use the subscription with the return value:
You have to handle the events in the application loop. See pygame.event.get() respectively pygame.event.pump().
For each frame of your game, you will need to make some sort of call to the event queue. This ensures your program can internally interact with the rest of the operating system.
import pygame
WIDTH, HEIGHT = 800, 600
BACKGROUND = (0, 0, 0)
screen = pygame.display.set_mode ((600, 400))
class Player:
def __init__(self):
self.image = pygame.image.load("Player.png").convert_alpha()
self.rect = self.image.get_rect()
def main():
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
player = Player()
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
screen.fill(BACKGROUND)
screen.blit(player.image, player.rect)
pygame.display.flip()
clock.tick(60)
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
player.rect.y -=5
if keys[pygame.K_s]:
player.rect.y +=5
if __name__ == "__main__":
main()
pygame.quit()
quit()
See also How can I make a sprite move when key is held down.
I am trying to get this square to go across my screen and back along the path it came by but it just stays where it is. It's a clash between two if statements and I have tried using a break statement but that just stopped everything.
if squareX < 100:
squareX += 1
elif squareX > 900:
squareX -= 1
You have a state in your game, which describes in which directions your rect moves. So when you go out of screen, this state changes.
When you update your game (which is one of the three things you do in your main loop: handle events, update the game state, draw the game), you look at your state and decide in which direction you move your rect. Then you check if it's out of the screen.
Here's a minimal example:
import pygame
def main():
screen = pygame.display.set_mode((400, 200))
clock = pygame.time.Clock()
rect = pygame.Rect(100, 100, 32, 32)
direction = 1
while True:
for e in pygame.event.get():
if e.type == pygame.QUIT:
return
rect.move_ip(direction * 3, 0)
if not screen.get_rect().contains(rect):
direction *= -1
screen.fill((30, 30, 30))
pygame.draw.rect(screen, pygame.Color('dodgerblue'), rect)
clock.tick(120)
pygame.display.flip()
if __name__ == '__main__':
main()
easy, you first need to understand what a sprite class is.
follow the following code:
import pygame
class MovingSquare(pygame.sprite.Sprite):
def __init__(self, location, speed):
pygame.sprite.Sprite.__init__(self)
image_surface = pygame.surface.Surface([30, 30])
image_surface.fill([0,0,0])
self.image = image_surface.convert()
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
self.speed=speed
def move(self):
self.rect=self.rect.move(self.speed)
if self.rect.right>screen.get_width() or self.rect.left<0:
self.speed[0]=-self.speed[0]
pygame.init()
screen=pygame.display.set_mode([640, 480])
screen.fill([255, 255, 255])
x=5
y=0
squareX=MovingSquare([50, 50], [x, y])
clock=pygame.time.Clock()
running=True
while running:
clock.tick(30)
square.move()
screen.blit(squareX.image, squareX.rect)
pygame.display.flip()
for event in pygame.event.get():
if event.type==pygame.QUIT:
running=False
pygame.quit()
the only problem is that it doesn't erase it's tracks so i suggest using an image file instead.
I am currently trying to make a pygame version of flappy bird (way more complicated than I thought) and am stuck on making the pipes generate at random heights. Could anyone help me with this? To make this same animated I want to generate the pipes a little past the right of the screen and delete them a little past the left. When I run the current code the pipe images are on top of each other in the top left corner and don't move. (The bird works though)
import pygame, random, sys
pygame.init()
icon = pygame.image.load('flappybirdicon.png')
pygame.display.set_icon(icon)
screen = pygame.display.set_mode([284, 512])
pygame.display.set_caption("Flappy Bird")
bg = pygame.image.load('flappybirdbackground.png')
bgrect = bg.get_rect()
clock = pygame.time.Clock()
pipex = 335
class Bird(pygame.sprite.Sprite):
def __init__(self, image, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image)
self.rect = self.image.get_rect()
self.pos = [x, y]
class Pipe(pygame.sprite.Sprite):
def __init__(self, image, height):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image)
self.rect = self.image.get_rect()
self.height = height
self.pos = [pipex, height]
def scroll(self):
self.rect.move_ip(-3, 0)
self.pos[0] -= 3
self.rect.center = self.pos
def draw_pipes():
pipe1_height = random.randint(115, screen.get_height())
pipe1 = Pipe('flappybirdpipe.png', pipe1_height)
pipe2_height = 397 - pipe1_height
pipe2 = Pipe('flappybirdpipe2.png', pipe2_height)
screen.blit(pipe1.image, pipe1.rect)
screen.blit(pipe2.image, pipe2.rect)
bird = Bird('flappybirdbird.png', 142, 256)
draw_pipes()
while True:
clock.tick(30)
bird.pos[1] += 5
bird.rect.center = bird.pos
screen.blit(bg, bgrect)
pipe1.scroll()
pipe2.scroll()
screen.blit(bird.image, bird.rect)
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
bird.pos[1] -= 75
elif event.type == pygame.MOUSEBUTTONDOWN:
bird.pos[1] -= 75
I'm not familiar with PyGame, but it looks like you're not setting an X coordinate for your pipes anywhere. You're setting a height, but never a location.
It also looks like you're not saving the pipe data anywhere, so I imagine your code is also causing new pipes to be created/drawn every time draw_pipes() is called, which looks to be every frame.