@inglorious/engine 2.0.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -80,7 +80,7 @@ Here is a complete example showing how to set up and run a game using the engine
80
80
  <script type="importmap">
81
81
  {
82
82
  "imports": {
83
- "immer": "https://unpkg.com/immer@latest/dist/immer.mjs",
83
+ "mutative": "https://unpkg.com/mutative@latest/dist/mutative.esm.mjs",
84
84
  "@inglorious/utils/": "https://unpkg.com/@inglorious%2Futils@latest/src/",
85
85
  "@inglorious/store/": "https://unpkg.com/@inglorious%2Fstore@latest/src/",
86
86
  "@inglorious/engine/": "https://unpkg.com/@inglorious%2Fengine@latest/src/",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inglorious/engine",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "A JavaScript game engine written with global state, immutability, and pure functions in mind. Have fun(ctional programming) with it!",
5
5
  "author": "IceOnFire <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
6
6
  "license": "MIT",
@@ -30,12 +30,12 @@
30
30
  "access": "public"
31
31
  },
32
32
  "dependencies": {
33
- "@inglorious/store": "4.0.0",
34
- "@inglorious/utils": "3.5.0"
33
+ "@inglorious/store": "4.0.3",
34
+ "@inglorious/utils": "3.5.1"
35
35
  },
36
36
  "peerDependencies": {
37
- "@inglorious/store": "4.0.0",
38
- "@inglorious/utils": "3.5.0"
37
+ "@inglorious/store": "4.0.3",
38
+ "@inglorious/utils": "3.5.1"
39
39
  },
40
40
  "devDependencies": {
41
41
  "prettier": "^3.5.3",
@@ -57,7 +57,7 @@ export function camera(params) {
57
57
  }
58
58
  },
59
59
 
60
- mouseWheel(entity, { deltaY }) {
60
+ mouseWheel(entity, deltaY) {
61
61
  const delta = Math.sign(deltaY)
62
62
  // Scrolling down (positive deltaY) should zoom out (decrease zoom value)
63
63
  entity.targetZoom -= delta * entity.zoomSpeed * entity.zoomSensitivity
@@ -2,8 +2,6 @@ import { findCollision } from "@inglorious/engine/collision/detection.js"
2
2
  import { clampToBounds } from "@inglorious/engine/physics/bounds.js"
3
3
  import { zero } from "@inglorious/utils/math/vector.js"
4
4
 
5
- const NO_Y = 0
6
-
7
5
  export function mouse() {
8
6
  return {
9
7
  create(entity, entityId) {
@@ -33,10 +31,15 @@ export function mouse() {
33
31
  }
34
32
  }
35
33
 
36
- export function track(parent, options) {
37
- const handleMouseMove = createHandler("mouseMove", parent, options)
38
- const handleClick = createHandler("mouseClick", parent, options)
39
- const handleWheel = createHandler("mouseWheel", parent, options)
34
+ export function trackMouse(parent, api, toGamePosition) {
35
+ const handleMouseMove = createHandler(
36
+ "mouseMove",
37
+ parent,
38
+ api,
39
+ toGamePosition,
40
+ )
41
+ const handleClick = createHandler("mouseClick", parent, api, toGamePosition)
42
+ const handleWheel = createHandler("mouseWheel", parent, api, toGamePosition)
40
43
 
41
44
  return {
42
45
  onMouseMove: handleMouseMove,
@@ -54,32 +57,21 @@ export function createMouse(overrides = {}) {
54
57
  }
55
58
  }
56
59
 
57
- function createHandler(type, parent, api) {
60
+ function createHandler(type, parent, api, toGamePosition) {
58
61
  return (event) => {
62
+ event.preventDefault()
59
63
  event.stopPropagation()
60
64
 
61
65
  if (parent == null) {
62
66
  return
63
67
  }
64
68
 
65
- // For wheel events, the payload is different from other mouse events.
66
69
  if (type === "mouseWheel") {
67
- api.notify(type, { deltaY: event.deltaY })
70
+ api.notify(type, event.deltaY)
68
71
  return
69
72
  }
70
73
 
71
- // For move and click events, the payload is the calculated position.
72
- const payload = calculatePosition(event, parent)
73
- api.notify(type, payload)
74
+ const position = toGamePosition(event.clientX, event.clientY)
75
+ api.notify(type, position)
74
76
  }
75
77
  }
76
-
77
- function calculatePosition(event, parent) {
78
- const { clientX, clientY } = event
79
- const { left, bottom } = parent.getBoundingClientRect()
80
-
81
- const x = clientX - left
82
- const z = bottom - clientY
83
-
84
- return [x, NO_Y, z]
85
- }
@@ -0,0 +1,121 @@
1
+ import { findCollision } from "@inglorious/engine/collision/detection.js"
2
+ import { clampToBounds } from "@inglorious/engine/physics/bounds.js"
3
+ import { magnitude } from "@inglorious/utils/math/vector.js"
4
+ import { subtract } from "@inglorious/utils/math/vectors.js"
5
+ import { v } from "@inglorious/utils/v.js"
6
+
7
+ const MOVEMENT_THRESHOLD = 5
8
+
9
+ export function touch() {
10
+ return {
11
+ touchStart(entity, { index, position }, api) {
12
+ entity.isSwiping = false
13
+ entity.positions[index] = position
14
+
15
+ const entities = api.getEntities()
16
+ const touchedEntity = findCollision(
17
+ { ...entity, position: entity.positions[index] },
18
+ entities,
19
+ "touch",
20
+ )
21
+ if (touchedEntity) {
22
+ entity.targetIds[index] = touchedEntity.id
23
+ api.notify("entityTouchStart", entity.targetIds[index])
24
+ } else {
25
+ api.notify("sceneTouchStart", v(...entity.positions[index]))
26
+ }
27
+ },
28
+
29
+ touchMove(entity, { index, position }, api) {
30
+ const delta = subtract(position, entity.positions[index])
31
+
32
+ if (magnitude(delta) > MOVEMENT_THRESHOLD) {
33
+ entity.isSwiping = true
34
+ }
35
+
36
+ entity.positions[index] = position
37
+ const game = api.getEntity("game")
38
+ clampToBounds({ ...entity, position: entity.positions[index] }, game.size)
39
+
40
+ if (entity.targetIds[index]) {
41
+ api.notify("entityTouchMove", {
42
+ targetId: entity.targetIds[index],
43
+ position: v(...entity.positions[index]),
44
+ })
45
+ }
46
+ },
47
+
48
+ touchEnd(entity, { index }, api) {
49
+ if (entity.isSwiping) {
50
+ entity.isSwiping = false
51
+ }
52
+
53
+ if (entity.targetIds[index]) {
54
+ api.notify("entityTouchEnd", {
55
+ targetId: entity.targetIds[index],
56
+ position: v(...entity.positions[index]),
57
+ })
58
+ entity.targetIds[index] = undefined
59
+ } else {
60
+ api.notify("sceneTouchEnd", v(...entity.positions[index]))
61
+ }
62
+ },
63
+ }
64
+ }
65
+
66
+ export function trackTouch(parent, api, toGamePosition) {
67
+ const handleTouchStart = createHandler(
68
+ "touchStart",
69
+ parent,
70
+ api,
71
+ toGamePosition,
72
+ )
73
+ const handleTouchMove = createHandler(
74
+ "touchMove",
75
+ parent,
76
+ api,
77
+ toGamePosition,
78
+ )
79
+ const handleTouchEnd = createHandler("touchEnd", parent, api, toGamePosition)
80
+
81
+ return {
82
+ onTouchStart: handleTouchStart,
83
+ onTouchMove: handleTouchMove,
84
+ onTouchCancel: handleTouchEnd,
85
+ onTouchEnd: handleTouchEnd,
86
+ }
87
+ }
88
+
89
+ export function createTouch() {
90
+ return {
91
+ type: "touch",
92
+ layer: 999, // A high layer value to ensure it's always rendered on top
93
+ positions: [],
94
+ collisions: {
95
+ bounds: { shape: "point" },
96
+ touch: { shape: "circle", radius: 44 },
97
+ },
98
+ targetIds: [],
99
+ }
100
+ }
101
+
102
+ function createHandler(type, parent, api, toGamePosition) {
103
+ return (event) => {
104
+ event.preventDefault()
105
+ event.stopPropagation()
106
+
107
+ if (parent == null) {
108
+ return
109
+ }
110
+
111
+ // touchend doesn't have touches anymore, but it has changedTouches
112
+ const touches = event.touches.length ? event.touches : event.changedTouches
113
+
114
+ Array.from(touches).forEach((touch, index) => {
115
+ const { clientX, clientY } = touch
116
+
117
+ const position = toGamePosition(clientX, clientY)
118
+ api.notify(type, { index, position })
119
+ })
120
+ }
121
+ }
@@ -12,5 +12,8 @@ export const coreEvents = [
12
12
  "inputRelease",
13
13
  "mouseMove",
14
14
  "mouseClick",
15
+ "touchStart",
16
+ "touchMove",
17
+ "touchEnd",
15
18
  "spriteAnimationEnd",
16
19
  ]