game_qu.getting_started.pong (example game) API documentation
Description: This is an example of a simple game of pong made using the game engine. Click the see 'Expand Source Code' button below to see the code.

# Module `game_qu.getting_started.pong (example game)`

This is an example of a simple game of pong made using the game engine. Click the see 'Expand Source Code' button below to see the code.

Expand source code

    """This is an example of a simple game of pong made using the game engine. Click the see 'Expand Source Code' button below
    to see the code."""

    from game_qu.base.library_changer import LibraryChanger
    from game_qu.base.colors import *

    # This must be before the other imports, so we can actually modify the constants. Otherwise, the constants will remain the
    # same as the default values.
    LibraryChanger.set_game_library("pygame")
    LibraryChanger.set_screen_dimensions(800, 600)
    LibraryChanger.set_background_color(black)

    # The rest of the imports
    from game_qu.gui_components.screen import Screen
    from game_qu.gui_components.component import Component
    from game_qu.gui_components.text_box import TextBox
    from game_qu.base.important_variables import *
    from game_qu.base.velocity_calculator import VelocityCalculator
    from game_qu.base.utility_functions import key_is_pressed, render_ellipse
    from game_qu.math.vector_2d import Vector2D
    from game_qu.base.engines import CollisionsEngine
    from game_qu.base.game_runner_function import run_game
    import math

    class Player(Component):
        """The paddles of the game of Pong"""

        up_key = None
        down_key = None
        velocity = VelocityCalculator.get_velocity(SCREEN_HEIGHT, 2000)
        length = VelocityCalculator.get_dimension(SCREEN_LENGTH, 3.5)
        height = VelocityCalculator.get_dimension(SCREEN_HEIGHT, 33)

        def __init__(self, up_key, down_key, base_left_edge, color):
            """Initializes the object"""

            super().__init__()
            self.set_color(color)

            self.up_key = up_key
            self.down_key = down_key
            self.left_edge = base_left_edge

            self.reset()

        def run(self):
            """Runs the movement of the player"""

            if key_is_pressed(self.up_key):
                self.top_edge -= VelocityCalculator.get_distance(self.velocity)

            if key_is_pressed(self.down_key):
                self.top_edge += VelocityCalculator.get_distance(self.velocity)

            self.top_edge = max(0, self.top_edge)
            self.top_edge = min(SCREEN_HEIGHT - self.height, self.top_edge)

        def reset(self):
            """Resets all the variables to the start of the game"""

            middle_of_screen = (SCREEN_HEIGHT - self.height) / 2
            self.top_edge = middle_of_screen

    class Ball(Component):
        """The ball of the game pong"""

        base_velocity = VelocityCalculator.get_velocity(SCREEN_LENGTH, 700)
        velocity = base_velocity

        # The velocity increases by 5% every time it hits the ball
        velocity_multiplier = 1.05

        length = VelocityCalculator.get_dimension(SCREEN_HEIGHT, 6)
        height = length
        vector = None

        def __init__(self):
            """Initializes the object"""

            super().__init__()
            self.reset()  # Sets the variables to the start of the game

        def reset(self):
            """Resets all the variables so they are the same as the start of the game"""

            self.left_edge = SCREEN_LENGTH / 2
            self.top_edge = SCREEN_HEIGHT / 2
            self.velocity = self.base_velocity
            self.vector = Vector2D(math.pi / 4, 1).normalize()  # A 45-degree angle upwards

            self.set_color(white)

        def run(self):
            """Moves the ball across the screen"""

            # First move the ball
            displacement_vector = self.vector.get_vector_multiplied_by_scalar(VelocityCalculator.delta_time * self.velocity)
            self.left_edge += displacement_vector.get_x_magnitude()
            self.top_edge += displacement_vector.get_y_magnitude()

            # Then check if the ball has hit the top or bottom of the screen. This should be after movement, so the ball is
            # always rendered within the screen (rendering is called after the run method)
            if self.top_edge < 0:
                self.vector.set_y_magnitude(-self.vector.get_y_magnitude())
                self.top_edge = 0

            if self.bottom_edge > SCREEN_HEIGHT:
                self.vector.set_y_magnitude(-self.vector.get_y_magnitude())
                self.set_bottom_edge(SCREEN_HEIGHT)

        def change_horizontal_direction(self):
            """Changes the horizontal direction of the ball"""

            self.vector.set_x_magnitude(-self.vector.get_x_magnitude())
            self.velocity *= self.velocity_multiplier

        def render(self):
            """Renders the ball onto the screen (renders a circle instead of the default rectangle)"""

            render_ellipse(self.left_edge, self.top_edge, self.length, self.height, self.color)

    class MainScreen(Screen):
        """The main screen of the game. This is where the game is played"""

        # The game objects
        player1 = Player(KEY_W, KEY_S, 0, blue)
        player2 = Player(KEY_UP, KEY_DOWN, SCREEN_LENGTH - Player.length, red)
        ball = Ball()

        # Keeping track of the score
        player1_score = 0
        player2_score = 0
        score_text_box = TextBox("", 35, light_gray, black, True)

        def __init__(self):
            """Initializes the object"""

            super().__init__("", light_gray)
            self.update_score_text_box()
            self.score_text_box.set_is_rendering_background(False)  # So the text does not have a background color under it
            self.score_text_box.percentage_set_dimensions(20, 0, 60, 10)

            # The order of the items in the list affects the order that their run method and render methods are called. The
            # text box should be run and rendered first so the ball and players can be rendered on top of it.
            self.components = [self.score_text_box, self.player1, self.player2, self.ball]

        def run(self):
            """Runs all the collision logic"""

            if CollisionsEngine.is_collision(self.ball, self.player1):
                self.ball.change_horizontal_direction()
                self.ball.set_color(self.player1.get_color())
                self.ball.set_left_edge(self.player1.right_edge)

            if CollisionsEngine.is_collision(self.ball, self.player2):
                self.ball.change_horizontal_direction()
                self.ball.set_color(self.player2.get_color())
                self.ball.set_right_edge(self.player2.left_edge)

            if self.ball.right_edge < 0:
                self.player2_score += 1
                self.update_score_text_box()

            if self.ball.left_edge > SCREEN_LENGTH:
                self.player1_score += 1
                self.update_score_text_box()

        def update_score_text_box(self):
            """Updates the score of the score that the game displays"""

            score_text = f"Player1: {self.player1_score}     Player2: {self.player2_score}"
            self.score_text_box.set_text(score_text)

            self.player1.reset()
            self.player2.reset()
            self.ball.reset()

    if __name__ == "__main__":
        # Finally running the game
        run_game(MainScreen())

