Flawed collision detection between rectangles - python

I am creating a physics-based game with Pygame in which the player controls a ball. As you control the ball, it accelerates in the specified direction (holding the left arrow adds x pixels per frame to its movement speed). Since the ball is... well... a ball, and Pygame doesn't support ball collision detection, I created a new class with its own collision method. The method has two parts: if the ball runs into the corner of a rectangle, or if it runs into the side of the rectangle. The problem concerns the circle-to-side collision.
The ball is based on a rect object, and therefore has those pesky corners. I cannot use the simple colliderect method, otherwise the situation above would detect a collision where there should be none, and it would overlap the first part of my collision detection method. Instead, I opted to use collidepoint between the rectangle and the midpoints on each side of the ball's rectangle.
Finally, the heart of the issue. I mentioned earlier that the ball accelerates. When the ball accelerates to the point that (even though it appears to be standing still) it moves far enough into the rectangle for another midpoint on the circle to detect a "collision." This problem likely stems from the fact that (for a collision on the left side of the ball) my code sets the ball's left equal to the rectangle's right, so that when the ball accelerates enough to be inside the rectangle, it gets moved to another face of the rectangle.
Thank you so much for bearing with me, any and all suggestions are welcome. I would either be looking for a fix to my specific problem, or a cleaner way to handle the collision detection. My full code is below:
import pygame, sys, math
global Color
Color = {}
Color['white'] = (255,255,255)
Color['black'] = ( 0, 0, 0)
Color['red'] = (255, 0, 0)
Color['green'] = ( 0,255, 0)
Color['blue'] = ( 0, 0,255)
global WINDOWWIDTH, WINDOWHEIGHT
WINDOWWIDTH, WINDOWHEIGHT = 500, 500
class Ball():
def __init__(self, x, y, r):
self.rect = pygame.Rect(x, y, r, r)
self.radius = r/2
self.speed = [0, 0]
self.b_fact = 1
self.move = {'left':False, 'right':False, 'up':False, 'down':False}
self.new_dir = {'left':False, 'right':False, 'up':False, 'down':False}
def move_self(self):
if self.move['left']:
self.speed[0] -= 2
if self.move['up']:
self.speed[1] -= 2
if self.move['right']:
self.speed[0] += 2
if self.move['down']:
self.speed[1] += 2
if self.speed[0] < 0:
self.speed[0] += 1
if self.speed[1] < 0:
self.speed[1] += 1
if self.speed[0] > 0:
self.speed[0] -= 1
if self.speed[1] > 0:
self.speed[1] -= 1
self.rect.left += self.speed[0]
self.rect.top += self.speed[1]
def bounce(self, rectList):
for rect in rectList:
self.collide_rect(rect)
if self.rect.left <= 0:
self.rect.left = 0
self.new_dir['right'] = True
if self.rect.right >= WINDOWWIDTH:
self.rect.right = WINDOWWIDTH
self.new_dir['left'] = True
if self.rect.top <= 0:
self.rect.top = 0
self.new_dir['down'] = True
if self.rect.bottom >= WINDOWHEIGHT:
self.rect.bottom = WINDOWHEIGHT
self.new_dir['up'] = True
for key in self.new_dir:
if self.new_dir[key] and key=='left':
self.speed[0] *= (-1)*self.b_fact
if self.new_dir[key] and key=='right':
self.speed[0] *= (-1)*self.b_fact
if self.new_dir[key] and key=='up':
self.speed[1] *= (-1)*self.b_fact
if self.new_dir[key] and key=='down':
self.speed[1] *= (-1)*self.b_fact
self.new_dir[key] = False
def collide_rect(self, rect):
x1, y1, r = self.rect.centerx, self.rect.centery, self.radius
foundSide = 0
foundCorner = 0
side_list = ['left', 'right', 'bottom', 'top']
corner_list = ['topleft', 'topright', 'bottomleft', 'bottomright']
collision_list = []
for side in side_list:
if rect.collidepoint(eval('self.rect.mid'+side)):
collision_list.append(side)
for corner in corner_list:
x2, y2 = eval('rect.'+corner)[0], eval('rect.'+corner)[1]
dist = math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
if dist < r:
if corner.find('left') > -1:
corner = corner.replace('left','right')
else:
corner = corner.replace('right','left')
if corner.find('top') > -1:
corner = corner.replace('top','bottom')
else:
corner = corner.replace('bottom','top')
collision_list.append(corner)
for direction in collision_list:
if direction.find('left') > -1:
self.rect.left = rect.right
self.new_dir['left'] = True
if direction.find('top') > -1:
self.rect.top = rect.bottom
self.new_dir['top'] = True
if direction.find('right') > -1:
self.rect.right = rect.left
self.new_dir['right'] = True
if direction.find('bottom') > -1:
self.rect.bottom = rect.top
self.new_dir['bottom'] = True
class BallGame():
def __init__(self):
pygame.display.set_caption("Ball is life")
pygame.init()
self.ball = Ball(0, 0, 30)
self.allRects = []
rect = pygame.Rect(60,60,50,50)
self.allRects.append(rect)
self.mainClock = pygame.time.Clock()
self.screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
self.basicFont = pygame.font.SysFont(None, 50)
def drawScreen(self):
self.screen.fill(Color['green'])
pygame.draw.ellipse(self.screen, Color['white'], self.ball.rect)
for rect in self.allRects:
pygame.draw.rect(self.screen, Color['black'], rect)
def mainloop(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
for i in range(2):
k = (pygame.KEYUP, pygame.KEYDOWN)
if event.type == k[i]:
if event.key == pygame.K_LEFT:
self.ball.move['left'] = i
elif event.key == pygame.K_UP:
self.ball.move['up'] = i
elif event.key == pygame.K_RIGHT:
self.ball.move['right'] = i
elif event.key == pygame.K_DOWN:
self.ball.move['down'] = i
self.ball.move_self()
self.ball.bounce(self.allRects)
self.drawScreen()
pygame.display.update()
self.mainClock.tick(20)
Game = BallGame()
while True:
Game.mainloop()

Another way to think about the collision is to consider an enlarged version of the black rectangle. This would be a rounded rectangle with corner radius r. The collision between the ball and black rectangle is equivalent to the collision between the center of the ball and the rounded rectangle. This can help make the analysis of the situation easier.
When it bounces a more accurate way of determining the new position is to consider the line from the previous position to the current position. You can calculate where this line crosses the boundary and where a prefect reflection should be.

Related

How to make a collision detector in pygame

I am making a networked game that involves generating random blocks. Players should not be able to move inside the blocks so I created a collision detection function to stop a player moving inside a block. The function is able to stop a player moving into a block from the left and the top but players can still move in from the right and bottom. I also have one more problem that ever since I generated the block the player moves extremely slow.
This is the code for the Player class:
class player:
def __init__(self, x, y, width, height, colour):
self.width = width # dimensions of player
self.height = height # dimensions of player
self.x = x # position on the screen
self.y = y # position on the screen
self.colour = colour # players colour
self.rect = (x, y, width, height) # all the players properties in one
self.speed = 2 # how far/fast you move with each key press
self.direction = ""
def draw(self, win):
pygame.draw.rect(win, self.colour, self.rect)
def move(self, platforms):
keys = pygame.key.get_pressed() # dictionary of keys - values of 0/1
if keys[pygame.K_LEFT]: # move left: minus from x position value
if self.x <= 5:
pass
else:
self.x -= self.speed
self.direction = "Left"
elif keys[pygame.K_RIGHT]: # move right: add to x position value
if self.x == 785:
pass
else:
self.x += self.speed
self.direction = "right"
elif keys[pygame.K_UP]: # move up: minus from y position value
if self.y <= 5:
pass
else:
self.y -= self.speed
self.direction = "up"
elif keys[pygame.K_DOWN]: # move down from
if self.y >= 785:
pass
else:
self.y += self.speed
self.direction = "down"
def update(self, platforms, direction):
self.collision_with_platform(platforms, direction)
self.rect = (self.x, self.y, self.width, self.height) # redefine where the player is
self.update(platforms, self.direction)
This is the collision detector:
def collision_with_platform(self, platforms, direction):
# evaluates if the player is inside a platform, moving the player to it's edge if so
for platform in platforms:
# checks if player's coordinates are inside the platform, for each platform
if platform.rect.left - 20 < self.x < platform.rect.left + 50:
if platform.rect.top - 20 < self.y < platform.rect.top + 50:
# if moving horizontally
if direction == "left" or direction == "right": # evaluates which side of the platform to move the player to
if direction == "left":
self.x = platform.rect.left + 10 # move to the right side
if direction == "right":
self.x = platform.rect.left - 10 # move to the left side
# if moving vertically
elif direction == "down" or direction == "up": # evaluates which side of the platform to move the player to
if direction == "down":
self.y = platform.rect.top - 10 # move to the top side
elif direction == "up":
self.y_pos = platform.rect.top + 50 # move to the bottom side
This is how I generate platforms:
class Platform:
# represents a platform which the player can stand on
def __init__(self, left, top, width, height, colour):
self.rect = pygame.Rect(left, top, width, height) # square representing a single platform
self.colour = colour # platform's colour
def generate_platforms(probability):
# generates platforms randomly
points, platforms = [], []
# generates a list of all possible platform coordinates
# format of points : [(0,0), (0,1), (0,2), ..., (1,0), (1,1), (1,2), ...]
for x in range(0, 600):
for y in range(0, 600):
points.append((x, y))
# randomly selects platforms to create out of list of all possible platforms
for point in points:
if random.randint(1, 100) <= probability: # probability of each individual platform being created
platforms.append(Platform(point[0] * 50, point[1] * 50, 50, 50, (0, 0, 225)))
return platforms # returns the list of generated platforms
This is the main game loop:
def main(): # asking server for updates, checking for events
run = True
n = Network()
startPos = read_pos(n.getPos())
p = player(startPos[0], startPos[1], 10, 10, (255, 0, 0)) # connect, get starting position
p2 = player(0, 0, 10, 10, (0, 0, 255))
platforms = generate_platforms(25)
clock = pygame.time.Clock()
while run:
clock.tick(60)
p2Pos = read_pos(n.send(make_pos((p.x, p.y))))
p2.x = p2Pos[0]
p2.y = p2Pos[1]
p2.update(platforms, p.direction)
for event in pygame.event.get():
if event.type == pygame.QUIT: # quitting condition
run = False
pygame.quit()
p.move(platforms) # move character based off what keys are being pressed
redrawWindow(win, p, p2, platforms)
The problem is you have way more platforms than you think, there is a 25% chance to have a platform on every pixel that is 50 x 50. you have a lot of overlapping platforms. I ran it and got a length of 62516 platforms. I think what you want it
for x in range(0, screen_Width//50):
for y in range(0, screen_Height//50):
if random.randint(1, 100) <= probability: # probability of each individual platform being created
platforms.append(Platform(x * 50, y * 50, 50, 50, (0, 0, 225)))
This only creates platforms every 50 pixels, so none overlap. Running this i got a length of 22, a lot lower and still looks about the same. This will speed up your program considerably. I was getting 1.5 fps but now maxed out fps at 60.
To fix your collisions.
Change your player rect to a pygame rect object
self.rect = pygame.Rect(x, y, width, height) # all the players properties in one
and change the rect when you move
if keys[pygame.K_LEFT]: # move left: minus from x position value
if self.x > 5:
self.x -= self.speed
self.rect.x -= self.speed
self.direction = "left" # lowercase l as everything else was lowercase
then for the collisions:
if self.rect.colliderect(platform.rect):
if direction == "left":
self.rect.left = platform.rect.right # move to the right side
elif direction == "right":
self.rect.right = platform.rect.left # move to the left side
# if moving vertically
elif direction == "down":
self.rect.bottom = platform.rect.top # move to the top side
elif direction == "up":
self.rect.top = platform.rect.bottom # move to the bottom side
also In player.update you dont need to call it again inside it. So just this will do
def update(self, platforms):
self.collision_with_platform(platforms, self.direction)

Pygame collision check bug

I recently started making Atari Breakout in Pygame and I encountered a weird bug. Whenever the ball touches the left side of the paddle, it bounces off normally but when it's on the right, it flies through the paddle. Please help, because I don't know how to fix it.
This is my code:
import pygame, random, math
pygame.init()
screen = pygame.display.set_mode((800,600))
pygame.display.set_caption('Atari Breakout')
player = pygame.image.load('player copy.png')
ball = pygame.image.load('poland.png')
ballx, bally = 400, 300
balldx, balldy = 2,2
def isCollision(x1,y1,x2,y2):
distance = math.sqrt(math.pow(x1 - x2, 2) + math.pow(y1 - y2, 2))
if distance <= 32:
return True
else:
return False
running = True
while running:
screen.fill((0,0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pos = pygame.mouse.get_pos()
if isCollision(ballx, bally, pos[0], 525):
balldy *= -1
if bally >= 0:
balldy *= -1
if bally <= 570:
balldy *= -1
if ballx <= 0:
balldx *= -1
if ballx >= 770:
balldx *= -1
ballx += balldx
bally += balldy
screen.blit(player, (pos[0], 525))
screen.blit(ball, (ballx,bally))
pygame.display.update()
Actually isCollision computes the Euclidean distance between the top left of the rectangle which surrounds the ball and the top left of the paddle.
The shape of the player (paddle) is a rectangle with a very long and a very short side. Thus the collision algorithm doesn't work at all. I recommend to use pygame.Rect objects and colliderect, to detect a collision between the ball and the player. e.g.:
def isCollision(x1,y1,x2,y2):
ballRect = ball.get_rect(topleft = (x1, y1))
playerRect = player.get_rect(topleft = (x2, y2))
return ballRect.colliderect(playerRect)
while running:
# [...]
pos = pygame.mouse.get_pos()
if isCollision(ballx, bally, pos[0], 525):
balldy *= -1

pygame: Random direction of a ball at the start of the game

I'm doing the Pong game. However instead of 2 players, I'm doing it for 4 (one on each side of the screen). I need to have the ball randomly "choose" the direction it has to go.
import pygame
import random
class Ball(object):
#classmethod
def init(cls, SCREEN_WIDTH, SCREEN_HEIGHT):
cls.radius = 20
cls.centerx = SCREEN_WIDTH*0.5
cls.centery = SCREEN_HEIGHT*0.5
cls.rect = pygame.Rect(cls.centerx - cls.radius,
cls.centery - cls.radius,
cls.radius * 2,
cls.radius * 2)
# x , y
cls.direction = [random.choice([1, -1]), random.choice([1, -1])]
cls.speed = [5, 8] # x, y
# left, right, top, bottom
cls.hit_edge = [False, False, False, False]
#classmethod
def update(cls, player1, player2, player3, player4, SCREEN_WIDTH,
SCREEN_HEIGHT):
cls.centerx += cls.direction[0] * cls.speed[0]
cls.centery += cls.direction[1] * cls.speed[1]
cls.rect.center = (cls.centerx, cls.centery)
#detects if someone losses
if cls.rect.left <= 0:
cls.hit_edge[0] = True
elif cls.rect.right >= SCREEN_WIDTH-1:
cls.hit_edge[1] = True
elif cls.rect.top <= 0:
cls.hit_edge[2] = True
elif cls.rect.bottom >= SCREEN_HEIGHT-1:
cls.hit_edge[3] = True
#detects collision between players & the ball
if cls.rect.colliderect(player1.rect):
cls.direction[0] = 1
cls.up_speed()
elif cls.rect.colliderect(player2.rect):
cls.direction[0] = -1
cls.up_speed()
elif cls.rect.colliderect(player3.rect):
cls.direction[1] = 1
cls.up_speed()
elif cls.rect.colliderect(player4.rect):
cls.direction[1] = -1
cls.up_speed()
#classmethod
def up_speed(cls):
cls.speed[0] += random.uniform(0, 0.25)
cls.speed[1] += random.uniform(0, 0.25)
#classmethod
def render(cls, SCREEN, color):
pygame.draw.circle(SCREEN, color, cls.rect.center, cls.radius, 0)
To take into account: I had the idea to add a "0" in every random.choice(), although if I do this only function at the beginning, then it will not be able to move in the axis where the "0" . Also I have two types of speeds in X and Y, could be solved by putting a "0.1" in random.choice () but this would make when the game starts the ball goes very slow. As you would do for the ball to start in a random direction (taking into account that the speed of the ball at the start must be the same for all players. If the ball goes at the beginning to the left,and later (in another game) when it starts but the ball goes up has to go at the same speed)
This may be a little over-complicating things, but if you know the speed you want the ball to start with overall, you could use something like this:
Generate random number between 0-1
angle = 360 * random number
xSpeed = startSpeed * sin(angle)
ySpeed = startSpeed * cos(angle)
This will mean that your ball will always travel at the same speed. The only thing that is random is the direction it travels in.
I recommend to use vectors. For the velocity you can just pick an arbitrary start speed like (8, 0) and then rotate the vector by a random angle.
position = pg.math.Vector2(100, 200)
velocity = pg.math.Vector2(8, 0).rotate(random.randrange(360))
To update the position:
position += velocity
Here's an example program that spawns balls with random color and velocity.
import sys
import math
from random import randrange
import pygame as pg
class Ball(pg.sprite.Sprite):
def __init__(self, pos, *groups):
super().__init__(groups)
self.image = pg.Surface((30, 30), pg.SRCALPHA)
col = randrange(256), randrange(256), randrange(256)
pg.draw.circle(self.image, col, (15, 15), 15)
self.rect = self.image.get_rect(center=pos)
self.vel = pg.math.Vector2(8, 0).rotate(randrange(360))
self.pos = pg.math.Vector2(pos)
def update(self):
self.pos += self.vel
self.rect.center = self.pos
if self.rect.left < 0 or self.rect.right > 640:
self.vel.x *= -1
if self.rect.top < 0 or self.rect.bottom > 480:
self.vel.y *= -1
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
sprite_group = pg.sprite.Group()
ball = Ball((320, 240), sprite_group)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.MOUSEBUTTONDOWN:
sprite_group.add(Ball((320, 240)))
sprite_group.update()
screen.fill((30, 30, 30))
sprite_group.draw(screen)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()

brick game bounce off the walls

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

How can i add collision rectangles on click? (python & pygame)

Can anyone show me how to add a rectangle wherever i click somewhere and make the ball bounce off it for example when i click somewhere on the screen it place a rectangle at that coordinate and when they make the ball collide with it the ball will bounce.
Also my is their a way of making it HD?
import sys
import pygame
import os
image_file = os.path.expanduser("ball.png")
delta = {
pygame.K_LEFT: (-20, 0),
pygame.K_RIGHT: (+20, 0),
pygame.K_UP: (0, -20),
pygame.K_DOWN: (0, +20),
}
gravity = +1
class Ball(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.speed = [0, 0]
area = pygame.display.get_surface().get_rect()
self.width, self.height = area.width, area.height
def update(self):
self.rect = self.rect.move(self.speed)
if self.rect.left < 0 or self.rect.right > self.width:
self.speed[0] = -self.speed[0]
if self.rect.top < 0 or self.rect.bottom > self.height:
self.speed[1] = -self.speed[1]
self.rect.left = clip(self.rect.left, 0, self.width)
self.rect.right = clip(self.rect.right, 0, self.width)
self.rect.top = clip(self.rect.top, 0, self.height)
self.rect.bottom = clip(self.rect.bottom, 0, self.height)
def clip(val, minval, maxval):
return min(max(val, minval), maxval)
class Main(object):
def __init__(self):
self.setup()
def setup(self):
pygame.init()
size = (self.width, self.height) = (640,360)
self.screen = pygame.display.set_mode((1000,1000),pygame.FULLSCREEN)
self.ball = Ball()
self.setup_background()
def setup_background(self):
self.background = pygame.Surface(self.screen.get_size())
self.background = self.background.convert()
self.background.fill((0, 0, 0))
self.screen.blit(self.background, (0, 0))
pygame.display.flip()
def draw(self):
self.screen.blit(self.background, (0, 0))
self.screen.blit(self.ball.image, self.ball.rect)
pygame.display.flip()
def event_loop(self):
ball = self.ball
friction = 1
while True:
for event in pygame.event.get():
if ((event.type == pygame.QUIT) or
(event.type == pygame.KEYDOWN and
event.key == pygame.K_ESCAPE)):
sys.exit()
elif event.type == pygame.KEYDOWN:
deltax, deltay = delta.get(event.key, (0, 0))
ball.speed[0] += deltax
ball.speed[1] += deltay
friction = 1
elif event.type == pygame.KEYUP:
friction = 0.99
ball.speed = [friction*s for s in ball.speed]
ball.speed[1] += gravity
ball.update()
self.draw()
pygame.time.delay(10)
if __name__ == '__main__':
app = Main()
app.event_loop()
You have to be able to perform several steps:
Detect when the mouse changes from unpressed to pressed state.
If that happens:
Add a Rectange object to a list (consists of x, y, width and height).
In each loop:
For each Rectange in the list: Check if it intersects with the ball. You can model the ball as a rectangle, which is a little bit easier, or as a circle. A circle touches a rectangle if a corner of the rectange is inside of it or if the center is below/above/beneath the rectangle and less than its radius away. (It's easier to explain with a picture.)
If the ball collides: Change the speed as if it had touched the corner of the screen.
Do you have further problems regarding one of these steps?
"Also my is their a way of making it HD?"
I was able to change the resolution to 1600 x 900. Each graphics card only supports a certain set of fullscreen resolutions and 1000x1000 didn't work for mine.

Categories