I made a class Ball with two instances: ballOne and ballTwo. When I call ballTwo.update() and then ballOne.update(), the last called ball sometimes disappears on some frames, like it sometimes flickers on and off. Can someone please help?
import pygame, sys
pygame.init()
red = (255,0,0)
black = (0,0,0)
white = (255,255,255)
blue = (0,0,255)
green = (0,255,0)
pygame.mouse.set_visible(0)
clock = pygame.time.Clock()
displaySize = (800,600)
screen = pygame.display.set_mode(displaySize)
g = 50
dt = 0.05
Cd = 0.01
m = 5
class ball:
def __init__(self, x, y, vx, vy, r,ax,ay, color):
self.Fx = 0
self.Fy = 0
self.Dx = 0
self.Dy = 0
self.ay = ay
self.ax = ax
self.x = x
self.y = y
self.r = r
self.color = color
self.vx = vx
self.vy = vy
def update(self):
self.x, self.y = self.physics()
pygame.draw.circle(screen, self.color, (int(round(self.x)),int(round(self.y))), self.r)
pygame.display.update()
def physics(self):
self.x +=self.vx*dt
self.y +=self.vy*dt
self.vy += self.ay*dt
self.vx += self.ax*dt
self.ay = self.Fy/m
self.ax = self.Fx/m
self.Fy = m*g - self.Dy
self.Fx = -self.Dx
self.Dy = Cd*self.vy*abs(self.vy)
self.Dx = Cd*self.vx*abs(self.vx)
if self.x <= self.r:
self.vx *= -0.7
if self.x >= displaySize[0]- self.r:
self.vx *= -0.7
if self.y <= self.r:
self.vy *= -0.7
if self.y >= displaySize[1] - self.r:
self.vy *= -0.7
return self.x, self.y
ballOne = ball(100,100,50,-100,30,0,0,red)
ballTwo = ball(500,500,-75,0,45,0,0,green)
while 1:
clock.tick(60)
screen.fill(blue)
ballTwo.update()
ballOne.update()
You're calling pygame.display.update() for each object, which is causing the flickering. Remove those calls and use pygame.display.flip() in the game loop.
I also recommend separating the updating and drawing of objects. Later, you may want to draw the objects in a different order than you want to update the objects.
A typical game loop does the following:
Process events
Calculate new position of objects
Draw next frame
Display frame
In Python, the game loop might look like this:
objects = [ballOne, ballTwo]
while True:
# 1. handle events
# 2. update objects
for object in objects:
object.update()
# 3. draw frame
screen.fill(blue)
for object in objects:
object.draw()
# 4. display frame
pygame.display.flip()
clock.tick(60)
Related
I don't know if there is a better way to implement ramps.
First i calculate the points that belong to the hipotenuse and use collidepoint to see if there is a collision between the rectangle and any point that belongs to the hipotenuse, then i update the rectangle based on the point where there was a collision.
Being careful when the rectangle is at the top of the ramp.
The rectangle ascends the ramp perfectly, but when the rectangle descends the ramp, the rectangle shakes.
import sys
import pygame
from pygame.locals import *
pygame.init()
fps = 60
fpsClock = pygame.time.Clock()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
def draw_grid():
for y in range(0,height,32):
pygame.draw.line(screen,'red',(0,y),(width,y))
for x in range(0,width,32):
pygame.draw.line(screen,'red',(x,0),(x,height))
class Ramp(pygame.sprite.Sprite):
def __init__(self, x, y, width, height, color):
super().__init__()
self.image = pygame.Surface((width, height), pygame.SRCALPHA)
#self.image.fill('green')
pygame.draw.polygon(self.image, color,
points=[(0, 0), (0, height), (width, height)])
self.rect = self.image.get_rect(topleft=(x, y))
class Player(pygame.sprite.Sprite):
def __init__(self,x,y):
super().__init__()
self.image = pygame.Surface((32, 32))
self.image.fill('blue')
self.rect = self.image.get_rect(topleft=(x,y))
self.speed = 5
self.direction = pygame.math.Vector2(0,0)
self.gravity = 0.9
self.initial_jump = -20
self.on_ground = True
def apply_gravity(self):
self.direction.y += self.gravity
self.rect.y += self.direction.y
def move(self):
keys=pygame.key.get_pressed()
if keys[K_LEFT]:
self.direction.x = -self.speed
elif keys[K_RIGHT]:
self.direction.x = self.speed
else:
self.direction.x = 0
if keys[K_UP] and self.on_ground:
self.direction.y = self.initial_jump
self.on_ground = False
self.rect.x += self.direction.x
def check_borders(self):
if self.rect.x <= 0:
self.rect.x = 0
if self.rect.right >= width:
self.rect.right = width
if self.rect.bottom >= height:
self.rect.bottom = height
self.direction.y = 0
self.on_ground = True
if self.rect.colliderect(ramp_rect):
if self.direction.x > 0 and abs(self.rect.right-ramp_rect.left) <= 5:
self.rect.right = ramp_rect.left
# ramp stuff
for p in hypotenuse_points:
if self.rect.collidepoint(p):
if self.rect.left >= ramp_rect.left:
self.rect.bottomleft = p
else:
self.rect.bottom = ramp_rect.top
self.on_ground = True
self.direction.y = 0
def update(self):
self.move()
self.apply_gravity()
self.check_borders()
player = pygame.sprite.GroupSingle(Player(12*32,10*32))
ramp = pygame.sprite.GroupSingle(Ramp(5*32,10*32,7*32,5*32,'red'))
ramp_rect = ramp.sprite.rect
m = (ramp_rect.height)/( ramp_rect.width)
x1,y1 = ramp_rect.topleft
hypotenuse_points = []
for x in range(ramp_rect.left,ramp_rect.right):
hypotenuse_points.append((x,m*(x-x1)+y1)) # Point-slope equation
while True:
screen.fill('white')
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
ramp.draw(screen)
player.update()
player.draw(screen)
#draw_grid()
pygame.draw.lines(screen,'black',False,hypotenuse_points,3)
pygame.display.update()
fpsClock.tick(fps)
There is no problem with your code. Only gravity is too weak. The movement is so fast that gravity is acting too late. Note that instead of moving down the slope, you move to the right and then fall.
Of course there is one problem with your code. Since pygame.Rect is supposed to represent an area on the screen, a pygame.Rect object can only store integral data.
The coordinates for Rect objects are all integers. [...]
The fraction part of the coordinates gets lost when the new position of the object is assigned to the Rect object. If this is done every frame, the position error will accumulate over time.
If you want to store object positions with floating point accuracy, you have to store the location of the object in separate variables respectively attributes and to synchronize the pygame.Rect object. round the coordinates and assign it to the location of the rectangle.
Instead of the list of points I suggest to compute the height of the ramp under the palyer:
if self.rect.colliderect(ramp_rect):
ratio = ramp_rect.height / ramp_rect.width
self.rect.bottom = ramp_rect.bottom - (ramp_rect.right - max(self.rect.left, ramp_rect.left)) * ratio
self.y = self.rect.y
Complete example:
import sys
import pygame
from pygame.locals import *
pygame.init()
fps = 60
fpsClock = pygame.time.Clock()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
def draw_grid():
for y in range(0,height,32):
pygame.draw.line(screen,'red',(0,y),(width,y))
for x in range(0,width,32):
pygame.draw.line(screen,'red',(x,0),(x,height))
class Ramp(pygame.sprite.Sprite):
def __init__(self, x, y, width, height, color):
super().__init__()
self.image = pygame.Surface((width, height), pygame.SRCALPHA)
#self.image.fill('green')
pygame.draw.polygon(self.image, color,
points=[(0, 0), (0, height), (width, height)])
self.rect = self.image.get_rect(topleft=(x, y))
class Player(pygame.sprite.Sprite):
def __init__(self,x,y):
super().__init__()
self.image = pygame.Surface((32, 32))
self.image.fill('blue')
self.rect = self.image.get_rect(topleft=(x,y))
self.x, self.y = self.rect.topleft
self.speed = 5
self.direction = pygame.math.Vector2(0,0)
self.gravity = 0.9
self.initial_jump = -20
self.on_ground = True
def apply_gravity(self):
self.direction.y += self.gravity
self.y += self.direction.y
self.rect.y = round(self.y)
def move(self):
keys = pygame.key.get_pressed()
self.direction.x = (keys[K_RIGHT] - keys[K_LEFT]) * self.speed
if keys[K_UP] and self.on_ground:
self.direction.y = self.initial_jump
self.on_ground = False
self.x += self.direction.x
self.rect.x = round(self.x)
def check_borders(self):
if self.rect.x <= 0:
self.rect.x = 0
self.x = self.rect.x
if self.rect.right >= width:
self.rect.right = width
self.x = self.rect.x
if self.rect.bottom >= height:
self.rect.bottom = height
self.direction.y = 0
self.on_ground = True
self.y = self.rect.y
if self.rect.colliderect(ramp_rect):
if self.old_rect.right-1 <= ramp_rect.left:
self.rect.right = ramp_rect.left
self.x = self.rect.x
else:
ratio = ramp_rect.height / ramp_rect.width
bottom = ramp_rect.bottom - (ramp_rect.right - max(self.rect.left, ramp_rect.left)) * ratio
if self.on_ground or self.rect.bottom > bottom:
self.rect.bottom = bottom
self.y = self.rect.y
self.direction.y = 0
self.on_ground = True
def update(self):
self.old_rect = self.rect.copy()
self.move()
self.apply_gravity()
self.check_borders()
player = pygame.sprite.GroupSingle(Player(12*32,10*32))
ramp = pygame.sprite.GroupSingle(Ramp(5*32,10*32,7*32,5*32,'red'))
ramp_rect = ramp.sprite.rect
m = (ramp_rect.height)/( ramp_rect.width)
x1,y1 = ramp_rect.topleft
while True:
screen.fill('white')
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
ramp.draw(screen)
player.update()
player.draw(screen)
pygame.display.update()
fpsClock.tick(fps)
I know this question has been asked multiple times but I just cant wrap my head around the concept of collisions, now I know I am asking a lot but I will appreciate it greatly!, All I ask is someone to add collisions to my game and explain each step so I can try to understand whats going on,I tried youtube videos and they aren't explained very well or I just get overwhelmed which is what I feel right now, So I just want the player to stop when hitting the tree, something as simple as that! And if possible I want it to get the collision from a list for example I would have trees and other images in the list.
import pygame
import sys
import math
from pygame.locals import *
import tiles_list
pygame.init()
display_w = 800
display_h = 600
window = pygame.display.set_mode((display_w, display_h), HWSURFACE | DOUBLEBUF | RESIZABLE)
pygame.display.set_icon(pygame.image.load("game_icon.png"))
pygame.display.set_caption("Work in progress")
clock = pygame.time.Clock()
background = pygame.image.load("background.png")
class Player(object):
"""The controllable player in game"""
def __init__(self, x, y, width, height, speed):
self.x = x
self.y = y
self.width = width
self.height = height
self.image = pygame.image.load("sprite_sheet.png")
self.speed = speed
self.timer = 0
self.frames = 1
self.direction = 2
def animation(self):
x_coord = 50 * self.frames
y_coord = 50 * self.direction
self.character = self.image.subsurface(x_coord, y_coord, self.width, self.height)
self.timer += 0
if self.timer >= 10:
self.timer = 0
self.frames += 1
if self.frames >= 9:
self.frames = 1
def draw(self):
window.blit(self.character, (self.x, self.y))
self.rect = pygame.Rect(self.x, self.y, self.width, self.height)
def movement(self):
self.keys = pygame.key.get_pressed()
if self.keys[pygame.K_LEFT] or self.keys[pygame.K_a]:
self.x -= self.speed
self.direction = 1
self.timer += 2
if self.keys[pygame.K_RIGHT] or self.keys[pygame.K_d]:
self.x += self.speed
self.direction = 3
self.timer += 2
if self.keys[pygame.K_UP] or self.keys[pygame.K_w]:
self.y -= self.speed
self.direction = 0
self.timer += 2
if self.keys[pygame.K_DOWN] or self.keys[pygame.K_s]:
self.y += self.speed
self.direction = 2
self.timer += 2
if self.x >= 780:
self.x = 780
self.frames = 0
if self.y >= 555:
self.y = 555
self.frames = 0
if self.x <= 0:
self.x = 0
self.frames = 0
if self.y <= 0:
self.y = 0
self.frames = 0
player = Player(400, 300, 50, 50, 4.5)
class Tree:
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.image = (
pygame.transform.scale(tiles_list.tiles.subsurface(pygame.Rect(99, 147, self.width, self.height)),
(62, 82)))
def draw(self):
window.blit(self.image, (self.x, self.y))
tree = Tree(348, 300, 42, 62)
running = True
while running:
window.blit(background, (0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == VIDEORESIZE:
screen = pygame.display.set_mode((event.w, event.h), RESIZABLE)
elif event.type == pygame.KEYUP:
if player.keys:
player.frames = 0
dist_x = math.hypot(tree.x - player.x)
dist_y = math.hypot(tree.y - player.y) # Does nothing except calculate the distence
print("distx", dist_x, "disty", dist_y)
tree.draw()
player.movement()
player.animation()
player.draw()
clock.tick(60)
pygame.display.flip()
Fist of all I suggest that you start to try to implement the collision test, before you ask a question. If you get stuck, you can ask a question about the code that gets you stuck.
Anyway I'll give you some hints.
In common the collision detection is based on pygame.Rect. For instance create a rectangle from pygaem.Surface objects player.image and tree.image by get_rect(). Evaluate if the 2 objects are colliding by colliderect():
player_rect = player.image.get_rect(topleft = (player.x, player.y))
tree_rect = tree.image.get_rect(topleft = (tree.x, tree.y))
if player_rect.colliderect(tree_rect):
print("hit")
If you "just want the player to stop when hitting the tree", the store the position of the player and move the player. After that evaluate if the player hits the tree. If the player is hitting, then restore the position:
while running:
# [...]
# store position of player
player_pos = (player.x, player.y)
# move player
player.movement()
player_rect = player.image.get_rect(topleft = (player.x, player.y))
tree_rect = tree.image.get_rect(topleft = (tree.x, tree.y))
# test collision of player and tree
if player_rect.colliderect(tree_rect):
# restore player position
(player.x, player.y) = player_pos
See also How to detect collisions between two rectangular objects or images in pygame
I am willing to explain you the process of collisions.
In your game you have two objects - the tree and the player. So, you can say that if the x and y coordinates of the player are the same , then there occurs a collisions. You can use this concept and create variables for detecting collisions.
Thanks
Let's consider following code (balls with random centers and velocities collide, with screen surface bounds, and with each other):
import pygame,sys,math
from pygame.locals import *
from random import randrange
WIDTH = 500
HEIGHT = 500
WHITE = (255,255,255)
BLUE = (0, 0, 255)
RADIUS = 10
FPS = 30
DISPLAYSURF = pygame.display.set_mode((WIDTH,HEIGHT),0,32)
TAB = []
fpsClock = pygame.time.Clock()
pygame.display.set_caption('Animation')
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def distance(self, A):
return math.sqrt((A.x-self.x)**2 + (A.y-self.y)**2)
def getTouple(self):
return (self.x,self.y)
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def norm(self):
return math.sqrt(self.x**2 + self.y**2)
class Ball:
def __init__(self, center, radius, velocity):
self.center = center
self.radius = radius
self.velocity = velocity
def __init__(self):
self.radius = RADIUS
self.center = Point(randrange(RADIUS,WIDTH-RADIUS), randrange(RADIUS,HEIGHT-RADIUS))
vx = randrange(-5,5)
vy = randrange(-5,5)
while vx == 0 or vy == 0:
vx = randrange(-5,5)
vy = randrange(-5,5)
self.velocity = Vector(vx,vy)
def draw(self):
self.center.x += self.velocity.x
self.center.y += self.velocity.y
for ball in TAB:
if ball != self:
if ball.center.distance(self.center) <= 2*RADIUS:
tmp = self.velocity
self.velocity = ball.velocity
ball.velocity = tmp
if self.center.x - self.radius <= 0:
self.velocity.x = -self.velocity.x
if self.center.x + self.radius >= WIDTH:
self.velocity.x = -self.velocity.x
if self.center.y - self.radius <= 0:
self.velocity.y = -self.velocity.y
if self.center.y + self.radius >= HEIGHT:
self.velocity.y = -self.velocity.y
pygame.draw.circle(DISPLAYSURF, BLUE, self.center.getTouple(), self.radius, 0)
BallNum = 30
for i in range(BallNum):
k = Ball()
TAB.append(k)
while True:
DISPLAYSURF.fill(WHITE)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
for ball in TAB:
ball.draw()
pygame.display.update()
fpsClock.tick(FPS)
This code works but not corectly: some balls are 'catched' by the bounds and others 'stick together'. I think the problem is in Ball class method draw. I will be grateful for any ideas on how to improve that code.
The main problem with the code you have posted which causes some of the balls to stick together, is that after they bounce off of each other, they still are in contact, so they bounce off of each other indefinitely which causes them to 'stick together'.
To fix this problem:
Add in an attribute/variable which holds a reference to the ball that it last hit. I called this attribute ball_last_hit and I initialized it to None.
Then, in the collision detection code, simply check to make sure the ball is not in contact with the ball it last hit, with an if statement like this: if ball != self.ball_last_hit:.
Then, if the balls should bounce off of each other, after swapping their velocities, set self.ball_last_hit to ball.
This will solve the 'sticking together' problem between the balls, but the ball could still get 'stuck' to the wall, although it is less common. To solve this you could add in an attribute called something like self.ignore_walls and after each collision with a wall, set it to true, then after a certain amount of time, set it back to false, so it can collide with walls again.
Here is the fixed code:
import pygame,sys,math
from pygame.locals import *
from random import randrange
WIDTH = 500
HEIGHT = 500
WHITE = (255,255,255)
BLUE = (0, 0, 255)
RADIUS = 10
FPS = 30
DISPLAYSURF = pygame.display.set_mode((WIDTH,HEIGHT),0,32)
TAB = []
fpsClock = pygame.time.Clock()
pygame.display.set_caption('Animation')
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def distance(self, A):
return math.sqrt((A.x-self.x)**2 + (A.y-self.y)**2)
def getTouple(self):
return (self.x,self.y)
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def norm(self):
return math.sqrt(self.x**2 + self.y**2)
class Ball:
def __init__(self):
self.radius = RADIUS
self.center = Point(randrange(RADIUS,WIDTH-RADIUS), randrange(RADIUS,HEIGHT-RADIUS))
vx = randrange(-5,5)
vy = randrange(-5,5)
while vx == 0 or vy == 0:
vx = randrange(-5,5)
vy = randrange(-5,5)
self.velocity = Vector(vx,vy)
self.ball_last_hit = None
def draw(self):
self.center.x += self.velocity.x
self.center.y += self.velocity.y
for ball in TAB:
if ball != self:
if ball.center.distance(self.center) <= 2*RADIUS:
if ball != self.ball_last_hit:
tmp = self.velocity
self.velocity = ball.velocity
ball.velocity = tmp
self.ball_last_hit = ball
if self.center.x - self.radius <= 0:
self.velocity.x = -self.velocity.x
if self.center.x + self.radius >= WIDTH:
self.velocity.x = -self.velocity.x
if self.center.y - self.radius <= 0:
self.velocity.y = -self.velocity.y
if self.center.y + self.radius >= HEIGHT:
self.velocity.y = -self.velocity.y
pygame.draw.circle(DISPLAYSURF, BLUE, self.center.getTouple(), self.radius, 0)
BallNum = 30
for i in range(BallNum):
k = Ball()
TAB.append(k)
while True:
DISPLAYSURF.fill(WHITE)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
for ball in TAB:
ball.draw()
pygame.display.update()
fpsClock.tick(FPS)
Note: instead of using a temp variable, and executing three lines of code, you can swap the balls' velocities with just one this line of code: self.velocity, ball.velocity = ball.velocity, self.velocity.
I hope this answer helped you, and if you have any further questions, please feel free to leave a comment below!
Edit: to get rid of the sticking to the walls, all we need to do is make sure that after a collision with the wall, the ball is not still in contact with the wall, because if it is, it will bounce against the wall indefinitely, and get 'stuck'
After changing the ball's velocity, when it collides with the wall, I just set the center of the ball to one pixel away from the wall, so it is definitely not touching the wall, and this fixed the problem for me.
Here is the new collision detection code, which goes at the end of the draw() method. There are just 4 new lines needed.
if self.center.x - self.radius <= 0:
self.velocity.x = -self.velocity.x
self.center.x = self.radius + 1
if self.center.x + self.radius >= WIDTH:
self.velocity.x = -self.velocity.x
self.center.x = WIDTH - self.radius - 1
if self.center.y - self.radius <= 0:
self.velocity.y = -self.velocity.y
self.center.y = self.radius + 1
if self.center.y + self.radius >= HEIGHT:
self.velocity.y = -self.velocity.y
self.center.y = HEIGHT - self.radius - 1
Note: this simulation gets very tricky if you increase the ball number even higher, because groups of 3 balls start to collide with each other at a time, and your current code is only capable of handling collision between two balls.
so I am new to pygame/python/coding and first time using classes. I already made a working pygame program of a ball bouncing around and accelerating with gravity. However, now that I use classes, the ball only seems to be moving at a constant speed. Please tell me what I am doing wrong and how
I should change my code. Thanks in advance!
import pygame, sys
pygame.init()
red = (255,0,0)
black = (0,0,0)
white = (255,255,255)
blue = (0,0,255)
pygame.mouse.set_visible(0)
clock = pygame.time.Clock()
displaySize = (800,600)
screen = pygame.display.set_mode(displaySize)
g = 30
dt = 0.05
class ball:
def __init__(self, x, y, vx, vy, r,ax,ay, color):
dt = 0.05
Cd = 0.01
m = 5
self.ay = ay
self.ax = ax
self.x = x
self.y = y
self.r = r
self.color = color
self.vx = vx
self.vy = vx
def update(self, x, y):
x, y = physics()
pygame.draw.circle(screen, self.color, (int(round(x)),int(round(y))), self.r)
pygame.display.update()
def physics(self):
self.Dy = Cd*self.vy*abs(self.vy)
self.Dx = Cd*self.vx*abs(self.vx)
self.Fy = self.m*g - self.Dy
self.Fx = -self.Dx
self.ay = self.Fy/m
self.ax = self.Fx/m
self.vy += self.ay*dt
self.vx += self.ax*dt
self.x +=self.vx*dt
self.y +=self.vy*dt
return self.x, self.y
one = ball(100,100,0,0,0,0,30,red)
while 1:
clock.tick(30)
screen.fill(blue)
one.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
self.vx and self.vy should be within the constructor method instead of the physics method, otherwise their values will be set back to 50 and 0 each time the physics method is called within the game loop, resulting in a constant speed.
I have a huge assignment due in class and Im lost like , asking god to spare me lost. Im making a brick game and the most basic function of getting the ball to bounce of the walls I cant figure out , my teacher is too busy and classmates are competitive , I dont want you to write the code for me, I just dont know how to code it. I keep getting errors and its just been hell the last couple of classes.
import math
import pygame
import random
pygame.init()
screen = pygame.display.set_mode([800,600])
done = False
clock = pygame.time.Clock()
#DEFINE COLORS
WHITE = (255,255,255)
BLUE=(0,102,204)
LIGHT_BLUE=(0,0,204)
pink=(238,130,238)
#import images
#lives = pygame.image.load("heart.png")
# initialize font; must be called after 'pygame.init()' to avoid 'Font not Initialized' error
myfont = pygame.font.SysFont("monospace", 15)
#var carying the space of the game
top = -100
left= -50
right= -750
bottom= -600
angle = math.radians(random.randint(-140,-30))
class game_screen():
def draw_screen():
pygame.draw.rect(screen,BLUE,(50,100,700,600))
def save_button():
pygame.draw.rect(screen,pink,(500,20,50,30),0)
save = "Save"
label = myfont.render(save, 40, (0,0,0))
screen.blit(label, (505, 20))
def quit_button():
pygame.draw.rect(screen,pink,(600,20,50,30),0)
quit1 = "Quit"
label = myfont.render(quit1, 40, (0,0,0))
screen.blit(label, (605, 20))
mX, mY = pygame.mouse.get_pos()
mouseButtons = pygame.mouse.get_pressed()
if mouseButtons[0] == True:
if (mX in range (600-20,600+20) and mY in range (20-20,20+20)):
pygame.quit()
#def display_lives():
#lives_counter = screen.blit(lives,(50,30))
#lives_counter2 = screen.blit(lives,(120,30))
#lives_counter3 = screen.blit(lives,(190,30))
class PADDLE:
def __init__(self,xpos,ypos):
self.x = xpos
self.y = ypos
def draw(self): # draws paddle
pygame.draw.rect(screen,pink,(self.x,self.y,70,20))
def move(self):
keys = pygame.key.get_pressed() #checking pressed keys
if keys[pygame.K_LEFT]:
if self.x<=50:
self.x=50
else:
self.x -= 10
elif keys[pygame.K_RIGHT]:
if self.x >=680:
self.x = 680
else:
self.x += 10
class BALL:
def __init__(self,paddle1):
self.x = (paddle1.x+35)
self.y = (paddle1.y-5)
self.speed = 0
self.speedX = 0
self.speedY = 0
self.direction = 200
def draw(self):
pygame.draw.circle(screen,WHITE,(self.x,self.y),10)
def bounce(self):
self.direction = (180 - self.direction) % 360
def move_ball(self):
keys = pygame.key.get_pressed() #checking pressed keys
ball_on_paddle = True
if ball_on_paddle == True :
self.x = (paddle1.x+35)
self.y = (paddle1.y-5)
self.speed = 0
if keys[pygame.K_UP] == True:
ball_on_paddle = False
print("a")
self.speed = 10
self.speedX += int(math.cos(angle)* self.speed)
self.speedY += int(math.sin(angle)* self.speed)
print(bottom)
print(self.speedY)
if self.y <= 0:
self.bounce(0)
self.y = 1
if self.x <= 0:
self.direction = (360 - self.direction) % 360
self.x = 1
if self.x > self.screenwidth - self.width:
self.direction = (360 - self.direction) % 360
self.x = self.screenwidth - self.width - 1
paddle1 = PADDLE(350,550)
ball1 = BALL(paddle1)
# MAIN LOOP
while not done:
screen.fill((LIGHT_BLUE))
game_screen.draw_screen()
game_screen.save_button()
game_screen.quit_button()
paddle1.draw()
paddle1.move()
ball1.draw()
ball1.move_ball()
ball1.bounce()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pygame.display.flip()
clock.tick(60)
pygame.quit()
The collission between ball and wall can be detected by comparing the ball's coordinates with the coordinates of the walls. Reflecting the ball means a multiplication of either speedX or speedY - depending on the wall - with -1.
The easiest way to do this is to make a function bounce(self) in your class BALL.
First, you decide which border you touch.
Then, you change the angle of the ball according to which border you bounce on. If you work in a 360-degree system, the angle is mirrored:
around a vertical axis when the ball bounces of the bottom and the top border. So angle = 180 - angle.
around a horizontal axis when the ball bounces of the side borders. So angle = - angle .
And lastly, you have to move the ball back what it has travelled too much.
Like you can see, the ball travels in 1 iteration from C1 to C3', while we want it to go to C3. We can achieve this by reflecting it around the axis BOUNDARY_X - ball_size.
The new x-coordinate of the ball becomes then x = BOUNDARY_X - ball_size - (x - BOUNDARY_X + ball_size) = 2*(BOUNDARY_X - ball_size) - x .
When we cast that into code, we get:
class BALL:
def bounce(self):
if self.x < ball_size:
self.angle = math.pi - self.angle
self.x = 2*ball_size - self.x
elif self.x > DISPLAY_WIDTH - ball_size:
self.angle = math.pi - self.angle
self.x = 2*(DISPLAY_WIDTH - ball_size) - self.x
if self.y < ball_size:
self.angle = - self.angle
self.y = 2*ball_size - self.y
elif self.y > DISPLAY_HEIGHT - ball_size:
self.angle = - self.angle
self.y = 2*(DISPLAY_HEIGHT - ball_size) - self.y