rngine 0.6.0 → 0.7.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
@@ -21,28 +21,33 @@ configure({
21
21
  entities: [
22
22
  {
23
23
  id: 'player',
24
- px: 400,
25
- py: 400,
26
- width: 40,
27
- height: 40,
28
- color: '#00ff00',
24
+ px: 420,
25
+ py: 420,
26
+ color: '#0f0',
27
+ shape: {
28
+ radius: 20,
29
+ },
29
30
  },
30
31
  {
31
32
  id: 'enemy_1',
32
- px: 100,
33
- py: 100,
34
- width: 40,
35
- height: 40,
36
- color: '#ff0000',
33
+ px: 120,
34
+ py: 120,
35
+ color: '#f00',
36
+ shape: {
37
+ width: 40,
38
+ height: 40,
39
+ },
37
40
  vx: 1000,
38
41
  },
39
42
  {
40
43
  id: 'enemy_2',
41
- px: 200,
42
- py: 200,
43
- width: 40,
44
- height: 40,
45
- color: '#ff0000',
44
+ px: 220,
45
+ py: 220,
46
+ color: '#f00',
47
+ shape: {
48
+ width: 40,
49
+ height: 40,
50
+ },
46
51
  vx: -1000,
47
52
  },
48
53
  ],
@@ -53,7 +58,10 @@ configure({
53
58
  onTick: (enemies) => {
54
59
  enemies.forEach((enemy) => {
55
60
  // reverse direction when reaching screen edges
56
- if (enemy.px <= 0 || enemy.px + enemy.width >= 800) {
61
+ if (
62
+ enemy.px - enemy.width / 2 <= 0 ||
63
+ enemy.px + enemy.width / 2 >= 800
64
+ ) {
57
65
  update({ id: enemy.id, vx: -enemy.vx });
58
66
  }
59
67
  });
@@ -70,7 +78,7 @@ export default function App() {
70
78
 
71
79
  ## Concepts
72
80
 
73
- **Entities** are the objects in your game world. Each entity has a position, size, color, and velocity. See [`Entity`](./src/nativeTypes.ts).
81
+ **Entities** are the objects in your game world. Each entity has a position, shape, color, and velocity. See [`Entity`](./src/nativeTypes.ts).
74
82
 
75
83
  **Systems** define your game logic. Each system optionally declares which entities it cares about via `entities`, which collision pairs to watch via `collisions`, or both. Systems run every tick receiving the resolved entities and any active collisions. See [`System`](./src/types.ts).
76
84
 
@@ -13,6 +13,7 @@ add_library(
13
13
  src/main/cpp/GameLoopJNI.cpp
14
14
  ../shared/GameLoop.cpp
15
15
  ../shared/GameMethods.cpp
16
+ ../shared/CollisionUtils.cpp
16
17
  )
17
18
 
18
19
  # Add Nitrogen specs :)
@@ -3,6 +3,7 @@
3
3
  #include <cstdint>
4
4
  #include <jni.h>
5
5
  #include <mutex>
6
+ #include <variant>
6
7
 
7
8
  extern "C" {
8
9
  JNIEXPORT jbyteArray JNICALL
@@ -46,14 +47,37 @@ Java_com_margelo_nitro_rngine_GameView_getSnapshot(JNIEnv *env, jobject) {
46
47
  }
47
48
 
48
49
  for (const auto &[_, entitySnapshot] : entitiesSnapshot) {
49
- const auto entitySnapshotLeft =
50
- static_cast<float>(entitySnapshot.px - (entitySnapshot.width / 2));
51
- const auto entitySnapshotRight =
52
- static_cast<float>(entitySnapshot.px + (entitySnapshot.width / 2));
53
- const auto entitySnapshotTop =
54
- static_cast<float>(entitySnapshot.py - (entitySnapshot.height / 2));
55
- const auto entitySnapshotBottom =
56
- static_cast<float>(entitySnapshot.py + (entitySnapshot.height / 2));
50
+ uint8_t shapeType{0};
51
+ float entitySnapshotLeft{0}, entitySnapshotRight{0}, entitySnapshotTop{0},
52
+ entitySnapshotBottom{0}, circleRadius{0};
53
+
54
+ std::visit(
55
+ [&](const auto &shape) {
56
+ using T = std::decay_t<decltype(shape)>;
57
+ if constexpr (std::is_same_v<T, margelo::nitro::rngine::Rect>) {
58
+ shapeType = 0;
59
+ entitySnapshotLeft =
60
+ static_cast<float>(entitySnapshot.px - shape.width / 2.0);
61
+ entitySnapshotRight =
62
+ static_cast<float>(entitySnapshot.px + shape.width / 2.0);
63
+ entitySnapshotTop =
64
+ static_cast<float>(entitySnapshot.py - shape.height / 2.0);
65
+ entitySnapshotBottom =
66
+ static_cast<float>(entitySnapshot.py + shape.height / 2.0);
67
+ } else {
68
+ shapeType = 1;
69
+ circleRadius = static_cast<float>(shape.radius);
70
+ entitySnapshotLeft =
71
+ static_cast<float>(entitySnapshot.px - shape.radius);
72
+ entitySnapshotRight =
73
+ static_cast<float>(entitySnapshot.px + shape.radius);
74
+ entitySnapshotTop =
75
+ static_cast<float>(entitySnapshot.py - shape.radius);
76
+ entitySnapshotBottom =
77
+ static_cast<float>(entitySnapshot.py + shape.radius);
78
+ }
79
+ },
80
+ entitySnapshot.shape);
57
81
 
58
82
  if (entitySnapshotRight < 0 || entitySnapshotLeft > screenSnapshot.width ||
59
83
  entitySnapshotBottom < 0 || entitySnapshotTop > screenSnapshot.height) {
@@ -65,10 +89,19 @@ Java_com_margelo_nitro_rngine_GameView_getSnapshot(JNIEnv *env, jobject) {
65
89
  const auto entitySnapshotAsset =
66
90
  static_cast<int32_t>(entitySnapshot.asset.value_or(0));
67
91
 
68
- writeFloat(entitySnapshotLeft);
69
- writeFloat(entitySnapshotRight);
70
- writeFloat(entitySnapshotTop);
71
- writeFloat(entitySnapshotBottom);
92
+ buffer.push_back(shapeType);
93
+
94
+ if (shapeType == 0) {
95
+ writeFloat(entitySnapshotLeft);
96
+ writeFloat(entitySnapshotRight);
97
+ writeFloat(entitySnapshotTop);
98
+ writeFloat(entitySnapshotBottom);
99
+ } else {
100
+ writeFloat(static_cast<float>(entitySnapshot.px));
101
+ writeFloat(static_cast<float>(entitySnapshot.py));
102
+ writeFloat(circleRadius);
103
+ }
104
+
72
105
  writeU32(entitySnapshotColor);
73
106
  writeI32(entitySnapshotAsset);
74
107
 
@@ -1,7 +1,7 @@
1
1
  package com.margelo.nitro.rngine
2
2
 
3
3
  import android.content.Context
4
- import android.graphics.Color
4
+ import android.graphics.Canvas
5
5
  import android.graphics.Paint
6
6
  import android.util.AttributeSet
7
7
  import android.view.SurfaceView
@@ -23,52 +23,93 @@ class GameView(
23
23
  var onDetached: () -> Unit = {}
24
24
 
25
25
  private val paint = Paint().apply {
26
- color = Color.TRANSPARENT
27
26
  style = Paint.Style.FILL
28
27
  }
29
28
 
30
- private fun drawRenderable(
31
- canvas: android.graphics.Canvas,
29
+ private fun drawAsset(
30
+ canvas: Canvas,
32
31
  left: Float,
33
32
  top: Float,
34
33
  right: Float,
35
34
  bottom: Float,
36
- color: Int,
37
35
  asset: Int,
38
36
  progress: Float?,
39
- clampedLeft: Float = left,
40
- clampedTop: Float = top,
41
- clampedRight: Float = right,
42
- clampedBottom: Float = bottom,
43
37
  ) {
44
- paint.color = color
45
- canvas.drawRect(clampedLeft, clampedTop, clampedRight, clampedBottom, paint)
46
-
47
- canvas.withClip(clampedLeft, clampedTop, clampedRight, clampedBottom) {
48
- withTranslation(left, top) {
49
- when (val resolvedAsset = GameAssets.getAsset(asset)) {
50
- is Asset.Svg -> {
51
- scale(
52
- (right - left) / resolvedAsset.picture.width,
53
- (bottom - top) / resolvedAsset.picture.height
54
- )
55
- drawPicture(resolvedAsset.picture)
56
- }
38
+ canvas.withTranslation(left, top) {
39
+ when (val resolvedAsset = GameAssets.getAsset(asset)) {
40
+ is Asset.Svg -> {
41
+ scale(
42
+ (right - left) / resolvedAsset.picture.width,
43
+ (bottom - top) / resolvedAsset.picture.height
44
+ )
45
+ drawPicture(resolvedAsset.picture)
46
+ }
57
47
 
58
- is Asset.Lottie -> {
59
- progress?.let {
60
- resolvedAsset.drawable.progress = it
61
- }
62
- resolvedAsset.drawable.setBounds(0, 0, (right - left).toInt(), (bottom - top).toInt())
63
- resolvedAsset.drawable.draw(canvas)
48
+ is Asset.Lottie -> {
49
+ progress?.let {
50
+ resolvedAsset.drawable.progress = it
64
51
  }
65
-
66
- null -> {}
52
+ resolvedAsset.drawable.setBounds(0, 0, (right - left).toInt(), (bottom - top).toInt())
53
+ resolvedAsset.drawable.draw(canvas)
67
54
  }
55
+
56
+ null -> {}
68
57
  }
69
58
  }
70
59
  }
71
60
 
61
+ private fun drawRect(
62
+ canvas: Canvas,
63
+ left: Float,
64
+ top: Float,
65
+ right: Float,
66
+ bottom: Float,
67
+ color: Int,
68
+ asset: Int,
69
+ progress: Float?,
70
+ ) {
71
+ paint.color = color
72
+ canvas.drawRect(left, top, right, bottom, paint)
73
+
74
+ drawAsset(
75
+ canvas,
76
+ left,
77
+ top,
78
+ right,
79
+ bottom,
80
+ asset,
81
+ progress
82
+ )
83
+ }
84
+
85
+ private fun drawCircle(
86
+ canvas: Canvas,
87
+ cx: Float,
88
+ cy: Float,
89
+ radius: Float,
90
+ color: Int,
91
+ asset: Int,
92
+ progress: Float?,
93
+ ) {
94
+ val left = cx - radius
95
+ val top = cy - radius
96
+ val right = cx + radius
97
+ val bottom = cy + radius
98
+
99
+ paint.color = color
100
+ canvas.drawCircle(cx, cy, radius, paint)
101
+
102
+ drawAsset(
103
+ canvas,
104
+ left,
105
+ top,
106
+ right,
107
+ bottom,
108
+ asset,
109
+ progress,
110
+ )
111
+ }
112
+
72
113
  init {
73
114
  addOnAttachStateChangeListener(
74
115
  object : OnAttachStateChangeListener {
@@ -91,7 +132,7 @@ class GameView(
91
132
  val screenRight = screenLeft + snapshot.screen.width * scale
92
133
  val screenBottom = screenTop + snapshot.screen.height * scale
93
134
 
94
- drawRenderable(
135
+ drawRect(
95
136
  canvas,
96
137
  screenLeft,
97
138
  screenTop,
@@ -102,31 +143,44 @@ class GameView(
102
143
  snapshot.screen.progress,
103
144
  )
104
145
 
105
- snapshot.rects.forEach { rect ->
106
- val left = rect.left * scale + screenLeft
107
- val top = rect.top * scale + screenTop
108
- val right = rect.right * scale + screenLeft
109
- val bottom = rect.bottom * scale + screenTop
110
-
111
- val clampedLeft = left.coerceAtLeast(screenLeft)
112
- val clampedTop = top.coerceAtLeast(screenTop)
113
- val clampedRight = right.coerceAtMost(screenLeft + snapshot.screen.width * scale)
114
- val clampedBottom = bottom.coerceAtMost(screenTop + snapshot.screen.height * scale)
115
-
116
- drawRenderable(
117
- canvas,
118
- left,
119
- top,
120
- right,
121
- bottom,
122
- rect.color,
123
- rect.asset,
124
- rect.progress,
125
- clampedLeft,
126
- clampedTop,
127
- clampedRight,
128
- clampedBottom
129
- )
146
+ canvas.withClip(screenLeft, screenTop, screenRight, screenBottom) {
147
+ snapshot.shapes.forEach { shape ->
148
+ when (shape) {
149
+ is Shape.Rect -> {
150
+ val left = shape.left * scale + screenLeft
151
+ val top = shape.top * scale + screenTop
152
+ val right = shape.right * scale + screenLeft
153
+ val bottom = shape.bottom * scale + screenTop
154
+
155
+ drawRect(
156
+ canvas,
157
+ left,
158
+ top,
159
+ right,
160
+ bottom,
161
+ shape.color,
162
+ shape.asset,
163
+ shape.progress,
164
+ )
165
+ }
166
+
167
+ is Shape.Circle -> {
168
+ val cx = shape.px * scale + screenLeft
169
+ val cy = shape.py * scale + screenTop
170
+ val radius = shape.radius * scale
171
+
172
+ drawCircle(
173
+ canvas,
174
+ cx,
175
+ cy,
176
+ radius,
177
+ shape.color,
178
+ shape.asset,
179
+ shape.progress,
180
+ )
181
+ }
182
+ }
183
+ }
130
184
  }
131
185
  holder.unlockCanvasAndPost(canvas)
132
186
  }
@@ -0,0 +1,26 @@
1
+ package com.margelo.nitro.rngine
2
+
3
+ sealed class Shape(
4
+ val color: Int,
5
+ val asset: Int,
6
+ val progress: Float?,
7
+ ) {
8
+ class Rect(
9
+ val left: Float,
10
+ val right: Float,
11
+ val top: Float,
12
+ val bottom: Float,
13
+ color: Int,
14
+ asset: Int,
15
+ progress: Float?,
16
+ ) : Shape(color, asset, progress)
17
+
18
+ class Circle(
19
+ val px: Float,
20
+ val py: Float,
21
+ val radius: Float,
22
+ color: Int,
23
+ asset: Int,
24
+ progress: Float?,
25
+ ) : Shape(color, asset, progress)
26
+ }
@@ -1,3 +1,3 @@
1
1
  package com.margelo.nitro.rngine
2
2
 
3
- data class Snapshot(val screen: Screen, val rects: List<Rect>)
3
+ data class Snapshot(val screen: Screen, val shapes: List<Shape>)
@@ -1,5 +1,6 @@
1
1
  package com.margelo.nitro.rngine
2
2
 
3
+ import android.util.Log
3
4
  import java.nio.ByteBuffer
4
5
  import java.nio.ByteOrder
5
6
 
@@ -14,20 +15,39 @@ object SnapshotSerializer {
14
15
  val progress = if (asset < 0) buffer.float else null
15
16
 
16
17
  val screen = Screen(width, height, color, asset, progress)
17
- val rects = ArrayList<Rect>()
18
-
19
- while (buffer.remaining() >= 24) {
20
- val left = buffer.float
21
- val right = buffer.float
22
- val top = buffer.float
23
- val bottom = buffer.float
24
- val color = buffer.int
25
- val asset = buffer.int
26
- val progress = if (asset < 0) buffer.float else null
27
-
28
- rects.add(Rect(left, right, top, bottom, color, asset, progress))
18
+ val shapes = ArrayList<Shape>()
19
+
20
+ while (buffer.hasRemaining()) {
21
+ when (val shapeType = buffer.get().toInt()) {
22
+ 0 -> {
23
+ val left = buffer.float
24
+ val right = buffer.float
25
+ val top = buffer.float
26
+ val bottom = buffer.float
27
+
28
+ val color = buffer.int
29
+ val asset = buffer.int
30
+ val progress = if (asset < 0) buffer.float else null
31
+
32
+ shapes.add(Shape.Rect(left, right, top, bottom, color, asset, progress))
33
+ }
34
+
35
+ 1 -> {
36
+ val px = buffer.float
37
+ val py = buffer.float
38
+ val radius = buffer.float
39
+
40
+ val color = buffer.int
41
+ val asset = buffer.int
42
+ val progress = if (asset < 0) buffer.float else null
43
+
44
+ shapes.add(Shape.Circle(px, py, radius, color, asset, progress))
45
+ }
46
+
47
+ else -> Log.e("SnapshotSerializer", "Unknown shapeType: $shapeType")
48
+ }
29
49
  }
30
50
 
31
- return Snapshot(screen, rects)
51
+ return Snapshot(screen, shapes)
32
52
  }
33
53
  }
@@ -4,12 +4,20 @@ interface Positioned {
4
4
  /** Y position in game units. */
5
5
  py: number;
6
6
  }
7
- interface Shaped {
7
+ interface Rect {
8
8
  /** Width in game units. */
9
9
  width: number;
10
10
  /** Height in game units. */
11
11
  height: number;
12
12
  }
13
+ interface Circle {
14
+ /** Radius in game units. */
15
+ radius: number;
16
+ }
17
+ interface Shaped {
18
+ /** Shape of the entity. */
19
+ shape: Rect | Circle;
20
+ }
13
21
  interface Renderable {
14
22
  /** Fill color as a hex string e.g. `'#00ff00'`. */
15
23
  color?: string;
@@ -19,12 +27,16 @@ interface Renderable {
19
27
  progress?: number;
20
28
  }
21
29
  interface Kinematic {
22
- /** Velocity on the X axis in game units per second. */
30
+ /** Horizontal velocity in game units per second. */
23
31
  vx?: number;
24
- /** Velocity on the Y axis in game units per second. */
32
+ /** Vertical velocity in game units per second. */
25
33
  vy?: number;
34
+ /** Horizontal acceleration in game units per second squared. */
35
+ ax?: number;
36
+ /** Vertical acceleration in game units per second squared. */
37
+ ay?: number;
26
38
  }
27
- export interface Screen extends Shaped, Renderable {
39
+ export interface Screen extends Rect, Renderable {
28
40
  }
29
41
  export interface Entity extends Positioned, Shaped, Renderable, Kinematic {
30
42
  /** Unique identifier. Use `_` as a separator for group queries e.g. `'enemy_1'`. */
@@ -1 +1 @@
1
- {"version":3,"file":"nativeTypes.d.ts","sourceRoot":"","sources":["../../../src/nativeTypes.ts"],"names":[],"mappings":"AAAA,UAAU,UAAU;IAClB,gCAAgC;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,UAAU,MAAM;IACd,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,UAAU;IAClB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,SAAS;IACjB,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,MAAO,SAAQ,MAAM,EAAE,UAAU;CAAG;AAErD,MAAM,WAAW,MAAO,SAAQ,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS;IACvE,oFAAoF;IACpF,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,YAAa,SAAQ,OAAO,CAC3C,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,CAC7C;IACC,6DAA6D;IAC7D,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,CAAC,EAAE,MAAM,CAAC;IACV,yDAAyD;IACzD,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,SAAS;IACxB,wDAAwD;IACxD,CAAC,EAAE,MAAM,CAAC;IACV,yDAAyD;IACzD,CAAC,EAAE,MAAM,CAAC;IACV,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,MAAM;IACrB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,mEAAmE;IACnE,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,MAAM,CAAC;CACjE"}
1
+ {"version":3,"file":"nativeTypes.d.ts","sourceRoot":"","sources":["../../../src/nativeTypes.ts"],"names":[],"mappings":"AAAA,UAAU,UAAU;IAClB,gCAAgC;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,UAAU,IAAI;IACZ,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,MAAM;IACd,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,MAAM;IACd,2BAA2B;IAC3B,KAAK,EAAE,IAAI,GAAG,MAAM,CAAC;CACtB;AAED,UAAU,UAAU;IAClB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,SAAS;IACjB,oDAAoD;IACpD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,kDAAkD;IAClD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gEAAgE;IAChE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,8DAA8D;IAC9D,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,MAAO,SAAQ,IAAI,EAAE,UAAU;CAAG;AAEnD,MAAM,WAAW,MAAO,SAAQ,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS;IACvE,oFAAoF;IACpF,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,YAAa,SAAQ,OAAO,CAC3C,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,CAC7C;IACC,6DAA6D;IAC7D,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,CAAC,EAAE,MAAM,CAAC;IACV,yDAAyD;IACzD,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,SAAS;IACxB,wDAAwD;IACxD,CAAC,EAAE,MAAM,CAAC;IACV,yDAAyD;IACzD,CAAC,EAAE,MAAM,CAAC;IACV,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,MAAM;IACrB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,mEAAmE;IACnE,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,MAAM,CAAC;CACjE"}
@@ -0,0 +1,83 @@
1
+ ///
2
+ /// Circle.hpp
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ #pragma once
9
+
10
+ #if __has_include(<NitroModules/JSIConverter.hpp>)
11
+ #include <NitroModules/JSIConverter.hpp>
12
+ #else
13
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
14
+ #endif
15
+ #if __has_include(<NitroModules/NitroDefines.hpp>)
16
+ #include <NitroModules/NitroDefines.hpp>
17
+ #else
18
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
19
+ #endif
20
+ #if __has_include(<NitroModules/JSIHelpers.hpp>)
21
+ #include <NitroModules/JSIHelpers.hpp>
22
+ #else
23
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
24
+ #endif
25
+ #if __has_include(<NitroModules/PropNameIDCache.hpp>)
26
+ #include <NitroModules/PropNameIDCache.hpp>
27
+ #else
28
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
29
+ #endif
30
+
31
+
32
+
33
+
34
+
35
+ namespace margelo::nitro::rngine {
36
+
37
+ /**
38
+ * A struct which can be represented as a JavaScript object (Circle).
39
+ */
40
+ struct Circle final {
41
+ public:
42
+ double radius SWIFT_PRIVATE;
43
+
44
+ public:
45
+ Circle() = default;
46
+ explicit Circle(double radius): radius(radius) {}
47
+
48
+ public:
49
+ friend bool operator==(const Circle& lhs, const Circle& rhs) = default;
50
+ };
51
+
52
+ } // namespace margelo::nitro::rngine
53
+
54
+ namespace margelo::nitro {
55
+
56
+ // C++ Circle <> JS Circle (object)
57
+ template <>
58
+ struct JSIConverter<margelo::nitro::rngine::Circle> final {
59
+ static inline margelo::nitro::rngine::Circle fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
60
+ jsi::Object obj = arg.asObject(runtime);
61
+ return margelo::nitro::rngine::Circle(
62
+ JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "radius")))
63
+ );
64
+ }
65
+ static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::rngine::Circle& arg) {
66
+ jsi::Object obj(runtime);
67
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "radius"), JSIConverter<double>::toJSI(runtime, arg.radius));
68
+ return obj;
69
+ }
70
+ static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
71
+ if (!value.isObject()) {
72
+ return false;
73
+ }
74
+ jsi::Object obj = value.getObject(runtime);
75
+ if (!nitro::isPlainObject(runtime, obj)) {
76
+ return false;
77
+ }
78
+ if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "radius")))) return false;
79
+ return true;
80
+ }
81
+ };
82
+
83
+ } // namespace margelo::nitro
@@ -28,9 +28,15 @@
28
28
  #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
29
29
  #endif
30
30
 
31
-
31
+ // Forward declaration of `Rect` to properly resolve imports.
32
+ namespace margelo::nitro::rngine { struct Rect; }
33
+ // Forward declaration of `Circle` to properly resolve imports.
34
+ namespace margelo::nitro::rngine { struct Circle; }
32
35
 
33
36
  #include <string>
37
+ #include "Rect.hpp"
38
+ #include "Circle.hpp"
39
+ #include <variant>
34
40
  #include <optional>
35
41
 
36
42
  namespace margelo::nitro::rngine {
@@ -43,17 +49,18 @@ namespace margelo::nitro::rngine {
43
49
  std::string id SWIFT_PRIVATE;
44
50
  double px SWIFT_PRIVATE;
45
51
  double py SWIFT_PRIVATE;
46
- double width SWIFT_PRIVATE;
47
- double height SWIFT_PRIVATE;
52
+ std::variant<Rect, Circle> shape SWIFT_PRIVATE;
48
53
  std::optional<std::string> color SWIFT_PRIVATE;
49
54
  std::optional<double> asset SWIFT_PRIVATE;
50
55
  std::optional<double> progress SWIFT_PRIVATE;
51
56
  std::optional<double> vx SWIFT_PRIVATE;
52
57
  std::optional<double> vy SWIFT_PRIVATE;
58
+ std::optional<double> ax SWIFT_PRIVATE;
59
+ std::optional<double> ay SWIFT_PRIVATE;
53
60
 
54
61
  public:
55
62
  Entity() = default;
56
- explicit Entity(std::string id, double px, double py, double width, double height, std::optional<std::string> color, std::optional<double> asset, std::optional<double> progress, std::optional<double> vx, std::optional<double> vy): id(id), px(px), py(py), width(width), height(height), color(color), asset(asset), progress(progress), vx(vx), vy(vy) {}
63
+ explicit Entity(std::string id, double px, double py, std::variant<Rect, Circle> shape, std::optional<std::string> color, std::optional<double> asset, std::optional<double> progress, std::optional<double> vx, std::optional<double> vy, std::optional<double> ax, std::optional<double> ay): id(id), px(px), py(py), shape(shape), color(color), asset(asset), progress(progress), vx(vx), vy(vy), ax(ax), ay(ay) {}
57
64
 
58
65
  public:
59
66
  friend bool operator==(const Entity& lhs, const Entity& rhs) = default;
@@ -72,13 +79,14 @@ namespace margelo::nitro {
72
79
  JSIConverter<std::string>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "id"))),
73
80
  JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "px"))),
74
81
  JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "py"))),
75
- JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width"))),
76
- JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height"))),
82
+ JSIConverter<std::variant<margelo::nitro::rngine::Rect, margelo::nitro::rngine::Circle>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "shape"))),
77
83
  JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "color"))),
78
84
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "asset"))),
79
85
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "progress"))),
80
86
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vx"))),
81
- JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vy")))
87
+ JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vy"))),
88
+ JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "ax"))),
89
+ JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "ay")))
82
90
  );
83
91
  }
84
92
  static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::rngine::Entity& arg) {
@@ -86,13 +94,14 @@ namespace margelo::nitro {
86
94
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "id"), JSIConverter<std::string>::toJSI(runtime, arg.id));
87
95
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "px"), JSIConverter<double>::toJSI(runtime, arg.px));
88
96
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "py"), JSIConverter<double>::toJSI(runtime, arg.py));
89
- obj.setProperty(runtime, PropNameIDCache::get(runtime, "width"), JSIConverter<double>::toJSI(runtime, arg.width));
90
- obj.setProperty(runtime, PropNameIDCache::get(runtime, "height"), JSIConverter<double>::toJSI(runtime, arg.height));
97
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "shape"), JSIConverter<std::variant<margelo::nitro::rngine::Rect, margelo::nitro::rngine::Circle>>::toJSI(runtime, arg.shape));
91
98
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "color"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.color));
92
99
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "asset"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.asset));
93
100
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "progress"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.progress));
94
101
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "vx"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.vx));
95
102
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "vy"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.vy));
103
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "ax"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.ax));
104
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "ay"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.ay));
96
105
  return obj;
97
106
  }
98
107
  static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
@@ -106,13 +115,14 @@ namespace margelo::nitro {
106
115
  if (!JSIConverter<std::string>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "id")))) return false;
107
116
  if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "px")))) return false;
108
117
  if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "py")))) return false;
109
- if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width")))) return false;
110
- if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height")))) return false;
118
+ if (!JSIConverter<std::variant<margelo::nitro::rngine::Rect, margelo::nitro::rngine::Circle>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "shape")))) return false;
111
119
  if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "color")))) return false;
112
120
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "asset")))) return false;
113
121
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "progress")))) return false;
114
122
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vx")))) return false;
115
123
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vy")))) return false;
124
+ if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "ax")))) return false;
125
+ if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "ay")))) return false;
116
126
  return true;
117
127
  }
118
128
  };
@@ -28,10 +28,16 @@
28
28
  #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
29
29
  #endif
30
30
 
31
-
31
+ // Forward declaration of `Rect` to properly resolve imports.
32
+ namespace margelo::nitro::rngine { struct Rect; }
33
+ // Forward declaration of `Circle` to properly resolve imports.
34
+ namespace margelo::nitro::rngine { struct Circle; }
32
35
 
33
36
  #include <string>
34
37
  #include <optional>
38
+ #include "Rect.hpp"
39
+ #include "Circle.hpp"
40
+ #include <variant>
35
41
 
36
42
  namespace margelo::nitro::rngine {
37
43
 
@@ -43,17 +49,18 @@ namespace margelo::nitro::rngine {
43
49
  std::string id SWIFT_PRIVATE;
44
50
  std::optional<double> px SWIFT_PRIVATE;
45
51
  std::optional<double> py SWIFT_PRIVATE;
46
- std::optional<double> width SWIFT_PRIVATE;
47
- std::optional<double> height SWIFT_PRIVATE;
52
+ std::optional<std::variant<Rect, Circle>> shape SWIFT_PRIVATE;
48
53
  std::optional<std::string> color SWIFT_PRIVATE;
49
54
  std::optional<double> asset SWIFT_PRIVATE;
50
55
  std::optional<double> progress SWIFT_PRIVATE;
51
56
  std::optional<double> vx SWIFT_PRIVATE;
52
57
  std::optional<double> vy SWIFT_PRIVATE;
58
+ std::optional<double> ax SWIFT_PRIVATE;
59
+ std::optional<double> ay SWIFT_PRIVATE;
53
60
 
54
61
  public:
55
62
  EntityUpdate() = default;
56
- explicit EntityUpdate(std::string id, std::optional<double> px, std::optional<double> py, std::optional<double> width, std::optional<double> height, std::optional<std::string> color, std::optional<double> asset, std::optional<double> progress, std::optional<double> vx, std::optional<double> vy): id(id), px(px), py(py), width(width), height(height), color(color), asset(asset), progress(progress), vx(vx), vy(vy) {}
63
+ explicit EntityUpdate(std::string id, std::optional<double> px, std::optional<double> py, std::optional<std::variant<Rect, Circle>> shape, std::optional<std::string> color, std::optional<double> asset, std::optional<double> progress, std::optional<double> vx, std::optional<double> vy, std::optional<double> ax, std::optional<double> ay): id(id), px(px), py(py), shape(shape), color(color), asset(asset), progress(progress), vx(vx), vy(vy), ax(ax), ay(ay) {}
57
64
 
58
65
  public:
59
66
  friend bool operator==(const EntityUpdate& lhs, const EntityUpdate& rhs) = default;
@@ -72,13 +79,14 @@ namespace margelo::nitro {
72
79
  JSIConverter<std::string>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "id"))),
73
80
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "px"))),
74
81
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "py"))),
75
- JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width"))),
76
- JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height"))),
82
+ JSIConverter<std::optional<std::variant<margelo::nitro::rngine::Rect, margelo::nitro::rngine::Circle>>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "shape"))),
77
83
  JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "color"))),
78
84
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "asset"))),
79
85
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "progress"))),
80
86
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vx"))),
81
- JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vy")))
87
+ JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vy"))),
88
+ JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "ax"))),
89
+ JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "ay")))
82
90
  );
83
91
  }
84
92
  static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::rngine::EntityUpdate& arg) {
@@ -86,13 +94,14 @@ namespace margelo::nitro {
86
94
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "id"), JSIConverter<std::string>::toJSI(runtime, arg.id));
87
95
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "px"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.px));
88
96
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "py"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.py));
89
- obj.setProperty(runtime, PropNameIDCache::get(runtime, "width"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.width));
90
- obj.setProperty(runtime, PropNameIDCache::get(runtime, "height"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.height));
97
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "shape"), JSIConverter<std::optional<std::variant<margelo::nitro::rngine::Rect, margelo::nitro::rngine::Circle>>>::toJSI(runtime, arg.shape));
91
98
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "color"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.color));
92
99
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "asset"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.asset));
93
100
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "progress"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.progress));
94
101
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "vx"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.vx));
95
102
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "vy"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.vy));
103
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "ax"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.ax));
104
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "ay"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.ay));
96
105
  return obj;
