I am trying to make a replica for pong in pygame for my first project but when I try to move my paddles they stretch instead. I believe the reason is it creates a new rect every time I try to move it but I can't seem to figure out why. Please review the code and help rectify my mistake.
Here is my code:
import pygame
W, H = 600, 500
screen = pygame.display.set_mode((W, H))
FPS = 30
class Paddle(pygame.sprite.Sprite):
def __init__(self, x, y, width, height):
super(Paddle, self).__init__()
self.x = x
self.y = y
self.width = width
self.height = height
self.surf = pygame.Surface((width, height))
self.surf.fill((255, 255, 255))
self.rect = self.surf.get_rect()
self.rect.center = (x, y)
def move(self, distance):
self.rect.move_ip(0, distance)
paddleA = Paddle(15, 250, 10, 50)
paddleB = Paddle(585, 250, 10, 50)
allSprites = pygame.sprite.Group()
allSprites.add(paddleA)
allSprites.add(paddleB)
run = True
clock = pygame.time.Clock()
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
pressedKeys = pygame.key.get_pressed()
if pressedKeys[pygame.K_UP]:
paddleB.move(-5)
elif pressedKeys[pygame.K_DOWN]:
paddleB.move(5)
elif pressedKeys[pygame.K_w]:
paddleA.move(-5)
elif pressedKeys[pygame.K_s]:
paddleA.move(5)
for sprite in allSprites:
screen.blit(sprite.surf, sprite.rect)
pygame.display.update()
clock.tick(FPS)
pygame.quit()
quit()
Before drawing the new rect you should fill the screen with the background color, to remove the old rect. Otherwise the old one is still drawn there and you are just drawing new over the old one. Its' like painting a new picture on an old one.
screen.fill(color, rect) should do the trick.
Related
I am making a flappy bird clone game, using pygame. I want to draw pillars by using Sprite.draw. I made a Pillar class and initialized it with two rectangles p_upper and p_lower on the left side of the screen, coming towards the right side with the help of the update function of the sprite. But the screen is only showing the p_lower pillar. Can anyone help?
class Pillar(pygame.sprite.Sprite):
# the "h" parameter is height of upper pillar upto gap
# "w" is the width of the pillar
# pillar is coming from left to right
def __init__(self, w, h, gap):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((w, h))
self.image.fill(green)
self.p_upper = self.rect = self.image.get_rect()
self.p_upper.topleft = (-w, 0)
self.image = pygame.Surface((w, HEIGHT - (h + gap)))
self.image.fill(green)
self.p_lower = self.rect = self.image.get_rect()
self.p_lower.topleft = (-w, h + gap)
def update(self):
self.p_upper.x += 1
self.p_lower.x += 1
Because of the following two lines:
self.p_upper = self.rect = self.image.get_rect()
and...
self.p_lower = self.rect = self.image.get_rect()
These are both grabbing the same reference to the self.rect. The first line runs and assigns the rect reference to p_upper. Then the same reference is assigned to p_lower. Because it's the same reference, when you update the location of the lower rectangle, you're actually updating both.
Using a sprite that consists of two rects and images isn't a good solution for this problem. I suggest to create two separate sprites with their own image and rect. To create two sprite instances at the same time and to add them to a sprite group, you can write a short function as you can see in this example:
import pygame as pg
from pygame.math import Vector2
green = pg.Color('green')
HEIGHT = 480
class Pillar(pg.sprite.Sprite):
def __init__(self, x, y, w, h):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((w, h))
self.image.fill(green)
self.rect = self.image.get_rect(topleft=(x, y))
def update(self):
self.rect.x += 1
def create_pillars(w, h, gap, sprite_group):
sprite_group.add(Pillar(0, 0, w, h-gap))
sprite_group.add(Pillar(0, HEIGHT-(h+gap), w, h+gap))
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
create_pillars(50, 170, 0, all_sprites)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_a:
create_pillars(50, 170, 15, all_sprites)
elif event.key == pg.K_s:
create_pillars(50, 170, 30, all_sprites)
elif event.key == pg.K_d:
create_pillars(50, 100, -60, all_sprites)
all_sprites.update()
screen.fill((30, 30, 30))
all_sprites.draw(screen)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
I am trying to make objects fall like they would on earth. I already got them to blit where I wanted them to but I can't seem to animate them.
This is the object that I want to fall
import pygame
class circle():
def __init__(self, screen):
planet_color = (255,0,0)
planet_radius = 20
self.screen = screen
ev = pygame.event.get()
self.image = pygame.image.load('../images/jupiter.bmp')
self.image = pygame.transform.scale(self.image, (80, 80))
def blitme(self):
self.x = pygame.mouse.get_pos()
self.rect = self.image.get_rect()
self.rect.center = self.x
self.screen.blit(self.image, self.rect)
And this is the code that runs it. When the mouse is clicked a little picture of Jupiter is made where the mouse was clicked. How do I get this image to fall?
import pygame
import gravfunc as gf
from gravfunc import circle
import sys
def run_game():
screen_height = 670
screen_width = 1270
pygame.init()
screen = pygame.display.set_mode((screen_width, screen_height))
screen.fill((10,10,30))
running = True
circ = circle(screen)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
circ.blitme()
pygame.display.flip()
run_game()
Give your class a self.speed_y attribute and add the GRAVITY to it each frame to accelerate the object. I've also added a self.pos_y attribute because pygame.Rects can't have floating point numbers as their coordinates. So,
increase the speed
add the speed to the position (self.pos_y)
assign the self.pos_y to self.rect.y.
Since you are already using a class, I recommend to make it a pygame sprite subclass (inherit from pygame.sprite.Sprite). Then you can add all circles to a pygame.sprite.Group and update and draw them by calling sprite_group.update() and sprite_grop.draw(screen).
import pygame
GRAVITY = .2 # Pretty low gravity.
class Circle(pygame.sprite.Sprite):
def __init__(self, pos, screen):
super().__init__()
self.screen = screen
self.image = pygame.Surface((80, 80), pygame.SRCALPHA)
pygame.draw.circle(self.image, (30, 90, 150), (40, 40), 40)
self.rect = self.image.get_rect(center=pos)
self.pos_y = pos[1]
self.speed_y = 0
def update(self):
self.speed_y += GRAVITY
self.pos_y += self.speed_y
self.rect.y = self.pos_y
if self.pos_y > self.screen.get_height():
self.kill() # Remove off-screen circles.
def run_game():
pygame.init()
screen = pygame.display.set_mode((1270, 670))
clock = pygame.time.Clock()
running = True
circles = pygame.sprite.Group(Circle((600, 0), screen))
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
elif event.type == pygame.MOUSEBUTTONDOWN:
circles.add(Circle(event.pos, screen))
circles.update()
screen.fill((10, 10, 30))
circles.draw(screen)
pygame.display.flip()
clock.tick(60)
run_game()
pygame.quit()
I am new to Python Game Development and I am trying to learn by following the tutorial on Youtube by FreeCodeCamp but not getting the expected output. When I run the program the window opens but displays a black screen with no output.
Tried to include pygame.init() and pygame.display.init() but that didn't work either.
import pygame
width = 500
height = 500
win = pygame.display.set_mode((width, height))
pygame.display.set_caption("Client")
client_number = 0
class Player():
def __init__(self, x, y, width, height, color):
self.x = x
self.y = y
self.height = height
self.width = width
self.color = color
self.rect = (x, y, width, height)
self.vel = 3
def draw(self, win):
pygame.draw.rect(win, self.color, self.rect)
def move(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.x -= self.vel
if keys[pygame.K_RIGHT]:
self.x += self.vel
if keys[pygame.K_DOWN]:
self.y += self.vel
if keys[pygame.K_UP]:
self.y -= self.vel
self.rect = (self.x, self.y, self.width, self.height)
def redraw_Window(win, player):
win.fill((255, 255, 255))
player.draw(win)
pygame.display.update()
def main():
run = True
p = Player(50, 50, 100, 100, (0, 255, 0))
clock = pygame.time.Clock()
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
p.move()
redraw_Window(win, p)
main()
You've to respect the Indentation.
p.move() and redraw_Window(win, p) have to be in the scope of the main loop (in scope of while run:) rather than in scope of the function main main:
def main():
run = True
p = Player(50, 50, 100, 100, (0, 255, 0))
clock = pygame.time.Clock()
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
# ->>>
p.move()
redraw_Window(win, p)
main()
I am trying to make objects fall like they would on earth. I already got them to blit where I wanted them to but I can't seem to animate them.
This is the object that I want to fall
import pygame
class circle():
def __init__(self, screen):
planet_color = (255,0,0)
planet_radius = 20
self.screen = screen
ev = pygame.event.get()
self.image = pygame.image.load('../images/jupiter.bmp')
self.image = pygame.transform.scale(self.image, (80, 80))
def blitme(self):
self.x = pygame.mouse.get_pos()
self.rect = self.image.get_rect()
self.rect.center = self.x
self.screen.blit(self.image, self.rect)
And this is the code that runs it. When the mouse is clicked a little picture of Jupiter is made where the mouse was clicked. How do I get this image to fall?
import pygame
import gravfunc as gf
from gravfunc import circle
import sys
def run_game():
screen_height = 670
screen_width = 1270
pygame.init()
screen = pygame.display.set_mode((screen_width, screen_height))
screen.fill((10,10,30))
running = True
circ = circle(screen)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
circ.blitme()
pygame.display.flip()
run_game()
Give your class a self.speed_y attribute and add the GRAVITY to it each frame to accelerate the object. I've also added a self.pos_y attribute because pygame.Rects can't have floating point numbers as their coordinates. So,
increase the speed
add the speed to the position (self.pos_y)
assign the self.pos_y to self.rect.y.
Since you are already using a class, I recommend to make it a pygame sprite subclass (inherit from pygame.sprite.Sprite). Then you can add all circles to a pygame.sprite.Group and update and draw them by calling sprite_group.update() and sprite_grop.draw(screen).
import pygame
GRAVITY = .2 # Pretty low gravity.
class Circle(pygame.sprite.Sprite):
def __init__(self, pos, screen):
super().__init__()
self.screen = screen
self.image = pygame.Surface((80, 80), pygame.SRCALPHA)
pygame.draw.circle(self.image, (30, 90, 150), (40, 40), 40)
self.rect = self.image.get_rect(center=pos)
self.pos_y = pos[1]
self.speed_y = 0
def update(self):
self.speed_y += GRAVITY
self.pos_y += self.speed_y
self.rect.y = self.pos_y
if self.pos_y > self.screen.get_height():
self.kill() # Remove off-screen circles.
def run_game():
pygame.init()
screen = pygame.display.set_mode((1270, 670))
clock = pygame.time.Clock()
running = True
circles = pygame.sprite.Group(Circle((600, 0), screen))
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
elif event.type == pygame.MOUSEBUTTONDOWN:
circles.add(Circle(event.pos, screen))
circles.update()
screen.fill((10, 10, 30))
circles.draw(screen)
pygame.display.flip()
clock.tick(60)
run_game()
pygame.quit()
im relatively new to coding and after understanding some basics in python i'm trying to apply oop in pygame
I have this code and I can't figure out why the rectangle won't appear
import pygame
import time
pygame.init()
screen = pygame.display.set_mode((800,600))
pygame.display.set_caption("EXAMPLE")
clock = pygame.time.Clock()
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
FPS = 30
class Puddles(pygame.sprite.Sprite):
puddle_width = 100
puddle_height = 20
def __init__(self,color,x,y):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.color = color
self.image = pygame.Surface((Puddles.puddle_width,Puddles.puddle_height))
self.image.fill(self.color)
self.rect = self.image.get_rect()
self.rect.x = self.x # i think problem's here because if I type specific integers for x and y the tile will appear
self.rect.y = self.y
all_sprites = pygame.sprite.Group()
puddle1 = Puddles(red, 400, 600)
all_sprites.add(puddle1)
gameExit = False
while not gameExit:
clock.tick(FPS)
for event in pygame.event.get():
print event
if event.type == pygame.QUIT:
gameExit = True
all_sprites.update()
screen.fill(white)
all_sprites.draw(screen)
pygame.display.flip()
pygame.quit()
quit()
any ideas?
thanks in advance:)
puddle1 = Puddles(red, 400, 600)
The y position of the puddle is below the screen height, so it's outside of the screen. ;) Try to change it for example to puddle1 = Puddles(red, 400, 200).
Also, lines 43-46 should be indented, so that they're in the while loop.