Skip to main content

A single-file importable 3D game engine for Python built on Pygame and OpenGL.

Project description

PyGine3D

A single-file importable 3D game engine for Python built on Pygame and OpenGL 3.3 Core.

Created by Somting — MIT License


What is it?

PyGine3D is a lightweight 3D game engine that lives in a single .py file. Drop it into your project, import it, and you have a full Unity-style game engine with GameObjects, Components, Scenes, cameras, lighting, collision, a 2D HUD overlay, and a Minecraft-style inventory — no framework setup, no project structure required.


Installation

Option 1 — pip

pip install pygine3d

Option 2 — manual

Download PyGine3D.py and drop it next to your game file. Then at the top of your script force Python to load the local file:

import sys
sys.path.insert(0, r"path/to/your/project")
import PyGine3D

Dependencies

pip install pygame PyOpenGL PyOpenGL_accelerate numpy pillow

Quick Start

import sys
sys.path.insert(0, r"C:/your/project/folder")
import PyGine3D

engine = PyGine3D.Engine(800, 600, "My Game")
scene  = engine.scene

# Add a cube
cube = scene.spawn("Cube")
cube.add_component(PyGine3D.MeshRenderer(PyGine3D.Mesh.cube()))
cube.transform.position = PyGine3D.Vec3(0, 0, -5)

# Lighting
scene.ambient_light = PyGine3D.Color(0.2, 0.2, 0.2)
scene.directional_light = PyGine3D.DirectionalLight(
    direction=PyGine3D.Vec3(-1, -2, -1),
    color=PyGine3D.Color(1.0, 0.95, 0.85)
)

# Camera
engine.camera = PyGine3D.FlyCamera(speed=5.0)

engine.run()

Core Concepts

PyGine3D uses a Unity-style Entity-Component architecture.

  • Engine — creates the window, runs the game loop
  • Scene — holds all GameObjects
  • GameObject — an entity in the world, has a Transform and Components
  • Component — behaviour attached to a GameObject, subclass to add logic
  • Transform — position, rotation (Euler degrees), scale as Vec3

API Reference

Engine

engine = PyGine3D.Engine(width, height, title, fps=60, clear_color=None)
Property / Method Description
engine.scene The active Scene
engine.camera The active Camera
engine.input The Input object
engine.hud The 2D HUD overlay
engine.time Total elapsed seconds
engine.frame Current frame number
engine.on_start Callback — called once before the loop
engine.on_update Callback — called every frame with dt
engine.on_gui Callback — called every frame for HUD drawing
engine.on_quit Callback — called when the engine stops
engine.set_icon(path_or_surface) Set a custom window icon
engine.quit() Stop the engine from anywhere
engine.run() Start the game loop

Scene

scene = engine.scene
Method Description
scene.spawn(name) Create and return a new GameObject
scene.destroy(go) Remove a GameObject from the scene
scene.find(name) Find a GameObject by name
scene.find_by_tag(tag) Find all GameObjects with a tag
scene.check_collision(collider) Returns list of overlapping BoxColliders
scene.ambient_light Color — ambient light applied to all objects
scene.directional_light DirectionalLight — main directional light

GameObject

go = scene.spawn("MyObject")
Property / Method Description
go.name Name string
go.active Bool — if False, object is skipped
go.transform The Transform
go.tags List of tag strings
go.add_component(comp) Attach a component, returns it
go.get_component(cls) Get first component of type

Transform

go.transform.position = PyGine3D.Vec3(0, 1, -5)
go.transform.rotation = PyGine3D.Vec3(0, 45, 0)   # Euler degrees
go.transform.scale    = PyGine3D.Vec3(1, 1, 1)

Component

Subclass Component to add custom behaviour to any GameObject.

class Spinner(PyGine3D.Component):
    def on_start(self):
        pass  # called once when the scene starts

    def on_update(self, dt):
        self.owner.transform.rotation.y += 60 * dt  # spin 60 deg/sec

    def on_destroy(self):
        pass  # called when the GameObject is destroyed

cube.add_component(Spinner())

Vec3