97
106
  }
98
107
  static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
@@ -106,13 +115,14 @@ namespace margelo::nitro {
106
115
  if (!JSIConverter<std::string>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "id")))) return false;
107
116
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "px")))) return false;
108
117
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "py")))) return false;
109
- if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width")))) return false;
110
- if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height")))) return false;
118
+ if (!JSIConverter<std::optional<std::variant<margelo::nitro::rngine::Rect, margelo::nitro::rngine::Circle>>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "shape")))) return false;
111
119
  if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "color")))) return false;
112
120
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "asset")))) return false;
113
121
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "progress")))) return false;
114
122
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vx")))) return false;
115
123
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "vy")))) return false;
124
+ if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "ax")))) return false;
125
+ if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "ay")))) return false;
116
126
  return true;
117
127
  }
118
128
  };
@@ -0,0 +1,87 @@
1
+ ///
2
+ /// Rect.hpp
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ #pragma once
9
+
10
+ #if __has_include(<NitroModules/JSIConverter.hpp>)
11
+ #include <NitroModules/JSIConverter.hpp>
12
+ #else
13
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
14
+ #endif
15
+ #if __has_include(<NitroModules/NitroDefines.hpp>)
16
+ #include <NitroModules/NitroDefines.hpp>
17
+ #else
18
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
19
+ #endif
20
+ #if __has_include(<NitroModules/JSIHelpers.hpp>)
21
+ #include <NitroModules/JSIHelpers.hpp>
22
+ #else
23
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
24
+ #endif
25
+ #if __has_include(<NitroModules/PropNameIDCache.hpp>)
26
+ #include <NitroModules/PropNameIDCache.hpp>
27
+ #else
28
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
29
+ #endif
30
+
31
+
32
+
33
+
34
+
35
+ namespace margelo::nitro::rngine {
36
+
37
+ /**
38
+ * A struct which can be represented as a JavaScript object (Rect).
39
+ */
40
+ struct Rect final {
41
+ public:
42
+ double width SWIFT_PRIVATE;
43
+ double height SWIFT_PRIVATE;
44
+
45
+ public:
46
+ Rect() = default;
47
+ explicit Rect(double width, double height): width(width), height(height) {}
48
+
49
+ public:
50
+ friend bool operator==(const Rect& lhs, const Rect& rhs) = default;
51
+ };
52
+
53
+ } // namespace margelo::nitro::rngine
54
+
55
+ namespace margelo::nitro {
56
+
57
+ // C++ Rect <> JS Rect (object)
58
+ template <>
59
+ struct JSIConverter<margelo::nitro::rngine::Rect> final {
60
+ static inline margelo::nitro::rngine::Rect fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
61
+ jsi::Object obj = arg.asObject(runtime);
62
+ return margelo::nitro::rngine::Rect(
63
+ JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width"))),
64
+ JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height")))
65
+ );
66
+ }
67
+ static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::rngine::Rect& arg) {
68
+ jsi::Object obj(runtime);
69
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "width"), JSIConverter<double>::toJSI(runtime, arg.width));
70
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "height"), JSIConverter<double>::toJSI(runtime, arg.height));
71
+ return obj;
72
+ }
73
+ static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
74
+ if (!value.isObject()) {
75
+ return false;
76
+ }
77
+ jsi::Object obj = value.getObject(runtime);
78
+ if (!nitro::isPlainObject(runtime, obj)) {
79
+ return false;
80
+ }
81
+ if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width")))) return false;
82
+ if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height")))) return false;
83
+ return true;
84
+ }
85
+ };
86
+
87
+ } // namespace margelo::nitro
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rngine",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "description": "React Native 2D game engine powered by Nitro Modules",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -0,0 +1,67 @@
1
+ #include "CollisionUtils.hpp"
2
+
3
+ namespace margelo::nitro::rngine::CollisionUtils {
4
+ std::optional<double> overlap(const Rect &a, double ax, double ay,
5
+ const Rect &b, double bx, double by) {
6
+
7
+ double aLeft = ax - a.width / 2.0, aRight = ax + a.width / 2.0;
8
+ double aTop = ay - a.height / 2.0, aBottom = ay + a.height / 2.0;
9
+ double bLeft = bx - b.width / 2.0, bRight = bx + b.width / 2.0;
10
+ double bTop = by - b.height / 2.0, bBottom = by + b.height / 2.0;
11
+
12
+ double overlapX = std::min(aRight, bRight) - std::max(aLeft, bLeft);
13
+ double overlapY = std::min(aBottom, bBottom) - std::max(aTop, bTop);
14
+
15
+ if (overlapX > 0 && overlapY > 0)
16
+ return std::min(overlapX, overlapY);
17
+ return std::nullopt;
18
+ }
19
+
20
+ std::optional<double> overlap(const Circle &a, double ax, double ay,
21
+ const Circle &b, double bx, double by) {
22
+ double dx = bx - ax, dy = by - ay;
23
+ double dist = std::sqrt(dx * dx + dy * dy);
24
+ double depth = (a.radius + b.radius) - dist;
25
+
26
+ if (depth > 0)
27
+ return depth;
28
+ return std::nullopt;
29
+ }
30
+
31
+ std::optional<double> overlap(const Rect &a, double ax, double ay,
32
+ const Circle &b, double bx, double by) {
33
+ double left = ax - a.width / 2.0, right = ax + a.width / 2.0;
34
+ double top = ay - a.height / 2.0, bottom = ay + a.height / 2.0;
35
+
36
+ double closestX = std::clamp(bx, left, right);
37
+ double closestY = std::clamp(by, top, bottom);
38
+
39
+ double dx = bx - closestX, dy = by - closestY;
40
+ double distSq = dx * dx + dy * dy;
41
+
42
+ if (distSq >= b.radius * b.radius)
43
+ return std::nullopt;
44
+
45
+ double dist = std::sqrt(distSq);
46
+ return b.radius - dist;
47
+ }
48
+
49
+ std::optional<double> overlap(const Circle &a, double ax, double ay,
50
+ const Rect &b, double bx, double by) {
51
+ return overlap(b, bx, by, a, ax, ay);
52
+ }
53
+
54
+ std::optional<double> shapeOverlap(const Entity &entityA,
55
+ const Entity &entityB) {
56
+ return std::visit(
57
+ [&](const auto &shapeA) -> std::optional<double> {
58
+ return std::visit(
59
+ [&](const auto &shapeB) -> std::optional<double> {
60
+ return overlap(shapeA, entityA.px, entityA.py, shapeB, entityB.px,
61
+ entityB.py);
62
+ },
63
+ entityB.shape);
64
+ },
65
+ entityA.shape);
66
+ }
67
+ } // namespace margelo::nitro::rngine::CollisionUtils
@@ -0,0 +1,19 @@
1
+ #pragma once
2
+
3
+ #include "Circle.hpp"
4
+ #include "Entity.hpp"
5
+ #include "Rect.hpp"
6
+ #include <optional>
7
+
8
+ namespace margelo::nitro::rngine::CollisionUtils {
9
+ std::optional<double> overlap(const Rect &a, double ax, double ay,
10
+ const Rect &b, double bx, double by);
11
+ std::optional<double> overlap(const Circle &a, double ax, double ay,
12
+ const Circle &b, double bx, double by);
13
+ std::optional<double> overlap(const Rect &a, double ax, double ay,
14
+ const Circle &b, double bx, double by);
15
+ std::optional<double> overlap(const Circle &a, double ax, double ay,
16
+ const Rect &b, double bx, double by);
17
+ std::optional<double> shapeOverlap(const Entity &entityA,
18
+ const Entity &entityB);
19
+ } // namespace margelo::nitro::rngine::CollisionUtils
@@ -1,5 +1,6 @@
1
1
  #include "GameLoop.hpp"
