aether-engine 1.8.0__tar.gz → 1.8.1__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.
- {aether_engine-1.8.0 → aether_engine-1.8.1}/MANIFEST.in +3 -0
- {aether_engine-1.8.0/aether_engine.egg-info → aether_engine-1.8.1}/PKG-INFO +12 -6
- {aether_engine-1.8.0 → aether_engine-1.8.1}/README.md +7 -1
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/__init__.py +1 -1
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/cli.py +36 -14
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/core/_identity.py +1 -1
- aether_engine-1.8.1/aether/docs/GUIDE.md +270 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/ui/hud.py +67 -12
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/web/content.py +10 -7
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/web/plain_content.py +9 -4
- {aether_engine-1.8.0 → aether_engine-1.8.1/aether_engine.egg-info}/PKG-INFO +12 -6
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether_engine.egg-info/SOURCES.txt +2 -0
- aether_engine-1.8.1/docs/GUIDE.md +270 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/setup.py +1 -1
- {aether_engine-1.8.0 → aether_engine-1.8.1}/LICENSE +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/__main__.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/accelerators/__init__.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/accelerators/gameplay.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/accelerators/voxel.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/ai/behavior_tree.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/ai/navmesh.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/animation/skeleton.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/assets/__pycache__/asset_pipeline.cpython-314.pyc +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/assets/asset_pipeline.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/assets/fonts/AetherSans.ttf +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/audio/__init__.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/audio/audio_manager.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/audio/music.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/audio/sfx.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/audio/sound.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/core/__init__.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/core/achievement_system.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/core/application.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/core/boot_splash.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/core/branding_guard.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/core/config.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/core/console.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/core/engine.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/core/event_bus.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/core/input.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/core/plugin_system.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/core/save_system.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/core/time_manager.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/core/window.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/editor/__init__.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/environment/environment_system.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/__init__.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/camera.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/first_person.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/framebuffer.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/light.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/lod_system.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/material.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/mesh.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/mesh_factory.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/particle_system.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/post_process.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/renderer.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/shader.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/shader_library.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/sky_atmosphere.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/terrain.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/texture.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/voxel_mesh.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics/water.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/graphics2d/__init__.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/network/network_manager.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/physics/__init__.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/physics/bullet_backend.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/physics/collider.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/physics/physics2d.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/physics/physics3d.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/physics/physics_world.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/physics/raycast.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/physics/rigidbody.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/platform/steam_api.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/resources/__init__.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/resources/asset_database.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/resources/asset_loader.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/resources/loaders/model_loader.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/resources/loaders/obj_loader.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/resources/loaders/texture_loader.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/resources/resource_manager.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/resources/save_load.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/resources/serialization.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/scene/__init__.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/scene/component.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/scene/entity.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/scene/scene.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/scene/scene_graph.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/scene/scene_manager.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/tools/__init__.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/tools/packager.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/ui/__init__.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/ui/button.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/ui/canvas.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/ui/text.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/utils/__init__.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/utils/fonts.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/utils/logger.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/utils/math_utils.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/utils/object_pool.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/utils/profiler.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/web/__init__.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/web/bot_detect.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/web/config.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/web/notifications.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/web/plain.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/web/registry.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/web/secrets.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/web/server.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/web/templates.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether/web/urls.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether_engine.egg-info/dependency_links.txt +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether_engine.egg-info/entry_points.txt +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether_engine.egg-info/requires.txt +4 -4
- {aether_engine-1.8.0 → aether_engine-1.8.1}/aether_engine.egg-info/top_level.txt +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/examples/01_hello_cube.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/examples/02_sphere_scene.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/examples/03_first_person.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/examples/04_physics2d.py +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/pyproject.toml +0 -0
- {aether_engine-1.8.0 → aether_engine-1.8.1}/setup.cfg +0 -0
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
include README.md
|
|
2
2
|
include LICENSE
|
|
3
3
|
include pyproject.toml
|
|
4
|
+
include docs/GUIDE.md
|
|
4
5
|
|
|
5
6
|
recursive-include aether *.py
|
|
6
7
|
recursive-include aether *.glsl
|
|
7
8
|
recursive-include aether *.vert
|
|
8
9
|
recursive-include aether *.frag
|
|
9
10
|
recursive-include aether *.json
|
|
11
|
+
recursive-include aether *.md
|
|
10
12
|
recursive-include aether/assets *
|
|
13
|
+
recursive-include aether/docs *
|
|
11
14
|
|
|
12
15
|
recursive-include examples *.py
|
|
13
16
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aether-engine
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.1
|
|
4
4
|
Summary: 3D/2D game engine by entiti937 — OpenGL, physics, FPS, mandatory branding splash
|
|
5
5
|
Home-page: https://pypi.org/project/aether-engine/
|
|
6
6
|
Author: entiti937
|
|
@@ -31,13 +31,13 @@ Requires-Dist: trimesh>=3.21; extra == "models"
|
|
|
31
31
|
Provides-Extra: build
|
|
32
32
|
Requires-Dist: pyinstaller>=6.0; extra == "build"
|
|
33
33
|
Provides-Extra: full
|
|
34
|
-
Requires-Dist:
|
|
35
|
-
Requires-Dist: trimesh>=3.21; extra == "full"
|
|
34
|
+
Requires-Dist: pymunk>=6.0; extra == "full"
|
|
36
35
|
Requires-Dist: imageio>=2.31; extra == "full"
|
|
37
|
-
Requires-Dist: pyinstaller>=6.0; extra == "full"
|
|
38
36
|
Requires-Dist: pyyaml>=6.0; extra == "full"
|
|
39
|
-
Requires-Dist:
|
|
37
|
+
Requires-Dist: pyinstaller>=6.0; extra == "full"
|
|
40
38
|
Requires-Dist: freetype-py>=2.4; extra == "full"
|
|
39
|
+
Requires-Dist: trimesh>=3.21; extra == "full"
|
|
40
|
+
Requires-Dist: pygame-ce>=2.5; extra == "full"
|
|
41
41
|
Dynamic: author
|
|
42
42
|
Dynamic: classifier
|
|
43
43
|
Dynamic: description
|
|
@@ -52,7 +52,7 @@ Dynamic: summary
|
|
|
52
52
|
# Aether Engine
|
|
53
53
|
|
|
54
54
|
**3D / 2D игровой движок на Python + OpenGL**
|
|
55
|
-
**Разработчик:** entiti937 · **Версия:** 1.8.
|
|
55
|
+
**Разработчик:** entiti937 · **Версия:** 1.8.1 · **Лицензия:** MIT
|
|
56
56
|
**PyPI:** https://pypi.org/project/aether-engine/
|
|
57
57
|
|
|
58
58
|
> Полное руководство: [`docs/GUIDE.md`](docs/GUIDE.md) · сайт: `aether website`
|
|
@@ -70,6 +70,12 @@ import aether # правильно
|
|
|
70
70
|
# import aether_engine # НЕПРАВИЛЬНО — такого модуля нет
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
## Что нового в 1.8.1
|
|
74
|
+
|
|
75
|
+
- `Hud.draw_bar(x, y, w, h, value, max_value, color)` — простой и понятный вызов
|
|
76
|
+
- `aether docs` печатает **полный** GUIDE.md (гайд вшит в пакет)
|
|
77
|
+
- Координаты HUD явно: (0,0) = центр экрана
|
|
78
|
+
|
|
73
79
|
## Что нового в 1.8.0
|
|
74
80
|
|
|
75
81
|
- `Scene.remove()` / `despawn()` / `find()`
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Aether Engine
|
|
2
2
|
|
|
3
3
|
**3D / 2D игровой движок на Python + OpenGL**
|
|
4
|
-
**Разработчик:** entiti937 · **Версия:** 1.8.
|
|
4
|
+
**Разработчик:** entiti937 · **Версия:** 1.8.1 · **Лицензия:** MIT
|
|
5
5
|
**PyPI:** https://pypi.org/project/aether-engine/
|
|
6
6
|
|
|
7
7
|
> Полное руководство: [`docs/GUIDE.md`](docs/GUIDE.md) · сайт: `aether website`
|
|
@@ -19,6 +19,12 @@ import aether # правильно
|
|
|
19
19
|
# import aether_engine # НЕПРАВИЛЬНО — такого модуля нет
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
## Что нового в 1.8.1
|
|
23
|
+
|
|
24
|
+
- `Hud.draw_bar(x, y, w, h, value, max_value, color)` — простой и понятный вызов
|
|
25
|
+
- `aether docs` печатает **полный** GUIDE.md (гайд вшит в пакет)
|
|
26
|
+
- Координаты HUD явно: (0,0) = центр экрана
|
|
27
|
+
|
|
22
28
|
## Что нового в 1.8.0
|
|
23
29
|
|
|
24
30
|
- `Scene.remove()` / `despawn()` / `find()`
|
|
@@ -31,7 +31,7 @@ from aether.audio.sfx import SfxBank
|
|
|
31
31
|
from aether.resources.save_load import save_json, load_json
|
|
32
32
|
from aether.physics.raycast import Raycaster
|
|
33
33
|
|
|
34
|
-
__version__ = "1.8.
|
|
34
|
+
__version__ = "1.8.1"
|
|
35
35
|
|
|
36
36
|
from aether.graphics.voxel_mesh import ChunkedVoxelMesher
|
|
37
37
|
from aether.accelerators import is_native_available, backend_name
|
|
@@ -60,10 +60,15 @@ TRANSFORM
|
|
|
60
60
|
tf.set_position(x,y,z) / set_rotation / set_scale
|
|
61
61
|
tf.translate(dx,dy,dz)
|
|
62
62
|
|
|
63
|
-
HUD
|
|
63
|
+
HUD (координаты: 0,0 = ЦЕНТР экрана, +Y вверх; текста нет — пишите в title)
|
|
64
|
+
from aether import Hud
|
|
64
65
|
engine.draw_hud = True
|
|
65
66
|
hud = Hud(engine.renderer2d)
|
|
66
|
-
hud.clear()
|
|
67
|
+
hud.clear()
|
|
68
|
+
# draw_bar(x, y, width, height, value, max_value, color)
|
|
69
|
+
hud.draw_bar(-500, 300, 200, 20, hp, 100, (0.8, 0.2, 0.2, 1.0))
|
|
70
|
+
hud.draw_crosshair()
|
|
71
|
+
engine.window.set_title(f"HP {{hp}}")
|
|
67
72
|
|
|
68
73
|
FPS / КАМЕРА
|
|
69
74
|
engine.enable_first_person(camera, eye_height=1.7, walk_speed=6)
|
|
@@ -109,13 +114,13 @@ NPC / НАГРАДЫ (RUST, опционально)
|
|
|
109
114
|
aether build my_game.py --name MyGame --console
|
|
110
115
|
|
|
111
116
|
ИНСТРУМЕНТЫ
|
|
112
|
-
aether help —
|
|
113
|
-
aether docs —
|
|
114
|
-
aether website —
|
|
117
|
+
aether help — краткая шпаргалка
|
|
118
|
+
aether docs — ПОЛНЫЙ гайд (весь GUIDE.md в терминал)
|
|
119
|
+
aether website — HTML-сайт документации
|
|
115
120
|
python -m aether website
|
|
116
121
|
python games/aether_craft.py
|
|
117
122
|
|
|
118
|
-
ПОЛНАЯ ДОКУМЕНТАЦИЯ: docs
|
|
123
|
+
ПОЛНАЯ ДОКУМЕНТАЦИЯ: aether docs | сайт: aether website
|
|
119
124
|
PyPI: https://pypi.org/project/aether-engine/
|
|
120
125
|
"""
|
|
121
126
|
|
|
@@ -126,12 +131,29 @@ def cmd_help(_args):
|
|
|
126
131
|
|
|
127
132
|
|
|
128
133
|
def cmd_docs(_args):
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
134
|
+
"""Print the full bundled developer guide."""
|
|
135
|
+
here = Path(__file__).resolve().parent
|
|
136
|
+
candidates = [
|
|
137
|
+
here / "docs" / "GUIDE.md",
|
|
138
|
+
here.parents[1] / "docs" / "GUIDE.md",
|
|
139
|
+
here.parents[0] / "docs" / "GUIDE.md",
|
|
140
|
+
]
|
|
141
|
+
for guide in candidates:
|
|
142
|
+
if guide.exists():
|
|
143
|
+
text = guide.read_text(encoding="utf-8")
|
|
144
|
+
try:
|
|
145
|
+
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
146
|
+
except Exception:
|
|
147
|
+
pass
|
|
148
|
+
try:
|
|
149
|
+
print(text)
|
|
150
|
+
except UnicodeEncodeError:
|
|
151
|
+
sys.stdout.buffer.write(text.encode("utf-8", errors="replace"))
|
|
152
|
+
sys.stdout.buffer.write(b"\n")
|
|
153
|
+
return 0
|
|
154
|
+
print(QUICK_REFERENCE)
|
|
155
|
+
print("\n[aether docs] GUIDE.md not found in package — reinstall: pip install -U aether-engine")
|
|
156
|
+
return 1
|
|
135
157
|
|
|
136
158
|
|
|
137
159
|
def cmd_build(args):
|
|
@@ -161,8 +183,8 @@ def main(argv=None):
|
|
|
161
183
|
|
|
162
184
|
sub = parser.add_subparsers(dest="command")
|
|
163
185
|
|
|
164
|
-
sub.add_parser("help", help="Краткая
|
|
165
|
-
sub.add_parser("docs", help="
|
|
186
|
+
sub.add_parser("help", help="Краткая шпаргалка").set_defaults(func=cmd_help)
|
|
187
|
+
sub.add_parser("docs", help="Полный гайд разработчика (весь GUIDE.md)").set_defaults(func=cmd_docs)
|
|
166
188
|
|
|
167
189
|
p_build = sub.add_parser("build", help="Собрать игру в .exe (PyInstaller)")
|
|
168
190
|
p_build.add_argument("script", help="Путь к main.py игры")
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# Aether Engine — Full Developer Guide
|
|
2
|
+
|
|
3
|
+
**Version:** 1.8.1 · **Author:** entiti937 · **License:** MIT
|
|
4
|
+
**PyPI package:** `aether-engine`
|
|
5
|
+
**Python import:** `import aether` ← NEVER `import aether_engine`
|
|
6
|
+
|
|
7
|
+
Commands:
|
|
8
|
+
- `aether help` — short cheat sheet
|
|
9
|
+
- `aether docs` — **this full guide** (printed to terminal)
|
|
10
|
+
- `aether website` — local HTML docs (+ `/plain/all` for AI)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 0. Exact package names
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install -U "aether-engine[full]"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
from aether import Engine, Scene, Entity, Transform, MeshRenderer
|
|
22
|
+
from aether import MeshFactory, Material, Camera, Hud, HudBar, Sprite, AssetLoader
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 1. Minimal 3D game
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from aether import (
|
|
31
|
+
Engine, Scene, Entity, Transform, MeshRenderer,
|
|
32
|
+
MeshFactory, Material, Camera,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
engine = Engine(1280, 720, "My Game")
|
|
36
|
+
scene = Scene("Main")
|
|
37
|
+
camera = Camera(position=(0, 2, 8), yaw=-90, pitch=-15)
|
|
38
|
+
scene.set_main_camera(camera)
|
|
39
|
+
|
|
40
|
+
cube = Entity("Cube")
|
|
41
|
+
cube.add_component(Transform(position=(0, 1, 0)))
|
|
42
|
+
mat = Material("green")
|
|
43
|
+
mat.albedo[:] = (0.2, 0.9, 0.4)
|
|
44
|
+
cube.add_component(MeshRenderer(mesh=MeshFactory.create_cube(), material=mat))
|
|
45
|
+
scene.spawn(cube)
|
|
46
|
+
|
|
47
|
+
engine.load_scene(scene)
|
|
48
|
+
engine.enable_first_person(camera)
|
|
49
|
+
engine.run() # blocks until ESC
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 2. Scene — add / remove objects
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
scene.spawn(entity) # add
|
|
58
|
+
scene.remove(entity) # REMOVE from scene + destroy() ← use this to delete
|
|
59
|
+
scene.despawn(entity) # same as remove
|
|
60
|
+
found = scene.find("Player") # Entity or None
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Important:** `entity.destroy()` alone does NOT remove it from `scene.entities`. Always prefer `scene.remove(entity)`.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 3. Transform
|
|
68
|
+
|
|
69
|
+
`position`, `rotation`, `scale` = **numpy float32 arrays** length 3. Rotation in **degrees**.
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
tf = Transform(position=(0, 1, 0), rotation=(0, 45, 0), scale=(1, 1, 1))
|
|
73
|
+
tf.set_position(x, y, z)
|
|
74
|
+
tf.position[:] = (1, 2, 3)
|
|
75
|
+
tf.position[1] += 0.1
|
|
76
|
+
tf.translate(dx, dy, dz)
|
|
77
|
+
tf.set_rotation(rx, ry, rz)
|
|
78
|
+
tf.rotate(0, 90 * dt, 0)
|
|
79
|
+
tf.set_scale(sx, sy, sz)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 4. Camera
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
cam = Camera(position=(0, 5, 10), yaw=-90, pitch=-20, fov=60)
|
|
88
|
+
cam.position = (x, y, z) # tuple OK
|
|
89
|
+
cam.yaw = -45
|
|
90
|
+
cam.pitch = -15
|
|
91
|
+
cam.look_at(target) # world point or player_tf.position
|
|
92
|
+
cam.rotate(dx, dy) # mouse deltas
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Third-person follow:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
engine.free_camera = False # REQUIRED when you move the camera yourself
|
|
99
|
+
target = player_tf.position
|
|
100
|
+
cam.position = (target[0], target[1] + 6, target[2] + 10)
|
|
101
|
+
cam.look_at(target)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
FPS: `engine.enable_first_person(camera, eye_height=1.7, walk_speed=6)`
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 5. MeshFactory — ALL primitives
|
|
109
|
+
|
|
110
|
+
| Method | Signature |
|
|
111
|
+
|--------|-----------|
|
|
112
|
+
| cube | `create_cube(size=1.0)` |
|
|
113
|
+
| plane | `create_plane(size=10.0)` |
|
|
114
|
+
| sphere | `create_sphere(radius=1.0, sectors=24, stacks=16)` |
|
|
115
|
+
| cylinder | `create_cylinder(radius=0.5, height=1.0, segments=24, capped=True)` |
|
|
116
|
+
| pyramid | `create_pyramid(size=1.0, height=1.0)` |
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
MeshFactory.create_cylinder(radius=0.8, height=3.0, segments=24)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 6. Material
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
mat = Material("metal")
|
|
128
|
+
mat.albedo[:] = (0.9, 0.2, 0.2) # RGB 0..1 numpy
|
|
129
|
+
mat.metallic = 0.8
|
|
130
|
+
mat.roughness = 0.3
|
|
131
|
+
mat.ao = 1.0
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 7. HUD — exact API (read carefully)
|
|
137
|
+
|
|
138
|
+
Enable overlay:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from aether import Hud, HudBar
|
|
142
|
+
|
|
143
|
+
engine.draw_hud = True
|
|
144
|
+
hud = Hud(engine.renderer2d)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Coordinates:** origin `(0,0)` = **center of the window**, +X right, +Y up.
|
|
148
|
+
Not top-left pixels. On 1280×720, top-left area ≈ `(-500, 300)`.
|
|
149
|
+
|
|
150
|
+
**No bitmap text yet.** Put strings in the window title:
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
engine.window.set_title(f"HP {hp} | score {score}")
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### draw_bar — exact signatures
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
# RECOMMENDED — current value + max value + color
|
|
160
|
+
hud.draw_bar(x, y, width, height, value, max_value, color)
|
|
161
|
+
hud.draw_bar(-500, 300, 200, 20, hp, 100, (0.8, 0.2, 0.2, 1.0))
|
|
162
|
+
|
|
163
|
+
# Fraction 0..1 only
|
|
164
|
+
hud.draw_bar(-500, 300, 200, 20, 0.75)
|
|
165
|
+
|
|
166
|
+
# HudBar object
|
|
167
|
+
hud.draw_bar(-500, 300, 200, 20, HudBar("hp", value=0.75, color=(0.8, 0.2, 0.2, 1.0)))
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Other HUD methods
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
hud.clear() # call every frame before drawing
|
|
174
|
+
hud.draw_crosshair(size=10, thickness=2)
|
|
175
|
+
hud.draw_hotbar(slots=7, selected=0, colors=[(1,0,0), (0,1,0)], y=-220)
|
|
176
|
+
hud.draw_rect(x, y, width, height, color=(1,1,1,1), layer=70)
|
|
177
|
+
hud.draw_panel(x, y, width, height)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Full frame example:
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
def update(dt):
|
|
184
|
+
hud.clear()
|
|
185
|
+
hud.draw_bar(-500, 300, 200, 20, hp, 100, (0.8, 0.2, 0.2, 1.0))
|
|
186
|
+
hud.draw_crosshair()
|
|
187
|
+
engine.window.set_title(f"HP {hp}")
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 8. Assets
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
from aether import AssetLoader, Sprite
|
|
196
|
+
|
|
197
|
+
mesh = AssetLoader.load_model("hero.glb")
|
|
198
|
+
sprite = Sprite.from_image("icon.png", x=0, y=0)
|
|
199
|
+
tex_id = AssetLoader.load_texture("wall.jpg")
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 9. Physics
|
|
205
|
+
|
|
206
|
+
**2D (ready):** `engine.physics2d` (pymunk) — see `examples/04_physics2d.py`
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
engine.set_mode("2d")
|
|
210
|
+
pw = engine.physics2d
|
|
211
|
+
ground = pw.create_box(0, -200, 600, 40, static=True)
|
|
212
|
+
ball = pw.create_circle(0, 0, 20, mass=1.0)
|
|
213
|
+
sprite.x, sprite.y = ball.x, ball.y # Y-up, same space
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**3D:** lightweight built-in solver. PyBullet/Jolt planned later.
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
from aether import BoxCollider
|
|
220
|
+
body = engine.physics3d.create_body_for_entity(ent, mass=1.0, collider=BoxCollider(size=(1,1,1)))
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## 10. Input / update
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
import glfw
|
|
229
|
+
|
|
230
|
+
def update(dt):
|
|
231
|
+
if engine.input.get_key(glfw.KEY_W):
|
|
232
|
+
...
|
|
233
|
+
if engine.input.get_key_down(glfw.KEY_SPACE):
|
|
234
|
+
...
|
|
235
|
+
|
|
236
|
+
engine.on_update(update)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## 11. Window vs audio
|
|
242
|
+
|
|
243
|
+
- **GLFW** — window, input, OpenGL 4.6
|
|
244
|
+
- **pygame-ce** — sound mixer only (display never initialized)
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## 12. CLI
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
aether help
|
|
252
|
+
aether docs # full guide (this file)
|
|
253
|
+
aether website # HTML docs on localhost
|
|
254
|
+
aether build game.py --name MyGame
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## 13. Examples
|
|
260
|
+
|
|
261
|
+
| File | Topic |
|
|
262
|
+
|------|--------|
|
|
263
|
+
| `examples/01_hello_cube.py` | Basics |
|
|
264
|
+
| `examples/02_sphere_scene.py` | Materials |
|
|
265
|
+
| `examples/03_first_person.py` | FPS |
|
|
266
|
+
| `examples/04_physics2d.py` | 2D physics |
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
Aether Engine © entiti937
|
|
@@ -2,21 +2,40 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
-
from typing import List, Tuple
|
|
5
|
+
from typing import List, Optional, Tuple, Union
|
|
6
6
|
|
|
7
7
|
from aether.graphics2d import Sprite
|
|
8
8
|
|
|
9
|
+
Color = Tuple[float, float, float, float]
|
|
10
|
+
|
|
9
11
|
|
|
10
12
|
@dataclass
|
|
11
13
|
class HudBar:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
"""Progress bar data. value is 0..1 (fraction filled)."""
|
|
15
|
+
|
|
16
|
+
label: str = ""
|
|
17
|
+
value: float = 1.0 # 0..1
|
|
18
|
+
color: Color = (0.2, 0.85, 0.35, 0.95)
|
|
19
|
+
back: Color = (0.1, 0.1, 0.12, 0.7)
|
|
16
20
|
|
|
17
21
|
|
|
18
22
|
class Hud:
|
|
19
|
-
"""
|
|
23
|
+
"""
|
|
24
|
+
Immediate-mode HUD (colored rectangles only — no TrueType text yet).
|
|
25
|
+
|
|
26
|
+
Coordinate system (IMPORTANT):
|
|
27
|
+
Origin (0, 0) = CENTER of the window.
|
|
28
|
+
+X right, +Y up. Same as engine 2D mode.
|
|
29
|
+
Example top-left HP bar on 1280x720: draw_bar(-500, 300, 200, 20, hp, 100)
|
|
30
|
+
|
|
31
|
+
Typical usage each frame:
|
|
32
|
+
engine.draw_hud = True
|
|
33
|
+
hud = Hud(engine.renderer2d)
|
|
34
|
+
hud.clear()
|
|
35
|
+
hud.draw_bar(-500, 300, 200, 20, hp, max_hp, (0.8, 0.2, 0.2, 1.0))
|
|
36
|
+
hud.draw_crosshair()
|
|
37
|
+
engine.window.set_title(f"HP {hp}") # text goes here for now
|
|
38
|
+
"""
|
|
20
39
|
|
|
21
40
|
def __init__(self, renderer2d):
|
|
22
41
|
self.r = renderer2d
|
|
@@ -24,6 +43,7 @@ class Hud:
|
|
|
24
43
|
self._owned: List[Sprite] = []
|
|
25
44
|
|
|
26
45
|
def clear(self):
|
|
46
|
+
"""Remove HUD sprites from last frame. Call once at the start of each update."""
|
|
27
47
|
for s in self._owned:
|
|
28
48
|
if s in self.r.sprites:
|
|
29
49
|
self.r.sprites.remove(s)
|
|
@@ -35,11 +55,13 @@ class Hud:
|
|
|
35
55
|
return sprite
|
|
36
56
|
|
|
37
57
|
def draw_crosshair(self, size: float = 10.0, thickness: float = 2.0):
|
|
58
|
+
"""White crosshair at screen center."""
|
|
38
59
|
c = (1, 1, 1, 0.9)
|
|
39
60
|
self._add(Sprite(0, 0, size, thickness, color=c, layer=100))
|
|
40
61
|
self._add(Sprite(0, 0, thickness, size, color=c, layer=100))
|
|
41
62
|
|
|
42
63
|
def draw_hotbar(self, slots: int, selected: int, colors, y: float = -220):
|
|
64
|
+
"""Inventory-style slots along the bottom."""
|
|
43
65
|
slot_w, slot_h, gap = 44, 44, 6
|
|
44
66
|
total = slots * slot_w + (slots - 1) * gap
|
|
45
67
|
start_x = -total * 0.5 + slot_w * 0.5
|
|
@@ -50,7 +72,40 @@ class Hud:
|
|
|
50
72
|
col = colors[i] if i < len(colors) else (0.4, 0.4, 0.4, 1)
|
|
51
73
|
self._add(Sprite(x, y, slot_w - 6, slot_h - 6, color=(*col[:3], 1.0), layer=91))
|
|
52
74
|
|
|
53
|
-
def draw_bar(
|
|
75
|
+
def draw_bar(
|
|
76
|
+
self,
|
|
77
|
+
x: float,
|
|
78
|
+
y: float,
|
|
79
|
+
width: float,
|
|
80
|
+
height: float,
|
|
81
|
+
value: Union[float, HudBar],
|
|
82
|
+
max_value: Optional[float] = None,
|
|
83
|
+
color: Color = (0.8, 0.2, 0.2, 1.0),
|
|
84
|
+
back: Color = (0.1, 0.1, 0.12, 0.7),
|
|
85
|
+
):
|
|
86
|
+
"""
|
|
87
|
+
Draw a horizontal progress bar. Center of the bar is at (x, y).
|
|
88
|
+
|
|
89
|
+
Easy form (recommended):
|
|
90
|
+
hud.draw_bar(-500, 300, 200, 20, hp, 100, (0.8, 0.2, 0.2, 1.0))
|
|
91
|
+
# x y w h cur max RGBA color
|
|
92
|
+
|
|
93
|
+
With fraction 0..1:
|
|
94
|
+
hud.draw_bar(-500, 300, 200, 20, 0.75)
|
|
95
|
+
|
|
96
|
+
With HudBar object:
|
|
97
|
+
hud.draw_bar(-500, 300, 200, 20, HudBar("hp", value=0.75, color=(...)))
|
|
98
|
+
"""
|
|
99
|
+
if isinstance(value, HudBar):
|
|
100
|
+
bar = value
|
|
101
|
+
else:
|
|
102
|
+
cur = float(value)
|
|
103
|
+
if max_value is None or float(max_value) <= 0:
|
|
104
|
+
frac = cur if 0.0 <= cur <= 1.0 else 0.0
|
|
105
|
+
else:
|
|
106
|
+
frac = cur / float(max_value)
|
|
107
|
+
bar = HudBar(value=frac, color=color, back=back)
|
|
108
|
+
|
|
54
109
|
self._add(Sprite(x, y, width, height, color=bar.back, layer=80))
|
|
55
110
|
fill = max(0.0, min(1.0, bar.value)) * (width - 4)
|
|
56
111
|
self._add(
|
|
@@ -70,10 +125,10 @@ class Hud:
|
|
|
70
125
|
y: float,
|
|
71
126
|
width: float,
|
|
72
127
|
height: float,
|
|
73
|
-
color=(1.0, 1.0, 1.0, 1.0),
|
|
128
|
+
color: Color = (1.0, 1.0, 1.0, 1.0),
|
|
74
129
|
layer: int = 70,
|
|
75
130
|
):
|
|
76
|
-
"""
|
|
131
|
+
"""Solid rectangle. Center at (x, y)."""
|
|
77
132
|
self._add(Sprite(x, y, width, height, color=color, layer=layer))
|
|
78
133
|
|
|
79
134
|
def draw_panel(
|
|
@@ -82,11 +137,11 @@ class Hud:
|
|
|
82
137
|
y: float,
|
|
83
138
|
width: float,
|
|
84
139
|
height: float,
|
|
85
|
-
fill=(0.05, 0.06, 0.08, 0.75),
|
|
86
|
-
border=(0.9, 0.9, 0.95, 0.9),
|
|
140
|
+
fill: Color = (0.05, 0.06, 0.08, 0.75),
|
|
141
|
+
border: Color = (0.9, 0.9, 0.95, 0.9),
|
|
87
142
|
border_thickness: float = 2.0,
|
|
88
143
|
):
|
|
89
|
-
"""
|
|
144
|
+
"""Bordered panel. No text — use engine.window.set_title(...) for strings."""
|
|
90
145
|
self.draw_rect(x, y, width, height, color=fill, layer=70)
|
|
91
146
|
t = border_thickness
|
|
92
147
|
self.draw_rect(x, y + height * 0.5, width, t, color=border, layer=71)
|
|
@@ -247,16 +247,19 @@ mat.metallic = 0.8
|
|
|
247
247
|
mat.roughness = 0.3</code></pre>
|
|
248
248
|
|
|
249
249
|
<h2>Hud</h2>
|
|
250
|
-
<p>
|
|
251
|
-
<pre><code>from aether import Hud
|
|
250
|
+
<p><strong>Coords:</strong> (0,0) = center of window, +Y up. No text — use <code>engine.window.set_title(...)</code>.</p>
|
|
251
|
+
<pre><code>from aether import Hud
|
|
252
|
+
|
|
252
253
|
engine.draw_hud = True
|
|
253
254
|
hud = Hud(engine.renderer2d)
|
|
254
255
|
hud.clear()
|
|
256
|
+
# draw_bar(x, y, width, height, value, max_value, color)
|
|
257
|
+
hud.draw_bar(-500, 300, 200, 20, hp, 100, (0.8, 0.2, 0.2, 1.0))
|
|
255
258
|
hud.draw_crosshair()
|
|
256
|
-
hud.draw_bar(-400, 300, 200, 18, HudBar("hp", value=0.75))
|
|
257
259
|
hud.draw_hotbar(7, 0, colors=[(1,0,0),(0,1,0)])
|
|
258
260
|
hud.draw_rect(0, -250, 120, 40, color=(0,0,0,0.5))
|
|
259
|
-
hud.draw_panel(0, 250, 300, 60)
|
|
261
|
+
hud.draw_panel(0, 250, 300, 60)
|
|
262
|
+
engine.window.set_title(f"HP {hp}")</code></pre>
|
|
260
263
|
</section>
|
|
261
264
|
""",
|
|
262
265
|
"api-3d": """
|
|
@@ -322,8 +325,8 @@ hero = Sprite.from_image("sprites/hero.png", x=0, y=0)
|
|
|
322
325
|
engine.renderer2d.add_sprite(hero)</code></pre>
|
|
323
326
|
|
|
324
327
|
<h2>HUD on top of 3D</h2>
|
|
325
|
-
<p>
|
|
326
|
-
<pre><code>from aether import Hud
|
|
328
|
+
<p>Coords: (0,0)=screen center. Exact bar API:</p>
|
|
329
|
+
<pre><code>from aether import Hud
|
|
327
330
|
|
|
328
331
|
engine.draw_hud = True
|
|
329
332
|
hud = Hud(engine.renderer2d)
|
|
@@ -331,7 +334,7 @@ hud = Hud(engine.renderer2d)
|
|
|
331
334
|
def update(dt):
|
|
332
335
|
hud.clear()
|
|
333
336
|
hud.draw_crosshair(size=12)
|
|
334
|
-
hud.draw_bar(-500, 320, 220, 16,
|
|
337
|
+
hud.draw_bar(-500, 320, 220, 16, hp, 100, (0.8, 0.2, 0.2, 1.0))
|
|
335
338
|
engine.window.set_title(f"Score {score}")
|
|
336
339
|
|
|
337
340
|
engine.on_update(update)</code></pre>
|
|
@@ -133,9 +133,13 @@ MATERIAL
|
|
|
133
133
|
- albedo (np.array RGB), metallic, roughness, ao
|
|
134
134
|
|
|
135
135
|
HUD (engine.draw_hud=True; no text rendering yet)
|
|
136
|
-
-
|
|
137
|
-
-
|
|
138
|
-
-
|
|
136
|
+
- Coords: (0,0)=CENTER of window, +Y up
|
|
137
|
+
- clear() every frame
|
|
138
|
+
- draw_bar(x, y, width, height, value, max_value, color)
|
|
139
|
+
Example: hud.draw_bar(-500, 300, 200, 20, hp, 100, (0.8, 0.2, 0.2, 1.0))
|
|
140
|
+
- Also: draw_bar(..., 0.75) fraction, or draw_bar(..., HudBar(...))
|
|
141
|
+
- draw_crosshair(), draw_hotbar(...), draw_rect(...), draw_panel(...)
|
|
142
|
+
- Text: engine.window.set_title(f"HP {hp}")
|
|
139
143
|
""",
|
|
140
144
|
"api-3d": """
|
|
141
145
|
Engine(width, height, title)
|
|
@@ -150,7 +154,8 @@ scene.remove(entity)
|
|
|
150
154
|
engine.set_mode("2d")
|
|
151
155
|
engine.renderer2d.add_sprite(Sprite(x, y, w, h, color=(r,g,b,a)))
|
|
152
156
|
Sprite.from_image("icon.png")
|
|
153
|
-
Hud:
|
|
157
|
+
Hud: draw_bar(x,y,w,h, value, max_value, color) — also fraction or HudBar
|
|
158
|
+
Coords (0,0)=screen center. draw_crosshair, draw_hotbar, draw_rect, draw_panel (no text)
|
|
154
159
|
""",
|
|
155
160
|
"physics": """
|
|
156
161
|
2D PHYSICS — AVAILABLE NOW (pymunk via engine.physics2d)
|