Skip to content

Instantly share code, notes, and snippets.

@SealtielFreak
Created September 19, 2023 20:18
Show Gist options
  • Save SealtielFreak/cb2c4269ddd91512c1f03929493e72ae to your computer and use it in GitHub Desktop.
Save SealtielFreak/cb2c4269ddd91512c1f03929493e72ae to your computer and use it in GitHub Desktop.
Pong in Pygame
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import abc
import math
import functools
import pygame
import pygame.locals
import pygame.math
TEXTURE_BALL = "ball.png"
TEXTURE_BAR = "bar.png"
SCREEN_SIZE = 640, 480
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Drawawble:
def __init__(self, texture):
self.position = pygame.math.Vector2()
self.texture = texture
def blit(self, surface):
surface.blit(self.texture, self.position)
@abc.abstractmethod
def update(self, dt): ...
class Ball(Drawawble, metaclass=Singleton):
def __init__(self):
super().__init__(pygame.image.load(TEXTURE_BALL))
self.texture = self.texture.convert_alpha()
self.texture = pygame.transform.smoothscale(self.texture, (30, 30))
self.speed = pygame.math.Vector2(.1, -.1)
self.position = pygame.math.Vector2(300, 300)
def update(self, dt):
width, height = SCREEN_SIZE
w, h = self.texture.get_size()
if not math.floor(self.position.x) in range(width - w):
self.speed.x *= -1
if not math.floor(self.position.y) in range(height - h):
self.speed.y *= -1
self.position += self.speed * dt
class Bar(Drawawble):
LIMIT = 15
def __init__(self):
super().__init__(pygame.image.load(TEXTURE_BAR))
self.texture = pygame.transform.smoothscale(self.texture, pygame.math.Vector2(self.texture.get_size()) / 3)
self.texture = pygame.transform.rotate(self.texture, 90)
def get_limits(y, limit, height, bottom):
return y > limit, y < (height - bottom) - limit
def slide_collision(a, b, goal):
def slide(a, b, goal):
x, y = goal
if y > 0:
a.bottom = b.top
else:
a.top = b.bottom
if x > 0:
a.right = b.left
else:
a.left = b.right
return a
direcction = [False, False]
x, y = goal
for i, vec in enumerate(((0, x), (y, 0))):
direcction[i] = a.colliderect(b)
if direcction[i]:
a = slide(a, b, vec)
return a, direcction
def collision_process():
pass
class BarIA(Bar, metaclass=Singleton):
def __init__(self):
super().__init__()
self.position = pygame.math.Vector2(SCREEN_SIZE[0] - (Bar.LIMIT + self.texture.get_rect().right), Bar.LIMIT)
def update(self, dt):
ball = Ball()
self.position.y = ball.position.y - (self.texture.get_rect().bottom / 2)
class BarPlayer(Bar, metaclass=Singleton):
def __init__(self):
super().__init__()
self.position = pygame.math.Vector2(Bar.LIMIT, Bar.LIMIT)
def update(self, dt):
width, height = SCREEN_SIZE
limit_top, limit_bottom = get_limits(self.position.y, Bar.LIMIT, height, self.texture.get_height())
keys = pygame.key.get_pressed()
if keys[pygame.locals.K_w] and limit_top:
self.position.y -= 0.25 * dt
if keys[pygame.locals.K_s] and limit_bottom:
self.position.y += 0.25 * dt
ball = Ball()
rect_player = self.texture.get_rect().move(self.position)
rect_ball = ball.texture.get_rect().move(ball.position)
rect_player, direcction = slide_collision(rect_player, rect_ball, ball.speed)
if direcction[0]:
ball.speed.x *= -1
if direcction[1]:
ball.speed.y *= -1
if __name__ == "__main__":
pygame.init()
running = True
screen = pygame.display.set_mode(SCREEN_SIZE)
clock = pygame.time.Clock()
pygame.display.set_caption("Pong")
dt = 1.0
bar_player = BarPlayer()
bar_ia = BarIA()
ball = Ball()
entities = bar_player, bar_ia, ball
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
for ent in entities:
ent.update(dt)
screen.fill((255, 255, 255))
for ent in entities:
ent.blit(screen)
pygame.display.update()
dt = clock.tick(60)
pygame.quit()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment