I was working on a code to simulate multiple balls moving inside a box using pygame. I wrote the code for a single ball that collides with the walls of the container. I want to increase the number of balls as I want. I looked for help here and got a tutorial here: https://github.com/petercollingridge/code-for-blog/blob/master/pygame%20physics%20simulation/particle_tutorial_3.py
Here he uses class. But for now, I don't want to use a class to simulate this. Is there any other way? Please help me. I am new to python. This is my code:
import pygame
import time
import random
pygame.init()
display_width = 860
display_height = 540
black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
display_surface = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption("Simulation")
clock = pygame.time.Clock()
def draw_ball(ball_color, ballx, bally, ballr):
pygame.draw.ellipse(display_surface, ball_color, [int(ballx), int(bally), int(2 *ballr),int(2 * ballr)])
ball_radius = 7
ball_x_vel = 5
ball_y_vel = 5
ball_x_position=0.0
ball_y_position=0.0
number_of_balls=5
ball_x_position =ball_x_position+ random.randrange(0,display_width-2*ball_radius)
ball_y_position = ball_y_position+random.randrange(0,display_height-2*ball_radius)
display_exit = False
while not display_exit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if ball_x_position > display_width - 2 * ball_radius or ball_x_position < 0:
ball_x_vel *= -1
if ball_y_position > display_height - 2 * ball_radius or ball_y_position < 0:
ball_y_vel *= -1
ball_x_position += ball_x_vel
ball_y_position += ball_y_vel
display_surface.fill(white)
draw_ball(red, ball_x_position, ball_y_position, ball_radius)
pygame.display.update()
clock.tick(100)
pygame.quit()
quit()
I think I should use some kind of for loop to create multiple balls for random initial positions and then follow the same boundary conditions.
Edit: After the suggestions:
import pygame
import random
pygame.init()
display_width = 860
display_height = 540
black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)
display_surface = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption("Simulation")
clock = pygame.time.Clock()
def draw_ball(ball_color, ball_specs):
pygame.draw.ellipse(display_surface, ball_color, ball_specs)
ball_x_position = 0
ball_y_position = 0
ball_diameter = 10
number_of_balls = 10
def ball_show(number_of_balls):
for n in range(number_of_balls):
ball_x_position = random.randrange(0, display_width)
ball_y_position = random.randrange(0, display_height)
ball = [ball_x_position, ball_y_position, ball_diameter, ball_diameter]
draw_ball(red, ball)
display_exit = False
while not display_exit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
display_surface.fill(white)
ball_show(number_of_balls)
pygame.display.update()
clock.tick(100)
pygame.quit()
quit()
Related
I am trying to make a game where there are a bunch of falling circles and the player(the square) needs to avoid them. I have managed to get the controls of the player and all of the falling circles but when I press play all I see are the falling circles and no square. The only time the square shows is when I press the arrow keys. How can I make the square and circles show up at the same time?
import pygame
from pygame.locals import *
import os
import random
import math
import sys
import time
white = (255,255,255)
blue = (0,0,255)
gravity = 10
size =10
height = 500
width =600
varHeigth = height
ballNum = 5
eBall = []
apGame = pygame.display.set_mode((width, height))
pygame.display.set_caption("AP Project")
clock = pygame.time.Clock()
class Player(object):
def __init__(self):
red = (255, 0, 0)
move_x = 300
move_y = 400
self.rect = pygame.draw.rect(apGame,red, (move_x, move_y, 10, 10))
self.dist = 10
def handle_keys(self):
for e in pygame.event.get():
if e.type == pygame.QUIT:
pygame.quit();
exit()
elif e.type == pygame.KEYDOWN:
key = e.key
if key == pygame.K_LEFT:
self.draw_rect(-1, 0)
elif key == pygame.K_RIGHT:
self.draw_rect(1, 0)
elif key == pygame.K_ESCAPE:
pygame.quit();
exit()
def draw_rect(self, x, y):
red = (255, 0, 0)
black = (0, 0, 0)
'''apGame.fill(black)'''
self.rect = self.rect.move(x * self.dist, y * self.dist);
pygame.draw.rect(apGame, red , self.rect)
pygame.display.update()
def draw(self,surface):
red = (255, 0, 0)
move_x = 300
move_y = 400
pygame.draw.rect(apGame, red, (move_x, move_y, 10, 10))
move_x = 300
move_y = 400
red = (255, 0, 0)
black = (0, 0, 0)
player = Player()
clock = pygame.time.Clock()
'''apGame.fill(black)'''
player.draw(apGame)
pygame.display.update()
for q in range(ballNum):
x = random.randrange(0, width)
y = random.randrange(0, varHeigth)
eBall.append([x, y])
while True:
#I think this is where my problem is
apGame.fill(black)
player.handle_keys()
for i in range(len(eBall)):
pygame.draw.circle(apGame, blue, eBall[i], size)
eBall[i][1] += 5
if eBall[i][1] > height:
y = random.randrange(-50, -10)
eBall[i][1] = y
x = random.randrange(0, width)
eBall[i][0] = x
pygame.display.flip()
clock.tick(30)
If you insert a line :
player.draw_rect (0, 0)
just above
pygame.display.flip ()
then your square will show up.
I would recommend using :
pygame.key.get_pressed ()
instead of :
pygame.KEYDOWN
so that your player will keep moving as long as the key is being held down instead of having to press and release the left or right keys over and over.
Edit :
In response to OPs question in comments, here is working code :
import pygame
from pygame.locals import *
import random
white = (255,255,255)
blue = (0,0,255)
gravity = 10
size =10
height = 500
width =600
varHeigth = height
ballNum = 5
eBall = []
apGame = pygame.display.set_mode((width, height))
pygame.display.set_caption("AP Project")
clock = pygame.time.Clock()
class Player(object):
def __init__(self):
red = (255, 0, 0)
move_x = 300
move_y = 400
self.rect = pygame.draw.rect(apGame,red, (move_x, move_y, 10, 10))
self.dist = 10
def handle_keys(self):
for e in pygame.event.get():
if e.type == pygame.QUIT:
pygame.quit();
exit()
key = pygame.key.get_pressed ()
if key [pygame.K_LEFT]:
self.draw_rect(-1, 0)
elif key [pygame.K_RIGHT]:
self.draw_rect(1, 0)
elif key [pygame.K_ESCAPE]:
pygame.quit();
exit()
else :
self.draw_rect (0, 0)
def draw_rect(self, x, y):
red = (255, 0, 0)
black = (0, 0, 0)
self.rect = self.rect.move(x * self.dist, y * self.dist);
pygame.draw.rect(apGame, red , self.rect)
def draw(self,surface):
red = (255, 0, 0)
move_x = 300
move_y = 400
pygame.draw.rect(apGame, red, (move_x, move_y, 10, 10))
move_x = 300
move_y = 400
red = (255, 0, 0)
black = (0, 0, 0)
player = Player()
clock = pygame.time.Clock()
'''apGame.fill(black)'''
player.draw(apGame)
pygame.display.update()
for q in range(ballNum):
x = random.randrange(0, width)
y = random.randrange(0, varHeigth)
eBall.append([x, y])
while True:
apGame.fill(black)
for i in range(len(eBall)):
pygame.draw.circle(apGame, blue, eBall[i], size)
eBall[i][1] += 5
if eBall[i][1] > height:
y = random.randrange(-50, -10)
eBall[i][1] = y
x = random.randrange(0, width)
eBall[i][0] = x
player.handle_keys ()
pygame.display.flip()
clock.tick(30)
This question already has an answer here:
Why is my collision test always returning 'true' and why is the position of the rectangle of the image always wrong (0, 0)?
(1 answer)
Closed 2 years ago.
Alright so I am trying to just code a simple pong game in python using pygame module and I keep running into an attribute error. I know similar questions have been asked before but I can't figure out the answer from those questions. I'd appreciate any help at all :).
so, the error i am getting in my code is
File "D:/Dev/Documents/Projects/Pong/pong.py", line 81, in <module>
ball.x += ball_speed_x
AttributeError: 'pygame.Surface' object has no attribute 'x'
my code is
import pygame, sys
pygame.init()
clock = pygame.time.Clock()
screen_width = 1280
screen_height = 960
screen = pygame.display.set_mode((screen_width,screen_height))
pygame.display.set_caption('game')
background = pygame.image.load('bg.png')
white = (255, 255, 255)
green = (51, 255, 51)
ball = pygame.image.load('ball.png')
paddle1 = pygame.Rect(screen_width - int(20), screen_height/int(2) - int(70), int(10), int(140))
paddle2 = pygame.Rect(int(10), screen_height/int(2) - int(70), int(10), int(140))
basicfont = pygame.font.SysFont(None, 48)
text = basicfont.render('Pong Game', True, green)
textrect = text.get_rect()
textrect.centerx = screen.get_rect().centerx
ball_speed_x = 7
ball_speed_y = 7
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.fill(white)
screen.blit(background, (0, 0))
screen.blit(text, textrect)
pygame.draw.rect(screen, white, paddle1)
pygame.draw.rect(screen, white, paddle2)
pygame.draw.aaline(screen, green, (screen_width/2, 0), (screen_width/2, screen_height))
pygame.display.flip()
ball.x += ball_speed_x
ball.y += ball_speed_y
if ball.top <= 0 or ball.bottom >= screen_height:
ball_speed_y *= -1
if ball.left <= 0 or ball.right >= screen_width:
ball_speed_x *= -1
clock.tick(60)
Again, any help would be greatly appreciated and I am aware of other similar questions, I'm just new to this language and can't seem to figure this out. Thanks.
A pygame.Surface has no position. A Surface just contains the image.
If you want to draw the ball surface in the window, then you have to blit() the ball at a certain position.
You have to create a pygame.Surface and a pygame.Rect objecct:
ball = pygame.image.load('ball.png')
ball_rect = ball.get_rect(center = (screen_width // 2, screen_height // 2))
Then you can change the location of ball_rect and blit the ball to the screen Surface:
screen.blit(ball, ball_rect)
See the example:
import pygame, sys
pygame.init()
clock = pygame.time.Clock()
screen_width = 1280
screen_height = 960
screen = pygame.display.set_mode((screen_width,screen_height))
pygame.display.set_caption('game')
background = pygame.image.load('bg.png')
white = (255, 255, 255)
green = (51, 255, 51)
ball = pygame.image.load('ball.png')
ball_rect = ball.get_rect(center = (screen_width // 2, screen_height // 2))
paddle1 = pygame.Rect(screen_width - int(20), screen_height/int(2) - int(70), int(10), int(140))
paddle2 = pygame.Rect(int(10), screen_height/int(2) - int(70), int(10), int(140))
basicfont = pygame.font.SysFont(None, 48)
text = basicfont.render('Pong Game', True, green)
textrect = text.get_rect()
textrect.centerx = screen.get_rect().centerx
ball_speed_x = 7
ball_speed_y = 7
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.fill(white)
screen.blit(background, (0, 0))
screen.blit(text, textrect)
pygame.draw.rect(screen, white, paddle1)
pygame.draw.rect(screen, white, paddle2)
pygame.draw.aaline(screen, green, (screen_width/2, 0), (screen_width/2, screen_height))
screen.blit(ball, ball_rect)
pygame.display.flip()
ball_rect.x += ball_speed_x
ball_rect.y += ball_speed_y
if ball_rect.top <= 0 or ball_rect.bottom >= screen_height:
ball_speed_y *= -1
if ball_rect.left <= 0 or ball_rect.right >= screen_width:
ball_speed_x *= -1
clock.tick(60)
I'm using pygame.key.get_pressed() in my code in order to make a rectangle move up and down but when I let go of the key the rectangle continues moving. I'm wondering how to make the rectangle stop moving when the key is released.
import pygame, random, sys
from pygame.locals import *
fpsClock=pygame.time.Clock()
pygame.init()
WINDOWWIDTH = 600
WINDOWHEIGHT = 600
TEXTCOLOR = (255, 255, 255)
BACKGROUNDCOLOR = (0, 0, 255)
FPS = 40
BLACK = (0,0,0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
rectY1 = 300
rectY2 = 300
Y1change = 0
Y2change = 0
def moveup():
rectY1 -= 10
pygame.display.set_caption('Pong')
def drawshapes():
pygame.init()
DISPLAY=pygame.display.set_mode((600,600),0,32)
DISPLAY.fill(BLACK)
pygame.draw.rect(DISPLAY,RED,(18,rectY1,10,120))
pygame.draw.rect(DISPLAY,RED,(580,rectY2,10,120))
pygame.draw.ellipse(DISPLAY,BLUE,(300,300,30,30))
drawshapes()
while True:
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
keys = pygame.key.get_pressed()
if keys[K_UP]:
Y1change -= 10
if keys[K_DOWN]:
Y1change += 10
rectY1 += Y1change
rectY2 += Y2change
drawshapes()
pygame.display.update()
fpsClock.tick(FPS)
pygame.display.update()
You have to reset it before every test
Y1change = 0
if keys[K_UP]:
Y1change -= 10
if keys[K_DOWN]:
Y1change += 10
import random
import sys
import pygame
# --- constants (UPPERCASE_NAMES) ---
WINDOWWIDTH = 600
WINDOWHEIGHT = 600
TEXTCOLOR = (255, 255, 255)
BACKGROUNDCOLOR = (0, 0, 255)
FPS = 40
BLACK = (0,0,0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
# --- classes (CamelCaseNames)---
# empty
# --- functions (lower_case_names)---
def move_up():
global rectY1
rectY1 -= 10
def draw_shapes():
pygame.draw.rect(DISPLAY, RED, (18, rectY1, 10, 120)) # spaces
pygame.draw.rect(DISPLAY, RED, (580, rectY2, 10, 120)) # spaces
pygame.draw.ellipse(DISPLAY, BLUE, (300, 300, 30, 30)) # spaces
# --- main ---
rectY1 = 300
rectY2 = 300
Y1change = 0
Y2change = 0
# - init -
pygame.init()
DISPLAY = pygame.display.set_mode((600, 600), 0, 32) # spaces
pygame.display.set_caption('Pong')
#TODO: use pygame.Rect() to keep size and position of paddles and ball
# - mainloop -
fpsClock = pygame.time.Clock()
while True:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# - changes -
keys = pygame.key.get_pressed()
Y1change = 0
if keys[pygame.K_UP]:
Y1change -= 10
if keys[pygame.K_DOWN]:
Y1change += 10
# - updates -
rectY1 += Y1change
rectY2 += Y2change
# - draws -
DISPLAY.fill(BLACK)
draw_shapes()
pygame.display.update() # only once in loop
# - FPS -
fpsClock.tick(FPS)
I'm writing code for a one paddle pong game in pygame where the ball will bounce off of the 3 walls the paddle is not on, and when it does hit the paddle's wall instead of the paddle, it makes you lose a life. My problem is that I cannot figure out the collision detection to do this. Here is what I've done so far:
import pygame, sys
from pygame.locals import *
pygame.init()
screen_width = 640
screen_height = 480
Display = pygame.display.set_mode((screen_width, screen_height), 0, 32)
pygame.display.set_caption('Lonely Pong')
back = pygame.Surface((screen_width, screen_height))
background = back.convert()
background.fill((255, 255, 255))
paddle = pygame.Surface((80, 20))
_paddle = paddle.convert()
_paddle.fill((128, 0, 0))
ball = pygame.Surface((15, 15))
circle = pygame.draw.circle(ball, (0, 0, 0), (7, 7), 7)
_ball = ball.convert()
_ball.set_colorkey((0, 0, 0))
_paddle_x = (screen_width / 2) - 40
_paddle_y = screen_height - 20
_paddlemove = 0
_ball_x, _ball_y = 8, 8
speed_x, speed_y, speed_circle = 250, 250, 250
Lives = 5
clock = pygame.time.Clock()
font = pygame.font.SysFont("verdana", 20)
paddle_spd = 5
while True:
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
if event.type == KEYDOWN:
if event.key == K_RIGHT:
_paddlemove = paddle_spd
elif event.key == K_LEFT:
_paddlemove = -paddle_spd
elif event.type == KEYUP:
if event.key == K_RIGHT:
_paddlemove = 0
elif event.key == K_LEFT:
_paddlemove = 0
Livespr = font.render(str(Lives), True, (0, 0, 0))
Display.blit(background, (0, 0))
Display.blit(_paddle, (_paddle_x, _paddle_y))
Display.blit(_ball, (_ball_x, _ball_y))
Display.blit(Livespr, ((screen_width / 2), 5))
_paddle_x += _paddlemove
passed = clock.tick(30)
sec = passed / 1000
_ball_x += speed_x * sec
_ball_y += speed_y * sec
pygame.display.update()
Another problem I've been having is that when I start it up, the ball doesn't appear at all. Could somebody please point me in the right direction?
first things first, the ball doesn't appear because you are not filling the surface, you are setting the color_key:
_ball.set_colorkey((0, 0, 0))
should be
_ball.fill((0, 0, 0))
Second, for collision detection, pygame offers some functions such as collidepoint and colliderect.
https://www.pygame.org/docs/ref/rect.html#pygame.Rect.collidepoint
which means you will need the rectangles of the surfaces. do this by:
my_surface.get_rect()
https://www.pygame.org/docs/ref/surface.html#pygame.Surface.get_rect
In order to collide with the edges of the screen, you can always do
if _ball_x <= 0 or _ball_y <= 0 or _ball_x >= 640 or _ball_y >= 480:
# collision detected
When I run this code it just make a trail of circles instead of one circle moving. The code is as follows:
import pygame, sys, random
from pygame.locals import *
pygame.init()
windowSurface = pygame.display.set_mode((500, 400), 0, 32)
WHITE = (255, 255, 255)
circX = 250
circY= 250
diffX= 0
diffY=0
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
diffX += random.randint(-1,1)
diffY += random.randint(-1,1)
circX += diffX
circY += diffY
circLocate = (circX,circY)
pygame.draw.circle(windowSurface, WHITE, circLocate, 10, 0)
pygame.display.flip()
You have to clear the screen so it appears like the object is moving.
windowSurface.fill(WHITE)
As such:
import pygame, sys, random
from pygame.locals import *
pygame.init()
windowSurface = pygame.display.set_mode((500, 400), 0, 32)
WHITE = (255, 255, 255)
circX = 250
circY= 250
diffX= 0
diffY=0
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
diffX += random.randint(-1,1)
diffY += random.randint(-1,1)
circX += diffX
circY += diffY
circLocate = (circX,circY)
windowSurface.fill(WHITE)
pygame.draw.circle(windowSurface, WHITE, circLocate, 10, 0)
pygame.display.flip()
However, make sure that the windowSurface.fill() is before the pygame.draw.circle(), else, it will only show a white screen.
This addition should clear your screen each time you want the circle to move
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
windowSurface.fill(WHITE) //add this line to clear the screen
diffX += random.randint(-1,1)
diffY += random.randint(-1,1)
circX += diffX
circY += diffY
circLocate = (circX,circY)
pygame.draw.circle(windowSurface, WHITE, circLocate, 10, 0)
pygame.display.flip()