2
2
  #include "Collision.hpp"
3
+ #include "CollisionUtils.hpp"
3
4
  #include "Entity.hpp"
4
5
  #include <android/log.h>
5
6
  #include <chrono>
@@ -113,8 +114,8 @@ void GameLoop::runSystems() {
113
114
  auto resolvedEntitiesInternalA = resolveEntitiesInternal(a);
114
115
  auto resolvedEntitiesInternalB = resolveEntitiesInternal(b);
115
116
 
116
- for (auto *entityA : resolvedEntitiesInternalA) {
117
- for (auto *entityB : resolvedEntitiesInternalB) {
117
+ for (const auto &entityA : resolvedEntitiesInternalA) {
118
+ for (const auto &entityB : resolvedEntitiesInternalB) {
118
119
  if (entityA == entityB)
119
120
  continue;
120
121
 
@@ -125,22 +126,9 @@ void GameLoop::runSystems() {
125
126
 
126
127
  uniqueEntityIdPairs.insert(uniqueEntityIdPairKey);
127
128
 
128
- double aLeft = entityA->px - entityA->width / 2.0;
129
- double aRight = entityA->px + entityA->width / 2.0;
130
- double aTop = entityA->py - entityA->height / 2.0;
131
- double aBottom = entityA->py + entityA->height / 2.0;
132
-
133
- double bLeft = entityB->px - entityB->width / 2.0;
134
- double bRight = entityB->px + entityB->width / 2.0;
135
- double bTop = entityB->py - entityB->height / 2.0;
136
- double bBottom = entityB->py + entityB->height / 2.0;
137
-
138
- double overlapX = std::min(aRight, bRight) - std::max(aLeft, bLeft);
139
- double overlapY = std::min(aBottom, bBottom) - std::max(aTop, bTop);
140
-
141
- if (overlapX > 0 && overlapY > 0) {
142
- collisions.push_back(Collision(entityA->id, entityB->id,
143
- std::min(overlapX, overlapY)));
129
+ if (auto ov = CollisionUtils::shapeOverlap(*entityA, *entityB)) {
130
+ collisions.push_back(
131
+ Collision(entityA->id, entityB->id, ov.value()));
144
132
  }
145
133
  }
146
134
  }
@@ -204,16 +192,23 @@ void GameLoop::updateEntities(double deltaTime) {
204
192
  std::lock_guard<std::mutex> lock(_mutex);
205
193
 
206
194
  for (auto &[id, entity] : _entities) {
207
- if (entity.vx) {
208
- entity.px += *entity.vx * deltaTime;
195
+
196
+ if (entity.ax.has_value()) {
197
+ entity.vx = entity.vx.value_or(0.0) + entity.ax.value() * deltaTime;
198
+ }
199
+ if (entity.ay.has_value()) {
200
+ entity.vy = entity.vy.value_or(0.0) + entity.ay.value() * deltaTime;
209
201
  }
210
202
 
211
- if (entity.vy) {
212
- entity.py += *entity.vy * deltaTime;
203
+ if (entity.vx.has_value()) {
204
+ entity.px += entity.vx.value() * deltaTime;
205
+ }
206
+ if (entity.vy.has_value()) {
207
+ entity.py += entity.vy.value() * deltaTime;
213
208
  }
214
209
 
215
- if (entity.asset && entity.asset < 0) {
216
- auto it = _lottieDurations.find(*entity.asset);
210
+ if (entity.asset.has_value() && entity.asset.value() < 0) {
211
+ auto it = _lottieDurations.find(entity.asset.value());
217
212
  if (it != _lottieDurations.end() && it->second > 0.0) {
218
213
  entity.progress =
219
214
  fmod(entity.progress.value_or(0.0) + deltaTime / it->second, 1.0);
@@ -127,11 +127,8 @@ void GameMethods::update(const std::vector<EntityUpdate> &updates) {
127
127
  if (update.py.has_value()) {
128
128
  entity->py = update.py.value();
129
129
  }
130
- if (update.width.has_value()) {
131
- entity->width = update.width.value();
132
- }
133
- if (update.height.has_value()) {
134
- entity->height = update.height.value();
130
+ if (update.shape.has_value()) {
131
+ entity->shape = update.shape.value();
135
132
  }
136
133
  if (update.asset.has_value()) {
137
134
  entity->asset = update.asset.value();
@@ -148,6 +145,12 @@ void GameMethods::update(const std::vector<EntityUpdate> &updates) {
148
145
  if (update.vy.has_value()) {
149
146
  entity->vy = update.vy.value();
150
147
  }
148
+ if (update.ax.has_value()) {
149
+ entity->ax = update.ax.value();
150
+ }
151
+ if (update.ay.has_value()) {
152
+ entity->ay = update.ay.value();
153
+ }
151
154
  }
152
155
 
153
156
  __android_log_print(ANDROID_LOG_INFO, "GameMethods",
@@ -5,13 +5,23 @@ interface Positioned {
5
5
  py: number;
6
6
  }
7
7
 
8
- interface Shaped {
8
+ interface Rect {
9
9
  /** Width in game units. */
10
10
  width: number;
11
11
  /** Height in game units. */
12
12
  height: number;
13
13
  }
14
14
 
15
+ interface Circle {
16
+ /** Radius in game units. */
17
+ radius: number;
18
+ }
19
+
20
+ interface Shaped {
21
+ /** Shape of the entity. */
22
+ shape: Rect | Circle;
23
+ }
24
+
15
25
  interface Renderable {
16
26
  /** Fill color as a hex string e.g. `'#00ff00'`. */
17
27
  color?: string;
@@ -22,13 +32,17 @@ interface Renderable {
22
32
  }
23
33
 
24
34
  interface Kinematic {
25
- /** Velocity on the X axis in game units per second. */
35
+ /** Horizontal velocity in game units per second. */
26
36
  vx?: number;
27
- /** Velocity on the Y axis in game units per second. */
37
+ /** Vertical velocity in game units per second. */
28
38
  vy?: number;
39
+ /** Horizontal acceleration in game units per second squared. */
40
+ ax?: number;
41
+ /** Vertical acceleration in game units per second squared. */
42
+ ay?: number;
29
43
  }
30
44
 
31
- export interface Screen extends Shaped, Renderable {}
45
+ export interface Screen extends Rect, Renderable {}
32
46
 
33
47
  export interface Entity extends Positioned, Shaped, Renderable, Kinematic {
34
48
  /** Unique identifier. Use `_` as a separator for group queries e.g. `'enemy_1'`. */
@@ -1,11 +0,0 @@
1
- package com.margelo.nitro.rngine
2
-
3
- data class Rect(
4
- val left: Float,
5
- val right: Float,
6
- val top: Float,
7
- val bottom: Float,
8
- val color: Int,
9
- val asset: Int,
10
- val progress: Float?,
11
- )