Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

3D Game with PyOpenGl

A topic by TatorTillInfinity created Jan 26, 2025 Views: 747 Replies: 7
Viewing posts 1 to 4
Developer

Tutorial: Creating a 3D Game with PyOpenGL

Step 1: Install Required Libraries

Before you begin, make sure you have PyGame and PyOpenGL installed. These libraries will help with window management and rendering 3D objects.

In your terminal or command prompt, run:

bash
CopyEdit
pip install pygame PyOpenGL 

Step 2: Basic Folder Structure

Here is the folder structure we'll use:

bash
CopyEdit
3d_game/ │ ├── assets/               # For storing any textures, models, sounds ├── src/                  # Source code for the game │   ├── main.py           # Main game loop │   ├── engine.py         # Contains camera and movement logic │   ├── player.py         # Handles user input (WASD, mouse) │   └── physics.py        # Handles physics, e.g., preventing falling └── README.md             # Game info (optional) 

Step 3: engine.py - Setting Up OpenGL and Camera

In this file, we’ll set up OpenGL, initialize the camera, and handle basic camera movement.

python
CopyEdit
import pygame from pygame.locals import * from OpenGL.GL import * from OpenGL.GLU import * import math  # Window settings WIDTH, HEIGHT = 800, 600 screen = pygame.display.set_mode((WIDTH, HEIGHT), DOUBLEBUF | OPENGL)  # Camera settings camera_pos = [0, 0, -5]  # Camera's position in 3D space (x, y, z) camera_angle = [0, 0]    # Camera's angle (yaw, pitch)  # Initialize OpenGL and set up the camera def init_camera():     glMatrixMode(GL_PROJECTION)     glLoadIdentity()     gluPerspective(45, (WIDTH / HEIGHT), 0.1, 50.0)  # Perspective projection     glTranslatef(camera_pos[0], camera_pos[1], camera_pos[2])  # Position the camera  def update_camera():     glRotatef(camera_angle[0], 1, 0, 0)  # Rotate around X-axis (pitch)     glRotatef(camera_angle[1], 0, 1, 0)  # Rotate around Y-axis (yaw)  # Handle keyboard input for movement (WASD keys) def handle_keys():     global camera_pos     keys = pygame.key.get_pressed()      # Move forward, backward, left, right     if keys[pygame.K_w]:         camera_pos[2] += 0.1  # Move forward     if keys[pygame.K_s]:         camera_pos[2] -= 0.1  # Move backward     if keys[pygame.K_a]:         camera_pos[0] += 0.1  # Move left     if keys[pygame.K_d]:         camera_pos[0] -= 0.1  # Move right 

Step 4: player.py - Handling Mouse Look

The player file will handle mouse movement for looking around.

python
CopyEdit
import pygame from engine import camera_pos, camera_angle  # Mouse sensitivity for camera rotation MOUSE_SENSITIVITY = 0.1  def handle_mouse():     global camera_angle     mouse_x, mouse_y = pygame.mouse.get_pos()      # Calculate the movement of the mouse from the center     delta_x = mouse_x - (WIDTH // 2)     delta_y = mouse_y - (HEIGHT // 2)      # Update camera angles (yaw and pitch)     camera_angle[1] += delta_x * MOUSE_SENSITIVITY  # Rotate left/right (yaw)     camera_angle[0] -= delta_y * MOUSE_SENSITIVITY  # Rotate up/down (pitch)      # Restrict pitch angle (up/down) to prevent flipping     if camera_angle[0] > 90:         camera_angle[0] = 90     if camera_angle[0] < -90:         camera_angle[0] = -90      # Center the mouse in the window     pygame.mouse.set_pos(WIDTH // 2, HEIGHT // 2)  def update():     handle_mouse()  # Control camera with mouse     handle_keys()   # Control movement with WASD 

Step 5: physics.py - Basic Physics (Collision)

This file handles simple physics, like making sure the player doesn’t fall through the ground.

python
CopyEdit
# Simple collision check for the ground def check_collision(player_pos, ground_level=0):     if player_pos[1] < ground_level:         player_pos[1] = ground_level  # Prevent player from falling below ground 

