├── .gitignore ├── LICENSE ├── README.MD ├── index.html ├── package-lock.json ├── package.json ├── preview.png ├── public ├── kirby-like.png ├── level-1.json ├── level-1.png ├── level-2.json └── level-2.png ├── src ├── constants.ts ├── entities.ts ├── kaboomCtx.ts ├── main.ts ├── state.ts └── utils.ts ├── tsconfig.json └── vite.config.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 JSLegend 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # Kirby like Platformer Game made with TypeScript + Kaboom.js 2 | 3 | ![game preview](preview.png) 4 | 5 | Live demo : https://jslegend.itch.io/kirby-like-platformer-asset-pack 6 | 7 | Learn how to build this game by following my tutorial : https://www.youtube.com/watch?v=rICeqnbzkZk 8 | 9 | Everything was made by me including the art which you can use in your games. 10 | 11 | 12 | ## How to run the project ? 13 | 14 | Assuming you have `node` installed. 15 | - Install dependencies with `npm install` 16 | - Run locally with `npm run dev` 17 | - Build for production with `npm run build` and a dist folder should appear 18 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kirby-like-ts", 3 | "version": "0.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "kirby-like-ts", 9 | "version": "0.0.0", 10 | "dependencies": { 11 | "kaboom": "^3000.1.17" 12 | }, 13 | "devDependencies": { 14 | "typescript": "^5.2.2", 15 | "vite": "^5.0.8" 16 | } 17 | }, 18 | "node_modules/@esbuild/aix-ppc64": { 19 | "version": "0.19.12", 20 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", 21 | "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", 22 | "cpu": [ 23 | "ppc64" 24 | ], 25 | "dev": true, 26 | "optional": true, 27 | "os": [ 28 | "aix" 29 | ], 30 | "engines": { 31 | "node": ">=12" 32 | } 33 | }, 34 | "node_modules/@esbuild/android-arm": { 35 | "version": "0.19.12", 36 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", 37 | "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", 38 | "cpu": [ 39 | "arm" 40 | ], 41 | "dev": true, 42 | "optional": true, 43 | "os": [ 44 | "android" 45 | ], 46 | "engines": { 47 | "node": ">=12" 48 | } 49 | }, 50 | "node_modules/@esbuild/android-arm64": { 51 | "version": "0.19.12", 52 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", 53 | "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", 54 | "cpu": [ 55 | "arm64" 56 | ], 57 | "dev": true, 58 | "optional": true, 59 | "os": [ 60 | "android" 61 | ], 62 | "engines": { 63 | "node": ">=12" 64 | } 65 | }, 66 | "node_modules/@esbuild/android-x64": { 67 | "version": "0.19.12", 68 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", 69 | "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", 70 | "cpu": [ 71 | "x64" 72 | ], 73 | "dev": true, 74 | "optional": true, 75 | "os": [ 76 | "android" 77 | ], 78 | "engines": { 79 | "node": ">=12" 80 | } 81 | }, 82 | "node_modules/@esbuild/darwin-arm64": { 83 | "version": "0.19.12", 84 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", 85 | "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", 86 | "cpu": [ 87 | "arm64" 88 | ], 89 | "dev": true, 90 | "optional": true, 91 | "os": [ 92 | "darwin" 93 | ], 94 | "engines": { 95 | "node": ">=12" 96 | } 97 | }, 98 | "node_modules/@esbuild/darwin-x64": { 99 | "version": "0.19.12", 100 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", 101 | "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", 102 | "cpu": [ 103 | "x64" 104 | ], 105 | "dev": true, 106 | "optional": true, 107 | "os": [ 108 | "darwin" 109 | ], 110 | "engines": { 111 | "node": ">=12" 112 | } 113 | }, 114 | "node_modules/@esbuild/freebsd-arm64": { 115 | "version": "0.19.12", 116 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", 117 | "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", 118 | "cpu": [ 119 | "arm64" 120 | ], 121 | "dev": true, 122 | "optional": true, 123 | "os": [ 124 | "freebsd" 125 | ], 126 | "engines": { 127 | "node": ">=12" 128 | } 129 | }, 130 | "node_modules/@esbuild/freebsd-x64": { 131 | "version": "0.19.12", 132 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", 133 | "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", 134 | "cpu": [ 135 | "x64" 136 | ], 137 | "dev": true, 138 | "optional": true, 139 | "os": [ 140 | "freebsd" 141 | ], 142 | "engines": { 143 | "node": ">=12" 144 | } 145 | }, 146 | "node_modules/@esbuild/linux-arm": { 147 | "version": "0.19.12", 148 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", 149 | "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", 150 | "cpu": [ 151 | "arm" 152 | ], 153 | "dev": true, 154 | "optional": true, 155 | "os": [ 156 | "linux" 157 | ], 158 | "engines": { 159 | "node": ">=12" 160 | } 161 | }, 162 | "node_modules/@esbuild/linux-arm64": { 163 | "version": "0.19.12", 164 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", 165 | "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", 166 | "cpu": [ 167 | "arm64" 168 | ], 169 | "dev": true, 170 | "optional": true, 171 | "os": [ 172 | "linux" 173 | ], 174 | "engines": { 175 | "node": ">=12" 176 | } 177 | }, 178 | "node_modules/@esbuild/linux-ia32": { 179 | "version": "0.19.12", 180 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", 181 | "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", 182 | "cpu": [ 183 | "ia32" 184 | ], 185 | "dev": true, 186 | "optional": true, 187 | "os": [ 188 | "linux" 189 | ], 190 | "engines": { 191 | "node": ">=12" 192 | } 193 | }, 194 | "node_modules/@esbuild/linux-loong64": { 195 | "version": "0.19.12", 196 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", 197 | "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", 198 | "cpu": [ 199 | "loong64" 200 | ], 201 | "dev": true, 202 | "optional": true, 203 | "os": [ 204 | "linux" 205 | ], 206 | "engines": { 207 | "node": ">=12" 208 | } 209 | }, 210 | "node_modules/@esbuild/linux-mips64el": { 211 | "version": "0.19.12", 212 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", 213 | "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", 214 | "cpu": [ 215 | "mips64el" 216 | ], 217 | "dev": true, 218 | "optional": true, 219 | "os": [ 220 | "linux" 221 | ], 222 | "engines": { 223 | "node": ">=12" 224 | } 225 | }, 226 | "node_modules/@esbuild/linux-ppc64": { 227 | "version": "0.19.12", 228 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", 229 | "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", 230 | "cpu": [ 231 | "ppc64" 232 | ], 233 | "dev": true, 234 | "optional": true, 235 | "os": [ 236 | "linux" 237 | ], 238 | "engines": { 239 | "node": ">=12" 240 | } 241 | }, 242 | "node_modules/@esbuild/linux-riscv64": { 243 | "version": "0.19.12", 244 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", 245 | "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", 246 | "cpu": [ 247 | "riscv64" 248 | ], 249 | "dev": true, 250 | "optional": true, 251 | "os": [ 252 | "linux" 253 | ], 254 | "engines": { 255 | "node": ">=12" 256 | } 257 | }, 258 | "node_modules/@esbuild/linux-s390x": { 259 | "version": "0.19.12", 260 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", 261 | "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", 262 | "cpu": [ 263 | "s390x" 264 | ], 265 | "dev": true, 266 | "optional": true, 267 | "os": [ 268 | "linux" 269 | ], 270 | "engines": { 271 | "node": ">=12" 272 | } 273 | }, 274 | "node_modules/@esbuild/linux-x64": { 275 | "version": "0.19.12", 276 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", 277 | "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", 278 | "cpu": [ 279 | "x64" 280 | ], 281 | "dev": true, 282 | "optional": true, 283 | "os": [ 284 | "linux" 285 | ], 286 | "engines": { 287 | "node": ">=12" 288 | } 289 | }, 290 | "node_modules/@esbuild/netbsd-x64": { 291 | "version": "0.19.12", 292 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", 293 | "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", 294 | "cpu": [ 295 | "x64" 296 | ], 297 | "dev": true, 298 | "optional": true, 299 | "os": [ 300 | "netbsd" 301 | ], 302 | "engines": { 303 | "node": ">=12" 304 | } 305 | }, 306 | "node_modules/@esbuild/openbsd-x64": { 307 | "version": "0.19.12", 308 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", 309 | "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", 310 | "cpu": [ 311 | "x64" 312 | ], 313 | "dev": true, 314 | "optional": true, 315 | "os": [ 316 | "openbsd" 317 | ], 318 | "engines": { 319 | "node": ">=12" 320 | } 321 | }, 322 | "node_modules/@esbuild/sunos-x64": { 323 | "version": "0.19.12", 324 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", 325 | "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", 326 | "cpu": [ 327 | "x64" 328 | ], 329 | "dev": true, 330 | "optional": true, 331 | "os": [ 332 | "sunos" 333 | ], 334 | "engines": { 335 | "node": ">=12" 336 | } 337 | }, 338 | "node_modules/@esbuild/win32-arm64": { 339 | "version": "0.19.12", 340 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", 341 | "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", 342 | "cpu": [ 343 | "arm64" 344 | ], 345 | "dev": true, 346 | "optional": true, 347 | "os": [ 348 | "win32" 349 | ], 350 | "engines": { 351 | "node": ">=12" 352 | } 353 | }, 354 | "node_modules/@esbuild/win32-ia32": { 355 | "version": "0.19.12", 356 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", 357 | "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", 358 | "cpu": [ 359 | "ia32" 360 | ], 361 | "dev": true, 362 | "optional": true, 363 | "os": [ 364 | "win32" 365 | ], 366 | "engines": { 367 | "node": ">=12" 368 | } 369 | }, 370 | "node_modules/@esbuild/win32-x64": { 371 | "version": "0.19.12", 372 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", 373 | "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", 374 | "cpu": [ 375 | "x64" 376 | ], 377 | "dev": true, 378 | "optional": true, 379 | "os": [ 380 | "win32" 381 | ], 382 | "engines": { 383 | "node": ">=12" 384 | } 385 | }, 386 | "node_modules/@rollup/rollup-android-arm-eabi": { 387 | "version": "4.9.6", 388 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz", 389 | "integrity": "sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==", 390 | "cpu": [ 391 | "arm" 392 | ], 393 | "dev": true, 394 | "optional": true, 395 | "os": [ 396 | "android" 397 | ] 398 | }, 399 | "node_modules/@rollup/rollup-android-arm64": { 400 | "version": "4.9.6", 401 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.6.tgz", 402 | "integrity": "sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw==", 403 | "cpu": [ 404 | "arm64" 405 | ], 406 | "dev": true, 407 | "optional": true, 408 | "os": [ 409 | "android" 410 | ] 411 | }, 412 | "node_modules/@rollup/rollup-darwin-arm64": { 413 | "version": "4.9.6", 414 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.6.tgz", 415 | "integrity": "sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw==", 416 | "cpu": [ 417 | "arm64" 418 | ], 419 | "dev": true, 420 | "optional": true, 421 | "os": [ 422 | "darwin" 423 | ] 424 | }, 425 | "node_modules/@rollup/rollup-darwin-x64": { 426 | "version": "4.9.6", 427 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz", 428 | "integrity": "sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==", 429 | "cpu": [ 430 | "x64" 431 | ], 432 | "dev": true, 433 | "optional": true, 434 | "os": [ 435 | "darwin" 436 | ] 437 | }, 438 | "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 439 | "version": "4.9.6", 440 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.6.tgz", 441 | "integrity": "sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ==", 442 | "cpu": [ 443 | "arm" 444 | ], 445 | "dev": true, 446 | "optional": true, 447 | "os": [ 448 | "linux" 449 | ] 450 | }, 451 | "node_modules/@rollup/rollup-linux-arm64-gnu": { 452 | "version": "4.9.6", 453 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.6.tgz", 454 | "integrity": "sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ==", 455 | "cpu": [ 456 | "arm64" 457 | ], 458 | "dev": true, 459 | "optional": true, 460 | "os": [ 461 | "linux" 462 | ] 463 | }, 464 | "node_modules/@rollup/rollup-linux-arm64-musl": { 465 | "version": "4.9.6", 466 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.6.tgz", 467 | "integrity": "sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ==", 468 | "cpu": [ 469 | "arm64" 470 | ], 471 | "dev": true, 472 | "optional": true, 473 | "os": [ 474 | "linux" 475 | ] 476 | }, 477 | "node_modules/@rollup/rollup-linux-riscv64-gnu": { 478 | "version": "4.9.6", 479 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.6.tgz", 480 | "integrity": "sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA==", 481 | "cpu": [ 482 | "riscv64" 483 | ], 484 | "dev": true, 485 | "optional": true, 486 | "os": [ 487 | "linux" 488 | ] 489 | }, 490 | "node_modules/@rollup/rollup-linux-x64-gnu": { 491 | "version": "4.9.6", 492 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.6.tgz", 493 | "integrity": "sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw==", 494 | "cpu": [ 495 | "x64" 496 | ], 497 | "dev": true, 498 | "optional": true, 499 | "os": [ 500 | "linux" 501 | ] 502 | }, 503 | "node_modules/@rollup/rollup-linux-x64-musl": { 504 | "version": "4.9.6", 505 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.6.tgz", 506 | "integrity": "sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ==", 507 | "cpu": [ 508 | "x64" 509 | ], 510 | "dev": true, 511 | "optional": true, 512 | "os": [ 513 | "linux" 514 | ] 515 | }, 516 | "node_modules/@rollup/rollup-win32-arm64-msvc": { 517 | "version": "4.9.6", 518 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.6.tgz", 519 | "integrity": "sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA==", 520 | "cpu": [ 521 | "arm64" 522 | ], 523 | "dev": true, 524 | "optional": true, 525 | "os": [ 526 | "win32" 527 | ] 528 | }, 529 | "node_modules/@rollup/rollup-win32-ia32-msvc": { 530 | "version": "4.9.6", 531 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.6.tgz", 532 | "integrity": "sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ==", 533 | "cpu": [ 534 | "ia32" 535 | ], 536 | "dev": true, 537 | "optional": true, 538 | "os": [ 539 | "win32" 540 | ] 541 | }, 542 | "node_modules/@rollup/rollup-win32-x64-msvc": { 543 | "version": "4.9.6", 544 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.6.tgz", 545 | "integrity": "sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ==", 546 | "cpu": [ 547 | "x64" 548 | ], 549 | "dev": true, 550 | "optional": true, 551 | "os": [ 552 | "win32" 553 | ] 554 | }, 555 | "node_modules/@types/estree": { 556 | "version": "1.0.5", 557 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", 558 | "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", 559 | "dev": true 560 | }, 561 | "node_modules/esbuild": { 562 | "version": "0.19.12", 563 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", 564 | "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", 565 | "dev": true, 566 | "hasInstallScript": true, 567 | "bin": { 568 | "esbuild": "bin/esbuild" 569 | }, 570 | "engines": { 571 | "node": ">=12" 572 | }, 573 | "optionalDependencies": { 574 | "@esbuild/aix-ppc64": "0.19.12", 575 | "@esbuild/android-arm": "0.19.12", 576 | "@esbuild/android-arm64": "0.19.12", 577 | "@esbuild/android-x64": "0.19.12", 578 | "@esbuild/darwin-arm64": "0.19.12", 579 | "@esbuild/darwin-x64": "0.19.12", 580 | "@esbuild/freebsd-arm64": "0.19.12", 581 | "@esbuild/freebsd-x64": "0.19.12", 582 | "@esbuild/linux-arm": "0.19.12", 583 | "@esbuild/linux-arm64": "0.19.12", 584 | "@esbuild/linux-ia32": "0.19.12", 585 | "@esbuild/linux-loong64": "0.19.12", 586 | "@esbuild/linux-mips64el": "0.19.12", 587 | "@esbuild/linux-ppc64": "0.19.12", 588 | "@esbuild/linux-riscv64": "0.19.12", 589 | "@esbuild/linux-s390x": "0.19.12", 590 | "@esbuild/linux-x64": "0.19.12", 591 | "@esbuild/netbsd-x64": "0.19.12", 592 | "@esbuild/openbsd-x64": "0.19.12", 593 | "@esbuild/sunos-x64": "0.19.12", 594 | "@esbuild/win32-arm64": "0.19.12", 595 | "@esbuild/win32-ia32": "0.19.12", 596 | "@esbuild/win32-x64": "0.19.12" 597 | } 598 | }, 599 | "node_modules/fsevents": { 600 | "version": "2.3.3", 601 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 602 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 603 | "dev": true, 604 | "hasInstallScript": true, 605 | "optional": true, 606 | "os": [ 607 | "darwin" 608 | ], 609 | "engines": { 610 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 611 | } 612 | }, 613 | "node_modules/kaboom": { 614 | "version": "3000.1.17", 615 | "resolved": "https://registry.npmjs.org/kaboom/-/kaboom-3000.1.17.tgz", 616 | "integrity": "sha512-npAtjGxj9Oj9vLpXfURck9eUPHR2ac1Lhc1bNcZ0NWcs+Lgs40Ty+wjujv1C2DwjWvxaX+3r2G64M35BS/Ry2g==" 617 | }, 618 | "node_modules/nanoid": { 619 | "version": "3.3.7", 620 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", 621 | "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", 622 | "dev": true, 623 | "funding": [ 624 | { 625 | "type": "github", 626 | "url": "https://github.com/sponsors/ai" 627 | } 628 | ], 629 | "bin": { 630 | "nanoid": "bin/nanoid.cjs" 631 | }, 632 | "engines": { 633 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 634 | } 635 | }, 636 | "node_modules/picocolors": { 637 | "version": "1.0.0", 638 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 639 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 640 | "dev": true 641 | }, 642 | "node_modules/postcss": { 643 | "version": "8.4.33", 644 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", 645 | "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", 646 | "dev": true, 647 | "funding": [ 648 | { 649 | "type": "opencollective", 650 | "url": "https://opencollective.com/postcss/" 651 | }, 652 | { 653 | "type": "tidelift", 654 | "url": "https://tidelift.com/funding/github/npm/postcss" 655 | }, 656 | { 657 | "type": "github", 658 | "url": "https://github.com/sponsors/ai" 659 | } 660 | ], 661 | "dependencies": { 662 | "nanoid": "^3.3.7", 663 | "picocolors": "^1.0.0", 664 | "source-map-js": "^1.0.2" 665 | }, 666 | "engines": { 667 | "node": "^10 || ^12 || >=14" 668 | } 669 | }, 670 | "node_modules/rollup": { 671 | "version": "4.9.6", 672 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.6.tgz", 673 | "integrity": "sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==", 674 | "dev": true, 675 | "dependencies": { 676 | "@types/estree": "1.0.5" 677 | }, 678 | "bin": { 679 | "rollup": "dist/bin/rollup" 680 | }, 681 | "engines": { 682 | "node": ">=18.0.0", 683 | "npm": ">=8.0.0" 684 | }, 685 | "optionalDependencies": { 686 | "@rollup/rollup-android-arm-eabi": "4.9.6", 687 | "@rollup/rollup-android-arm64": "4.9.6", 688 | "@rollup/rollup-darwin-arm64": "4.9.6", 689 | "@rollup/rollup-darwin-x64": "4.9.6", 690 | "@rollup/rollup-linux-arm-gnueabihf": "4.9.6", 691 | "@rollup/rollup-linux-arm64-gnu": "4.9.6", 692 | "@rollup/rollup-linux-arm64-musl": "4.9.6", 693 | "@rollup/rollup-linux-riscv64-gnu": "4.9.6", 694 | "@rollup/rollup-linux-x64-gnu": "4.9.6", 695 | "@rollup/rollup-linux-x64-musl": "4.9.6", 696 | "@rollup/rollup-win32-arm64-msvc": "4.9.6", 697 | "@rollup/rollup-win32-ia32-msvc": "4.9.6", 698 | "@rollup/rollup-win32-x64-msvc": "4.9.6", 699 | "fsevents": "~2.3.2" 700 | } 701 | }, 702 | "node_modules/source-map-js": { 703 | "version": "1.0.2", 704 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 705 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 706 | "dev": true, 707 | "engines": { 708 | "node": ">=0.10.0" 709 | } 710 | }, 711 | "node_modules/typescript": { 712 | "version": "5.3.3", 713 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", 714 | "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", 715 | "dev": true, 716 | "bin": { 717 | "tsc": "bin/tsc", 718 | "tsserver": "bin/tsserver" 719 | }, 720 | "engines": { 721 | "node": ">=14.17" 722 | } 723 | }, 724 | "node_modules/vite": { 725 | "version": "5.0.12", 726 | "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.12.tgz", 727 | "integrity": "sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==", 728 | "dev": true, 729 | "dependencies": { 730 | "esbuild": "^0.19.3", 731 | "postcss": "^8.4.32", 732 | "rollup": "^4.2.0" 733 | }, 734 | "bin": { 735 | "vite": "bin/vite.js" 736 | }, 737 | "engines": { 738 | "node": "^18.0.0 || >=20.0.0" 739 | }, 740 | "funding": { 741 | "url": "https://github.com/vitejs/vite?sponsor=1" 742 | }, 743 | "optionalDependencies": { 744 | "fsevents": "~2.3.3" 745 | }, 746 | "peerDependencies": { 747 | "@types/node": "^18.0.0 || >=20.0.0", 748 | "less": "*", 749 | "lightningcss": "^1.21.0", 750 | "sass": "*", 751 | "stylus": "*", 752 | "sugarss": "*", 753 | "terser": "^5.4.0" 754 | }, 755 | "peerDependenciesMeta": { 756 | "@types/node": { 757 | "optional": true 758 | }, 759 | "less": { 760 | "optional": true 761 | }, 762 | "lightningcss": { 763 | "optional": true 764 | }, 765 | "sass": { 766 | "optional": true 767 | }, 768 | "stylus": { 769 | "optional": true 770 | }, 771 | "sugarss": { 772 | "optional": true 773 | }, 774 | "terser": { 775 | "optional": true 776 | } 777 | } 778 | } 779 | } 780 | } 781 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kirby-like-ts", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "typescript": "^5.2.2", 13 | "vite": "^5.0.8" 14 | }, 15 | "dependencies": { 16 | "kaboom": "^3000.1.17" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSLegendDev/Kirby-like-ts/cdcac97bf5aaa76a1b8ee6cee08fd417468471f6/preview.png -------------------------------------------------------------------------------- /public/kirby-like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSLegendDev/Kirby-like-ts/cdcac97bf5aaa76a1b8ee6cee08fd417468471f6/public/kirby-like.png -------------------------------------------------------------------------------- /public/level-1.json: -------------------------------------------------------------------------------- 1 | { "compressionlevel":-1, 2 | "height":20, 3 | "infinite":false, 4 | "layers":[ 5 | { 6 | "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12 | 0, 0, 0, 0, 0, 0, 0, 64, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13 | 0, 0, 0, 0, 0, 0, 0, 73, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14 | 0, 0, 0, 0, 0, 0, 0, 82, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15 | 0, 0, 0, 0, 0, 0, 0, 82, 83, 0, 64, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16 | 0, 0, 0, 0, 0, 0, 0, 82, 83, 0, 73, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17 | 0, 0, 64, 65, 0, 0, 0, 82, 83, 53, 82, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18 | 0, 0, 73, 74, 0, 0, 53, 82, 83, 62, 82, 83, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19 | 0, 0, 82, 83, 0, 0, 62, 82, 83, 62, 82, 83, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20 | 0, 0, 82, 83, 0, 0, 62, 82, 83, 62, 82, 83, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21 | 0, 0, 82, 83, 0, 0, 62, 82, 83, 62, 82, 83, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22 | 0, 0, 82, 83, 0, 0, 62, 82, 83, 62, 82, 83, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23 | 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24 | 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 63, 63, 63, 63, 63, 25 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 26 | "height":20, 27 | "id":2, 28 | "name":"background", 29 | "opacity":1, 30 | "type":"tilelayer", 31 | "visible":true, 32 | "width":27, 33 | "x":0, 34 | "y":0 35 | }, 36 | { 37 | "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43 | 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44 | 0, 0, 0, 55, 56, 57, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 45 | 0, 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0, 46 | 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47 | 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 48 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 49 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 57 | "height":20, 58 | "id":3, 59 | "name":"clouds", 60 | "opacity":1, 61 | "type":"tilelayer", 62 | "visible":true, 63 | "width":27, 64 | "x":0, 65 | "y":0 66 | }, 67 | { 68 | "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81 | 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 82 | 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 58, 66, 0, 0, 0, 70, 58, 0, 0, 0, 0, 0, 0, 83 | 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 58, 75, 67, 68, 69, 79, 58, 0, 0, 0, 0, 0, 0, 84 | 0, 40, 71, 40, 0, 58, 0, 40, 40, 40, 0, 40, 40, 0, 58, 0, 76, 77, 78, 0, 58, 0, 0, 0, 0, 0, 0, 85 | 50, 51, 51, 51, 51, 61, 0, 50, 51, 51, 51, 51, 52, 0, 59, 51, 51, 51, 51, 51, 61, 0, 0, 0, 0, 0, 0, 86 | 59, 60, 60, 60, 60, 61, 0, 59, 60, 60, 60, 60, 61, 0, 59, 60, 60, 60, 60, 60, 61, 0, 0, 0, 0, 0, 0, 87 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 88 | "height":20, 89 | "id":1, 90 | "name":"platforms", 91 | "opacity":1, 92 | "type":"tilelayer", 93 | "visible":true, 94 | "width":27, 95 | "x":0, 96 | "y":0 97 | }, 98 | { 99 | "draworder":"topdown", 100 | "id":4, 101 | "name":"colliders", 102 | "objects":[ 103 | { 104 | "height":32, 105 | "id":1, 106 | "name":"", 107 | "rotation":0, 108 | "type":"", 109 | "visible":true, 110 | "width":80, 111 | "x":0, 112 | "y":272 113 | }, 114 | { 115 | "height":96, 116 | "id":2, 117 | "name":"", 118 | "rotation":0, 119 | "type":"", 120 | "visible":true, 121 | "width":16, 122 | "x":80, 123 | "y":208 124 | }, 125 | { 126 | "height":32, 127 | "id":3, 128 | "name":"", 129 | "rotation":0, 130 | "type":"", 131 | "visible":true, 132 | "width":96, 133 | "x":112, 134 | "y":272 135 | }, 136 | { 137 | "height":96, 138 | "id":4, 139 | "name":"", 140 | "rotation":0, 141 | "type":"", 142 | "visible":true, 143 | "width":16, 144 | "x":224, 145 | "y":208 146 | }, 147 | { 148 | "height":32, 149 | "id":5, 150 | "name":"", 151 | "rotation":0, 152 | "type":"", 153 | "visible":true, 154 | "width":80, 155 | "x":240, 156 | "y":272 157 | }, 158 | { 159 | "height":96, 160 | "id":6, 161 | "name":"", 162 | "rotation":0, 163 | "type":"", 164 | "visible":true, 165 | "width":16, 166 | "x":320, 167 | "y":208 168 | }, 169 | { 170 | "height":16, 171 | "id":19, 172 | "name":"exit", 173 | "rotation":0, 174 | "type":"", 175 | "visible":true, 176 | "width":16, 177 | "x":272, 178 | "y":256 179 | }], 180 | "opacity":1, 181 | "type":"objectgroup", 182 | "visible":false, 183 | "x":0, 184 | "y":0 185 | }, 186 | { 187 | "draworder":"topdown", 188 | "id":6, 189 | "name":"spawnpoints", 190 | "objects":[ 191 | { 192 | "height":0, 193 | "id":7, 194 | "name":"player", 195 | "point":true, 196 | "rotation":0, 197 | "type":"", 198 | "visible":true, 199 | "width":0, 200 | "x":16, 201 | "y":256 202 | }, 203 | { 204 | "height":0, 205 | "id":8, 206 | "name":"flame", 207 | "point":true, 208 | "rotation":0, 209 | "type":"", 210 | "visible":true, 211 | "width":0, 212 | "x":80, 213 | "y":192 214 | }, 215 | { 216 | "height":0, 217 | "id":11, 218 | "name":"flame", 219 | "point":true, 220 | "rotation":0, 221 | "type":"", 222 | "visible":true, 223 | "width":0, 224 | "x":224, 225 | "y":192 226 | }, 227 | { 228 | "height":0, 229 | "id":14, 230 | "name":"flame", 231 | "point":true, 232 | "rotation":0, 233 | "type":"", 234 | "visible":true, 235 | "width":0, 236 | "x":320, 237 | "y":192 238 | }, 239 | { 240 | "height":0, 241 | "id":16, 242 | "name":"bird", 243 | "point":true, 244 | "rotation":0, 245 | "type":"", 246 | "visible":true, 247 | "width":0, 248 | "x":400, 249 | "y":128 250 | }, 251 | { 252 | "height":0, 253 | "id":17, 254 | "name":"bird", 255 | "point":true, 256 | "rotation":0, 257 | "type":"", 258 | "visible":true, 259 | "width":0, 260 | "x":432, 261 | "y":144 262 | }, 263 | { 264 | "height":0, 265 | "id":20, 266 | "name":"guy", 267 | "point":true, 268 | "rotation":0, 269 | "type":"", 270 | "visible":true, 271 | "width":0, 272 | "x":160, 273 | "y":256 274 | }], 275 | "opacity":1, 276 | "type":"objectgroup", 277 | "visible":false, 278 | "x":0, 279 | "y":0 280 | }], 281 | "nextlayerid":7, 282 | "nextobjectid":23, 283 | "orientation":"orthogonal", 284 | "renderorder":"right-down", 285 | "tiledversion":"1.10.2", 286 | "tileheight":16, 287 | "tilesets":[ 288 | { 289 | "columns":9, 290 | "firstgid":1, 291 | "image":"kirby-like.png", 292 | "imageheight":160, 293 | "imagewidth":144, 294 | "margin":0, 295 | "name":"kirby-like", 296 | "spacing":0, 297 | "tilecount":90, 298 | "tileheight":16, 299 | "tilewidth":16 300 | }], 301 | "tilewidth":16, 302 | "type":"map", 303 | "version":"1.10", 304 | "width":27 305 | } -------------------------------------------------------------------------------- /public/level-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSLegendDev/Kirby-like-ts/cdcac97bf5aaa76a1b8ee6cee08fd417468471f6/public/level-1.png -------------------------------------------------------------------------------- /public/level-2.json: -------------------------------------------------------------------------------- 1 | { "compressionlevel":-1, 2 | "height":20, 3 | "infinite":false, 4 | "layers":[ 5 | { 6 | "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13 | 0, 0, 0, 0, 0, 0, 64, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 65, 0, 0, 0, 0, 0, 0, 0, 0, 14 | 0, 0, 0, 0, 0, 0, 73, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 74, 64, 65, 0, 0, 0, 0, 0, 0, 15 | 0, 0, 0, 0, 0, 0, 82, 83, 0, 0, 64, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 65, 82, 83, 73, 74, 0, 0, 0, 0, 0, 0, 16 | 0, 0, 0, 0, 0, 0, 82, 83, 0, 0, 73, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 74, 82, 83, 82, 83, 64, 65, 0, 0, 0, 0, 17 | 0, 0, 0, 0, 0, 0, 82, 83, 0, 0, 82, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 65, 82, 83, 82, 83, 82, 83, 73, 74, 0, 0, 0, 0, 18 | 0, 0, 0, 0, 0, 0, 82, 83, 0, 0, 82, 83, 53, 0, 0, 0, 0, 0, 0, 0, 0, 62, 53, 0, 0, 0, 0, 53, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 74, 82, 83, 82, 83, 82, 83, 82, 83, 64, 65, 0, 0, 19 | 0, 0, 0, 0, 0, 0, 82, 83, 53, 0, 82, 83, 62, 0, 0, 0, 0, 0, 0, 0, 0, 62, 62, 0, 0, 0, 0, 62, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 83, 82, 83, 82, 83, 82, 83, 82, 83, 73, 74, 0, 0, 20 | 0, 64, 65, 0, 0, 0, 82, 83, 62, 0, 82, 83, 62, 0, 0, 0, 0, 0, 0, 0, 0, 62, 62, 0, 0, 0, 0, 62, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 83, 82, 83, 82, 83, 82, 83, 82, 83, 82, 83, 0, 0, 21 | 0, 73, 74, 0, 0, 53, 82, 83, 62, 0, 82, 83, 62, 0, 0, 0, 0, 0, 0, 0, 0, 62, 62, 0, 0, 0, 0, 62, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 82, 83, 82, 83, 82, 83, 82, 83, 82, 83, 82, 83, 0, 0, 22 | 0, 82, 83, 53, 0, 62, 82, 83, 62, 0, 82, 83, 62, 0, 0, 0, 0, 0, 0, 0, 0, 62, 62, 0, 0, 0, 0, 62, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 62, 82, 83, 82, 83, 82, 83, 82, 83, 82, 83, 82, 83, 53, 0, 23 | 0, 82, 83, 62, 0, 62, 82, 83, 62, 0, 82, 83, 62, 0, 0, 0, 0, 0, 0, 0, 0, 62, 62, 0, 0, 0, 0, 62, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 62, 82, 83, 82, 83, 82, 83, 82, 83, 82, 83, 82, 83, 62, 0, 24 | 0, 82, 83, 62, 0, 62, 82, 83, 62, 0, 82, 83, 62, 0, 0, 0, 0, 0, 0, 0, 0, 62, 62, 0, 0, 0, 0, 62, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 62, 82, 83, 82, 83, 82, 83, 82, 83, 82, 83, 82, 83, 62, 0, 25 | 63, 82, 83, 62, 63, 62, 82, 83, 62, 0, 82, 83, 62, 0, 0, 63, 63, 0, 0, 0, 0, 62, 62, 0, 0, 0, 0, 62, 62, 0, 0, 0, 0, 63, 63, 63, 63, 63, 62, 62, 82, 83, 82, 83, 82, 83, 82, 83, 82, 83, 82, 83, 62, 63], 26 | "height":20, 27 | "id":2, 28 | "name":"background", 29 | "opacity":1, 30 | "type":"tilelayer", 31 | "visible":true, 32 | "width":54, 33 | "x":0, 34 | "y":0 35 | }, 36 | { 37 | "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39 | 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 40 | 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 41 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42 | 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43 | 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 44 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 45 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46 | 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47 | 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 50 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 51 | 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52 | 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54 | 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55 | 0, 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 57 | "height":20, 58 | "id":3, 59 | "name":"clouds", 60 | "opacity":1, 61 | "type":"tilelayer", 62 | "visible":true, 63 | "width":54, 64 | "x":0, 65 | "y":0 66 | }, 67 | { 68 | "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 41, 42, 42, 43, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 67, 68, 69, 70, 0, 0, 76 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 42, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 76, 77, 78, 79, 0, 0, 77 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 85, 86, 87, 88, 0, 0, 78 | 0, 50, 51, 51, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79 | 0, 59, 60, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 50, 51, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80 | 0, 41, 42, 42, 42, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 42, 43, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 51, 51, 51, 51, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 50, 51, 51, 52, 0, 0, 0, 0, 41, 42, 42, 42, 42, 42, 42, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 51, 52, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85 | 0, 0, 0, 0, 0, 0, 0, 50, 51, 51, 51, 51, 51, 51, 52, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86 | 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 60, 60, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87 | 0, 0, 0, 0, 0, 0, 0, 59, 60, 60, 60, 60, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 59, 60, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 88 | "height":20, 89 | "id":1, 90 | "name":"platforms", 91 | "opacity":1, 92 | "type":"tilelayer", 93 | "visible":true, 94 | "width":54, 95 | "x":0, 96 | "y":0 97 | }, 98 | { 99 | "draworder":"topdown", 100 | "id":4, 101 | "name":"colliders", 102 | "objects":[ 103 | { 104 | "height":48, 105 | "id":1, 106 | "name":"", 107 | "rotation":0, 108 | "type":"", 109 | "visible":true, 110 | "width":80, 111 | "x":16, 112 | "y":160 113 | }, 114 | { 115 | "height":48, 116 | "id":3, 117 | "name":"", 118 | "rotation":0, 119 | "type":"", 120 | "visible":true, 121 | "width":128, 122 | "x":112, 123 | "y":272 124 | }, 125 | { 126 | "height":208, 127 | "id":6, 128 | "name":"", 129 | "rotation":0, 130 | "type":"", 131 | "visible":true, 132 | "width":64, 133 | "x":272, 134 | "y":0 135 | }, 136 | { 137 | "height":16, 138 | "id":19, 139 | "name":"exit", 140 | "rotation":0, 141 | "type":"", 142 | "visible":true, 143 | "width":16, 144 | "x":784, 145 | "y":128 146 | }, 147 | { 148 | "height":64, 149 | "id":28, 150 | "name":"", 151 | "rotation":0, 152 | "type":"", 153 | "visible":true, 154 | "width":64, 155 | "x":272, 156 | "y":256 157 | }, 158 | { 159 | "height":112, 160 | "id":29, 161 | "name":"", 162 | "rotation":0, 163 | "type":"", 164 | "visible":true, 165 | "width":64, 166 | "x":368, 167 | "y":0 168 | }, 169 | { 170 | "height":144, 171 | "id":30, 172 | "name":"", 173 | "rotation":0, 174 | "type":"", 175 | "visible":true, 176 | "width":64, 177 | "x":368, 178 | "y":176 179 | }, 180 | { 181 | "height":144, 182 | "id":31, 183 | "name":"", 184 | "rotation":0, 185 | "type":"", 186 | "visible":true, 187 | "width":64, 188 | "x":464, 189 | "y":0 190 | }, 191 | { 192 | "height":112, 193 | "id":32, 194 | "name":"", 195 | "rotation":0, 196 | "type":"", 197 | "visible":true, 198 | "width":64, 199 | "x":464, 200 | "y":208 201 | }, 202 | { 203 | "height":32, 204 | "id":33, 205 | "name":"", 206 | "rotation":0, 207 | "type":"", 208 | "visible":true, 209 | "width":128, 210 | "x":592, 211 | "y":192 212 | }, 213 | { 214 | "height":16, 215 | "id":40, 216 | "name":"", 217 | "rotation":0, 218 | "type":"", 219 | "visible":true, 220 | "width":48, 221 | "x":768, 222 | "y":144 223 | }], 224 | "opacity":1, 225 | "type":"objectgroup", 226 | "visible":false, 227 | "x":0, 228 | "y":0 229 | }, 230 | { 231 | "draworder":"topdown", 232 | "id":6, 233 | "name":"spawnpoints", 234 | "objects":[ 235 | { 236 | "height":0, 237 | "id":7, 238 | "name":"player", 239 | "point":true, 240 | "rotation":0, 241 | "type":"", 242 | "visible":true, 243 | "width":0, 244 | "x":48, 245 | "y":128 246 | }, 247 | { 248 | "height":0, 249 | "id":8, 250 | "name":"flame", 251 | "point":true, 252 | "rotation":0, 253 | "type":"", 254 | "visible":true, 255 | "width":0, 256 | "x":304, 257 | "y":240 258 | }, 259 | { 260 | "height":0, 261 | "id":11, 262 | "name":"flame", 263 | "point":true, 264 | "rotation":0, 265 | "type":"", 266 | "visible":true, 267 | "width":0, 268 | "x":272, 269 | "y":240 270 | }, 271 | { 272 | "height":0, 273 | "id":14, 274 | "name":"flame", 275 | "point":true, 276 | "rotation":0, 277 | "type":"", 278 | "visible":true, 279 | "width":0, 280 | "x":368, 281 | "y":160 282 | }, 283 | { 284 | "height":0, 285 | "id":16, 286 | "name":"bird", 287 | "point":true, 288 | "rotation":0, 289 | "type":"", 290 | "visible":true, 291 | "width":0, 292 | "x":864, 293 | "y":144 294 | }, 295 | { 296 | "height":0, 297 | "id":17, 298 | "name":"bird", 299 | "point":true, 300 | "rotation":0, 301 | "type":"", 302 | "visible":true, 303 | "width":0, 304 | "x":864, 305 | "y":112 306 | }, 307 | { 308 | "height":0, 309 | "id":20, 310 | "name":"guy", 311 | "point":true, 312 | "rotation":0, 313 | "type":"", 314 | "visible":true, 315 | "width":0, 316 | "x":160, 317 | "y":256 318 | }, 319 | { 320 | "height":0, 321 | "id":34, 322 | "name":"bird", 323 | "point":true, 324 | "rotation":0, 325 | "type":"", 326 | "visible":true, 327 | "width":0, 328 | "x":864, 329 | "y":176 330 | }, 331 | { 332 | "height":0, 333 | "id":35, 334 | "name":"bird", 335 | "point":true, 336 | "rotation":0, 337 | "type":"", 338 | "visible":true, 339 | "width":0, 340 | "x":864, 341 | "y":80 342 | }, 343 | { 344 | "height":0, 345 | "id":36, 346 | "name":"flame", 347 | "point":true, 348 | "rotation":0, 349 | "type":"", 350 | "visible":true, 351 | "width":0, 352 | "x":400, 353 | "y":160 354 | }, 355 | { 356 | "height":0, 357 | "id":37, 358 | "name":"flame", 359 | "point":true, 360 | "rotation":0, 361 | "type":"", 362 | "visible":true, 363 | "width":0, 364 | "x":464, 365 | "y":192 366 | }, 367 | { 368 | "height":0, 369 | "id":38, 370 | "name":"flame", 371 | "point":true, 372 | "rotation":0, 373 | "type":"", 374 | "visible":true, 375 | "width":0, 376 | "x":496, 377 | "y":192 378 | }, 379 | { 380 | "height":0, 381 | "id":39, 382 | "name":"guy", 383 | "point":true, 384 | "rotation":0, 385 | "type":"", 386 | "visible":true, 387 | "width":0, 388 | "x":192, 389 | "y":256 390 | }, 391 | { 392 | "height":0, 393 | "id":42, 394 | "name":"guy", 395 | "point":true, 396 | "rotation":0, 397 | "type":"", 398 | "visible":true, 399 | "width":0, 400 | "x":640, 401 | "y":176 402 | }, 403 | { 404 | "height":0, 405 | "id":43, 406 | "name":"guy", 407 | "point":true, 408 | "rotation":0, 409 | "type":"", 410 | "visible":true, 411 | "width":0, 412 | "x":672, 413 | "y":176 414 | }], 415 | "opacity":1, 416 | "type":"objectgroup", 417 | "visible":false, 418 | "x":0, 419 | "y":0 420 | }], 421 | "nextlayerid":7, 422 | "nextobjectid":44, 423 | "orientation":"orthogonal", 424 | "renderorder":"right-down", 425 | "tiledversion":"1.10.2", 426 | "tileheight":16, 427 | "tilesets":[ 428 | { 429 | "columns":9, 430 | "firstgid":1, 431 | "image":"kirby-like.png", 432 | "imageheight":160, 433 | "imagewidth":144, 434 | "margin":0, 435 | "name":"kirby-like", 436 | "spacing":0, 437 | "tilecount":90, 438 | "tileheight":16, 439 | "tilewidth":16 440 | }], 441 | "tilewidth":16, 442 | "type":"map", 443 | "version":"1.10", 444 | "width":54 445 | } -------------------------------------------------------------------------------- /public/level-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JSLegendDev/Kirby-like-ts/cdcac97bf5aaa76a1b8ee6cee08fd417468471f6/public/level-2.png -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | export const scale = 4; 2 | -------------------------------------------------------------------------------- /src/entities.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AreaComp, 3 | BodyComp, 4 | DoubleJumpComp, 5 | GameObj, 6 | HealthComp, 7 | KaboomCtx, 8 | OpacityComp, 9 | PosComp, 10 | ScaleComp, 11 | SpriteComp, 12 | } from "kaboom"; 13 | import { scale } from "./constants"; 14 | import { globalGameState } from "./state"; 15 | 16 | type PlayerGameObj = GameObj< 17 | SpriteComp & 18 | AreaComp & 19 | BodyComp & 20 | PosComp & 21 | ScaleComp & 22 | DoubleJumpComp & 23 | HealthComp & 24 | OpacityComp & { 25 | speed: number; 26 | direction: string; 27 | isInhaling: boolean; 28 | isFull: boolean; 29 | } 30 | >; 31 | 32 | export function makePlayer(k: KaboomCtx, posX: number, posY: number) { 33 | const player = k.make([ 34 | k.sprite("assets", { anim: "kirbIdle" }), 35 | k.area({ shape: new k.Rect(k.vec2(4, 5.9), 8, 10) }), 36 | k.body(), 37 | k.pos(posX * scale, posY * scale), 38 | k.scale(scale), 39 | k.doubleJump(10), 40 | k.health(3), 41 | k.opacity(1), 42 | { 43 | speed: 300, 44 | direction: "right", 45 | isInhaling: false, 46 | isFull: false, 47 | }, 48 | "player", 49 | ]); 50 | 51 | player.onCollide("enemy", async (enemy: GameObj) => { 52 | if (player.isInhaling && enemy.isInhalable) { 53 | player.isInhaling = false; 54 | k.destroy(enemy); 55 | player.isFull = true; 56 | return; 57 | } 58 | 59 | if (player.hp() === 0) { 60 | k.destroy(player); 61 | k.go(globalGameState.currentScene); 62 | return; 63 | } 64 | 65 | player.hurt(); 66 | await k.tween( 67 | player.opacity, 68 | 0, 69 | 0.05, 70 | (val) => (player.opacity = val), 71 | k.easings.linear 72 | ); 73 | await k.tween( 74 | player.opacity, 75 | 1, 76 | 0.05, 77 | (val) => (player.opacity = val), 78 | k.easings.linear 79 | ); 80 | }); 81 | 82 | player.onCollide("exit", () => { 83 | k.go(globalGameState.nextScene); 84 | }); 85 | 86 | const inhaleEffect = k.add([ 87 | k.sprite("assets", { anim: "kirbInhaleEffect" }), 88 | k.pos(), 89 | k.scale(scale), 90 | k.opacity(0), 91 | "inhaleEffect", 92 | ]); 93 | 94 | const inhaleZone = player.add([ 95 | k.area({ shape: new k.Rect(k.vec2(0), 20, 4) }), 96 | k.pos(), 97 | "inhaleZone", 98 | ]); 99 | 100 | inhaleZone.onUpdate(() => { 101 | if (player.direction === "left") { 102 | inhaleZone.pos = k.vec2(-14, 8); 103 | inhaleEffect.pos = k.vec2(player.pos.x - 60, player.pos.y + 0); 104 | inhaleEffect.flipX = true; 105 | return; 106 | } 107 | inhaleZone.pos = k.vec2(14, 8); 108 | inhaleEffect.pos = k.vec2(player.pos.x + 60, player.pos.y + 0); 109 | inhaleEffect.flipX = false; 110 | }); 111 | 112 | player.onUpdate(() => { 113 | if (player.pos.y > 2000) { 114 | k.go(globalGameState.currentScene); 115 | } 116 | }); 117 | 118 | return player; 119 | } 120 | 121 | export function setControls(k: KaboomCtx, player: PlayerGameObj) { 122 | const inhaleEffectRef = k.get("inhaleEffect")[0]; 123 | 124 | k.onKeyDown((key) => { 125 | switch (key) { 126 | case "left": 127 | player.direction = "left"; 128 | player.flipX = true; 129 | player.move(-player.speed, 0); 130 | break; 131 | case "right": 132 | player.direction = "right"; 133 | player.flipX = false; 134 | player.move(player.speed, 0); 135 | break; 136 | case "z": 137 | if (player.isFull) { 138 | player.play("kirbFull"); 139 | inhaleEffectRef.opacity = 0; 140 | break; 141 | } 142 | 143 | player.isInhaling = true; 144 | player.play("kirbInhaling"); 145 | inhaleEffectRef.opacity = 1; 146 | break; 147 | default: 148 | } 149 | }); 150 | k.onKeyPress((key) => { 151 | switch (key) { 152 | case "x": 153 | player.doubleJump(); 154 | break; 155 | default: 156 | } 157 | }); 158 | k.onKeyRelease((key) => { 159 | switch (key) { 160 | case "z": 161 | if (player.isFull) { 162 | player.play("kirbInhaling"); 163 | const shootingStar = k.add([ 164 | k.sprite("assets", { 165 | anim: "shootingStar", 166 | flipX: player.direction === "right", 167 | }), 168 | k.area({ shape: new k.Rect(k.vec2(5, 4), 6, 6) }), 169 | k.pos( 170 | player.direction === "left" 171 | ? player.pos.x - 80 172 | : player.pos.x + 80, 173 | player.pos.y + 5 174 | ), 175 | k.scale(scale), 176 | player.direction === "left" 177 | ? k.move(k.LEFT, 800) 178 | : k.move(k.RIGHT, 800), 179 | "shootingStar", 180 | ]); 181 | shootingStar.onCollide("platform", () => k.destroy(shootingStar)); 182 | 183 | player.isFull = false; 184 | k.wait(1, () => player.play("kirbIdle")); 185 | break; 186 | } 187 | 188 | inhaleEffectRef.opacity = 0; 189 | player.isInhaling = false; 190 | player.play("kirbIdle"); 191 | break; 192 | default: 193 | } 194 | }); 195 | } 196 | 197 | export function makeInhalable(k: KaboomCtx, enemy: GameObj) { 198 | enemy.onCollide("inhaleZone", () => { 199 | enemy.isInhalable = true; 200 | }); 201 | 202 | enemy.onCollideEnd("inhaleZone", () => { 203 | enemy.isInhalable = false; 204 | }); 205 | 206 | enemy.onCollide("shootingStar", (shootingStar: GameObj) => { 207 | k.destroy(enemy); 208 | k.destroy(shootingStar); 209 | }); 210 | 211 | const playerRef = k.get("player")[0]; 212 | enemy.onUpdate(() => { 213 | if (playerRef.isInhaling && enemy.isInhalable) { 214 | if (playerRef.direction === "right") { 215 | enemy.move(-800, 0); 216 | return; 217 | } 218 | enemy.move(800, 0); 219 | } 220 | }); 221 | } 222 | 223 | export function makeFlameEnemy(k: KaboomCtx, posX: number, posY: number) { 224 | const flame = k.add([ 225 | k.sprite("assets", { anim: "flame" }), 226 | k.scale(scale), 227 | k.pos(posX * scale, posY * scale), 228 | k.area({ 229 | shape: new k.Rect(k.vec2(4, 6), 8, 10), 230 | collisionIgnore: ["enemy"], 231 | }), 232 | k.body(), 233 | k.state("idle", ["idle", "jump"]), 234 | "enemy", 235 | ]); 236 | 237 | makeInhalable(k, flame); 238 | 239 | flame.onStateEnter("idle", async () => { 240 | await k.wait(1); 241 | flame.enterState("jump"); 242 | }); 243 | 244 | flame.onStateEnter("jump", async () => { 245 | flame.jump(1000); 246 | }); 247 | 248 | flame.onStateUpdate("jump", async () => { 249 | if (flame.isGrounded()) { 250 | flame.enterState("idle"); 251 | } 252 | }); 253 | 254 | return flame; 255 | } 256 | 257 | export function makeGuyEnemy(k: KaboomCtx, posX: number, posY: number) { 258 | const guy = k.add([ 259 | k.sprite("assets", { anim: "guyWalk" }), 260 | k.scale(scale), 261 | k.pos(posX * scale, posY * scale), 262 | k.area({ 263 | shape: new k.Rect(k.vec2(2, 3.9), 12, 12), 264 | collisionIgnore: ["enemy"], 265 | }), 266 | k.body(), 267 | k.state("idle", ["idle", "left", "right", "jump"]), 268 | { isInhalable: false, speed: 100 }, 269 | "enemy", 270 | ]); 271 | 272 | makeInhalable(k, guy); 273 | 274 | guy.onStateEnter("idle", async () => { 275 | await k.wait(1); 276 | guy.enterState("left"); 277 | }); 278 | 279 | guy.onStateEnter("left", async () => { 280 | guy.flipX = false; 281 | await k.wait(2); 282 | guy.enterState("right"); 283 | }); 284 | 285 | guy.onStateUpdate("left", () => { 286 | guy.move(-guy.speed, 0); 287 | }); 288 | 289 | guy.onStateEnter("right", async () => { 290 | guy.flipX = true; 291 | await k.wait(2); 292 | guy.enterState("left"); 293 | }); 294 | 295 | guy.onStateUpdate("right", () => { 296 | guy.move(guy.speed, 0); 297 | }); 298 | 299 | return guy; 300 | } 301 | 302 | export function makeBirdEnemy( 303 | k: KaboomCtx, 304 | posX: number, 305 | posY: number, 306 | speed: number 307 | ) { 308 | const bird = k.add([ 309 | k.sprite("assets", { anim: "bird" }), 310 | k.scale(scale), 311 | k.pos(posX * scale, posY * scale), 312 | k.area({ 313 | shape: new k.Rect(k.vec2(4, 6), 8, 10), 314 | collisionIgnore: ["enemy"], 315 | }), 316 | k.body({ isStatic: true }), 317 | k.move(k.LEFT, speed), 318 | k.offscreen({ destroy: true, distance: 400 }), 319 | "enemy", 320 | ]); 321 | 322 | makeInhalable(k, bird); 323 | 324 | return bird; 325 | } 326 | -------------------------------------------------------------------------------- /src/kaboomCtx.ts: -------------------------------------------------------------------------------- 1 | import kaboom from "kaboom"; 2 | import { scale } from "./constants"; 3 | 4 | export const k = kaboom({ 5 | width: 256 * scale, 6 | height: 144 * scale, 7 | letterbox: true, 8 | scale, // Work around for a Kaboom bug. Need to both set scaling here and scale sprites so that 9 | // each pixel takes mostly the correct amount of space. 10 | global: false, 11 | }); 12 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { k } from "./kaboomCtx"; 2 | import { makeMap } from "./utils"; 3 | import { 4 | makeBirdEnemy, 5 | makeFlameEnemy, 6 | makeGuyEnemy, 7 | makePlayer, 8 | setControls, 9 | } from "./entities"; 10 | import { globalGameState } from "./state"; 11 | 12 | async function gameSetup() { 13 | k.loadSprite("assets", "./kirby-like.png", { 14 | sliceX: 9, 15 | sliceY: 10, 16 | anims: { 17 | kirbIdle: 0, 18 | kirbInhaling: 1, 19 | kirbFull: 2, 20 | kirbInhaleEffect: { from: 3, to: 8, speed: 15, loop: true }, 21 | shootingStar: 9, 22 | flame: { from: 36, to: 37, speed: 4, loop: true }, 23 | guyIdle: 18, 24 | guyWalk: { from: 18, to: 19, speed: 4, loop: true }, 25 | bird: { from: 27, to: 28, speed: 4, loop: true }, 26 | }, 27 | }); 28 | k.loadSprite("level-1", "./level-1.png"); 29 | k.loadSprite("level-2", "./level-2.png"); 30 | 31 | k.add([k.rect(k.width(), k.height()), k.color(0, 0, 0), k.fixed()]); 32 | 33 | const { map: level1Layout, spawnPoints: level1SpawnPoints } = await makeMap( 34 | k, 35 | "level-1" 36 | ); 37 | 38 | const { map: level2Layout, spawnPoints: level2SpawnPoints } = await makeMap( 39 | k, 40 | "level-2" 41 | ); 42 | 43 | k.scene("level-1", async () => { 44 | globalGameState.setCurrentScene("level-1"); 45 | globalGameState.setNextScene("level-2"); 46 | k.setGravity(2100); 47 | k.add([ 48 | k.rect(k.width(), k.height()), 49 | k.color(k.Color.fromHex("#f7d7db")), 50 | k.fixed(), 51 | ]); 52 | 53 | k.add(level1Layout); 54 | 55 | const kirb = makePlayer( 56 | k, 57 | level1SpawnPoints.player[0].x, 58 | level1SpawnPoints.player[0].y 59 | ); 60 | 61 | setControls(k, kirb); 62 | k.add(kirb); 63 | k.camScale(k.vec2(0.7)); 64 | k.onUpdate(() => { 65 | if (kirb.pos.x < level1Layout.pos.x + 432) 66 | k.camPos(kirb.pos.x + 500, 800); 67 | }); 68 | 69 | for (const flame of level1SpawnPoints.flame) { 70 | makeFlameEnemy(k, flame.x, flame.y); 71 | } 72 | 73 | for (const guy of level1SpawnPoints.guy) { 74 | makeGuyEnemy(k, guy.x, guy.y); 75 | } 76 | 77 | for (const bird of level1SpawnPoints.bird) { 78 | const possibleSpeeds = [100, 200, 300]; 79 | k.loop(10, () => { 80 | makeBirdEnemy( 81 | k, 82 | bird.x, 83 | bird.y, 84 | possibleSpeeds[Math.floor(Math.random() * possibleSpeeds.length)] 85 | ); 86 | }); 87 | } 88 | }); 89 | 90 | k.scene("level-2", () => { 91 | globalGameState.setCurrentScene("level-2"); 92 | globalGameState.setNextScene("level-1"); 93 | k.setGravity(2100); 94 | k.add([ 95 | k.rect(k.width(), k.height()), 96 | k.color(k.Color.fromHex("#f7d7db")), 97 | k.fixed(), 98 | ]); 99 | 100 | k.add(level2Layout); 101 | const kirb = makePlayer( 102 | k, 103 | level2SpawnPoints.player[0].x, 104 | level2SpawnPoints.player[0].y 105 | ); 106 | 107 | setControls(k, kirb); 108 | k.add(kirb); 109 | k.camScale(k.vec2(0.7)); 110 | k.onUpdate(() => { 111 | if (kirb.pos.x < level2Layout.pos.x + 2100) 112 | k.camPos(kirb.pos.x + 500, 800); 113 | }); 114 | 115 | for (const flame of level2SpawnPoints.flame) { 116 | makeFlameEnemy(k, flame.x, flame.y); 117 | } 118 | 119 | for (const guy of level2SpawnPoints.guy) { 120 | makeGuyEnemy(k, guy.x, guy.y); 121 | } 122 | 123 | for (const bird of level2SpawnPoints.bird) { 124 | const possibleSpeeds = [100, 200, 300]; 125 | k.loop(10, () => { 126 | makeBirdEnemy( 127 | k, 128 | bird.x, 129 | bird.y, 130 | possibleSpeeds[Math.floor(Math.random() * possibleSpeeds.length)] 131 | ); 132 | }); 133 | } 134 | }); 135 | 136 | k.scene("end", () => {}); 137 | 138 | k.go("level-1"); 139 | } 140 | 141 | gameSetup(); 142 | -------------------------------------------------------------------------------- /src/state.ts: -------------------------------------------------------------------------------- 1 | export const globalGameState: { 2 | scenes: string[]; 3 | nextScene: string; 4 | currentScene: string; 5 | setNextScene: (sceneName: string) => void; 6 | setCurrentScene: (sceneName: string) => void; 7 | } = { 8 | scenes: ["level-1", "level-2", "end"], 9 | nextScene: "", 10 | currentScene: "level-1", 11 | setCurrentScene(sceneName: string) { 12 | if (this.scenes.includes(sceneName)) { 13 | this.currentScene = sceneName; 14 | } 15 | }, 16 | setNextScene(sceneName: string) { 17 | if (this.scenes.includes(sceneName)) { 18 | this.nextScene = sceneName; 19 | } 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { KaboomCtx } from "kaboom"; 2 | import { scale } from "./constants"; 3 | 4 | export async function makeMap(k: KaboomCtx, name: string) { 5 | const mapData = await (await fetch(`./${name}.json`)).json(); 6 | 7 | const map = k.make([k.sprite(name), k.scale(scale), k.pos(0)]); 8 | 9 | const spawnPoints: { [key: string]: { x: number; y: number }[] } = {}; 10 | 11 | for (const layer of mapData.layers) { 12 | if (layer.name === "colliders") { 13 | for (const collider of layer.objects) { 14 | map.add([ 15 | k.area({ 16 | shape: new k.Rect(k.vec2(0), collider.width, collider.height), 17 | collisionIgnore: ["platform", "exit"], 18 | }), 19 | collider.name !== "exit" ? k.body({ isStatic: true }) : null, 20 | k.pos(collider.x, collider.y), 21 | collider.name !== "exit" ? "platform" : "exit", 22 | ]); 23 | } 24 | continue; 25 | } 26 | if (layer.name === "spawnpoints") { 27 | for (const spawnPoint of layer.objects) { 28 | if (spawnPoints[spawnPoint.name]) { 29 | spawnPoints[spawnPoint.name].push({ 30 | x: spawnPoint.x, 31 | y: spawnPoint.y, 32 | }); 33 | continue; 34 | } 35 | spawnPoints[spawnPoint.name] = [{ x: spawnPoint.x, y: spawnPoint.y }]; 36 | } 37 | } 38 | } 39 | 40 | return { map, spawnPoints }; 41 | } 42 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true 21 | }, 22 | "include": ["src"] 23 | } 24 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | 3 | export default defineConfig({ 4 | base: "./", 5 | build: { 6 | minify: false, 7 | }, 8 | }); 9 | --------------------------------------------------------------------------------