## Classes

`class Ball`

  The ball of the game pong

  Initializes the object

  Expand source code

      class Ball(Component):
          """The ball of the game pong"""

          base_velocity = VelocityCalculator.get_velocity(SCREEN_LENGTH, 700)
          velocity = base_velocity

          # The velocity increases by 5% every time it hits the ball
          velocity_multiplier = 1.05

          length = VelocityCalculator.get_dimension(SCREEN_HEIGHT, 6)
          height = length
          vector = None

          def __init__(self):
              """Initializes the object"""

              super().__init__()
              self.reset()  # Sets the variables to the start of the game

          def reset(self):
              """Resets all the variables so they are the same as the start of the game"""

              self.left_edge = SCREEN_LENGTH / 2
              self.top_edge = SCREEN_HEIGHT / 2
              self.velocity = self.base_velocity
              self.vector = Vector2D(math.pi / 4, 1).normalize()  # A 45-degree angle upwards

              self.set_color(white)

          def run(self):
              """Moves the ball across the screen"""

              # First move the ball
              displacement_vector = self.vector.get_vector_multiplied_by_scalar(VelocityCalculator.delta_time * self.velocity)
              self.left_edge += displacement_vector.get_x_magnitude()
              self.top_edge += displacement_vector.get_y_magnitude()

              # Then check if the ball has hit the top or bottom of the screen. This should be after movement, so the ball is
              # always rendered within the screen (rendering is called after the run method)
              if self.top_edge < 0:
                  self.vector.set_y_magnitude(-self.vector.get_y_magnitude())
                  self.top_edge = 0

              if self.bottom_edge > SCREEN_HEIGHT:
                  self.vector.set_y_magnitude(-self.vector.get_y_magnitude())
                  self.set_bottom_edge(SCREEN_HEIGHT)

          def change_horizontal_direction(self):
              """Changes the horizontal direction of the ball"""

              self.vector.set_x_magnitude(-self.vector.get_x_magnitude())
              self.velocity *= self.velocity_multiplier

          def render(self):
              """Renders the ball onto the screen (renders a circle instead of the default rectangle)"""

              render_ellipse(self.left_edge, self.top_edge, self.length, self.height, self.color)

  ### Ancestors

  - Component
  - Dimensions

  ### Class variables

  `var base_velocity`
  `var height`
  `var length`
  `var vector`
  `var velocity`
  `var velocity_multiplier`

  ### Methods

  `def change_horizontal_direction(self)`

    Changes the horizontal direction of the ball

    Expand source code

        def change_horizontal_direction(self):
            """Changes the horizontal direction of the ball"""

            self.vector.set_x_magnitude(-self.vector.get_x_magnitude())
            self.velocity *= self.velocity_multiplier

  `def render(self)`

    Renders the ball onto the screen (renders a circle instead of the default rectangle)

    Expand source code

        def render(self):
            """Renders the ball onto the screen (renders a circle instead of the default rectangle)"""

            render_ellipse(self.left_edge, self.top_edge, self.length, self.height, self.color)

  `def reset(self)`

    Resets all the variables so they are the same as the start of the game

    Expand source code

        def reset(self):
            """Resets all the variables so they are the same as the start of the game"""

            self.left_edge = SCREEN_LENGTH / 2
            self.top_edge = SCREEN_HEIGHT / 2
            self.velocity = self.base_velocity
            self.vector = Vector2D(math.pi / 4, 1).normalize()  # A 45-degree angle upwards

            self.set_color(white)

  `def run(self)`

    Moves the ball across the screen

    Expand source code

        def run(self):
            """Moves the ball across the screen"""

            # First move the ball
            displacement_vector = self.vector.get_vector_multiplied_by_scalar(VelocityCalculator.delta_time * self.velocity)
            self.left_edge += displacement_vector.get_x_magnitude()
            self.top_edge += displacement_vector.get_y_magnitude()

            # Then check if the ball has hit the top or bottom of the screen. This should be after movement, so the ball is
            # always rendered within the screen (rendering is called after the run method)
            if self.top_edge < 0:
                self.vector.set_y_magnitude(-self.vector.get_y_magnitude())
                self.top_edge = 0

            if self.bottom_edge > SCREEN_HEIGHT:
                self.vector.set_y_magnitude(-self.vector.get_y_magnitude())
                self.set_bottom_edge(SCREEN_HEIGHT)

  ### Inherited members

  - `Component`:
    - `bottom_edge`
    - `get_scaled_dimensions`
    - `got_clicked`
    - `horizontal_midpoint`
    - `mouse_enter_function`
    - `mouse_exit_function`
    - `number_set_dimensions`
    - `percentage_set_dimensions`
    - `right_edge`
    - `set_color`
    - `set_mouse_enter_function`
    - `set_mouse_exit_function`
    - `set_mouse_functions`
    - `vertical_midpoint`
