junghu1124

original source

May 11th, 2023
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.73 KB | None | 0 0
  1. import abc
  2. from typing import Tuple
  3.  
  4. import numpy as np
  5. import pygame
  6. from pygame import Color
  7.  
  8. pygame.init()
  9.  
  10. screen_width = 320
  11. screen_height = 320
  12.  
  13. background_color = (255, 255, 255)  # white
  14.  
  15. screen_size = (screen_width, screen_height)
  16.  
  17. clock = pygame.time.Clock()
  18.  
  19. screen = pygame.display.set_mode(screen_size)
  20. pygame.display.set_caption("Collision at boundary")
  21.  
  22.  
  23. class Vector2D:
  24.     @staticmethod
  25.     def from_tuple(vector):
  26.         return Vector2D(vector[0], vector[1])
  27.  
  28.     def __init__(self, x=0.0, y=0.0):
  29.         self.x = x
  30.         self.y = y
  31.  
  32.     def direction(self):
  33.         return np.arctan(self.y / self.x)
  34.  
  35.     def to_tuple(self):
  36.         return self.x, self.y
  37.  
  38.     def norm(self):
  39.         return (self.x ** 2 + self.y ** 2) ** 0.5
  40.  
  41.     def normalize(self):
  42.         self.x /= self.norm()
  43.         self.y /= self.norm()
  44.  
  45.     def normalized(self):
  46.         return Vector2D(self.x / self.norm(), self.y / self.norm())
  47.  
  48.     def __add__(self, other):
  49.         return Vector2D(self.x + other.x, self.y + other.y)
  50.  
  51.     def __sub__(self, other):
  52.         return Vector2D(self.x - other.x, self.y - other.y)
  53.  
  54.     def __mul__(self, other):
  55.         if isinstance(other, float) or isinstance(other, int):
  56.             return Vector2D(self.x * other, self.y * other)
  57.         elif isinstance(other, Vector2D):
  58.             return self.x * other.x + self.y * other.y
  59.  
  60.     def __rmul__(self, other):
  61.         if isinstance(other, float) or isinstance(other, int):
  62.             return Vector2D(self.x * other, self.y * other)
  63.  
  64.     def __truediv__(self, other):
  65.         if isinstance(other, float) or isinstance(other, int):
  66.             return Vector2D(self.x / other, self.y / other)
  67.  
  68.     def __str__(self):
  69.         return "Vector2D: " + str(self.to_tuple())
  70.  
  71.  
  72. class Shape(metaclass=abc.ABCMeta):
  73.     def __init__(
  74.             self,
  75.             cur_screen: pygame.surface.Surface,
  76.             coordinates: Tuple[int, int],
  77.             initial_v: Tuple[float, float],
  78.             mass: int,
  79.             color: Color
  80.     ):
  81.         self.coors = Vector2D.from_tuple(coordinates)
  82.         self.velocity = Vector2D.from_tuple(initial_v)
  83.         self.mass = mass
  84.         self.screen = cur_screen
  85.         self.color = color
  86.  
  87.         self.hit_flag = False
  88.  
  89.     @abc.abstractmethod
  90.     def draw(self):
  91.         pass
  92.  
  93.     def move(self):
  94.         self.coors += self.velocity
  95.  
  96.  
  97. class Circle(Shape):
  98.     def __init__(
  99.             self,
  100.             cur_screen: pygame.surface.Surface,
  101.             coordinates: Tuple[int, int],
  102.             initial_v: Tuple[float, float],
  103.             mass: int,
  104.             color: Color,
  105.             radius: int,
  106.     ):
  107.         super().__init__(cur_screen, coordinates, initial_v, mass, color)
  108.         self.radius = radius
  109.  
  110.     def draw(self):
  111.         pygame.draw.circle(self.screen, self.color, self.coors.to_tuple(), self.radius)
  112.  
  113.     def detect_wall_collision(self):
  114.         boundary = self.screen.get_size()
  115.         if self.coors.x - self.radius <= 0 or self.coors.x + self.radius >= boundary[0]:
  116.             self.velocity = Vector2D(-self.velocity.x, self.velocity.y)
  117.         if self.coors.y - self.radius <= 0 or self.coors.y + self.radius >= boundary[1]:
  118.             self.velocity = Vector2D(self.velocity.x, -self.velocity.y)
  119.  
  120.  
  121. def detect_collision(body1: Circle, body2: Circle):
  122.     distance_v = body1.coors - body2.coors
  123.     rad_sum = body1.radius + body2.radius
  124.     if distance_v.norm() <= rad_sum:
  125.         return True
  126.     return False
  127.  
  128.  
  129. def collision(body1: Shape, body2: Shape):
  130.     m1 = body1.mass
  131.     m2 = body2.mass
  132.     v1_i = body1.velocity
  133.     v2_i = body2.velocity
  134.  
  135.     d = body1.coors - body2.coors
  136.  
  137.     t = ((v2_i - v1_i) * d) * 2 / ((d * d) * (1 / m1) + (d * d) * (1 / m2))
  138.     I: Vector2D | float = d * t
  139.     v1_f = v1_i + I * (1 / m1)
  140.     v2_f = v2_i - I * (1 / m2)
  141.  
  142.     body1.velocity = v1_f
  143.     body2.velocity = v2_f
  144.  
  145.  
  146. def update_pos(circles: list):
  147.     for i in range(len(circles)):
  148.         c1 = circles[i]
  149.         for j in range(i + 1, len(circles)):
  150.             c2 = circles[j]
  151.             if detect_collision(c1, c2):
  152.                 collision(c1, c2)
  153.  
  154.         c1.detect_wall_collision()
  155.         c1.move()
  156.         c1.draw()
  157.  
  158.  
  159. circle1 = Circle(screen, (160, 80), (0.5, 1.0), 10, Color("blue"), 30)
  160. circle2 = Circle(screen, (80, 240), (-0.6, 0.3), 10, Color("green"), 30)
  161. circle3 = Circle(screen, (240, 240), (-0.8, -0.8), 10, Color("red"), 30)
  162.  
  163. circles = [circle1, circle2, circle3]
  164.  
  165. running = True
  166.  
  167.  
  168. while running:
  169.     clock.tick(120)
  170.     screen.fill(background_color)
  171.  
  172.     for event in pygame.event.get():
  173.         if event.type == pygame.QUIT:
  174.             running = False
  175.  
  176.     update_pos(circles)
  177.  
  178.     pygame.display.flip()
  179.  
Add Comment
Please, Sign In to add comment