kiwiengine 0.0.1-alpha → 0.5.2

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.
Files changed (438) hide show
  1. package/README.ko.md +550 -0
  2. package/README.md +575 -4
  3. package/examples/collision-test/assets/cat.png +0 -0
  4. package/examples/collision-test/dist/game.js +2 -0
  5. package/examples/collision-test/dist/game.js.LICENSE.txt +35 -0
  6. package/examples/collision-test/index.ts +30 -0
  7. package/examples/dom-particle-test/assets/bird.png +0 -0
  8. package/examples/dom-particle-test/dist/game.js +2 -0
  9. package/examples/dom-particle-test/dist/game.js.LICENSE.txt +35 -0
  10. package/examples/dom-particle-test/index.html +24 -0
  11. package/examples/dom-particle-test/index.ts +27 -0
  12. package/examples/dom-sprite-test/assets/bird.png +0 -0
  13. package/examples/dom-sprite-test/assets/fire.png +0 -0
  14. package/examples/dom-sprite-test/assets/run.png +0 -0
  15. package/examples/dom-sprite-test/dist/game.js +2 -0
  16. package/examples/dom-sprite-test/dist/game.js.LICENSE.txt +35 -0
  17. package/examples/dom-sprite-test/index.html +24 -0
  18. package/examples/dom-sprite-test/index.ts +38 -0
  19. package/examples/dom-test/dist/game.js +2 -0
  20. package/examples/dom-test/dist/game.js.LICENSE.txt +35 -0
  21. package/examples/dom-test/index.html +24 -0
  22. package/examples/dom-test/index.ts +22 -0
  23. package/examples/flappy-cat/assets/bgm/bgm.ogg +0 -0
  24. package/examples/flappy-cat/assets/images/base.png +0 -0
  25. package/examples/flappy-cat/assets/images/bg.png +0 -0
  26. package/examples/flappy-cat/assets/images/cat.png +0 -0
  27. package/examples/flappy-cat/assets/images/pipe-green.png +0 -0
  28. package/examples/flappy-cat/assets/images/pipe-red.png +0 -0
  29. package/examples/flappy-cat/assets/sfx/die.wav +0 -0
  30. package/examples/flappy-cat/assets/sfx/hit.wav +0 -0
  31. package/examples/flappy-cat/assets/sfx/point.wav +0 -0
  32. package/examples/flappy-cat/assets/sfx/wing.wav +0 -0
  33. package/examples/flappy-cat/dist/game.js +0 -0
  34. package/examples/flappy-cat/index.html +24 -0
  35. package/examples/flappy-cat/index.ts +0 -0
  36. package/examples/particle-test/assets/bird.png +0 -0
  37. package/examples/particle-test/dist/game.js +2 -0
  38. package/examples/particle-test/dist/game.js.LICENSE.txt +35 -0
  39. package/examples/particle-test/index.html +24 -0
  40. package/examples/particle-test/index.ts +30 -0
  41. package/examples/renderer-test/dist/game.js +2 -0
  42. package/examples/renderer-test/dist/game.js.LICENSE.txt +35 -0
  43. package/examples/renderer-test/index.html +24 -0
  44. package/examples/renderer-test/index.ts +9 -0
  45. package/examples/simple-battle/assets/bgm/battle.mp3 +0 -0
  46. package/examples/simple-battle/assets/bitmap-fonts/white-peaberry.fnt +107 -0
  47. package/examples/simple-battle/assets/bitmap-fonts/white-peaberry.png +0 -0
  48. package/examples/simple-battle/assets/joystick/joystick.png +0 -0
  49. package/examples/simple-battle/assets/joystick/knob.png +0 -0
  50. package/examples/simple-battle/assets/sfx/hero/die/die.wav +0 -0
  51. package/examples/simple-battle/assets/sfx/hero/heal/heal.wav +0 -0
  52. package/examples/simple-battle/assets/sfx/hero/hit/hit1.wav +0 -0
  53. package/examples/simple-battle/assets/sfx/hero/hit/hit2.wav +0 -0
  54. package/examples/simple-battle/assets/sfx/hero/hit/hit3.wav +0 -0
  55. package/examples/simple-battle/assets/sfx/hero/miss/miss1.wav +0 -0
  56. package/examples/simple-battle/assets/sfx/hero/miss/miss2.wav +0 -0
  57. package/examples/simple-battle/assets/sfx/hero/miss/miss3.wav +0 -0
  58. package/examples/simple-battle/assets/sfx/orc/die/die.wav +0 -0
  59. package/examples/simple-battle/assets/sfx/orc/hit/hit1.wav +0 -0
  60. package/examples/simple-battle/assets/sfx/orc/hit/hit2.wav +0 -0
  61. package/examples/simple-battle/assets/sfx/orc/hit/hit3.wav +0 -0
  62. package/examples/simple-battle/assets/sfx/orc/miss/miss1.wav +0 -0
  63. package/examples/simple-battle/assets/sfx/orc/miss/miss2.wav +0 -0
  64. package/examples/simple-battle/assets/sfx/orc/miss/miss3.wav +0 -0
  65. package/examples/simple-battle/assets/spritesheets/hero-atlas.json +289 -0
  66. package/examples/simple-battle/assets/spritesheets/hero.png +0 -0
  67. package/examples/simple-battle/assets/spritesheets/orc-atlas.json +289 -0
  68. package/examples/simple-battle/assets/spritesheets/orc.png +0 -0
  69. package/examples/simple-battle/assets/spritesheets/potion-atlas.json +83 -0
  70. package/examples/simple-battle/assets/spritesheets/potion.png +0 -0
  71. package/examples/simple-battle/dist/game.js +2 -0
  72. package/examples/simple-battle/dist/game.js.LICENSE.txt +35 -0
  73. package/examples/simple-battle/hud/damage-text.ts +45 -0
  74. package/examples/simple-battle/hud/heal-text.ts +45 -0
  75. package/examples/simple-battle/hud/hp-bar.ts +38 -0
  76. package/examples/simple-battle/index.html +24 -0
  77. package/examples/simple-battle/index.ts +41 -0
  78. package/examples/simple-battle/objects/character.ts +95 -0
  79. package/examples/simple-battle/objects/hero.ts +113 -0
  80. package/examples/simple-battle/objects/orc.ts +109 -0
  81. package/examples/simple-battle/objects/potion.ts +29 -0
  82. package/examples/simple-battle/stage.ts +176 -0
  83. package/examples/spine-test/assets/spine/spineboy.atlas +95 -0
  84. package/examples/spine-test/assets/spine/spineboy.png +0 -0
  85. package/examples/spine-test/assets/spine/spineboy.skel +0 -0
  86. package/examples/spine-test/dist/game.js +2 -0
  87. package/examples/spine-test/dist/game.js.LICENSE.txt +35 -0
  88. package/examples/spine-test/index.html +24 -0
  89. package/examples/spine-test/index.ts +29 -0
  90. package/examples/sprite-test/assets/bird.png +0 -0
  91. package/examples/sprite-test/assets/fire.png +0 -0
  92. package/examples/sprite-test/dist/game.js +2 -0
  93. package/examples/sprite-test/dist/game.js.LICENSE.txt +35 -0
  94. package/examples/sprite-test/index.html +24 -0
  95. package/examples/sprite-test/index.ts +41 -0
  96. package/examples/tsconfig.json +2 -1
  97. package/examples/webpack.config.js +14 -3
  98. package/jest.config.ts +10 -0
  99. package/lib/asset/audio.js +47 -11
  100. package/lib/asset/audio.js.map +1 -1
  101. package/lib/asset/loaders/audio.js +3 -3
  102. package/lib/asset/loaders/audio.js.map +1 -1
  103. package/lib/asset/loaders/binary.js +3 -3
  104. package/lib/asset/loaders/binary.js.map +1 -1
  105. package/lib/asset/loaders/bitmap-font.js +71 -0
  106. package/lib/asset/loaders/bitmap-font.js.map +1 -0
  107. package/lib/asset/loaders/font.js +1 -1
  108. package/lib/asset/loaders/font.js.map +1 -1
  109. package/lib/asset/loaders/loader.js +17 -12
  110. package/lib/asset/loaders/loader.js.map +1 -1
  111. package/lib/asset/loaders/spritesheet.js +6 -7
  112. package/lib/asset/loaders/spritesheet.js.map +1 -1
  113. package/lib/asset/loaders/text.js +3 -3
  114. package/lib/asset/loaders/text.js.map +1 -1
  115. package/lib/asset/loaders/texture.js +5 -4
  116. package/lib/asset/loaders/texture.js.map +1 -1
  117. package/lib/asset/preload.js +60 -56
  118. package/lib/asset/preload.js.map +1 -1
  119. package/lib/collision/check-collision.js +804 -0
  120. package/lib/collision/check-collision.js.map +1 -0
  121. package/lib/collision/check-collision.test.js +300 -0
  122. package/lib/collision/check-collision.test.js.map +1 -0
  123. package/lib/collision/colliders.js +8 -0
  124. package/lib/collision/colliders.js.map +1 -0
  125. package/lib/debug.js.map +1 -0
  126. package/lib/dom/dom-animated-sprite.js +121 -0
  127. package/lib/dom/dom-animated-sprite.js.map +1 -0
  128. package/lib/dom/dom-game-object.js +106 -0
  129. package/lib/dom/dom-game-object.js.map +1 -0
  130. package/lib/dom/dom-particle.js +105 -0
  131. package/lib/dom/dom-particle.js.map +1 -0
  132. package/lib/dom/dom-preload.js +43 -0
  133. package/lib/dom/dom-preload.js.map +1 -0
  134. package/lib/dom/dom-sprite.js +40 -0
  135. package/lib/dom/dom-sprite.js.map +1 -0
  136. package/lib/dom/dom-texture-loader.js +36 -0
  137. package/lib/dom/dom-texture-loader.js.map +1 -0
  138. package/lib/dom/dom-utils.js +20 -0
  139. package/lib/dom/dom-utils.js.map +1 -0
  140. package/lib/index copy.js +16 -0
  141. package/lib/index copy.js.map +1 -0
  142. package/lib/index.js +35 -10
  143. package/lib/index.js.map +1 -1
  144. package/lib/input/joystick.js +262 -0
  145. package/lib/input/joystick.js.map +1 -0
  146. package/lib/node/core/dirty-number.js +38 -0
  147. package/lib/node/core/dirty-number.js.map +1 -0
  148. package/lib/node/core/game-node.js +63 -0
  149. package/lib/node/core/game-node.js.map +1 -0
  150. package/lib/node/core/game-object.js +8 -0
  151. package/lib/node/core/game-object.js.map +1 -0
  152. package/lib/node/core/renderable.js +52 -0
  153. package/lib/node/core/renderable.js.map +1 -0
  154. package/lib/node/core/transform.js +59 -0
  155. package/lib/node/core/transform.js.map +1 -0
  156. package/lib/node/core/transformable.js +85 -0
  157. package/lib/node/core/transformable.js.map +1 -0
  158. package/lib/node/ext/animated-sprite.js +96 -0
  159. package/lib/node/ext/animated-sprite.js.map +1 -0
  160. package/lib/node/ext/bitmap-text.js +89 -0
  161. package/lib/node/ext/bitmap-text.js.map +1 -0
  162. package/lib/node/ext/circle.js +28 -0
  163. package/lib/node/ext/circle.js.map +1 -0
  164. package/lib/node/ext/deplay.js +20 -0
  165. package/lib/node/ext/deplay.js.map +1 -0
  166. package/lib/node/ext/dom-container.js +51 -0
  167. package/lib/node/ext/dom-container.js.map +1 -0
  168. package/lib/node/ext/interval.js +20 -0
  169. package/lib/node/ext/interval.js.map +1 -0
  170. package/lib/node/ext/particle.js +98 -0
  171. package/lib/node/ext/particle.js.map +1 -0
  172. package/lib/node/ext/rectangle.js +32 -0
  173. package/lib/node/ext/rectangle.js.map +1 -0
  174. package/lib/node/ext/spine.js +272 -0
  175. package/lib/node/ext/spine.js.map +1 -0
  176. package/lib/node/ext/sprite.js +42 -0
  177. package/lib/node/ext/sprite.js.map +1 -0
  178. package/lib/node/physics/physics-object.js +112 -0
  179. package/lib/node/physics/physics-object.js.map +1 -0
  180. package/lib/node/physics/physics-world.js +27 -0
  181. package/lib/node/physics/physics-world.js.map +1 -0
  182. package/lib/renderer/camera.js +19 -0
  183. package/lib/renderer/camera.js.map +1 -0
  184. package/lib/renderer/container-manager.js +29 -0
  185. package/lib/renderer/container-manager.js.map +1 -0
  186. package/lib/renderer/fps-display.js +18 -0
  187. package/lib/renderer/fps-display.js.map +1 -0
  188. package/lib/renderer/layer.js +12 -0
  189. package/lib/renderer/layer.js.map +1 -0
  190. package/lib/renderer/renderer.js +145 -0
  191. package/lib/renderer/renderer.js.map +1 -0
  192. package/lib/renderer/ticker.js +56 -0
  193. package/lib/renderer/ticker.js.map +1 -0
  194. package/lib/renderer/ticker.test.js +241 -0
  195. package/lib/renderer/ticker.test.js.map +1 -0
  196. package/lib/types/asset/audio.d.ts +5 -4
  197. package/lib/types/asset/audio.d.ts.map +1 -1
  198. package/lib/types/asset/loaders/audio.d.ts +1 -1
  199. package/lib/types/asset/loaders/audio.d.ts.map +1 -1
  200. package/lib/types/asset/loaders/binary.d.ts +1 -1
  201. package/lib/types/asset/loaders/binary.d.ts.map +1 -1
  202. package/lib/types/asset/loaders/bitmap-font.d.ts +16 -0
  203. package/lib/types/asset/loaders/bitmap-font.d.ts.map +1 -0
  204. package/lib/types/asset/loaders/font.d.ts +1 -1
  205. package/lib/types/asset/loaders/font.d.ts.map +1 -1
  206. package/lib/types/asset/loaders/loader.d.ts +6 -6
  207. package/lib/types/asset/loaders/loader.d.ts.map +1 -1
  208. package/lib/types/asset/loaders/spritesheet.d.ts +5 -5
  209. package/lib/types/asset/loaders/spritesheet.d.ts.map +1 -1
  210. package/lib/types/asset/loaders/text.d.ts +1 -1
  211. package/lib/types/asset/loaders/text.d.ts.map +1 -1
  212. package/lib/types/asset/loaders/texture.d.ts +2 -2
  213. package/lib/types/asset/loaders/texture.d.ts.map +1 -1
  214. package/lib/types/asset/preload.d.ts +5 -3
  215. package/lib/types/asset/preload.d.ts.map +1 -1
  216. package/lib/types/bitmap-font.js +2 -0
  217. package/lib/types/bitmap-font.js.map +1 -0
  218. package/lib/types/collision/check-collision.d.ts +4 -0
  219. package/lib/types/collision/check-collision.d.ts.map +1 -0
  220. package/lib/types/collision/check-collision.test.d.ts +2 -0
  221. package/lib/types/collision/check-collision.test.d.ts.map +1 -0
  222. package/lib/types/collision/colliders.d.ts +34 -0
  223. package/lib/types/collision/colliders.d.ts.map +1 -0
  224. package/lib/types/debug.d.ts.map +1 -0
  225. package/lib/types/dom/dom-animated-sprite.d.ts +29 -0
  226. package/lib/types/dom/dom-animated-sprite.d.ts.map +1 -0
  227. package/lib/types/dom/dom-game-object.d.ts +44 -0
  228. package/lib/types/dom/dom-game-object.d.ts.map +1 -0
  229. package/lib/types/dom/dom-particle.d.ts +30 -0
  230. package/lib/types/dom/dom-particle.d.ts.map +1 -0
  231. package/lib/types/dom/dom-preload.d.ts +2 -0
  232. package/lib/types/dom/dom-preload.d.ts.map +1 -0
  233. package/lib/types/dom/dom-sprite.d.ts +13 -0
  234. package/lib/types/dom/dom-sprite.d.ts.map +1 -0
  235. package/lib/types/dom/dom-texture-loader.d.ts +8 -0
  236. package/lib/types/dom/dom-texture-loader.d.ts.map +1 -0
  237. package/lib/types/dom/dom-utils.d.ts +3 -0
  238. package/lib/types/dom/dom-utils.d.ts.map +1 -0
  239. package/lib/types/index copy.d.ts +16 -0
  240. package/lib/types/index copy.d.ts.map +1 -0
  241. package/lib/types/index.d.ts +25 -11
  242. package/lib/types/index.d.ts.map +1 -1
  243. package/lib/types/input/joystick.d.ts +28 -0
  244. package/lib/types/input/joystick.d.ts.map +1 -0
  245. package/lib/types/node/core/dirty-number.d.ts +17 -0
  246. package/lib/types/node/core/dirty-number.d.ts.map +1 -0
  247. package/lib/types/node/core/game-node.d.ts +16 -0
  248. package/lib/types/node/core/game-node.d.ts.map +1 -0
  249. package/lib/types/node/core/game-object.d.ts +8 -0
  250. package/lib/types/node/core/game-object.d.ts.map +1 -0
  251. package/lib/types/node/core/renderable.d.ts +22 -0
  252. package/lib/types/node/core/renderable.d.ts.map +1 -0
  253. package/lib/types/node/core/transform.d.ts +25 -0
  254. package/lib/types/node/core/transform.d.ts.map +1 -0
  255. package/lib/types/node/core/transformable.d.ts +44 -0
  256. package/lib/types/node/core/transformable.d.ts.map +1 -0
  257. package/lib/types/node/ext/animated-sprite.d.ts +28 -0
  258. package/lib/types/node/ext/animated-sprite.d.ts.map +1 -0
  259. package/lib/types/node/ext/bitmap-text.d.ts +14 -0
  260. package/lib/types/node/ext/bitmap-text.d.ts.map +1 -0
  261. package/lib/types/node/ext/circle.d.ts +19 -0
  262. package/lib/types/node/ext/circle.d.ts.map +1 -0
  263. package/lib/types/node/ext/deplay.d.ts +8 -0
  264. package/lib/types/node/ext/deplay.d.ts.map +1 -0
  265. package/lib/types/node/ext/dom-container.d.ts +12 -0
  266. package/lib/types/node/ext/dom-container.d.ts.map +1 -0
  267. package/lib/types/node/ext/interval.d.ts +9 -0
  268. package/lib/types/node/ext/interval.d.ts.map +1 -0
  269. package/lib/types/node/ext/particle.d.ts +30 -0
  270. package/lib/types/node/ext/particle.d.ts.map +1 -0
  271. package/lib/types/node/ext/rectangle.d.ts +22 -0
  272. package/lib/types/node/ext/rectangle.d.ts.map +1 -0
  273. package/lib/types/node/ext/spine.d.ts +36 -0
  274. package/lib/types/node/ext/spine.d.ts.map +1 -0
  275. package/lib/types/node/ext/sprite.d.ts +13 -0
  276. package/lib/types/node/ext/sprite.d.ts.map +1 -0
  277. package/lib/types/node/physics/physics-object.d.ts +38 -0
  278. package/lib/types/node/physics/physics-object.d.ts.map +1 -0
  279. package/lib/types/node/physics/physics-world.d.ts +18 -0
  280. package/lib/types/node/physics/physics-world.d.ts.map +1 -0
  281. package/lib/types/renderer/camera.d.ts +13 -0
  282. package/lib/types/renderer/camera.d.ts.map +1 -0
  283. package/lib/types/renderer/container-manager.d.ts +9 -0
  284. package/lib/types/renderer/container-manager.d.ts.map +1 -0
  285. package/lib/types/renderer/fps-display.d.ts +7 -0
  286. package/lib/types/renderer/fps-display.d.ts.map +1 -0
  287. package/lib/types/renderer/layer.d.ts +7 -0
  288. package/lib/types/renderer/layer.d.ts.map +1 -0
  289. package/lib/types/renderer/renderer.d.ts +40 -0
  290. package/lib/types/renderer/renderer.d.ts.map +1 -0
  291. package/lib/types/renderer/ticker.d.ts +6 -0
  292. package/lib/types/renderer/ticker.d.ts.map +1 -0
  293. package/lib/types/renderer/ticker.test.d.ts +40 -0
  294. package/lib/types/renderer/ticker.test.d.ts.map +1 -0
  295. package/lib/types/types/bitmap-font.d.ts +18 -0
  296. package/lib/types/types/bitmap-font.d.ts.map +1 -0
  297. package/lib/types/utils/device.d.ts +2 -0
  298. package/lib/types/utils/device.d.ts.map +1 -0
  299. package/lib/utils/device.js +2 -0
  300. package/lib/utils/device.js.map +1 -0
  301. package/package.json +8 -7
  302. package/src/asset/audio.ts +134 -90
  303. package/src/asset/loaders/audio.ts +19 -19
  304. package/src/asset/loaders/binary.ts +16 -16
  305. package/src/asset/loaders/bitmap-font.ts +85 -0
  306. package/src/asset/loaders/font.ts +14 -14
  307. package/src/asset/loaders/loader.ts +27 -23
  308. package/src/asset/loaders/spritesheet.ts +34 -36
  309. package/src/asset/loaders/text.ts +15 -15
  310. package/src/asset/loaders/texture.ts +29 -28
  311. package/src/asset/preload.ts +75 -64
  312. package/src/collision/check-collision.test.ts +349 -0
  313. package/src/collision/check-collision.ts +821 -0
  314. package/src/collision/colliders.ts +19 -0
  315. package/src/debug.ts +5 -0
  316. package/src/dom/dom-animated-sprite.ts +153 -0
  317. package/src/dom/dom-game-object.ts +131 -0
  318. package/src/dom/dom-particle.ts +151 -0
  319. package/src/dom/dom-preload.ts +54 -0
  320. package/src/dom/dom-sprite.ts +50 -0
  321. package/src/dom/dom-texture-loader.ts +44 -0
  322. package/src/dom/dom-utils.ts +19 -0
  323. package/src/index.ts +46 -13
  324. package/src/input/joystick.ts +316 -0
  325. package/src/node/core/dirty-number.ts +45 -0
  326. package/src/node/core/game-node.ts +74 -0
  327. package/src/node/core/game-object.ts +11 -0
  328. package/src/node/core/renderable.ts +65 -0
  329. package/src/node/core/transform.ts +70 -0
  330. package/src/node/core/transformable.ts +111 -0
  331. package/src/node/ext/animated-sprite.ts +123 -0
  332. package/src/node/ext/bitmap-text.ts +109 -0
  333. package/src/node/ext/circle.ts +40 -0
  334. package/src/node/ext/deplay.ts +24 -0
  335. package/src/node/ext/dom-container.ts +62 -0
  336. package/src/node/ext/interval.ts +24 -0
  337. package/src/node/ext/particle.ts +142 -0
  338. package/src/node/ext/rectangle.ts +51 -0
  339. package/src/node/ext/spine.ts +323 -0
  340. package/src/node/ext/sprite.ts +53 -0
  341. package/src/node/physics/physics-object.ts +156 -0
  342. package/src/node/physics/physics-world.ts +40 -0
  343. package/src/renderer/camera.ts +25 -0
  344. package/src/renderer/container-manager.ts +36 -0
  345. package/src/renderer/fps-display.ts +21 -0
  346. package/src/renderer/layer.ts +15 -0
  347. package/src/renderer/renderer.ts +180 -0
  348. package/src/renderer/ticker.test.ts +325 -0
  349. package/src/renderer/ticker.ts +54 -0
  350. package/src/types/bitmap-font.ts +19 -0
  351. package/src/utils/device.ts +1 -0
  352. package/examples/test-dom/index.ts +0 -21
  353. package/lib/game-object/game-object-physics.js +0 -188
  354. package/lib/game-object/game-object-physics.js.map +0 -1
  355. package/lib/game-object/game-object-rendering.js +0 -35
  356. package/lib/game-object/game-object-rendering.js.map +0 -1
  357. package/lib/game-object/game-object.js +0 -162
  358. package/lib/game-object/game-object.js.map +0 -1
  359. package/lib/game-object/transform.js +0 -118
  360. package/lib/game-object/transform.js.map +0 -1
  361. package/lib/game-object-ext/animated-sprite.js +0 -117
  362. package/lib/game-object-ext/animated-sprite.js.map +0 -1
  363. package/lib/game-object-ext/dom-container.js +0 -56
  364. package/lib/game-object-ext/dom-container.js.map +0 -1
  365. package/lib/game-object-ext/rect.js +0 -30
  366. package/lib/game-object-ext/rect.js.map +0 -1
  367. package/lib/game-object-ext/spine.js +0 -206
  368. package/lib/game-object-ext/spine.js.map +0 -1
  369. package/lib/game-object-ext/sprite.js +0 -46
  370. package/lib/game-object-ext/sprite.js.map +0 -1
  371. package/lib/game-object-ext/text.js +0 -68
  372. package/lib/game-object-ext/text.js.map +0 -1
  373. package/lib/game-object-ext/tiling-sprite.js +0 -64
  374. package/lib/game-object-ext/tiling-sprite.js.map +0 -1
  375. package/lib/types/game-object/game-object-physics.d.ts +0 -42
  376. package/lib/types/game-object/game-object-physics.d.ts.map +0 -1
  377. package/lib/types/game-object/game-object-rendering.d.ts +0 -15
  378. package/lib/types/game-object/game-object-rendering.d.ts.map +0 -1
  379. package/lib/types/game-object/game-object.d.ts +0 -81
  380. package/lib/types/game-object/game-object.d.ts.map +0 -1
  381. package/lib/types/game-object/transform.d.ts +0 -43
  382. package/lib/types/game-object/transform.d.ts.map +0 -1
  383. package/lib/types/game-object-ext/animated-sprite.d.ts +0 -29
  384. package/lib/types/game-object-ext/animated-sprite.d.ts.map +0 -1
  385. package/lib/types/game-object-ext/dom-container.d.ts +0 -16
  386. package/lib/types/game-object-ext/dom-container.d.ts.map +0 -1
  387. package/lib/types/game-object-ext/rect.d.ts +0 -17
  388. package/lib/types/game-object-ext/rect.d.ts.map +0 -1
  389. package/lib/types/game-object-ext/spine.d.ts +0 -35
  390. package/lib/types/game-object-ext/spine.d.ts.map +0 -1
  391. package/lib/types/game-object-ext/sprite.d.ts +0 -14
  392. package/lib/types/game-object-ext/sprite.d.ts.map +0 -1
  393. package/lib/types/game-object-ext/text.d.ts +0 -26
  394. package/lib/types/game-object-ext/text.d.ts.map +0 -1
  395. package/lib/types/game-object-ext/tiling-sprite.d.ts +0 -20
  396. package/lib/types/game-object-ext/tiling-sprite.d.ts.map +0 -1
  397. package/lib/types/utils/debug.d.ts.map +0 -1
  398. package/lib/types/utils/go.d.ts +0 -26
  399. package/lib/types/utils/go.d.ts.map +0 -1
  400. package/lib/types/world/world-debug.d.ts +0 -11
  401. package/lib/types/world/world-debug.d.ts.map +0 -1
  402. package/lib/types/world/world-physics.d.ts +0 -16
  403. package/lib/types/world/world-physics.d.ts.map +0 -1
  404. package/lib/types/world/world-rendering.d.ts +0 -28
  405. package/lib/types/world/world-rendering.d.ts.map +0 -1
  406. package/lib/types/world/world.d.ts +0 -38
  407. package/lib/types/world/world.d.ts.map +0 -1
  408. package/lib/utils/debug.js.map +0 -1
  409. package/lib/utils/go.js +0 -33
  410. package/lib/utils/go.js.map +0 -1
  411. package/lib/world/world-debug.js +0 -89
  412. package/lib/world/world-debug.js.map +0 -1
  413. package/lib/world/world-physics.js +0 -45
  414. package/lib/world/world-physics.js.map +0 -1
  415. package/lib/world/world-rendering.js +0 -123
  416. package/lib/world/world-rendering.js.map +0 -1
  417. package/lib/world/world.js +0 -147
  418. package/lib/world/world.js.map +0 -1
  419. package/src/game-object/game-object-physics.ts +0 -191
  420. package/src/game-object/game-object-rendering.ts +0 -27
  421. package/src/game-object/game-object.ts +0 -190
  422. package/src/game-object/transform.ts +0 -164
  423. package/src/game-object-ext/animated-sprite.ts +0 -140
  424. package/src/game-object-ext/dom-container.ts +0 -67
  425. package/src/game-object-ext/rect.ts +0 -40
  426. package/src/game-object-ext/spine.ts +0 -235
  427. package/src/game-object-ext/sprite.ts +0 -55
  428. package/src/game-object-ext/text.ts +0 -83
  429. package/src/game-object-ext/tiling-sprite.ts +0 -73
  430. package/src/utils/debug.ts +0 -5
  431. package/src/utils/go.ts +0 -53
  432. package/src/world/world-debug.ts +0 -114
  433. package/src/world/world-physics.ts +0 -52
  434. package/src/world/world-rendering.ts +0 -145
  435. package/src/world/world.ts +0 -171
  436. /package/examples/{test-dom → collision-test}/index.html +0 -0
  437. /package/lib/{utils/debug.js → debug.js} +0 -0
  438. /package/lib/types/{utils/debug.d.ts → debug.d.ts} +0 -0
