openglcontext-hill-runner 0.1.0a2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. openglcontext_hill_runner-0.1.0a2/ASSET-LICENSES.md +42 -0
  2. openglcontext_hill_runner-0.1.0a2/LICENSE +26 -0
  3. openglcontext_hill_runner-0.1.0a2/PKG-INFO +181 -0
  4. openglcontext_hill_runner-0.1.0a2/README.md +148 -0
  5. openglcontext_hill_runner-0.1.0a2/pyproject.toml +89 -0
  6. openglcontext_hill_runner-0.1.0a2/setup.cfg +4 -0
  7. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/__init__.py +14 -0
  8. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/__main__.py +5 -0
  9. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/app.py +340 -0
  10. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/atmosphere.py +52 -0
  11. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/canopy.py +125 -0
  12. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/chase.py +143 -0
  13. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/content.py +74 -0
  14. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/course.py +724 -0
  15. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/credits.py +72 -0
  16. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/cues.py +119 -0
  17. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/events.py +23 -0
  18. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/forest_packs.json +18 -0
  19. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/game.py +194 -0
  20. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/groundcover.py +137 -0
  21. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/hud.py +57 -0
  22. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/landscape.py +473 -0
  23. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/look.py +206 -0
  24. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/menu.py +91 -0
  25. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/packs.json +18 -0
  26. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/pilot.py +122 -0
  27. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/portal.py +99 -0
  28. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/run.py +90 -0
  29. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/runner.py +213 -0
  30. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/scenery.py +624 -0
  31. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/session.py +104 -0
  32. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/sound.py +59 -0
  33. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/tiles.py +243 -0
  34. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/treasure.py +126 -0
  35. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/tunnel.py +329 -0
  36. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner/woods.py +210 -0
  37. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner.egg-info/PKG-INFO +181 -0
  38. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner.egg-info/SOURCES.txt +66 -0
  39. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner.egg-info/dependency_links.txt +1 -0
  40. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner.egg-info/entry_points.txt +2 -0
  41. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner.egg-info/requires.txt +18 -0
  42. openglcontext_hill_runner-0.1.0a2/src/openglcontext_hill_runner.egg-info/top_level.txt +1 -0
  43. openglcontext_hill_runner-0.1.0a2/tests/test_app.py +576 -0
  44. openglcontext_hill_runner-0.1.0a2/tests/test_atmosphere.py +54 -0
  45. openglcontext_hill_runner-0.1.0a2/tests/test_canopy.py +97 -0
  46. openglcontext_hill_runner-0.1.0a2/tests/test_cave_land.py +153 -0
  47. openglcontext_hill_runner-0.1.0a2/tests/test_cave_scenery.py +105 -0
  48. openglcontext_hill_runner-0.1.0a2/tests/test_caves.py +268 -0
  49. openglcontext_hill_runner-0.1.0a2/tests/test_chase.py +232 -0
  50. openglcontext_hill_runner-0.1.0a2/tests/test_content.py +124 -0
  51. openglcontext_hill_runner-0.1.0a2/tests/test_course.py +329 -0
  52. openglcontext_hill_runner-0.1.0a2/tests/test_credits.py +40 -0
  53. openglcontext_hill_runner-0.1.0a2/tests/test_cues.py +186 -0
  54. openglcontext_hill_runner-0.1.0a2/tests/test_game.py +396 -0
  55. openglcontext_hill_runner-0.1.0a2/tests/test_groundcover.py +161 -0
  56. openglcontext_hill_runner-0.1.0a2/tests/test_hud.py +109 -0
  57. openglcontext_hill_runner-0.1.0a2/tests/test_landscape.py +246 -0
  58. openglcontext_hill_runner-0.1.0a2/tests/test_look.py +66 -0
  59. openglcontext_hill_runner-0.1.0a2/tests/test_menu.py +140 -0
  60. openglcontext_hill_runner-0.1.0a2/tests/test_pilot.py +116 -0
  61. openglcontext_hill_runner-0.1.0a2/tests/test_runner.py +269 -0
  62. openglcontext_hill_runner-0.1.0a2/tests/test_scenery.py +449 -0
  63. openglcontext_hill_runner-0.1.0a2/tests/test_session.py +226 -0
  64. openglcontext_hill_runner-0.1.0a2/tests/test_sound.py +101 -0
  65. openglcontext_hill_runner-0.1.0a2/tests/test_tiles.py +237 -0
  66. openglcontext_hill_runner-0.1.0a2/tests/test_treasure.py +130 -0
  67. openglcontext_hill_runner-0.1.0a2/tests/test_tunnel.py +203 -0
  68. openglcontext_hill_runner-0.1.0a2/tests/test_woods.py +176 -0
