jeski 0.5.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.
- jeski-0.5.0/PKG-INFO +262 -0
- jeski-0.5.0/README.md +237 -0
- jeski-0.5.0/jeski/__init__.py +245 -0
- jeski-0.5.0/jeski/__main__.py +21 -0
- jeski-0.5.0/jeski/animations.py +32 -0
- jeski-0.5.0/jeski/commands.py +43 -0
- jeski-0.5.0/jeski/config.py +197 -0
- jeski-0.5.0/jeski/credits.py +3 -0
- jeski-0.5.0/jeski/deps.py +39 -0
- jeski-0.5.0/jeski/entities/__init__.py +3 -0
- jeski-0.5.0/jeski/entities/_shapes.py +202 -0
- jeski-0.5.0/jeski/entities/base.py +182 -0
- jeski-0.5.0/jeski/entities/entity.py +550 -0
- jeski-0.5.0/jeski/entities/shapes.py +370 -0
- jeski-0.5.0/jeski/entities/ui.py +114 -0
- jeski-0.5.0/jeski/grid.py +6 -0
- jeski-0.5.0/jeski/imageTools.py +31 -0
- jeski-0.5.0/jeski/math.py +34 -0
- jeski-0.5.0/jeski/mesh.py +108 -0
- jeski-0.5.0/jeski/scripts.py +35 -0
- jeski-0.5.0/jeski/sounds.py +88 -0
- jeski-0.5.0/jeski/tests.py +62 -0
- jeski-0.5.0/jeski/utils.py +364 -0
- jeski-0.5.0/jeski.egg-info/PKG-INFO +262 -0
- jeski-0.5.0/jeski.egg-info/SOURCES.txt +28 -0
- jeski-0.5.0/jeski.egg-info/dependency_links.txt +1 -0
- jeski-0.5.0/jeski.egg-info/requires.txt +6 -0
- jeski-0.5.0/jeski.egg-info/top_level.txt +1 -0
- jeski-0.5.0/setup.cfg +4 -0
- jeski-0.5.0/setup.py +34 -0
jeski-0.5.0/PKG-INFO
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: jeski
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Jeski Project, UI-Development made simple.
|
|
5
|
+
Author: Siddharth
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Requires-Python: >=3.6
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: pygame
|
|
12
|
+
Requires-Dist: pyautogui
|
|
13
|
+
Requires-Dist: keyboard
|
|
14
|
+
Requires-Dist: numpy
|
|
15
|
+
Requires-Dist: asteval
|
|
16
|
+
Requires-Dist: mouse
|
|
17
|
+
Dynamic: author
|
|
18
|
+
Dynamic: classifier
|
|
19
|
+
Dynamic: description
|
|
20
|
+
Dynamic: description-content-type
|
|
21
|
+
Dynamic: license
|
|
22
|
+
Dynamic: requires-dist
|
|
23
|
+
Dynamic: requires-python
|
|
24
|
+
Dynamic: summary
|
|
25
|
+
|
|
26
|
+
# Jeski Engine
|
|
27
|
+
|
|
28
|
+
**Jeski** is a Scratch-inspired 2D game engine and rapid prototyping wrapper built on top of **Pygame**. Created by **Siddharth Barnwal (Enirb)**, Jeski turns verbose Pygame boilerplate into intuitive, object-oriented building blocks—bringing sprites (`Entity`), costumes, stamps, clones, pixel-perfect mask collisions, speech/input bubbles (`Box`), geometric primitives, 1D/2D layout meshes, and multi-threaded background scripts (`Script`) to Python.
|
|
29
|
+
|
|
30
|
+
| Metadata | Details |
|
|
31
|
+
| :--- | :--- |
|
|
32
|
+
| **Package Name** | `Jeski` |
|
|
33
|
+
| **Author** | Siddharth Barnwal (`beast.barnwal` / `Enirb`) |
|
|
34
|
+
| **Engine Backend** | Pygame (`pygame`, `pygame.gfxdraw`) |
|
|
35
|
+
| **Python Compatibility** | Python 3.9+ |
|
|
36
|
+
|
|
37
|
+
## Key Features
|
|
38
|
+
|
|
39
|
+
- **Zero-Boilerplate Engine Loop**: Initialize the display window, audio mixer, clock, and asset folders in a single `INITIALIZE()` call, and refresh frames with `UPDATE()` and `SMOOTH()`.
|
|
40
|
+
- **Scratch-Style `Entity` System**: Create sprites with support for `move()`, `turn()`, `pointTowards()`, `goto()`, `changeXby()`, `changeYby()`, `setSize()`, `changeSize()`, `stamp()`, and `createClone()`.
|
|
41
|
+
- **Costume & Animation Management**: Attach multiple `Costume` objects to any `Entity`, cycle through frames with `nextCostume()` / `previousCostume()`, or run background sprite-sheet loops via `startAnimation()` and `blink()`.
|
|
42
|
+
- **Pixel-Perfect Mask Collisions**: Built-in `touching()` and automatic rollback collision resolution (`check_collisions()`) powered by `pygame.mask`, plus live collision mask debugging (`M` key or `T` hotkey).
|
|
43
|
+
- **Interactive Speech & Input Bubbles**: Prompt players with Scratch-like `askAndWait()`, `say()`, and timed `sayFor()` dialog boxes directly on the canvas.
|
|
44
|
+
- **Rich Vector Shapes & Grouping**: Draw and manipulate `Rectangle`, `CurvedRectangle`, `Circle`, `Ellipse`, `Triangle`, `Polygon`, `Line`, `ZigZag`, and composite `Group` hierarchies (plus non-registered `*F` costume variants like `RectangleF` and `CircleF`).
|
|
45
|
+
- **Reactive UI & Grid Meshes**: Render live global variables on screen with `Variable` and `Text`, trigger native OS dialogs via `MESSAGE`, and align objects effortlessly using `GridMesh1D` and `GridMesh2D`.
|
|
46
|
+
- **Multi-Channel Audio (`SOUNDPLAYER`)**: Play, loop, fade, mute, and block on sound effects with automatic channel cleanup.
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
Install `Jeski` from PyPI using `pip`:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install Jeski
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
To ensure all runtime dependencies are installed alongside `Jeski`:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install pygame numpy pyautogui keyboard mouse asteval safeImport
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
> **Platform Note**: Because `Jeski` uses the `keyboard` and `mouse` libraries for global hotkey polling alongside `pyautogui`, Linux users may need root permissions or X11 display access, and Windows users can use the built-in `RunAsAdmin()` helper when global hooks require elevation.
|
|
63
|
+
|
|
64
|
+
## Quick Start
|
|
65
|
+
|
|
66
|
+
Here is a complete, runnable example demonstrating a player sprite, geometric obstacles, live variable tracking, and keyboard controls:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from Jeski import *
|
|
70
|
+
|
|
71
|
+
# Optional: Set your app name before initializing
|
|
72
|
+
__APPNAME__ = "SpaceDash"
|
|
73
|
+
CONFIG.WINDOWTITLE = "SpaceDash - Jeski Demo"
|
|
74
|
+
CONFIG.backgroundColor = (240, 244, 248)
|
|
75
|
+
|
|
76
|
+
# 1. Start the Jeski Engine
|
|
77
|
+
INITIALIZE(stayInActiveDirectory=True)
|
|
78
|
+
|
|
79
|
+
# 2. Create a score variable and display it on screen
|
|
80
|
+
score = 0
|
|
81
|
+
score_label = Variable("score", x=WINDOW.w // 2, y=30, size=36, color=colors.BLUE)
|
|
82
|
+
|
|
83
|
+
# 3. Create the player Entity (uses a colored rectangle if no image path is provided)
|
|
84
|
+
player = Entity(
|
|
85
|
+
name="Player1",
|
|
86
|
+
x=CONFIG.centerX,
|
|
87
|
+
y=CONFIG.centerY,
|
|
88
|
+
sizeX=50,
|
|
89
|
+
sizeY=50,
|
|
90
|
+
color=colors.RED,
|
|
91
|
+
collider=True
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# 4. Add a decorative Circle shape
|
|
95
|
+
goal = Circle(center=(200, 200), radius=25, color=colors.GREEN)
|
|
96
|
+
|
|
97
|
+
# 5. Main game loop
|
|
98
|
+
while CORE.RUNNING:
|
|
99
|
+
UPDATE()
|
|
100
|
+
|
|
101
|
+
# Poll movement keys using Pygame's key state in CORE.KEYS
|
|
102
|
+
if CORE.KEYS[pygame.K_w] or CORE.KEYS[pygame.K_UP]:
|
|
103
|
+
player.move(6)
|
|
104
|
+
if CORE.KEYS[pygame.K_s] or CORE.KEYS[pygame.K_DOWN]:
|
|
105
|
+
player.move(-6)
|
|
106
|
+
if CORE.KEYS[pygame.K_a] or CORE.KEYS[pygame.K_LEFT]:
|
|
107
|
+
player.turn(-4)
|
|
108
|
+
if CORE.KEYS[pygame.K_d] or CORE.KEYS[pygame.K_RIGHT]:
|
|
109
|
+
player.turn(4)
|
|
110
|
+
|
|
111
|
+
# Check pixel-perfect collision with the goal circle
|
|
112
|
+
if player.touching(goal):
|
|
113
|
+
score += 1
|
|
114
|
+
goal.center = (random.randint(60, WINDOW.w - 60), random.randint(60, WINDOW.h - 60))
|
|
115
|
+
goal.refresh()
|
|
116
|
+
|
|
117
|
+
SMOOTH()
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Core Architecture & API Reference
|
|
121
|
+
|
|
122
|
+
### 1. Engine Lifecycle (`__init__.py`)
|
|
123
|
+
|
|
124
|
+
| Function | Description |
|
|
125
|
+
| :--- | :--- |
|
|
126
|
+
| `INITIALIZE(**kwargs)` | Initializes Pygame, mixer, fonts, `CORE.SCREEN`, `CORE.CLOCK`, and asset directories. Pass `stayInActiveDirectory=True` to keep your current working directory. Alias: `INITIALISE()`. |
|
|
127
|
+
| `UPDATE()` | Clears the screen with `CONFIG.backgroundColor`, processes window/input events (`UPDATEVARS()`), updates `SOUNDPLAYER`, renders all stamps and entities (`DRAWSCREEN()`), and ticks `CORE.CLOCK` at `CONFIG.FPS`. |
|
|
128
|
+
| `SMOOTH(smooth=None, noPauseWait=False)` | Sleeps for `CONFIG.smoothWait` (default `1/60` sec) and yields execution while honoring `CONFIG.PAUSED`. |
|
|
129
|
+
| `SHUTDOWN()` / `QUIT()` | Stops the engine loop (`CORE.RUNNING = False`) or posts a `pygame.QUIT` event. |
|
|
130
|
+
| `startConfigSync(data_dict)` | Starts a background `Script` that continuously synchronizes a dictionary of variable names with the caller's global scope. |
|
|
131
|
+
|
|
132
|
+
### 2. Sprites & Entities (`entities/entity.py`)
|
|
133
|
+
|
|
134
|
+
`Entity` is the core sprite class in Jeski. Every `Entity` is automatically added to `CORE.ENTITIES` (unless `type='Stamp'`) and rendered each frame.
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
hero = Entity(
|
|
138
|
+
image="hero.png", # Optional path to image file (or pass rawimage=Surface)
|
|
139
|
+
x=300, y=300, # Defaults to screen center (CONFIG.centerX, CONFIG.centerY)
|
|
140
|
+
sizeX=64, sizeY=64, # Dimensions when using procedural rectangle fallback
|
|
141
|
+
color=colors.BLUE, # Fill color if no image is supplied
|
|
142
|
+
centered=True, # Center sprite on (x, y)
|
|
143
|
+
collider=True # Enable automatic collision rollback in check_collisions()
|
|
144
|
+
)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
#### Movement, Rotation & Scaling
|
|
148
|
+
|
|
149
|
+
- `hero.move(steps, raw=False)`: Moves forward along `hero.direction` (clamped to window bounds unless `raw=True`).
|
|
150
|
+
- `hero.turn(deg)`: Rotates the entity by `deg` degrees and checks collisions.
|
|
151
|
+
- `hero.pointTowards(other_entity)`: Rotates to face another entity's `(x, y)` coordinates.
|
|
152
|
+
- `hero.goto(x, y)` / `hero._goto(other_entity)`: Teleports to coordinates or another entity's position.
|
|
153
|
+
- `hero.changeXby(steps)` (`chx`) / `hero.changeYby(steps)` (`chy`): Moves along a single axis with collision rollback.
|
|
154
|
+
- `hero.setSize(percent)` / `hero.changeSize(delta_percent)` (`chs`) / `hero.setSizeToVal((w, h))`: Scales `original_image` smoothly using `pygame.transform.smoothscale`.
|
|
155
|
+
- `hero.rotationStyle`: Set to `2` for full 360° rotation (default), `1` for left-right horizontal flip, or `0` for fixed orientation.
|
|
156
|
+
|
|
157
|
+
#### Costumes, Visual Effects & Layering
|
|
158
|
+
|
|
159
|
+
- `hero.addCostume(Costume(name, obj))` / `hero.removeCostume(idx)`: Manages the entity's costume list.
|
|
160
|
+
- `hero.nextCostume()` / `hero.previousCostume()` / `hero.changeCostume(idx)`: Switches active appearance.
|
|
161
|
+
- `hero.transparency`: Value from `0` (opaque) to `255` (invisible).
|
|
162
|
+
- `hero.brightness`: Positive values (`0` to `255`) brighten via `BLEND_RGBA_ADD`; negative values darken via `BLEND_RGBA_SUB`.
|
|
163
|
+
- `hero.hide()` / `hero.show()`: Toggles visibility.
|
|
164
|
+
- `hero.bringToFront()` / `hero.sendToBack()`: Reorders draw priority inside `CORE.ENTITIES`.
|
|
165
|
+
|
|
166
|
+
#### Clones, Stamps & Collisions
|
|
167
|
+
|
|
168
|
+
- `hero.stamp(var=None, ret=False)`: Leaves a static visual copy on `CORE.STAMPS` (press `Q` at runtime to clear stamps).
|
|
169
|
+
- `hero.createClone(ret=False, config=None)`: Spawns an independent `Clone` entity inheriting position, direction, costumes, and variables.
|
|
170
|
+
- `hero.touching(other_or_mouse)`: Returns `True` on pixel-perfect mask overlap with another entity or `'__mouse__'`.
|
|
171
|
+
- `hero.isClicked()`: Returns `True` if the mouse button is down and touching the entity's mask.
|
|
172
|
+
- `hero.delete()`: Removes the entity from `CORE.ENTITIES` and any registered reference lists.
|
|
173
|
+
|
|
174
|
+
#### Dialogs (`Box`)
|
|
175
|
+
|
|
176
|
+
- `answer = hero.askAndWait("What is your name?")`: Opens an interactive text input box next to the entity and returns the submitted string.
|
|
177
|
+
- `hero.sayFor("Hello!", timeout=2)`: Displays a speech bubble for `timeout` seconds.
|
|
178
|
+
- `hero.say("Thinking...")`: Displays a persistent speech bubble bound to `hero.var['msg']` (set `hero.var['msg'] = ''` to dismiss).
|
|
179
|
+
|
|
180
|
+
### 3. Geometric Shapes & Groups (`entities/shapes.py`)
|
|
181
|
+
|
|
182
|
+
All shapes support `BASICDRAW` caching, masks, and `Entity` helper methods via `verifyAttributes()`. Each class also provides a `*F` subclass (e.g., `RectangleF`, `CircleF`, `PolygonF`) with `trueEntity=False` for building `Costume` objects or composite `Group` hierarchies without adding sub-parts directly to `CORE.ENTITIES`.
|
|
183
|
+
|
|
184
|
+
| Shape Class | Constructor Signature |
|
|
185
|
+
| :--- | :--- |
|
|
186
|
+
| `Image` / `ImageF` | `Image(path, x=None, y=None, raw=False, trueEntity=True)` |
|
|
187
|
+
| `Rectangle` / `RectangleF` | `Rectangle(x, y, w, h, color=colors.BLACK, trueEntity=True)` |
|
|
188
|
+
| `CurvedRectangle` / `CurvedRectangleF` | `CurvedRectangle(x, y, w, h, curve, color=colors.BLACK, trueEntity=True)` |
|
|
189
|
+
| `Circle` / `CircleF` | `Circle(center, radius, width=0, color=colors.BLACK, trueEntity=True)` |
|
|
190
|
+
| `Ellipse` / `EllipseF` | `Ellipse(center, radiusMinor, radiusMajor, width=0, color=colors.BLACK, trueEntity=True)` |
|
|
191
|
+
| `Triangle` / `TriangleF` | `Triangle(cord1, cord2, cord3, color=colors.BLACK, trueEntity=True)` |
|
|
192
|
+
| `Polygon` / `PolygonF` | `Polygon(cords, color=colors.BLACK, trueEntity=True)` |
|
|
193
|
+
| `Line` / `LineF` | `Line(cord1, cord2, color=colors.BLACK, width=5, trueEntity=True)` |
|
|
194
|
+
| `ZigZag` / `ZigZagF` | `ZigZag(cords, color=colors.BLACK, width=5, trueEntity=True)` |
|
|
195
|
+
| `Group` / `GroupF` | `Group(attributes=None, entities=None, tight=False, trueEntity=True)` |
|
|
196
|
+
|
|
197
|
+
### 4. UI, Text, Grids & Meshes (`entities/ui.py`, `mesh.py`)
|
|
198
|
+
|
|
199
|
+
- **`Text(text, x, y, font=None, size=40, align='center', color=colors.BLACK)`**: Renders cached Pygame font surfaces. Update properties dynamically with `text_obj.change('text', 'New Value')`.
|
|
200
|
+
- **`Variable(variable_name, x, y, size=40, color=colors.BLACK)`**: Subclasses `Text` and spawns a background `Script` that watches a global variable by name (e.g., `Variable('score', 100, 50)`) and re-renders automatically whenever its value changes.
|
|
201
|
+
- **`MESSAGE`**: Static wrapper around `tkinter.messagebox` providing `info()`, `warning()` / `warn()`, `error()`, `yesNo()`, `okCancel()`, `retryCancel()`, and `yesNoCancel()`.
|
|
202
|
+
- **`GridMesh2D(x=10, y=10, center=True, margin=0)` & `GridMesh1D(type='x', c=10, center=True, margin=0)`**: Automatically computes cell widths/heights across `WINDOW` and positions objects added via `.add(obj, coords=(col, row))`.
|
|
203
|
+
|
|
204
|
+
### 5. Animations, Audio & Concurrency (`animations.py`, `sounds.py`, `scripts.py`)
|
|
205
|
+
|
|
206
|
+
- **`Script(function, starter='CORE.RUNNING', once=True, loop=None, waitUntilFinished=False)`**: Runs `function` in a daemon thread when the `starter` expression evaluates to truthy.
|
|
207
|
+
- **`startAnimation(obj, costs=[0, 1, 2], fps=10)`**: Cycles `obj` through the specified costume indices at `fps` frames per second in a background `Script`.
|
|
208
|
+
- **`blink(obj, fast=False)`**: Pulses an entity's brightness up to `100` and back to its original value.
|
|
209
|
+
- **`SOUNDPLAYER`**:
|
|
210
|
+
- `SOUNDPLAYER.play(sound, raw=False, config={'volume': 50, 'loops': 0, 'fade_ms': 0}, untilFinished=False)`
|
|
211
|
+
- `SOUNDPLAYER.setMasterVolume(80)`
|
|
212
|
+
- `SOUNDPLAYER.fadeAll(500)` / `SOUNDPLAYER.stopAll()`
|
|
213
|
+
- `SOUNDPLAYER.mute()` / `SOUNDPLAYER.unmute()`
|
|
214
|
+
|
|
215
|
+
### 6. Configuration & Built-in Shortcuts (`config.py`)
|
|
216
|
+
|
|
217
|
+
Customize `WINDOW` and `CONFIG` before calling `INITIALIZE()`:
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
WINDOW.WIDTH = 1280
|
|
221
|
+
WINDOW.HEIGHT = 720
|
|
222
|
+
CONFIG.WINDOWTITLE = "My Jeski Game"
|
|
223
|
+
CONFIG.FPS = 60
|
|
224
|
+
CONFIG.backgroundColor = colors.WHITE
|
|
225
|
+
CONFIG.debug = True
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Built-in Runtime Hotkeys:**
|
|
229
|
+
- **`M` key** (or **`T`** when `CONFIG.debug = True`): Toggles red/translucent collision mask overlays (`CONFIG.showMask`) across all entities.
|
|
230
|
+
- **`Q` key**: Clears all `Stamp` entities from `CORE.ENTITIES`.
|
|
231
|
+
|
|
232
|
+
## Project Structure
|
|
233
|
+
|
|
234
|
+
```text
|
|
235
|
+
Jeski/
|
|
236
|
+
├── __init__.py # Engine lifecycle (INITIALIZE, UPDATE, DRAWSCREEN, UPDATEVARS)
|
|
237
|
+
├── __main__.py # Built-in 2-player demo script
|
|
238
|
+
├── animations.py # Costume frame animation and brightness blink effects
|
|
239
|
+
├── commands.py # Shell execution (RunCommand), PyInstaller paths, UAC elevation
|
|
240
|
+
├── config.py # CORE state, WINDOW dimensions, CONFIG settings, colors, GUI aliases
|
|
241
|
+
├── credits.py # Author metadata
|
|
242
|
+
├── deps.py # Dependency imports and safeImport verification fallback
|
|
243
|
+
├── grid.py # Grid module stub (implemented in utils.py / __init__.py)
|
|
244
|
+
├── imageTools.py # Surface brightness and alpha manipulation helpers
|
|
245
|
+
├── mesh.py # GridMesh1D and GridMesh2D layout managers
|
|
246
|
+
├── scripts.py # Threaded Script runner and roughScript helper
|
|
247
|
+
├── sounds.py # SOUNDPLAYER multi-channel mixer controller
|
|
248
|
+
├── tests.py # Interactive live-variable entity test harness (TESTS_)
|
|
249
|
+
├── utils.py # Surface compositing, attribute verification, eval helpers, timing
|
|
250
|
+
├── assets/ # Built-in WAV sound effects (alert.wav, coin.wav, Lose.wav)
|
|
251
|
+
└── entities/
|
|
252
|
+
├── __init__.py # Exports Entity, shapes, and UI classes
|
|
253
|
+
├── base.py # BASICDRAW surface caching, rotation, brightness, mask overlay
|
|
254
|
+
├── entity.py # Core Entity, Costume, and Box (say/ask) classes
|
|
255
|
+
├── shapes.py # Vector shapes, Group compositor, and *F non-entity subclasses
|
|
256
|
+
├── _shapes.py # Legacy shapes module
|
|
257
|
+
└── ui.py # MESSAGE dialogs, Text renderer, and reactive Variable widget
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Author & Credits
|
|
261
|
+
|
|
262
|
+
Created and maintained by **Siddharth Barnwal** (`Enirb` / `beast.barnwal`).
|
jeski-0.5.0/README.md
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# Jeski Engine
|
|
2
|
+
|
|
3
|
+
**Jeski** is a Scratch-inspired 2D game engine and rapid prototyping wrapper built on top of **Pygame**. Created by **Siddharth Barnwal (Enirb)**, Jeski turns verbose Pygame boilerplate into intuitive, object-oriented building blocks—bringing sprites (`Entity`), costumes, stamps, clones, pixel-perfect mask collisions, speech/input bubbles (`Box`), geometric primitives, 1D/2D layout meshes, and multi-threaded background scripts (`Script`) to Python.
|
|
4
|
+
|
|
5
|
+
| Metadata | Details |
|
|
6
|
+
| :--- | :--- |
|
|
7
|
+
| **Package Name** | `Jeski` |
|
|
8
|
+
| **Author** | Siddharth Barnwal (`beast.barnwal` / `Enirb`) |
|
|
9
|
+
| **Engine Backend** | Pygame (`pygame`, `pygame.gfxdraw`) |
|
|
10
|
+
| **Python Compatibility** | Python 3.9+ |
|
|
11
|
+
|
|
12
|
+
## Key Features
|
|
13
|
+
|
|
14
|
+
- **Zero-Boilerplate Engine Loop**: Initialize the display window, audio mixer, clock, and asset folders in a single `INITIALIZE()` call, and refresh frames with `UPDATE()` and `SMOOTH()`.
|
|
15
|
+
- **Scratch-Style `Entity` System**: Create sprites with support for `move()`, `turn()`, `pointTowards()`, `goto()`, `changeXby()`, `changeYby()`, `setSize()`, `changeSize()`, `stamp()`, and `createClone()`.
|
|
16
|
+
- **Costume & Animation Management**: Attach multiple `Costume` objects to any `Entity`, cycle through frames with `nextCostume()` / `previousCostume()`, or run background sprite-sheet loops via `startAnimation()` and `blink()`.
|
|
17
|
+
- **Pixel-Perfect Mask Collisions**: Built-in `touching()` and automatic rollback collision resolution (`check_collisions()`) powered by `pygame.mask`, plus live collision mask debugging (`M` key or `T` hotkey).
|
|
18
|
+
- **Interactive Speech & Input Bubbles**: Prompt players with Scratch-like `askAndWait()`, `say()`, and timed `sayFor()` dialog boxes directly on the canvas.
|
|
19
|
+
- **Rich Vector Shapes & Grouping**: Draw and manipulate `Rectangle`, `CurvedRectangle`, `Circle`, `Ellipse`, `Triangle`, `Polygon`, `Line`, `ZigZag`, and composite `Group` hierarchies (plus non-registered `*F` costume variants like `RectangleF` and `CircleF`).
|
|
20
|
+
- **Reactive UI & Grid Meshes**: Render live global variables on screen with `Variable` and `Text`, trigger native OS dialogs via `MESSAGE`, and align objects effortlessly using `GridMesh1D` and `GridMesh2D`.
|
|
21
|
+
- **Multi-Channel Audio (`SOUNDPLAYER`)**: Play, loop, fade, mute, and block on sound effects with automatic channel cleanup.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
Install `Jeski` from PyPI using `pip`:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install Jeski
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
To ensure all runtime dependencies are installed alongside `Jeski`:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install pygame numpy pyautogui keyboard mouse asteval safeImport
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
> **Platform Note**: Because `Jeski` uses the `keyboard` and `mouse` libraries for global hotkey polling alongside `pyautogui`, Linux users may need root permissions or X11 display access, and Windows users can use the built-in `RunAsAdmin()` helper when global hooks require elevation.
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
Here is a complete, runnable example demonstrating a player sprite, geometric obstacles, live variable tracking, and keyboard controls:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from Jeski import *
|
|
45
|
+
|
|
46
|
+
# Optional: Set your app name before initializing
|
|
47
|
+
__APPNAME__ = "SpaceDash"
|
|
48
|
+
CONFIG.WINDOWTITLE = "SpaceDash - Jeski Demo"
|
|
49
|
+
CONFIG.backgroundColor = (240, 244, 248)
|
|
50
|
+
|
|
51
|
+
# 1. Start the Jeski Engine
|
|
52
|
+
INITIALIZE(stayInActiveDirectory=True)
|
|
53
|
+
|
|
54
|
+
# 2. Create a score variable and display it on screen
|
|
55
|
+
score = 0
|
|
56
|
+
score_label = Variable("score", x=WINDOW.w // 2, y=30, size=36, color=colors.BLUE)
|
|
57
|
+
|
|
58
|
+
# 3. Create the player Entity (uses a colored rectangle if no image path is provided)
|
|
59
|
+
player = Entity(
|
|
60
|
+
name="Player1",
|
|
61
|
+
x=CONFIG.centerX,
|
|
62
|
+
y=CONFIG.centerY,
|
|
63
|
+
sizeX=50,
|
|
64
|
+
sizeY=50,
|
|
65
|
+
color=colors.RED,
|
|
66
|
+
collider=True
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# 4. Add a decorative Circle shape
|
|
70
|
+
goal = Circle(center=(200, 200), radius=25, color=colors.GREEN)
|
|
71
|
+
|
|
72
|
+
# 5. Main game loop
|
|
73
|
+
while CORE.RUNNING:
|
|
74
|
+
UPDATE()
|
|
75
|
+
|
|
76
|
+
# Poll movement keys using Pygame's key state in CORE.KEYS
|
|
77
|
+
if CORE.KEYS[pygame.K_w] or CORE.KEYS[pygame.K_UP]:
|
|
78
|
+
player.move(6)
|
|
79
|
+
if CORE.KEYS[pygame.K_s] or CORE.KEYS[pygame.K_DOWN]:
|
|
80
|
+
player.move(-6)
|
|
81
|
+
if CORE.KEYS[pygame.K_a] or CORE.KEYS[pygame.K_LEFT]:
|
|
82
|
+
player.turn(-4)
|
|
83
|
+
if CORE.KEYS[pygame.K_d] or CORE.KEYS[pygame.K_RIGHT]:
|
|
84
|
+
player.turn(4)
|
|
85
|
+
|
|
86
|
+
# Check pixel-perfect collision with the goal circle
|
|
87
|
+
if player.touching(goal):
|
|
88
|
+
score += 1
|
|
89
|
+
goal.center = (random.randint(60, WINDOW.w - 60), random.randint(60, WINDOW.h - 60))
|
|
90
|
+
goal.refresh()
|
|
91
|
+
|
|
92
|
+
SMOOTH()
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Core Architecture & API Reference
|
|
96
|
+
|
|
97
|
+
### 1. Engine Lifecycle (`__init__.py`)
|
|
98
|
+
|
|
99
|
+
| Function | Description |
|
|
100
|
+
| :--- | :--- |
|
|
101
|
+
| `INITIALIZE(**kwargs)` | Initializes Pygame, mixer, fonts, `CORE.SCREEN`, `CORE.CLOCK`, and asset directories. Pass `stayInActiveDirectory=True` to keep your current working directory. Alias: `INITIALISE()`. |
|
|
102
|
+
| `UPDATE()` | Clears the screen with `CONFIG.backgroundColor`, processes window/input events (`UPDATEVARS()`), updates `SOUNDPLAYER`, renders all stamps and entities (`DRAWSCREEN()`), and ticks `CORE.CLOCK` at `CONFIG.FPS`. |
|
|
103
|
+
| `SMOOTH(smooth=None, noPauseWait=False)` | Sleeps for `CONFIG.smoothWait` (default `1/60` sec) and yields execution while honoring `CONFIG.PAUSED`. |
|
|
104
|
+
| `SHUTDOWN()` / `QUIT()` | Stops the engine loop (`CORE.RUNNING = False`) or posts a `pygame.QUIT` event. |
|
|
105
|
+
| `startConfigSync(data_dict)` | Starts a background `Script` that continuously synchronizes a dictionary of variable names with the caller's global scope. |
|
|
106
|
+
|
|
107
|
+
### 2. Sprites & Entities (`entities/entity.py`)
|
|
108
|
+
|
|
109
|
+
`Entity` is the core sprite class in Jeski. Every `Entity` is automatically added to `CORE.ENTITIES` (unless `type='Stamp'`) and rendered each frame.
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
hero = Entity(
|
|
113
|
+
image="hero.png", # Optional path to image file (or pass rawimage=Surface)
|
|
114
|
+
x=300, y=300, # Defaults to screen center (CONFIG.centerX, CONFIG.centerY)
|
|
115
|
+
sizeX=64, sizeY=64, # Dimensions when using procedural rectangle fallback
|
|
116
|
+
color=colors.BLUE, # Fill color if no image is supplied
|
|
117
|
+
centered=True, # Center sprite on (x, y)
|
|
118
|
+
collider=True # Enable automatic collision rollback in check_collisions()
|
|
119
|
+
)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### Movement, Rotation & Scaling
|
|
123
|
+
|
|
124
|
+
- `hero.move(steps, raw=False)`: Moves forward along `hero.direction` (clamped to window bounds unless `raw=True`).
|
|
125
|
+
- `hero.turn(deg)`: Rotates the entity by `deg` degrees and checks collisions.
|
|
126
|
+
- `hero.pointTowards(other_entity)`: Rotates to face another entity's `(x, y)` coordinates.
|
|
127
|
+
- `hero.goto(x, y)` / `hero._goto(other_entity)`: Teleports to coordinates or another entity's position.
|
|
128
|
+
- `hero.changeXby(steps)` (`chx`) / `hero.changeYby(steps)` (`chy`): Moves along a single axis with collision rollback.
|
|
129
|
+
- `hero.setSize(percent)` / `hero.changeSize(delta_percent)` (`chs`) / `hero.setSizeToVal((w, h))`: Scales `original_image` smoothly using `pygame.transform.smoothscale`.
|
|
130
|
+
- `hero.rotationStyle`: Set to `2` for full 360° rotation (default), `1` for left-right horizontal flip, or `0` for fixed orientation.
|
|
131
|
+
|
|
132
|
+
#### Costumes, Visual Effects & Layering
|
|
133
|
+
|
|
134
|
+
- `hero.addCostume(Costume(name, obj))` / `hero.removeCostume(idx)`: Manages the entity's costume list.
|
|
135
|
+
- `hero.nextCostume()` / `hero.previousCostume()` / `hero.changeCostume(idx)`: Switches active appearance.
|
|
136
|
+
- `hero.transparency`: Value from `0` (opaque) to `255` (invisible).
|
|
137
|
+
- `hero.brightness`: Positive values (`0` to `255`) brighten via `BLEND_RGBA_ADD`; negative values darken via `BLEND_RGBA_SUB`.
|
|
138
|
+
- `hero.hide()` / `hero.show()`: Toggles visibility.
|
|
139
|
+
- `hero.bringToFront()` / `hero.sendToBack()`: Reorders draw priority inside `CORE.ENTITIES`.
|
|
140
|
+
|
|
141
|
+
#### Clones, Stamps & Collisions
|
|
142
|
+
|
|
143
|
+
- `hero.stamp(var=None, ret=False)`: Leaves a static visual copy on `CORE.STAMPS` (press `Q` at runtime to clear stamps).
|
|
144
|
+
- `hero.createClone(ret=False, config=None)`: Spawns an independent `Clone` entity inheriting position, direction, costumes, and variables.
|
|
145
|
+
- `hero.touching(other_or_mouse)`: Returns `True` on pixel-perfect mask overlap with another entity or `'__mouse__'`.
|
|
146
|
+
- `hero.isClicked()`: Returns `True` if the mouse button is down and touching the entity's mask.
|
|
147
|
+
- `hero.delete()`: Removes the entity from `CORE.ENTITIES` and any registered reference lists.
|
|
148
|
+
|
|
149
|
+
#### Dialogs (`Box`)
|
|
150
|
+
|
|
151
|
+
- `answer = hero.askAndWait("What is your name?")`: Opens an interactive text input box next to the entity and returns the submitted string.
|
|
152
|
+
- `hero.sayFor("Hello!", timeout=2)`: Displays a speech bubble for `timeout` seconds.
|
|
153
|
+
- `hero.say("Thinking...")`: Displays a persistent speech bubble bound to `hero.var['msg']` (set `hero.var['msg'] = ''` to dismiss).
|
|
154
|
+
|
|
155
|
+
### 3. Geometric Shapes & Groups (`entities/shapes.py`)
|
|
156
|
+
|
|
157
|
+
All shapes support `BASICDRAW` caching, masks, and `Entity` helper methods via `verifyAttributes()`. Each class also provides a `*F` subclass (e.g., `RectangleF`, `CircleF`, `PolygonF`) with `trueEntity=False` for building `Costume` objects or composite `Group` hierarchies without adding sub-parts directly to `CORE.ENTITIES`.
|
|
158
|
+
|
|
159
|
+
| Shape Class | Constructor Signature |
|
|
160
|
+
| :--- | :--- |
|
|
161
|
+
| `Image` / `ImageF` | `Image(path, x=None, y=None, raw=False, trueEntity=True)` |
|
|
162
|
+
| `Rectangle` / `RectangleF` | `Rectangle(x, y, w, h, color=colors.BLACK, trueEntity=True)` |
|
|
163
|
+
| `CurvedRectangle` / `CurvedRectangleF` | `CurvedRectangle(x, y, w, h, curve, color=colors.BLACK, trueEntity=True)` |
|
|
164
|
+
| `Circle` / `CircleF` | `Circle(center, radius, width=0, color=colors.BLACK, trueEntity=True)` |
|
|
165
|
+
| `Ellipse` / `EllipseF` | `Ellipse(center, radiusMinor, radiusMajor, width=0, color=colors.BLACK, trueEntity=True)` |
|
|
166
|
+
| `Triangle` / `TriangleF` | `Triangle(cord1, cord2, cord3, color=colors.BLACK, trueEntity=True)` |
|
|
167
|
+
| `Polygon` / `PolygonF` | `Polygon(cords, color=colors.BLACK, trueEntity=True)` |
|
|
168
|
+
| `Line` / `LineF` | `Line(cord1, cord2, color=colors.BLACK, width=5, trueEntity=True)` |
|
|
169
|
+
| `ZigZag` / `ZigZagF` | `ZigZag(cords, color=colors.BLACK, width=5, trueEntity=True)` |
|
|
170
|
+
| `Group` / `GroupF` | `Group(attributes=None, entities=None, tight=False, trueEntity=True)` |
|
|
171
|
+
|
|
172
|
+
### 4. UI, Text, Grids & Meshes (`entities/ui.py`, `mesh.py`)
|
|
173
|
+
|
|
174
|
+
- **`Text(text, x, y, font=None, size=40, align='center', color=colors.BLACK)`**: Renders cached Pygame font surfaces. Update properties dynamically with `text_obj.change('text', 'New Value')`.
|
|
175
|
+
- **`Variable(variable_name, x, y, size=40, color=colors.BLACK)`**: Subclasses `Text` and spawns a background `Script` that watches a global variable by name (e.g., `Variable('score', 100, 50)`) and re-renders automatically whenever its value changes.
|
|
176
|
+
- **`MESSAGE`**: Static wrapper around `tkinter.messagebox` providing `info()`, `warning()` / `warn()`, `error()`, `yesNo()`, `okCancel()`, `retryCancel()`, and `yesNoCancel()`.
|
|
177
|
+
- **`GridMesh2D(x=10, y=10, center=True, margin=0)` & `GridMesh1D(type='x', c=10, center=True, margin=0)`**: Automatically computes cell widths/heights across `WINDOW` and positions objects added via `.add(obj, coords=(col, row))`.
|
|
178
|
+
|
|
179
|
+
### 5. Animations, Audio & Concurrency (`animations.py`, `sounds.py`, `scripts.py`)
|
|
180
|
+
|
|
181
|
+
- **`Script(function, starter='CORE.RUNNING', once=True, loop=None, waitUntilFinished=False)`**: Runs `function` in a daemon thread when the `starter` expression evaluates to truthy.
|
|
182
|
+
- **`startAnimation(obj, costs=[0, 1, 2], fps=10)`**: Cycles `obj` through the specified costume indices at `fps` frames per second in a background `Script`.
|
|
183
|
+
- **`blink(obj, fast=False)`**: Pulses an entity's brightness up to `100` and back to its original value.
|
|
184
|
+
- **`SOUNDPLAYER`**:
|
|
185
|
+
- `SOUNDPLAYER.play(sound, raw=False, config={'volume': 50, 'loops': 0, 'fade_ms': 0}, untilFinished=False)`
|
|
186
|
+
- `SOUNDPLAYER.setMasterVolume(80)`
|
|
187
|
+
- `SOUNDPLAYER.fadeAll(500)` / `SOUNDPLAYER.stopAll()`
|
|
188
|
+
- `SOUNDPLAYER.mute()` / `SOUNDPLAYER.unmute()`
|
|
189
|
+
|
|
190
|
+
### 6. Configuration & Built-in Shortcuts (`config.py`)
|
|
191
|
+
|
|
192
|
+
Customize `WINDOW` and `CONFIG` before calling `INITIALIZE()`:
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
WINDOW.WIDTH = 1280
|
|
196
|
+
WINDOW.HEIGHT = 720
|
|
197
|
+
CONFIG.WINDOWTITLE = "My Jeski Game"
|
|
198
|
+
CONFIG.FPS = 60
|
|
199
|
+
CONFIG.backgroundColor = colors.WHITE
|
|
200
|
+
CONFIG.debug = True
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Built-in Runtime Hotkeys:**
|
|
204
|
+
- **`M` key** (or **`T`** when `CONFIG.debug = True`): Toggles red/translucent collision mask overlays (`CONFIG.showMask`) across all entities.
|
|
205
|
+
- **`Q` key**: Clears all `Stamp` entities from `CORE.ENTITIES`.
|
|
206
|
+
|
|
207
|
+
## Project Structure
|
|
208
|
+
|
|
209
|
+
```text
|
|
210
|
+
Jeski/
|
|
211
|
+
├── __init__.py # Engine lifecycle (INITIALIZE, UPDATE, DRAWSCREEN, UPDATEVARS)
|
|
212
|
+
├── __main__.py # Built-in 2-player demo script
|
|
213
|
+
├── animations.py # Costume frame animation and brightness blink effects
|
|
214
|
+
├── commands.py # Shell execution (RunCommand), PyInstaller paths, UAC elevation
|
|
215
|
+
├── config.py # CORE state, WINDOW dimensions, CONFIG settings, colors, GUI aliases
|
|
216
|
+
├── credits.py # Author metadata
|
|
217
|
+
├── deps.py # Dependency imports and safeImport verification fallback
|
|
218
|
+
├── grid.py # Grid module stub (implemented in utils.py / __init__.py)
|
|
219
|
+
├── imageTools.py # Surface brightness and alpha manipulation helpers
|
|
220
|
+
├── mesh.py # GridMesh1D and GridMesh2D layout managers
|
|
221
|
+
├── scripts.py # Threaded Script runner and roughScript helper
|
|
222
|
+
├── sounds.py # SOUNDPLAYER multi-channel mixer controller
|
|
223
|
+
├── tests.py # Interactive live-variable entity test harness (TESTS_)
|
|
224
|
+
├── utils.py # Surface compositing, attribute verification, eval helpers, timing
|
|
225
|
+
├── assets/ # Built-in WAV sound effects (alert.wav, coin.wav, Lose.wav)
|
|
226
|
+
└── entities/
|
|
227
|
+
├── __init__.py # Exports Entity, shapes, and UI classes
|
|
228
|
+
├── base.py # BASICDRAW surface caching, rotation, brightness, mask overlay
|
|
229
|
+
├── entity.py # Core Entity, Costume, and Box (say/ask) classes
|
|
230
|
+
├── shapes.py # Vector shapes, Group compositor, and *F non-entity subclasses
|
|
231
|
+
├── _shapes.py # Legacy shapes module
|
|
232
|
+
└── ui.py # MESSAGE dialogs, Text renderer, and reactive Variable widget
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Author & Credits
|
|
236
|
+
|
|
237
|
+
Created and maintained by **Siddharth Barnwal** (`Enirb` / `beast.barnwal`).
|