rngine 0.4.2 → 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.
- package/README.md +1 -1
- package/android/kls_database.db +0 -0
- package/android/src/main/cpp/GameLoopJNI.cpp +84 -27
- package/android/src/main/java/com/margelo/nitro/rngine/GameAssets.kt +34 -20
- package/android/src/main/java/com/margelo/nitro/rngine/GameView.kt +80 -48
- package/android/src/main/java/com/margelo/nitro/rngine/Rect.kt +2 -2
- package/android/src/main/java/com/margelo/nitro/rngine/Screen.kt +9 -0
- package/android/src/main/java/com/margelo/nitro/rngine/Snapshot.kt +3 -0
- package/android/src/main/java/com/margelo/nitro/rngine/SnapshotSerializer.kt +33 -0
- package/lib/module/GameAssets.js +41 -0
- package/lib/module/GameAssets.js.map +1 -0
- package/lib/module/GameEngine.js +1 -1
- package/lib/module/GameEngine.js.map +1 -1
- package/lib/module/GameMethods.js +43 -0
- package/lib/module/GameMethods.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/GameAssets.d.ts +2 -0
- package/lib/typescript/src/GameAssets.d.ts.map +1 -0
- package/lib/typescript/src/GameAssets.nitro.d.ts +2 -2
- package/lib/typescript/src/GameAssets.nitro.d.ts.map +1 -1
- package/lib/typescript/src/GameMethods.d.ts +8 -0
- package/lib/typescript/src/GameMethods.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/nativeTypes.d.ts +25 -44
- package/lib/typescript/src/nativeTypes.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +2 -15
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JHybridGameAssetsSpec.cpp +31 -6
- package/nitrogen/generated/android/c++/JHybridGameAssetsSpec.hpp +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngine/HybridGameAssetsSpec.kt +3 -2
- package/nitrogen/generated/ios/Rngine-Swift-Cxx-Bridge.cpp +16 -0
- package/nitrogen/generated/ios/Rngine-Swift-Cxx-Bridge.hpp +65 -6
- package/nitrogen/generated/ios/Rngine-Swift-Cxx-Umbrella.hpp +1 -0
- package/nitrogen/generated/ios/c++/HybridGameAssetsSpecSwift.hpp +7 -2
- package/nitrogen/generated/ios/swift/Func_void.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
- package/nitrogen/generated/ios/swift/HybridGameAssetsSpec.swift +2 -2
- package/nitrogen/generated/ios/swift/HybridGameAssetsSpec_cxx.swift +24 -8
- package/nitrogen/generated/shared/c++/HybridGameAssetsSpec.hpp +3 -2
- package/package.json +1 -1
- package/shared/GameLoop.cpp +11 -38
- package/shared/GameLoop.hpp +0 -2
- package/shared/GameMethods.cpp +2 -0
- package/src/GameAssets.nitro.ts +2 -2
- package/src/GameAssets.ts +47 -0
- package/src/GameEngine.tsx +1 -1
- package/src/GameMethods.ts +48 -0
- package/src/index.tsx +8 -1
- package/src/nativeTypes.ts +31 -46
- package/src/types.ts +3 -19
- package/android/src/main/java/com/margelo/nitro/rngine/RectSerializer.kt +0 -25
- package/lib/module/Shared.js +0 -85
- package/lib/module/Shared.js.map +0 -1
- package/lib/typescript/src/Shared.d.ts +0 -8
- package/lib/typescript/src/Shared.d.ts.map +0 -1
- package/shared/Rect.hpp +0 -16
- package/src/Shared.ts +0 -99
- /package/{shared → android/src/main/cpp}/ColorUtils.hpp +0 -0
package/README.md
CHANGED
|
@@ -72,7 +72,7 @@ export default function App() {
|
|
|
72
72
|
|
|
73
73
|
**Entities** are the objects in your game world. Each entity has a position, size, color, and velocity. See [`Entity`](./src/nativeTypes.ts).
|
|
74
74
|
|
|
75
|
-
**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/
|
|
75
|
+
**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
76
|
|
|
77
77
|
**Screen** defines the viewport dimensions and background color. Entities outside the screen bounds are automatically clipped. See [`Screen`](./src/nativeTypes.ts).
|
|
78
78
|
|
package/android/kls_database.db
CHANGED
|
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
|
|
6
|
-
|
|
7
|
-
auto
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
uint8_t
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
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
|
|
@@ -4,7 +4,9 @@ import android.util.Log
|
|
|
4
4
|
import com.airbnb.lottie.LottieCompositionFactory
|
|
5
5
|
import com.airbnb.lottie.LottieDrawable
|
|
6
6
|
import com.caverock.androidsvg.SVG
|
|
7
|
+
import com.margelo.nitro.core.Promise
|
|
7
8
|
import java.net.URL
|
|
9
|
+
import com.margelo.nitro.NitroModules
|
|
8
10
|
|
|
9
11
|
class GameAssets : HybridGameAssetsSpec() {
|
|
10
12
|
private external fun registerLottieDuration(id: Double, duration: Double)
|
|
@@ -18,30 +20,42 @@ class GameAssets : HybridGameAssetsSpec() {
|
|
|
18
20
|
return id.toInt() in assetCache
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
override fun registerSvg(id: Double, uri: String) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
override fun registerSvg(id: Double, uri: String): Promise<Unit> {
|
|
24
|
+
return Promise.async {
|
|
25
|
+
try {
|
|
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
|
+
}
|
|
36
|
+
assetCache[id.toInt()] = Asset.Svg(SVG.getFromInputStream(stream).renderToPicture())
|
|
37
|
+
Log.d("GameAssets", "assetCache: $assetCache")
|
|
38
|
+
} catch (e: Exception) {
|
|
39
|
+
Log.e("GameAssets", "Failed to parse SVG: $uri", e)
|
|
40
|
+
throw e
|
|
41
|
+
}
|
|
28
42
|
}
|
|
29
43
|
}
|
|
30
44
|
|
|
31
|
-
override fun registerLottie(id: Double, json: String) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
override fun registerLottie(id: Double, json: String): Promise<Unit> {
|
|
46
|
+
return Promise.async {
|
|
47
|
+
try {
|
|
48
|
+
val composition = LottieCompositionFactory.fromJsonStringSync(json, null).value
|
|
49
|
+
?: throw IllegalStateException("Failed to parse Lottie JSON for id: $id")
|
|
50
|
+
val drawable = LottieDrawable()
|
|
51
|
+
drawable.composition = composition
|
|
52
|
+
assetCache[id.toInt()] = Asset.Lottie(drawable)
|
|
53
|
+
registerLottieDuration(id, composition.duration.toDouble() / 1000)
|
|
54
|
+
Log.d("GameAssets", "assetCache: $assetCache")
|
|
55
|
+
} catch (e: Exception) {
|
|
56
|
+
Log.e("GameAssets", "Failed to register Lottie: $id", e)
|
|
57
|
+
throw e
|
|
37
58
|
}
|
|
38
|
-
val drawable = LottieDrawable()
|
|
39
|
-
drawable.composition = composition
|
|
40
|
-
assetCache[id.toInt()] = Asset.Lottie(drawable)
|
|
41
|
-
registerLottieDuration(id, composition.duration.toDouble() / 1000)
|
|
42
|
-
Log.d("GameAssets", "assetCache: $assetCache")
|
|
43
|
-
} catch (e: Exception) {
|
|
44
|
-
Log.e("GameAssets", "Failed to register Lottie: $id", e)
|
|
45
59
|
}
|
|
46
60
|
}
|
|
47
61
|
}
|
|
@@ -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
|
|
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
|
|
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
|
|
52
|
-
val
|
|
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 +
|
|
56
|
-
val top = rect.top * scale +
|
|
57
|
-
val right = rect.right * scale +
|
|
58
|
-
val bottom = rect.bottom * scale +
|
|
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(
|
|
61
|
-
val clampedTop = top.coerceAtLeast(
|
|
62
|
-
val clampedRight = right.coerceAtMost(
|
|
63
|
-
val clampedBottom = bottom.coerceAtMost(
|
|
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
|
-
|
|
66
|
-
|
|
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
|
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { Image } from 'react-native';
|
|
4
|
+
import { gameAssets } from "./GameAssets.nitro.js";
|
|
5
|
+
const assetCache = new WeakMap();
|
|
6
|
+
let nextId = -1;
|
|
7
|
+
const loadAsset = async asset => {
|
|
8
|
+
switch (typeof asset) {
|
|
9
|
+
case 'object':
|
|
10
|
+
if (asset === null) {
|
|
11
|
+
throw new Error('loadAssets: asset cannot be null');
|
|
12
|
+
}
|
|
13
|
+
if (assetCache.has(asset)) {
|
|
14
|
+
return assetCache.get(asset);
|
|
15
|
+
}
|
|
16
|
+
const assetId = nextId--;
|
|
17
|
+
assetCache.set(asset, assetId);
|
|
18
|
+
await gameAssets.registerLottie(assetId, JSON.stringify(asset));
|
|
19
|
+
return assetId;
|
|
20
|
+
case 'number':
|
|
21
|
+
if (gameAssets.isAssetRegistered(asset)) {
|
|
22
|
+
return asset;
|
|
23
|
+
}
|
|
24
|
+
const assetUri = Image.resolveAssetSource(asset)?.uri;
|
|
25
|
+
if (!assetUri) {
|
|
26
|
+
throw new Error(`loadAssets: could not resolve asset URI for ${asset}`);
|
|
27
|
+
}
|
|
28
|
+
await gameAssets.registerSvg(asset, assetUri);
|
|
29
|
+
return asset;
|
|
30
|
+
}
|
|
31
|
+
throw new Error(`loadAssets: unsupported asset type "${typeof asset}"`);
|
|
32
|
+
};
|
|
33
|
+
export const loadAssets = async assets => {
|
|
34
|
+
const keys = Object.keys(assets);
|
|
35
|
+
const result = {};
|
|
36
|
+
for (const key of keys) {
|
|
37
|
+
result[key] = await loadAsset(assets[key]);
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=GameAssets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Image","gameAssets","assetCache","WeakMap","nextId","loadAsset","asset","Error","has","get","assetId","set","registerLottie","JSON","stringify","isAssetRegistered","assetUri","resolveAssetSource","uri","registerSvg","loadAssets","assets","keys","Object","result","key"],"sourceRoot":"../../src","sources":["GameAssets.ts"],"mappings":";;AAAA,SAASA,KAAK,QAAQ,cAAc;AACpC,SAASC,UAAU,QAAQ,uBAAoB;AAE/C,MAAMC,UAAU,GAAG,IAAIC,OAAO,CAAiB,CAAC;AAChD,IAAIC,MAAM,GAAG,CAAC,CAAC;AAEf,MAAMC,SAAS,GAAG,MAAOC,KAAc,IAAK;EAC1C,QAAQ,OAAOA,KAAK;IAClB,KAAK,QAAQ;MACX,IAAIA,KAAK,KAAK,IAAI,EAAE;QAClB,MAAM,IAAIC,KAAK,CAAC,kCAAkC,CAAC;MACrD;MACA,IAAIL,UAAU,CAACM,GAAG,CAACF,KAAK,CAAC,EAAE;QACzB,OAAOJ,UAAU,CAACO,GAAG,CAACH,KAAK,CAAC;MAC9B;MACA,MAAMI,OAAO,GAAGN,MAAM,EAAE;MACxBF,UAAU,CAACS,GAAG,CAACL,KAAK,EAAEI,OAAO,CAAC;MAC9B,MAAMT,UAAU,CAACW,cAAc,CAACF,OAAO,EAAEG,IAAI,CAACC,SAAS,CAACR,KAAK,CAAC,CAAC;MAC/D,OAAOI,OAAO;IAEhB,KAAK,QAAQ;MACX,IAAIT,UAAU,CAACc,iBAAiB,CAACT,KAAK,CAAC,EAAE;QACvC,OAAOA,KAAK;MACd;MACA,MAAMU,QAAQ,GAAGhB,KAAK,CAACiB,kBAAkB,CAACX,KAAK,CAAC,EAAEY,GAAG;MACrD,IAAI,CAACF,QAAQ,EAAE;QACb,MAAM,IAAIT,KAAK,CAAC,+CAA+CD,KAAK,EAAE,CAAC;MACzE;MACA,MAAML,UAAU,CAACkB,WAAW,CAACb,KAAK,EAAEU,QAAQ,CAAC;MAC7C,OAAOV,KAAK;EAChB;EAEA,MAAM,IAAIC,KAAK,CAAC,uCAAuC,OAAOD,KAAK,GAAG,CAAC;AACzE,CAAC;AAED,OAAO,MAAMc,UAAU,GAAG,MACxBC,MAAS,IAC+B;EACxC,MAAMC,IAAI,GAAGC,MAAM,CAACD,IAAI,CAACD,MAAM,CAAgB;EAC/C,MAAMG,MAAM,GAAG,CAAC,CAA+B;EAE/C,KAAK,MAAMC,GAAG,IAAIH,IAAI,EAAE;IACtBE,MAAM,CAACC,GAAG,CAAC,GAAG,MAAMpB,SAAS,CAACgB,MAAM,CAACI,GAAG,CAAC,CAAC;EAC5C;EAEA,OAAOD,MAAM;AACf,CAAC","ignoreList":[]}
|
package/lib/module/GameEngine.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { getHostComponent } from 'react-native-nitro-modules';
|
|
4
|
-
|
|
4
|
+
import GameEngineConfig from '../nitrogen/generated/shared/json/GameEngineConfig.json';
|
|
5
5
|
/**
|
|
6
6
|
* A game engine view component that renders the game world.
|
|
7
7
|
* Size it using the style prop like any other React Native view.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["getHostComponent","GameEngineConfig"
|
|
1
|
+
{"version":3,"names":["getHostComponent","GameEngineConfig"],"sourceRoot":"../../src","sources":["GameEngine.tsx"],"mappings":";;AAAA,SAASA,gBAAgB,QAAQ,4BAA4B;AAC7D,OAAOC,gBAAgB,MAAM,yDAAyD;AAGtF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAeD,gBAAgB,CAC7B,YAAY,EACZ,MAAMC,gBACR,CAAC","ignoreList":[]}
|
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { gameMethods } from "./GameMethods.nitro.js";
|
|
4
|
+
/** Sets up the game engine with the given configuration. Call this before anything else. */
|
|
5
|
+
export const configure = ({
|
|
6
|
+
tickRate,
|
|
7
|
+
screen,
|
|
8
|
+
entities = [],
|
|
9
|
+
systems = [],
|
|
10
|
+
paused = true
|
|
11
|
+
}) => {
|
|
12
|
+
let nativeSystems = [];
|
|
13
|
+
for (const system of systems) {
|
|
14
|
+
nativeSystems.push({
|
|
15
|
+
entities: system.entities,
|
|
16
|
+
collisions: system.collisions,
|
|
17
|
+
onTick: (e, c) => {
|
|
18
|
+
const start = Date.now();
|
|
19
|
+
system.onTick(e, c);
|
|
20
|
+
const finish = Date.now();
|
|
21
|
+
return finish - start;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
gameMethods.setTickRate(tickRate);
|
|
26
|
+
gameMethods.setScreen(screen);
|
|
27
|
+
gameMethods.setEntities(entities);
|
|
28
|
+
gameMethods.setSystems(nativeSystems);
|
|
29
|
+
if (paused) {
|
|
30
|
+
gameMethods.pause();
|
|
31
|
+
} else {
|
|
32
|
+
gameMethods.resume();
|
|
33
|
+
}
|
|
34
|
+
};
|
|
4
35
|
|
|
5
36
|
/** Pauses the game loop. Systems will stop running. */
|
|
6
37
|
export const pause = () => gameMethods.pause();
|
|
@@ -8,6 +39,18 @@ export const pause = () => gameMethods.pause();
|
|
|
8
39
|
/** Resumes the game loop. */
|
|
9
40
|
export const resume = () => gameMethods.resume();
|
|
10
41
|
|
|
42
|
+
/** Spawns one or more entities into the world. Skips duplicates by id. */
|
|
43
|
+
export const spawn = entities => {
|
|
44
|
+
const entityArray = Array.isArray(entities) ? entities : [entities];
|
|
45
|
+
gameMethods.spawn(entityArray);
|
|
46
|
+
};
|
|
47
|
+
|
|
11
48
|
/** Removes an entity or all entities matching the given id prefix from the world. */
|
|
12
49
|
export const despawn = id => gameMethods.despawn(id);
|
|
50
|
+
|
|
51
|
+
/** Updates one or more entities. Only the provided fields are changed. */
|
|
52
|
+
export const update = updates => {
|
|
53
|
+
const entityUpdateArray = Array.isArray(updates) ? updates : [updates];
|
|
54
|
+
gameMethods.update(entityUpdateArray);
|
|
55
|
+
};
|
|
13
56
|
//# sourceMappingURL=GameMethods.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["gameMethods","pause","resume","despawn","id"],"sourceRoot":"../../src","sources":["GameMethods.ts"],"mappings":";;AAAA,SAASA,WAAW,QAAQ,wBAAqB
|
|
1
|
+
{"version":3,"names":["gameMethods","configure","tickRate","screen","entities","systems","paused","nativeSystems","system","push","collisions","onTick","e","c","start","Date","now","finish","setTickRate","setScreen","setEntities","setSystems","pause","resume","spawn","entityArray","Array","isArray","despawn","id","update","updates","entityUpdateArray"],"sourceRoot":"../../src","sources":["GameMethods.ts"],"mappings":";;AAAA,SAASA,WAAW,QAAQ,wBAAqB;AAIjD;AACA,OAAO,MAAMC,SAAS,GAAGA,CAAC;EACxBC,QAAQ;EACRC,MAAM;EACNC,QAAQ,GAAG,EAAE;EACbC,OAAO,GAAG,EAAE;EACZC,MAAM,GAAG;AACH,CAAC,KAAK;EACZ,IAAIC,aAAuB,GAAG,EAAE;EAEhC,KAAK,MAAMC,MAAM,IAAIH,OAAO,EAAE;IAC5BE,aAAa,CAACE,IAAI,CAAC;MACjBL,QAAQ,EAAEI,MAAM,CAACJ,QAAQ;MACzBM,UAAU,EAAEF,MAAM,CAACE,UAAU;MAC7BC,MAAM,EAAEA,CAACC,CAAC,EAAEC,CAAC,KAAK;QAChB,MAAMC,KAAK,GAAGC,IAAI,CAACC,GAAG,CAAC,CAAC;QACxBR,MAAM,CAACG,MAAM,CAACC,CAAC,EAAEC,CAAC,CAAC;QACnB,MAAMI,MAAM,GAAGF,IAAI,CAACC,GAAG,CAAC,CAAC;QACzB,OAAOC,MAAM,GAAGH,KAAK;MACvB;IACF,CAAC,CAAC;EACJ;EAEAd,WAAW,CAACkB,WAAW,CAAChB,QAAQ,CAAC;EACjCF,WAAW,CAACmB,SAAS,CAAChB,MAAM,CAAC;EAC7BH,WAAW,CAACoB,WAAW,CAAChB,QAAQ,CAAC;EACjCJ,WAAW,CAACqB,UAAU,CAACd,aAAa,CAAC;EACrC,IAAID,MAAM,EAAE;IACVN,WAAW,CAACsB,KAAK,CAAC,CAAC;EACrB,CAAC,MAAM;IACLtB,WAAW,CAACuB,MAAM,CAAC,CAAC;EACtB;AACF,CAAC;;AAED;AACA,OAAO,MAAMD,KAAK,GAAGA,CAAA,KAAMtB,WAAW,CAACsB,KAAK,CAAC,CAAC;;AAE9C;AACA,OAAO,MAAMC,MAAM,GAAGA,CAAA,KAAMvB,WAAW,CAACuB,MAAM,CAAC,CAAC;;AAEhD;AACA,OAAO,MAAMC,KAAK,GAAIpB,QAA2B,IAAK;EACpD,MAAMqB,WAAW,GAAGC,KAAK,CAACC,OAAO,CAACvB,QAAQ,CAAC,GAAGA,QAAQ,GAAG,CAACA,QAAQ,CAAC;EACnEJ,WAAW,CAACwB,KAAK,CAACC,WAAW,CAAC;AAChC,CAAC;;AAED;AACA,OAAO,MAAMG,OAAO,GAAIC,EAAU,IAAK7B,WAAW,CAAC4B,OAAO,CAACC,EAAE,CAAC;;AAE9D;AACA,OAAO,MAAMC,MAAM,GAAIC,OAAsC,IAAK;EAChE,MAAMC,iBAAiB,GAAGN,KAAK,CAACC,OAAO,CAACI,OAAO,CAAC,GAAGA,OAAO,GAAG,CAACA,OAAO,CAAC;EACtE/B,WAAW,CAAC8B,MAAM,CAACE,iBAAiB,CAAC;AACvC,CAAC","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["GameEngine"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,UAAU,MAAM,iBAAc;AAErC,cAAc,kBAAe;AAC7B,cAAc,
|
|
1
|
+
{"version":3,"names":["GameEngine"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,UAAU,MAAM,iBAAc;AAErC,cAAc,kBAAe;AAC7B,cAAc,iBAAc;AAC5B,cAAc,YAAS;AAQvB,SAASA,UAAU","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GameAssets.d.ts","sourceRoot":"","sources":["../../../src/GameAssets.ts"],"names":[],"mappings":"AAmCA,eAAO,MAAM,UAAU,GAAU,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChE,QAAQ,CAAC,KACR,OAAO,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,GAAE,CASpC,CAAC"}
|
|
@@ -4,8 +4,8 @@ interface GameAssets extends HybridObject<{
|
|
|
4
4
|
android: 'kotlin';
|
|
5
5
|
}> {
|
|
6
6
|
isAssetRegistered(id: number): boolean;
|
|
7
|
-
registerSvg(id: number, uri: string): void
|
|
8
|
-
registerLottie(id: number, json: string): void
|
|
7
|
+
registerSvg(id: number, uri: string): Promise<void>;
|
|
8
|
+
registerLottie(id: number, json: string): Promise<void>;
|
|
9
9
|
}
|
|
10
10
|
export declare const gameAssets: GameAssets;
|
|
11
11
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GameAssets.nitro.d.ts","sourceRoot":"","sources":["../../../src/GameAssets.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG/D,UAAU,UAAW,SAAQ,YAAY,CAAC;IACxC,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC;CACnB,CAAC;IACA,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IACvC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"GameAssets.nitro.d.ts","sourceRoot":"","sources":["../../../src/GameAssets.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG/D,UAAU,UAAW,SAAQ,YAAY,CAAC;IACxC,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC;CACnB,CAAC;IACA,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IACvC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED,eAAO,MAAM,UAAU,YACoC,CAAC"}
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import type { Entity, EntityUpdate } from './nativeTypes';
|
|
2
|
+
import type { Config } from './types';
|
|
3
|
+
/** Sets up the game engine with the given configuration. Call this before anything else. */
|
|
4
|
+
export declare const configure: ({ tickRate, screen, entities, systems, paused, }: Config) => void;
|
|
1
5
|
/** Pauses the game loop. Systems will stop running. */
|
|
2
6
|
export declare const pause: () => void;
|
|
3
7
|
/** Resumes the game loop. */
|
|
4
8
|
export declare const resume: () => void;
|
|
9
|
+
/** Spawns one or more entities into the world. Skips duplicates by id. */
|
|
10
|
+
export declare const spawn: (entities: Entity | Entity[]) => void;
|
|
5
11
|
/** Removes an entity or all entities matching the given id prefix from the world. */
|
|
6
12
|
export declare const despawn: (id: string) => void;
|
|
13
|
+
/** Updates one or more entities. Only the provided fields are changed. */
|
|
14
|
+
export declare const update: (updates: EntityUpdate | EntityUpdate[]) => void;
|
|
7
15
|
//# sourceMappingURL=GameMethods.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GameMethods.d.ts","sourceRoot":"","sources":["../../../src/GameMethods.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GameMethods.d.ts","sourceRoot":"","sources":["../../../src/GameMethods.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAU,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC,4FAA4F;AAC5F,eAAO,MAAM,SAAS,GAAI,kDAMvB,MAAM,SAyBR,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,KAAK,YAA4B,CAAC;AAE/C,6BAA6B;AAC7B,eAAO,MAAM,MAAM,YAA6B,CAAC;AAEjD,0EAA0E;AAC1E,eAAO,MAAM,KAAK,GAAI,UAAU,MAAM,GAAG,MAAM,EAAE,SAGhD,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,OAAO,GAAI,IAAI,MAAM,SAA4B,CAAC;AAE/D,0EAA0E;AAC1E,eAAO,MAAM,MAAM,GAAI,SAAS,YAAY,GAAG,YAAY,EAAE,SAG5D,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import GameEngine from './GameEngine';
|
|
2
2
|
export * from './GameMethods';
|
|
3
|
-
export * from './
|
|
3
|
+
export * from './GameAssets';
|
|
4
4
|
export * from './types';
|
|
5
|
+
export type { Screen, Entity, CollisionPair, Collision, EntityUpdate, } from './nativeTypes';
|
|
5
6
|
export { GameEngine };
|
|
6
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,cAAc,CAAC;AAEtC,cAAc,eAAe,CAAC;AAC9B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,cAAc,CAAC;AAEtC,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,YAAY,EACV,MAAM,EACN,MAAM,EACN,aAAa,EACb,SAAS,EACT,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,CAAC"}
|