@@ -0,0 +1,42 @@
1
+ # Asset licenses
2
+
3
+ Audio under `src/openglcontext_hill_runner/assets/audio/`. Every file is
4
+ CC0 1.0 (public domain dedication, <https://creativecommons.org/publicdomain/zero/1.0/>).
5
+ Credit is not required; the authors are listed for provenance.
6
+
7
+ | File | Title | Author | Source page | License | Edit |
8
+ | --- | --- | --- | --- | --- | --- |
9
+ | music.ogg | Medieval: Market Day (`Loop_Market_Day.mp3`, the looping version) | RandomMind | <https://opengameart.org/content/medieval-market-day> | CC0 | MP3 converted to Ogg Vorbis (libvorbis q4), metadata stripped |
10
+ | footstep.ogg | RPG Audio, `footstep00.ogg` | Kenney (Kenney Vleugels) | <https://kenney.nl/assets/rpg-audio> | CC0 (License.txt in the pack) | Re-encoded to Ogg Vorbis (q5), metadata stripped |
11
+ | slide.ogg | Scrapes, `scrape-6.ogg` (object dragged across a cinder block) | AntumDeluge | <https://opengameart.org/content/scrapes> | CC0 (page and LICENSE.txt in the pack) | Trimmed to 1.1 s, 30 ms fade in, 300 ms fade out, +6 dB, re-encoded to Ogg Vorbis (q5) |
12
+ | jump_grunt.ogg | RPG Voice Starter Pack, Type 2 (medium-tone female voice), `jump1.wav` | Cici Fyre (cicifyre) | <https://opengameart.org/content/female-rpg-voice-starter-pack> | CC0 | WAV converted to Ogg Vorbis (q5) |
13
+ | coin.ogg | RPG Audio, `handleCoins2.ogg` | Kenney (Kenney Vleugels) | <https://kenney.nl/assets/rpg-audio> | CC0 (License.txt in the pack) | Re-encoded to Ogg Vorbis (q5), metadata stripped |
14
+ | crash.ogg | Impact Sounds, `impactSoft_heavy_001.ogg` | Kenney | <https://kenney.nl/assets/impact-sounds> | CC0 (License.txt in the pack) | Re-encoded to Ogg Vorbis (q5), metadata stripped |
15
+
16
+ `slide.ogg` is a scrape across a cinder block.
17
+
18
+ `chime.ogg` is synthesized for this project from three sine tones with decaying envelopes, and is released under CC0 1.0.
19
+
20
+ ## Character
21
+
22
+ `src/openglcontext_hill_runner/assets/runner.glb` is the female figure of Quaternius' Universal Base
23
+ Characters carrying the Universal Animation Library clips (both CC0 1.0), as prepared in
24
+ `grass-clumps/ual/female_character_ual.glb`, with one clip added: `Slide`, a baseball slide authored by
25
+ `grass-clumps/slide.py`. The clip is original to this project and is released under the same terms.
26
+
27
+ ## Trees and ground cover
28
+
29
+ Used when the forest demo's art is installed (`pip install openglcontext-hill-runner[forest]`, then
30
+ the demo's content pack); the game reads it from there and ships none of it. The tree models are CC-BY 4.0,
31
+ and the game prints these credits when it plants them:
32
+
33
+ | Model | Author | Source |
34
+ | --- | --- | --- |
35
+ | Fir tree | Georgeous | <https://skfb.ly/pA8TG> |
36
+ | Noel_Pine_Tree | 3D Error 404 | <https://skfb.ly/6XHoJ> |
37
+ | Maple trees pack (lowpoly, game ready, LODs) | LOLIPOP | <https://skfb.ly/p9tGx> |
38
+
39
+ The grass, ferns, nettles, periwinkle and shrub are Poly Haven scans, CC0. The ground and trail photographs
40
+ are ambientCG materials (`Grass004` for grass, `Ground042` for the forest floor, `Rock030` for rock,
41
+ `Ground080` for sand, `Ground068` for the trails), CC0, fetched by `OpenGLContext.loaders.cc0` on first run
42
+ and cached; without a network the game draws procedural surfaces.
@@ -0,0 +1,26 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mike C. Fletcher
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ NOTE: This license covers the demo's own source code only. The bundled and
24
+ referenced art assets (tree models, textures, terrain elevation) carry their
25
+ own licenses — see ASSET-LICENSES.md. The tree models are CC-BY 4.0 and
26
+ require attribution, which the demo prints on launch.
@@ -0,0 +1,181 @@
1
+ Metadata-Version: 2.4
2
+ Name: openglcontext-hill-runner
3
+ Version: 0.1.0a2
4
+ Summary: An endless downhill runner for OpenGLContext: parallel paths, streamed generated tiles, shadows, sound and a skinned runner.
5
+ Author-email: "Mike C. Fletcher" <vrplumber@gmail.com>
6
+ License-Expression: MIT
7
+ Keywords: OpenGLContext,OpenGL,game,runner,PBR,demo,3D
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Environment :: X11 Applications
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Topic :: Games/Entertainment
13
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Rendering
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ License-File: ASSET-LICENSES.md
18
+ Requires-Dist: OpenGLContext[audio,glfw,video]>=3.0.0a5
19
+ Requires-Dist: opengl_extrusions>=1.2.1a1
20
+ Requires-Dist: numpy>=2.0
21
+ Requires-Dist: PyOpenGL>=4.0.0a1
22
+ Requires-Dist: glfw>=2.5
23
+ Provides-Extra: test
24
+ Requires-Dist: pytest>=7; extra == "test"
25
+ Requires-Dist: pytest-timeout; extra == "test"
26
+ Requires-Dist: pillow; extra == "test"
27
+ Requires-Dist: tomli; python_version < "3.11" and extra == "test"
28
+ Provides-Extra: dev
29
+ Requires-Dist: openglcontext-hill-runner[test]; extra == "dev"
30
+ Requires-Dist: ruff; extra == "dev"
31
+ Requires-Dist: mypy; extra == "dev"
32
+ Dynamic: license-file
33
+
34
+ # OpenGLContext Hill Runner Demo
35
+
36
+ OpenGLContext engine demo that creates an endless runner game down a valley on a hill.
37
+ Demonstrates tiles3d on-demand tile creation, GPU accelerated animations, vegetation,
38
+ GUI widgets and the Heads Up Display.
39
+
40
+ ```bash
41
+ uv run --pre --with openglcontext-hill-runner oglc-hill-runner
42
+ ```
43
+
44
+ Or you can pip-install it and run like so:
45
+
46
+ ```bash
47
+ oglc-hill-runner # the main screen: play, demo, settings, credits, quit
48
+ oglc-hill-runner --demo # the autopilot plays, with no main screen
49
+ oglc-hill-runner --seed 7 # a different hill
50
+ oglc-hill-runner --no-sound --size 1920 1080
51
+ oglc-hill-runner --no-forest --no-photos # no use of the forest demo's art or the engine's textures, no download
52
+ oglc-hill-runner --yes # fetch the packs below without asking, where they are not here
53
+ ```
54
+
55
+ The game runs on three downloads, all under Creative Commons terms: its own art and sound (the runner,
56
+ the music, the sounds), the forest demo's trees and ground cover, and the engine's photographic
57
+ textures (CC0). The first run lists them with their sizes and terms, asks once and fetches them
58
+ into the per-user content store; later runs find them there. A checkout holding the art in
59
+ `src/openglcontext_hill_runner/assets` does not fetch its own pack.
60
+
61
+ ## Playing
62
+
63
+ | Key | Does |
64
+ | --- | --- |
65
+ | Left, Right | Hop to the next path, unless a hedge stands between the two or the paths have drawn apart |
66
+ | Up | Jump over a log or a boulder, or up to a jewel |
67
+ | Down | Slide under a gate (in the air: drop, then slide). Held on, the runner stays down, and rises only when the key is let go: the body rises over the last 0.3 s of a slide, and a gate met then is a hit |
68
+ | Escape | Menu: resume, restart, demo, settings, credits, quit. Demo hands the run to the computer, which runs without a hit for as long as it is left; the menu's Play takes it back. The main screen the game opens on offers Play and Demo too |
69
+ | Alt+F | Show or hide the developer overlay: frame rate, timings and draw counts |
70
+ | F2 | Save a screenshot to the pictures folder, as `Hill-Runner-0001.png` and so on |
71
+
72
+ The three trails are 0.5 m wide with 0.2 m between them, so a hop is one big step. The runner speeds
73
+ up from 10 to 24 m/s and cannot slow down on its own. A log, a boulder, a gate board or a wall is a
74
+ hit; they stand across one or two trails and are a metre high or more. Coins hang at knee height and are
75
+ worth 1 coin. Jewels hang above a runner's reach and are worth 5 coins: they need a jump. The HUD shows
76
+ coins, score, hits and metres run.
77
+
78
+ ### Hits and continues
79
+
80
+ A hit knocks the runner down just short of the obstacle. It stays there for 1.3 s, rolling to its feet, with the keys doing nothing, and then runs on from 10 m/s: the speed gained is lost. Each hit costs a continue of 100 coins. The edges of the
81
+ screen turn red and flash at the hit, and the coins flash red as they count down by 100 over the 1.3 s of the roll. When the 100 are paid the red clears and the runner
82
+ runs on. A runner with fewer than 100 coins cannot buy a continue: the run is over at the hit, with the edges red, and the coins it has are kept and shown on the end screen. The score is not spent.
83
+ Nothing hits the runner again for the next 15 m, so a row of obstacles is one hit.
84
+
85
+ ### The country
86
+
87
+ The hill runs through forest, rocks, sand, meadow and dense forest, a few hundred metres of each, in an
88
+ order the seed picks. The land, the ground, the trees, the ground cover and the rocks change with it.
89
+ The trail wanders from side to side.
90
+
91
+ ### Caves
92
+
93
+ Every two or three kilometres, after a stretch of rock country, the trail runs into a cave. The
94
+ valley is filled up to the height of the hills beside it over 22 m, so the trail runs into the foot of
95
+ a hillside and the cave is a hole bored through it: the ground is tessellated out to the rim of the
96
+ opening, and the tunnel runs from there to a second opening in the far side of the hill. The tunnel
97
+ is 250 to 320 m long, an arch swept along a spline through the trail and cut into rock: flat facets,
98
+ steps and pits (`OpenGLContext.scenegraph.rockwork`). It leads out into more rock country or into
99
+ forest, the seed's choice.
100
+
101
+ * The ceiling is high in places (4.4 to 7.5 m over the floor) and low in others (2.4 to 3.0 m),
102
+ changing over 16 m. Running or sliding under a low ceiling is safe; **a jump under one is a hit**,
103
+ and so is a jump at the edge of one, since the head arrives at the top of the jump. The camera
104
+ sinks under a low ceiling and rises again once it is clear; where it has sunk it stands to the right
105
+ of the runner and looks across to the left, so the runner does not hide what is ahead.
106
+ * A crevice runs right across the floor, 1.8 m wide and 2.6 m deep. It has to be jumped, and a runner
107
+ who is on the ground over it is a hit. Crevices stand only where no low ceiling is within 14 m, so
108
+ the jump a crevice asks for is always safe; so is every jump the course asks for in a cave, and the
109
+ jewels that hang out of reach of a standing runner.
110
+ * The logs, boughs and walls of the open hill are in caves too. A fallen log under a low ceiling is a
111
+ bough to slide under instead.
112
+ * A torch on the wall every 18 m, on alternate sides, is all the light there is. The sun, the sky's light
113
+ and the haze go out over the first 28 m inside the mouth. The torches' lights are the nearest of the
114
+ scene's lights, which is what the engine binds when there are more than it has room for.
115
+ * No fork runs near a cave, and no trees or ground cover grow over one. The stone of an obstacle is
116
+ paler than the rock about it and glows a little, so it shows in shade.
117
+
118
+ ### Forks
119
+
120
+ Every kilometre or so two more paths appear beside the trail, on the left or the right. They draw away
121
+ and run through another country, then come back and join. Hop onto them in the first few seconds, while
122
+ they are within a hop of the trail; after that they are on a trail of their own. A path that joins the
123
+ trail carries its runner onto the nearest path of it.
124
+
125
+ ## What it uses from the engine
126
+
127
+ | Feature | From |
128
+ | --- | --- |
129
+ | The hill, one tile for each 72 m, made in worker processes as the runner nears it | `GeneratedTiles` with `maker`, `OpenGLContext.loaders.tiles3d.generated`, `.tileprocess` |
130
+ | The runner, with `Sprint_Loop`, `Jog_Fwd_Loop`, `Jump_Start`, `Jump_Loop`, `Slide` and `Death01` | `OpenGLContext.character.CharacterModel` |
131
+ | Sun with cascaded shadow maps fitted to `shadowDistance` and fading out at its end, PBR materials, fog | `DirectionalLight`, `ContextDefinition.shadowDistance`, the PBR pass, `Fog` |
132
+ | Ground, trail, rock and bark photographs (CC0) | `OpenGLContext.loaders.cc0.physical_material`, with procedural `OpenGLContext.scenegraph.surfaces` as the fallback |
133
+ | Rocks, logs, fence rails and dry-stone walls | `OpenGLContext.scenegraph.natural` (`stone`, `timber`, `rubble`) |
134
+ | Rock country's ground: flat faces scraped into the land | `OpenGLContext.scenegraph.terrain.RockRelief` |
135
+ | Procedural textures for bark, sawn ends and the ground | `OpenGLContext.scenegraph.surfaces` |
136
+ | Trees: the forest demo's models, real branches near and cards far, swapped a stretch at a time | `VegetationField.replant`, from the forest demo's art |
137
+ | Grass, ferns, nettles, flowers on the forest floor | `GroundCover`, from the forest demo's art: the grass and the other plants as two nodes (`groundcover`) |
138
+ | Chase camera | `OpenGLContext.move.followcam.FollowCamera` |
139
+ | HUD, with the edge shading of damage; main, pause and end-of-run screens | `OpenGLContext.ui.hudwidgets` (`DamageIndicator`: `level`, `hurt_all`), `OpenGLContext.ui` panels |
140
+ | Music, footsteps, grunt, slide, coins | the engine's audio mixer, through `audioscene.engine_for` |
141
+
142
+ ## How it is put together
143
+
144
+ The rules have no GL and are tested without a window.
145
+
146
+ | Module | Holds |
147
+ | --- | --- |
148
+ | `course` | Paths, the slope, the wandering trail, forks, caves and their ceilings, obstacles (a crevice among them), coins, jewels and hedges; a chunk is a function of the seed and its index |
149
+ | `landscape` | The countries, and the land, ground layers, tree, cover and rock densities of each |
150
+ | `runner` | The body: speed, hopping, jumping, sliding |
151
+ | `game` | Collisions, the fall and getting up, the continue bought with coins, head against a ceiling, treasure, the end of a run |
152
+ | `atmosphere` | How dark and how hazy the air is at a distance: bright in the open, dark in a cave |
153
+ | `pilot` | The autopilot; the test that every generated course can be run |
154
+ | `cues` | Which clip plays, which sounds fire, when a foot lands |
155
+ | `chase` | The point the camera follows |
156
+ | `session` | One run advanced a frame at a time: the above, together |
157
+ | `tunnel`, `portal` | The tunnel of a cave (the arch swept along the trail, the rock cut into it, the floor) and the ground tessellated out to the rim of each opening |
158
+ | `scenery`, `look`, `tiles` | The hill as meshes and materials, and the tile generator; where one country gives way to another the second ground is blended over the first |
159
+ | `groundcover` | The grass, grown tall, and the other plants of the forest demo's art as two nodes, with where each grows |
160
+ | `woods` | The forest demo's trees, planted a stretch of hill at a time, clear of the trails |
161
+ | `treasure`, `hud`, `menu`, `credits`, `sound` | Coins and jewels in view, the HUD, the screens, the credits shown at start and in the menu, the engine's audio mixer |
162
+ | `app`, `run` | The window and the command |
163
+
164
+ ## Tests
165
+
166
+ ```bash
167
+ pip install -e ".[dev]"
168
+ pytest
169
+ ```
170
+
171
+ The render smoke test skips where there is no display.
172
+
173
+ ## Assets
174
+
175
+ Audio and the character are CC0. The music is Medieval: Market Day by RandomMind. The forest demo's tree models are CC-BY 4.0 and credited on launch. [ASSET-LICENSES](ASSET-LICENSES.md) lists each file. The character's `Slide` clip is made by
176
+ `grass-clumps/slide.py` in the OpenGL-dev workspace.
177
+
178
+ The runner, the music and the sounds (2.7 MB) are a content pack, `openglcontext-hill-runner/assets`, attached to
179
+ a GitHub release and not carried in the wheel. The first run lists the pack's size and terms and asks before it
180
+ fetches it; a checkout runs from its own copy and asks nothing. `release-assets.py` builds the pack and writes the
181
+ registry the game ships (`packs.json`); `tools/publish-content.py` in the workspace attaches it to its release.
@@ -0,0 +1,148 @@
1
+ # OpenGLContext Hill Runner Demo
2
+
3
+ OpenGLContext engine demo that creates an endless runner game down a valley on a hill.
4
+ Demonstrates tiles3d on-demand tile creation, GPU accelerated animations, vegetation,
5
+ GUI widgets and the Heads Up Display.
6
+
7
+ ```bash
8
+ uv run --pre --with openglcontext-hill-runner oglc-hill-runner
9
+ ```
10
+
11
+ Or you can pip-install it and run like so:
12
+
13
+ ```bash
14
+ oglc-hill-runner # the main screen: play, demo, settings, credits, quit
15
+ oglc-hill-runner --demo # the autopilot plays, with no main screen
16
+ oglc-hill-runner --seed 7 # a different hill
17
+ oglc-hill-runner --no-sound --size 1920 1080
18
+ oglc-hill-runner --no-forest --no-photos # no use of the forest demo's art or the engine's textures, no download
19
+ oglc-hill-runner --yes # fetch the packs below without asking, where they are not here
20
+ ```
21
+
22
+ The game runs on three downloads, all under Creative Commons terms: its own art and sound (the runner,
23
+ the music, the sounds), the forest demo's trees and ground cover, and the engine's photographic
24
+ textures (CC0). The first run lists them with their sizes and terms, asks once and fetches them
25
+ into the per-user content store; later runs find them there. A checkout holding the art in
26
+ `src/openglcontext_hill_runner/assets` does not fetch its own pack.
27
+
28
+ ## Playing
29
+
30
+ | Key | Does |
31
+ | --- | --- |
32
+ | Left, Right | Hop to the next path, unless a hedge stands between the two or the paths have drawn apart |
33
+ | Up | Jump over a log or a boulder, or up to a jewel |
34
+ | Down | Slide under a gate (in the air: drop, then slide). Held on, the runner stays down, and rises only when the key is let go: the body rises over the last 0.3 s of a slide, and a gate met then is a hit |
35
+ | Escape | Menu: resume, restart, demo, settings, credits, quit. Demo hands the run to the computer, which runs without a hit for as long as it is left; the menu's Play takes it back. The main screen the game opens on offers Play and Demo too |
36
+ | Alt+F | Show or hide the developer overlay: frame rate, timings and draw counts |
37
+ | F2 | Save a screenshot to the pictures folder, as `Hill-Runner-0001.png` and so on |
38
+
39
+ The three trails are 0.5 m wide with 0.2 m between them, so a hop is one big step. The runner speeds
40
+ up from 10 to 24 m/s and cannot slow down on its own. A log, a boulder, a gate board or a wall is a
41
+ hit; they stand across one or two trails and are a metre high or more. Coins hang at knee height and are
42
+ worth 1 coin. Jewels hang above a runner's reach and are worth 5 coins: they need a jump. The HUD shows
43
+ coins, score, hits and metres run.
44
+
45
+ ### Hits and continues
46
+
47
+ A hit knocks the runner down just short of the obstacle. It stays there for 1.3 s, rolling to its feet, with the keys doing nothing, and then runs on from 10 m/s: the speed gained is lost. Each hit costs a continue of 100 coins. The edges of the
48
+ screen turn red and flash at the hit, and the coins flash red as they count down by 100 over the 1.3 s of the roll. When the 100 are paid the red clears and the runner
49
+ runs on. A runner with fewer than 100 coins cannot buy a continue: the run is over at the hit, with the edges red, and the coins it has are kept and shown on the end screen. The score is not spent.
50
+ Nothing hits the runner again for the next 15 m, so a row of obstacles is one hit.
51
+
52
+ ### The country
53
+
54
+ The hill runs through forest, rocks, sand, meadow and dense forest, a few hundred metres of each, in an
55
+ order the seed picks. The land, the ground, the trees, the ground cover and the rocks change with it.
56
+ The trail wanders from side to side.
57
+
58
+ ### Caves
59
+
60
+ Every two or three kilometres, after a stretch of rock country, the trail runs into a cave. The
61
+ valley is filled up to the height of the hills beside it over 22 m, so the trail runs into the foot of
62
+ a hillside and the cave is a hole bored through it: the ground is tessellated out to the rim of the
63
+ opening, and the tunnel runs from there to a second opening in the far side of the hill. The tunnel
64
+ is 250 to 320 m long, an arch swept along a spline through the trail and cut into rock: flat facets,
65
+ steps and pits (`OpenGLContext.scenegraph.rockwork`). It leads out into more rock country or into
66
+ forest, the seed's choice.
67
+
68
+ * The ceiling is high in places (4.4 to 7.5 m over the floor) and low in others (2.4 to 3.0 m),
69
+ changing over 16 m. Running or sliding under a low ceiling is safe; **a jump under one is a hit**,
70
+ and so is a jump at the edge of one, since the head arrives at the top of the jump. The camera
71
+ sinks under a low ceiling and rises again once it is clear; where it has sunk it stands to the right
72
+ of the runner and looks across to the left, so the runner does not hide what is ahead.
73
+ * A crevice runs right across the floor, 1.8 m wide and 2.6 m deep. It has to be jumped, and a runner
74
+ who is on the ground over it is a hit. Crevices stand only where no low ceiling is within 14 m, so
75
+ the jump a crevice asks for is always safe; so is every jump the course asks for in a cave, and the
76
+ jewels that hang out of reach of a standing runner.
77
+ * The logs, boughs and walls of the open hill are in caves too. A fallen log under a low ceiling is a
78
+ bough to slide under instead.
79
+ * A torch on the wall every 18 m, on alternate sides, is all the light there is. The sun, the sky's light
80
+ and the haze go out over the first 28 m inside the mouth. The torches' lights are the nearest of the
81
+ scene's lights, which is what the engine binds when there are more than it has room for.
82
+ * No fork runs near a cave, and no trees or ground cover grow over one. The stone of an obstacle is
83
+ paler than the rock about it and glows a little, so it shows in shade.
84
+
85
+ ### Forks
86
+
87
+ Every kilometre or so two more paths appear beside the trail, on the left or the right. They draw away
88
+ and run through another country, then come back and join. Hop onto them in the first few seconds, while
89
+ they are within a hop of the trail; after that they are on a trail of their own. A path that joins the
90
+ trail carries its runner onto the nearest path of it.
91
+
92
+ ## What it uses from the engine
93
+
94
+ | Feature | From |
95
+ | --- | --- |
96
+ | The hill, one tile for each 72 m, made in worker processes as the runner nears it | `GeneratedTiles` with `maker`, `OpenGLContext.loaders.tiles3d.generated`, `.tileprocess` |
97
+ | The runner, with `Sprint_Loop`, `Jog_Fwd_Loop`, `Jump_Start`, `Jump_Loop`, `Slide` and `Death01` | `OpenGLContext.character.CharacterModel` |
98
+ | Sun with cascaded shadow maps fitted to `shadowDistance` and fading out at its end, PBR materials, fog | `DirectionalLight`, `ContextDefinition.shadowDistance`, the PBR pass, `Fog` |
99
+ | Ground, trail, rock and bark photographs (CC0) | `OpenGLContext.loaders.cc0.physical_material`, with procedural `OpenGLContext.scenegraph.surfaces` as the fallback |
100
+ | Rocks, logs, fence rails and dry-stone walls | `OpenGLContext.scenegraph.natural` (`stone`, `timber`, `rubble`) |
101
+ | Rock country's ground: flat faces scraped into the land | `OpenGLContext.scenegraph.terrain.RockRelief` |
102
+ | Procedural textures for bark, sawn ends and the ground | `OpenGLContext.scenegraph.surfaces` |
103
+ | Trees: the forest demo's models, real branches near and cards far, swapped a stretch at a time | `VegetationField.replant`, from the forest demo's art |
104
+ | Grass, ferns, nettles, flowers on the forest floor | `GroundCover`, from the forest demo's art: the grass and the other plants as two nodes (`groundcover`) |
105
+ | Chase camera | `OpenGLContext.move.followcam.FollowCamera` |
106
+ | HUD, with the edge shading of damage; main, pause and end-of-run screens | `OpenGLContext.ui.hudwidgets` (`DamageIndicator`: `level`, `hurt_all`), `OpenGLContext.ui` panels |
107
+ | Music, footsteps, grunt, slide, coins | the engine's audio mixer, through `audioscene.engine_for` |
108
+
109
+ ## How it is put together
110
+
111
+ The rules have no GL and are tested without a window.
112
+
113
+ | Module | Holds |
114
+ | --- | --- |
115
+ | `course` | Paths, the slope, the wandering trail, forks, caves and their ceilings, obstacles (a crevice among them), coins, jewels and hedges; a chunk is a function of the seed and its index |
116
+ | `landscape` | The countries, and the land, ground layers, tree, cover and rock densities of each |
117
+ | `runner` | The body: speed, hopping, jumping, sliding |
118
+ | `game` | Collisions, the fall and getting up, the continue bought with coins, head against a ceiling, treasure, the end of a run |
119
+ | `atmosphere` | How dark and how hazy the air is at a distance: bright in the open, dark in a cave |
120
+ | `pilot` | The autopilot; the test that every generated course can be run |
121
+ | `cues` | Which clip plays, which sounds fire, when a foot lands |
122
+ | `chase` | The point the camera follows |
123
+ | `session` | One run advanced a frame at a time: the above, together |
124
+ | `tunnel`, `portal` | The tunnel of a cave (the arch swept along the trail, the rock cut into it, the floor) and the ground tessellated out to the rim of each opening |
125
+ | `scenery`, `look`, `tiles` | The hill as meshes and materials, and the tile generator; where one country gives way to another the second ground is blended over the first |
126
+ | `groundcover` | The grass, grown tall, and the other plants of the forest demo's art as two nodes, with where each grows |
127
+ | `woods` | The forest demo's trees, planted a stretch of hill at a time, clear of the trails |
128
+ | `treasure`, `hud`, `menu`, `credits`, `sound` | Coins and jewels in view, the HUD, the screens, the credits shown at start and in the menu, the engine's audio mixer |
129
+ | `app`, `run` | The window and the command |
130
+
131
+ ## Tests
132
+
133
+ ```bash
134
+ pip install -e ".[dev]"
135
+ pytest
136
+ ```
137
+
138
+ The render smoke test skips where there is no display.
139
+
140
+ ## Assets
141
+
142
+ Audio and the character are CC0. The music is Medieval: Market Day by RandomMind. The forest demo's tree models are CC-BY 4.0 and credited on launch. [ASSET-LICENSES](ASSET-LICENSES.md) lists each file. The character's `Slide` clip is made by
143
+ `grass-clumps/slide.py` in the OpenGL-dev workspace.
144
+
145
+ The runner, the music and the sounds (2.7 MB) are a content pack, `openglcontext-hill-runner/assets`, attached to
146
+ a GitHub release and not carried in the wheel. The first run lists the pack's size and terms and asks before it
147
+ fetches it; a checkout runs from its own copy and asks nothing. `release-assets.py` builds the pack and writes the
148
+ registry the game ships (`packs.json`); `tools/publish-content.py` in the workspace attaches it to its release.
@@ -0,0 +1,89 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "openglcontext-hill-runner"
7
+ # Read from src/openglcontext_hill_runner/__init__.py, the one definition; see
8
+ # [tool.setuptools.dynamic].
9
+ dynamic = ["version"]
10
+ description = "An endless downhill runner for OpenGLContext: parallel paths, streamed generated tiles, shadows, sound and a skinned runner."
11
+ readme = "README.md"
12
+ requires-python = ">=3.10"
13
+ license = "MIT"
14
+ license-files = ["LICENSE", "ASSET-LICENSES.md"]
15
+ authors = [{ name = "Mike C. Fletcher", email = "vrplumber@gmail.com" }]
16
+ keywords = ["OpenGLContext", "OpenGL", "game", "runner", "PBR", "demo", "3D"]
17
+ classifiers = [
18
+ "Development Status :: 3 - Alpha",
19
+ "Environment :: X11 Applications",
20
+ "Intended Audience :: Developers",
21
+ "Programming Language :: Python :: 3",
22
+ "Topic :: Games/Entertainment",
23
+ "Topic :: Multimedia :: Graphics :: 3D Rendering",
24
+ ]
25
+ dependencies = [
26
+ "OpenGLContext[glfw,video,audio]>=3.0.0a5",
27
+ "opengl_extrusions>=1.2.1a1",
28
+ "numpy>=2.0",
29
+ "PyOpenGL>=4.0.0a1",
30
+ "glfw>=2.5",
31
+ ]
32
+
33
+ [project.optional-dependencies]
34
+ test = ["pytest>=7", "pytest-timeout", "pillow", "tomli; python_version < '3.11'"]
35
+ dev = ["openglcontext-hill-runner[test]", "ruff", "mypy"]
36
+
37
+ [project.scripts]
38
+ oglc-hill-runner = "openglcontext_hill_runner.run:main"
39
+
40
+ [tool.setuptools.dynamic]
41
+ version = { attr = "openglcontext_hill_runner.__version__" }
42
+
43
+ [tool.setuptools]
44
+ package-dir = { "" = "src" }
45
+
46
+ [tool.setuptools.packages.find]
47
+ where = ["src"]
48
+
49
+ [tool.setuptools.package-data]
50
+ # The art is a content pack fetched on the first run (content.py), not part of the wheel.
51
+ openglcontext_hill_runner = ["packs.json", "forest_packs.json"]
52
+
53
+ [tool.openglcontext-checks]
54
+ select = ["OGC101", "OGC102", "OGC111", "OGC121", "OGC131", "OGC141", "OGC201", "OGC221", "OGC222", "OGC223"]
55
+
56
+ [tool.ruff]
57
+ line-length = 100
58
+ target-version = "py310"
59
+
60
+ [tool.ruff.lint]
61
+ select = ["E", "W", "F", "B", "I", "UP", "BLE", "S110", "PGH003", "PGH004", "RUF100", "RUF012", "ARG", "S112", "E722", "TRY400", "DTZ"]
62
+ ignore = [
63
+ "E501", # line length is kept readable by hand
64
+ "E741", # x/y/z read naturally as coordinates
65
+ "UP031", # percent formatting, as the engine uses
66
+ ]
67
+
68
+ [tool.ruff.lint.per-file-ignores]
69
+ "tests/*" = ["ARG"]
70
+
71
+ [tool.mypy]
72
+ python_version = "3.12"
73
+ check_untyped_defs = true
74
+ disallow_untyped_defs = true
75
+ disallow_incomplete_defs = true
76
+ warn_return_any = true
77
+ warn_unused_ignores = true
78
+ ignore_missing_imports = true
79
+
80
+ [tool.pytest.ini_options]
81
+ testpaths = ["tests"]
82
+ addopts = "-ra -p OpenGLContext.testing.plugin"
83
+ timeout = 300
84
+ markers = [
85
+ "needs_gl: opens a real GL window; skipped where there is no display",
86
+ ]
87
+
88
+ [tool.uv]
89
+ cache-keys = [{ file = "pyproject.toml" }, { file = "src/openglcontext_hill_runner/__init__.py" }]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,14 @@
1
+ """An endless downhill runner for OpenGLContext.
2
+
3
+ The player runs a hill that never ends, on parallel paths, hopping between them
4
+ unless something blocks the way, jumping low obstacles and sliding under high
5
+ ones, and collecting treasure. The hill is generated tile by tile as the runner
6
+ nears it and streamed through the engine's 3D Tiles runtime.
7
+
8
+ The rules (the course, the runner's body, collisions, scoring) are plain objects
9
+ with no GL, tested without a window; ``app`` is the window that draws them.
10
+
11
+ Run it with ``oglc-hill-runner``, or ``python -m openglcontext_hill_runner``.
12
+ """
13
+
14
+ __version__ = "0.1.0a2"
@@ -0,0 +1,5 @@
1
+ """``python -m openglcontext_hill_runner`` runs the game."""
2
+ from openglcontext_hill_runner.run import main
3
+
4
+ if __name__ == "__main__":
5
+ main()