`class MainScreen`

  The main screen of the game. This is where the game is played

  Initializes the object

  Expand source code

      class MainScreen(Screen):
          """The main screen of the game. This is where the game is played"""

          # The game objects
          player1 = Player(KEY_W, KEY_S, 0, blue)
          player2 = Player(KEY_UP, KEY_DOWN, SCREEN_LENGTH - Player.length, red)
          ball = Ball()

          # Keeping track of the score
          player1_score = 0
          player2_score = 0
          score_text_box = TextBox("", 35, light_gray, black, True)

          def __init__(self):
              """Initializes the object"""

              super().__init__("", light_gray)
              self.update_score_text_box()
              self.score_text_box.set_is_rendering_background(False)  # So the text does not have a background color under it
              self.score_text_box.percentage_set_dimensions(20, 0, 60, 10)

              # The order of the items in the list affects the order that their run method and render methods are called. The
              # text box should be run and rendered first so the ball and players can be rendered on top of it.
              self.components = [self.score_text_box, self.player1, self.player2, self.ball]

          def run(self):
              """Runs all the collision logic"""

              if CollisionsEngine.is_collision(self.ball, self.player1):
                  self.ball.change_horizontal_direction()
                  self.ball.set_color(self.player1.get_color())
                  self.ball.set_left_edge(self.player1.right_edge)

              if CollisionsEngine.is_collision(self.ball, self.player2):
                  self.ball.change_horizontal_direction()
                  self.ball.set_color(self.player2.get_color())
                  self.ball.set_right_edge(self.player2.left_edge)

              if self.ball.right_edge < 0:
                  self.player2_score += 1
                  self.update_score_text_box()

              if self.ball.left_edge > SCREEN_LENGTH:
                  self.player1_score += 1
                  self.update_score_text_box()

          def update_score_text_box(self):
              """Updates the score of the score that the game displays"""

              score_text = f"Player1: {self.player1_score}     Player2: {self.player2_score}"
              self.score_text_box.set_text(score_text)

              self.player1.reset()
              self.player2.reset()
              self.ball.reset()

  ### Ancestors

  - Screen
  - Component
  - Dimensions

  ### Class variables

  `var ball`
  `var player1`
  `var player1_score`
  `var player2`
  `var player2_score`
  `var score_text_box`

  ### Methods

  `def run(self)`

    Runs all the collision logic

    Expand source code

        def run(self):
            """Runs all the collision logic"""

            if CollisionsEngine.is_collision(self.ball, self.player1):
                self.ball.change_horizontal_direction()
                self.ball.set_color(self.player1.get_color())
                self.ball.set_left_edge(self.player1.right_edge)

            if CollisionsEngine.is_collision(self.ball, self.player2):
                self.ball.change_horizontal_direction()
                self.ball.set_color(self.player2.get_color())
                self.ball.set_right_edge(self.player2.left_edge)

            if self.ball.right_edge < 0:
                self.player2_score += 1
                self.update_score_text_box()

            if self.ball.left_edge > SCREEN_LENGTH:
                self.player1_score += 1
                self.update_score_text_box()

  `def update_score_text_box(self)`

    Updates the score of the score that the game displays

    Expand source code

        def update_score_text_box(self):
            """Updates the score of the score that the game displays"""

            score_text = f"Player1: {self.player1_score}     Player2: {self.player2_score}"
            self.score_text_box.set_text(score_text)

            self.player1.reset()
            self.player2.reset()
            self.ball.reset()

  ### Inherited members

  - `Screen`:
    - `bottom_edge`
    - `get_components`
    - `get_scaled_dimensions`
    - `got_clicked`
    - `hide`
    - `horizontal_midpoint`
    - `mouse_enter_function`
    - `mouse_exit_function`
    - `number_set_dimensions`
    - `percentage_set_dimensions`
    - `render`
    - `render_background`
    - `right_edge`
    - `set_background_color`
    - `set_color`
    - `set_is_visible`
    - `set_mouse_enter_function`
    - `set_mouse_exit_function`
    - `set_mouse_functions`
    - `set_path_to_background_image`
    - `show`
    - `vertical_midpoint`
