@inglorious/engine 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inglorious/engine",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
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",
@@ -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
@@ -1,8 +1,10 @@
1
1
  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
+ import { v } from "@inglorious/utils/v.js"
4
5
 
5
6
  const NO_Y = 0
7
+ const HALF = 2
6
8
 
7
9
  export function mouse() {
8
10
  return {
@@ -33,10 +35,10 @@ export function mouse() {
33
35
  }
34
36
  }
35
37
 
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)
38
+ export function trackMouse(parent, api) {
39
+ const handleMouseMove = createHandler("mouseMove", parent, api)
40
+ const handleClick = createHandler("mouseClick", parent, api)
41
+ const handleWheel = createHandler("mouseWheel", parent, api)
40
42
 
41
43
  return {
42
44
  onMouseMove: handleMouseMove,
@@ -56,30 +58,50 @@ export function createMouse(overrides = {}) {
56
58
 
57
59
  function createHandler(type, parent, api) {
58
60
  return (event) => {
61
+ event.preventDefault()
59
62
  event.stopPropagation()
60
63
 
61
64
  if (parent == null) {
62
65
  return
63
66
  }
64
67
 
65
- // For wheel events, the payload is different from other mouse events.
66
68
  if (type === "mouseWheel") {
67
- api.notify(type, { deltaY: event.deltaY })
69
+ api.notify(type, event.deltaY)
68
70
  return
69
71
  }
70
72
 
71
- // For move and click events, the payload is the calculated position.
72
- const payload = calculatePosition(event, parent)
73
+ const payload = calculatePosition(event, parent, api)
73
74
  api.notify(type, payload)
74
75
  }
75
76
  }
76
77
 
77
- function calculatePosition(event, parent) {
78
+ function calculatePosition(event, parent, api) {
78
79
  const { clientX, clientY } = event
79
- const { left, bottom } = parent.getBoundingClientRect()
80
+ const {
81
+ left,
82
+ bottom,
83
+ width: canvasWidth,
84
+ height: canvasHeight,
85
+ } = parent.getBoundingClientRect()
80
86
 
81
87
  const x = clientX - left
82
- const z = bottom - clientY
88
+ const y = bottom - clientY
83
89
 
84
- return [x, NO_Y, z]
90
+ const game = api.getEntity("game")
91
+ const [gameWidth, gameHeight] = game.size
92
+
93
+ const scaleX = canvasWidth / gameWidth
94
+ const scaleY = canvasHeight / gameHeight
95
+ const scale = Math.min(scaleX, scaleY)
96
+
97
+ const scaledGameWidth = gameWidth * scale
98
+ const scaledGameHeight = gameHeight * scale
99
+
100
+ const offsetX = (canvasWidth - scaledGameWidth) / HALF
101
+ const offsetY = (canvasHeight - scaledGameHeight) / HALF
102
+
103
+ const gameX = (x - offsetX) / scale
104
+ const gameY = (y - offsetY) / scale
105
+
106
+ return v(gameX, NO_Y, gameY)
85
107
  }
@@ -0,0 +1,127 @@
1
+ import { findCollision } from "@inglorious/engine/collision/detection.js"
2
+ import { clampToBounds } from "@inglorious/engine/physics/bounds.js"
3
+ import { magnitude, zero } 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 NO_Y = 0
8
+ const MOVEMENT_THRESHOLD = 5
9
+ const HALF = 2
10
+
11
+ export function touch() {
12
+ return {
13
+ create(entity, entityId) {
14
+ if (entityId !== entity.id) return
15
+
16
+ entity.collisions ??= {}
17
+ entity.collisions.bounds ??= { shape: "point" }
18
+ },
19
+
20
+ touchStart(entity, position) {
21
+ entity.isSwiping = false
22
+ entity.position = position
23
+ },
24
+
25
+ touchMove(entity, position, api) {
26
+ const game = api.getEntity("game")
27
+
28
+ const delta = subtract(position, entity.position)
29
+
30
+ if (magnitude(delta) > MOVEMENT_THRESHOLD) {
31
+ entity.isSwiping = true
32
+ }
33
+
34
+ entity.position = position
35
+
36
+ clampToBounds(entity, game.size)
37
+ },
38
+
39
+ touchEnd(entity, _, api) {
40
+ if (entity.isSwiping) {
41
+ api.notify("swipe", v(...entity.position))
42
+ entity.isSwiping = false
43
+ return
44
+ }
45
+
46
+ const entities = api.getEntities()
47
+ const clickedEntity = findCollision(entity, entities)
48
+ if (clickedEntity) {
49
+ api.notify("entityTouch", clickedEntity.id)
50
+ } else {
51
+ api.notify("sceneTouch", v(...entity.position))
52
+ }
53
+ },
54
+ }
55
+ }
56
+
57
+ export function trackTouch(parent, api) {
58
+ const handleTouchStart = createHandler("touchStart", parent, api)
59
+ const handleTouchMove = createHandler("touchMove", parent, api)
60
+ const handleTouchEnd = createHandler("touchEnd", parent, api)
61
+
62
+ return {
63
+ onTouchStart: handleTouchStart,
64
+ onTouchMove: handleTouchMove,
65
+ onTouchEnd: handleTouchEnd,
66
+ }
67
+ }
68
+
69
+ export function createTouch(overrides = {}) {
70
+ return {
71
+ type: "touch",
72
+ layer: 999, // A high layer value to ensure it's always rendered on top
73
+ position: zero(),
74
+ ...overrides,
75
+ }
76
+ }
77
+
78
+ function createHandler(type, parent, api) {
79
+ return (event) => {
80
+ event.preventDefault()
81
+ event.stopPropagation()
82
+
83
+ if (parent == null) {
84
+ return
85
+ }
86
+
87
+ if (type === "touchEnd") {
88
+ api.notify(type)
89
+ return
90
+ }
91
+
92
+ const payload = calculatePosition(event, parent, api)
93
+ api.notify(type, payload)
94
+ }
95
+ }
96
+
97
+ function calculatePosition(event, parent, api) {
98
+ const [touch] = event.touches
99
+ const { clientX, clientY } = touch
100
+ const {
101
+ left,
102
+ bottom,
103
+ width: canvasWidth,
104
+ height: canvasHeight,
105
+ } = parent.getBoundingClientRect()
106
+
107
+ const x = clientX - left
108
+ const y = bottom - clientY
109
+
110
+ const game = api.getEntity("game")
111
+ const [gameWidth, gameHeight] = game.size
112
+
113
+ const scaleX = canvasWidth / gameWidth
114
+ const scaleY = canvasHeight / gameHeight
115
+ const scale = Math.min(scaleX, scaleY)
116
+
117
+ const scaledGameWidth = gameWidth * scale
118
+ const scaledGameHeight = gameHeight * scale
119
+
120
+ const offsetX = (canvasWidth - scaledGameWidth) / HALF
121
+ const offsetY = (canvasHeight - scaledGameHeight) / HALF
122
+
123
+ const gameX = (x - offsetX) / scale
124
+ const gameY = (y - offsetY) / scale
125
+
126
+ return v(gameX, NO_Y, gameY)
127
+ }
@@ -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
  ]