Advertisement
Windspar

Pygame Simple Boiler Plate With Bouncing Ball Example

Feb 19th, 2021
905
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.90 KB | None | 0 0
  1. import pygame
  2. import random
  3. from pygame.sprite import Group, Sprite
  4.  
  5. # Simple state
  6. class State:
  7.     def __init__(self, engine):
  8.         self.engine = engine
  9.  
  10.     def on_draw(self, surface):
  11.         pass
  12.  
  13.     def on_event(self, event):
  14.         pass
  15.  
  16.     def on_update(self, delta, ticks):
  17.         pass
  18.  
  19. # Simple display and state manager
  20. class DisplayEngine:
  21.     def __init__(self, caption, width, height, flags=0):
  22.         pygame.display.set_caption(caption)
  23.         self.surface = pygame.display.set_mode((width, height), flags)
  24.         self.rect = self.surface.get_rect()
  25.         self.clock = pygame.time.Clock()
  26.         self.running = False
  27.         self.delta = 0
  28.         self.fps = 60
  29.  
  30.         self.state = State(self)
  31.         self.on_quit = self.quit
  32.  
  33.     @property
  34.     def width(self):
  35.         return self.rect.width
  36.  
  37.     @property
  38.     def height(self):
  39.         return self.rect.height
  40.  
  41.     @property
  42.     def size(self):
  43.         return self.rect.size
  44.  
  45.     def main_loop(self):
  46.         self.running = True
  47.         while self.running:
  48.             for event in pygame.event.get():
  49.                 if event.type == pygame.QUIT:
  50.                     self.on_quit()
  51.                 else:
  52.                     self.state.on_event(event)
  53.  
  54.             ticks = pygame.time.get_ticks()
  55.             self.state.on_draw(self.surface)
  56.             self.state.on_update(self.delta, ticks)
  57.             pygame.display.flip()
  58.             self.delta = self.clock.tick(self.fps)
  59.  
  60.     def quit(self):
  61.         self.running = False
  62.  
  63. def rnd(start, end):
  64.     return random.randint(start, end) - int(end * 0.5)
  65.  
  66. class Ball(Sprite):
  67.     velocity = 0.1
  68.     radius = 7
  69.  
  70.     def __init__(self, image, position):
  71.         Sprite.__init__(self)
  72.         self.image = image
  73.         self.rect = self.image.get_rect(center=position)
  74.         self.center = pygame.Vector2(self.rect.center)
  75.         self.vector = pygame.Vector2(rnd(0, 21), rnd(0, 21))
  76.  
  77.         while self.vector == pygame.Vector2():
  78.             self.vector = pygame.Vector2(rnd(0, 21), rnd(0, 21))
  79.  
  80.         self.vector.normalize_ip()
  81.  
  82.     def update(self, delta, group):
  83.         self.center += self.vector * delta * Ball.velocity
  84.         self.rect.center = self.center
  85.  
  86.         for item in group:
  87.             if item != self:
  88.                 if isinstance(item, Ball):
  89.                     if item.center.distance_to(self.center) < Ball.radius + 1:
  90.                         self.vector.reflect_ip(item.vector)
  91.                 else:
  92.                     if item.rect.colliderect(self.rect):
  93.                         self.vector.reflect_ip(item.vector)
  94.  
  95. class Wall(Sprite):
  96.     def __init__(self, image, position, vector):
  97.         Sprite.__init__(self)
  98.         self.image = image
  99.         self.rect = image.get_rect(topleft=position)
  100.         self.vector = vector
  101.  
  102. class BounceBall(State):
  103.     def __init__(self, engine):
  104.         State.__init__(self, engine)
  105.         self.ball_tick = 2000
  106.         self.ball_timer = self.ball_tick * 2
  107.         self.max_balls = 20
  108.  
  109.         self.all_sprites = Group()
  110.         self.balls_group = Group()
  111.         self.create_images()
  112.  
  113.         rect = engine.rect
  114.         self.add_wall("wallh", (0, 0), (0, -1))
  115.         self.add_wall("wallh", (0, rect.h - 10), (0, 1))
  116.         self.add_wall("wallv", (0, 0), (1, 0))
  117.         self.add_wall("wallv", (rect.w - 10, 0), (-1, 0))
  118.  
  119.         self.add_ball()
  120.  
  121.     def create_images(self):
  122.         self.images = {}
  123.         size = Ball.radius * 2
  124.         surface = pygame.Surface((size, size), pygame.SRCALPHA)
  125.         surface.fill((0, 0, 0, 0))
  126.         pos = Ball.radius, Ball.radius,
  127.         pygame.draw.circle(surface, pygame.Color("gray40"), pos, Ball.radius)
  128.         self.images['ball'] = surface
  129.  
  130.         surface = pygame.Surface((self.engine.rect.width, 10))
  131.         surface.fill(pygame.Color("beige"))
  132.         self.images["wallh"] = surface
  133.  
  134.         surface = pygame.Surface((10, self.engine.rect.height))
  135.         surface.fill(pygame.Color("beige"))
  136.         self.images["wallv"] = surface
  137.  
  138.     def add_wall(self, name, position, vector):
  139.         wall = Wall(self.images[name], position, vector)
  140.         self.all_sprites.add(wall)
  141.  
  142.     def add_ball(self):
  143.         ball = Ball(self.images['ball'], self.engine.rect.center)
  144.         self.all_sprites.add(ball)
  145.         self.balls_group.add(ball)
  146.  
  147.     def on_draw(self, surface):
  148.         surface.fill(pygame.Color('black'))
  149.         self.all_sprites.draw(surface)
  150.  
  151.     def on_update(self, delta, ticks):
  152.         self.balls_group.update(delta, self.all_sprites)
  153.  
  154.         if len(self.balls_group) < self.max_balls:
  155.             if ticks > self.ball_timer:
  156.                 self.ball_timer = ticks + self.ball_tick
  157.                 self.add_ball()
  158.  
  159. def main():
  160.     pygame.init()
  161.     engine = DisplayEngine("Bouncing Balls", 800, 600)
  162.     state = BounceBall(engine)
  163.     engine.state = state
  164.     engine.main_loop()
  165.  
  166. main()
  167.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement