zx-kit 0.16.2 → 0.18.0
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.
- package/dist/collision.d.ts +50 -16
- package/dist/collision.d.ts.map +1 -1
- package/dist/collision.js +98 -49
- package/dist/collision.js.map +1 -1
- package/dist/renderer.d.ts +55 -0
- package/dist/renderer.d.ts.map +1 -1
- package/dist/renderer.js +87 -3
- package/dist/renderer.js.map +1 -1
- package/package.json +1 -1
package/dist/collision.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Sprite } from './sprite.js';
|
|
2
2
|
import type { TileMap } from './tilemap.js';
|
|
3
|
+
import type { Bitmap } from './renderer.js';
|
|
3
4
|
/**
|
|
4
5
|
* Axis-aligned bounding rectangle in game pixels.
|
|
5
6
|
*/
|
|
@@ -30,6 +31,16 @@ export declare function rectsOverlap(a: Rect, b: Rect): boolean;
|
|
|
30
31
|
* if (spritesOverlap(player, coin)) collectCoin()
|
|
31
32
|
*/
|
|
32
33
|
export declare function spritesOverlap(a: Sprite, b: Sprite): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Returns the bounding `Rect` for a {@link Bitmap} positioned at `(x, y)`.
|
|
36
|
+
* Works for any size — `16×16`, `16×24`, `32×32`, `96×128`, etc.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* const heroRect = bitmapRect(HERO_BITMAP, hero.x, hero.y)
|
|
40
|
+
* const enemyRect = bitmapRect(ENEMY_BITMAP, enemy.x, enemy.y)
|
|
41
|
+
* if (rectsOverlap(heroRect, enemyRect)) damage(hero)
|
|
42
|
+
*/
|
|
43
|
+
export declare function bitmapRect(bitmap: Bitmap, x: number, y: number): Rect;
|
|
33
44
|
/**
|
|
34
45
|
* Returns `true` when the game pixel at `(px, py)` falls inside a solid tile.
|
|
35
46
|
* Converts pixel coords to tile coords via integer division by `CELL`.
|
|
@@ -40,15 +51,45 @@ export declare function spritesOverlap(a: Sprite, b: Sprite): boolean;
|
|
|
40
51
|
*/
|
|
41
52
|
export declare function isSolidAt(map: TileMap, px: number, py: number): boolean;
|
|
42
53
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
54
|
+
* Generic horizontal sweep-resolver for any axis-aligned rectangle.
|
|
55
|
+
* Works correctly for sprites taller than `CELL` (e.g. 16×24 hero) — the leading
|
|
56
|
+
* edge is checked across every tile row the rectangle spans, not just two corners.
|
|
46
57
|
*
|
|
47
|
-
*
|
|
58
|
+
* Returns the clamped x and collision flags. On collision, the rectangle is
|
|
59
|
+
* placed flush against the wall.
|
|
48
60
|
*
|
|
49
|
-
* @
|
|
50
|
-
*
|
|
51
|
-
*
|
|
61
|
+
* @example
|
|
62
|
+
* const rect = bitmapRect(HERO, hero.x, hero.y)
|
|
63
|
+
* const r = resolveRectX(rect, map, hero.x + dx)
|
|
64
|
+
* hero.x = r.x
|
|
65
|
+
* if (r.hitLeft || r.hitRight) hero.vx = 0
|
|
66
|
+
*/
|
|
67
|
+
export declare function resolveRectX(rect: Rect, map: TileMap, newX: number): {
|
|
68
|
+
x: number;
|
|
69
|
+
hitLeft: boolean;
|
|
70
|
+
hitRight: boolean;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Generic vertical sweep-resolver for any axis-aligned rectangle.
|
|
74
|
+
* Works correctly for sprites wider than `CELL` — the leading edge is checked
|
|
75
|
+
* across every tile column the rectangle spans.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* const rect = bitmapRect(HERO, hero.x, hero.y)
|
|
79
|
+
* const r = resolveRectY(rect, map, hero.y + dy)
|
|
80
|
+
* hero.y = r.y
|
|
81
|
+
* if (r.hitBottom) { hero.vy = 0; onGround = true }
|
|
82
|
+
*/
|
|
83
|
+
export declare function resolveRectY(rect: Rect, map: TileMap, newY: number): {
|
|
84
|
+
y: number;
|
|
85
|
+
hitTop: boolean;
|
|
86
|
+
hitBottom: boolean;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Resolves a proposed horizontal movement for an 8×8 sprite against solid tiles.
|
|
90
|
+
* Thin wrapper over {@link resolveRectX} preserved for backward compatibility.
|
|
91
|
+
*
|
|
92
|
+
* Call BEFORE `resolveY` so each axis is resolved independently.
|
|
52
93
|
*
|
|
53
94
|
* @example
|
|
54
95
|
* moveSprite(player, dt)
|
|
@@ -62,22 +103,15 @@ export declare function resolveX(sprite: Sprite, map: TileMap, newX: number): {
|
|
|
62
103
|
hitRight: boolean;
|
|
63
104
|
};
|
|
64
105
|
/**
|
|
65
|
-
* Resolves a proposed vertical movement for
|
|
66
|
-
*
|
|
67
|
-
* Returns the clamped y coordinate and collision flags.
|
|
106
|
+
* Resolves a proposed vertical movement for an 8×8 sprite against solid tiles.
|
|
107
|
+
* Thin wrapper over {@link resolveRectY} preserved for backward compatibility.
|
|
68
108
|
*
|
|
69
109
|
* Typical platformer pattern: `hitBottom` means the sprite landed on a floor.
|
|
70
|
-
* Zero out `vy` on `hitBottom` and `hitTop` to prevent tunnelling.
|
|
71
|
-
*
|
|
72
|
-
* @param sprite - Sprite being moved (uses current `sprite.x` for horizontal extent)
|
|
73
|
-
* @param map - Tile map to test solidity against
|
|
74
|
-
* @param newY - Proposed new y position (after `moveSprite`)
|
|
75
110
|
*
|
|
76
111
|
* @example
|
|
77
112
|
* const ry = resolveY(player, map, player.y)
|
|
78
113
|
* player.y = ry.y
|
|
79
114
|
* if (ry.hitBottom) { player.vy = 0; onGround = true }
|
|
80
|
-
* if (ry.hitTop) { player.vy = 0 }
|
|
81
115
|
*/
|
|
82
116
|
export declare function resolveY(sprite: Sprite, map: TileMap, newY: number): {
|
|
83
117
|
y: number;
|
package/dist/collision.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collision.d.ts","sourceRoot":"","sources":["../src/collision.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAE3C;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAE/C;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,OAAO,CAKtD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAEvE;AAED
|
|
1
|
+
{"version":3,"file":"collision.d.ts","sourceRoot":"","sources":["../src/collision.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAE3C;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAE/C;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,OAAO,CAKtD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAErE;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAEvE;AAwBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,MAAM,GACX;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAuBpD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,MAAM,GACX;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAuBpD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,MAAM,GACX;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAEpD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,MAAM,GACX;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAEpD"}
|
package/dist/collision.js
CHANGED
|
@@ -29,6 +29,18 @@ export function rectsOverlap(a, b) {
|
|
|
29
29
|
export function spritesOverlap(a, b) {
|
|
30
30
|
return rectsOverlap(spriteRect(a), spriteRect(b));
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Returns the bounding `Rect` for a {@link Bitmap} positioned at `(x, y)`.
|
|
34
|
+
* Works for any size — `16×16`, `16×24`, `32×32`, `96×128`, etc.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* const heroRect = bitmapRect(HERO_BITMAP, hero.x, hero.y)
|
|
38
|
+
* const enemyRect = bitmapRect(ENEMY_BITMAP, enemy.x, enemy.y)
|
|
39
|
+
* if (rectsOverlap(heroRect, enemyRect)) damage(hero)
|
|
40
|
+
*/
|
|
41
|
+
export function bitmapRect(bitmap, x, y) {
|
|
42
|
+
return { x, y, w: bitmap.width, h: bitmap.height };
|
|
43
|
+
}
|
|
32
44
|
/**
|
|
33
45
|
* Returns `true` when the game pixel at `(px, py)` falls inside a solid tile.
|
|
34
46
|
* Converts pixel coords to tile coords via integer division by `CELL`.
|
|
@@ -40,88 +52,125 @@ export function spritesOverlap(a, b) {
|
|
|
40
52
|
export function isSolidAt(map, px, py) {
|
|
41
53
|
return map.isSolid(Math.floor(px / CELL), Math.floor(py / CELL));
|
|
42
54
|
}
|
|
55
|
+
// ─── Generic rect-based collision (works for any sprite size) ────────────────
|
|
56
|
+
function _solidAlongVerticalEdge(map, edgeX, y0, y1) {
|
|
57
|
+
// Check every tile row the edge from y0..y1 crosses (handles tall sprites > CELL).
|
|
58
|
+
const tileTop = Math.floor(y0 / CELL);
|
|
59
|
+
const tileBot = Math.floor(y1 / CELL);
|
|
60
|
+
for (let ty = tileTop; ty <= tileBot; ty++) {
|
|
61
|
+
if (isSolidAt(map, edgeX, ty * CELL))
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
function _solidAlongHorizontalEdge(map, edgeY, x0, x1) {
|
|
67
|
+
// Check every tile column the edge from x0..x1 crosses (handles wide sprites > CELL).
|
|
68
|
+
const tileLeft = Math.floor(x0 / CELL);
|
|
69
|
+
const tileRight = Math.floor(x1 / CELL);
|
|
70
|
+
for (let tx = tileLeft; tx <= tileRight; tx++) {
|
|
71
|
+
if (isSolidAt(map, tx * CELL, edgeY))
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
43
76
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
77
|
+
* Generic horizontal sweep-resolver for any axis-aligned rectangle.
|
|
78
|
+
* Works correctly for sprites taller than `CELL` (e.g. 16×24 hero) — the leading
|
|
79
|
+
* edge is checked across every tile row the rectangle spans, not just two corners.
|
|
47
80
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* @param sprite - Sprite being moved (uses current `sprite.y` for vertical extent)
|
|
51
|
-
* @param map - Tile map to test solidity against
|
|
52
|
-
* @param newX - Proposed new x position (after `moveSprite`)
|
|
81
|
+
* Returns the clamped x and collision flags. On collision, the rectangle is
|
|
82
|
+
* placed flush against the wall.
|
|
53
83
|
*
|
|
54
84
|
* @example
|
|
55
|
-
*
|
|
56
|
-
* const
|
|
57
|
-
*
|
|
58
|
-
* if (
|
|
85
|
+
* const rect = bitmapRect(HERO, hero.x, hero.y)
|
|
86
|
+
* const r = resolveRectX(rect, map, hero.x + dx)
|
|
87
|
+
* hero.x = r.x
|
|
88
|
+
* if (r.hitLeft || r.hitRight) hero.vx = 0
|
|
59
89
|
*/
|
|
60
|
-
export function
|
|
61
|
-
const y0 =
|
|
62
|
-
const y1 =
|
|
90
|
+
export function resolveRectX(rect, map, newX) {
|
|
91
|
+
const y0 = rect.y;
|
|
92
|
+
const y1 = rect.y + rect.h - 1;
|
|
63
93
|
let x = newX;
|
|
64
94
|
let hitLeft = false;
|
|
65
95
|
let hitRight = false;
|
|
66
|
-
if (newX <
|
|
67
|
-
|
|
68
|
-
if (isSolidAt(map, newX, y0) || isSolidAt(map, newX, y1)) {
|
|
69
|
-
// Clamp to in-bounds before computing tile column (avoids negative col from OOB overshoot)
|
|
96
|
+
if (newX < rect.x) {
|
|
97
|
+
if (_solidAlongVerticalEdge(map, newX, y0, y1)) {
|
|
70
98
|
const safeX = Math.max(0, newX);
|
|
71
99
|
x = (Math.floor(safeX / CELL) + 1) * CELL;
|
|
72
100
|
hitLeft = true;
|
|
73
101
|
}
|
|
74
102
|
}
|
|
75
|
-
else if (newX >
|
|
76
|
-
|
|
77
|
-
if (
|
|
78
|
-
const safeEdge = Math.min(map.cols * CELL - 1,
|
|
79
|
-
x = Math.floor(safeEdge / CELL) * CELL -
|
|
103
|
+
else if (newX > rect.x) {
|
|
104
|
+
const rightEdge = newX + rect.w - 1;
|
|
105
|
+
if (_solidAlongVerticalEdge(map, rightEdge, y0, y1)) {
|
|
106
|
+
const safeEdge = Math.min(map.cols * CELL - 1, rightEdge);
|
|
107
|
+
x = Math.floor(safeEdge / CELL) * CELL - rect.w;
|
|
80
108
|
hitRight = true;
|
|
81
109
|
}
|
|
82
110
|
}
|
|
83
111
|
return { x, hitLeft, hitRight };
|
|
84
112
|
}
|
|
85
113
|
/**
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* Typical platformer pattern: `hitBottom` means the sprite landed on a floor.
|
|
91
|
-
* Zero out `vy` on `hitBottom` and `hitTop` to prevent tunnelling.
|
|
92
|
-
*
|
|
93
|
-
* @param sprite - Sprite being moved (uses current `sprite.x` for horizontal extent)
|
|
94
|
-
* @param map - Tile map to test solidity against
|
|
95
|
-
* @param newY - Proposed new y position (after `moveSprite`)
|
|
114
|
+
* Generic vertical sweep-resolver for any axis-aligned rectangle.
|
|
115
|
+
* Works correctly for sprites wider than `CELL` — the leading edge is checked
|
|
116
|
+
* across every tile column the rectangle spans.
|
|
96
117
|
*
|
|
97
118
|
* @example
|
|
98
|
-
* const
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* if (
|
|
119
|
+
* const rect = bitmapRect(HERO, hero.x, hero.y)
|
|
120
|
+
* const r = resolveRectY(rect, map, hero.y + dy)
|
|
121
|
+
* hero.y = r.y
|
|
122
|
+
* if (r.hitBottom) { hero.vy = 0; onGround = true }
|
|
102
123
|
*/
|
|
103
|
-
export function
|
|
104
|
-
const x0 =
|
|
105
|
-
const x1 =
|
|
124
|
+
export function resolveRectY(rect, map, newY) {
|
|
125
|
+
const x0 = rect.x;
|
|
126
|
+
const x1 = rect.x + rect.w - 1;
|
|
106
127
|
let y = newY;
|
|
107
128
|
let hitTop = false;
|
|
108
129
|
let hitBottom = false;
|
|
109
|
-
if (newY <
|
|
110
|
-
|
|
111
|
-
if (isSolidAt(map, x0, newY) || isSolidAt(map, x1, newY)) {
|
|
130
|
+
if (newY < rect.y) {
|
|
131
|
+
if (_solidAlongHorizontalEdge(map, newY, x0, x1)) {
|
|
112
132
|
const safeY = Math.max(0, newY);
|
|
113
133
|
y = (Math.floor(safeY / CELL) + 1) * CELL;
|
|
114
134
|
hitTop = true;
|
|
115
135
|
}
|
|
116
136
|
}
|
|
117
|
-
else if (newY >
|
|
118
|
-
|
|
119
|
-
if (
|
|
120
|
-
const safeEdge = Math.min(map.rows * CELL - 1,
|
|
121
|
-
y = Math.floor(safeEdge / CELL) * CELL -
|
|
137
|
+
else if (newY > rect.y) {
|
|
138
|
+
const bottomEdge = newY + rect.h - 1;
|
|
139
|
+
if (_solidAlongHorizontalEdge(map, bottomEdge, x0, x1)) {
|
|
140
|
+
const safeEdge = Math.min(map.rows * CELL - 1, bottomEdge);
|
|
141
|
+
y = Math.floor(safeEdge / CELL) * CELL - rect.h;
|
|
122
142
|
hitBottom = true;
|
|
123
143
|
}
|
|
124
144
|
}
|
|
125
145
|
return { y, hitTop, hitBottom };
|
|
126
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Resolves a proposed horizontal movement for an 8×8 sprite against solid tiles.
|
|
149
|
+
* Thin wrapper over {@link resolveRectX} preserved for backward compatibility.
|
|
150
|
+
*
|
|
151
|
+
* Call BEFORE `resolveY` so each axis is resolved independently.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* moveSprite(player, dt)
|
|
155
|
+
* const rx = resolveX(player, map, player.x)
|
|
156
|
+
* player.x = rx.x
|
|
157
|
+
* if (rx.hitLeft || rx.hitRight) player.vx = 0
|
|
158
|
+
*/
|
|
159
|
+
export function resolveX(sprite, map, newX) {
|
|
160
|
+
return resolveRectX(spriteRect(sprite), map, newX);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Resolves a proposed vertical movement for an 8×8 sprite against solid tiles.
|
|
164
|
+
* Thin wrapper over {@link resolveRectY} preserved for backward compatibility.
|
|
165
|
+
*
|
|
166
|
+
* Typical platformer pattern: `hitBottom` means the sprite landed on a floor.
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* const ry = resolveY(player, map, player.y)
|
|
170
|
+
* player.y = ry.y
|
|
171
|
+
* if (ry.hitBottom) { player.vy = 0; onGround = true }
|
|
172
|
+
*/
|
|
173
|
+
export function resolveY(sprite, map, newY) {
|
|
174
|
+
return resolveRectY(spriteRect(sprite), map, newY);
|
|
175
|
+
}
|
|
127
176
|
//# sourceMappingURL=collision.js.map
|
package/dist/collision.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collision.js","sourceRoot":"","sources":["../src/collision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"collision.js","sourceRoot":"","sources":["../src/collision.ts"],"names":[],"mappings":"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"}
|
package/dist/renderer.d.ts
CHANGED
|
@@ -127,5 +127,60 @@ export declare function drawTextCentered(ctx: CanvasRenderingContext2D, text: st
|
|
|
127
127
|
* drawScanlines(ctx, 0.35) // stronger effect
|
|
128
128
|
*/
|
|
129
129
|
export declare function drawScanlines(ctx: CanvasRenderingContext2D, alpha?: number): void;
|
|
130
|
+
/**
|
|
131
|
+
* An arbitrary-size monochrome bitmap. Width must be a multiple of 8 (byte-aligned).
|
|
132
|
+
* `data` is row-major: `(width/8) * height` bytes, with bit 7 = leftmost pixel of each byte.
|
|
133
|
+
*
|
|
134
|
+
* Common sizes:
|
|
135
|
+
* - 16×16 → 32 bytes (small character, Manic Miner style)
|
|
136
|
+
* - 16×24 → 48 bytes (taller character, Jetman style)
|
|
137
|
+
* - 24×24 → 72 bytes (large enemy)
|
|
138
|
+
* - 32×32 → 128 bytes (boss / vehicle)
|
|
139
|
+
*
|
|
140
|
+
* Use {@link createBitmap} for safe construction, {@link drawBitmap} to render,
|
|
141
|
+
* {@link mirrorBitmap} to derive a horizontally-flipped variant.
|
|
142
|
+
*/
|
|
143
|
+
export interface Bitmap {
|
|
144
|
+
/** Row-major pixel data: bytes = (width/8) * height. Bit 7 of each byte is the leftmost pixel. */
|
|
145
|
+
data: Uint8Array;
|
|
146
|
+
/** Width in pixels. Must be a positive multiple of 8. */
|
|
147
|
+
width: number;
|
|
148
|
+
/** Height in pixels. Must be positive. */
|
|
149
|
+
height: number;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Constructs a {@link Bitmap} with validation. Throws on invalid dimensions
|
|
153
|
+
* or wrong byte count so the error surfaces at definition time, not render time.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* const JETMAN_STAND = createBitmap(new Uint8Array([
|
|
157
|
+
* 0x03, 0xC0, // row 0 (16 px wide → 2 bytes per row)
|
|
158
|
+
* 0x07, 0xE0, // row 1
|
|
159
|
+
* // … 22 more rows
|
|
160
|
+
* ]), 16, 24)
|
|
161
|
+
*/
|
|
162
|
+
export declare function createBitmap(data: Uint8Array, width: number, height: number): Bitmap;
|
|
163
|
+
/**
|
|
164
|
+
* Draws a {@link Bitmap} of arbitrary width and height at game coordinates `(x, y)`.
|
|
165
|
+
* If `paper` is provided, fills the full bounding rectangle first; otherwise leaves the
|
|
166
|
+
* background untouched (transparent).
|
|
167
|
+
*
|
|
168
|
+
* Same ink/paper applies to the whole sprite — there is no per-cell colour attribute.
|
|
169
|
+
* For multi-colour effects, overlay several bitmaps at the same position.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* drawBitmap(ctx, JETMAN_STAND, x, y, C.B_WHITE, C.BLACK)
|
|
173
|
+
* drawBitmap(ctx, ROCKET_BASE, x, y, C.B_YELLOW) // transparent background
|
|
174
|
+
*/
|
|
175
|
+
export declare function drawBitmap(ctx: CanvasRenderingContext2D, bitmap: Bitmap, x: number, y: number, ink: SpectrumColor, paper?: SpectrumColor): void;
|
|
176
|
+
/**
|
|
177
|
+
* Returns a horizontally-flipped copy of `src`. The original is not modified.
|
|
178
|
+
* Use at module load time to derive left-facing sprites from right-facing definitions.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* export const HERO_RIGHT = createBitmap(HERO_RIGHT_BYTES, 16, 24)
|
|
182
|
+
* export const HERO_LEFT = mirrorBitmap(HERO_RIGHT)
|
|
183
|
+
*/
|
|
184
|
+
export declare function mirrorBitmap(src: Bitmap): Bitmap;
|
|
130
185
|
export declare function flashBorder(color: SpectrumColor, times: number, intervalMs: number, resetColor?: SpectrumColor): void;
|
|
131
186
|
//# sourceMappingURL=renderer.d.ts.map
|
package/dist/renderer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AAiB1D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,MAAM,EACb,KAAK,SAAM,EACX,MAAM,SAAM,GACX,wBAAwB,CAS1B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,iBAAiB,EAAE,SAAS,SAAI,GAAG,IAAI,CAS3E;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAUxD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,wBAAwB,EAC7B,MAAM,EAAE,UAAU,EAClB,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GACvC,IAAI,CAKN;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CACtB,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,aAAa,EAAE,KAAK,CAAC,EAAE,aAAa,GACxC,IAAI,CAON;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CACtB,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,aAAa,EAAE,KAAK,CAAC,EAAE,aAAa,GACxC,IAAI,CAIN;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EACT,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,aAAa,EAAE,KAAK,CAAC,EAAE,aAAa,GACxC,IAAI,CAGN;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,wBAAwB,EAC7B,KAAK,SAAO,GACX,IAAI,CASN;AAoBD,wBAAgB,WAAW,CACzB,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,UAAU,GAAE,aAAuB,GAClC,IAAI,CAmBN"}
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AAiB1D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,MAAM,EACb,KAAK,SAAM,EACX,MAAM,SAAM,GACX,wBAAwB,CAS1B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,iBAAiB,EAAE,SAAS,SAAI,GAAG,IAAI,CAS3E;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAUxD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,wBAAwB,EAC7B,MAAM,EAAE,UAAU,EAClB,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GACvC,IAAI,CAKN;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CACtB,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,aAAa,EAAE,KAAK,CAAC,EAAE,aAAa,GACxC,IAAI,CAON;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CACtB,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,aAAa,EAAE,KAAK,CAAC,EAAE,aAAa,GACxC,IAAI,CAIN;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EACT,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,aAAa,EAAE,KAAK,CAAC,EAAE,aAAa,GACxC,IAAI,CAGN;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,wBAAwB,EAC7B,KAAK,SAAO,GACX,IAAI,CASN;AAID;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,MAAM;IACrB,kGAAkG;IAClG,IAAI,EAAE,UAAU,CAAA;IAChB,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAA;IACb,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAcpF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,wBAAwB,EAC7B,MAAM,EAAE,MAAM,EACd,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,aAAa,EAClB,KAAK,CAAC,EAAE,aAAa,GACpB,IAAI,CAoBN;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAkBhD;AAoBD,wBAAgB,WAAW,CACzB,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,UAAU,GAAE,aAAuB,GAClC,IAAI,CAmBN"}
|
package/dist/renderer.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { C, CELL } from './palette.js';
|
|
2
2
|
import { getCharRow } from './font.js';
|
|
3
|
-
function
|
|
3
|
+
function _draw8x8Bits(ctx, getByte, x, y) {
|
|
4
4
|
for (let row = 0; row < 8; row++) {
|
|
5
5
|
const byte = getByte(row);
|
|
6
6
|
for (let bit = 0; bit < 8; bit++) {
|
|
@@ -103,7 +103,7 @@ export function drawSprite(ctx, sprite, x, y, ink, paper) {
|
|
|
103
103
|
ctx.fillStyle = paper;
|
|
104
104
|
ctx.fillRect(x, y, CELL, CELL);
|
|
105
105
|
ctx.fillStyle = ink;
|
|
106
|
-
|
|
106
|
+
_draw8x8Bits(ctx, row => sprite[row], x, y);
|
|
107
107
|
}
|
|
108
108
|
/**
|
|
109
109
|
* Draws a single ASCII character at game coordinates using the ROM font.
|
|
@@ -126,7 +126,7 @@ export function drawChar(ctx, code, x, y, ink, paper) {
|
|
|
126
126
|
ctx.fillRect(x, y, CELL, CELL);
|
|
127
127
|
}
|
|
128
128
|
ctx.fillStyle = ink;
|
|
129
|
-
|
|
129
|
+
_draw8x8Bits(ctx, row => getCharRow(code, row), x, y);
|
|
130
130
|
}
|
|
131
131
|
/**
|
|
132
132
|
* Draws a string left-to-right starting at game coordinates `(x, y)`.
|
|
@@ -194,6 +194,90 @@ export function drawScanlines(ctx, alpha = 0.25) {
|
|
|
194
194
|
}
|
|
195
195
|
ctx.restore();
|
|
196
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Constructs a {@link Bitmap} with validation. Throws on invalid dimensions
|
|
199
|
+
* or wrong byte count so the error surfaces at definition time, not render time.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* const JETMAN_STAND = createBitmap(new Uint8Array([
|
|
203
|
+
* 0x03, 0xC0, // row 0 (16 px wide → 2 bytes per row)
|
|
204
|
+
* 0x07, 0xE0, // row 1
|
|
205
|
+
* // … 22 more rows
|
|
206
|
+
* ]), 16, 24)
|
|
207
|
+
*/
|
|
208
|
+
export function createBitmap(data, width, height) {
|
|
209
|
+
if (!Number.isInteger(width) || width <= 0 || width % 8 !== 0) {
|
|
210
|
+
throw new Error(`createBitmap: width must be a positive multiple of 8, got ${width}`);
|
|
211
|
+
}
|
|
212
|
+
if (!Number.isInteger(height) || height <= 0) {
|
|
213
|
+
throw new Error(`createBitmap: height must be a positive integer, got ${height}`);
|
|
214
|
+
}
|
|
215
|
+
const expected = (width / 8) * height;
|
|
216
|
+
if (data.length !== expected) {
|
|
217
|
+
throw new Error(`createBitmap: data length mismatch — expected ${expected} bytes for ${width}×${height}, got ${data.length}`);
|
|
218
|
+
}
|
|
219
|
+
return { data, width, height };
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Draws a {@link Bitmap} of arbitrary width and height at game coordinates `(x, y)`.
|
|
223
|
+
* If `paper` is provided, fills the full bounding rectangle first; otherwise leaves the
|
|
224
|
+
* background untouched (transparent).
|
|
225
|
+
*
|
|
226
|
+
* Same ink/paper applies to the whole sprite — there is no per-cell colour attribute.
|
|
227
|
+
* For multi-colour effects, overlay several bitmaps at the same position.
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* drawBitmap(ctx, JETMAN_STAND, x, y, C.B_WHITE, C.BLACK)
|
|
231
|
+
* drawBitmap(ctx, ROCKET_BASE, x, y, C.B_YELLOW) // transparent background
|
|
232
|
+
*/
|
|
233
|
+
export function drawBitmap(ctx, bitmap, x, y, ink, paper) {
|
|
234
|
+
const { data, width, height } = bitmap;
|
|
235
|
+
const bytesPerRow = width / 8;
|
|
236
|
+
if (paper !== undefined) {
|
|
237
|
+
ctx.fillStyle = paper;
|
|
238
|
+
ctx.fillRect(x, y, width, height);
|
|
239
|
+
}
|
|
240
|
+
ctx.fillStyle = ink;
|
|
241
|
+
for (let row = 0; row < height; row++) {
|
|
242
|
+
const rowOffset = row * bytesPerRow;
|
|
243
|
+
for (let byteIdx = 0; byteIdx < bytesPerRow; byteIdx++) {
|
|
244
|
+
const byte = data[rowOffset + byteIdx];
|
|
245
|
+
if (!byte)
|
|
246
|
+
continue;
|
|
247
|
+
const colBase = byteIdx * 8;
|
|
248
|
+
for (let bit = 0; bit < 8; bit++) {
|
|
249
|
+
if (byte & (0x80 >> bit))
|
|
250
|
+
ctx.fillRect(x + colBase + bit, y + row, 1, 1);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Returns a horizontally-flipped copy of `src`. The original is not modified.
|
|
257
|
+
* Use at module load time to derive left-facing sprites from right-facing definitions.
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* export const HERO_RIGHT = createBitmap(HERO_RIGHT_BYTES, 16, 24)
|
|
261
|
+
* export const HERO_LEFT = mirrorBitmap(HERO_RIGHT)
|
|
262
|
+
*/
|
|
263
|
+
export function mirrorBitmap(src) {
|
|
264
|
+
const { data, width, height } = src;
|
|
265
|
+
const bytesPerRow = width / 8;
|
|
266
|
+
const out = new Uint8Array(data.length);
|
|
267
|
+
for (let row = 0; row < height; row++) {
|
|
268
|
+
const rowOffset = row * bytesPerRow;
|
|
269
|
+
for (let byteIdx = 0; byteIdx < bytesPerRow; byteIdx++) {
|
|
270
|
+
const srcByte = data[rowOffset + byteIdx];
|
|
271
|
+
let m = 0;
|
|
272
|
+
for (let bit = 0; bit < 8; bit++) {
|
|
273
|
+
if (srcByte & (1 << bit))
|
|
274
|
+
m |= (1 << (7 - bit));
|
|
275
|
+
}
|
|
276
|
+
out[rowOffset + (bytesPerRow - 1 - byteIdx)] = m;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return { data: out, width, height };
|
|
280
|
+
}
|
|
197
281
|
/**
|
|
198
282
|
* Flashes `document.body.style.backgroundColor` between `color` and `resetColor`.
|
|
199
283
|
* Fire-and-forget — does not block. Uses `setInterval` internally.
|
package/dist/renderer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,IAAI,EAAsB,MAAM,cAAc,CAAA;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEtC,SAAS,
|
|
1
|
+
{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"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"}
|