Hello Ridhwan! This article is for you. Today, we’re going to create an exciting Pong game using Python and the Ursina game engine. This guide will walk you through each step, explain what the code does, and give you some fun exercises to try at the end. Let’s get started!

Step 1: Setting up your workspace

  1. On your Linux computer, create a new folder called “PongGame”.
  2. Right-click on the folder and select “Open with VSCode”.

Step 2: Creating a virtual environment A virtual environment is like a special container for your project. It helps keep your project’s packages separate from other projects.

  1. Open the terminal in VSCode (View > Terminal).
  2. Type this command and press Enter:
    python3 -m venv venv
    
  3. Activate the virtual environment:
    source venv/bin/activate
    

Step 3: Installing Ursina Ursina is a game engine that makes it easier to create games in Python.

  1. In the terminal, type this command and press Enter:
    pip install ursina[extras]
    

Step 4: Creating the game file

  1. In VSCode, create a new file called “pong_game.py”.

Now, let’s start coding our Pong game! We’ll break it down into smaller parts and explain each section in detail.

Step 5: Setting up the game window Add this code to your file:

from ursina import *

app = Ursina()

window.color = color.black
camera.orthographic = True
camera.fov = 1

What this code does:

  • from ursina import * brings in all the tools we need from the Ursina engine.
  • app = Ursina() creates our game application.
  • window.color = color.black sets the background color to black.
  • camera.orthographic = True and camera.fov = 1 set up the camera to view our 2D game properly.

Step 6: Creating game objects Add this code:

left_paddle = Entity(scale=(1/32,6/32), x=-.75, model='quad', origin_x=.5, collider='box')
right_paddle = duplicate(left_paddle, x=left_paddle.x*-1, rotation_z=left_paddle.rotation_z+180)

floor = Entity(model='quad', y=-.5, origin_y=.5, collider='box', scale=(2,10), visible=False)
ceiling = duplicate(floor, y=.5, rotation_z=180, visible=False)
left_wall = duplicate(floor, x=-.5*window.aspect_ratio, rotation_z=90, visible=True)
right_wall = duplicate(floor, x=.5*window.aspect_ratio, rotation_z=-90, visible=True)

collision_cooldown = .15
ball = Entity(model='circle', scale=.05, collider='box', speed=0, collision_cooldown=collision_cooldown)

What this code does:

  • Creates the left paddle using Entity() and sets its size, position, and shape.
  • Creates the right paddle by duplicating the left paddle and adjusting its position.
  • Creates invisible floor and ceiling, and visible left and right walls.
  • Creates the ball with a circular shape and sets its initial speed to 0.

Step 7: Implementing game logic Add this code:

def update():
    ball.collision_cooldown -= time.dt
    ball.position += ball.right * time.dt * ball.speed

    left_paddle.y += (held_keys['w'] - held_keys['s']) * time.dt * 1
    right_paddle.y += (held_keys['up arrow'] - held_keys['down arrow']) * time.dt * 1

    if ball.collision_cooldown > 0:
        return

    hit_info = ball.intersects()
    if hit_info.hit:
        ball.collision_cooldown = collision_cooldown

        if hit_info.entity in (left_paddle, right_paddle, left_wall, right_wall):
            hit_info.entity.collision = False
            invoke(setattr, hit_info.entity, 'collision', False, delay=.1)
            direction_multiplier = 1
            if hit_info.entity == left_paddle:
                direction_multiplier = -1

                left_paddle.collision = False
                right_paddle.collision = True
            else:
                right_paddle.collision = False
                left_paddle.collision = True

            ball.rotation_z += 180 * direction_multiplier
            ball.rotation_z -= (hit_info.entity.world_y - ball.y) * 20 * 32 * direction_multiplier
            ball.speed *= 1.1

        else:
            ball.rotation_z *= -abs(hit_info.world_normal.normalized()[1])

        particle = Entity(model='quad', position=hit_info.world_point, scale=0, texture='circle', add_to_scene_entities=False)
        particle.animate_scale(.2, .5, curve=curve.out_expo)
        particle.animate_color(color.clear, duration=.5, curve=curve.out_expo)
        destroy(particle, delay=.5)

What this code does:

  • The update() function runs every frame of the game.
  • It moves the ball based on its speed and direction.
  • It allows players to move the paddles using ‘W’/‘S’ keys for the left paddle and up/down arrow keys for the right paddle.
  • It checks for collisions between the ball and other objects (paddles and walls).
  • When a collision occurs, it changes the ball’s direction and speed, and creates a particle effect.

Step 8: Adding game reset and input handling Add this code:

def reset():
    ball.position = (0,0,0)
    ball.rotation = (0,0,0)
    ball.speed = 10
    for paddle in (left_paddle, right_paddle):
        paddle.collision = True
        paddle.y = 0

info_text = Text("press space to play", y=-.45)

def input(key):
    if key == 'space':
        info_text.enabled = False
        reset()

    if key == 't':
        ball.speed += 5

What this code does:

  • The reset() function puts the ball back in the center and resets its speed.
  • It creates text that tells the player to press space to start.
  • The input() function handles key presses:
    • Pressing space starts the game.
    • Pressing ‘T’ increases the ball’s speed.

Step 9: Running the game Finally, add this line at the end of your file:

app.run()

This line starts the game.

Now you have a complete Pong game! To play:

  1. Use ‘W’ and ‘S’ keys to move the left paddle up and down.
  2. Use the up and down arrow keys to move the right paddle.
  3. Press the space bar to start the game.
  4. Press ‘T’ to increase the ball’s speed.

Exercises to try:

  1. Change the paddle colors: Try modifying the left_paddle and right_paddle creation to include a color. For example:

    left_paddle = Entity(scale=(1/32,6/32), x=-.75, model='quad', origin_x=.5, collider='box', color=color.red)
    
  2. Change the control keys: In the update() function, try changing the keys used to control the paddles. For example, you could use ‘A’ and ‘D’ for the left paddle instead of ‘W’ and ‘S’.

  3. Add a score display: Create two Text entities to show the scores for each player. Update these scores when the ball hits the left or right wall.

  4. Change the ball size: Modify the scale parameter when creating the ball to make it larger or smaller.

  5. Add sound effects: Use Ursina’s Audio class to add sound effects when the ball hits a paddle or when a player scores.

Remember, you can always improve the game by adding more features or changing how it looks. Have fun coding and playing your very own Pong game!