@waica/cli 0.3.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/LICENSE +21 -0
- package/README.md +64 -0
- package/dist/cli.js +184 -0
- package/dist/editor/assets/abap-08VXUWAP.js +1 -0
- package/dist/editor/assets/apex-BWPQTe0t.js +1 -0
- package/dist/editor/assets/azcli-Bc_sGQ0U.js +1 -0
- package/dist/editor/assets/bat-i0X4ZdIN.js +1 -0
- package/dist/editor/assets/bicep-B5-_aFwp.js +2 -0
- package/dist/editor/assets/cameligo-DMUM7wLl.js +1 -0
- package/dist/editor/assets/clojure-Cm7r79vr.js +1 -0
- package/dist/editor/assets/codicon-DCmgc-ay.ttf +0 -0
- package/dist/editor/assets/coffee-Ba7i2nA0.js +1 -0
- package/dist/editor/assets/cpp-C7h46wYY.js +1 -0
- package/dist/editor/assets/csharp-BKxtCVv1.js +1 -0
- package/dist/editor/assets/csp-bTuwJoIa.js +1 -0
- package/dist/editor/assets/css-DIMkf-bt.js +3 -0
- package/dist/editor/assets/css.worker-Fwwr_HdT.js +88 -0
- package/dist/editor/assets/cssMode-CQE-WdwL.js +4 -0
- package/dist/editor/assets/cypher-CVaqCwHa.js +1 -0
- package/dist/editor/assets/dart-onAF5SnQ.js +1 -0
- package/dist/editor/assets/dockerfile-DZFCIeNp.js +1 -0
- package/dist/editor/assets/ecl-D05T4iGw.js +1 -0
- package/dist/editor/assets/editor.worker-DsBDrWS5.js +12 -0
- package/dist/editor/assets/elixir-6RTg0lbw.js +1 -0
- package/dist/editor/assets/flow9-C5_-GSwl.js +1 -0
- package/dist/editor/assets/freemarker2-CYgdVabn.js +3 -0
- package/dist/editor/assets/fsharp-C8Ef5oNN.js +1 -0
- package/dist/editor/assets/go-C-y9NEjX.js +1 -0
- package/dist/editor/assets/graphql-fmXr3nnJ.js +1 -0
- package/dist/editor/assets/handlebars-DdeORCJD.js +1 -0
- package/dist/editor/assets/hcl-CpzslTdj.js +1 -0
- package/dist/editor/assets/html-DTIAGV84.js +1 -0
- package/dist/editor/assets/html.worker-B3Ztmmz2.js +495 -0
- package/dist/editor/assets/htmlMode-CRV3iBih.js +4 -0
- package/dist/editor/assets/index-Btzc6zxr.css +1 -0
- package/dist/editor/assets/index-Dhkqk31v.js +11016 -0
- package/dist/editor/assets/ini-sBoK_t0W.js +1 -0
- package/dist/editor/assets/java-BEtHBSE6.js +1 -0
- package/dist/editor/assets/javascript-dxBW86cl.js +1 -0
- package/dist/editor/assets/json.worker-PWQxM7ZO.js +51 -0
- package/dist/editor/assets/jsonMode-DFA5-FFK.js +10 -0
- package/dist/editor/assets/julia-Bri6UV-V.js +1 -0
- package/dist/editor/assets/kotlin-B0qVs-E9.js +1 -0
- package/dist/editor/assets/less-B9JPFI3C.js +2 -0
- package/dist/editor/assets/lexon-CfSJPG6W.js +1 -0
- package/dist/editor/assets/liquid-CScWaXYV.js +1 -0
- package/dist/editor/assets/lua-CsQS60Ue.js +1 -0
- package/dist/editor/assets/m3-D-oSqn_W.js +1 -0
- package/dist/editor/assets/markdown-Cimd5fb3.js +1 -0
- package/dist/editor/assets/mdx-Bvp84SqA.js +1 -0
- package/dist/editor/assets/mips-CIPQ_RoX.js +1 -0
- package/dist/editor/assets/msdax-DauUninz.js +1 -0
- package/dist/editor/assets/mysql-SOo6toE5.js +1 -0
- package/dist/editor/assets/objective-c-FvmIjYaQ.js +1 -0
- package/dist/editor/assets/pascal-DrH0SRf2.js +1 -0
- package/dist/editor/assets/pascaligo-D-ptJ9y-.js +1 -0
- package/dist/editor/assets/perl-oz_6vUea.js +1 -0
- package/dist/editor/assets/pgsql-DTj74zXo.js +1 -0
- package/dist/editor/assets/php-nr791fC2.js +1 -0
- package/dist/editor/assets/pla-CopQ2nXW.js +1 -0
- package/dist/editor/assets/postiats-43DmfD33.js +1 -0
- package/dist/editor/assets/powerquery-D3hlyOfw.js +1 -0
- package/dist/editor/assets/powershell-DmHpPYUd.js +1 -0
- package/dist/editor/assets/protobuf-C531GsRP.js +2 -0
- package/dist/editor/assets/pug-Z5eAx3Zn.js +1 -0
- package/dist/editor/assets/python-CG-OtvFa.js +1 -0
- package/dist/editor/assets/qsharp-DkqhCAOL.js +1 -0
- package/dist/editor/assets/r-BwWrilGY.js +1 -0
- package/dist/editor/assets/razor-r-iUEZPj.js +1 -0
- package/dist/editor/assets/redis-ClamHrr6.js +1 -0
- package/dist/editor/assets/redshift-DT7zqm-g.js +1 -0
- package/dist/editor/assets/restructuredtext-BYgofb2h.js +1 -0
- package/dist/editor/assets/ruby-DezsRK8O.js +1 -0
- package/dist/editor/assets/rust-DdL9SqIa.js +1 -0
- package/dist/editor/assets/sb-CcwsVR0C.js +1 -0
- package/dist/editor/assets/scala-DHpiXF5c.js +1 -0
- package/dist/editor/assets/scheme-BeGwcela.js +1 -0
- package/dist/editor/assets/scss-gp-XZpBa.js +3 -0
- package/dist/editor/assets/shell-CC2rA5mh.js +1 -0
- package/dist/editor/assets/solidity-BEEn4gHE.js +1 -0
- package/dist/editor/assets/sophia-CRfGWb83.js +1 -0
- package/dist/editor/assets/sparql-D_Lu-MrJ.js +1 -0
- package/dist/editor/assets/sql-NEE52Syq.js +1 -0
- package/dist/editor/assets/st-DbInun42.js +1 -0
- package/dist/editor/assets/swift-Bxkupp3x.js +1 -0
- package/dist/editor/assets/systemverilog-Bz4Y3fRF.js +1 -0
- package/dist/editor/assets/tcl-DISqw1ZD.js +1 -0
- package/dist/editor/assets/ts.worker-0mEyHVru.js +51339 -0
- package/dist/editor/assets/tsMode-Bth1rJwM.js +11 -0
- package/dist/editor/assets/twig-De2hgUGE.js +1 -0
- package/dist/editor/assets/typescript-tNRuHsoe.js +1 -0
- package/dist/editor/assets/typespec-B8J7ngcE.js +1 -0
- package/dist/editor/assets/vb-DV3o63ZY.js +1 -0
- package/dist/editor/assets/wgsl-DpFanUEy.js +298 -0
- package/dist/editor/assets/xml-BCx9e6CK.js +1 -0
- package/dist/editor/assets/yaml-Bb-peGP_.js +1 -0
- package/dist/editor/index.html +14 -0
- package/dist/mcp/archetypes.js +103 -0
- package/dist/mcp/cli.js +6 -0
- package/dist/mcp/create-project.js +151 -0
- package/dist/mcp/introspection.js +201 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/assets/waica-coin.png +0 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/assets/waica-dog.png +0 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/assets/waica-slime.png +0 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/art.d.ts +10 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/art.js +13 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/bundle.d.ts +3 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/bundle.js +10 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/controls.d.ts +5 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/controls.js +12 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/index.d.ts +38 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/index.js +34 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/manifest.d.ts +15 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/manifest.js +26 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/prefabs.d.ts +7 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/prefabs.js +97 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/registry-data.d.ts +5 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/registry-data.js +45 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/registry.d.ts +6 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/registry.js +15 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/scene-default.d.ts +40 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/scene-default.js +93 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/ui.d.ts +10 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/ui.js +24 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/package.json +30 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/chaser.d.ts +59 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/chaser.js +127 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/collectible.d.ts +25 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/collectible.js +27 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/hazard.d.ts +29 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/hazard.js +42 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/index.d.ts +9 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/index.js +9 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/lifetime.d.ts +16 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/lifetime.js +19 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/npc.d.ts +4 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/npc.js +14 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/patrol.d.ts +43 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/patrol.js +68 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/platformer-motor.d.ts +124 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/platformer-motor.js +146 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/player-identity.d.ts +3 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/player-identity.js +5 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/player-states.d.ts +18 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/player-states.js +95 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/respawnable.d.ts +23 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/respawnable.js +27 -0
- package/dist/mcp/node_modules/@waica/behaviors/package.json +24 -0
- package/dist/mcp/node_modules/@waica/engine/dist/aabb.d.ts +2 -0
- package/dist/mcp/node_modules/@waica/engine/dist/aabb.js +4 -0
- package/dist/mcp/node_modules/@waica/engine/dist/animation/clip-player.d.ts +20 -0
- package/dist/mcp/node_modules/@waica/engine/dist/animation/clip-player.js +24 -0
- package/dist/mcp/node_modules/@waica/engine/dist/animation/contract.d.ts +21 -0
- package/dist/mcp/node_modules/@waica/engine/dist/animation/contract.js +23 -0
- package/dist/mcp/node_modules/@waica/engine/dist/animation/sheet.d.ts +65 -0
- package/dist/mcp/node_modules/@waica/engine/dist/animation/sheet.js +44 -0
- package/dist/mcp/node_modules/@waica/engine/dist/archetype.d.ts +37 -0
- package/dist/mcp/node_modules/@waica/engine/dist/archetype.js +1 -0
- package/dist/mcp/node_modules/@waica/engine/dist/camera.d.ts +71 -0
- package/dist/mcp/node_modules/@waica/engine/dist/camera.js +59 -0
- package/dist/mcp/node_modules/@waica/engine/dist/collision-shape.d.ts +26 -0
- package/dist/mcp/node_modules/@waica/engine/dist/collision-shape.js +136 -0
- package/dist/mcp/node_modules/@waica/engine/dist/component-registry.d.ts +16 -0
- package/dist/mcp/node_modules/@waica/engine/dist/component-registry.js +44 -0
- package/dist/mcp/node_modules/@waica/engine/dist/component.d.ts +58 -0
- package/dist/mcp/node_modules/@waica/engine/dist/component.js +11 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/animated-sprite.d.ts +80 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/animated-sprite.js +210 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/dynamic-body.d.ts +68 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/dynamic-body.js +189 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/hitbox.d.ts +25 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/hitbox.js +21 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/solid.d.ts +32 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/solid.js +45 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/sprite.d.ts +51 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/sprite.js +112 -0
- package/dist/mcp/node_modules/@waica/engine/dist/entity.d.ts +22 -0
- package/dist/mcp/node_modules/@waica/engine/dist/entity.js +52 -0
- package/dist/mcp/node_modules/@waica/engine/dist/events.d.ts +8 -0
- package/dist/mcp/node_modules/@waica/engine/dist/events.js +20 -0
- package/dist/mcp/node_modules/@waica/engine/dist/game.d.ts +95 -0
- package/dist/mcp/node_modules/@waica/engine/dist/game.js +263 -0
- package/dist/mcp/node_modules/@waica/engine/dist/index.d.ts +39 -0
- package/dist/mcp/node_modules/@waica/engine/dist/index.js +26 -0
- package/dist/mcp/node_modules/@waica/engine/dist/input.d.ts +40 -0
- package/dist/mcp/node_modules/@waica/engine/dist/input.js +84 -0
- package/dist/mcp/node_modules/@waica/engine/dist/scene.d.ts +80 -0
- package/dist/mcp/node_modules/@waica/engine/dist/scene.js +93 -0
- package/dist/mcp/node_modules/@waica/engine/dist/solid-axis.d.ts +21 -0
- package/dist/mcp/node_modules/@waica/engine/dist/solid-axis.js +77 -0
- package/dist/mcp/node_modules/@waica/engine/dist/state/hooks.d.ts +90 -0
- package/dist/mcp/node_modules/@waica/engine/dist/state/hooks.js +81 -0
- package/dist/mcp/node_modules/@waica/engine/dist/state/state-machine.d.ts +83 -0
- package/dist/mcp/node_modules/@waica/engine/dist/state/state-machine.js +173 -0
- package/dist/mcp/node_modules/@waica/engine/dist/stats.d.ts +27 -0
- package/dist/mcp/node_modules/@waica/engine/dist/stats.js +54 -0
- package/dist/mcp/node_modules/@waica/engine/dist/ui.d.ts +47 -0
- package/dist/mcp/node_modules/@waica/engine/dist/ui.js +175 -0
- package/dist/mcp/node_modules/@waica/engine/package.json +25 -0
- package/dist/mcp/package-resolver.js +240 -0
- package/dist/mcp/project-path.js +86 -0
- package/dist/mcp/scaffolds.js +153 -0
- package/dist/mcp/server.js +217 -0
- package/dist/mcp/stdio.js +13 -0
- package/dist/mcp/template/README.md +22 -0
- package/dist/mcp/template/_gitignore +5 -0
- package/dist/mcp/template/index.html +25 -0
- package/dist/mcp/template/package.json.tpl +20 -0
- package/dist/mcp/template/public/waica.params.json +1 -0
- package/dist/mcp/template/src/art/waica-coin.png +0 -0
- package/dist/mcp/template/src/art/waica-dog.png +0 -0
- package/dist/mcp/template/src/art/waica-slime.png +0 -0
- package/dist/mcp/template/src/characters/player.character.json +133 -0
- package/dist/mcp/template/src/characters/slime.character.json +61 -0
- package/dist/mcp/template/src/controls.json +8 -0
- package/dist/mcp/template/src/game.json +10 -0
- package/dist/mcp/template/src/main.ts +105 -0
- package/dist/mcp/template/src/objects/coin.object.json +41 -0
- package/dist/mcp/template/src/scenes/main.scene.json +217 -0
- package/dist/mcp/template/src/stats.json +7 -0
- package/dist/mcp/template/src/tiles/block.tile.json +21 -0
- package/dist/mcp/template/src/tiles/decor.tile.json +14 -0
- package/dist/mcp/template/src/tiles/platform.tile.json +21 -0
- package/dist/mcp/template/src/ui/coin-counter.html +12 -0
- package/dist/mcp/template/tsconfig.json +15 -0
- package/dist/mcp/template/vite.config.ts +3 -0
- package/dist/mcp/validation.js +323 -0
- package/dist/mcp/workspace-loader.js +14 -0
- package/dist/mcp/workspace-runtime.js +109 -0
- package/dist/server.js +210 -0
- package/package.json +38 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { Component } from '../component.js';
|
|
3
|
+
import { ClipPlayer } from '../animation/clip-player.js';
|
|
4
|
+
import { locateFrame, sheetCell } from '../animation/sheet.js';
|
|
5
|
+
const loader = new THREE.TextureLoader();
|
|
6
|
+
/**
|
|
7
|
+
* Sprite animated from one or more spritesheets. The main sheet is the
|
|
8
|
+
* top-level texture/cols/rows (or explicit cells); extraSheets append after
|
|
9
|
+
* it, and clip frames index the sheets consecutively (sheet 0 owns 0..n0-1,
|
|
10
|
+
* sheet 1 the next n1, …). Each instance clones its textures to animate UVs
|
|
11
|
+
* independently. On sheets with explicit cells the frames vary in pixel size,
|
|
12
|
+
* so the quad rescales per frame, anchored bottom-center — width/height size
|
|
13
|
+
* the sheet's largest frame and smaller ones keep their feet planted.
|
|
14
|
+
*/
|
|
15
|
+
export class AnimatedSprite extends Component {
|
|
16
|
+
static componentName = 'AnimatedSprite';
|
|
17
|
+
static params = {
|
|
18
|
+
offsetX: { label: 'x offset' },
|
|
19
|
+
offsetY: { label: 'y offset' },
|
|
20
|
+
layer: { label: 'layer', min: -5, max: 5, step: 1 },
|
|
21
|
+
};
|
|
22
|
+
/** Spritesheet URL. */
|
|
23
|
+
texture = '';
|
|
24
|
+
/** Sheet grid dimensions. */
|
|
25
|
+
cols = 1;
|
|
26
|
+
rows = 1;
|
|
27
|
+
// Slicing params for sheets whose frames don't fill the image (margins,
|
|
28
|
+
// gaps, fixed cell size). In image pixels; 0 = default uniform grid.
|
|
29
|
+
gridOffsetX = 0;
|
|
30
|
+
gridOffsetY = 0;
|
|
31
|
+
spacingX = 0;
|
|
32
|
+
spacingY = 0;
|
|
33
|
+
cellWidth = 0;
|
|
34
|
+
cellHeight = 0;
|
|
35
|
+
/** Explicit frame rects for the main sheet (packed sheets); wins over the grid. */
|
|
36
|
+
cells = [];
|
|
37
|
+
/** Additional sheets after the main one; clip frames continue across them. */
|
|
38
|
+
extraSheets = [];
|
|
39
|
+
// Size in world units. Reactive like Sprite's: assigning rescales the unit
|
|
40
|
+
// quad, even outside the simulation loop (the editor drags them live).
|
|
41
|
+
_width = 1;
|
|
42
|
+
_height = 1;
|
|
43
|
+
get width() {
|
|
44
|
+
return this._width;
|
|
45
|
+
}
|
|
46
|
+
set width(value) {
|
|
47
|
+
this._width = value;
|
|
48
|
+
this.syncQuad();
|
|
49
|
+
}
|
|
50
|
+
get height() {
|
|
51
|
+
return this._height;
|
|
52
|
+
}
|
|
53
|
+
set height(value) {
|
|
54
|
+
this._height = value;
|
|
55
|
+
this.syncQuad();
|
|
56
|
+
}
|
|
57
|
+
_offsetX = 0;
|
|
58
|
+
_offsetY = 0;
|
|
59
|
+
get offsetX() {
|
|
60
|
+
return this._offsetX;
|
|
61
|
+
}
|
|
62
|
+
set offsetX(value) {
|
|
63
|
+
this._offsetX = value;
|
|
64
|
+
this.syncQuad();
|
|
65
|
+
}
|
|
66
|
+
get offsetY() {
|
|
67
|
+
return this._offsetY;
|
|
68
|
+
}
|
|
69
|
+
set offsetY(value) {
|
|
70
|
+
this._offsetY = value;
|
|
71
|
+
this.syncQuad();
|
|
72
|
+
}
|
|
73
|
+
pixelArt = true;
|
|
74
|
+
// Draw order among sprites: higher layers render in front. Same-layer
|
|
75
|
+
// sprites fall back to spawn order, so give overlap an explicit layer.
|
|
76
|
+
_layer = 0;
|
|
77
|
+
get layer() {
|
|
78
|
+
return this._layer;
|
|
79
|
+
}
|
|
80
|
+
set layer(value) {
|
|
81
|
+
this._layer = value;
|
|
82
|
+
if (this.mesh)
|
|
83
|
+
this.mesh.position.z = value * 0.01;
|
|
84
|
+
}
|
|
85
|
+
clips = {};
|
|
86
|
+
initialClip;
|
|
87
|
+
/** Clip currently playing. */
|
|
88
|
+
current;
|
|
89
|
+
player = new ClipPlayer();
|
|
90
|
+
sheets = [];
|
|
91
|
+
texs = [];
|
|
92
|
+
mesh;
|
|
93
|
+
frame = 0;
|
|
94
|
+
// Current frame's quad scale relative to the sheet's largest cell: always
|
|
95
|
+
// 1 on grid sheets, per-frame on cell sheets (frames vary in pixel size).
|
|
96
|
+
frameScaleX = 1;
|
|
97
|
+
frameScaleY = 1;
|
|
98
|
+
onReady() {
|
|
99
|
+
const main = {
|
|
100
|
+
texture: this.texture,
|
|
101
|
+
cols: this.cols,
|
|
102
|
+
rows: this.rows,
|
|
103
|
+
gridOffsetX: this.gridOffsetX,
|
|
104
|
+
gridOffsetY: this.gridOffsetY,
|
|
105
|
+
spacingX: this.spacingX,
|
|
106
|
+
spacingY: this.spacingY,
|
|
107
|
+
cellWidth: this.cellWidth,
|
|
108
|
+
cellHeight: this.cellHeight,
|
|
109
|
+
};
|
|
110
|
+
if (this.cells.length)
|
|
111
|
+
main.cells = this.cells;
|
|
112
|
+
this.sheets = [main, ...this.extraSheets];
|
|
113
|
+
this.texs = this.sheets.map((sheet) => {
|
|
114
|
+
// Non-uniform slicing needs the image's pixel size, so re-apply the
|
|
115
|
+
// current frame once each texture is in.
|
|
116
|
+
const tex = loader.load(sheet.texture, () => this.applyFrame());
|
|
117
|
+
tex.colorSpace = THREE.SRGBColorSpace;
|
|
118
|
+
if (this.pixelArt) {
|
|
119
|
+
tex.magFilter = THREE.NearestFilter;
|
|
120
|
+
tex.minFilter = THREE.NearestFilter;
|
|
121
|
+
}
|
|
122
|
+
tex.repeat.set(1 / Math.max(1, sheet.cols), 1 / Math.max(1, sheet.rows));
|
|
123
|
+
return tex;
|
|
124
|
+
});
|
|
125
|
+
const material = new THREE.MeshBasicMaterial({ map: this.texs[0], transparent: true });
|
|
126
|
+
this.mesh = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), material);
|
|
127
|
+
this.mesh.position.z = this.layer * 0.01;
|
|
128
|
+
this.syncQuad();
|
|
129
|
+
this.entity.node.add(this.mesh);
|
|
130
|
+
if (this.initialClip)
|
|
131
|
+
this.play(this.initialClip);
|
|
132
|
+
}
|
|
133
|
+
/** Switches clip; repeating the same name doesn't restart the animation. */
|
|
134
|
+
play(name) {
|
|
135
|
+
if (this.current === name)
|
|
136
|
+
return;
|
|
137
|
+
const clip = this.clips[name];
|
|
138
|
+
if (!clip)
|
|
139
|
+
return;
|
|
140
|
+
this.player.set(clip);
|
|
141
|
+
this.current = name;
|
|
142
|
+
}
|
|
143
|
+
onUpdate(dt) {
|
|
144
|
+
if (this.texs.length === 0 || !this.current)
|
|
145
|
+
return;
|
|
146
|
+
this.showFrame(this.player.advance(dt));
|
|
147
|
+
}
|
|
148
|
+
onDestroy() {
|
|
149
|
+
this.mesh?.removeFromParent();
|
|
150
|
+
this.mesh?.geometry.dispose();
|
|
151
|
+
this.mesh?.material.dispose();
|
|
152
|
+
for (const tex of this.texs)
|
|
153
|
+
tex.dispose();
|
|
154
|
+
}
|
|
155
|
+
showFrame(index) {
|
|
156
|
+
this.frame = index;
|
|
157
|
+
this.applyFrame();
|
|
158
|
+
}
|
|
159
|
+
/** Repositions/rescales the quad from size, offsets and the frame scale. */
|
|
160
|
+
syncQuad() {
|
|
161
|
+
if (!this.mesh)
|
|
162
|
+
return;
|
|
163
|
+
this.mesh.scale.set(this._width * this.frameScaleX, this._height * this.frameScaleY, 1);
|
|
164
|
+
// Bottom-center anchor: a shrunk frame keeps its feet on the quad's floor.
|
|
165
|
+
this.mesh.position.x = this._offsetX;
|
|
166
|
+
this.mesh.position.y = this._offsetY - (this._height * (1 - this.frameScaleY)) / 2;
|
|
167
|
+
}
|
|
168
|
+
applyFrame() {
|
|
169
|
+
const located = locateFrame(this.sheets, this.frame);
|
|
170
|
+
const sheet = this.sheets[located.sheet];
|
|
171
|
+
const tex = this.texs[located.sheet];
|
|
172
|
+
if (!sheet || !tex)
|
|
173
|
+
return;
|
|
174
|
+
if (this.mesh && this.mesh.material.map !== tex) {
|
|
175
|
+
this.mesh.material.map = tex;
|
|
176
|
+
this.mesh.material.needsUpdate = true;
|
|
177
|
+
}
|
|
178
|
+
const cells = sheet.cells;
|
|
179
|
+
if (cells?.length) {
|
|
180
|
+
const cell = sheetCell(0, 0, sheet.cols, sheet.rows, located.frame, sheet);
|
|
181
|
+
const maxW = Math.max(...cells.map((c) => c.width));
|
|
182
|
+
const maxH = Math.max(...cells.map((c) => c.height));
|
|
183
|
+
this.frameScaleX = maxW > 0 ? cell.width / maxW : 1;
|
|
184
|
+
this.frameScaleY = maxH > 0 ? cell.height / maxH : 1;
|
|
185
|
+
this.syncQuad();
|
|
186
|
+
const image = tex.image;
|
|
187
|
+
if (image?.width && image?.height) {
|
|
188
|
+
tex.repeat.set(cell.width / image.width, cell.height / image.height);
|
|
189
|
+
tex.offset.set(cell.x / image.width, 1 - (cell.y + cell.height) / image.height);
|
|
190
|
+
}
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (this.frameScaleX !== 1 || this.frameScaleY !== 1) {
|
|
194
|
+
this.frameScaleX = 1;
|
|
195
|
+
this.frameScaleY = 1;
|
|
196
|
+
this.syncQuad();
|
|
197
|
+
}
|
|
198
|
+
const image = tex.image;
|
|
199
|
+
if (image?.width && image?.height) {
|
|
200
|
+
const cell = sheetCell(image.width, image.height, sheet.cols, sheet.rows, located.frame, sheet);
|
|
201
|
+
tex.repeat.set(cell.width / image.width, cell.height / image.height);
|
|
202
|
+
tex.offset.set(cell.x / image.width, 1 - (cell.y + cell.height) / image.height);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
// Image not loaded yet: uniform-grid math needs no pixel size.
|
|
206
|
+
const cols = Math.max(1, sheet.cols);
|
|
207
|
+
const rows = Math.max(1, sheet.rows);
|
|
208
|
+
tex.offset.set((located.frame % cols) / cols, 1 - (Math.floor(located.frame / cols) + 1) / rows);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type CollisionPoint, type CollisionShape } from '../collision-shape.js';
|
|
2
|
+
import { Component } from '../component.js';
|
|
3
|
+
/**
|
|
4
|
+
* Reusable linear body: integrates its public velocity and resolves only
|
|
5
|
+
* against static Solid geometry. Hitbox trigger overlaps remain independent.
|
|
6
|
+
*/
|
|
7
|
+
export declare class DynamicBody extends Component {
|
|
8
|
+
static componentName: string;
|
|
9
|
+
static params: {
|
|
10
|
+
vx: {
|
|
11
|
+
label: string;
|
|
12
|
+
step: number;
|
|
13
|
+
};
|
|
14
|
+
vy: {
|
|
15
|
+
label: string;
|
|
16
|
+
step: number;
|
|
17
|
+
};
|
|
18
|
+
shape: {
|
|
19
|
+
label: string;
|
|
20
|
+
options: CollisionShape[];
|
|
21
|
+
};
|
|
22
|
+
width: {
|
|
23
|
+
label: string;
|
|
24
|
+
min: number;
|
|
25
|
+
step: number;
|
|
26
|
+
};
|
|
27
|
+
height: {
|
|
28
|
+
label: string;
|
|
29
|
+
min: number;
|
|
30
|
+
step: number;
|
|
31
|
+
};
|
|
32
|
+
offsetX: {
|
|
33
|
+
label: string;
|
|
34
|
+
step: number;
|
|
35
|
+
};
|
|
36
|
+
offsetY: {
|
|
37
|
+
label: string;
|
|
38
|
+
step: number;
|
|
39
|
+
};
|
|
40
|
+
points: {
|
|
41
|
+
label: string;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
vx: number;
|
|
45
|
+
vy: number;
|
|
46
|
+
shape: CollisionShape;
|
|
47
|
+
width: number;
|
|
48
|
+
height: number;
|
|
49
|
+
offsetX: number;
|
|
50
|
+
offsetY: number;
|
|
51
|
+
/** Polygon vertices normalized against width/height. */
|
|
52
|
+
points: CollisionPoint[];
|
|
53
|
+
onUpdate(dt: number): void;
|
|
54
|
+
private moveAxis;
|
|
55
|
+
/**
|
|
56
|
+
* Finds the shortest cardinal translation that clears every Solid.
|
|
57
|
+
* Equal distances keep RECOVERY_DIRECTIONS order: -X, +X, -Y, +Y.
|
|
58
|
+
*/
|
|
59
|
+
private recoverInitialOverlap;
|
|
60
|
+
private setShift;
|
|
61
|
+
private resetPosition;
|
|
62
|
+
private overlapsAny;
|
|
63
|
+
private deliver;
|
|
64
|
+
private contact;
|
|
65
|
+
private solids;
|
|
66
|
+
private collisionBody;
|
|
67
|
+
private solidBody;
|
|
68
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { COLLISION_SHAPES, collisionBounds, collisionOverlap, resolveCollisionPoints, } from '../collision-shape.js';
|
|
2
|
+
import { Component } from '../component.js';
|
|
3
|
+
import { resolveSolidAxis } from '../solid-axis.js';
|
|
4
|
+
import { Solid } from './solid.js';
|
|
5
|
+
/** Stable tie order for equal-distance initial-overlap recovery. */
|
|
6
|
+
const RECOVERY_DIRECTIONS = [
|
|
7
|
+
{ axis: 'x', sign: -1, normal: { x: -1, y: 0 } },
|
|
8
|
+
{ axis: 'x', sign: 1, normal: { x: 1, y: 0 } },
|
|
9
|
+
{ axis: 'y', sign: -1, normal: { x: 0, y: -1 } },
|
|
10
|
+
{ axis: 'y', sign: 1, normal: { x: 0, y: 1 } },
|
|
11
|
+
];
|
|
12
|
+
const RECOVERY_ITERATIONS = 24;
|
|
13
|
+
/**
|
|
14
|
+
* Reusable linear body: integrates its public velocity and resolves only
|
|
15
|
+
* against static Solid geometry. Hitbox trigger overlaps remain independent.
|
|
16
|
+
*/
|
|
17
|
+
export class DynamicBody extends Component {
|
|
18
|
+
static componentName = 'DynamicBody';
|
|
19
|
+
static params = {
|
|
20
|
+
vx: { label: 'x velocity', step: 0.1 },
|
|
21
|
+
vy: { label: 'y velocity', step: 0.1 },
|
|
22
|
+
shape: { label: 'shape', options: [...COLLISION_SHAPES] },
|
|
23
|
+
width: { label: 'width', min: 0, step: 0.1 },
|
|
24
|
+
height: { label: 'height', min: 0, step: 0.1 },
|
|
25
|
+
offsetX: { label: 'x offset', step: 0.1 },
|
|
26
|
+
offsetY: { label: 'y offset', step: 0.1 },
|
|
27
|
+
points: { label: 'polygon points' },
|
|
28
|
+
};
|
|
29
|
+
vx = 0;
|
|
30
|
+
vy = 0;
|
|
31
|
+
shape = 'rectangle';
|
|
32
|
+
width = 1;
|
|
33
|
+
height = 1;
|
|
34
|
+
offsetX = 0;
|
|
35
|
+
offsetY = 0;
|
|
36
|
+
/** Polygon vertices normalized against width/height. */
|
|
37
|
+
points = resolveCollisionPoints(undefined);
|
|
38
|
+
onUpdate(dt) {
|
|
39
|
+
const delivered = new Map();
|
|
40
|
+
const recovery = this.recoverInitialOverlap();
|
|
41
|
+
if (recovery && !this.deliver(recovery.contacts, delivered))
|
|
42
|
+
return;
|
|
43
|
+
if (!this.moveAxis('x', this.vx * dt, delivered))
|
|
44
|
+
return;
|
|
45
|
+
this.moveAxis('y', this.vy * dt, delivered);
|
|
46
|
+
}
|
|
47
|
+
moveAxis(axis, displacement, delivered) {
|
|
48
|
+
if (displacement === 0)
|
|
49
|
+
return this.entity.alive;
|
|
50
|
+
const previous = this.entity.position[axis];
|
|
51
|
+
this.entity.position[axis] += displacement;
|
|
52
|
+
const solids = [];
|
|
53
|
+
const blocked = resolveSolidAxis({
|
|
54
|
+
entity: this.entity,
|
|
55
|
+
axis,
|
|
56
|
+
previous,
|
|
57
|
+
body: () => this.collisionBody(),
|
|
58
|
+
onContact: (solid) => solids.push(solid),
|
|
59
|
+
});
|
|
60
|
+
if (!blocked)
|
|
61
|
+
return this.entity.alive;
|
|
62
|
+
if (axis === 'x')
|
|
63
|
+
this.vx = 0;
|
|
64
|
+
else
|
|
65
|
+
this.vy = 0;
|
|
66
|
+
const normal = axis === 'x'
|
|
67
|
+
? { x: displacement > 0 ? -1 : 1, y: 0 }
|
|
68
|
+
: { x: 0, y: displacement > 0 ? -1 : 1 };
|
|
69
|
+
return this.deliver(solids.map((solid) => this.contact(solid, axis, normal)), delivered);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Finds the shortest cardinal translation that clears every Solid.
|
|
73
|
+
* Equal distances keep RECOVERY_DIRECTIONS order: -X, +X, -Y, +Y.
|
|
74
|
+
*/
|
|
75
|
+
recoverInitialOverlap() {
|
|
76
|
+
const solids = this.solids();
|
|
77
|
+
const overlapping = solids.filter((solid) => collisionOverlap(this.collisionBody(), this.solidBody(solid)));
|
|
78
|
+
if (overlapping.length === 0)
|
|
79
|
+
return null;
|
|
80
|
+
const original = { x: this.entity.position.x, y: this.entity.position.y };
|
|
81
|
+
const bodyBounds = collisionBounds(this.collisionBody());
|
|
82
|
+
let best = null;
|
|
83
|
+
for (const direction of RECOVERY_DIRECTIONS) {
|
|
84
|
+
const shifts = solids
|
|
85
|
+
.map((solid) => {
|
|
86
|
+
const bounds = collisionBounds(this.solidBody(solid));
|
|
87
|
+
if (direction.axis === 'x') {
|
|
88
|
+
return direction.sign < 0
|
|
89
|
+
? bounds.left - bodyBounds.right
|
|
90
|
+
: bounds.right - bodyBounds.left;
|
|
91
|
+
}
|
|
92
|
+
return direction.sign < 0
|
|
93
|
+
? bounds.bottom - bodyBounds.top
|
|
94
|
+
: bounds.top - bodyBounds.bottom;
|
|
95
|
+
})
|
|
96
|
+
.filter((shift) => shift * direction.sign > 0)
|
|
97
|
+
.sort((a, b) => Math.abs(a) - Math.abs(b));
|
|
98
|
+
let clear = null;
|
|
99
|
+
for (const shift of shifts) {
|
|
100
|
+
this.setShift(original, direction.axis, shift);
|
|
101
|
+
if (!this.overlapsAny(solids)) {
|
|
102
|
+
clear = shift;
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
this.resetPosition(original);
|
|
107
|
+
if (clear === null)
|
|
108
|
+
continue;
|
|
109
|
+
let blockedShift = 0;
|
|
110
|
+
let clearShift = clear;
|
|
111
|
+
for (let iteration = 0; iteration < RECOVERY_ITERATIONS; iteration++) {
|
|
112
|
+
const middle = (blockedShift + clearShift) / 2;
|
|
113
|
+
this.setShift(original, direction.axis, middle);
|
|
114
|
+
if (this.overlapsAny(solids))
|
|
115
|
+
blockedShift = middle;
|
|
116
|
+
else
|
|
117
|
+
clearShift = middle;
|
|
118
|
+
}
|
|
119
|
+
this.resetPosition(original);
|
|
120
|
+
if (best && Math.abs(clearShift) >= Math.abs(best.shift))
|
|
121
|
+
continue;
|
|
122
|
+
best = {
|
|
123
|
+
direction,
|
|
124
|
+
shift: clearShift,
|
|
125
|
+
contacts: overlapping.map((solid) => this.contact(solid, direction.axis, direction.normal)),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
if (!best)
|
|
129
|
+
return null;
|
|
130
|
+
this.setShift(original, best.direction.axis, best.shift);
|
|
131
|
+
return best;
|
|
132
|
+
}
|
|
133
|
+
setShift(original, axis, shift) {
|
|
134
|
+
this.entity.position[axis] = original[axis] + shift;
|
|
135
|
+
}
|
|
136
|
+
resetPosition(original) {
|
|
137
|
+
this.entity.position.x = original.x;
|
|
138
|
+
this.entity.position.y = original.y;
|
|
139
|
+
}
|
|
140
|
+
overlapsAny(solids) {
|
|
141
|
+
const body = this.collisionBody();
|
|
142
|
+
return solids.some((solid) => collisionOverlap(body, this.solidBody(solid)));
|
|
143
|
+
}
|
|
144
|
+
deliver(contacts, delivered) {
|
|
145
|
+
for (const contact of contacts) {
|
|
146
|
+
const direction = `${contact.axis}:${contact.normal.x}:${contact.normal.y}`;
|
|
147
|
+
const directions = delivered.get(contact.solid) ?? new Set();
|
|
148
|
+
if (directions.has(direction))
|
|
149
|
+
continue;
|
|
150
|
+
directions.add(direction);
|
|
151
|
+
delivered.set(contact.solid, directions);
|
|
152
|
+
for (const component of [...this.entity.components]) {
|
|
153
|
+
if (!this.entity.alive)
|
|
154
|
+
return false;
|
|
155
|
+
component.onContact?.(contact);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return this.entity.alive;
|
|
159
|
+
}
|
|
160
|
+
contact(solid, axis, normal) {
|
|
161
|
+
return { entity: solid.entity, solid, axis, normal };
|
|
162
|
+
}
|
|
163
|
+
solids() {
|
|
164
|
+
return this.game.entities
|
|
165
|
+
.filter((entity) => entity !== this.entity)
|
|
166
|
+
.map((entity) => entity.get(Solid))
|
|
167
|
+
.filter((solid) => solid !== undefined);
|
|
168
|
+
}
|
|
169
|
+
collisionBody() {
|
|
170
|
+
return {
|
|
171
|
+
x: this.entity.position.x + this.offsetX,
|
|
172
|
+
y: this.entity.position.y + this.offsetY,
|
|
173
|
+
width: this.width,
|
|
174
|
+
height: this.height,
|
|
175
|
+
shape: this.shape,
|
|
176
|
+
points: this.points,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
solidBody(solid) {
|
|
180
|
+
return {
|
|
181
|
+
x: solid.entity.position.x + solid.offsetX,
|
|
182
|
+
y: solid.entity.position.y + solid.offsetY,
|
|
183
|
+
width: solid.width,
|
|
184
|
+
height: solid.height,
|
|
185
|
+
shape: solid.shape,
|
|
186
|
+
points: solid.points,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Component } from '../component.js';
|
|
2
|
+
import { type CollisionPoint, type CollisionShape } from '../collision-shape.js';
|
|
3
|
+
/**
|
|
4
|
+
* Trigger collider: the Game detects overlaps between Hitboxes and calls
|
|
5
|
+
* onCollide(other) on both entities' components. For static physical
|
|
6
|
+
* collision see Solid.
|
|
7
|
+
*/
|
|
8
|
+
export declare class Hitbox extends Component {
|
|
9
|
+
static componentName: string;
|
|
10
|
+
static params: {
|
|
11
|
+
offsetX: {
|
|
12
|
+
label: string;
|
|
13
|
+
};
|
|
14
|
+
offsetY: {
|
|
15
|
+
label: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
shape: CollisionShape;
|
|
19
|
+
width: number;
|
|
20
|
+
height: number;
|
|
21
|
+
offsetX: number;
|
|
22
|
+
offsetY: number;
|
|
23
|
+
/** Polygon vertices normalized against width/height. */
|
|
24
|
+
points: CollisionPoint[];
|
|
25
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Component } from '../component.js';
|
|
2
|
+
import { resolveCollisionPoints, } from '../collision-shape.js';
|
|
3
|
+
/**
|
|
4
|
+
* Trigger collider: the Game detects overlaps between Hitboxes and calls
|
|
5
|
+
* onCollide(other) on both entities' components. For static physical
|
|
6
|
+
* collision see Solid.
|
|
7
|
+
*/
|
|
8
|
+
export class Hitbox extends Component {
|
|
9
|
+
static componentName = 'Hitbox';
|
|
10
|
+
static params = {
|
|
11
|
+
offsetX: { label: 'x offset' },
|
|
12
|
+
offsetY: { label: 'y offset' },
|
|
13
|
+
};
|
|
14
|
+
shape = 'rectangle';
|
|
15
|
+
width = 1;
|
|
16
|
+
height = 1;
|
|
17
|
+
offsetX = 0;
|
|
18
|
+
offsetY = 0;
|
|
19
|
+
/** Polygon vertices normalized against width/height. */
|
|
20
|
+
points = resolveCollisionPoints(undefined);
|
|
21
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Component } from '../component.js';
|
|
2
|
+
import { type CollisionPoint, type CollisionShape } from '../collision-shape.js';
|
|
3
|
+
/**
|
|
4
|
+
* Static collider. Character motors (e.g. PlatformerMotor) collide against
|
|
5
|
+
* every Solid in the scene.
|
|
6
|
+
*
|
|
7
|
+
* TODO(H1): general dynamic bodies via Rapier; genre character controllers
|
|
8
|
+
* stay hand-rolled so their game feel remains deterministic.
|
|
9
|
+
*/
|
|
10
|
+
export declare class Solid extends Component {
|
|
11
|
+
static componentName: string;
|
|
12
|
+
static params: {
|
|
13
|
+
offsetX: {
|
|
14
|
+
label: string;
|
|
15
|
+
};
|
|
16
|
+
offsetY: {
|
|
17
|
+
label: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
shape: CollisionShape;
|
|
21
|
+
width: number;
|
|
22
|
+
height: number;
|
|
23
|
+
offsetX: number;
|
|
24
|
+
offsetY: number;
|
|
25
|
+
/** Polygon vertices normalized against width/height. */
|
|
26
|
+
points: CollisionPoint[];
|
|
27
|
+
private get bounds();
|
|
28
|
+
get left(): number;
|
|
29
|
+
get right(): number;
|
|
30
|
+
get top(): number;
|
|
31
|
+
get bottom(): number;
|
|
32
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Component } from '../component.js';
|
|
2
|
+
import { collisionBounds, resolveCollisionPoints, } from '../collision-shape.js';
|
|
3
|
+
/**
|
|
4
|
+
* Static collider. Character motors (e.g. PlatformerMotor) collide against
|
|
5
|
+
* every Solid in the scene.
|
|
6
|
+
*
|
|
7
|
+
* TODO(H1): general dynamic bodies via Rapier; genre character controllers
|
|
8
|
+
* stay hand-rolled so their game feel remains deterministic.
|
|
9
|
+
*/
|
|
10
|
+
export class Solid extends Component {
|
|
11
|
+
static componentName = 'Solid';
|
|
12
|
+
static params = {
|
|
13
|
+
offsetX: { label: 'x offset' },
|
|
14
|
+
offsetY: { label: 'y offset' },
|
|
15
|
+
};
|
|
16
|
+
shape = 'rectangle';
|
|
17
|
+
width = 1;
|
|
18
|
+
height = 1;
|
|
19
|
+
offsetX = 0;
|
|
20
|
+
offsetY = 0;
|
|
21
|
+
/** Polygon vertices normalized against width/height. */
|
|
22
|
+
points = resolveCollisionPoints(undefined);
|
|
23
|
+
get bounds() {
|
|
24
|
+
return collisionBounds({
|
|
25
|
+
x: this.entity.position.x + this.offsetX,
|
|
26
|
+
y: this.entity.position.y + this.offsetY,
|
|
27
|
+
width: this.width,
|
|
28
|
+
height: this.height,
|
|
29
|
+
shape: this.shape,
|
|
30
|
+
points: this.points,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
get left() {
|
|
34
|
+
return this.bounds.left;
|
|
35
|
+
}
|
|
36
|
+
get right() {
|
|
37
|
+
return this.bounds.right;
|
|
38
|
+
}
|
|
39
|
+
get top() {
|
|
40
|
+
return this.bounds.top;
|
|
41
|
+
}
|
|
42
|
+
get bottom() {
|
|
43
|
+
return this.bounds.bottom;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Component } from '../component.js';
|
|
2
|
+
export type SpriteShape = 'rectangle' | 'circle';
|
|
3
|
+
/**
|
|
4
|
+
* Textured or flat-color quad. In the unified pipeline, a 2D sprite is a
|
|
5
|
+
* plane in front of the orthographic camera (see DESIGN.md §6, decision 2).
|
|
6
|
+
*/
|
|
7
|
+
export declare class Sprite extends Component {
|
|
8
|
+
static componentName: string;
|
|
9
|
+
static params: {
|
|
10
|
+
offsetX: {
|
|
11
|
+
label: string;
|
|
12
|
+
};
|
|
13
|
+
offsetY: {
|
|
14
|
+
label: string;
|
|
15
|
+
};
|
|
16
|
+
layer: {
|
|
17
|
+
label: string;
|
|
18
|
+
min: number;
|
|
19
|
+
max: number;
|
|
20
|
+
step: number;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
private _width;
|
|
24
|
+
private _height;
|
|
25
|
+
get width(): number;
|
|
26
|
+
set width(value: number);
|
|
27
|
+
get height(): number;
|
|
28
|
+
set height(value: number);
|
|
29
|
+
private _color;
|
|
30
|
+
get color(): number;
|
|
31
|
+
set color(value: number);
|
|
32
|
+
private _offsetX;
|
|
33
|
+
private _offsetY;
|
|
34
|
+
get offsetX(): number;
|
|
35
|
+
set offsetX(value: number);
|
|
36
|
+
get offsetY(): number;
|
|
37
|
+
set offsetY(value: number);
|
|
38
|
+
/** Optional texture URL; with pixelArt on it filters in nearest. */
|
|
39
|
+
texture?: string;
|
|
40
|
+
pixelArt: boolean;
|
|
41
|
+
private _layer;
|
|
42
|
+
get layer(): number;
|
|
43
|
+
set layer(value: number);
|
|
44
|
+
private _shape;
|
|
45
|
+
get shape(): SpriteShape;
|
|
46
|
+
set shape(value: SpriteShape);
|
|
47
|
+
private mesh?;
|
|
48
|
+
onReady(): void;
|
|
49
|
+
onDestroy(): void;
|
|
50
|
+
private createGeometry;
|
|
51
|
+
}
|