canvasengine 1.3.0 → 2.0.1-beta.1
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/.cursorrules +0 -0
- package/.github/workflows/ci.yml +29 -0
- package/README.md +79 -0
- package/dist/compiler/vite.js +119 -0
- package/dist/compiler/vite.js.map +1 -0
- package/dist/index.d.ts +846 -0
- package/dist/index.js +3340 -0
- package/dist/index.js.map +1 -0
- package/index.d.ts +6 -0
- package/logo.png +0 -0
- package/package.json +84 -18
- package/src/compiler/grammar.pegjs +180 -0
- package/src/compiler/vite.ts +166 -0
- package/src/components/Canvas.ts +134 -0
- package/src/components/Container.ts +46 -0
- package/src/components/DisplayObject.ts +458 -0
- package/src/components/DrawMap/index.ts +65 -0
- package/src/components/Graphic.ts +147 -0
- package/src/components/NineSliceSprite.ts +46 -0
- package/src/components/ParticleEmitter.ts +39 -0
- package/src/components/Scene.ts +6 -0
- package/src/components/Sprite.ts +493 -0
- package/src/components/Text.ts +145 -0
- package/src/components/Tilemap/Tile.ts +79 -0
- package/src/components/Tilemap/TileGroup.ts +207 -0
- package/src/components/Tilemap/TileLayer.ts +163 -0
- package/src/components/Tilemap/TileSet.ts +41 -0
- package/src/components/Tilemap/index.ts +80 -0
- package/src/components/TilingSprite.ts +39 -0
- package/src/components/Viewport.ts +159 -0
- package/src/components/index.ts +12 -0
- package/src/components/types/DisplayObject.ts +68 -0
- package/src/components/types/MouseEvent.ts +3 -0
- package/src/components/types/Spritesheet.ts +389 -0
- package/src/components/types/index.ts +4 -0
- package/src/directives/Drag.ts +84 -0
- package/src/directives/KeyboardControls.ts +922 -0
- package/src/directives/Scheduler.ts +112 -0
- package/src/directives/Sound.ts +91 -0
- package/src/directives/Transition.ts +45 -0
- package/src/directives/ViewportCull.ts +40 -0
- package/src/directives/ViewportFollow.ts +26 -0
- package/src/directives/index.ts +7 -0
- package/src/engine/animation.ts +113 -0
- package/src/engine/bootstrap.ts +19 -0
- package/src/engine/directive.ts +23 -0
- package/src/engine/reactive.ts +379 -0
- package/src/engine/signal.ts +138 -0
- package/src/engine/trigger.ts +40 -0
- package/src/engine/utils.ts +135 -0
- package/src/hooks/addContext.ts +6 -0
- package/src/hooks/useProps.ts +155 -0
- package/src/hooks/useRef.ts +21 -0
- package/src/index.ts +14 -0
- package/src/presets/Bar.ts +89 -0
- package/src/presets/Button.ts +0 -0
- package/src/presets/Joystick.ts +286 -0
- package/src/presets/NightAmbiant.ts +122 -0
- package/src/presets/Particle.ts +53 -0
- package/src/utils/Ease.ts +33 -0
- package/src/utils/RadialGradient.ts +86 -0
- package/starter/assets/logo.png +0 -0
- package/starter/components/app.ce +18 -0
- package/starter/components/hello.ce +35 -0
- package/starter/index.html +21 -0
- package/starter/main.ts +6 -0
- package/starter/package.json +20 -0
- package/starter/tsconfig.json +32 -0
- package/starter/vite.config.ts +12 -0
- package/tsconfig.json +32 -0
- package/tsconfig.node.json +10 -0
- package/tsup.config.ts +28 -0
- package/vitest.config.ts +12 -0
- package/.gitattributes +0 -22
- package/.npmignore +0 -163
- package/canvasengine-1.3.0.all.min.js +0 -21
- package/canvasengine.js +0 -5802
- package/core/DB.js +0 -24
- package/core/ModelServer.js +0 -348
- package/core/Users.js +0 -190
- package/core/engine-common.js +0 -952
- package/doc/cocoonjs.md +0 -36
- package/doc/doc-lang.yml +0 -43
- package/doc/doc-router.yml +0 -14
- package/doc/doc-tuto.yml +0 -9
- package/doc/doc.yml +0 -39
- package/doc/element.md +0 -37
- package/doc/entity.md +0 -90
- package/doc/extend.md +0 -47
- package/doc/get_started.md +0 -19
- package/doc/images/entity.png +0 -0
- package/doc/multitouch.md +0 -58
- package/doc/nodejs.md +0 -142
- package/doc/scene.md +0 -44
- package/doc/text.md +0 -156
- package/examples/server/client.html +0 -31
- package/examples/server/server.js +0 -16
- package/examples/tiled_server/client.html +0 -52
- package/examples/tiled_server/images/tiles_spritesheet.png +0 -0
- package/examples/tiled_server/server/map.json +0 -50
- package/examples/tiled_server/server/map.tmx +0 -16
- package/examples/tiled_server/server/server.js +0 -16
- package/extends/Animation.js +0 -910
- package/extends/Effect.js +0 -252
- package/extends/Gleed2d.js +0 -252
- package/extends/Hit.js +0 -1509
- package/extends/Input.js +0 -699
- package/extends/Marshal.js +0 -716
- package/extends/Scrolling.js +0 -388
- package/extends/Soundmanager2.js +0 -5466
- package/extends/Spritesheet.js +0 -196
- package/extends/Text.js +0 -366
- package/extends/Tiled.js +0 -403
- package/extends/Window.js +0 -575
- package/extends/gamepad.js +0 -397
- package/extends/socket.io.min.js +0 -2
- package/extends/swf/soundmanager2.swf +0 -0
- package/extends/swf/soundmanager2_debug.swf +0 -0
- package/extends/swf/soundmanager2_flash9.swf +0 -0
- package/extends/swf/soundmanager2_flash9_debug.swf +0 -0
- package/extends/swf/soundmanager2_flash_xdomain.zip +0 -0
- package/extends/workers/transition.js +0 -43
- package/index.js +0 -46
- package/license.txt +0 -19
- package/readme.md +0 -483
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { CompositeTilemap } from "@pixi/tilemap";
|
|
2
|
+
import { Tile as TiledTileClass } from '@rpgjs/tiled';
|
|
3
|
+
import { AnimatedSprite, Texture, groupD8 } from "pixi.js";
|
|
4
|
+
import { TileSet } from "./TileSet";
|
|
5
|
+
|
|
6
|
+
export class Tile extends AnimatedSprite {
|
|
7
|
+
static getTextures(tile: TiledTileClass, tileSet: TileSet) {
|
|
8
|
+
const textures: Texture[] = [];
|
|
9
|
+
|
|
10
|
+
if (tile.animations && tile.animations.length) {
|
|
11
|
+
tile.animations.forEach(frame => {
|
|
12
|
+
textures.push(tileSet.textures[frame.tileid])
|
|
13
|
+
});
|
|
14
|
+
} else {
|
|
15
|
+
textures.push(tileSet.textures[tile.gid - tileSet.firstgid])
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return textures;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
animations: { tileid: number, duration: number }[] = []
|
|
22
|
+
_x: number = 0
|
|
23
|
+
_y: number = 0
|
|
24
|
+
pointsBufIndex: number
|
|
25
|
+
properties: any = {}
|
|
26
|
+
|
|
27
|
+
constructor(
|
|
28
|
+
private tile: TiledTileClass,
|
|
29
|
+
private tileSet: TileSet
|
|
30
|
+
) {
|
|
31
|
+
super(Tile.getTextures(tile, tileSet));
|
|
32
|
+
this.animations = tile.animations || []
|
|
33
|
+
this.properties = tile.properties
|
|
34
|
+
this.textures = Tile.getTextures(tile, tileSet)
|
|
35
|
+
this.texture = this.textures[0] as Texture
|
|
36
|
+
this.flip()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get gid() {
|
|
40
|
+
return this.tile.gid
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
setAnimation(frame: CompositeTilemap) {
|
|
44
|
+
const size = this.animations.length
|
|
45
|
+
if (size > 1) {
|
|
46
|
+
const offset = (this.animations[1].tileid - this.animations[0].tileid) * this.width
|
|
47
|
+
frame.tileAnimX(offset, size)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
flip() {
|
|
52
|
+
let symmetry
|
|
53
|
+
let i = 0
|
|
54
|
+
const add = (symmetrySecond) => {
|
|
55
|
+
i++
|
|
56
|
+
if (symmetry) symmetry = groupD8.add(symmetry, symmetrySecond)
|
|
57
|
+
else symmetry = symmetrySecond
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (this.tile.horizontalFlip) {
|
|
61
|
+
add(groupD8.MIRROR_HORIZONTAL)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (this.tile.verticalFlip) {
|
|
65
|
+
add(groupD8.MIRROR_VERTICAL)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (this.tile.diagonalFlip) {
|
|
69
|
+
if (i % 2 == 0) {
|
|
70
|
+
add(groupD8.MAIN_DIAGONAL)
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
add(groupD8.REVERSE_DIAGONAL)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
//if (symmetry) this.texture.rotate = symmetry
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
interface TileOptions {
|
|
2
|
+
tilesetIndex?: number
|
|
3
|
+
tileId: number
|
|
4
|
+
x: number
|
|
5
|
+
y: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface TilesGroupOptions {
|
|
9
|
+
ignore?: boolean
|
|
10
|
+
probability?: number
|
|
11
|
+
baseHeight?: number
|
|
12
|
+
baseWidth?: number
|
|
13
|
+
rectMargin?: number
|
|
14
|
+
baseOffsetX?: number
|
|
15
|
+
baseOffsetY?: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class TileInfo {
|
|
19
|
+
tilesetIndex?: number
|
|
20
|
+
tileId: number
|
|
21
|
+
flags: Map<string, any> = new Map()
|
|
22
|
+
id: number = Math.random()
|
|
23
|
+
|
|
24
|
+
constructor(obj: TileOptions) {
|
|
25
|
+
this.tilesetIndex = obj.tilesetIndex ?? 0
|
|
26
|
+
this.tileId = obj.tileId
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
addFlag(key: string, value: any) {
|
|
30
|
+
this.flags.set(key, value)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class TilesGroup {
|
|
35
|
+
tiles: (TileInfo | null)[][] = []
|
|
36
|
+
width: number
|
|
37
|
+
height: number
|
|
38
|
+
ignore: boolean = false
|
|
39
|
+
probability: number = 1
|
|
40
|
+
baseHeight: number = 1
|
|
41
|
+
baseWidth?: number
|
|
42
|
+
baseOffsetX: number = 0
|
|
43
|
+
baseOffsetY: number = 0
|
|
44
|
+
rectMargin: number = 0
|
|
45
|
+
|
|
46
|
+
constructor(tiles: TileOptions[], public tilesetIndex: number = 0, options: TilesGroupOptions = {}) {
|
|
47
|
+
const pointsX = tiles.map(tile => tile.x)
|
|
48
|
+
const pointsY = tiles.map(tile => tile.y)
|
|
49
|
+
const offsetX = Math.min(...pointsX)
|
|
50
|
+
const offsetY = Math.min(...pointsY)
|
|
51
|
+
this.width = Math.max(...pointsX) - offsetX + 1
|
|
52
|
+
this.height = Math.max(...pointsY) - offsetY + 1
|
|
53
|
+
this.ignore = !!options.ignore
|
|
54
|
+
this.probability = options.probability ?? 1
|
|
55
|
+
this.baseHeight = options.baseHeight ?? 1
|
|
56
|
+
this.baseWidth = options.baseWidth
|
|
57
|
+
this.rectMargin = options.rectMargin ?? 0
|
|
58
|
+
this.baseOffsetX = options.baseOffsetX ?? 0
|
|
59
|
+
this.baseOffsetY = options.baseOffsetY ?? 0
|
|
60
|
+
this.fillTiles()
|
|
61
|
+
for (let tile of tiles) {
|
|
62
|
+
this.addTile(tile.x - offsetX, tile.y - offsetY, tile)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
getRect(x: number, y: number): { minX: number, minY: number, maxX: number, maxY: number } {
|
|
67
|
+
const margin = this.rectMargin
|
|
68
|
+
return {
|
|
69
|
+
minX: x - margin + this.baseOffsetX,
|
|
70
|
+
minY: y - this.tilesBaseHeight - margin - this.baseOffsetY,
|
|
71
|
+
maxX: x + this.tilesBaseWidth + margin,
|
|
72
|
+
maxY: y + margin
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get tilesBase() {
|
|
77
|
+
return this.tiles[this.tiles.length - 1]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
get tilesBaseWidth(): number {
|
|
81
|
+
return this.baseWidth ?? this.tilesBase.length
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
get tilesBaseHeight(): number {
|
|
85
|
+
return this.baseHeight
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
forEach(cb: (tileInfo: TileInfo | null, x: number, y: number) => void) {
|
|
89
|
+
for (let i = 0; i < this.tiles.length; i++) {
|
|
90
|
+
for (let j = 0; j < this.tiles[i].length; j++) {
|
|
91
|
+
cb(this.tiles[i][j], j, i)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
find(cb: (tileInfo: TileInfo | null, x: number, y: number) => boolean): TileInfo | null {
|
|
97
|
+
let found: TileInfo | null = null
|
|
98
|
+
this.forEach((tileInfo, x, y) => {
|
|
99
|
+
const bool = cb(tileInfo, x, y)
|
|
100
|
+
if (bool) found = tileInfo
|
|
101
|
+
})
|
|
102
|
+
return found
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
getOffsetY(): number {
|
|
106
|
+
const tilesBase = this.tilesBase
|
|
107
|
+
let offset = 0
|
|
108
|
+
this.forEach((tile, x, y) => {
|
|
109
|
+
if (tile?.tileId == (tilesBase?.[0]?.tileId)) {
|
|
110
|
+
offset = y
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
return offset
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
fillTiles() {
|
|
117
|
+
for (let i = 0; i < this.height; i++) {
|
|
118
|
+
this.tiles[i] = []
|
|
119
|
+
for (let j = 0; j < this.width; j++) {
|
|
120
|
+
this.tiles[i][j] = null
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
shiftToTopLeft(): void {
|
|
126
|
+
const matrix = this.tiles
|
|
127
|
+
|
|
128
|
+
// Find the first non-undefined element and its position
|
|
129
|
+
const foundFirst = () => {
|
|
130
|
+
let firstElementRow = -1;
|
|
131
|
+
let firstElementColumn = -1;
|
|
132
|
+
|
|
133
|
+
for (let col = 0; col < matrix.length; col++) {
|
|
134
|
+
if (!matrix[col]) matrix[col] = []
|
|
135
|
+
for (let row = 0; row < matrix[col].length; row++) {
|
|
136
|
+
if (matrix[col][row] !== undefined) {
|
|
137
|
+
firstElementRow = row;
|
|
138
|
+
firstElementColumn = col;
|
|
139
|
+
return {
|
|
140
|
+
firstElementRow,
|
|
141
|
+
firstElementColumn
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
firstElementRow,
|
|
149
|
+
firstElementColumn
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const { firstElementRow, firstElementColumn } = foundFirst()
|
|
154
|
+
|
|
155
|
+
// If no non-undefined element is found, return the original matrix
|
|
156
|
+
if (firstElementRow === -1) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Shift the matrix elements
|
|
161
|
+
const newMatrix: (TileInfo | null)[][] = [];
|
|
162
|
+
for (let col = firstElementColumn; col < matrix.length; col++) {
|
|
163
|
+
const newRow: (TileInfo | null)[] = [];
|
|
164
|
+
for (let row = firstElementRow; row < matrix[col].length; row++) {
|
|
165
|
+
newRow.push(matrix[col][row]);
|
|
166
|
+
}
|
|
167
|
+
newMatrix.push(newRow);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
this.tiles = newMatrix;
|
|
171
|
+
|
|
172
|
+
this.width = this.tiles[0].length
|
|
173
|
+
this.height = this.tiles.length
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
addTile(x: number, y: number, tileOptions: TileOptions) {
|
|
177
|
+
if (!this.tiles[y]) this.tiles[y] = []
|
|
178
|
+
this.tiles[y][x] = new TileInfo(tileOptions)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
addTileFlag(x: number, y: number, key: string, value: any) {
|
|
182
|
+
this.getTile(x, y)?.addFlag(key, value)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
getTile(x: number, y: number): TileInfo | null {
|
|
186
|
+
return this.tiles[y]?.[x]
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
getTilesByFlag(key: string, value: any): { tileInfo: TileInfo, x: number, y: number }[] {
|
|
190
|
+
const array: any = []
|
|
191
|
+
this.forEach((tileInfo, x, y) => {
|
|
192
|
+
const flag = tileInfo?.flags.get(key)
|
|
193
|
+
if (flag && flag == value) {
|
|
194
|
+
array.push({
|
|
195
|
+
tileInfo,
|
|
196
|
+
x,
|
|
197
|
+
y
|
|
198
|
+
})
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
return array
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
isTileBase(tileInfo: TileInfo): boolean {
|
|
205
|
+
return !!this.tilesBase.find(tile => tile?.id == tileInfo.id)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { CompositeTilemap, POINT_STRUCT_SIZE, Tilemap, settings } from '@pixi/tilemap';
|
|
2
|
+
import { Layer, Tile as TileClass } from '@rpgjs/tiled';
|
|
3
|
+
import { createComponent, registerComponent } from '../../engine/reactive';
|
|
4
|
+
import { DisplayObject } from '../DisplayObject';
|
|
5
|
+
import { Tile } from './Tile';
|
|
6
|
+
import { TileSet } from './TileSet';
|
|
7
|
+
|
|
8
|
+
settings.use32bitIndex = true
|
|
9
|
+
|
|
10
|
+
export class CanvasTileLayer extends DisplayObject(CompositeTilemap) {
|
|
11
|
+
private _tiles: any = {}
|
|
12
|
+
tiles: (TileClass | null)[]
|
|
13
|
+
private _layer: Layer
|
|
14
|
+
|
|
15
|
+
static findTileSet(gid: number, tileSets: TileSet[]) {
|
|
16
|
+
let tileset: TileSet | undefined
|
|
17
|
+
for (let i = tileSets.length - 1; i >= 0; i--) {
|
|
18
|
+
tileset = tileSets[i]
|
|
19
|
+
if (tileset.firstgid && tileset.firstgid <= gid) {
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return tileset;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** @internal */
|
|
27
|
+
createTile(x: number, y: number, options: any = {}): Tile | undefined {
|
|
28
|
+
const { real, filter } = options
|
|
29
|
+
const { tilewidth, tileheight, width } = this._layer
|
|
30
|
+
if (real) {
|
|
31
|
+
x = Math.floor(x / tilewidth)
|
|
32
|
+
y = Math.floor(y / tileheight)
|
|
33
|
+
}
|
|
34
|
+
const i = x + y * width;
|
|
35
|
+
const tiledTile = this._layer.getTileByIndex(i)
|
|
36
|
+
|
|
37
|
+
if (!tiledTile || (tiledTile && tiledTile.gid == 0)) return
|
|
38
|
+
|
|
39
|
+
const tileset = CanvasTileLayer.findTileSet(
|
|
40
|
+
tiledTile.gid,
|
|
41
|
+
this.tileSets
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
if (!tileset) return
|
|
45
|
+
|
|
46
|
+
const tile = new Tile(
|
|
47
|
+
tiledTile,
|
|
48
|
+
tileset
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
tile.x = x * tilewidth;
|
|
52
|
+
tile.y =
|
|
53
|
+
y * tileheight +
|
|
54
|
+
(tileheight -
|
|
55
|
+
tile.texture.height);
|
|
56
|
+
|
|
57
|
+
tile._x = x;
|
|
58
|
+
tile._y = y;
|
|
59
|
+
|
|
60
|
+
if (tileset.tileoffset) {
|
|
61
|
+
tile.x += tileset.tileoffset.x ?? 0;
|
|
62
|
+
tile.y += tileset.tileoffset.y ?? 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (filter) {
|
|
66
|
+
const ret = filter(tile)
|
|
67
|
+
if (!ret) return
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return tile
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** @internal */
|
|
74
|
+
changeTile(x: number, y: number) {
|
|
75
|
+
const { tilewidth, tileheight } = this._layer
|
|
76
|
+
x = Math.floor(x / tilewidth)
|
|
77
|
+
y = Math.floor(y / tileheight)
|
|
78
|
+
const oldTile: Tile = this._tiles[x + ';' + y]
|
|
79
|
+
const newTile = this.createTile(x, y)
|
|
80
|
+
if (!oldTile && newTile) {
|
|
81
|
+
this._addFrame(newTile, x, y)
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
if (newTile) {
|
|
85
|
+
const bufComposite: CompositeTilemap = new CompositeTilemap()
|
|
86
|
+
const frame = bufComposite.tile(newTile.texture, newTile.x, newTile.y)
|
|
87
|
+
newTile.setAnimation(frame)
|
|
88
|
+
this._tiles[x + ';' + y] = newTile
|
|
89
|
+
// @ts-ignore
|
|
90
|
+
const pointsBufComposite = (bufComposite.children[0] as Tilemap).pointsBuf
|
|
91
|
+
// Change Texture (=0, 1 and 7, rotate (=4), animX (=5), animY (=6))
|
|
92
|
+
;[0, 1, 4, 6, 7, 8].forEach((i) => {
|
|
93
|
+
if (this.pointsBuf) this.pointsBuf[oldTile.pointsBufIndex + i] = pointsBufComposite[i]
|
|
94
|
+
})
|
|
95
|
+
// @ts-ignore
|
|
96
|
+
this.children[0].modificationMarker = 0
|
|
97
|
+
this._addFrame(newTile, x, y)
|
|
98
|
+
this['modificationMarker'] = 0
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
delete this._tiles[x + ';' + y]
|
|
102
|
+
if (this.pointsBuf) this.pointsBuf.splice(oldTile.pointsBufIndex, POINT_STRUCT_SIZE)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** @internal */
|
|
108
|
+
get pointsBuf(): number[] | null {
|
|
109
|
+
const child = this.children[0] as Tilemap
|
|
110
|
+
if (!child) return null
|
|
111
|
+
return child['pointsBuf']
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private _addFrame(tile: Tile, x: number, y: number) {
|
|
115
|
+
const frame = this.tile(tile.texture, tile.x, tile.y, {
|
|
116
|
+
rotate: tile.texture.rotate
|
|
117
|
+
})
|
|
118
|
+
const pb = this.pointsBuf
|
|
119
|
+
if (!pb) return null
|
|
120
|
+
tile.pointsBufIndex = pb.length - POINT_STRUCT_SIZE
|
|
121
|
+
tile.setAnimation(frame)
|
|
122
|
+
this._tiles[x + ';' + y] = tile
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
onMount(args) {
|
|
126
|
+
const { props } = args
|
|
127
|
+
this.tileSets = props.tilesets
|
|
128
|
+
this._layer = new Layer({
|
|
129
|
+
...props
|
|
130
|
+
}, this.tileSets)
|
|
131
|
+
super.onMount(args)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
onUpdate(props) {
|
|
135
|
+
super.onUpdate(props)
|
|
136
|
+
if (!this.isMounted) return
|
|
137
|
+
if (props.tileheight) this._layer.tileheight = props.tileheight
|
|
138
|
+
if (props.tilewidth) this._layer.tilewidth = props.tilewidth
|
|
139
|
+
if (props.width) this._layer.width = props.width
|
|
140
|
+
if (props.height) this._layer.height = props.height
|
|
141
|
+
if (props.parallaxX) this._layer.parallaxX = props.parallaxx
|
|
142
|
+
if (props.parallaxY) this._layer.parallaxY = props.parallaxy
|
|
143
|
+
|
|
144
|
+
this.removeChildren()
|
|
145
|
+
|
|
146
|
+
for (let y = 0; y < this._layer.height; y++) {
|
|
147
|
+
for (let x = 0; x < this._layer.width; x++) {
|
|
148
|
+
const tile = this.createTile(x, y)
|
|
149
|
+
if (tile) {
|
|
150
|
+
this._addFrame(tile, x, y)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface CanvasTileLayer extends CompositeTilemap { }
|
|
158
|
+
|
|
159
|
+
registerComponent('CompositeTileLayer', CanvasTileLayer)
|
|
160
|
+
|
|
161
|
+
export function CompositeTileLayer(props) {
|
|
162
|
+
return createComponent('CompositeTileLayer', props)
|
|
163
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { TiledTileset, Tileset as TiledTilesetClass } from "@rpgjs/tiled";
|
|
2
|
+
import { Assets, Rectangle, Texture } from "pixi.js";
|
|
3
|
+
|
|
4
|
+
export class TileSet extends TiledTilesetClass {
|
|
5
|
+
public textures: Texture[] = [];
|
|
6
|
+
private tileGroups = {};
|
|
7
|
+
|
|
8
|
+
constructor(tileSet: TiledTileset) {
|
|
9
|
+
super(tileSet);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
loadGroup() {
|
|
13
|
+
// for (let tile of this.tileset.tiles) {
|
|
14
|
+
// }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** @internal */
|
|
18
|
+
async load(image: string) {
|
|
19
|
+
const texture = await Assets.load(image);
|
|
20
|
+
for (
|
|
21
|
+
let y = this.margin;
|
|
22
|
+
y < this.image.height;
|
|
23
|
+
y += this.tileheight + this.spacing
|
|
24
|
+
) {
|
|
25
|
+
for (
|
|
26
|
+
let x = this.margin;
|
|
27
|
+
x < this.image.width;
|
|
28
|
+
x += this.tilewidth + this.spacing
|
|
29
|
+
) {
|
|
30
|
+
this.textures.push(
|
|
31
|
+
new Texture({
|
|
32
|
+
source: texture.source,
|
|
33
|
+
frame: new Rectangle(+x, +y, +this.tilewidth, +this.tileheight),
|
|
34
|
+
})
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
this.loadGroup();
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { TiledLayer, TiledLayerType, TiledMap, TiledParserFile, TiledTileset } from "@rpgjs/tiled"
|
|
2
|
+
import { effect, signal } from '@signe/reactive'
|
|
3
|
+
import { loop } from "../../engine/reactive"
|
|
4
|
+
import { h } from "../../engine/signal"
|
|
5
|
+
import { useProps } from "../../hooks/useProps"
|
|
6
|
+
import { Container } from "../Container"
|
|
7
|
+
import { TilingSprite } from "../TilingSprite"
|
|
8
|
+
import { CompositeTileLayer } from "./TileLayer"
|
|
9
|
+
import { TileSet } from "./TileSet"
|
|
10
|
+
|
|
11
|
+
export function TiledMap(props) {
|
|
12
|
+
const { map } = useProps(props)
|
|
13
|
+
const layers = signal<TiledLayer[]>([])
|
|
14
|
+
const objectLayer = props.objectLayer
|
|
15
|
+
let tilesets: TiledTileset[] = []
|
|
16
|
+
let mapData: TiledMap = {} as TiledMap
|
|
17
|
+
|
|
18
|
+
const parseTmx = async (file: string, relativePath: string = '') => {
|
|
19
|
+
if (typeof file !== 'string') {
|
|
20
|
+
return file
|
|
21
|
+
}
|
|
22
|
+
// @ts-ignore
|
|
23
|
+
const parser = new TiledParserFile(
|
|
24
|
+
file,
|
|
25
|
+
{
|
|
26
|
+
basePath: '',
|
|
27
|
+
staticDir: '',
|
|
28
|
+
relativePath
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
const data = await parser.parseFilePromise({
|
|
32
|
+
getOnlyBasename: false
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
return data
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
effect(async () => {
|
|
39
|
+
mapData = await parseTmx(map())
|
|
40
|
+
for (let tileSet of mapData.tilesets) {
|
|
41
|
+
tilesets.push(await new TileSet(tileSet).load(tileSet.image.source))
|
|
42
|
+
}
|
|
43
|
+
layers.set(mapData.layers)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const createLayer = (layers, props = {}) => {
|
|
47
|
+
return h(Container, props, loop(layers, (layer) => {
|
|
48
|
+
switch (layer.type) {
|
|
49
|
+
case TiledLayerType.Tile:
|
|
50
|
+
return h(CompositeTileLayer, {
|
|
51
|
+
tilewidth: mapData.tilewidth,
|
|
52
|
+
tileheight: mapData.tileheight,
|
|
53
|
+
// @ts-ignore
|
|
54
|
+
width: mapData.width,
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
height: mapData.height,
|
|
57
|
+
...layer,
|
|
58
|
+
tilesets
|
|
59
|
+
})
|
|
60
|
+
case TiledLayerType.Image:
|
|
61
|
+
const { width, height, source } = layer.image
|
|
62
|
+
return h(TilingSprite, {
|
|
63
|
+
image: source,
|
|
64
|
+
...layer,
|
|
65
|
+
width: layer.repeatx ? layer.width * layer.tilewidth : width,
|
|
66
|
+
height: layer.repeaty ? layer.height * layer.tileheight : height
|
|
67
|
+
})
|
|
68
|
+
case TiledLayerType.Group:
|
|
69
|
+
return createLayer(signal(layer.layers), layer)
|
|
70
|
+
case TiledLayerType.ObjectGroup:
|
|
71
|
+
const child = objectLayer?.(layer)
|
|
72
|
+
return h(Container, layer, child)
|
|
73
|
+
default:
|
|
74
|
+
return h(Container)
|
|
75
|
+
}
|
|
76
|
+
}))
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return createLayer(layers)
|
|
80
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { TilingSprite as PixiTilingSprite, Texture } from 'pixi.js';
|
|
2
|
+
import { createComponent, registerComponent } from '../engine/reactive';
|
|
3
|
+
import { DisplayObject } from './DisplayObject';
|
|
4
|
+
import { DisplayObjectProps } from './types/DisplayObject';
|
|
5
|
+
|
|
6
|
+
interface TilingSpriteProps extends DisplayObjectProps {
|
|
7
|
+
image?: string;
|
|
8
|
+
tileScale?: { x: number; y: number };
|
|
9
|
+
tilePosition?: { x: number; y: number };
|
|
10
|
+
width?: number;
|
|
11
|
+
height?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class CanvasTilingSprite extends DisplayObject(PixiTilingSprite) {
|
|
15
|
+
onUpdate(props: TilingSpriteProps): void {
|
|
16
|
+
super.onUpdate(props);
|
|
17
|
+
if (props.image) {
|
|
18
|
+
this.texture = Texture.from(props.image);
|
|
19
|
+
}
|
|
20
|
+
if (props.tileScale) {
|
|
21
|
+
this.tileScale.set(props.tileScale.x, props.tileScale.y);
|
|
22
|
+
}
|
|
23
|
+
if (props.tilePosition) {
|
|
24
|
+
this.tilePosition.set(props.tilePosition.x, props.tilePosition.y);
|
|
25
|
+
}
|
|
26
|
+
if (props.width !== undefined) {
|
|
27
|
+
this.width = props.width;
|
|
28
|
+
}
|
|
29
|
+
if (props.height !== undefined) {
|
|
30
|
+
this.height = props.height;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
registerComponent('TilingSprite', CanvasTilingSprite)
|
|
36
|
+
|
|
37
|
+
export function TilingSprite(props: TilingSpriteProps) {
|
|
38
|
+
return createComponent('TilingSprite', props)
|
|
39
|
+
}
|