rngine 0.5.0 → 0.6.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.
Binary file
@@ -1,36 +1,93 @@
1
+ #include "ColorUtils.hpp"
1
2
  #include "GameLoop.hpp"
3
+ #include <cstdint>
2
4
  #include <jni.h>
5
+ #include <mutex>
3
6
 
4
7
  extern "C" {
5
- JNIEXPORT jobject JNICALL
6
- Java_com_margelo_nitro_rngine_GameView_getRectsSnapshot(JNIEnv *env, jobject) {
7
- auto rects =
8
- margelo::nitro::rngine::GameLoop::getInstance().getRectsSnapshot();
9
- const size_t size = rects.size() * margelo::nitro::rngine::RECT_SIZE;
10
-
11
- static std::vector<uint8_t> buffer;
12
- buffer.resize(size);
13
-
14
- uint8_t *data = buffer.data();
15
-
16
- for (const auto &rect : rects) {
17
- memcpy(data, &rect.left, sizeof(float));
18
- data += sizeof(float);
19
- memcpy(data, &rect.right, sizeof(float));
20
- data += sizeof(float);
21
- memcpy(data, &rect.top, sizeof(float));
22
- data += sizeof(float);
23
- memcpy(data, &rect.bottom, sizeof(float));
24
- data += sizeof(float);
25
- memcpy(data, &rect.progress, sizeof(float));
26
- data += sizeof(float);
27
- memcpy(data, &rect.color, sizeof(uint32_t));
28
- data += sizeof(uint32_t);
29
- memcpy(data, &rect.asset, sizeof(int32_t));
30
- data += sizeof(int32_t);
8
+ JNIEXPORT jbyteArray JNICALL
9
+ Java_com_margelo_nitro_rngine_GameView_getSnapshot(JNIEnv *env, jobject) {
10
+ auto &gameLoop = margelo::nitro::rngine::GameLoop::getInstance();
11
+ auto &snapshotMutex = gameLoop.getSnapshotMutexInternal();
12
+
13
+ std::lock_guard<std::mutex> snapshotLock(snapshotMutex);
14
+ auto &screenSnapshot = gameLoop.getScreenSnapshotInternal();
15
+ auto &entitiesSnapshot = gameLoop.getEntitiesSnapshotInternal();
16
+
17
+ std::vector<uint8_t> buffer;
18
+
19
+ auto writeFloat = [&](float v) {
20
+ const auto *bytes = reinterpret_cast<const uint8_t *>(&v);
21
+ buffer.insert(buffer.end(), bytes, bytes + sizeof(float));
22
+ };
23
+ auto writeI32 = [&](int32_t v) {
24
+ const auto *bytes = reinterpret_cast<const uint8_t *>(&v);
25
+ buffer.insert(buffer.end(), bytes, bytes + sizeof(int32_t));
26
+ };
27
+ auto writeU32 = [&](uint32_t v) {
28
+ const auto *bytes = reinterpret_cast<const uint8_t *>(&v);
29
+ buffer.insert(buffer.end(), bytes, bytes + sizeof(uint32_t));
30
+ };
31
+
32
+ const auto screenSnapshotWidth = static_cast<float>(screenSnapshot.width);
33
+ const auto screenSnapshotHeight = static_cast<float>(screenSnapshot.height);
34
+ const auto screenSnapshotColor =
35
+ margelo::nitro::rngine::parseHexColor(screenSnapshot.color);
36
+ const auto screenSnapshotAsset =
37
+ static_cast<int32_t>(screenSnapshot.asset.value_or(0));
38
+
39
+ writeFloat(screenSnapshotWidth);
40
+ writeFloat(screenSnapshotHeight);
41
+ writeU32(screenSnapshotColor);
42
+ writeI32(screenSnapshotAsset);
43
+
44
+ if (screenSnapshotAsset < 0) {
45
+ writeFloat(static_cast<float>(screenSnapshot.progress.value_or(0)));
46
+ }
47
+
48
+ 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));
57
+
58
+ if (entitySnapshotRight < 0 || entitySnapshotLeft > screenSnapshot.width ||
59
+ entitySnapshotBottom < 0 || entitySnapshotTop > screenSnapshot.height) {
60
+ continue;
61
+ }
62
+
63
+ const auto entitySnapshotColor =
64
+ margelo::nitro::rngine::parseHexColor(entitySnapshot.color);
65
+ const auto entitySnapshotAsset =
66
+ static_cast<int32_t>(entitySnapshot.asset.value_or(0));
67
+
68
+ writeFloat(entitySnapshotLeft);
69
+ writeFloat(entitySnapshotRight);
70
+ writeFloat(entitySnapshotTop);
71
+ writeFloat(entitySnapshotBottom);
72
+ writeU32(entitySnapshotColor);
73
+ writeI32(entitySnapshotAsset);
74
+
75
+ if (entitySnapshotAsset < 0) {
76
+ writeFloat(static_cast<float>(entitySnapshot.progress.value_or(0)));
77
+ }
31
78
  }
32
79
 
33
- return env->NewDirectByteBuffer(buffer.data(), (jlong)size);
80
+ auto bufferSize = static_cast<jsize>(buffer.size());
81
+ jbyteArray result = env->NewByteArray(bufferSize);
82
+
83
+ if (result == nullptr) {
84
+ return nullptr;
85
+ }
86
+
87
+ env->SetByteArrayRegion(result, 0, bufferSize,
88
+ reinterpret_cast<const jbyte *>(buffer.data()));
89
+
90
+ return result;
34
91
  }
35
92
 
36
93
  JNIEXPORT void JNICALL
@@ -6,6 +6,7 @@ import com.airbnb.lottie.LottieDrawable
6
6
  import com.caverock.androidsvg.SVG
7
7
  import com.margelo.nitro.core.Promise
8
8
  import java.net.URL
9
+ import com.margelo.nitro.NitroModules
9
10
 
10
11
  class GameAssets : HybridGameAssetsSpec() {
11
12
  private external fun registerLottieDuration(id: Double, duration: Double)
@@ -22,7 +23,16 @@ class GameAssets : HybridGameAssetsSpec() {
22
23
  override fun registerSvg(id: Double, uri: String): Promise<Unit> {
23
24
  return Promise.async {
24
25
  try {
25
- val stream = URL(uri).openStream()
26
+ val stream = if (uri.startsWith("http://") || uri.startsWith("https://")) {
27
+ URL(uri).openStream()
28
+ } else {
29
+ val context = NitroModules.applicationContext ?: throw Error("No Context available!")
30
+ val resId = context.resources.getIdentifier(uri, "raw", context.packageName)
31
+ if (resId == 0) {
32
+ throw IllegalStateException("Could not resolve drawable resource for asset: $uri")
33
+ }
34
+ context.resources.openRawResource(resId)
35
+ }
26
36
  assetCache[id.toInt()] = Asset.Svg(SVG.getFromInputStream(stream).renderToPicture())
27
37
  Log.d("GameAssets", "assetCache: $assetCache")
28
38
  } catch (e: Exception) {
@@ -4,10 +4,8 @@ import android.content.Context
4
4
  import android.graphics.Color
5
5
  import android.graphics.Paint
6
6
  import android.util.AttributeSet
7
- import android.util.Log
8
7
  import android.view.SurfaceView
9
8
  import android.view.View
10
- import java.nio.ByteBuffer
11
9
  import androidx.core.graphics.withTranslation
12
10
  import androidx.core.graphics.withClip
13
11
 
@@ -20,7 +18,7 @@ class GameView(
20
18
  attrs,
21
19
  defStyleAttr,
22
20
  ) {
23
- private external fun getRectsSnapshot(): ByteBuffer
21
+ private external fun getSnapshot(): ByteArray
24
22
  var onAttached: () -> Unit = {}
25
23
  var onDetached: () -> Unit = {}
26
24
 
@@ -29,6 +27,48 @@ class GameView(
29
27
  style = Paint.Style.FILL
30
28
  }
31
29
 
30
+ private fun drawRenderable(
31
+ canvas: android.graphics.Canvas,
32
+ left: Float,
33
+ top: Float,
34
+ right: Float,
35
+ bottom: Float,
36
+ color: Int,
37
+ asset: Int,
38
+ progress: Float?,
39
+ clampedLeft: Float = left,
40
+ clampedTop: Float = top,
41
+ clampedRight: Float = right,
42
+ clampedBottom: Float = bottom,
43
+ ) {
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
+ }
57
+
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)
64
+ }
65
+
66
+ null -> {}
67
+ }
68
+ }
69
+ }
70
+ }
71
+
32
72
  init {
33
73
  addOnAttachStateChangeListener(
34
74
  object : OnAttachStateChangeListener {
@@ -40,61 +80,53 @@ class GameView(
40
80
  fun drawFrame() {
41
81
  if (!holder.surface.isValid) return
42
82
  val canvas = holder.lockCanvas() ?: return
83
+ val snapshot = SnapshotSerializer.decode(getSnapshot())
43
84
 
44
- val rects = RectSerializer.decode(getRectsSnapshot())
45
-
46
- val worldRect = rects.first()
47
- val scaleX = canvas.width / worldRect.right
48
- val scaleY = canvas.height / worldRect.bottom
85
+ val scaleX = canvas.width / snapshot.screen.width
86
+ val scaleY = canvas.height / snapshot.screen.height
49
87
  val scale = minOf(scaleX, scaleY)
50
88
 
51
- val offsetX = (canvas.width - worldRect.right * scale) / 2f
52
- val offsetY = (canvas.height - worldRect.bottom * scale) / 2f
89
+ val screenLeft = (canvas.width - snapshot.screen.width * scale) / 2f
90
+ val screenTop = (canvas.height - snapshot.screen.height * scale) / 2f
91
+ val screenRight = screenLeft + snapshot.screen.width * scale
92
+ val screenBottom = screenTop + snapshot.screen.height * scale
93
+
94
+ drawRenderable(
95
+ canvas,
96
+ screenLeft,
97
+ screenTop,
98
+ screenRight,
99
+ screenBottom,
100
+ snapshot.screen.color,
101
+ snapshot.screen.asset,
102
+ snapshot.screen.progress,
103
+ )
53
104
 
54
- rects.forEach { rect ->
55
- val left = rect.left * scale + offsetX
56
- val top = rect.top * scale + offsetY
57
- val right = rect.right * scale + offsetX
58
- val bottom = rect.bottom * scale + offsetY
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
59
110
 
60
- val clampedLeft = left.coerceAtLeast(offsetX)
61
- val clampedTop = top.coerceAtLeast(offsetY)
62
- val clampedRight = right.coerceAtMost(offsetX + worldRect.right * scale)
63
- val clampedBottom = bottom.coerceAtMost(offsetY + worldRect.bottom * scale)
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)
64
115
 
65
- paint.color = rect.color
66
- canvas.drawRect(
116
+ drawRenderable(
117
+ canvas,
118
+ left,
119
+ top,
120
+ right,
121
+ bottom,
122
+ rect.color,
123
+ rect.asset,
124
+ rect.progress,
67
125
  clampedLeft,
68
126
  clampedTop,
69
127
  clampedRight,
70
- clampedBottom,
71
- paint
128
+ clampedBottom
72
129
  )
73
- when(val asset = GameAssets.getAsset(rect.asset)){
74
- is Asset.Svg -> {
75
- canvas.withClip(clampedLeft, clampedTop, clampedRight, clampedBottom) {
76
- withTranslation(left, top) {
77
- scale(
78
- (right - left) / asset.picture.width,
79
- (bottom - top) / asset.picture.height
80
- )
81
- drawPicture(asset.picture)
82
- }
83
- }
84
- }
85
-
86
- is Asset.Lottie -> {
87
- canvas.withClip(clampedLeft, clampedTop, clampedRight, clampedBottom) {
88
- withTranslation(left, top) {
89
- asset.drawable.progress = rect.progress
90
- asset.drawable.setBounds(0, 0, (right - left).toInt(), (bottom - top).toInt())
91
- asset.drawable.draw(canvas)
92
- }
93
- }
94
- }
95
-
96
- null -> {}
97
- }
98
130
  }
99
131
  holder.unlockCanvasAndPost(canvas)
100
132
  }
@@ -5,7 +5,7 @@ data class Rect(
5
5
  val right: Float,
6
6
  val top: Float,
7
7
  val bottom: Float,
8
- val progress: Float,
9
8
  val color: Int,
10
- val asset: Int
9
+ val asset: Int,
10
+ val progress: Float?,
11
11
  )
@@ -0,0 +1,9 @@
1
+ package com.margelo.nitro.rngine
2
+
3
+ data class Screen(
4
+ val width: Float,
5
+ val height: Float,
6
+ val color: Int,
7
+ val asset: Int,
8
+ val progress: Float?,
9
+ )
@@ -0,0 +1,3 @@
1
+ package com.margelo.nitro.rngine
2
+
3
+ data class Snapshot(val screen: Screen, val rects: List<Rect>)
@@ -0,0 +1,33 @@
1
+ package com.margelo.nitro.rngine
2
+
3
+ import java.nio.ByteBuffer
4
+ import java.nio.ByteOrder
5
+
6
+ object SnapshotSerializer {
7
+ fun decode(bytes: ByteArray): Snapshot {
8
+ val buffer = ByteBuffer.wrap(bytes).order(ByteOrder.nativeOrder())
9
+
10
+ val width = buffer.float
11
+ val height = buffer.float
12
+ val color = buffer.int
13
+ val asset = buffer.int
14
+ val progress = if (asset < 0) buffer.float else null
15
+
16
+ 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))
29
+ }
30
+
31
+ return Snapshot(screen, rects)
32
+ }
33
+ }
@@ -1,79 +1,60 @@
1
- export type Screen = {
2
- /** Width of the screen in game units. */
3
- width: number;
4
- /** Height of the screen in game units. */
5
- height: number;
6
- /** Background color of the screen as a hex string e.g. `'#1a1a1a'`. */
7
- color?: string;
8
- /** Asset to render, use `require` with the file path to get the id. */
9
- asset?: number;
10
- /** Animation progress between 0 and 1, automatically advanced each tick for Lottie assets. */
11
- progress?: number;
12
- };
13
- export type Entity = {
14
- /** Unique identifier. Use `_` as a separator for group queries e.g. `'enemy_1'`. */
15
- id: string;
1
+ interface Positioned {
16
2
  /** X position in game units. */
17
3
  px: number;
18
4
  /** Y position in game units. */
19
5
  py: number;
6
+ }
7
+ interface Shaped {
20
8
  /** Width in game units. */
21
9
  width: number;
22
10
  /** Height in game units. */
23
11
  height: number;
12
+ }
13
+ interface Renderable {
24
14
  /** Fill color as a hex string e.g. `'#00ff00'`. */
25
15
  color?: string;
26
16
  /** Asset to render, use `require` with the file path to get the id. */
27
17
  asset?: number;
28
18
  /** Animation progress between 0 and 1, automatically advanced each tick for Lottie assets. */
29
19
  progress?: number;
20
+ }
21
+ interface Kinematic {
30
22
  /** Velocity on the X axis in game units per second. */
31
23
  vx?: number;
32
24
  /** Velocity on the Y axis in game units per second. */
33
25
  vy?: number;
34
- };
35
- export type CollisionPair = {
26
+ }
27
+ export interface Screen extends Shaped, Renderable {
28
+ }
29
+ export interface Entity extends Positioned, Shaped, Renderable, Kinematic {
30
+ /** Unique identifier. Use `_` as a separator for group queries e.g. `'enemy_1'`. */
31
+ id: string;
32
+ }
33
+ export interface EntityUpdate extends Partial<Positioned & Shaped & Renderable & Kinematic> {
34
+ /** Unique identifier or prefix of the entities to update. */
35
+ id: string;
36
+ }
37
+ export interface CollisionPair {
36
38
  /** Entity id or prefix of the first entity to watch. */
37
39
  a: string;
38
40
  /** Entity id or prefix of the second entity to watch. */
39
41
  b: string;
40
- };
41
- export type Collision = {
42
+ }
43
+ export interface Collision {
42
44
  /** Id of the first entity involved in the collision. */
43
45
  a: string;
44
46
  /** Id of the second entity involved in the collision. */
45
47
  b: string;
46
48
  /** Penetration depth of the collision. */
47
49
  depth: number;
48
- };
49
- export type System = {
50
+ }
51
+ export interface System {
50
52
  /** Entity ids or prefixes this system subscribes to. */
51
53
  entities?: string[];
52
54
  /** Collision pairs to watch for every tick. */
53
55
  collisions?: CollisionPair[];
54
56
  /** Called every tick with the resolved entities and collisions. */
55
57
  onTick: (entities: Entity[], collisions: Collision[]) => number;
56
- };
57
- export type EntityUpdate = {
58
- /** Unique identifier or prefix of the entities to update. */
59
- id: string;
60
- /** X position in game units. */
61
- px?: number;
62
- /** Y position in game units. */
63
- py?: number;
64
- /** Width in game units. */
65
- width?: number;
66
- /** Height in game units. */
67
- height?: number;
68
- /** Fill color as a hex string e.g. `'#00ff00'`. */
69
- color?: string;
70
- /** Asset to render, use `require` with the file path to get the id. */
71
- asset?: number;
72
- /** Animation progress between 0 and 1, automatically advanced each tick for Lottie assets. */
73
- progress?: number;
74
- /** Velocity on the X axis in game units per second. */
75
- vx?: number;
76
- /** Velocity on the Y axis in game units per second. */
77
- vy?: number;
78
- };
58
+ }
59
+ export {};
79
60
  //# sourceMappingURL=nativeTypes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"nativeTypes.d.ts","sourceRoot":"","sources":["../../../src/nativeTypes.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG;IACnB,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,oFAAoF;IACpF,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,wDAAwD;IACxD,CAAC,EAAE,MAAM,CAAC;IACV,yDAAyD;IACzD,CAAC,EAAE,MAAM,CAAC;CACX,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,wDAAwD;IACxD,CAAC,EAAE,MAAM,CAAC;IACV,yDAAyD;IACzD,CAAC,EAAE,MAAM,CAAC;IACV,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,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,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,6DAA6D;IAC7D,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rngine",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
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",
@@ -1,6 +1,5 @@
1
1
  #include "GameLoop.hpp"
2
2
  #include "Collision.hpp"
3
- #include "ColorUtils.hpp"
4
3
  #include "Entity.hpp"
5
4
  #include <android/log.h>
6
5
  #include <chrono>
@@ -60,37 +59,6 @@ void GameLoop::registerLottieDuration(double id, double duration) {
60
59
  id, duration);
61
60
  }
