Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ __pycache__/
# built zip are artifacts -- dist/INSTALL.md is the tracked source.
/dist/*.zip
/dist/*.livecode
/dist/*.oxtstack
83 changes: 47 additions & 36 deletions dist/INSTALL.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,43 @@
# Box2Dxt Platformer — Install & Run

Everything needed to run the **Box2Dxt** physics platformer is in this folder.
No C compiler, no internet, no extra downloads — just these files and an
**OpenXTalk (OXT)** or **LiveCode 9.6.3+** IDE you already have installed.
Everything needed to run the **Box2Dxt** physics platformer is in this package —
no C compiler, no internet, no extra downloads. You just need **OpenXTalk (OXT)**
installed (the demo is an OXT `.oxtstack`; OXT is the OpenXTalk fork of LiveCode,
and the extension/engine are also compatible with **LiveCode 9.6.3+**).

## What's in this package

```
box2dxt-platformer/
├── INSTALL.md ← you are here
├── box2dxt.lcb ← the Box2Dxt extension (the b2… physics API)
├── platformer.livecode ← the platformer stack (you open this last)
└── lib/
├── box2dxt.dll ← native library — Windows (x64)
├── box2dxt.dylib ← native library — macOS (Intel + Apple Silicon)
└── box2dxt.so ← native library — Linux (x86-64)
NewPlateformerDemo.oxtstack ← the platformer stack (you open this)
source/
├── box2dxt.lcb ← the Box2Dxt extension (the b2… physics API)
├── box2d_lc.c ← the C shim it binds to (source, for rebuilding)
└── box2dxt-kit.livecodescript ← the Kit (the friendly b2k… layer; also embedded
in the stack, so the demo runs on its own)
libraries/
├── box2dxt.dll ← native library — Windows (x64)
├── box2dxt.dylib ← native library — macOS (Intel + Apple Silicon)
└── box2dxt.so ← native library — Linux (x86-64)
spritesheets/ ← the demo's art (point the stack here on first run)
```

You only need the **one** `lib/` file for your operating system.
To **run** the demo you only touch three things, in order: a native library
(Step 1), the extension (Step 2), and the stack (Step 3). The `box2d_lc.c` and
the standalone Kit in `source/` are there for reference / rebuilding — you don't
need them to play.

---

## Step 1 · Put the native library where the engine can find it

Box2Dxt's physics run in a small native library. Copy the file for your OS:
Box2Dxt's physics run in a small native library. Copy the **one file for your
OS** from `libraries/`:

| Your OS | Copy this file | To here |
|---------|----------------|---------|
| **Windows** | `lib/box2dxt.dll` | the **same folder** as `platformer.livecode` |
| **macOS** | `lib/box2dxt.dylib` | the **same folder** as `platformer.livecode` |
| **Linux** | `lib/box2dxt.so` | a library search path — see the note below |
| **Windows** | `libraries/box2dxt.dll` | the **same folder** as `NewPlateformerDemo.oxtstack` |
| **macOS** | `libraries/box2dxt.dylib` | the **same folder** as `NewPlateformerDemo.oxtstack` |
| **Linux** | `libraries/box2dxt.so` | a library search path — see the note below |

**Do not rename these files.** They are already the bare name the loader looks
for (`box2dxt`, with no `lib` prefix). Renaming is the #1 cause of "unable to
Expand All @@ -38,7 +46,7 @@ load foreign library".
> **Linux only.** The dynamic loader does *not* search the stack's folder. Put
> `box2dxt.so` somewhere the loader looks:
> ```
> sudo cp lib/box2dxt.so /usr/lib/ && sudo ldconfig
> sudo cp libraries/box2dxt.so /usr/lib/ && sudo ldconfig
> ```
> (or place it next to the OXT engine binary, or add its folder to
> `LD_LIBRARY_PATH` before launching OXT).
Expand All @@ -47,15 +55,15 @@ load foreign library".

## Step 2 · Install the extension

The extension `box2dxt.lcb` adds the `b2…` physics handlers to the IDE.
The extension `source/box2dxt.lcb` adds the `b2…` physics handlers to the IDE.

1. Launch **OXT / LiveCode**.
1. Launch **OXT**.
2. Open **Tools → Extension Manager**.
3. Click **+ (Add)**, choose **`box2dxt.lcb`** from this folder, then click
**Load**.
3. Click **+ (Add)**, choose **`source/box2dxt.lcb`** from this package, then
click **Load**.

> Alternatively: **Tools → Extension Builder**, open `box2dxt.lcb`, and click
> **Test** — that compiles and loads it in one step.
> Alternatively: **Tools → Extension Builder**, open `source/box2dxt.lcb`, and
> click **Test** — that compiles and loads it in one step.

**Confirm it worked:** open the **Message Box** (the small toolbar icon, or
Ctrl/Cmd-M) and type:
Expand All @@ -70,15 +78,16 @@ Press Enter. You should see **`4`**. If you get an error, see *Troubleshooting*.

## Step 3 · Open the platformer

Open **`platformer.livecode`** (File → Open Stack…, or double-click it). The
game builds itself and starts immediately.
Open **`NewPlateformerDemo.oxtstack`** (File → Open Stack…, or double-click it).
The game builds itself and starts immediately.

- **First run** may ask you to locate a spritesheet folder. Click **Cancel** to
play with the built-in placeholder art, or point it at a Kenney spritesheet
folder if you have one. Once you **save** the stack, the artwork is remembered
and loads instantly every time after.
- **Controls:** **arrows** or **WASD** to move · **Space** to jump · **↓** to
duck. Grab the coins and touch the flag to advance — there are four levels.
- **First run** asks you to locate a spritesheet folder — choose the
**`spritesheets/`** folder in this package. After you **save** the stack the
art is remembered (and cached), so it loads instantly every time after.
- **Controls:** **arrows / WASD** move · **Space** jump (press again in mid-air
to **double-jump**, or off a wall to **wall-jump**) · **SHIFT / X** dash ·
**↓** duck · **R** restart · **M** mute. Grab every coin (the flag turns gold)
and touch the flag to advance — there are four levels.

That's it. Enjoy the physics.

Expand All @@ -88,13 +97,15 @@ That's it. Enjoy the physics.

| Symptom | Fix |
|---------|-----|
| `b2Version()` errors, or "handler not found" | The extension isn't loaded. Redo **Step 2** (Extension Manager → Load `box2dxt.lcb`). It loads per IDE session. |
| First physics call says **"unable to load foreign library"** | The native library isn't found. Make sure the `lib/` file for your OS sits **next to `platformer.livecode`** (Windows/macOS) or on a loader path (Linux). Don't rename it. *Tip: launch OXT from a terminal — it prints the exact filename it's looking for.* |
| `b2Version()` returns a number **other than 4** | Your `box2dxt.lcb` and the native library are from different builds. Use the `.lcb` and the `lib/` file **from this same package** together. |
| `b2Version()` errors, or "handler not found" | The extension isn't loaded. Redo **Step 2** (Extension Manager → Load `source/box2dxt.lcb`). It loads per IDE session. |
| First physics call says **"unable to load foreign library"** | The native library isn't found. Make sure the `libraries/` file for your OS sits **next to `NewPlateformerDemo.oxtstack`** (Windows/macOS) or on a loader path (Linux). Don't rename it. *Tip: launch OXT from a terminal — it prints the exact filename it's looking for.* |
| `b2Version()` returns a number **other than 4** | Your `box2dxt.lcb` and the native library are from different builds. Use the `source/box2dxt.lcb` and the `libraries/` file **from this same package** together. |
| The level loads with plain placeholder shapes (no art) | On first run, point the spritesheet prompt at this package's **`spritesheets/`** folder, then **save** the stack. (Hold **Shift** while pressing **R** to re-pick the folder.) |
| The window opens but nothing moves, or a `b2…` call errors | The extension loaded but the native library didn't (or is the wrong build). Re-check Steps 1–2 and confirm `put b2Version()` is `4` before opening the stack. |

---

*Box2Dxt is the Box2D v3 physics engine packaged for OpenXTalk and the xTalk
language family. The platformer is one of several example games. For the full
toolkit, source, and documentation, see the project repository.*
language family. The platformer is one of several example games. The `source/`
folder holds the full extension, its C shim, and the Kit; for the complete
toolkit and documentation, see the project repository.*
37 changes: 21 additions & 16 deletions docs/building.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,32 +78,37 @@ with it).
## Packaging a distribution zip

To hand someone a ready-to-run game (no repo, no toolchain, no internet),
bundle the extension, the per-platform native libraries, a built **and saved**
stack, and the end-user install guide into one zip. `tools/make-release.py`
does it:
bundle the source (extension + C shim + Kit), the per-platform native
libraries, the demo's spritesheets, a built **and saved** stack, and the
end-user install guide into one zip. `tools/make-release.py` does it:

```sh
# Build & SAVE the stack in OXT first (e.g. the platformer), then:
python3 tools/make-release.py --stack /path/to/platformer.livecode
# -> dist/box2dxt-platformer.zip
python3 tools/make-release.py --stack /path/to/NewPlateformerDemo.oxtstack
# -> dist/NewPlateformerDemo.zip
```

It copies `src/box2dxt.lcb` and `dist/INSTALL.md`, renames each `prebuilt/`
library to the bare name the loader wants under `lib/`, and adds your saved
stack — producing:
It copies `src/box2dxt.lcb` / `box2d_lc.c` / `box2dxt-kit.livecodescript` into
`source/`, renames each `prebuilt/` library to the bare name the loader wants
under `libraries/`, copies the platformer's `Spritesheets/` art into
`spritesheets/`, adds `dist/INSTALL.md`, and drops your saved stack at the
root — producing:

```
box2dxt-platformer/
├── INSTALL.md # the three-step end-user install guide
├── box2dxt.lcb
├── platformer.livecode # your --stack
└── lib/box2dxt.{dll,dylib,so}
NewPlateformerDemo/
├── NewPlateformerDemo.oxtstack # your --stack
├── INSTALL.md # the three-step end-user install guide
├── source/ box2dxt.lcb, box2d_lc.c, box2dxt-kit.livecodescript
├── libraries/ box2dxt.{dll,dylib,so}
└── spritesheets/ the demo's PNG + XML sheets
```

Override a library with `--win` / `--mac` / `--linux` (e.g. an SSE2 or
older-glibc build); `--check` validates the inputs without writing the zip.
The recipient just follows `INSTALL.md`: drop their platform's `lib/` file
beside the stack, **Load** `box2dxt.lcb`, open the stack.
older-glibc build), the art folder with `--sheets`, or the stack's in-zip name
with `--stack-name`; `--check` validates the inputs without writing the zip.
The recipient follows `INSTALL.md`: drop their platform's `libraries/` file
beside the stack, **Load** `source/box2dxt.lcb`, open the stack, and point its
first-run prompt at `spritesheets/`.

## Platform & CPU notes

Expand Down
102 changes: 68 additions & 34 deletions tools/make-release.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
#!/usr/bin/env python3
"""Assemble a ready-to-ship Box2Dxt platformer zip.
"""Assemble a ready-to-ship Box2Dxt platformer package.

The zip is self-contained: the extension, the per-platform native libraries
(already renamed to the bare name the loader wants), a saved stack, and the
end-user install guide (dist/INSTALL.md). See its layout in that guide.
The zip is self-contained and matches dist/INSTALL.md:

The only thing this script can't produce is the *saved* stack -- you build and
save platformer.livecode in OXT first, then point --stack at it:
NewPlateformerDemo.oxtstack (your saved stack -- --stack)
INSTALL.md
source/ box2dxt.lcb, box2d_lc.c, box2dxt-kit.livecodescript
libraries/ box2dxt.dll, box2dxt.dylib, box2dxt.so (renamed to the bare name)
spritesheets/ the platformer's PNG + XML sheets

python3 tools/make-release.py --stack ~/Desktop/platformer.livecode
The only thing this script can't produce is the *saved* stack -- build and save
it in OXT first, then point --stack at it:

By default the native libraries come from prebuilt/ (the committed ABI-4
binaries). Override any of them with --win / --mac / --linux if you have a
fresher or differently-tuned build.
python3 tools/make-release.py --stack ~/Desktop/NewPlateformerDemo.oxtstack

Run with --check to validate the inputs (and the embedded-Kit sync) without
writing the zip.
By default the native libraries come from prebuilt/ (the committed ABI-4
binaries) and the art from Spritesheets/. Override the libs with --win / --mac /
--linux, or the art folder with --sheets. --check validates the inputs only.
"""

import argparse
Expand All @@ -25,13 +26,22 @@

REPO = Path(__file__).resolve().parent.parent

# arcname (inside lib/) -> default source under prebuilt/
# the extension, the C shim, and the Kit -> source/
SOURCE_FILES = ["box2dxt.lcb", "box2d_lc.c", "box2dxt-kit.livecodescript"]

# bare deploy name -> default committed binary (goes to libraries/)
DEFAULT_LIBS = {
"box2dxt.dll": "prebuilt/box2dxt-windows-x64.dll",
"box2dxt.dylib": "prebuilt/libbox2dxt-macos-universal.dylib",
"box2dxt.so": "prebuilt/libbox2dxt-linux-x86_64.so",
}

# the spritesheets the platformer loads (PNG + XML each) -> spritesheets/
PLATFORMER_SHEETS = [
"spritesheet-characters-default", "spritesheet-enemies-default",
"spritesheet-tiles-default", "spritesheet-backgrounds-default", "enemies",
]


def human(nbytes):
size = float(nbytes)
Expand All @@ -42,39 +52,63 @@ def human(nbytes):
return f"{size:.1f} MB"


def rel(src):
return src.relative_to(REPO) if src.is_relative_to(REPO) else src


def main():
ap = argparse.ArgumentParser(description="Build the Box2Dxt platformer distribution zip.")
ap.add_argument("--stack", help="path to the built & saved platformer stack (.livecode)")
ap.add_argument("--out", default="dist/box2dxt-platformer.zip", help="output zip path (default: dist/box2dxt-platformer.zip)")
ap.add_argument("--top", default="box2dxt-platformer", help="top-level folder name inside the zip")
ap.add_argument("--stack-name", default="platformer.livecode", help="filename the stack gets inside the zip (the guide refers to this name)")
ap.add_argument("--win", help="override the Windows library (-> lib/box2dxt.dll)")
ap.add_argument("--mac", help="override the macOS library (-> lib/box2dxt.dylib)")
ap.add_argument("--linux", help="override the Linux library (-> lib/box2dxt.so)")
ap.add_argument("--stack", help="path to the built & saved platformer stack (.oxtstack)")
ap.add_argument("--out", default="dist/NewPlateformerDemo.zip", help="output zip path")
ap.add_argument("--top", default="NewPlateformerDemo", help="top-level folder name inside the zip")
ap.add_argument("--stack-name", default="NewPlateformerDemo.oxtstack", help="filename the stack gets inside the zip (the guide refers to this name)")
ap.add_argument("--sheets", default="Spritesheets", help="folder holding the platformer's spritesheets")
ap.add_argument("--win", help="override the Windows library (-> libraries/box2dxt.dll)")
ap.add_argument("--mac", help="override the macOS library (-> libraries/box2dxt.dylib)")
ap.add_argument("--linux", help="override the Linux library (-> libraries/box2dxt.so)")
ap.add_argument("--check", action="store_true", help="validate inputs only; do not write the zip")
args = ap.parse_args()

# Resolve the four always-bundled pieces + the per-platform libraries.
items = [] # (arcname-relative-to-top, source Path)
problems = []

lcb = REPO / "src" / "box2dxt.lcb"
install = REPO / "dist" / "INSTALL.md"
for arc, src in (("box2dxt.lcb", lcb), ("INSTALL.md", install)):
# source/ : the extension, the C shim, the Kit
for name in SOURCE_FILES:
src = REPO / "src" / name
if src.is_file():
items.append((arc, src))
items.append((f"source/{name}", src))
else:
problems.append(f"missing required file: {src.relative_to(REPO) if src.is_relative_to(REPO) else src}")
problems.append(f"missing source file: src/{name}")

# the install guide, at the root
install = REPO / "dist" / "INSTALL.md"
if install.is_file():
items.append(("INSTALL.md", install))
else:
problems.append("missing dist/INSTALL.md")

# libraries/ : the per-platform native libs, renamed to the bare name
overrides = {"box2dxt.dll": args.win, "box2dxt.dylib": args.mac, "box2dxt.so": args.linux}
for bare, default_rel in DEFAULT_LIBS.items():
src = Path(overrides[bare]).expanduser() if overrides[bare] else (REPO / default_rel)
if src.is_file():
items.append((f"lib/{bare}", src))
items.append((f"libraries/{bare}", src))
else:
problems.append(f"missing library for lib/{bare}: {src}")

# The saved stack is required to build the zip (but not just to --check).
problems.append(f"missing library for libraries/{bare}: {src}")

# spritesheets/ : the demo's art (PNG + XML pairs)
sheets_dir = Path(args.sheets).expanduser()
if not sheets_dir.is_absolute():
sheets_dir = REPO / args.sheets
for base in PLATFORMER_SHEETS:
for ext in ("png", "xml"):
src = sheets_dir / f"{base}.{ext}"
if src.is_file():
items.append((f"spritesheets/{base}.{ext}", src))
else:
problems.append(f"missing spritesheet: {src}")

# the saved stack, at the root (required to build the zip, not just to --check)
stack = None
if args.stack:
stack = Path(args.stack).expanduser()
Expand All @@ -83,7 +117,7 @@ def main():
else:
problems.append(f"--stack is not a file: {stack}")
elif not args.check:
problems.append("--stack is required (build & save platformer.livecode in OXT first)")
problems.append("--stack is required (build & save the .oxtstack in OXT first)")

if problems:
print("Cannot build the release:", file=sys.stderr)
Expand All @@ -93,19 +127,19 @@ def main():

print(f"Release contents (top folder: {args.top}/):")
for arc, src in items:
print(f" {arc:<22} <- {src if not src.is_relative_to(REPO) else src.relative_to(REPO)} ({human(src.stat().st_size)})")
print(f" {arc:<34} <- {rel(src)} ({human(src.stat().st_size)})")

if args.check:
print("\n--check: inputs valid" + ("" if stack else " (no --stack given; a real build needs one)") + ".")
return 0

out = (REPO / args.out) if not Path(args.out).is_absolute() else Path(args.out)
out = Path(args.out) if Path(args.out).is_absolute() else (REPO / args.out)
out.parent.mkdir(parents=True, exist_ok=True)
with zipfile.ZipFile(out, "w", zipfile.ZIP_DEFLATED) as z:
for arc, src in items:
z.write(src, f"{args.top}/{arc}")

print(f"\nWrote {out.relative_to(REPO) if out.is_relative_to(REPO) else out} ({human(out.stat().st_size)}).")
print(f"\nWrote {rel(out)} ({human(out.stat().st_size)}).")
return 0


Expand Down
Loading