diff --git a/ball.py b/ball.py new file mode 100644 index 0000000..01277bc --- /dev/null +++ b/ball.py @@ -0,0 +1,19 @@ +from element import Element +from pygame import Surface + +class Ball(Element): + def __init__(self, surface: Surface, x: int, y: int, visible: bool = True) -> None: + super().__init__(surface, x, y, visible, False) + # this states whether the ball is released or not. + self.__is_released = False + def is_released(self) -> bool: + """ + :return: whether the ball is released or not. + """ + return self.__is_released + def set_released(self, released:bool) -> None: + """ + Set the ball as released or not. + :param bool released: the release state of the ball. + """ + self.__is_released = released \ No newline at end of file diff --git a/ball_release_event_listener.py b/ball_release_event_listener.py index 48d8036..481bcc2 100644 --- a/ball_release_event_listener.py +++ b/ball_release_event_listener.py @@ -15,10 +15,14 @@ def run(self, event, game): # retrieve the placeholder ball. placeholder_ball = game.get_window().get_element("placeholder_ball") # check if the ball is at the same position - if abs(ball.get_x() - ball.get_initial_x()) < 15 and abs(ball.get_y() - ball.get_initial_y()) < 15: + if abs(ball.get_x() - ball.get_initial_x()) < 15 and abs(ball.get_y() - ball.get_initial_y()) < 15 or ball.is_released(): return + ball.set_released(True) # disable ball. placeholder_ball.set_visible(False) + # clear dots. + for i in range(20): + game.get_window().remove_element(("dot_",str(i))) # launch new thread. self.__t = StoppableThread(target=self.__move_ball, args=(game,)) # register the thread in order to be able to kill it. diff --git a/drag_event_listener.py b/drag_event_listener.py index 176c4ce..5a7e4c7 100644 --- a/drag_event_listener.py +++ b/drag_event_listener.py @@ -1,4 +1,5 @@ from event_listener import EventListener +from element import Element import pygame class DragEventListener(EventListener): @@ -8,18 +9,27 @@ def __init__(self) -> None: self.__white_dot = pygame.transform.scale(self.__white_dot, (20, 20)) def run(self, event, game): - if pygame.mouse.get_pressed()[0] == True: - # retrieve the ball. - ball = game.get_window().get_element("ball") + # pre-register the dots. + for i in range(0, 20): + game.get_window().register_element(("dot_",str(i)), Element(self.__white_dot, 0, 0, False, False)) + # retrieve the ball. + ball = game.get_window().get_element("ball") + if pygame.mouse.get_pressed()[0] == True and not ball.is_released(): # update x and y position. ball.set_x(pygame.mouse.get_pos()[0] - 30) ball.set_y(pygame.mouse.get_pos()[1] - 30) # get the initial x and y value. ix, iy = ball.get_initial_x(), ball.get_initial_y() - for t in range(0, 150): - t = t + vx, vy = 1.1 * (ix - ball.get_x()), 1.1 * (iy - ball.get_y()) + for t in range(20): # get the inital vector values. - vx, vy = ix - ball.get_x(), iy - ball.get_y() - x = ball.get_x() + 30 + vx * t - y = -(1/2) * -9.81 * t**2 + vy * t + ball.get_y() + 30 - game.get_screen().blit(self.__white_dot, (x, y)) \ No newline at end of file + x = (ball.get_x() + 30 + vx * t) + y = (9.81 * t**2 + vy * t + ball.get_y() + 30) + if t != 0: + # retrieve the dot. + dot = game.get_window().get_element(("dot_",str(t))) + # update x and y coordinates. + dot.set_x(x) + dot.set_y(y) + # set the dot visible. + dot.set_visible(True) \ No newline at end of file diff --git a/element.py b/element.py index 3b1dd6f..b46c5d3 100644 --- a/element.py +++ b/element.py @@ -1,13 +1,14 @@ from pygame import Surface class Element(): - def __init__(self, surface:Surface, x:int, y:int, visible:bool=True) -> None: + def __init__(self, surface:Surface, x:int, y:int, visible:bool=True, allow_override:bool=False) -> None: self.__surface = surface # those are the inital x and y coordinates. (those coordinates are immutable) self.__ix, self.__iy = x, y # those are the mutable x and y coordinates. self.__x, self.__y = x, y self.__visible = visible + self.__allow_override = allow_override pass def get(self) -> tuple: """ @@ -44,6 +45,12 @@ def get_surface(self): :return: the element surface. """ return self.__surface + def allow_override(self): + """ + :return: whether the element can be overrident or not. + (another element can erase this one.) + """ + return self.__allow_override def is_visible(self): """ :return: whether the element is visible or not. (Note it can still interact.) diff --git a/game.py b/game.py index f1d86a7..5a51469 100644 --- a/game.py +++ b/game.py @@ -4,6 +4,7 @@ from player import Player from element import Element from window import Window +from ball import Ball from event_listener import EventListener from drag_event_listener import DragEventListener @@ -31,7 +32,7 @@ def __init__(self, screen:pygame.Surface, img_location:str, img_name: str, sound # register the field without public. self.get_window().register_element("field", Element(field, 0, 0)) # register the ball. - self.get_window().register_element("ball", Element(ball, 170, 450)) + self.get_window().register_element("ball", Ball(ball, 170, 450)) # register the placeholder ball. self.get_window().register_element("placeholder_ball", Element(placeholder_ball, 170, 450)) # listen to events. @@ -68,7 +69,7 @@ def setup(self): for element in self.__window.get_elements(): # retrive the object. obj = element[1] - if(obj.is_visible()): + if obj != None and obj.is_visible(): self.__screen.blit(obj.get()[0], obj.get()[1]) for event in pygame.event.get(): if event.type == pygame.QUIT: diff --git a/window.py b/window.py index d3ee42e..08a9a56 100644 --- a/window.py +++ b/window.py @@ -8,18 +8,34 @@ def register_element(self, key:str, element): :param str key: the key to pair to the given element. :param object element: the element to store. """ + # try to get the previous element bind with this key. + previous_element = self.get_element(key) + # check if this element can be overriden. + if previous_element != None and previous_element.allow_override(): + self.remove_element(key) self.__elements.append([key, element]) def get_element(self, key:str): """ If present returns the element paired with the given key else it raises RuntimeError. :param str key: the key paired to the game element. - :return: the game element. + :return: the game element or None if not found. """ for element in self.__elements: if element[0] == key: return element[1] - raise RuntimeError("element not found for key: ", key) + return None + def remove_element(self, key:str) -> bool: + """ + Removes the element paired to the given key. + :param str key: the key bind with the element to remove. + :return: whether the element has been removed or not. + """ + for element in self.__elements: + if element[0] == key: + self.__elements.remove(element) + return True + return False def get_elements(self): """ :return: the game elements.