Runespoor is a flexible, straight forward, multi-paradigm game engine that is built from the ground up with developer experience in mind.Utilizing a game loop system similar to pygame, you are able to abstract elements of your game away from the game loop as much as you'd like.
Project description
Runespoor Python 3D Game Engine
A python 3D game engine written in c++ using SDL, Assimp, OpenGL(GLAD), and GLM.
To install:
pip install Runespoor
Please note:
-
Runespoor is still in development and only dev versions are available right now. Everything is subject to change, be fixed, and improve.
-
When building from source
pkg-config
must be installed. In addition to this,GLM
must be installed and present in your c/c++ package manager's include directory. Successful attempts to compile have been made on windows withvcpkg
as the package manager.
About:
Runespoor is a flexible, straight forward, multi-paradigm game engine that is built from the ground up with developer experience in mind. Utilizing a game loop system similar to pygame, you are able to abstract elements of your game away from the game loop as much as you'd like.
For a taste of the api check out the test file:
from renderer import (
Vec3, Camera, Mesh, Object, Window, EVENT_FLAG,
Material, Shader, ShaderType, EVENT_STATE, Quaternion
)
import math
from copy import copy
# The meshes used in this testfile are not provided with the library or source files.
dim = (1280, 720)
focal_length = 10000
camera = Camera(Vec3(0.0,0.0,0.0), Vec3(0.0,0.0,0.0), *dim, focal_length, math.radians(60))
window = Window("FBX Car Test", camera, *dim, False)
# Materials are equivalent to shader programs.
default_material = Material(
Shader.from_file("./default_vertex.glsl", ShaderType.VERTEX),
Shader.from_file("./default_fragment.glsl", ShaderType.FRAGMENT)
)
default_material.set_uniform("focal_length", focal_length, "i")
# "i" means the uniform is an integer type
car_meshes = Mesh.from_file("./meshes/fbx_car/svj_PACKED.fbx")
car = Object(car_meshes,
Vec3(0.0,-100.0,500), Vec3(0,0,0), Vec3(1,1,1), material=default_material)
car2 = Object(car_meshes,
Vec3(300,0,500), Vec3(10,3.57,23.2), material=default_material)
teapot = Object(Mesh.from_file("./meshes/teapot/teapot.obj"),
Vec3(-100,0,200), Vec3(0,0,0), material=default_material)
pirate_ship = Object(Mesh.from_file("./meshes/pirate_ship/pirate_ship.obj"),
Vec3(-100,-100,300), Vec3(0,10,0), material=default_material)
render_list = [
car,
car2,
teapot,
pirate_ship
]
window.lock_mouse(True)
vel_yaw = 0.0
vel = 0.0
frict = 0.1
accel = 5
cam_dist = 300.0
magic_turn_dampener = 4
mouse_sensitivity = 10
counter = 0
counter_speed = 1
while not window.event.check_flag(EVENT_FLAG.QUIT) and window.event.get_flag(EVENT_FLAG.KEY_ESCAPE) != EVENT_STATE.PRESSED:
# Use WASD keys.
if window.event.get_flag(EVENT_FLAG.KEY_d) == EVENT_STATE.PRESSED:
# ROTATE RIGHT
vel_yaw -= 0.3
if window.event.get_flag(EVENT_FLAG.KEY_a) == EVENT_STATE.PRESSED:
# ROTATE LEFT
vel_yaw += 0.3
if window.event.get_flag(EVENT_FLAG.KEY_s) == EVENT_STATE.PRESSED:
# BACKWARDS
vel -= accel
if window.event.get_flag(EVENT_FLAG.KEY_w) == EVENT_STATE.PRESSED:
# FORWARD
vel += accel
# apply a quaternion rotation arround the vector vec3(1,1,0)
teapot.rotation = Quaternion.from_axis_angle(Vec3(1,1,0), math.radians(counter))
# Clamp and rotate, then apply friction.
vel_yaw = min(max(vel_yaw, -100), 100) if abs(vel_yaw) > frict else 0
car.rotation.rotate_yaw(-vel_yaw/magic_turn_dampener * window.dt)
vel_yaw -= math.copysign(frict, vel_yaw)
# Clamp the velocity.
vel = min(max(vel, -1000), 1000) if abs(vel) > frict else 0
# Move the car forwards with its forwards vector with a magnitude of `vel` and apply friction
car.position += -car.rotation.forward * vel * window.dt # window.dt is deltatime
vel -= math.copysign(frict, vel)
# Rotate the camera
cam_rot = Quaternion.from_quat(camera.rotation)
yaw_rot = 0 # capture the yaw rot so we can apply it to the quat later in the case where the camera is clamped
if window.event.check_flag(EVENT_FLAG.MOUSE_MOTION):
cam_rot.rotate_yaw(yaw_rot := -math.radians(window.event.mouse.rel_x * mouse_sensitivity * window.dt))
cam_rot.rotate(cam_rot.right, math.radians(window.event.mouse.rel_y * mouse_sensitivity * window.dt))
# zoom in and out
if window.event.check_flag(EVENT_FLAG.MOUSE_WHEEL):
cam_dist -= window.event.mouse.wheel.y * 10
# apply/clamp, position, and camera rotation
if cam_rot.up.y >= 0.7:
# Position the camera behind the car based on its forward vector
camera.position = car.position - (cam_rot.forward * cam_dist)
camera.rotation = cam_rot
else:
camera.rotation.rotate_yaw(yaw_rot)
# Position the camera behind the car based on its forward vector
camera.position = car.position - (camera.rotation.forward * cam_dist)
# Re-render the scene.
window.update(render_list)
# This also refreshes window.current_event.
counter += counter_speed
Then when we run it, it looks something like this:
TODO:
-
Refactor MVP matrix into their respective entities.
-
Figure out better solution for multimesh assimp imports. (Current solution groups all meshes from the scene in a python list.)
-
Add
from_raw
constructor to mesh to make procedural meshes possible. -
Make render list managed by Window object.
-
Add Sprite object and Object2D object for 2D games/HUD.
-
Add window/fullscreen scaling.
-
Add Matrix datastructures for GLM.
Future Plans:
- Switch to Vulkan.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Hashes for Runespoor-1.0.0.dev16-pp310-pypy310_pp73-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 462144d833c4c3255f77ab9e7d2713bce9e434e9c58794104353b1f804b97e72 |
|
MD5 | 8ad118be76c5101e5730e46fd5e6a3d8 |
|
BLAKE2b-256 | 7d483f604619e0a2d2b5f9b00fdddde0b4be7ec465cbce6511452e1b084dd834 |
Hashes for Runespoor-1.0.0.dev16-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4bfc6fcfc183c68c94238b6a57248f77d32578c4a2ade05a887adf19f79d33f6 |
|
MD5 | 372fb74fd292393f40eed79cd287fc6e |
|
BLAKE2b-256 | 2a9454a92dad4745ddb4ac372a1f981009db3ea4df69a80940874c19ee1d9d78 |
Hashes for Runespoor-1.0.0.dev16-pp39-pypy39_pp73-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f75f1591994840749ccc8e984485e6b418b8d34881d0493bb53cd92c9686b154 |
|
MD5 | bf0530bd7407108ec9b696d470cdca53 |
|
BLAKE2b-256 | b0f17e9e241789766181b2cacc43afb9f92c32cd739265ebca5fe0691a52ed52 |
Hashes for Runespoor-1.0.0.dev16-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 8ffd1ef5a127085f600a709e23b71f55b735351814c78578687487a5ebce4909 |
|
MD5 | a3cb519161d508980de73c40e7cdb409 |
|
BLAKE2b-256 | c2d8ab21e79d4d67dbff16ec257309fc8e4dd7fc9263d2693daf47e33a4a0f22 |
Hashes for Runespoor-1.0.0.dev16-pp38-pypy38_pp73-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | cb3e017c969084b8af7e7563f5b086bf389faefe82ab40503c13b3aeb357f758 |
|
MD5 | 8ca7169e5414c7cdfe9bbc8939dca9ab |
|
BLAKE2b-256 | 72e25a534351dfa22249c8ad2fe3f23fd02ff677288bf13e5d97988afd8c10fb |
Hashes for Runespoor-1.0.0.dev16-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | b9406368572466d887dbf689c8e8e56ca55784fd1e56ddb00c0abae7f740a282 |
|
MD5 | 8bb1fab9807fcb84132e57cb78ca965f |
|
BLAKE2b-256 | 3e5d97d57afeaa11260325bb4fb6d0ef9c8d6b8ca1d17f05046867d200270445 |
Hashes for Runespoor-1.0.0.dev16-pp37-pypy37_pp73-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6f5c41341674240aaeb361449227d0a7317cebd3ef426bc0605ffaa71b7c31d3 |
|
MD5 | 91c0530ad3cb146e8a1e08a168624c4b |
|
BLAKE2b-256 | e61beb89d7f1baf308df970918bf8d0d3e524dae0bae9aa06ed784c701f61e46 |
Hashes for Runespoor-1.0.0.dev16-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9563dc4142913ec094dd48c326ba036df574826b28079dc29ee74da3befc6059 |
|
MD5 | e40df40b14a15b1393029b9248b2f234 |
|
BLAKE2b-256 | 94bab1f99b3bb7595c6b8e92ec246f73f4aa5828883ed1264aa11a0260c82c6b |
Hashes for Runespoor-1.0.0.dev16-cp312-cp312-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | e68ae87bb24d8494268ebbb7ded8bdfe614e5343815cf592c5c53f648a52149b |
|
MD5 | fd83ba8793ab4b8eefafe7e616406dc1 |
|
BLAKE2b-256 | 63ec790aff81147b3db4f546bc84507dd3c19a3ba55f75dea3c5099cba3d3919 |
Hashes for Runespoor-1.0.0.dev16-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3c21297a60e84c10bb0fc2cd6cbae3cac03888a1d8c4d9283de7706f9d89b5ad |
|
MD5 | 9b6f2301db24307caa79e9d9e2c0c224 |
|
BLAKE2b-256 | e3e8ed0f1612c317d9ee6cf77b57b10ceb18fd3993db6d3223b7088db4d78676 |
Hashes for Runespoor-1.0.0.dev16-cp311-cp311-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | b7f453c6d6f7942de17ace3a218263f8fa418a3d7cfdc9d83fca9c37d0139471 |
|
MD5 | 9edf5cf96ee4ea5966b9ce0da9f96f6d |
|
BLAKE2b-256 | 803d79b9a65a14b20b1b7d258cf63f6bff530c39536bb1f4b893e862f50ce0fa |
Hashes for Runespoor-1.0.0.dev16-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 39cc1d605d85b2285f68fafeb48c8cf8c0a2c7bd0958d5a1590ec6204c334bde |
|
MD5 | 30eaaf2b852e821fef20bf8c7024ab4a |
|
BLAKE2b-256 | d50670fc0f5cda92b055d937ad1c9d484403f169829ee7dfdbb89d3345004dd4 |
Hashes for Runespoor-1.0.0.dev16-cp310-cp310-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 508cbe95895402e17c881896efe49b6cf66c60036d49745d64bdd7edebd83266 |
|
MD5 | f5f4f28b49bfd01a04be78cb4374c49f |
|
BLAKE2b-256 | 8d0b12b194a3fd539c91889359e27d39ca0adf714e79a1825821562264a66383 |
Hashes for Runespoor-1.0.0.dev16-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 49871b91a208338805314419d43103c68cce112dc0535fec0e524ce5c075d707 |
|
MD5 | 03cf940c101ac3f8ca118cb4cfb220a3 |
|
BLAKE2b-256 | a028d88872bf334892133eae99d491c923c32a5e10467c927593cd77687c04f2 |
Hashes for Runespoor-1.0.0.dev16-cp39-cp39-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 19a7417b0d47eff307c8dac33460ad3861f55511f7132a79ad3a9fe477de44a0 |
|
MD5 | 21a30b17c8bf772aa8367861f4a92bde |
|
BLAKE2b-256 | ce7ef7b1ee7405154b801a5f4552a338fafcb0bdc79b2be4c93fe56d33cae6dd |
Hashes for Runespoor-1.0.0.dev16-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9de9afe6a65ab57dcfb99776d555e821eb344c737d704856512ff3497a1d565a |
|
MD5 | b5a04b7e1ffffe97aad9e67790fb9306 |
|
BLAKE2b-256 | 613e2eda597f46ee7a290c2d01f4ec608928e0b91cbfd638ffccb79053fd44bc |
Hashes for Runespoor-1.0.0.dev16-cp38-cp38-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | bee620f1fa664cf5c66d72e8ec06f3aefdb93037b43482fb0d19fd43a7811e18 |
|
MD5 | abff5ce55ea148c25d937e8119c0ade8 |
|
BLAKE2b-256 | 2dd8d0026b981f226170cfdf6c4708fc8520735a4d4a5fc60b65638ce632ecfc |
Hashes for Runespoor-1.0.0.dev16-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | d43ad6e35ed39385fb0f90f327617261350796619adb7fcef06aa007ffd0459e |
|
MD5 | f3dfc6d6bb3c69a4ea9ffc1db9d995e6 |
|
BLAKE2b-256 | 34ae81cfeec348c3cae084be4ee5c7a68ec7f4423da804ff6aa230485b4297ac |