v = PyGine3D.Vec3(x, y, z)
Method / Property Description
v + v2, v - v2, v * scalar Arithmetic
v.dot(v2) Dot product
v.cross(v2) Cross product
v.length() Magnitude
v.normalized() Unit vector
Vec3.zero() (0, 0, 0)
Vec3.one() (1, 1, 1)
Vec3.up() (0, 1, 0)
Vec3.forward() (0, 0, -1)
Vec3.right() (1, 0, 0)

Color

c = PyGine3D.Color(r, g, b, a=1.0)   # values 0.0 to 1.0

Static helpers: Color.white(), Color.black(), Color.red(), Color.green(), Color.blue()


Mesh

PyGine3D.Mesh.cube()
PyGine3D.Mesh.sphere(radius=0.5, rings=16, sectors=16)
PyGine3D.Mesh.plane(size=10.0, divisions=4)
PyGine3D.Mesh.from_obj("path/to/model.obj")

Texture

tex = PyGine3D.Texture("path/to/image.png")
tex = PyGine3D.Texture.solid_color(r, g, b, a)   # 1x1 colour texture

Material

mat = PyGine3D.Material(texture=tex, color=PyGine3D.Color(1, 0.5, 0.2))

Both texture and color are optional. Color acts as a tint multiplied over the texture.


MeshRenderer

go.add_component(PyGine3D.MeshRenderer(mesh, material))

Renders a Mesh with a Material. Uses a built-in Phong shader automatically.


Lighting

scene.ambient_light = PyGine3D.Color(0.2, 0.2, 0.25)

scene.directional_light = PyGine3D.DirectionalLight(
    direction  = PyGine3D.Vec3(-1, -2, -1),
    color      = PyGine3D.Color(1.0, 0.95, 0.85),
    intensity  = 1.0
)

BoxCollider

go.add_component(PyGine3D.BoxCollider(PyGine3D.Vec3(0.5, 0.5, 0.5)))

# Check for overlaps
col  = go.get_component(PyGine3D.BoxCollider)
hits = scene.check_collision(col)   # returns list of BoxColliders
for h in hits:
    print(h.owner.name)

auto_collision=True is the default on quick_cube, quick_plane, and quick_box — they add a BoxCollider automatically.


Cameras

FlyCamera

First-person free-fly camera. Right-click + drag to look, WASD to move.

engine.camera = PyGine3D.FlyCamera(speed=5.0, sensitivity=0.15, fov=75)

Controls: WASD / arrow keys — move, Q/E — down/up, right-click drag — look

OrbitCamera

Orbits around a target point.

engine.camera = PyGine3D.OrbitCamera(target=PyGine3D.Vec3(0,0,0), distance=8.0)

Controls: right-click drag — orbit, scroll wheel — zoom


Input

engine.input.get_key(pygame.K_w)          # held down
engine.input.get_key_down(pygame.K_space) # just pressed this frame
engine.input.get_mouse_button(1)          # 1=left, 2=middle, 3=right
engine.input.mouse_pos                    # (x, y) tuple
engine.input.mouse_delta                  # (dx, dy) tuple

Key constants are also available directly: PyGine3D.K_W, PyGine3D.K_SPACE, PyGine3D.K_ESC, etc.


Convenience Spawners

# Uniform scale cube with optional texture/color and auto BoxCollider
quick_cube(scene, position, color, texture, scale, name, auto_collision=True)

# Flat plane
quick_plane(scene, position, size, color, texture, name, auto_collision=True)

# Non-uniform box (width/height/depth independently)
quick_box(scene, position, size=Vec3(1,1,1), color, texture, name, auto_collision=True)

Set auto_collision=False for purely decorative objects that the player should walk through.


HUD (2D Overlay)

Draw 2D elements on top of the 3D scene. Call inside engine.on_gui.

def on_gui():
    hud = engine.hud
    hud.rect(x, y, w, h, color=(0,0,0,180), border_radius=6)
    hud.text("Hello!", x, y, size=20, color=(255,255,255), shadow=True)
    hud.text_centered("Centred", x, y, w, h, size=18)
    hud.image("icon.png", x, y, w, h)
    hud.line(x1, y1, x2, y2, color=(255,255,255), width=1)
    hud.circle(cx, cy, radius, color=(255,255,255,255))
    hud.crosshair(size=10, thickness=2, color=(255,255,255,200))
    hud.panel(x, y, w, h)   # dark semi-transparent panel

engine.on_gui = on_gui

Inventory