@@ -0,0 +1,180 @@
1
+ import { EventMap } from '@webtaku/event-emitter'
2
+ import { AutoDetectOptions, autoDetectRenderer, ColorSource, Container as PixiContainer, Renderer as PixiRenderer } from 'pixi.js'
3
+ import { debugMode } from '../debug'
4
+ import { setStyle } from '../dom/dom-utils'
5
+ import { RenderableNode } from '../node/core/renderable'
6
+ import { Camera } from './camera'
7
+ import { RendererContainerManager } from './container-manager'
8
+ import { FpsDisplay } from './fps-display'
9
+ import { Layer } from './layer'
10
+ import { Ticker } from './ticker'
11
+
12
+ export type RendererOptions = {
13
+ logicalWidth?: number
14
+ logicalHeight?: number
15
+ backgroundColor?: ColorSource
16
+ backgroundAlpha?: number
17
+ layers?: { name: string; drawOrder: number }[]
18
+ }
19
+
20
+ export class Renderer extends RenderableNode<PixiContainer, {
21
+ resize: (width: number, height: number) => void
22
+ }> {
23
+ #containerManager: RendererContainerManager
24
+ #ticker = new Ticker((dt) => this.#render(dt))
25
+ camera = new Camera()
26
+ fpsDisplay?: FpsDisplay
27
+
28
+ #logicalWidth?: number
29
+ #logicalHeight?: number
30
+ #backgroundColor?: ColorSource
31
+ #backgroundAlpha?: number
32
+
33
+ #pixiRenderer?: PixiRenderer
34
+ #layers: { [name: string]: Layer } = {}
35
+ _isSizeDirty = false
36
+
37
+ canvasWidth = 0
38
+ canvasHeight = 0
39
+ canvasLeft = 0
40
+ canvasTop = 0
41
+ viewportScale = 1
42
+ centerX = 0
43
+ centerY = 0
44
+
45
+ constructor(public container: HTMLElement, options?: RendererOptions) {
46
+ super(new PixiContainer({ sortableChildren: true }))
47
+ this.renderer = this
48
+
49
+ this.worldTransform.x.v = 0
50
+ this.worldTransform.y.v = 0
51
+ this.worldTransform.resetDirty()
52
+
53
+ this.#containerManager = new RendererContainerManager(container)
54
+ this.#containerManager.on('resize', (width, height) => this.#updateSize(width, height))
55
+
56
+ this.camera.on('positionChanged', () => this.#updatePosition())
57
+ this.camera.on('scaleChanged', () => this.#updatePosition())
58
+
59
+ if (options) {
60
+ if (options.logicalWidth !== undefined) this.#logicalWidth = options.logicalWidth
61
+ if (options.logicalHeight !== undefined) this.#logicalHeight = options.logicalHeight
62
+ if (options.backgroundColor !== undefined) this.#backgroundColor = options.backgroundColor
63
+ if (options.backgroundAlpha !== undefined) this.#backgroundAlpha = options.backgroundAlpha
64
+
65
+ if (options.layers) {
66
+ for (const layerOption of options.layers) {
67
+ const layer = new Layer(layerOption.drawOrder)
68
+ this._pixiContainer.addChild(layer._pixiContainer)
69
+ this.#layers[layerOption.name] = layer
70
+ }
71
+ }
72
+ }
73
+
74
+ if (debugMode) {
75
+ this.fpsDisplay = new FpsDisplay(container)
76
+ }
77
+
78
+ this.init()
79
+ }
80
+
81
+ private async init() {
82
+ const options: Partial<AutoDetectOptions> = {
83
+ eventMode: 'none',
84
+ resolution: window.devicePixelRatio,
85
+ }
86
+
87
+ if (this.#logicalWidth) options.width = this.#logicalWidth
88
+ if (this.#logicalHeight) options.height = this.#logicalHeight
89
+ if (this.#backgroundColor) options.backgroundColor = this.#backgroundColor
90
+ if (this.#backgroundAlpha) options.backgroundAlpha = this.#backgroundAlpha
91
+
92
+ const pr = await autoDetectRenderer(options)
93
+
94
+ setStyle(pr.canvas, {
95
+ position: 'absolute',
96
+ touchAction: 'auto',
97
+ })
98
+ this.container.appendChild(pr.canvas)
99
+
100
+ this.#pixiRenderer = pr
101
+
102
+ const cr = this.container.getBoundingClientRect()
103
+ this.#updateSize(cr.width, cr.height)
104
+ }
105
+
106
+ #updatePosition() {
107
+ const S = this.camera.scale
108
+ this._pixiContainer.scale = S
109
+ this._pixiContainer.position.set(
110
+ this.centerX - this.camera.x * S,
111
+ this.centerY - this.camera.y * S
112
+ )
113
+ }
114
+
115
+ #updateSize(containerWidth: number, containerHeight: number) {
116
+ const canvasWidth = this.#logicalWidth ?? containerWidth
117
+ const canvasHeight = this.#logicalHeight ?? containerHeight
118
+ this.canvasWidth = canvasWidth
119
+ this.canvasHeight = canvasHeight
120
+
121
+ this.centerX = canvasWidth / 2
122
+ this.centerY = canvasHeight / 2
123
+ this.#updatePosition()
124
+
125
+ const S = Math.min(containerWidth / canvasWidth, containerHeight / canvasHeight)
126
+ this.viewportScale = S
127
+
128
+ const displayWidth = canvasWidth * S
129
+ const displayHeight = canvasHeight * S
130
+
131
+ const canvasLeft = (containerWidth - displayWidth) / 2
132
+ const canvasTop = (containerHeight - displayHeight) / 2
133
+ this.canvasLeft = canvasLeft
134
+ this.canvasTop = canvasTop
135
+
136
+ if (this.#pixiRenderer) {
137
+ this.#pixiRenderer.resize(canvasWidth, canvasHeight)
138
+
139
+ setStyle(this.#pixiRenderer.canvas, {
140
+ width: `${displayWidth}px`,
141
+ height: `${displayHeight}px`,
142
+ left: `${canvasLeft}px`,
143
+ top: `${canvasTop}px`,
144
+ })
145
+
146
+ this.emit('resize', canvasWidth, canvasHeight)
147
+ }
148
+
149
+ this._isSizeDirty = true
150
+ }
151
+
152
+ #render(dt: number) {
153
+ this._isSizeDirty = false
154
+
155
+ this.update(dt)
156
+ this._updateWorldTransform()
157
+ this.#pixiRenderer?.render(this._pixiContainer)
158
+ this.fpsDisplay?.update()
159
+ }
160
+
161
+ _addToLayer(node: RenderableNode<PixiContainer, EventMap>, layerName: string) {
162
+ const layer = this.#layers[layerName]
163
+ if (!layer) throw new Error(`Layer ${layerName} does not exist.`)
164
+ layer._pixiContainer.addChild(node._pixiContainer)
165
+ }
166
+
167
+ override remove() {
168
+ this.#containerManager.remove()
169
+ this.#ticker.remove()
170
+ this.#pixiRenderer?.destroy()
171
+ this.fpsDisplay?.remove()
172
+ super.remove()
173
+ }
174
+
175
+ screenToWorld(screenX: number, screenY: number) {
176
+ const x = (screenX - this.canvasLeft) / this.viewportScale - this.canvasWidth / 2
177
+ const y = (screenY - this.canvasTop) / this.viewportScale - this.canvasHeight / 2
178
+ return { x, y }
179
+ }
180
+ }
@@ -0,0 +1,325 @@
1
+ /** @jest-environment jsdom */
2
+
3
+ /**
4
+ * Test Suite — Ticker (Jest)
5
+ * -------------------------------------------------------
6
+ * Goals
7
+ * - Avoid floating-point pitfalls around fixed step boundaries
8
+ * - Validate uncapped, capped via blur (6fps), long frame split,
9
+ * focus/pageshow transitions, and remove()
10
+ * - In this implementation: no setFixedFps; debugMode + focus/blur/pageshow control fps cap
11
+ *
12
+ * Principles
13
+ * - Do not assert exactly at the boundary (e.g., prefer 170ms over ~166ms)
14
+ * - Validate deltaTime using toBeCloseTo + loose call count checks
15
+ */
16
+
17
+ /** ----------------------- Time & RAF harness ----------------------- **/
18
+
19
+ // Local callback type to avoid depending on DOM lib typings.
20
+ type FrameCb = (time: number) => void
21
+
22
+ // Simulated monotonic clock (ms)
23
+ let nowMs = 0
24
+
25
+ // RAF callback registry: id -> cb
26
+ const rafCallbacks = new Map<number, FrameCb>()
27
+ let nextRafId = 1
28
+
29
+ const installTimeAndRafMocks = () => {
30
+ jest.spyOn(performance, 'now').mockImplementation(() => nowMs)
31
+
32
+ jest
33
+ .spyOn(window, 'requestAnimationFrame')
34
+ .mockImplementation((cb: FrameCb) => {
35
+ const id = nextRafId++
36
+ rafCallbacks.set(id, cb)
37
+ return id as unknown as number
38
+ })
39
+
40
+ jest.spyOn(window, 'cancelAnimationFrame').mockImplementation((id: number) => {
41
+ rafCallbacks.delete(id)
42
+ })
43
+ }
44
+
45
+ const resetHarness = () => {
46
+ nowMs = 0
47
+ rafCallbacks.clear()
48
+ nextRafId = 1
49
+ }
50
+
51
+ /**
52
+ * Advance a single frame: move the clock by advanceMs and
53
+ * run only the currently registered RAF callbacks
54
+ * (callbacks registered during this step run on the next step).
55
+ */
56
+ const step = (advanceMs: number) => {
57
+ nowMs += advanceMs
58
+ const cbs = [...rafCallbacks.values()]
59
+ rafCallbacks.clear()
60
+ for (const cb of cbs) cb(nowMs)
61
+ }
62
+
63
+ /** Advance multiple frames (helper) */
64
+ const advance = (totalMs: number, stepMs = 16) => {
65
+ const n = Math.floor(totalMs / stepMs)
66
+ for (let i = 0; i < n; i++) step(stepMs)
67
+ const remain = totalMs - n * stepMs
68
+ if (remain > 0) step(remain)
69
+ }
70
+
71
+ /**
72
+ * Helper to (re)load Ticker with a specific debugMode value.
73
+ * Uses jest.resetModules + jest.doMock to inject the desired export.
74
+ */
75
+ const loadTickerWithDebug = async (debug: boolean) => {
76
+ jest.resetModules()
77
+ jest.doMock('../debug', () => ({ debugMode: debug }), { virtual: true })
78
+ const mod = await import('./ticker')
79
+ return (mod as any).Ticker as new (onTick: (dt: number) => void) => { remove(): void }
80
+ }
81
+
82
+ /** Small helpers to read arguments cleanly */
83
+ const argOf = (mockFn: jest.Mock, nthZeroBased: number) => mockFn.mock.calls[nthZeroBased][0] as number
84
+ const lastArg = (mockFn: jest.Mock) => {
85
+ const i = mockFn.mock.calls.length - 1
86
+ return mockFn.mock.calls[i][0] as number
87
+ }
88
+
89
+ /** ----------------------- Lifecycle -------------------------- **/
90
+
91
+ beforeEach(() => {
92
+ resetHarness()
93
+ jest.restoreAllMocks()
94
+ installTimeAndRafMocks()
95
+ })
96
+
97
+ afterEach(() => {
98
+ jest.restoreAllMocks()
99
+ resetHarness()
100
+ })
101
+
102
+ /** ----------------------- Tests ------------------------------ **/
103
+
104
+ describe('uncapped mode (debugMode=false)', () => {
105
+ it('calls onTick once per frame with raw deltaTime (seconds)', async () => {
106
+ const Ticker = await loadTickerWithDebug(false)
107
+ const spy = jest.fn()
108
+ const ticker = new Ticker(spy) // default: uncapped
109
+
110
+ step(10) // 0.010
111
+ step(20) // 0.020
112
+ step(30) // 0.030
113
+
114
+ expect(spy).toHaveBeenCalledTimes(3)
115
+
116
+ // Assert shapes, then values
117
+ expect(spy).toHaveBeenNthCalledWith(1, expect.any(Number))
118
+ expect(spy).toHaveBeenNthCalledWith(2, expect.any(Number))
119
+ expect(spy).toHaveBeenNthCalledWith(3, expect.any(Number))
120
+
121
+ expect(argOf(spy, 0)).toBeCloseTo(0.010, 6)
122
+ expect(argOf(spy, 1)).toBeCloseTo(0.020, 6)
123
+ expect(argOf(spy, 2)).toBeCloseTo(0.030, 6)
124
+
125
+ ticker.remove()
126
+ })
127
+
128
+ it('does not call onTick when deltaTime <= 0', async () => {
129
+ const Ticker = await loadTickerWithDebug(false)
130
+ const spy = jest.fn()
131
+ const ticker = new Ticker(spy)
132
+
133
+ step(0)
134
+ expect(spy).not.toHaveBeenCalled()
135
+
136
+ step(5)
137
+ expect(spy).toHaveBeenCalledTimes(1)
138
+ expect(spy).toHaveBeenLastCalledWith(expect.any(Number))
139
+ expect(lastArg(spy)).toBeCloseTo(0.005, 6)
140
+
141
+ ticker.remove()
142
+ })
143
+ })
144
+
145
+ describe('capped mode via blur (debugMode=true -> 6fps)', () => {
146
+ it('accumulates lag and calls at fixed-step boundaries (avoid exact boundary)', async () => {
147
+ const Ticker = await loadTickerWithDebug(true)
148
+ jest.spyOn(document, 'hasFocus').mockReturnValue(true)
149
+
150
+ const spy = jest.fn()
151
+ const ticker = new Ticker(spy)
152
+
153
+ // Apply 6fps cap using blur (fixedStep ≈ 1/6 ≈ 0.1666667s)
154
+ window.dispatchEvent(new Event('blur'))
155
+
156
+ // 100 + 70 = 170ms -> crosses one boundary -> one call ≈ fixedStep
157
+ step(100)
158
+ step(70)
159
+ expect(spy).toHaveBeenCalledTimes(1)
160
+ expect(spy).toHaveBeenLastCalledWith(expect.any(Number))
161
+ expect(lastArg(spy)).toBeCloseTo(1 / 6, 6)
162
+
163
+ // Remaining lag ≈ 0.0033s
164
+ step(91) // still below another boundary
165
+ expect(spy).toHaveBeenCalledTimes(1)
166
+ step(80) // crosses again
167
+ expect(spy).toHaveBeenCalledTimes(2)
168
+ expect(spy).toHaveBeenLastCalledWith(expect.any(Number))
169
+ expect(lastArg(spy)).toBeCloseTo(1 / 6, 6)
170
+
171
+ ticker.remove()
172
+ })
173
+
174
+ it('long frame (delta >= 2*fixedStep) triggers two calls: fixedStep then raw delta; then lag resets', async () => {
175
+ const Ticker = await loadTickerWithDebug(true)
176
+ jest.spyOn(document, 'hasFocus').mockReturnValue(true)
177
+
178
+ const spy = jest.fn()
179
+ const ticker = new Ticker(spy)
180
+
181
+ window.dispatchEvent(new Event('blur')) // enable 6fps cap
182
+
183
+ // 500ms (0.5s) >= 2 * (1/6 ≈ 0.3333s)
184
+ step(500)
185
+ expect(spy).toHaveBeenCalledTimes(2)
186
+
187
+ expect(spy).toHaveBeenNthCalledWith(1, expect.any(Number))
188
+ expect(argOf(spy, 0)).toBeCloseTo(1 / 6, 6)
189
+
190
+ expect(spy).toHaveBeenNthCalledWith(2, expect.any(Number))
191
+ expect(argOf(spy, 1)).toBeCloseTo(0.5, 6)
192
+
193
+ // Repeat pattern
194
+ step(500)
195
+ expect(spy).toHaveBeenCalledTimes(4)
196
+
197
+ expect(spy).toHaveBeenNthCalledWith(3, expect.any(Number))
198
+ expect(argOf(spy, 2)).toBeCloseTo(1 / 6, 6)
199
+
200
+ expect(spy).toHaveBeenNthCalledWith(4, expect.any(Number))
201
+ expect(argOf(spy, 3)).toBeCloseTo(0.5, 6)
202
+
203
+ ticker.remove()
204
+ })
205
+ })
206
+
207
+ describe('runtime transitions via focus/pageshow (debugMode=true)', () => {
208
+ it('blur -> capped(6fps) / focus -> uncapped: after focus, raw delta behavior resumes', async () => {
209
+ const Ticker = await loadTickerWithDebug(true)
210
+ jest.spyOn(document, 'hasFocus').mockReturnValue(true)
211
+
212
+ const spy = jest.fn()
213
+ const ticker = new Ticker(spy)
214
+
215
+ // Enter capped mode and get one fixed-step call
216
+ window.dispatchEvent(new Event('blur'))
217
+ step(170)
218
+ expect(spy).toHaveBeenCalledTimes(1)
219
+ expect(spy).toHaveBeenLastCalledWith(expect.any(Number))
220
+ expect(lastArg(spy)).toBeCloseTo(1 / 6, 6)
221
+
222
+ // Back to uncapped
223
+ window.dispatchEvent(new Event('focus'))
224
+
225
+ spy.mockClear()
226
+ step(16)
227
+ step(33)
228
+ expect(spy).toHaveBeenCalledTimes(2)
229
+
230
+ expect(spy).toHaveBeenNthCalledWith(1, expect.any(Number))
231
+ expect(argOf(spy, 0)).toBeCloseTo(0.016, 6)
232
+
233
+ expect(spy).toHaveBeenNthCalledWith(2, expect.any(Number))
234
+ expect(argOf(spy, 1)).toBeCloseTo(0.033, 6)
235
+
236
+ ticker.remove()
237
+ })
238
+
239
+ it('pageshow(persisted=true) sets fpsCap to uncapped again', async () => {
240
+ const Ticker = await loadTickerWithDebug(true)
241
+ jest.spyOn(document, 'hasFocus').mockReturnValue(true)
242
+
243
+ const spy = jest.fn()
244
+ const ticker = new Ticker(spy)
245
+
246
+ window.dispatchEvent(new Event('blur'))
247
+ step(200) // > 1/6s => fixed-step call
248
+ expect(spy).toHaveBeenCalledTimes(1)
249
+ expect(spy).toHaveBeenLastCalledWith(expect.any(Number))
250
+ expect(lastArg(spy)).toBeCloseTo(1 / 6, 6)
251
+
252
+ // Create a pageshow event with persisted=true (jsdom lacks PageTransitionEvent)
253
+ const evt = new Event('pageshow') as Event & { persisted?: boolean }
254
+ Object.defineProperty(evt, 'persisted', { value: true })
255
+ window.dispatchEvent(evt)
256
+
257
+ spy.mockClear()
258
+ step(25)
259
+ step(40)
260
+ expect(spy).toHaveBeenCalledTimes(2)
261
+
262
+ expect(spy).toHaveBeenNthCalledWith(1, expect.any(Number))
263
+ expect(argOf(spy, 0)).toBeCloseTo(0.025, 6)
264
+
265
+ expect(spy).toHaveBeenNthCalledWith(2, expect.any(Number))
266
+ expect(argOf(spy, 1)).toBeCloseTo(0.040, 6)
267
+
268
+ ticker.remove()
269
+ })
270
+ })
271
+
272
+ describe('remove()', () => {
273
+ it('cancels next RAF and stops future ticks; also cleans up listeners', async () => {
274
+ const Ticker = await loadTickerWithDebug(true)
275
+
276
+ // Ensure the ticker starts in uncapped mode so the first small step triggers a tick.
277
+ jest.spyOn(document, 'hasFocus').mockReturnValue(true)
278
+
279
+ const spy = jest.fn()
280
+ const cancelSpy = jest.spyOn(window, 'cancelAnimationFrame')
281
+
282
+ const ticker = new Ticker(spy)
283
+
284
+ step(16) // ~0.016s -> should tick in uncapped mode
285
+ expect(spy).toHaveBeenCalledTimes(1)
286
+
287
+ ticker.remove()
288
+ expect(cancelSpy).toHaveBeenCalled()
289
+
290
+ spy.mockClear()
291
+ advance(200, 16)
292
+ expect(spy).not.toHaveBeenCalled()
293
+
294
+ // Listeners are cleaned up (dispatching events does nothing and does not throw)
295
+ expect(() => window.dispatchEvent(new Event('blur'))).not.toThrow()
296
+ expect(() => window.dispatchEvent(new Event('focus'))).not.toThrow()
297
+ })
298
+ })
299
+
300
+ describe('long-running sanity (ragged frames, capped=6fps)', () => {
301
+ it('produces a reasonable number of calls; includes fixedStep calls', async () => {
302
+ const Ticker = await loadTickerWithDebug(true)
303
+ jest.spyOn(document, 'hasFocus').mockReturnValue(true)
304
+
305
+ const spy = jest.fn()
306
+ const ticker = new Ticker(spy)
307
+
308
+ window.dispatchEvent(new Event('blur')) // 6fps -> fixedStep ≈ 0.1667
309
+
310
+ // Total ~1000ms with some long frames to trigger the split branch
311
+ const frames = [33, 33, 35, 201, 51, 61, 41, 201, 201, 251]
312
+ for (const ms of frames) step(ms)
313
+
314
+ const calls = spy.mock.calls.length
315
+ // With lag resets/rounding, tolerate a loose range
316
+ expect(calls).toBeGreaterThanOrEqual(5)
317
+ expect(calls).toBeLessThanOrEqual(9)
318
+
319
+ // At least one call should be exactly the fixed step (~1/6)
320
+ const hasFixedStep = spy.mock.calls.some(([dt]) => Math.abs((dt as number) - 1 / 6) < 1e-6)
321
+ expect(hasFixedStep).toBe(true)
322
+
323
+ ticker.remove()
324
+ })
325
+ })
@@ -0,0 +1,54 @@
1
+ import { debugMode } from '../debug'
2
+
3
+ export class Ticker {
4
+ #fpsCap?: number
5
+ #frameId = 0
6
+
7
+ constructor(onTick: (dt: number) => void) {
8
+ let prevTime = 0
9
+ let lagSeconds = 0
10
+
11
+ const step = (timestamp: number) => {
12
+ const dt = (timestamp - prevTime) / 1000
13
+ if (dt > 0) {
14
+ const fpsCap = this.#fpsCap
15
+ if (fpsCap !== undefined && fpsCap > 0) {
16
+ lagSeconds += dt
17
+ const fixedStep = 1 / fpsCap
18
+ if (lagSeconds >= fixedStep) {
19
+ onTick(fixedStep)
20
+ if (lagSeconds >= fixedStep * 2) { onTick(dt); lagSeconds = 0 }
21
+ else { lagSeconds -= fixedStep }
22
+ }
23
+ } else {
24
+ onTick(dt)
25
+ }
26
+ prevTime = timestamp
27
+ }
28
+ this.#frameId = requestAnimationFrame(step)
29
+ }
30
+ this.#frameId = requestAnimationFrame(step)
31
+
32
+ if (debugMode) {
33
+ if (!document.hasFocus()) this.#fpsCap = 6
34
+ window.addEventListener('blur', this.#blurListener)
35
+ window.addEventListener('focus', this.#focusListener)
36
+ window.addEventListener('pageshow', this.#pageshowListener)
37
+ }
38
+ }
39
+
40
+ #blurListener = () => { this.#fpsCap = 6 }
41
+ #focusListener = () => { this.#fpsCap = undefined }
42
+ #pageshowListener = (event: PageTransitionEvent) => {
43
+ if (event.persisted) {
44
+ this.#fpsCap = undefined
45
+ }
46
+ }
47
+
48
+ remove() {
49
+ cancelAnimationFrame(this.#frameId)
50
+ window.removeEventListener('blur', this.#blurListener)
51
+ window.removeEventListener('focus', this.#focusListener)
52
+ window.removeEventListener('pageshow', this.#pageshowListener)
53
+ }
54
+ }
@@ -0,0 +1,19 @@
1
+ import { Texture } from 'pixi.js'
2
+
3
+ export type Char = {
4
+ x: number
5
+ y: number
6
+ width: number
7
+ height: number
8
+ xoffset: number
9
+ yoffset: number
10
+ xadvance: number
11
+ }
12
+
13
+ export type BitmapFont = {
14
+ src: string
15
+ chars: Record<number, Char>
16
+ texture: Texture
17
+ size: number
18
+ lineHeight: number
19
+ }
@@ -0,0 +1 @@
1
+ export const isMobile = /Android|iPhone|iPad|iPod/i.test(navigator.userAgent)
@@ -1,21 +0,0 @@
1
- import { enableDebug, World, DomContainerObject } from '../../src';
2
-
3
- enableDebug();
4
-
5
- const world = new World({ width: 800, height: 600 });
6
- world.container.style.width = '100%';
7
- world.container.style.height = '100%';
8
- document.body.appendChild(world.container);
9
-
10
- const testEl = document.createElement('div');
11
- testEl.textContent = 'Hello World';
12
- testEl.style.color = 'red';
13
- testEl.onclick = () => alert('click');
14
-
15
- const go = new DomContainerObject({ el: testEl });
16
- go.alpha = 0.5;
17
- world.add(go);
18
-
19
- world.on('update', (dt) => {
20
- go.rotation += dt;
21
- });