rngine 0.8.2 → 0.9.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 +28 -21
- package/android/CMakeLists.txt +5 -2
- package/android/kls_database.db +0 -0
- package/android/src/main/java/com/margelo/nitro/rngine/ImageLoaderHelper.kt +56 -0
- package/lib/module/GameMethods.js +23 -10
- package/lib/module/GameMethods.js.map +1 -1
- package/lib/module/GameMethods.nitro.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/GameMethods.d.ts +11 -4
- package/lib/typescript/src/GameMethods.d.ts.map +1 -1
- package/lib/typescript/src/GameMethods.nitro.d.ts +9 -3
- package/lib/typescript/src/GameMethods.nitro.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/nativeTypes.d.ts +12 -2
- package/lib/typescript/src/nativeTypes.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +2 -2
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/nitrogen/generated/shared/c++/HybridGameMethodsSpec.cpp +3 -2
- package/nitrogen/generated/shared/c++/HybridGameMethodsSpec.hpp +6 -2
- package/nitrogen/generated/shared/c++/Screen.hpp +9 -1
- package/nitrogen/generated/shared/c++/ScreenUpdate.hpp +120 -0
- package/nitrogen/generated/shared/c++/System.hpp +8 -11
- package/nitrogen/generated/shared/c++/SystemContext.hpp +99 -0
- package/package.json +1 -1
- package/shared/GameLoop.cpp +16 -33
- package/shared/GameMethods.cpp +124 -92
- package/shared/GameMethods.hpp +5 -3
- package/shared/GameRenderer.cpp +27 -81
- package/shared/GameRenderer.hpp +8 -5
- package/shared/utils/AssetUtils.cpp +92 -0
- package/shared/utils/AssetUtils.hpp +11 -0
- package/shared/{CollisionUtils.cpp → utils/CollisionUtils.cpp} +9 -8
- package/shared/utils/CollisionUtils.hpp +10 -0
- package/src/GameMethods.nitro.ts +12 -2
- package/src/GameMethods.ts +23 -11
- package/src/index.tsx +1 -0
- package/src/nativeTypes.ts +13 -2
- package/src/types.ts +2 -2
- package/android/src/main/java/com/margelo/nitro/rngine/SvgLoaderHelper.kt +0 -24
- package/shared/CollisionUtils.hpp +0 -21
- /package/shared/{ColorUtils.cpp → utils/ColorUtils.cpp} +0 -0
- /package/shared/{ColorUtils.hpp → utils/ColorUtils.hpp} +0 -0
package/shared/GameMethods.hpp
CHANGED
|
@@ -24,14 +24,16 @@ public:
|
|
|
24
24
|
|
|
25
25
|
void despawn(const std::string &id) override;
|
|
26
26
|
|
|
27
|
-
void
|
|
27
|
+
void updateEntities(const std::vector<EntityUpdate> &entityUpdates) override;
|
|
28
|
+
|
|
29
|
+
void updateScreen(const ScreenUpdate &screenUpdate) override;
|
|
28
30
|
|
|
29
31
|
bool isAssetLoaded(double id) override;
|
|
30
32
|
|
|
31
33
|
std::shared_ptr<Promise<bool>>
|
|
32
34
|
loadLottie(double id, const std::string &jsonStr) override;
|
|
33
35
|
|
|
34
|
-
std::shared_ptr<Promise<bool>>
|
|
35
|
-
|
|
36
|
+
std::shared_ptr<Promise<bool>> loadImage(double id,
|
|
37
|
+
const std::string &svgUri) override;
|
|
36
38
|
};
|
|
37
39
|
} // namespace margelo::nitro::rngine
|
package/shared/GameRenderer.cpp
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include "GameRenderer.hpp"
|
|
2
|
+
#include "AssetUtils.hpp"
|
|
2
3
|
#include "ColorUtils.hpp"
|
|
3
4
|
#include "Rect.hpp"
|
|
4
5
|
|
|
@@ -10,6 +11,7 @@
|
|
|
10
11
|
#include "include/core/SkColorSpace.h"
|
|
11
12
|
#include "include/core/SkPaint.h"
|
|
12
13
|
#include "include/core/SkRect.h"
|
|
14
|
+
#include "include/core/SkRefCnt.h"
|
|
13
15
|
#include "include/core/SkSurface.h"
|
|
14
16
|
|
|
15
17
|
#include "include/gpu/ganesh/GrBackendSurface.h"
|
|
@@ -133,15 +135,20 @@ void GameRenderer::render(const Screen &screen,
|
|
|
133
135
|
|
|
134
136
|
float scale = std::min(scaleX, scaleY);
|
|
135
137
|
|
|
136
|
-
float offsetX =
|
|
137
|
-
|
|
138
|
-
|
|
138
|
+
float offsetX =
|
|
139
|
+
static_cast<float>(_width) * 0.5f - static_cast<float>(screen.px) * scale;
|
|
140
|
+
float offsetY = static_cast<float>(_height) * 0.5f -
|
|
141
|
+
static_cast<float>(screen.py) * scale;
|
|
139
142
|
|
|
140
143
|
canvas->save();
|
|
141
144
|
canvas->translate(offsetX, offsetY);
|
|
142
145
|
canvas->scale(scale, scale);
|
|
143
146
|
|
|
144
|
-
SkRect gameBounds =
|
|
147
|
+
SkRect gameBounds =
|
|
148
|
+
SkRect::MakeXYWH(static_cast<float>(screen.px) - virtualWidth * 0.5f,
|
|
149
|
+
static_cast<float>(screen.py) - virtualHeight * 0.5f,
|
|
150
|
+
virtualWidth, virtualHeight);
|
|
151
|
+
|
|
145
152
|
canvas->clipRect(gameBounds);
|
|
146
153
|
|
|
147
154
|
if (screen.color.has_value()) {
|
|
@@ -149,44 +156,16 @@ void GameRenderer::render(const Screen &screen,
|
|
|
149
156
|
}
|
|
150
157
|
|
|
151
158
|
if (screen.asset.has_value() && screen.asset.value() != 0) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
SkSize intrinsicSize = svgDom->containerSize();
|
|
159
|
-
if (intrinsicSize.isEmpty()) {
|
|
160
|
-
svgDom->setContainerSize(SkSize::Make(virtualWidth, virtualHeight));
|
|
161
|
-
intrinsicSize = SkSize::Make(virtualWidth, virtualHeight);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
float scaleX = virtualWidth / intrinsicSize.width();
|
|
165
|
-
float scaleY = virtualHeight / intrinsicSize.height();
|
|
166
|
-
|
|
167
|
-
canvas->save();
|
|
168
|
-
if (screen.flipH.has_value() || screen.flipV.has_value()) {
|
|
169
|
-
canvas->translate(virtualWidth / 2.f, virtualHeight / 2.f);
|
|
170
|
-
canvas->scale(screen.flipH.value_or(false) ? -1.f : 1.f,
|
|
171
|
-
screen.flipV.value_or(false) ? -1.f : 1.f);
|
|
172
|
-
canvas->translate(-virtualWidth / 2.f, -virtualHeight / 2.f);
|
|
173
|
-
}
|
|
174
|
-
canvas->scale(scaleX, scaleY);
|
|
175
|
-
svgDom->render(canvas);
|
|
176
|
-
canvas->restore();
|
|
177
|
-
} else {
|
|
178
|
-
auto lottieIt = _lottieCache.find(assetId);
|
|
179
|
-
if (lottieIt != _lottieCache.end() && lottieIt->second) {
|
|
180
|
-
auto &lottie = lottieIt->second;
|
|
181
|
-
lottie->seek(screen.progress.value_or(0.0));
|
|
182
|
-
SkRect dstBounds = SkRect::MakeWH(virtualWidth, virtualHeight);
|
|
183
|
-
lottie->render(canvas, &dstBounds);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
159
|
+
SkAutoCanvasRestore restore(canvas, true);
|
|
160
|
+
canvas->translate(gameBounds.left(), gameBounds.top());
|
|
161
|
+
AssetUtils::drawAsset(canvas, screen.asset.value(), virtualWidth,
|
|
162
|
+
virtualHeight, screen.flipH.value_or(false),
|
|
163
|
+
screen.flipV.value_or(false),
|
|
164
|
+
screen.progress.value_or(0.0));
|
|
186
165
|
}
|
|
187
166
|
|
|
188
167
|
for (const auto &[id, entity] : entities) {
|
|
189
|
-
if (!isEntityVisible(entity,
|
|
168
|
+
if (!isEntityVisible(entity, gameBounds)) {
|
|
190
169
|
continue;
|
|
191
170
|
}
|
|
192
171
|
|
|
@@ -219,8 +198,6 @@ void GameRenderer::render(const Screen &screen,
|
|
|
219
198
|
}
|
|
220
199
|
|
|
221
200
|
if ((entity.asset.has_value() && entity.asset.value() != 0)) {
|
|
222
|
-
double assetId = entity.asset.value();
|
|
223
|
-
|
|
224
201
|
float width = 0.f, height = 0.f;
|
|
225
202
|
std::visit(
|
|
226
203
|
[&](const auto &shape) {
|
|
@@ -239,39 +216,10 @@ void GameRenderer::render(const Screen &screen,
|
|
|
239
216
|
SkAutoCanvasRestore autoRestore(canvas, true);
|
|
240
217
|
canvas->translate(px - width / 2, py - height / 2);
|
|
241
218
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
canvas->translate(-width / 2.f, -height / 2.f);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
auto svgIt = _svgCache.find(assetId);
|
|
250
|
-
if (svgIt != _svgCache.end() && svgIt->second) {
|
|
251
|
-
auto &svgDom = svgIt->second;
|
|
252
|
-
|
|
253
|
-
SkSize intrinsicSize = svgDom->containerSize();
|
|
254
|
-
if (intrinsicSize.isEmpty()) {
|
|
255
|
-
svgDom->setContainerSize(SkSize::Make(width, height));
|
|
256
|
-
intrinsicSize = SkSize::Make(width, height);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
float scaleX = width / intrinsicSize.width();
|
|
260
|
-
float scaleY = height / intrinsicSize.height();
|
|
261
|
-
|
|
262
|
-
canvas->save();
|
|
263
|
-
canvas->scale(scaleX, scaleY);
|
|
264
|
-
svgDom->render(canvas);
|
|
265
|
-
canvas->restore();
|
|
266
|
-
} else {
|
|
267
|
-
auto lottieIt = _lottieCache.find(assetId);
|
|
268
|
-
if (lottieIt != _lottieCache.end() && lottieIt->second) {
|
|
269
|
-
auto &lottie = lottieIt->second;
|
|
270
|
-
lottie->seek(entity.progress.value_or(0.0));
|
|
271
|
-
SkRect dstBounds = SkRect::MakeWH(width, height);
|
|
272
|
-
lottie->render(canvas, &dstBounds);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
219
|
+
AssetUtils::drawAsset(canvas, entity.asset.value(), width, height,
|
|
220
|
+
entity.flipH.value_or(false),
|
|
221
|
+
entity.flipV.value_or(false),
|
|
222
|
+
entity.progress.value_or(0.0));
|
|
275
223
|
}
|
|
276
224
|
}
|
|
277
225
|
}
|
|
@@ -284,15 +232,13 @@ void GameRenderer::render(const Screen &screen,
|
|
|
284
232
|
__android_log_print(ANDROID_LOG_DEBUG, "GameRenderer", "render: complete");
|
|
285
233
|
}
|
|
286
234
|
|
|
287
|
-
bool GameRenderer::isEntityVisible(const Entity &entity,
|
|
288
|
-
|
|
289
|
-
float width = 0.f;
|
|
290
|
-
float height = 0.f;
|
|
235
|
+
bool GameRenderer::isEntityVisible(const Entity &entity,
|
|
236
|
+
const SkRect &viewBounds) {
|
|
237
|
+
float width = 0.f, height = 0.f;
|
|
291
238
|
|
|
292
239
|
std::visit(
|
|
293
240
|
[&](const auto &shape) {
|
|
294
241
|
using T = std::decay_t<decltype(shape)>;
|
|
295
|
-
|
|
296
242
|
if constexpr (std::is_same_v<T, Rect>) {
|
|
297
243
|
width = static_cast<float>(shape.width);
|
|
298
244
|
height = static_cast<float>(shape.height);
|
|
@@ -307,8 +253,8 @@ bool GameRenderer::isEntityVisible(const Entity &entity, float screenWidth,
|
|
|
307
253
|
float top = static_cast<float>(entity.py) - height / 2.f;
|
|
308
254
|
float bottom = static_cast<float>(entity.py) + height / 2.f;
|
|
309
255
|
|
|
310
|
-
return right >
|
|
311
|
-
top <
|
|
256
|
+
return right > viewBounds.left() && left < viewBounds.right() &&
|
|
257
|
+
bottom > viewBounds.top() && top < viewBounds.bottom();
|
|
312
258
|
}
|
|
313
259
|
|
|
314
260
|
bool GameRenderer::initializeEGL() {
|
package/shared/GameRenderer.hpp
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
#include "Entity.hpp"
|
|
3
3
|
#include "Screen.hpp"
|
|
4
|
+
#include "include/core/SkImage.h"
|
|
5
|
+
#include "include/core/SkRect.h"
|
|
4
6
|
#include "include/core/SkSurface.h"
|
|
5
7
|
#include "include/gpu/ganesh/GrDirectContext.h"
|
|
6
8
|
#include "modules/skottie/include/Skottie.h"
|
|
@@ -21,9 +23,11 @@ public:
|
|
|
21
23
|
|
|
22
24
|
~GameRenderer();
|
|
23
25
|
|
|
24
|
-
std::map<double, sk_sp<SkSVGDOM
|
|
25
|
-
|
|
26
|
+
std::map<double, std::variant<sk_sp<SkSVGDOM>, sk_sp<SkImage>>> &
|
|
27
|
+
getImageCacheInternal() {
|
|
28
|
+
return _imageCache;
|
|
26
29
|
};
|
|
30
|
+
|
|
27
31
|
std::map<double, sk_sp<skottie::Animation>> &getLottieCacheInternal() {
|
|
28
32
|
return _lottieCache;
|
|
29
33
|
};
|
|
@@ -52,11 +56,10 @@ private:
|
|
|
52
56
|
int _height{0};
|
|
53
57
|
bool _initialized{false};
|
|
54
58
|
|
|
55
|
-
std::map<double, sk_sp<SkSVGDOM>> _svgCache;
|
|
56
59
|
std::map<double, sk_sp<skottie::Animation>> _lottieCache;
|
|
60
|
+
std::map<double, std::variant<sk_sp<SkSVGDOM>, sk_sp<SkImage>>> _imageCache;
|
|
57
61
|
|
|
58
|
-
bool isEntityVisible(const Entity &entity,
|
|
59
|
-
float screenHeight);
|
|
62
|
+
bool isEntityVisible(const Entity &entity, const SkRect &viewBounds);
|
|
60
63
|
|
|
61
64
|
bool initializeEGL();
|
|
62
65
|
bool createEGLSurface();
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#include "AssetUtils.hpp"
|
|
2
|
+
#include "GameRenderer.hpp"
|
|
3
|
+
#include <variant>
|
|
4
|
+
|
|
5
|
+
namespace margelo::nitro::rngine::AssetUtils {
|
|
6
|
+
static void drawSVG(SkCanvas *canvas, const sk_sp<SkSVGDOM> &svg, float width,
|
|
7
|
+
float height) {
|
|
8
|
+
SkSize intrinsicSize = svg->containerSize();
|
|
9
|
+
if (intrinsicSize.isEmpty()) {
|
|
10
|
+
svg->setContainerSize(SkSize::Make(width, height));
|
|
11
|
+
intrinsicSize = SkSize::Make(width, height);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
SkAutoCanvasRestore restore(canvas, true);
|
|
15
|
+
canvas->scale(width / intrinsicSize.width(), height / intrinsicSize.height());
|
|
16
|
+
svg->render(canvas);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static void drawRaster(SkCanvas *canvas, const sk_sp<SkImage> &raster,
|
|
20
|
+
float width, float height) {
|
|
21
|
+
float intrinsicW = static_cast<float>(raster->width());
|
|
22
|
+
float intrinsicH = static_cast<float>(raster->height());
|
|
23
|
+
if (intrinsicW <= 0.0f || intrinsicH <= 0.0f)
|
|
24
|
+
return;
|
|
25
|
+
|
|
26
|
+
SkAutoCanvasRestore restore(canvas, true);
|
|
27
|
+
canvas->scale(width / intrinsicW, height / intrinsicH);
|
|
28
|
+
SkSamplingOptions sampling(SkFilterMode::kLinear, SkMipmapMode::kLinear);
|
|
29
|
+
canvas->drawImage(raster, 0.0f, 0.0f, sampling);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
void drawAsset(SkCanvas *canvas, double asset, float targetWidth,
|
|
33
|
+
float targetHeight, bool flipH, bool flipV, double progress) {
|
|
34
|
+
SkAutoCanvasRestore restoreGuard(canvas, true);
|
|
35
|
+
|
|
36
|
+
if (flipH || flipV) {
|
|
37
|
+
canvas->translate(targetWidth * 0.5f, targetHeight * 0.5f);
|
|
38
|
+
canvas->scale(flipH ? -1.0f : 1.0f, flipV ? -1.0f : 1.0f);
|
|
39
|
+
canvas->translate(-targetWidth * 0.5f, -targetHeight * 0.5f);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (asset == 0) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
auto &gameRenderer = GameRenderer::getInstance();
|
|
47
|
+
|
|
48
|
+
if (asset > 0) {
|
|
49
|
+
auto &imageCache = gameRenderer.getImageCacheInternal();
|
|
50
|
+
auto imageIt = imageCache.find(asset);
|
|
51
|
+
if (imageIt != imageCache.end()) {
|
|
52
|
+
std::visit(
|
|
53
|
+
[&](const auto &image) {
|
|
54
|
+
using T = std::decay_t<decltype(image)>;
|
|
55
|
+
if constexpr (std::is_same_v<T, sk_sp<SkSVGDOM>>) {
|
|
56
|
+
drawSVG(canvas, image, targetWidth, targetHeight);
|
|
57
|
+
} else {
|
|
58
|
+
drawRaster(canvas, image, targetWidth, targetHeight);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
imageIt->second);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
auto &lottieCache = gameRenderer.getLottieCacheInternal();
|
|
67
|
+
auto lottieIt = lottieCache.find(asset);
|
|
68
|
+
if (lottieIt != lottieCache.end() && lottieIt->second) {
|
|
69
|
+
lottieIt->second->seek(progress);
|
|
70
|
+
SkRect dstBounds = SkRect::MakeWH(targetWidth, targetHeight);
|
|
71
|
+
lottieIt->second->render(canvas, &dstBounds);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
void updateProgress(std::optional<double> &progress,
|
|
76
|
+
std::optional<double> &speed, double asset,
|
|
77
|
+
double deltaTime) {
|
|
78
|
+
if (asset < 0) {
|
|
79
|
+
auto &lottieCache = GameRenderer::getInstance().getLottieCacheInternal();
|
|
80
|
+
auto it = lottieCache.find(asset);
|
|
81
|
+
if (it != lottieCache.end() && it->second) {
|
|
82
|
+
if (speed.has_value() && speed.value() > 0) {
|
|
83
|
+
progress = fmod(progress.value_or(0.0) + (deltaTime * speed.value()) /
|
|
84
|
+
it->second->duration(),
|
|
85
|
+
1.0);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
} else if (progress.has_value()) {
|
|
89
|
+
progress.reset();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} // namespace margelo::nitro::rngine::AssetUtils
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include "include/core/SkCanvas.h"
|
|
3
|
+
#include "modules/svg/include/SkSVGDOM.h"
|
|
4
|
+
|
|
5
|
+
namespace margelo::nitro::rngine::AssetUtils {
|
|
6
|
+
void drawAsset(SkCanvas *canvas, double asset, float targetWidth,
|
|
7
|
+
float targetHeight, bool flipH, bool flipV, double progress);
|
|
8
|
+
void updateProgress(std::optional<double> &progress,
|
|
9
|
+
std::optional<double> &speed, double asset,
|
|
10
|
+
double deltaTime);
|
|
11
|
+
} // namespace margelo::nitro::rngine::AssetUtils
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#include "CollisionUtils.hpp"
|
|
2
2
|
#include "Collision.hpp"
|
|
3
|
+
#include "Overlap.hpp"
|
|
3
4
|
#include <optional>
|
|
4
5
|
|
|
5
6
|
namespace margelo::nitro::rngine::CollisionUtils {
|
|
6
|
-
std::optional<Overlap> overlap(const Rect &a, double ax, double ay,
|
|
7
|
-
|
|
7
|
+
static std::optional<Overlap> overlap(const Rect &a, double ax, double ay,
|
|
8
|
+
const Rect &b, double bx, double by) {
|
|
8
9
|
|
|
9
10
|
double aLeft = ax - a.width / 2.0, aRight = ax + a.width / 2.0;
|
|
10
11
|
double aTop = ay - a.height / 2.0, aBottom = ay + a.height / 2.0;
|
|
@@ -26,8 +27,8 @@ std::optional<Overlap> overlap(const Rect &a, double ax, double ay,
|
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
std::optional<Overlap> overlap(const Circle &a, double ax, double ay,
|
|
30
|
-
|
|
30
|
+
static std::optional<Overlap> overlap(const Circle &a, double ax, double ay,
|
|
31
|
+
const Circle &b, double bx, double by) {
|
|
31
32
|
double dx = bx - ax, dy = by - ay;
|
|
32
33
|
double dist = std::sqrt(dx * dx + dy * dy);
|
|
33
34
|
double depth = (a.radius + b.radius) - dist;
|
|
@@ -41,8 +42,8 @@ std::optional<Overlap> overlap(const Circle &a, double ax, double ay,
|
|
|
41
42
|
return Overlap{depth, dx / dist, dy / dist};
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
std::optional<Overlap> overlap(const Rect &a, double ax, double ay,
|
|
45
|
-
|
|
45
|
+
static std::optional<Overlap> overlap(const Rect &a, double ax, double ay,
|
|
46
|
+
const Circle &b, double bx, double by) {
|
|
46
47
|
double left = ax - a.width / 2.0, right = ax + a.width / 2.0;
|
|
47
48
|
double top = ay - a.height / 2.0, bottom = ay + a.height / 2.0;
|
|
48
49
|
|
|
@@ -67,8 +68,8 @@ std::optional<Overlap> overlap(const Rect &a, double ax, double ay,
|
|
|
67
68
|
return Overlap{b.radius - dist, dx / dist, dy / dist};
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
std::optional<Overlap> overlap(const Circle &a, double ax, double ay,
|
|
71
|
-
|
|
71
|
+
static std::optional<Overlap> overlap(const Circle &a, double ax, double ay,
|
|
72
|
+
const Rect &b, double bx, double by) {
|
|
72
73
|
auto result = overlap(b, bx, by, a, ax, ay);
|
|
73
74
|
|
|
74
75
|
if (!result.has_value()) {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "Collision.hpp"
|
|
4
|
+
#include "Entity.hpp"
|
|
5
|
+
#include <optional>
|
|
6
|
+
|
|
7
|
+
namespace margelo::nitro::rngine::CollisionUtils {
|
|
8
|
+
std::optional<Collision> shapeOverlap(const Entity &entityA,
|
|
9
|
+
const Entity &entityB);
|
|
10
|
+
} // namespace margelo::nitro::rngine::CollisionUtils
|
package/src/GameMethods.nitro.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
System,
|
|
6
6
|
Screen,
|
|
7
7
|
World,
|
|
8
|
+
ScreenUpdate,
|
|
8
9
|
} from './nativeTypes';
|
|
9
10
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
10
11
|
|
|
@@ -12,19 +13,28 @@ interface GameMethods extends HybridObject<{
|
|
|
12
13
|
ios: 'c++';
|
|
13
14
|
android: 'c++';
|
|
14
15
|
}> {
|
|
16
|
+
/** Configuration Methods */
|
|
15
17
|
setWorld(world: World): void;
|
|
16
18
|
setScreen(screen: Screen): void;
|
|
17
19
|
setEntities(entities: Entity[]): void;
|
|
18
20
|
setSystems(systems: System[]): void;
|
|
21
|
+
|
|
22
|
+
/** Pause/Resume Methods */
|
|
19
23
|
pause(): void;
|
|
20
24
|
resume(): void;
|
|
25
|
+
|
|
26
|
+
/** Entity Update Methods */
|
|
21
27
|
spawn(entities: Entity[]): void;
|
|
22
28
|
despawn(id: string): void;
|
|
23
|
-
|
|
29
|
+
updateEntities(entityUpdates: EntityUpdate[]): void;
|
|
30
|
+
|
|
31
|
+
/** Screen Update Methods */
|
|
32
|
+
updateScreen(screenUpdate: ScreenUpdate): void;
|
|
24
33
|
|
|
34
|
+
/** Asset Methods */
|
|
25
35
|
isAssetLoaded(id: number): boolean;
|
|
26
36
|
loadLottie(id: number, jsonStr: string): Promise<boolean>;
|
|
27
|
-
|
|
37
|
+
loadImage(id: number, imageUri: string): Promise<boolean>;
|
|
28
38
|
}
|
|
29
39
|
|
|
30
40
|
export const gameMethods =
|
package/src/GameMethods.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { gameMethods } from './GameMethods.nitro';
|
|
2
|
-
import type { Entity, EntityUpdate, System } from './nativeTypes';
|
|
2
|
+
import type { Entity, EntityUpdate, ScreenUpdate, System } from './nativeTypes';
|
|
3
3
|
import type { Config } from './types';
|
|
4
4
|
import { Image } from 'react-native';
|
|
5
5
|
|
|
@@ -17,9 +17,9 @@ export const configure = ({
|
|
|
17
17
|
nativeSystems.push({
|
|
18
18
|
entities: system.entities,
|
|
19
19
|
collisions: system.collisions,
|
|
20
|
-
onTick: (
|
|
20
|
+
onTick: (systemContext) => {
|
|
21
21
|
const start = Date.now();
|
|
22
|
-
system.onTick(
|
|
22
|
+
system.onTick(systemContext);
|
|
23
23
|
const finish = Date.now();
|
|
24
24
|
return finish - start;
|
|
25
25
|
},
|
|
@@ -49,13 +49,22 @@ export const spawn = (entities: Entity | Entity[]) => {
|
|
|
49
49
|
gameMethods.spawn(entityArray);
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
/** Removes an entity or all entities matching the given id prefix from the world. */
|
|
52
|
+
/** Removes an entity or all entities matching the given id prefix from the world. Only the provided fields are changed. */
|
|
53
53
|
export const despawn = (id: string) => gameMethods.despawn(id);
|
|
54
54
|
|
|
55
|
-
/**
|
|
56
|
-
export const
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
/** Fires one update, applied to entities matching the given id prefix from the world. Only the provided fields are changed. */
|
|
56
|
+
export const updateEntity = (entityUpdate: EntityUpdate) => {
|
|
57
|
+
gameMethods.updateEntities([entityUpdate]);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/** Fires multiple updates, each applied to entities matching the given id prefix from the world. */
|
|
61
|
+
export const updateEntities = (entityUpdates: EntityUpdate[]) => {
|
|
62
|
+
gameMethods.updateEntities(entityUpdates);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/** Updates the screen. Only the provided fields are changed. */
|
|
66
|
+
export const updateScreen = (screenUpdate: ScreenUpdate) => {
|
|
67
|
+
gameMethods.updateScreen(screenUpdate);
|
|
59
68
|
};
|
|
60
69
|
|
|
61
70
|
const assetCache = new WeakMap<object, number>();
|
|
@@ -89,9 +98,9 @@ const loadAsset = async (asset: unknown) => {
|
|
|
89
98
|
if (!assetUri) {
|
|
90
99
|
throw new Error(`loadAssets: could not resolve asset URI for ${asset}`);
|
|
91
100
|
}
|
|
92
|
-
const
|
|
93
|
-
if (!
|
|
94
|
-
throw new Error('loadAssets: Failed to load
|
|
101
|
+
const isLoaded = await gameMethods.loadImage(asset, assetUri);
|
|
102
|
+
if (!isLoaded) {
|
|
103
|
+
throw new Error('loadAssets: Failed to load image asset');
|
|
95
104
|
}
|
|
96
105
|
return asset;
|
|
97
106
|
}
|
|
@@ -99,6 +108,9 @@ const loadAsset = async (asset: unknown) => {
|
|
|
99
108
|
throw new Error(`loadAssets: unsupported asset type "${typeof asset}"`);
|
|
100
109
|
};
|
|
101
110
|
|
|
111
|
+
/** Preloads one or more SVG, PNG or Lottie assets ahead of time.
|
|
112
|
+
* Takes an object mapping names to `require(...)` sources (SVG/PNG) or imported JSON (Lottie),
|
|
113
|
+
* and resolves to an object of the same shape with numeric asset ids. */
|
|
102
114
|
export const loadAssets = async <T extends Record<string, unknown>>(
|
|
103
115
|
assets: T
|
|
104
116
|
): Promise<{ [K in keyof T]: number }> => {
|
package/src/index.tsx
CHANGED
package/src/nativeTypes.ts
CHANGED
|
@@ -61,7 +61,7 @@ export interface World {
|
|
|
61
61
|
gy?: number;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
export interface Screen extends Rect, Renderable {}
|
|
64
|
+
export interface Screen extends Positioned, Rect, Renderable {}
|
|
65
65
|
|
|
66
66
|
export interface Entity extends Positioned, Shaped, Renderable, Kinematic {
|
|
67
67
|
/** Unique identifier. Use `_` as a separator for group queries e.g. `'enemy_1'`. */
|
|
@@ -75,6 +75,8 @@ export interface EntityUpdate extends Partial<
|
|
|
75
75
|
id: string;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
export interface ScreenUpdate extends Partial<Screen> {}
|
|
79
|
+
|
|
78
80
|
export interface CollisionPair {
|
|
79
81
|
/** Entity id or prefix of the first entity to watch. */
|
|
80
82
|
a: string;
|
|
@@ -95,11 +97,20 @@ export interface Collision {
|
|
|
95
97
|
ny: number;
|
|
96
98
|
}
|
|
97
99
|
|
|
100
|
+
export interface SystemContext {
|
|
101
|
+
/** Current game screen state. */
|
|
102
|
+
screen: Screen;
|
|
103
|
+
/** Entities resolved from the system's entity subscriptions. */
|
|
104
|
+
entities: Entity[];
|
|
105
|
+
/** Collisions matching the system's collision subscriptions. */
|
|
106
|
+
collisions: Collision[];
|
|
107
|
+
}
|
|
108
|
+
|
|
98
109
|
export interface System {
|
|
99
110
|
/** Entity ids or prefixes this system subscribes to. */
|
|
100
111
|
entities?: string[];
|
|
101
112
|
/** Collision pairs to watch for every tick. */
|
|
102
113
|
collisions?: CollisionPair[];
|
|
103
114
|
/** Called every tick with the resolved entities and collisions. */
|
|
104
|
-
onTick: (
|
|
115
|
+
onTick: (systemContext: SystemContext) => number;
|
|
105
116
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
System as NativeSystem,
|
|
3
|
-
Collision,
|
|
4
3
|
Screen,
|
|
5
4
|
Entity,
|
|
6
5
|
World,
|
|
6
|
+
SystemContext,
|
|
7
7
|
} from './nativeTypes';
|
|
8
8
|
|
|
9
9
|
export type System = Omit<NativeSystem, 'onTick'> & {
|
|
10
10
|
/** Called every tick with the resolved entities and collisions. */
|
|
11
|
-
onTick: (
|
|
11
|
+
onTick: (systemContext: SystemContext) => void;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export type Config = {
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
package com.margelo.nitro.rngine
|
|
2
|
-
|
|
3
|
-
import androidx.annotation.Keep
|
|
4
|
-
import com.margelo.nitro.NitroModules
|
|
5
|
-
import java.net.URL
|
|
6
|
-
|
|
7
|
-
@Keep
|
|
8
|
-
object SvgLoaderHelper {
|
|
9
|
-
@JvmStatic
|
|
10
|
-
fun loadFromUrl(uri: String): ByteArray {
|
|
11
|
-
return URL(uri).openStream().use { it.readBytes() }
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
@JvmStatic
|
|
15
|
-
fun loadFromResource(uri: String): ByteArray {
|
|
16
|
-
val context = NitroModules.applicationContext
|
|
17
|
-
?: throw IllegalStateException("No Context available!")
|
|
18
|
-
val resId = context.resources.getIdentifier(uri, "raw", context.packageName)
|
|
19
|
-
if (resId == 0) {
|
|
20
|
-
throw IllegalStateException("Could not resolve raw resource for asset: $uri")
|
|
21
|
-
}
|
|
22
|
-
return context.resources.openRawResource(resId).use { it.readBytes() }
|
|
23
|
-
}
|
|
24
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include "Circle.hpp"
|
|
4
|
-
#include "Collision.hpp"
|
|
5
|
-
#include "Entity.hpp"
|
|
6
|
-
#include "Overlap.hpp"
|
|
7
|
-
#include "Rect.hpp"
|
|
8
|
-
#include <optional>
|
|
9
|
-
|
|
10
|
-
namespace margelo::nitro::rngine::CollisionUtils {
|
|
11
|
-
std::optional<Overlap> overlap(const Rect &a, double ax, double ay,
|
|
12
|
-
const Rect &b, double bx, double by);
|
|
13
|
-
std::optional<Overlap> overlap(const Circle &a, double ax, double ay,
|
|
14
|
-
const Circle &b, double bx, double by);
|
|
15
|
-
std::optional<Overlap> overlap(const Rect &a, double ax, double ay,
|
|
16
|
-
const Circle &b, double bx, double by);
|
|
17
|
-
std::optional<Overlap> overlap(const Circle &a, double ax, double ay,
|
|
18
|
-
const Rect &b, double bx, double by);
|
|
19
|
-
std::optional<Collision> shapeOverlap(const Entity &entityA,
|
|
20
|
-
const Entity &entityB);
|
|
21
|
-
} // namespace margelo::nitro::rngine::CollisionUtils
|
|
File without changes
|
|
File without changes
|