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
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
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
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
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