62
61
 
63
- std::vector<Rect> GameLoop::getRectsSnapshot() {
64
- std::lock_guard<std::mutex> snapshotLock(_snapshotMutex);
65
- std::vector<Rect> rects;
66
- rects.reserve(_entitiesSnapshot.size() + 1);
67
-
68
- rects.push_back({0, static_cast<float>(_screenSnapshot.width), 0,
69
- static_cast<float>(_screenSnapshot.height),
70
- static_cast<float>(_screenSnapshot.progress.value_or(0)),
71
- parseHexColor(_screenSnapshot.color),
72
- static_cast<int32_t>(_screenSnapshot.asset.value_or(0))});
73
-
74
- for (const auto &[id, entitySnapshot] : _entitiesSnapshot) {
75
- if (entitySnapshot.px + entitySnapshot.width < 0 ||
76
- entitySnapshot.px > _screenSnapshot.width ||
77
- entitySnapshot.py + entitySnapshot.height < 0 ||
78
- entitySnapshot.py > _screenSnapshot.height) {
79
- continue;
80
- }
81
-
82
- rects.push_back(
83
- {static_cast<float>(entitySnapshot.px),
84
- static_cast<float>(entitySnapshot.px + entitySnapshot.width),
85
- static_cast<float>(entitySnapshot.py),
86
- static_cast<float>(entitySnapshot.py + entitySnapshot.height),
87
- static_cast<float>(entitySnapshot.progress.value_or(0)),
88
- parseHexColor(entitySnapshot.color),
89
- static_cast<int32_t>(entitySnapshot.asset.value_or(0))});
90
- }
91
- return rects;
92
- }
93
-
94
62
  void GameLoop::runGameLoop() {
95
63
  using namespace std::chrono;
96
64
 
@@ -157,13 +125,18 @@ void GameLoop::runSystems() {
157
125
 
158
126
  uniqueEntityIdPairs.insert(uniqueEntityIdPairKey);
159
127
 
160
- float aLeft = entityA->px, aRight = entityA->px + entityA->width;
161
- float aTop = entityA->py, aBottom = entityA->py + entityA->height;
162
- float bLeft = entityB->px, bRight = entityB->px + entityB->width;
163
- float bTop = entityB->py, bBottom = entityB->py + entityB->height;
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;
164
137
 
165
- float overlapX = std::min(aRight, bRight) - std::max(aLeft, bLeft);
166
- float overlapY = std::min(aBottom, bBottom) - std::max(aTop, bTop);
138
+ double overlapX = std::min(aRight, bRight) - std::max(aLeft, bLeft);
139
+ double overlapY = std::min(aBottom, bBottom) - std::max(aTop, bTop);
167
140
 
168
141
  if (overlapX > 0 && overlapY > 0) {
169
142
  collisions.push_back(Collision(entityA->id, entityB->id,
@@ -2,7 +2,6 @@
2
2
 
3
3
  #include "Entity.hpp"
4
4
  #include "GameStats.hpp"
5
- #include "Rect.hpp"
6
5
  #include "Screen.hpp"
7
6
  #include "System.hpp"
8
7
  #include <atomic>
@@ -34,7 +33,6 @@ public:
34
33
 
35
34
  std::vector<Entity *> resolveEntitiesInternal(const std::string &prefix);
36
35
  void registerLottieDuration(double, double);
37
- std::vector<Rect> getRectsSnapshot();
38
36
 
39
37
  void setTickRate(double tickRate) { _tickRate.store(tickRate); };
40
38
 
@@ -1,83 +1,68 @@
1
- export type Screen = {
2
- /** Width of the screen in game units. */
3
- width: number;
4
- /** Height of the screen in game units. */
5
- height: number;
6
- /** Background color of the screen as a hex string e.g. `'#1a1a1a'`. */
7
- color?: string;
8
- /** Asset to render, use `require` with the file path to get the id. */
9
- asset?: number;
10
- /** Animation progress between 0 and 1, automatically advanced each tick for Lottie assets. */
11
- progress?: number;
12
- };
13
-
14
- export type Entity = {
15
- /** Unique identifier. Use `_` as a separator for group queries e.g. `'enemy_1'`. */
16
- id: string;
1
+ interface Positioned {
17
2
  /** X position in game units. */
18
3
  px: number;
19
4
  /** Y position in game units. */
20
5
  py: number;
6
+ }
7
+
8
+ interface Shaped {
21
9
  /** Width in game units. */
22
10
  width: number;
23
11
  /** Height in game units. */
24
12
  height: number;
13
+ }
14
+
15
+ interface Renderable {
25
16
  /** Fill color as a hex string e.g. `'#00ff00'`. */
26
17
  color?: string;
27
18
  /** Asset to render, use `require` with the file path to get the id. */
28
19
  asset?: number;
29
20
  /** Animation progress between 0 and 1, automatically advanced each tick for Lottie assets. */
30
21
  progress?: number;
22
+ }
23
+
24
+ interface Kinematic {
31
25
  /** Velocity on the X axis in game units per second. */
32
26
  vx?: number;
33
27
  /** Velocity on the Y axis in game units per second. */
34
28
  vy?: number;
35
- };
29
+ }
36
30
 
37
- export type CollisionPair = {
31
+ export interface Screen extends Shaped, Renderable {}
32
+
33
+ export interface Entity extends Positioned, Shaped, Renderable, Kinematic {
34
+ /** Unique identifier. Use `_` as a separator for group queries e.g. `'enemy_1'`. */
35
+ id: string;
36
+ }
37
+
38
+ export interface EntityUpdate extends Partial<
39
+ Positioned & Shaped & Renderable & Kinematic
40
+ > {
41
+ /** Unique identifier or prefix of the entities to update. */
42
+ id: string;
43
+ }
44
+
45
+ export interface CollisionPair {
38
46
  /** Entity id or prefix of the first entity to watch. */
39
47
  a: string;
40
48
  /** Entity id or prefix of the second entity to watch. */
41
49
  b: string;
42
- };
50
+ }
43
51
 
44
- export type Collision = {
52
+ export interface Collision {
45
53
  /** Id of the first entity involved in the collision. */
46
54
  a: string;
47
55
  /** Id of the second entity involved in the collision. */
48
56
  b: string;
49
57
  /** Penetration depth of the collision. */
50
58
  depth: number;
51
- };
59
+ }
52
60
 
53
- export type System = {
61
+ export interface System {
54
62
  /** Entity ids or prefixes this system subscribes to. */
55
63
  entities?: string[];
56
64
  /** Collision pairs to watch for every tick. */
57
65
  collisions?: CollisionPair[];
58
66
  /** Called every tick with the resolved entities and collisions. */
59
67
  onTick: (entities: Entity[], collisions: Collision[]) => number;
60
- };
61
-
62
- export type EntityUpdate = {
63
- /** Unique identifier or prefix of the entities to update. */
64
- id: string;
65
- /** X position in game units. */
66
- px?: number;
67
- /** Y position in game units. */
68
- py?: number;
69
- /** Width in game units. */
70
- width?: number;
71
- /** Height in game units. */
72
- height?: number;
73
- /** Fill color as a hex string e.g. `'#00ff00'`. */
74
- color?: string;
75
- /** Asset to render, use `require` with the file path to get the id. */
76
- asset?: number;
77
- /** Animation progress between 0 and 1, automatically advanced each tick for Lottie assets. */
78
- progress?: number;
79
- /** Velocity on the X axis in game units per second. */
80
- vx?: number;
81
- /** Velocity on the Y axis in game units per second. */
82
- vy?: number;
83
- };
68
+ }
@@ -1,25 +0,0 @@
1
- package com.margelo.nitro.rngine
2
-
3
- import java.nio.ByteBuffer
4
- import java.nio.ByteOrder
5
-
6
- object RectSerializer {
7
- private const val RECT_SIZE = 4 * 5 + 4 * 2
8
- fun decode(buffer: ByteBuffer): ArrayList<Rect> {
9
- buffer.order(ByteOrder.nativeOrder())
10
- val rects = ArrayList<Rect>()
11
-
12
- while (buffer.remaining() >= RECT_SIZE) {
13
- val left = buffer.float
14
- val right = buffer.float
15
- val top = buffer.float
16
- val bottom = buffer.float
17
- val progress = buffer.float
18
- val color = buffer.int
19
- val asset = buffer.int
20
-
21
- rects.add(Rect(left, right, top, bottom, progress, color, asset))
22
- }
23
- return rects
24
- }
25
- }
package/shared/Rect.hpp DELETED
@@ -1,16 +0,0 @@
1
- #pragma once
2
-
3
- namespace margelo::nitro::rngine {
4
- static constexpr int RECT_SIZE =
5
- sizeof(float) * 5 + sizeof(uint32_t) + sizeof(int32_t);
6
-
7
- struct Rect {
8
- float left;
9
- float right;
10
- float top;
11
- float bottom;
12
- float progress;
13
- uint32_t color;
14
- int32_t asset;
15
- };
16
- } // namespace margelo::nitro::rngine
File without changes