aether-engine 1.0.4__tar.gz → 1.2.0__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.2.0/PKG-INFO +122 -0
- aether_engine-1.2.0/README.md +74 -0
- aether_engine-1.2.0/aether/__init__.py +58 -0
- aether_engine-1.2.0/aether/audio/sfx.py +85 -0
- aether_engine-1.2.0/aether/core/__init__.py +17 -0
- aether_engine-1.2.0/aether/core/engine.py +475 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/core/input.py +84 -58
- aether_engine-1.2.0/aether/editor/__init__.py +5 -0
- aether_engine-1.2.0/aether/editor/__main__.py +6 -0
- aether_engine-1.2.0/aether/editor/model_editor.py +253 -0
- aether_engine-1.2.0/aether/graphics/camera.py +91 -0
- aether_engine-1.2.0/aether/graphics/first_person.py +105 -0
- aether_engine-1.2.0/aether/graphics/material.py +42 -0
- aether_engine-1.2.0/aether/graphics/mesh.py +103 -0
- aether_engine-1.2.0/aether/graphics/mesh_factory.py +175 -0
- aether_engine-1.2.0/aether/graphics/renderer.py +77 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/graphics/shader_library.py +79 -59
- aether_engine-1.2.0/aether/graphics2d/__init__.py +168 -0
- aether_engine-1.2.0/aether/physics/__init__.py +19 -0
- aether_engine-1.2.0/aether/physics/physics2d.py +233 -0
- aether_engine-1.2.0/aether/physics/physics3d.py +216 -0
- aether_engine-1.2.0/aether/physics/raycast.py +102 -0
- aether_engine-1.2.0/aether/resources/loaders/model_loader.py +185 -0
- aether_engine-1.2.0/aether/resources/loaders/obj_loader.py +57 -0
- aether_engine-1.2.0/aether/resources/save_load.py +20 -0
- aether_engine-1.2.0/aether/scene/component.py +221 -0
- aether_engine-1.2.0/aether/ui/__init__.py +5 -0
- aether_engine-1.2.0/aether/ui/hud.py +65 -0
- aether_engine-1.2.0/aether_engine.egg-info/PKG-INFO +122 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether_engine.egg-info/SOURCES.txt +15 -1
- aether_engine-1.2.0/aether_engine.egg-info/entry_points.txt +2 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether_engine.egg-info/requires.txt +6 -3
- aether_engine-1.2.0/examples/01_hello_cube.py +59 -0
- aether_engine-1.2.0/examples/02_sphere_scene.py +62 -0
- aether_engine-1.2.0/examples/03_first_person.py +99 -0
- aether_engine-1.2.0/examples/04_physics2d.py +67 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/setup.py +41 -28
- aether_engine-1.0.4/PKG-INFO +0 -149
- aether_engine-1.0.4/README.md +0 -108
- aether_engine-1.0.4/aether/__init__.py +0 -1
- aether_engine-1.0.4/aether/core/__init__.py +0 -211
- aether_engine-1.0.4/aether/core/engine.py +0 -211
- aether_engine-1.0.4/aether/graphics/camera.py +0 -69
- aether_engine-1.0.4/aether/graphics/material.py +0 -25
- aether_engine-1.0.4/aether/graphics/mesh.py +0 -83
- aether_engine-1.0.4/aether/graphics/mesh_factory.py +0 -67
- aether_engine-1.0.4/aether/graphics/renderer.py +0 -135
- aether_engine-1.0.4/aether/physics/raycast.py +0 -25
- aether_engine-1.0.4/aether/resources/loaders/obj_loader.py +0 -104
- aether_engine-1.0.4/aether/scene/component.py +0 -368
- aether_engine-1.0.4/aether/ui/__init__.py +0 -0
- aether_engine-1.0.4/aether/utils/__init__.py +0 -0
- aether_engine-1.0.4/aether_engine.egg-info/PKG-INFO +0 -149
- aether_engine-1.0.4/examples/01_hello_cube.py +0 -28
- aether_engine-1.0.4/examples/02_sphere_scene.py +0 -42
- {aether_engine-1.0.4 → aether_engine-1.2.0}/LICENSE +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/MANIFEST.in +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/ai/behavior_tree.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/ai/navmesh.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/animation/skeleton.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/assets/asset_pipeline.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/audio/__init__.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/audio/audio_manager.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/audio/music.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/audio/sound.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/core/achievement_system.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/core/application.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/core/config.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/core/console.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/core/event_bus.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/core/plugin_system.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/core/save_system.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/core/time_manager.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/core/window.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/editor/gizmo.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/editor/imgui_integration.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/environment/environment_system.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/graphics/__init__.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/graphics/framebuffer.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/graphics/light.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/graphics/lod_system.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/graphics/particle_system.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/graphics/post_process.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/graphics/shader.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/graphics/sky_atmosphere.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/graphics/terrain.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/graphics/texture.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/graphics/water.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/network/network_manager.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/physics/bullet_backend.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/physics/collider.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/physics/physics_world.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/physics/rigidbody.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/platform/steam_api.py +0 -0
- {aether_engine-1.0.4/aether/physics → aether_engine-1.2.0/aether/resources}/__init__.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/resources/asset_database.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/resources/loaders/texture_loader.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/resources/resource_manager.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/resources/serialization.py +0 -0
- {aether_engine-1.0.4/aether/resources → aether_engine-1.2.0/aether/scene}/__init__.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/scene/entity.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/scene/scene.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/scene/scene_graph.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/scene/scene_manager.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/ui/button.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/ui/canvas.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/ui/text.py +0 -0
- {aether_engine-1.0.4/aether/scene → aether_engine-1.2.0/aether/utils}/__init__.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/utils/logger.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/utils/math_utils.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/utils/object_pool.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether/utils/profiler.py +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether_engine.egg-info/dependency_links.txt +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/aether_engine.egg-info/top_level.txt +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/pyproject.toml +0 -0
- {aether_engine-1.0.4 → aether_engine-1.2.0}/setup.cfg +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aether-engine
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: 3D/2D game engine by entiti937 — OpenGL, physics, FPS, model editor, HUD
|
|
5
|
+
Home-page: https://pypi.org/project/aether-engine/
|
|
6
|
+
Author: entiti937
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Topic :: Games/Entertainment
|
|
17
|
+
Classifier: Topic :: Multimedia :: Graphics :: 3D Rendering
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: numpy>=1.24
|
|
22
|
+
Requires-Dist: glfw>=2.6
|
|
23
|
+
Requires-Dist: PyOpenGL>=3.1.7
|
|
24
|
+
Requires-Dist: Pillow>=10.0
|
|
25
|
+
Provides-Extra: audio
|
|
26
|
+
Requires-Dist: pygame-ce>=2.5; extra == "audio"
|
|
27
|
+
Provides-Extra: physics
|
|
28
|
+
Requires-Dist: pymunk>=6.0; extra == "physics"
|
|
29
|
+
Provides-Extra: models
|
|
30
|
+
Requires-Dist: trimesh>=3.21; extra == "models"
|
|
31
|
+
Provides-Extra: full
|
|
32
|
+
Requires-Dist: pyyaml>=6.0; extra == "full"
|
|
33
|
+
Requires-Dist: pygame-ce>=2.5; extra == "full"
|
|
34
|
+
Requires-Dist: trimesh>=3.21; extra == "full"
|
|
35
|
+
Requires-Dist: pymunk>=6.0; extra == "full"
|
|
36
|
+
Requires-Dist: freetype-py>=2.4; extra == "full"
|
|
37
|
+
Requires-Dist: imageio>=2.31; extra == "full"
|
|
38
|
+
Dynamic: author
|
|
39
|
+
Dynamic: classifier
|
|
40
|
+
Dynamic: description
|
|
41
|
+
Dynamic: description-content-type
|
|
42
|
+
Dynamic: home-page
|
|
43
|
+
Dynamic: license-file
|
|
44
|
+
Dynamic: provides-extra
|
|
45
|
+
Dynamic: requires-dist
|
|
46
|
+
Dynamic: requires-python
|
|
47
|
+
Dynamic: summary
|
|
48
|
+
|
|
49
|
+
# Aether Engine
|
|
50
|
+
|
|
51
|
+
**3D / 2D игровой движок на Python + OpenGL**
|
|
52
|
+
**Разработчик:** entiti937 · **Версия:** 1.2.0 · **Лицензия:** MIT
|
|
53
|
+
**PyPI:** https://pypi.org/project/aether-engine/
|
|
54
|
+
|
|
55
|
+
> Полное руководство: [`docs/GUIDE.md`](docs/GUIDE.md)
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Установка
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install -U "aether-engine[full]"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Showcase-игра (доказательство)
|
|
66
|
+
|
|
67
|
+
Minecraft-like sandbox **на этом же движке**:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
python games/aether_craft.py
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Там есть: воксельный мир, вид от 1 лица, ломать/ставить блоки, HUD, звуки, день/ночь, сейвы (F5/F9), урон и респавн.
|
|
74
|
+
|
|
75
|
+
## Другие запуски
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
python -m aether.editor
|
|
79
|
+
python games/orb_rush.py
|
|
80
|
+
python examples/03_first_person.py
|
|
81
|
+
python examples/04_physics2d.py
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Минимальный код
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from aether import Engine, Scene, Entity, MeshFactory, Material, Camera
|
|
88
|
+
from aether.scene.component import Transform, MeshRenderer
|
|
89
|
+
|
|
90
|
+
engine = Engine(1280, 720, "Game by you — engine by entiti937")
|
|
91
|
+
scene = Scene("Main")
|
|
92
|
+
camera = Camera(position=(0, 2, 6), yaw=-90)
|
|
93
|
+
scene.set_main_camera(camera)
|
|
94
|
+
|
|
95
|
+
cube = Entity("Cube")
|
|
96
|
+
cube.add_component(Transform(position=(0, 1, 0)))
|
|
97
|
+
mat = Material(); mat.albedo[:] = (0.2, 0.85, 1.0)
|
|
98
|
+
cube.add_component(MeshRenderer(mesh=MeshFactory.create_cube(), material=mat))
|
|
99
|
+
scene.spawn(cube)
|
|
100
|
+
|
|
101
|
+
engine.load_scene(scene)
|
|
102
|
+
engine.enable_first_person(camera)
|
|
103
|
+
engine.run()
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Возможности 1.2
|
|
107
|
+
|
|
108
|
+
- PBR 3D + sprites 2D + HUD overlay
|
|
109
|
+
- FPS (`enable_first_person`) и free-look камера
|
|
110
|
+
- Физика 3D/2D + raycast
|
|
111
|
+
- `ModelLoader` (OBJ/GLB/glTF/STL/FBX/…)
|
|
112
|
+
- Встроенный voxel model editor
|
|
113
|
+
- Procedural SFX, JSON save/load
|
|
114
|
+
- Примеры и две игры в репозитории
|
|
115
|
+
|
|
116
|
+
## Документация
|
|
117
|
+
|
|
118
|
+
Все команды, API и туториалы: **[docs/GUIDE.md](docs/GUIDE.md)**
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
Aether Engine © **entiti937**
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Aether Engine
|
|
2
|
+
|
|
3
|
+
**3D / 2D игровой движок на Python + OpenGL**
|
|
4
|
+
**Разработчик:** entiti937 · **Версия:** 1.2.0 · **Лицензия:** MIT
|
|
5
|
+
**PyPI:** https://pypi.org/project/aether-engine/
|
|
6
|
+
|
|
7
|
+
> Полное руководство: [`docs/GUIDE.md`](docs/GUIDE.md)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Установка
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install -U "aether-engine[full]"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Showcase-игра (доказательство)
|
|
18
|
+
|
|
19
|
+
Minecraft-like sandbox **на этом же движке**:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
python games/aether_craft.py
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Там есть: воксельный мир, вид от 1 лица, ломать/ставить блоки, HUD, звуки, день/ночь, сейвы (F5/F9), урон и респавн.
|
|
26
|
+
|
|
27
|
+
## Другие запуски
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
python -m aether.editor
|
|
31
|
+
python games/orb_rush.py
|
|
32
|
+
python examples/03_first_person.py
|
|
33
|
+
python examples/04_physics2d.py
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Минимальный код
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from aether import Engine, Scene, Entity, MeshFactory, Material, Camera
|
|
40
|
+
from aether.scene.component import Transform, MeshRenderer
|
|
41
|
+
|
|
42
|
+
engine = Engine(1280, 720, "Game by you — engine by entiti937")
|
|
43
|
+
scene = Scene("Main")
|
|
44
|
+
camera = Camera(position=(0, 2, 6), yaw=-90)
|
|
45
|
+
scene.set_main_camera(camera)
|
|
46
|
+
|
|
47
|
+
cube = Entity("Cube")
|
|
48
|
+
cube.add_component(Transform(position=(0, 1, 0)))
|
|
49
|
+
mat = Material(); mat.albedo[:] = (0.2, 0.85, 1.0)
|
|
50
|
+
cube.add_component(MeshRenderer(mesh=MeshFactory.create_cube(), material=mat))
|
|
51
|
+
scene.spawn(cube)
|
|
52
|
+
|
|
53
|
+
engine.load_scene(scene)
|
|
54
|
+
engine.enable_first_person(camera)
|
|
55
|
+
engine.run()
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Возможности 1.2
|
|
59
|
+
|
|
60
|
+
- PBR 3D + sprites 2D + HUD overlay
|
|
61
|
+
- FPS (`enable_first_person`) и free-look камера
|
|
62
|
+
- Физика 3D/2D + raycast
|
|
63
|
+
- `ModelLoader` (OBJ/GLB/glTF/STL/FBX/…)
|
|
64
|
+
- Встроенный voxel model editor
|
|
65
|
+
- Procedural SFX, JSON save/load
|
|
66
|
+
- Примеры и две игры в репозитории
|
|
67
|
+
|
|
68
|
+
## Документация
|
|
69
|
+
|
|
70
|
+
Все команды, API и туториалы: **[docs/GUIDE.md](docs/GUIDE.md)**
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
Aether Engine © **entiti937**
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Aether Engine — 3D / 2D game engine"""
|
|
2
|
+
|
|
3
|
+
from aether.core.engine import Engine
|
|
4
|
+
from aether.scene.scene import Scene
|
|
5
|
+
from aether.scene.entity import Entity
|
|
6
|
+
from aether.scene.component import (
|
|
7
|
+
Transform,
|
|
8
|
+
MeshRenderer,
|
|
9
|
+
CameraComponent,
|
|
10
|
+
LightComponent,
|
|
11
|
+
RigidbodyComponent,
|
|
12
|
+
ScriptComponent,
|
|
13
|
+
)
|
|
14
|
+
from aether.graphics.mesh_factory import MeshFactory
|
|
15
|
+
from aether.graphics.material import Material
|
|
16
|
+
from aether.graphics.camera import Camera
|
|
17
|
+
from aether.graphics.first_person import FirstPersonController
|
|
18
|
+
from aether.resources.loaders.model_loader import ModelLoader
|
|
19
|
+
from aether.physics import PhysicsWorld2D, PhysicsWorld3D, BoxCollider, SphereCollider
|
|
20
|
+
from aether.graphics2d import Renderer2D, Sprite, Camera2D
|
|
21
|
+
from aether.ui.hud import Hud, HudBar
|
|
22
|
+
from aether.audio.sfx import SfxBank
|
|
23
|
+
from aether.resources.save_load import save_json, load_json
|
|
24
|
+
from aether.physics.raycast import Raycaster
|
|
25
|
+
|
|
26
|
+
__version__ = "1.2.0"
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"Engine",
|
|
30
|
+
"Scene",
|
|
31
|
+
"Entity",
|
|
32
|
+
"Transform",
|
|
33
|
+
"MeshRenderer",
|
|
34
|
+
"CameraComponent",
|
|
35
|
+
"LightComponent",
|
|
36
|
+
"RigidbodyComponent",
|
|
37
|
+
"ScriptComponent",
|
|
38
|
+
"MeshFactory",
|
|
39
|
+
"Material",
|
|
40
|
+
"Camera",
|
|
41
|
+
"FirstPersonController",
|
|
42
|
+
"ModelLoader",
|
|
43
|
+
"PhysicsWorld2D",
|
|
44
|
+
"PhysicsWorld3D",
|
|
45
|
+
"BoxCollider",
|
|
46
|
+
"SphereCollider",
|
|
47
|
+
"Renderer2D",
|
|
48
|
+
"Sprite",
|
|
49
|
+
"Camera2D",
|
|
50
|
+
"ModelEditor",
|
|
51
|
+
"Hud",
|
|
52
|
+
"HudBar",
|
|
53
|
+
"SfxBank",
|
|
54
|
+
"save_json",
|
|
55
|
+
"load_json",
|
|
56
|
+
"Raycaster",
|
|
57
|
+
"__version__",
|
|
58
|
+
]
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Procedural sound helpers (no asset files required)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import math
|
|
5
|
+
import struct
|
|
6
|
+
import tempfile
|
|
7
|
+
import wave
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _write_wav(path: Path, samples, rate: int = 22050):
|
|
13
|
+
with wave.open(str(path), "w") as wf:
|
|
14
|
+
wf.setnchannels(1)
|
|
15
|
+
wf.setsampwidth(2)
|
|
16
|
+
wf.setframerate(rate)
|
|
17
|
+
frames = b"".join(struct.pack("<h", int(max(-1, min(1, s)) * 32767)) for s in samples)
|
|
18
|
+
wf.writeframes(frames)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def make_tone(
|
|
22
|
+
frequency: float = 440.0,
|
|
23
|
+
duration: float = 0.08,
|
|
24
|
+
volume: float = 0.35,
|
|
25
|
+
kind: str = "square",
|
|
26
|
+
rate: int = 22050,
|
|
27
|
+
) -> Path:
|
|
28
|
+
"""Generate a short WAV tone and return its path."""
|
|
29
|
+
n = int(rate * duration)
|
|
30
|
+
samples = []
|
|
31
|
+
for i in range(n):
|
|
32
|
+
t = i / rate
|
|
33
|
+
env = 1.0
|
|
34
|
+
if i < rate * 0.01:
|
|
35
|
+
env = i / (rate * 0.01)
|
|
36
|
+
elif i > n - rate * 0.02:
|
|
37
|
+
env = max(0.0, (n - i) / (rate * 0.02))
|
|
38
|
+
phase = 2 * math.pi * frequency * t
|
|
39
|
+
if kind == "sine":
|
|
40
|
+
val = math.sin(phase)
|
|
41
|
+
elif kind == "noise":
|
|
42
|
+
# deterministic pseudo-noise
|
|
43
|
+
val = math.sin(phase * 12.9898) * 2.0 % 2.0 - 1.0
|
|
44
|
+
else:
|
|
45
|
+
val = 1.0 if math.sin(phase) >= 0 else -1.0
|
|
46
|
+
samples.append(val * volume * env)
|
|
47
|
+
|
|
48
|
+
path = Path(tempfile.gettempdir()) / f"aether_tone_{int(frequency)}_{kind}.wav"
|
|
49
|
+
_write_wav(path, samples, rate)
|
|
50
|
+
return path
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class SfxBank:
|
|
54
|
+
"""Lazy bank of procedural SFX played through Engine.audio."""
|
|
55
|
+
|
|
56
|
+
def __init__(self, audio_manager):
|
|
57
|
+
self.audio = audio_manager
|
|
58
|
+
self._cache = {}
|
|
59
|
+
|
|
60
|
+
def _get(self, key: str, factory):
|
|
61
|
+
if key not in self._cache:
|
|
62
|
+
path = factory()
|
|
63
|
+
# AudioManager.load_sound(name, path)
|
|
64
|
+
self._cache[key] = self.audio.load_sound(key, str(path))
|
|
65
|
+
return self._cache[key]
|
|
66
|
+
|
|
67
|
+
def play_break(self):
|
|
68
|
+
snd = self._get("break", lambda: make_tone(180, 0.07, 0.4, "noise"))
|
|
69
|
+
if snd:
|
|
70
|
+
self.audio.play_sound("break", volume=0.45)
|
|
71
|
+
|
|
72
|
+
def play_place(self):
|
|
73
|
+
snd = self._get("place", lambda: make_tone(520, 0.06, 0.3, "square"))
|
|
74
|
+
if snd:
|
|
75
|
+
self.audio.play_sound("place", volume=0.4)
|
|
76
|
+
|
|
77
|
+
def play_select(self):
|
|
78
|
+
snd = self._get("select", lambda: make_tone(760, 0.04, 0.25, "sine"))
|
|
79
|
+
if snd:
|
|
80
|
+
self.audio.play_sound("select", volume=0.35)
|
|
81
|
+
|
|
82
|
+
def play_hurt(self):
|
|
83
|
+
snd = self._get("hurt", lambda: make_tone(120, 0.12, 0.45, "square"))
|
|
84
|
+
if snd:
|
|
85
|
+
self.audio.play_sound("hurt", volume=0.5)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Core subsystem of Aether Engine."""
|
|
2
|
+
|
|
3
|
+
from aether.core.engine import Engine
|
|
4
|
+
from aether.core.window import Window
|
|
5
|
+
from aether.core.input import Input
|
|
6
|
+
from aether.core.time_manager import Time
|
|
7
|
+
from aether.core.event_bus import EventBus
|
|
8
|
+
from aether.core.config import EngineConfig
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"Engine",
|
|
12
|
+
"Window",
|
|
13
|
+
"Input",
|
|
14
|
+
"Time",
|
|
15
|
+
"EventBus",
|
|
16
|
+
"EngineConfig",
|
|
17
|
+
]
|