Minecraft-style hotbar + grid inventory.

inv = PyGine3D.Inventory(engine, cols=9, rows=4)

# Add items to hotbar
inv.hotbar[0] = PyGine3D.InventoryItem("Sword",  color=(180, 180, 200))
inv.hotbar[1] = PyGine3D.InventoryItem("Torch",  count=8, color=(255, 180, 40))

# Add items to grid
inv.add_item(PyGine3D.InventoryItem("Stone", count=32, color=(120,120,120)))

# Remove item from grid
inv.remove_item("Stone")

# Get selected hotbar item
item = inv.selected_item()

def on_update(dt):
    inv.update()   # handles E to open/close, 1-9 keys, scroll wheel

def on_gui():
    inv.draw()     # renders hotbar + grid if open

engine.on_update = on_update
engine.on_gui    = on_gui

E — open/close inventory grid
1-9 — select hotbar slot
Scroll wheel — cycle hotbar selection

InventoryItem

item = PyGine3D.InventoryItem(
    name  = "Pickaxe",
    count = 1,
    icon  = "pickaxe.png",   # optional — file path or pygame.Surface
    color = (140, 120, 100)  # fallback color if no icon
)

Full Example

import sys
sys.path.insert(0, r"C:/your/project")
import PyGine3D
import pygame

engine = PyGine3D.Engine(1280, 720, "My Game", fps=60)
scene  = engine.scene

# Lighting
scene.ambient_light     = PyGine3D.Color(0.2, 0.2, 0.25)
scene.directional_light = PyGine3D.DirectionalLight(
    direction=PyGine3D.Vec3(-1, -2, -1),
    color=PyGine3D.Color(1.0, 0.95, 0.85),
    intensity=1.0
)

# Ground
floor = PyGine3D.quick_plane(scene, position=PyGine3D.Vec3(0,-0.5,0),
                              size=20, color=PyGine3D.Color(0.3,0.5,0.3))

# Cube with custom component
cube = PyGine3D.quick_cube(scene, position=PyGine3D.Vec3(0,0,-5),
                            color=PyGine3D.Color(0.8,0.3,0.2))

class Spinner(PyGine3D.Component):
    def on_update(self, dt):
        self.owner.transform.rotation.y += 45 * dt

cube.add_component(Spinner())

# Camera
engine.camera = PyGine3D.FlyCamera(speed=6.0)

# HUD
def on_gui():
    engine.hud.crosshair()
    engine.hud.text(f"Time: {engine.time:.1f}s", 10, 10, size=18)

engine.on_gui = on_gui
engine.run()

Version History

Version Notes
1.1.2 Fixed OpenGL wildcard import clobbering class names
1.1.1 Added 2D HUD overlay and Inventory system
1.1.0 Added auto_collision, quick_box, startup banner, custom icon support
1.0.0 Initial release

License

MIT License — Copyright (c) 2026 Somting

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pygine3d-1.1.3.tar.gz (24.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pygine3d-1.1.3-py3-none-any.whl (21.7 kB view details)

Uploaded Python 3

File details

Details for the file pygine3d-1.1.3.tar.gz.

File metadata

  • Download URL: pygine3d-1.1.3.tar.gz
  • Upload date:
  • Size: 24.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.0

File hashes

Hashes for pygine3d-1.1.3.tar.gz
Algorithm Hash digest
SHA256 3ac67989c1f4333002f4bed6e59338478015a7957c0cddbe8a079c7daff8aa5f
MD5 5e334c2ccb30580458efbb6118e45ed3
BLAKE2b-256 4e18514bfb92dbb28cb7309a60264bb0348f263cb932fe8aa7c4e2f2940ca17a

See more details on using hashes here.

File details

Details for the file pygine3d-1.1.3-py3-none-any.whl.

File metadata

  • Download URL: pygine3d-1.1.3-py3-none-any.whl
  • Upload date:
  • Size: 21.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.0

File hashes

Hashes for pygine3d-1.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 13520e88ebc3ebbbcb63951438226a64f1a8649883450135b959e7f74ae4d5a2
MD5 08a7c6becab6a8614f1434a07684aba3
BLAKE2b-256 cece451575e3bba840e28615ec2a5f1e38ca93edaff0d4fc235b4aa87c8b1596

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page