Step 6: main.py - The Main Game Loop

This is where everything comes together: initializing the game, running the game loop, and rendering objects.

python
CopyEdit
import pygame from engine import init_camera, update_camera from player import update from physics import check_collision  # Window settings WIDTH, HEIGHT = 800, 600 screen = pygame.display.set_mode((WIDTH, HEIGHT), DOUBLEBUF | OPENGL)  # Game loop def game_loop():     clock = pygame.time.Clock()     running = True      while running:         for event in pygame.event.get():             if event.type == pygame.QUIT:                 running = False          # Clear the screen before drawing         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)          # Initialize the camera         init_camera()          # Update the player input (movement, mouse look)         update()          # Basic collision (prevent falling through the ground)         check_collision(camera_pos)          # Draw a rotating cube (just an example)         draw_cube()          # Update the display         pygame.display.flip()          # Control the frame rate         clock.tick(60)      pygame.quit()  # Function to draw a simple cube def draw_cube():     vertices = [         (1, -1, -1), (1, 1, -1), (-1, 1, -1), (-1, -1, -1),         (1, -1, 1), (1, 1, 1), (-1, -1, 1), (-1, 1, 1)     ]      edges = [         (0, 1), (1, 2), (2, 3), (3, 0),         (4, 5), (5, 6), (6, 7), (7, 4),         (0, 4), (1, 5), (2, 6), (3, 7)     ]      glBegin(GL_LINES)     for edge in edges:         for vertex in edge:             glVertex3fv(vertices[vertex])     glEnd()  # Run the game if __name__ == "__main__":     pygame.mouse.set_visible(False)  # Hide the mouse cursor     pygame.mouse.set_pos(WIDTH // 2, HEIGHT // 2)  # Center the mouse     game_loop() 

Step 7: Run the Game

  1. Open the folder containing your game files in your terminal.
  2. Run the game by typing:
    bash
    CopyEdit
    python src/main.py 
    

This will open a window with a rotating cube in 3D space. You can use the WASD keys to move the camera around and the mouse to look around.

What’s Happening in the Code?

  • engine.py: Initializes OpenGL, sets up the camera, and handles basic movement (WASD).
  • player.py: Uses the mouse to look around (pitch and yaw).
  • physics.py: Ensures the player doesn’t fall below the ground (very basic physics).
  • main.py: Contains the main game loop and rendering logic (including drawing a rotating cube).

Next Steps

Once you have the basic setup running, you can:

  • Add 3D models: Use glBindTexture() to add textures to objects or load external models like .obj files.
  • Advanced Physics: Integrate more realistic physics (e.g., using PyBullet or Pymunk).
  • Lighting: Use glEnable(GL_LIGHTING) and glLightfv() to add lighting effects to your scene.

I have a question, what do the 

│   ├── 

symbols mean in the folder structure?

Developer

3d_game/

├── assets/              # For storing textures, models, sounds

├── src/                 # Source code for the game

│   ├── main.py          # Main game loop

│   ├── engine.py        # Contains camera and movement logic

│   ├── player.py        # Handles user input (WASD, mouse)

│   └── physics.py       # Handles physics (e.g., preventing falling)

└── README.md            # Game info (optional)

Developer

 https://itch.io/t/4514927/3d-game-with-pyopengl-tutorial

Developer

The symbols , ├──, and similar lines in the folder structure are used to visually represent the hierarchy of directories and files. They are a way to show how folders and files are organized within a project. Here’s what each symbol means:

  • : This vertical line is used to continue the tree structure vertically, indicating that the items below it are part of the same hierarchy.
  • ├──: This is used to show a branch in the tree. It means that there’s a file or folder at this level, and it might have subdirectories or files below it.
  • └──: This symbol indicates the last item in a branch, showing the end of a directory or file path.

I see thanks!

Yeah it's much more clearer in the new post with the correct indentation.

Developer

The Engines Update is being worked. It will retain the same functionality with better UI.

Developer

bash

copyedit are just there to show you can copy