Trying to use OOP for bouncing ball in pong game - python

So recently I got into OOP, which is a very new topic for me, and I had already made a pong game that did not employ objects and I'm thinking of doing a new script with objects utilised. The problem is, when I run the code, it displays an empty screen and I'm not sure what I did wrong (I'm still new to OOP). Can anyone help out?
import pygame
class Ball():
def __init__(self, x, y, xmove, ymove, color, size):
self.x = 0
self.y = 0
self.xmove = 0
self.ymove = 0
self.color = (255, 255, 255)
self.size = 10
def draw(self, screen):
pygame.draw.circle(screen, self.color, [self.x, self.y], self.size)
def ballmove(self):
self.x += self.xmove
self.y += self.ymove
done = False
pygame.init()
WIDTH = 640
HEIGHT = 480
clock = pygame.time.Clock()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
ball = Ball(0, 0, 1.5, 1.5, [255, 255, 255], 10)
while done != False:
screen.fill(0)
ball.ballmove()
ball.draw(screen)
pygame.display.update()

I think you used a wrong condtion in your loop. It should mean while done == False: or while done != True:
Also your constructor is wrong. The parameter you give to the ball will never set, because you initialized all paramters with default values. Use this constructor instead
def __init__(self, x, y, xmove, ymove, color, size):
self.x = x
self.y = y
self.xmove = xmove
self.ymove = ymove
self.color = color
self.size = size

Related

Top left corner of my pygame screen does not update correctly, but everything else works fine [duplicate]

This question already has answers here:
How to draw images and sprites in pygame?
(4 answers)
Replace a rectangle with an Image in Pygame
(1 answer)
Closed 3 months ago.
Here is my code for the beginnings of a pong game:
import pygame
from random import (uniform, choice)
pygame.init()
from pygame.locals import (
K_UP,
K_DOWN,
K_s,
K_w,
QUIT
)
class Ball(pygame.sprite.Sprite):
def __init__(self, color, left, top):
pygame.sprite.Sprite.__init__(self)
radius = 20
self.surface = pygame.Surface((radius * 2, radius * 2))
self.surface.set_colorkey([255, 0, 255])
self.surface.fill([255, 0, 255])
self.rect = pygame.draw.circle(self.surface, color, (radius, radius), radius)
self.old_rect = None
self.rect.x = left - radius
self.rect.y = top - radius
self.x_vel = None
self.y_vel = None
self.x_pos = self.rect.left
self.y_pos = self.rect.top
def start(self):
signs = [-1, 1]
self.x_vel = .1 * choice(signs)
self.y_vel = uniform(-.1, .1)
def move(self, screen):
screen.blit(self.surface, self.rect, self.rect)
self.x_pos += self.x_vel
self.y_pos += self.y_vel
self.old_rect = self.rect.copy()
self.rect.topleft = self.x_pos, self.y_pos
screen.blit(self.surface, self.rect)
class Paddle(pygame.sprite.Sprite):
def __init__(self, color, left, top):
pygame.sprite.Sprite.__init__(self)
width, height = 40, 120
self.surface = pygame.Surface((width, height))
self.surface.fill(color)
self.rect = self.surface.get_rect()
self.old_rect = None
self.rect.update(left, top, width, height)
self.y_pos = self.rect.top
def move(self, pressed_keys, keys, screen):
dy = 0
screen.blit(self.surface, self.rect, self.rect)
l_bound, u_bound = 5, 750 - self.rect.height - 5
if pressed_keys[keys[0]] and self.rect.top > l_bound:
dy = -.2
if pressed_keys[keys[1]] and self.rect.top < u_bound:
dy = .2
self.y_pos += dy
self.old_rect = self.rect.copy()
self.rect.top = self.y_pos
screen.blit(self.surface, self.rect)
class Main:
def __init__(self):
self.height, self.width = 750, 1000
self.screen = pygame.display.set_mode((self.width, self.height))
pygame.display.set_caption("pong")
self.loop()
def loop(self):
blue = [0, 0, 255]
red = [255, 0, 0]
paddle1 = Paddle(blue, 30, self.height // 2)
paddle2 = Paddle(blue, 930, self.height // 2)
ball = Ball(red, self.width // 2, self.height // 2)
running = True
start = True
while running:
self.screen.fill([0, 0, 0])
for event in pygame.event.get():
if event.type == QUIT:
running = False
pressed_keys = pygame.key.get_pressed()
if start:
ball.start()
start = False
paddle1.move(pressed_keys, [K_w, K_s], self.screen)
paddle2.move(pressed_keys, [K_UP, K_DOWN], self.screen)
ball.move(self.screen)
pygame.display.update([paddle1.rect,
paddle1.old_rect,
paddle2.rect,
paddle2.old_rect,
ball.rect,
ball.old_rect])
pygame.quit()
Main()
You should see what I mean if you test it out - Basically any sprite that interacts with the top left corner of the screen (the left paddle and potentially the ball) does not fully update after leaving the top left corner of the screen and leaves behind some residual part of its surface.
I assume this has something to do with the fact that I'm updating the position of the rects using the top left corner, see this line as one example of this:
self.rect.topleft = self.x_pos, self.y_pos
But I can't think of why that would be an issue.
Edit: Also I know that just calling update without any arguments technically solves the problem, but I want to keep my code optimized and only update what needs to be updated.
Edit 2: Someone was kind enough to test my code on their Windows machine and it worked for them without issue. So I think the problem is likely OS related (I'm on linux). If anyone with a linux box wants to see if they can replicate my issue I'd appreciate it!

Python3 Pygame: Tuple Type Error for draw.circle

I'm a beginner, so please excuse me if the information given might be incomplete.
I'm trying to draw a circle with pygame by calling the display method of my "Particle" object; I need the object since I'll be creating many of them. The error I get ("TypeError: an integer is required (got type tuple)") refers to the line "pygame.draw.circle".
Since I am really at my wits end I've included the complete code below.
Code:
import pygame, sys
pygame.init()
# COLORS
BLACK = (0,0,0)
WHITE = (255,255,255)
# SCREEN
scr_width = 1400
scr_height = 600
scr_bckgr_color = WHITE
screen = pygame.display.set_mode((scr_width,scr_height))
pygame.display.set_caption("Animation")
screen.fill(scr_bckgr_color)
#PARTICLE CLASS
class Particle:
def __init__(self, position, radius, color):
self.x = position[0],
self.y = position[1],
self.radius = radius,
self.color = color,
self.thickness = 0
def display(self):
pygame.draw.circle(screen, self.color, (self.x, self.y), self.radius, self.thickness)
# DRAW PARTICLES
Particle1 = Particle((200, 200), 15, BLACK)
Particle1.display()
#pygame.draw.circle(screen, BLACK, (200,200), 15, 0)
pygame.display.flip()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
You need to Remove the , at the end of the lines:
self.x = position[0],
self.y = position[1],
self.radius = radius,
self.color = color,
When you put a , at the end of a line a tuple object is constructed. Tupels are not formed by the comma operator. See Python - 5.3. Tuples and Sequences.
Remove the commas to fix your code:
class Particle:
def __init__(self, position, radius, color):
self.x = position[0]
self.y = position[1]
self.radius = radius
self.color = color
self.thickness = 0

Why doesn't this code produce shapes with random colors?

I'm working from the book "Program Arcade Games
With Python And Pygame" and working through the 'lab' at the end of Chapter 12: Introduction to Classes.
This code I've written for it randomises the coordinates size and movement direction for each shape created in 'my_list' by calling its constructor but not the colour, all the shapes created have the same colour, why is this?
import pygame
import random
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
class Rectangle():
x = 0
y = 0
width = 10
height = 10
change_x = 2
change_y = 2
color = [0, 0, 0]
def __init__(self):
self.x = random.randrange(0, 700)
self.y = random.randrange(0, 500)
self.change_x = random.randrange(-3., 3)
self.change_y = random.randrange(-3., 3)
self.width = random.randrange(20, 70)
self.height = random.randrange(20, 70)
for i in range(3):
self.color[i] = random.randrange(0, 256)
def draw(self, screen):
pygame.draw.rect(screen, self.color, [self.x, self.y, self.width, self.height], 0)
def move(self):
if self.x < 0:
self.change_x *= -1
if self.x > 700-self.width:
self.change_x *= -1
if self.y < 0:
self.change_y *= -1
if self.y > 500-self.height:
self.change_y *= -1
self.x += self.change_x
self.y += self.change_y
class Ellipse(Rectangle):
def draw(self, screen):
pygame.draw.ellipse(screen, self.color, [self.x, self.y, self.width, self.height], 0)
pygame.init()
# Set the width and height of the screen [width, height]
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
my_list = []
for i in range(10):
my_list.append(Rectangle())
for i in range(10):
my_list.append(Ellipse())
# -------- Main Program Loop -----------
while not done:
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# --- Game logic should go here
# --- Screen-clearing code goes here
# Here, we clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
# If you want a background image, replace this clear with blit'ing the
# background image.
screen.fill(WHITE)
# --- Drawing code should go here
for shape in my_list:
shape.draw(screen)
shape.move()
# --- Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# --- Limit to 60 frames per second
clock.tick(60)
# Close the window and quit.
pygame.quit()```
The instance attribute self.color is never created. The existing variable color is a class attribute. Read about the difference of Class and Instance Variables. A class attribute exists only once and (of course) has the same value in each instance when it is read. An instance variable exists per instance of the class and can have a different value in each instance.
Create the list of color channels by:
class Rectangle():
def __init__(self):
# [...]
self.color = [0, 0, 0]
for i in range(3):
self.color[i] = random.randrange(0, 256)
respectively
class Rectangle():
def __init__(self):
# [...]
self.color = [random.randrange(0, 256) for _ in range(3)]

I can't reduce the amount of rain drops falling from the ceiling

I have been making this game in which you are this block that has to dodge bullets, so I added this code that I found in the book that I have called "Python Hunting" this code allowed me to create my bullets class and add the bullets to the game. But I have been having trouble, the code works pretty well and I only have to include death for the player and a mini menu at the start, but I can't do it because there are way too many bullets and I want to fix that before doing anything else.
So I've found a way to reduce these bullets, but not enough, it's on line 58 (with the '''for i in range(1):''') and it allowed me to reduced them by a third, I tried using floats but it doesn't work. It still creates too many bullets. I also tried reducing the speed of the '''while''' loop, but sure enough it created less at a time but it also slowed them down and even made them really laggy it's horrible. So I don't know what to do.
Right here is the code I used. Sorry but I put everything in it because I didn't know what was important and what wasn't and so I thought I would play safe and put it all in. I put comments on sections of which object the program affects.
'''
import pygame, time, random, sys
from pygame.locals import *
pygame.init()
clock = pygame.time.Clock()
pygame.display.set_caption("Dodge the bullet")
screen = pygame.display.set_mode((800, 600))
screen.fill((0, 0, 0))
font = pygame.font.Font(None, 54)
font_color = pygame.Color('springgreen')
class Bullets:
def __init__(self, x, y):
self.x = x
self.y = y
self.speed = 8
def move(self):
self.y += self.speed
def draw(self):
pygame.draw.line(screen, (255, 255, 255), (self.x, self.y), (self.x,self.y+5), 3)
def off_screen(self):
return self.y > 800
class Player():
def __init__(self):
self.x = 380
self.y = 535
self.speed = 5
def moveRight(self):
self.x = self.x + self.speed
def moveLeft(self):
self.x = self.x - self.speed
def moveUp(self):
self.y = self.y - self.speed
def moveDown(self):
self.y = self.y + self.speed
def draw(self):
pygame.draw.rect(screen, (255, 255, 255), [self.x, self.y, 20, 20])
def hit_by(self, bullet):
return pygame.Rect(self.x, self.y, 20, 20).collidepoint((bullet.x, bullet.y))
class Top():
def __init__(self):
self.x = 0
self.y = 0
def rain(self):
for i in range(1):
bullets.append(Bullets(random.randint(self.x, self.x+800), self.y))
def draw(self):
pygame.draw.rect(screen, (255, 255, 255), [self.x, self.y, 1, 600])
player = Player()
bullets = []
top = Top()
passed_time = 0
timer_started = False
done = False
while 1:
clock.tick(60)
pressed_keys = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
screen.fill((0, 0, 0))
#Player
player.draw()
if pressed_keys[K_RIGHT]:
player.moveRight()
if pressed_keys[K_LEFT]:
player.moveLeft()
if pressed_keys[K_UP]:
player.moveUp()
if pressed_keys[K_DOWN]:
player.moveDown()
#Timer
if pressed_keys[K_SPACE]:
timer_started = not timer_started
if timer_started:
start_time = pygame.time.get_ticks()
if timer_started:
passed_time = pygame.time.get_ticks() - start_time
text = font.render(str(passed_time/1000), True, font_color)
screen.blit(text, (50, 50))
#Top
top.draw()
top.rain()
#Bullets
#bullets.append(Bullets())
i = 0
while i < len(bullets):
bullets[i].move()
bullets[i].draw()
flag = False
if bullets[i].off_screen():
flag = True
if player.hit_by(bullets[i]):
flag = True
last_hit_time = time.time()
if flag == True:
del bullets[i]
i -= 1
i+= 1
pygame.display.update()
pygame.quit()
'''
I expected something that would reduce the amount of bullets by a fair amount but I don't know whether that is possible or not. As you might see there are too many bullets for the player to dodge.
Thanks a lot in advance,
Hope to here from you guys/girls soon.
Add a .count attribute to the class Top. Increment the counter in the method rain. Only spawn Bullet objects, when the counter exceeds a certain limit:
e.g.
class Top():
def __init__(self):
self.x = 0
self.y = 0
self.count = 0
def rain(self):
self.count += 1
if self.count == 3:
self.count = 0
bullets.append(Bullets(random.randint(self.x, self.x+800), self.y))

How to display health for character in pygame

I am attempting to draw a health bar for a character in pygame. I am getting an error saying name 'draw_shield_bar' is not defined. I have tried player.draw_shield_bar and still doesn't work. Can someone help with the notation. Below I have included the code which calls the function and then the player class which defines that function. Help would be appreciated.
def draw(self):
# Game Loop - draw
whitehouse = pg.image.load("whiteHouseBG.png")
self.screen.blit(whitehouse,(0,0))
self.all_sprites.draw(self.screen)
self.draw_text(str(self.score), 22, WHITE, WIDTH / 2, 15)
draw_shield_bar(self.screen, 50, 50, player.shield)
# *after* drawing everything, flip the display
pg.display.flip()
class Player(pg.sprite.Sprite):
def __init__(self, game):
pg.sprite.Sprite.__init__(self)
self.game = game
self.walking = False
self.jumping = False
self.current_frame = 0
self.last_update = 0
self.load_images()
#me:girl standing
self.image = self.girl_standing[0]
self.rect = self.image.get_rect()
self.rect.center = (WIDTH / 2, HEIGHT/2)
self.pos = vec(WIDTH/2, HEIGHT*3/4)
self.vel = vec(0, 0)
self.acc = vec(0, 0)
self.shield = 100
self.screen = pg.display.set_mode((WIDTH, HEIGHT))
self.clock = pg.time.Clock()
def draw_shield_bar(surf, x, y, pct):
if pct < 0:
pct = 0
BAR_LENGTH = 200
BAR_HEIGHT = 20
fill = (pct/100 * BAR_LENGTH)
outline_rect = pg.Rect(x, y, BAR_LENGTH, BAR_HEIGHT)
fill_rect = pg.Rect(x, y, fill, BAR_HEIGHT)
pg.draw.rect(surf, GREEN, fill_rect)
pg.draw.rect(surf, WHITE, outline_rect, 2)
Assuming player is an instance of the Player class, using player.draw_shield_baris correct. The reason it fails, is probably because you forgot to use self as the first argument of the draw_shield_bar method. It should be:
def draw_shield_bar(self, surf, x, y, pct):
If this doesn't work. I'd like to see the full Traceback.

Categories