`class Player (up_key, down_key, base_left_edge, color)`

  The paddles of the game of Pong

  Initializes the object

  Expand source code

      class Player(Component):
          """The paddles of the game of Pong"""

          up_key = None
          down_key = None
          velocity = VelocityCalculator.get_velocity(SCREEN_HEIGHT, 2000)
          length = VelocityCalculator.get_dimension(SCREEN_LENGTH, 3.5)
          height = VelocityCalculator.get_dimension(SCREEN_HEIGHT, 33)

          def __init__(self, up_key, down_key, base_left_edge, color):
              """Initializes the object"""

              super().__init__()
              self.set_color(color)

              self.up_key = up_key
              self.down_key = down_key
              self.left_edge = base_left_edge

              self.reset()

          def run(self):
              """Runs the movement of the player"""

              if key_is_pressed(self.up_key):
                  self.top_edge -= VelocityCalculator.get_distance(self.velocity)

              if key_is_pressed(self.down_key):
                  self.top_edge += VelocityCalculator.get_distance(self.velocity)

              self.top_edge = max(0, self.top_edge)
              self.top_edge = min(SCREEN_HEIGHT - self.height, self.top_edge)

          def reset(self):
              """Resets all the variables to the start of the game"""

              middle_of_screen = (SCREEN_HEIGHT - self.height) / 2
              self.top_edge = middle_of_screen

  ### Ancestors

  - Component
  - Dimensions

  ### Class variables

  `var down_key`
  `var height`
  `var length`
  `var up_key`
  `var velocity`

  ### Methods

  `def reset(self)`

    Resets all the variables to the start of the game

    Expand source code

        def reset(self):
            """Resets all the variables to the start of the game"""

            middle_of_screen = (SCREEN_HEIGHT - self.height) / 2
            self.top_edge = middle_of_screen

  `def run(self)`

    Runs the movement of the player

    Expand source code

        def run(self):
            """Runs the movement of the player"""

            if key_is_pressed(self.up_key):
                self.top_edge -= VelocityCalculator.get_distance(self.velocity)

            if key_is_pressed(self.down_key):
                self.top_edge += VelocityCalculator.get_distance(self.velocity)

            self.top_edge = max(0, self.top_edge)
            self.top_edge = min(SCREEN_HEIGHT - self.height, self.top_edge)

  ### Inherited members

  - `Component`:
    - `bottom_edge`
    - `get_scaled_dimensions`
    - `got_clicked`
    - `horizontal_midpoint`
    - `mouse_enter_function`
    - `mouse_exit_function`
    - `number_set_dimensions`
    - `percentage_set_dimensions`
    - `render`
    - `right_edge`
    - `set_color`
    - `set_mouse_enter_function`
    - `set_mouse_exit_function`
    - `set_mouse_functions`
    - `vertical_midpoint`