rngine 0.3.2 → 0.4.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 +10 -7
- package/android/build.gradle +6 -4
- package/android/kls_database.db +0 -0
- package/android/src/main/cpp/GameLoopJNI.cpp +20 -9
- package/android/src/main/java/com/margelo/nitro/rngine/Asset.kt +9 -0
- package/android/src/main/java/com/margelo/nitro/rngine/GameAssets.kt +47 -0
- package/android/src/main/java/com/margelo/nitro/rngine/GameView.kt +46 -8
- package/android/src/main/java/com/margelo/nitro/rngine/Rect.kt +7 -5
- package/android/src/main/java/com/margelo/nitro/rngine/RectSerializer.kt +8 -6
- package/lib/module/GameAssets.nitro.js +5 -0
- package/lib/module/GameAssets.nitro.js.map +1 -0
- package/lib/module/GameMethods.js +1 -31
- package/lib/module/GameMethods.js.map +1 -1
- package/lib/module/GameMethods.nitro.js +2 -1
- package/lib/module/GameMethods.nitro.js.map +1 -1
- package/lib/module/Shared.js +72 -0
- package/lib/module/Shared.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/nativeTypes.js +2 -0
- package/lib/module/nativeTypes.js.map +1 -0
- package/lib/module/types.js +2 -0
- package/lib/typescript/src/GameAssets.nitro.d.ts +12 -0
- package/lib/typescript/src/GameAssets.nitro.d.ts.map +1 -0
- package/lib/typescript/src/GameMethods.d.ts +0 -7
- package/lib/typescript/src/GameMethods.d.ts.map +1 -1
- package/lib/typescript/src/GameMethods.nitro.d.ts +4 -2
- package/lib/typescript/src/GameMethods.nitro.d.ts.map +1 -1
- package/lib/typescript/src/Shared.d.ts +8 -0
- package/lib/typescript/src/Shared.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +2 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/nativeTypes.d.ts +79 -0
- package/lib/typescript/src/nativeTypes.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +11 -47
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/nitro.json +10 -0
- package/nitrogen/generated/android/c++/JHybridGameAssetsSpec.cpp +61 -0
- package/nitrogen/generated/android/c++/JHybridGameAssetsSpec.hpp +65 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngine/HybridGameAssetsSpec.kt +62 -0
- package/nitrogen/generated/android/rngine+autolinking.cmake +2 -0
- package/nitrogen/generated/android/rngineOnLoad.cpp +16 -0
- package/nitrogen/generated/ios/Rngine-Swift-Cxx-Bridge.cpp +17 -0
- package/nitrogen/generated/ios/Rngine-Swift-Cxx-Bridge.hpp +37 -0
- package/nitrogen/generated/ios/Rngine-Swift-Cxx-Umbrella.hpp +8 -0
- package/nitrogen/generated/ios/RngineAutolinking.mm +8 -0
- package/nitrogen/generated/ios/RngineAutolinking.swift +12 -0
- package/nitrogen/generated/ios/c++/HybridGameAssetsSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridGameAssetsSpecSwift.hpp +94 -0
- package/nitrogen/generated/ios/swift/HybridGameAssetsSpec.swift +57 -0
- package/nitrogen/generated/ios/swift/HybridGameAssetsSpec_cxx.swift +160 -0
- package/nitrogen/generated/shared/c++/Collision.hpp +91 -0
- package/nitrogen/generated/shared/c++/CollisionPair.hpp +87 -0
- package/nitrogen/generated/shared/c++/Entity.hpp +13 -5
- package/nitrogen/generated/shared/c++/EntityUpdate.hpp +9 -1
- package/nitrogen/generated/shared/c++/HybridGameAssetsSpec.cpp +23 -0
- package/nitrogen/generated/shared/c++/HybridGameAssetsSpec.hpp +64 -0
- package/nitrogen/generated/shared/c++/Screen.hpp +14 -5
- package/nitrogen/generated/shared/c++/System.hpp +20 -9
- package/package.json +1 -1
- package/shared/ColorUtils.hpp +6 -3
- package/shared/GameLoop.cpp +75 -12
- package/shared/GameLoop.hpp +2 -0
- package/shared/GameMethods.cpp +20 -7
- package/shared/Rect.hpp +8 -5
- package/src/GameAssets.nitro.ts +14 -0
- package/src/GameMethods.nitro.ts +6 -2
- package/src/GameMethods.ts +1 -34
- package/src/Shared.ts +83 -0
- package/src/index.tsx +2 -0
- package/src/nativeTypes.ts +83 -0
- package/src/types.ts +17 -49
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
#include <string>
|
|
34
|
+
#include <optional>
|
|
34
35
|
|
|
35
36
|
namespace margelo::nitro::rngine {
|
|
36
37
|
|
|
@@ -41,11 +42,13 @@ namespace margelo::nitro::rngine {
|
|
|
41
42
|
public:
|
|
42
43
|
double width SWIFT_PRIVATE;
|
|
43
44
|
double height SWIFT_PRIVATE;
|
|
44
|
-
std::string color SWIFT_PRIVATE;
|
|
45
|
+
std::optional<std::string> color SWIFT_PRIVATE;
|
|
46
|
+
std::optional<double> asset SWIFT_PRIVATE;
|
|
47
|
+
std::optional<double> progress SWIFT_PRIVATE;
|
|
45
48
|
|
|
46
49
|
public:
|
|
47
50
|
Screen() = default;
|
|
48
|
-
explicit Screen(double width, double height, std::string color): width(width), height(height), color(color) {}
|
|
51
|
+
explicit Screen(double width, double height, std::optional<std::string> color, std::optional<double> asset, std::optional<double> progress): width(width), height(height), color(color), asset(asset), progress(progress) {}
|
|
49
52
|
|
|
50
53
|
public:
|
|
51
54
|
friend bool operator==(const Screen& lhs, const Screen& rhs) = default;
|
|
@@ -63,14 +66,18 @@ namespace margelo::nitro {
|
|
|
63
66
|
return margelo::nitro::rngine::Screen(
|
|
64
67
|
JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width"))),
|
|
65
68
|
JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height"))),
|
|
66
|
-
JSIConverter<std::string
|
|
69
|
+
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "color"))),
|
|
70
|
+
JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "asset"))),
|
|
71
|
+
JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "progress")))
|
|
67
72
|
);
|
|
68
73
|
}
|
|
69
74
|
static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::rngine::Screen& arg) {
|
|
70
75
|
jsi::Object obj(runtime);
|
|
71
76
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "width"), JSIConverter<double>::toJSI(runtime, arg.width));
|
|
72
77
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "height"), JSIConverter<double>::toJSI(runtime, arg.height));
|
|
73
|
-
obj.setProperty(runtime, PropNameIDCache::get(runtime, "color"), JSIConverter<std::string
|
|
78
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "color"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.color));
|
|
79
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "asset"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.asset));
|
|
80
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "progress"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.progress));
|
|
74
81
|
return obj;
|
|
75
82
|
}
|
|
76
83
|
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
@@ -83,7 +90,9 @@ namespace margelo::nitro {
|
|
|
83
90
|
}
|
|
84
91
|
if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width")))) return false;
|
|
85
92
|
if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height")))) return false;
|
|
86
|
-
if (!JSIConverter<std::string
|
|
93
|
+
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "color")))) return false;
|
|
94
|
+
if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "asset")))) return false;
|
|
95
|
+
if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "progress")))) return false;
|
|
87
96
|
return true;
|
|
88
97
|
}
|
|
89
98
|
};
|
|
@@ -28,12 +28,19 @@
|
|
|
28
28
|
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
29
29
|
#endif
|
|
30
30
|
|
|
31
|
+
// Forward declaration of `CollisionPair` to properly resolve imports.
|
|
32
|
+
namespace margelo::nitro::rngine { struct CollisionPair; }
|
|
31
33
|
// Forward declaration of `Entity` to properly resolve imports.
|
|
32
34
|
namespace margelo::nitro::rngine { struct Entity; }
|
|
35
|
+
// Forward declaration of `Collision` to properly resolve imports.
|
|
36
|
+
namespace margelo::nitro::rngine { struct Collision; }
|
|
33
37
|
|
|
34
38
|
#include <string>
|
|
35
39
|
#include <vector>
|
|
40
|
+
#include <optional>
|
|
41
|
+
#include "CollisionPair.hpp"
|
|
36
42
|
#include "Entity.hpp"
|
|
43
|
+
#include "Collision.hpp"
|
|
37
44
|
#include <functional>
|
|
38
45
|
|
|
39
46
|
namespace margelo::nitro::rngine {
|
|
@@ -43,12 +50,13 @@ namespace margelo::nitro::rngine {
|
|
|
43
50
|
*/
|
|
44
51
|
struct System final {
|
|
45
52
|
public:
|
|
46
|
-
std::vector<std::string
|
|
47
|
-
std::
|
|
53
|
+
std::optional<std::vector<std::string>> entities SWIFT_PRIVATE;
|
|
54
|
+
std::optional<std::vector<CollisionPair>> collisions SWIFT_PRIVATE;
|
|
55
|
+
std::function<void(const std::vector<Entity>& /* entities */, const std::vector<Collision>& /* collisions */)> onTick SWIFT_PRIVATE;
|
|
48
56
|
|
|
49
57
|
public:
|
|
50
58
|
System() = default;
|
|
51
|
-
explicit System(std::vector<std::string
|
|
59
|
+
explicit System(std::optional<std::vector<std::string>> entities, std::optional<std::vector<CollisionPair>> collisions, std::function<void(const std::vector<Entity>& /* entities */, const std::vector<Collision>& /* collisions */)> onTick): entities(entities), collisions(collisions), onTick(onTick) {}
|
|
52
60
|
|
|
53
61
|
public:
|
|
54
62
|
// System is not equatable because these properties are not equatable: onTick
|
|
@@ -64,14 +72,16 @@ namespace margelo::nitro {
|
|
|
64
72
|
static inline margelo::nitro::rngine::System fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
65
73
|
jsi::Object obj = arg.asObject(runtime);
|
|
66
74
|
return margelo::nitro::rngine::System(
|
|
67
|
-
JSIConverter<std::vector<std::string
|
|
68
|
-
JSIConverter<std::
|
|
75
|
+
JSIConverter<std::optional<std::vector<std::string>>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "entities"))),
|
|
76
|
+
JSIConverter<std::optional<std::vector<margelo::nitro::rngine::CollisionPair>>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "collisions"))),
|
|
77
|
+
JSIConverter<std::function<void(const std::vector<margelo::nitro::rngine::Entity>&, const std::vector<margelo::nitro::rngine::Collision>&)>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "onTick")))
|
|
69
78
|
);
|
|
70
79
|
}
|
|
71
80
|
static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::rngine::System& arg) {
|
|
72
81
|
jsi::Object obj(runtime);
|
|
73
|
-
obj.setProperty(runtime, PropNameIDCache::get(runtime, "
|
|
74
|
-
obj.setProperty(runtime, PropNameIDCache::get(runtime, "
|
|
82
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "entities"), JSIConverter<std::optional<std::vector<std::string>>>::toJSI(runtime, arg.entities));
|
|
83
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "collisions"), JSIConverter<std::optional<std::vector<margelo::nitro::rngine::CollisionPair>>>::toJSI(runtime, arg.collisions));
|
|
84
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "onTick"), JSIConverter<std::function<void(const std::vector<margelo::nitro::rngine::Entity>&, const std::vector<margelo::nitro::rngine::Collision>&)>>::toJSI(runtime, arg.onTick));
|
|
75
85
|
return obj;
|
|
76
86
|
}
|
|
77
87
|
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
@@ -82,8 +92,9 @@ namespace margelo::nitro {
|
|
|
82
92
|
if (!nitro::isPlainObject(runtime, obj)) {
|
|
83
93
|
return false;
|
|
84
94
|
}
|
|
85
|
-
if (!JSIConverter<std::vector<std::string
|
|
86
|
-
if (!JSIConverter<std::
|
|
95
|
+
if (!JSIConverter<std::optional<std::vector<std::string>>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "entities")))) return false;
|
|
96
|
+
if (!JSIConverter<std::optional<std::vector<margelo::nitro::rngine::CollisionPair>>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "collisions")))) return false;
|
|
97
|
+
if (!JSIConverter<std::function<void(const std::vector<margelo::nitro::rngine::Entity>&, const std::vector<margelo::nitro::rngine::Collision>&)>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "onTick")))) return false;
|
|
87
98
|
return true;
|
|
88
99
|
}
|
|
89
100
|
};
|
package/package.json
CHANGED
package/shared/ColorUtils.hpp
CHANGED
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
namespace margelo::nitro::rngine {
|
|
5
5
|
|
|
6
|
-
inline uint32_t parseHexColor(const std::string &color) {
|
|
7
|
-
if (!color.
|
|
8
|
-
|
|
6
|
+
inline uint32_t parseHexColor(const std::optional<std::string> &color) {
|
|
7
|
+
if (!color.has_value())
|
|
8
|
+
return 0x00000000;
|
|
9
|
+
const std::string &c = color.value();
|
|
10
|
+
if (!c.empty() && c[0] == '#') {
|
|
11
|
+
std::string hex = c.substr(1);
|
|
9
12
|
|
|
10
13
|
if (hex.size() == 3 || hex.size() == 4) {
|
|
11
14
|
std::string expanded;
|
package/shared/GameLoop.cpp
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#include "GameLoop.hpp"
|
|
2
|
+
#include "Collision.hpp"
|
|
2
3
|
#include "ColorUtils.hpp"
|
|
3
4
|
#include "Entity.hpp"
|
|
4
5
|
#include <android/log.h>
|
|
5
6
|
#include <chrono>
|
|
6
7
|
#include <cinttypes>
|
|
8
|
+
#include <set>
|
|
7
9
|
|
|
8
10
|
namespace margelo::nitro::rngine {
|
|
9
11
|
|
|
@@ -50,13 +52,24 @@ GameLoop::resolveEntitiesInternal(const std::string &prefix) {
|
|
|
50
52
|
return results;
|
|
51
53
|
}
|
|
52
54
|
|
|
55
|
+
void GameLoop::registerLottieDuration(double id, double duration) {
|
|
56
|
+
std::lock_guard<std::mutex> lock(_mutex);
|
|
57
|
+
_lottieDurations[id] = duration;
|
|
58
|
+
__android_log_print(ANDROID_LOG_DEBUG, "GameLoop",
|
|
59
|
+
"Registered lottie duration: id: %.0f, duration: %.4f",
|
|
60
|
+
id, duration);
|
|
61
|
+
}
|
|
62
|
+
|
|
53
63
|
std::vector<Rect> GameLoop::getRectsSnapshot() {
|
|
54
64
|
std::lock_guard<std::mutex> lock(_mutex);
|
|
55
65
|
std::vector<Rect> rects;
|
|
56
66
|
rects.reserve(_entities.size() + 1);
|
|
57
67
|
|
|
58
|
-
rects.push_back(
|
|
59
|
-
|
|
68
|
+
rects.push_back({0, static_cast<float>(_screen.width), 0,
|
|
69
|
+
static_cast<float>(_screen.height),
|
|
70
|
+
static_cast<float>(_screen.progress.value_or(0)),
|
|
71
|
+
parseHexColor(_screen.color),
|
|
72
|
+
static_cast<int32_t>(_screen.asset.value_or(0))});
|
|
60
73
|
|
|
61
74
|
for (const auto &[id, entity] : _entities) {
|
|
62
75
|
if (entity.px + entity.width < 0 || entity.px > _screen.width ||
|
|
@@ -64,11 +77,13 @@ std::vector<Rect> GameLoop::getRectsSnapshot() {
|
|
|
64
77
|
continue;
|
|
65
78
|
}
|
|
66
79
|
|
|
67
|
-
rects.push_back({
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
80
|
+
rects.push_back({static_cast<float>(entity.px),
|
|
81
|
+
static_cast<float>(entity.px + entity.width),
|
|
82
|
+
static_cast<float>(entity.py),
|
|
83
|
+
static_cast<float>(entity.py + entity.height),
|
|
84
|
+
static_cast<float>(entity.progress.value_or(0)),
|
|
85
|
+
parseHexColor(entity.color),
|
|
86
|
+
static_cast<int32_t>(entity.asset.value_or(0))});
|
|
72
87
|
}
|
|
73
88
|
return rects;
|
|
74
89
|
}
|
|
@@ -109,14 +124,53 @@ void GameLoop::runGameLoop() {
|
|
|
109
124
|
void GameLoop::runSystems() {
|
|
110
125
|
for (auto &system : _systems) {
|
|
111
126
|
std::vector<Entity> entities;
|
|
127
|
+
std::vector<Collision> collisions;
|
|
112
128
|
|
|
113
|
-
|
|
114
|
-
auto
|
|
115
|
-
|
|
116
|
-
|
|
129
|
+
if (system.entities.has_value()) {
|
|
130
|
+
for (const auto &id : system.entities.value()) {
|
|
131
|
+
auto resolvedEntitiesInternal = resolveEntitiesInternal(id);
|
|
132
|
+
for (auto *entity : resolvedEntitiesInternal)
|
|
133
|
+
entities.push_back(*entity);
|
|
134
|
+
}
|
|
117
135
|
}
|
|
118
136
|
|
|
119
|
-
system.
|
|
137
|
+
if (system.collisions.has_value()) {
|
|
138
|
+
std::set<std::pair<std::string, std::string>> uniqueEntityIdPairs;
|
|
139
|
+
|
|
140
|
+
for (const auto &[a, b] : system.collisions.value()) {
|
|
141
|
+
auto resolvedEntitiesInternalA = resolveEntitiesInternal(a);
|
|
142
|
+
auto resolvedEntitiesInternalB = resolveEntitiesInternal(b);
|
|
143
|
+
|
|
144
|
+
for (auto *entityA : resolvedEntitiesInternalA) {
|
|
145
|
+
for (auto *entityB : resolvedEntitiesInternalB) {
|
|
146
|
+
if (entityA == entityB)
|
|
147
|
+
continue;
|
|
148
|
+
|
|
149
|
+
auto uniqueEntityIdPairKey = std::minmax(entityA->id, entityB->id);
|
|
150
|
+
|
|
151
|
+
if (uniqueEntityIdPairs.count(uniqueEntityIdPairKey))
|
|
152
|
+
continue;
|
|
153
|
+
|
|
154
|
+
uniqueEntityIdPairs.insert(uniqueEntityIdPairKey);
|
|
155
|
+
|
|
156
|
+
float aLeft = entityA->px, aRight = entityA->px + entityA->width;
|
|
157
|
+
float aTop = entityA->py, aBottom = entityA->py + entityA->height;
|
|
158
|
+
float bLeft = entityB->px, bRight = entityB->px + entityB->width;
|
|
159
|
+
float bTop = entityB->py, bBottom = entityB->py + entityB->height;
|
|
160
|
+
|
|
161
|
+
float overlapX = std::min(aRight, bRight) - std::max(aLeft, bLeft);
|
|
162
|
+
float overlapY = std::min(aBottom, bBottom) - std::max(aTop, bTop);
|
|
163
|
+
|
|
164
|
+
if (overlapX > 0 && overlapY > 0) {
|
|
165
|
+
collisions.push_back(Collision(entityA->id, entityB->id,
|
|
166
|
+
std::min(overlapX, overlapY)));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
system.onTick(entities, collisions);
|
|
120
174
|
}
|
|
121
175
|
}
|
|
122
176
|
|
|
@@ -156,9 +210,18 @@ void GameLoop::updateEntities(double deltaTime) {
|
|
|
156
210
|
if (entity.vx) {
|
|
157
211
|
entity.px += *entity.vx * deltaTime;
|
|
158
212
|
}
|
|
213
|
+
|
|
159
214
|
if (entity.vy) {
|
|
160
215
|
entity.py += *entity.vy * deltaTime;
|
|
161
216
|
}
|
|
217
|
+
|
|
218
|
+
if (entity.asset && entity.asset < 0) {
|
|
219
|
+
auto it = _lottieDurations.find(*entity.asset);
|
|
220
|
+
if (it != _lottieDurations.end() && it->second > 0.0) {
|
|
221
|
+
entity.progress =
|
|
222
|
+
fmod(entity.progress.value_or(0.0) + deltaTime / it->second, 1.0);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
162
225
|
}
|
|
163
226
|
}
|
|
164
227
|
} // namespace margelo::nitro::rngine
|
package/shared/GameLoop.hpp
CHANGED
|
@@ -28,6 +28,7 @@ public:
|
|
|
28
28
|
Screen &getScreenInternal() { return _screen; };
|
|
29
29
|
|
|
30
30
|
std::vector<Entity *> resolveEntitiesInternal(const std::string &prefix);
|
|
31
|
+
void registerLottieDuration(double, double);
|
|
31
32
|
std::vector<Rect> getRectsSnapshot();
|
|
32
33
|
|
|
33
34
|
void setTickRate(double tickRate) { _tickRate = tickRate; };
|
|
@@ -36,6 +37,7 @@ private:
|
|
|
36
37
|
explicit GameLoop();
|
|
37
38
|
std::mutex _mutex;
|
|
38
39
|
std::map<std::string, Entity> _entities;
|
|
40
|
+
std::map<double, double> _lottieDurations;
|
|
39
41
|
std::vector<System> _systems{};
|
|
40
42
|
std::atomic<bool> _isRunning{true};
|
|
41
43
|
std::atomic<bool> _isPaused{true};
|
package/shared/GameMethods.cpp
CHANGED
|
@@ -114,20 +114,33 @@ void GameMethods::update(const std::vector<EntityUpdate> &updates) {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
for (auto *entity : resolvedEntitiesInternals) {
|
|
117
|
-
if (update.px.has_value())
|
|
117
|
+
if (update.px.has_value()) {
|
|
118
118
|
entity->px = update.px.value();
|
|
119
|
-
|
|
119
|
+
}
|
|
120
|
+
if (update.py.has_value()) {
|
|
120
121
|
entity->py = update.py.value();
|
|
121
|
-
|
|
122
|
+
}
|
|
123
|
+
if (update.width.has_value()) {
|
|
122
124
|
entity->width = update.width.value();
|
|
123
|
-
|
|
125
|
+
}
|
|
126
|
+
if (update.height.has_value()) {
|
|
124
127
|
entity->height = update.height.value();
|
|
125
|
-
|
|
128
|
+
}
|
|
129
|
+
if (update.asset.has_value()) {
|
|
130
|
+
entity->asset = update.asset.value();
|
|
131
|
+
}
|
|
132
|
+
if (update.progress.has_value()) {
|
|
133
|
+
entity->progress = update.progress.value();
|
|
134
|
+
}
|
|
135
|
+
if (update.color.has_value()) {
|
|
126
136
|
entity->color = update.color.value();
|
|
127
|
-
|
|
137
|
+
}
|
|
138
|
+
if (update.vx.has_value()) {
|
|
128
139
|
entity->vx = update.vx.value();
|
|
129
|
-
|
|
140
|
+
}
|
|
141
|
+
if (update.vy.has_value()) {
|
|
130
142
|
entity->vy = update.vy.value();
|
|
143
|
+
}
|
|
131
144
|
}
|
|
132
145
|
|
|
133
146
|
__android_log_print(ANDROID_LOG_INFO, "GameMethods",
|
package/shared/Rect.hpp
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
3
|
namespace margelo::nitro::rngine {
|
|
4
|
-
static constexpr int RECT_SIZE =
|
|
4
|
+
static constexpr int RECT_SIZE =
|
|
5
|
+
sizeof(float) * 5 + sizeof(uint32_t) + sizeof(int32_t);
|
|
5
6
|
|
|
6
7
|
struct Rect {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
float left;
|
|
9
|
+
float right;
|
|
10
|
+
float top;
|
|
11
|
+
float bottom;
|
|
12
|
+
float progress;
|
|
11
13
|
uint32_t color;
|
|
14
|
+
int32_t asset;
|
|
12
15
|
};
|
|
13
16
|
} // namespace margelo::nitro::rngine
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { HybridObject } from 'react-native-nitro-modules';
|
|
2
|
+
import { NitroModules } from 'react-native-nitro-modules';
|
|
3
|
+
|
|
4
|
+
interface GameAssets extends HybridObject<{
|
|
5
|
+
ios: 'swift';
|
|
6
|
+
android: 'kotlin';
|
|
7
|
+
}> {
|
|
8
|
+
isAssetRegistered(id: number): boolean;
|
|
9
|
+
registerSvg(id: number, uri: string): void;
|
|
10
|
+
registerLottie(id: number, json: string): void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const gameAssets =
|
|
14
|
+
NitroModules.createHybridObject<GameAssets>('GameAssets');
|
package/src/GameMethods.nitro.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { HybridObject } from 'react-native-nitro-modules';
|
|
2
|
-
import type { Entity, EntityUpdate, System, Screen } from './
|
|
2
|
+
import type { Entity, EntityUpdate, System, Screen } from './nativeTypes';
|
|
3
|
+
import { NitroModules } from 'react-native-nitro-modules';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
interface GameMethods extends HybridObject<{
|
|
5
6
|
ios: 'c++';
|
|
6
7
|
android: 'c++';
|
|
7
8
|
}> {
|
|
@@ -15,3 +16,6 @@ export interface GameMethods extends HybridObject<{
|
|
|
15
16
|
despawn(id: string): void;
|
|
16
17
|
update(updates: EntityUpdate[]): void;
|
|
17
18
|
}
|
|
19
|
+
|
|
20
|
+
export const gameMethods =
|
|
21
|
+
NitroModules.createHybridObject<GameMethods>('GameMethods');
|
package/src/GameMethods.ts
CHANGED
|
@@ -1,27 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { GameMethods } from './GameMethods.nitro';
|
|
3
|
-
import type { Config, Entity, EntityUpdate } from './types';
|
|
4
|
-
|
|
5
|
-
const gameMethods = NitroModules.createHybridObject<GameMethods>('GameMethods');
|
|
6
|
-
|
|
7
|
-
/** Sets up the game engine with the given configuration. Call this before anything else. */
|
|
8
|
-
export function configure({
|
|
9
|
-
tickRate,
|
|
10
|
-
screen,
|
|
11
|
-
entities = [],
|
|
12
|
-
systems = [],
|
|
13
|
-
paused = true,
|
|
14
|
-
}: Config) {
|
|
15
|
-
gameMethods.setTickRate(tickRate);
|
|
16
|
-
gameMethods.setScreen(screen);
|
|
17
|
-
gameMethods.setEntities(entities);
|
|
18
|
-
gameMethods.setSystems(systems);
|
|
19
|
-
if (paused) {
|
|
20
|
-
gameMethods.pause();
|
|
21
|
-
} else {
|
|
22
|
-
gameMethods.resume();
|
|
23
|
-
}
|
|
24
|
-
}
|
|
1
|
+
import { gameMethods } from './GameMethods.nitro';
|
|
25
2
|
|
|
26
3
|
/** Pauses the game loop. Systems will stop running. */
|
|
27
4
|
export const pause = () => gameMethods.pause();
|
|
@@ -29,15 +6,5 @@ export const pause = () => gameMethods.pause();
|
|
|
29
6
|
/** Resumes the game loop. */
|
|
30
7
|
export const resume = () => gameMethods.resume();
|
|
31
8
|
|
|
32
|
-
/** Spawns one or more entities into the world. Skips duplicates by id. */
|
|
33
|
-
export const spawn = (entities: Entity | Entity[]) => {
|
|
34
|
-
gameMethods.spawn(Array.isArray(entities) ? entities : [entities]);
|
|
35
|
-
};
|
|
36
|
-
|
|
37
9
|
/** Removes an entity or all entities matching the given id prefix from the world. */
|
|
38
10
|
export const despawn = (id: string) => gameMethods.despawn(id);
|
|
39
|
-
|
|
40
|
-
/** Updates one or more entities. Only the provided fields are changed. */
|
|
41
|
-
export const update = (updates: EntityUpdate | EntityUpdate[]) => {
|
|
42
|
-
gameMethods.update(Array.isArray(updates) ? updates : [updates]);
|
|
43
|
-
};
|
package/src/Shared.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Image } from 'react-native';
|
|
2
|
+
import { gameAssets } from './GameAssets.nitro';
|
|
3
|
+
import { gameMethods } from './GameMethods.nitro';
|
|
4
|
+
import type {
|
|
5
|
+
Screen as NativeScreen,
|
|
6
|
+
Entity as NativeEntity,
|
|
7
|
+
EntityUpdate as NativeEntityUpdate,
|
|
8
|
+
} from './nativeTypes';
|
|
9
|
+
import type { Asset, Config, Entity, EntityUpdate } from './types';
|
|
10
|
+
|
|
11
|
+
const assetCache = new WeakMap<object, number>();
|
|
12
|
+
let nextId = -1;
|
|
13
|
+
|
|
14
|
+
const registerAssetIfNotExist = (asset?: Asset) => {
|
|
15
|
+
switch (typeof asset) {
|
|
16
|
+
case 'object':
|
|
17
|
+
if (assetCache.has(asset)) {
|
|
18
|
+
return assetCache.get(asset);
|
|
19
|
+
}
|
|
20
|
+
const assetId = nextId--;
|
|
21
|
+
assetCache.set(asset, assetId);
|
|
22
|
+
gameAssets.registerLottie(assetId, JSON.stringify(asset));
|
|
23
|
+
return assetId;
|
|
24
|
+
|
|
25
|
+
case 'number':
|
|
26
|
+
if (gameAssets.isAssetRegistered(asset)) {
|
|
27
|
+
return asset;
|
|
28
|
+
}
|
|
29
|
+
const assetUri = Image.resolveAssetSource(asset)?.uri;
|
|
30
|
+
if (!assetUri) {
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
gameAssets.registerSvg(asset, assetUri);
|
|
34
|
+
return asset;
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/** Sets up the game engine with the given configuration. Call this before anything else. */
|
|
40
|
+
export const configure = ({
|
|
41
|
+
tickRate,
|
|
42
|
+
screen,
|
|
43
|
+
entities = [],
|
|
44
|
+
systems = [],
|
|
45
|
+
paused = true,
|
|
46
|
+
}: Config) => {
|
|
47
|
+
screen.asset = registerAssetIfNotExist(screen.asset);
|
|
48
|
+
for (const entity of entities) {
|
|
49
|
+
entity.asset = registerAssetIfNotExist(entity.asset);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
gameMethods.setTickRate(tickRate);
|
|
53
|
+
gameMethods.setScreen(screen as NativeScreen);
|
|
54
|
+
gameMethods.setEntities(entities as NativeEntity[]);
|
|
55
|
+
gameMethods.setSystems(systems);
|
|
56
|
+
if (paused) {
|
|
57
|
+
gameMethods.pause();
|
|
58
|
+
} else {
|
|
59
|
+
gameMethods.resume();
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** Spawns one or more entities into the world. Skips duplicates by id. */
|
|
64
|
+
export const spawn = (entities: Entity | Entity[]) => {
|
|
65
|
+
const entityArray = Array.isArray(entities) ? entities : [entities];
|
|
66
|
+
|
|
67
|
+
for (const entity of entityArray) {
|
|
68
|
+
entity.asset = registerAssetIfNotExist(entity.asset);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
gameMethods.spawn(entityArray as NativeEntity[]);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/** Updates one or more entities. Only the provided fields are changed. */
|
|
75
|
+
export const update = (updates: EntityUpdate | EntityUpdate[]) => {
|
|
76
|
+
const entityUpdateArray = Array.isArray(updates) ? updates : [updates];
|
|
77
|
+
|
|
78
|
+
for (const entityUpdate of entityUpdateArray) {
|
|
79
|
+
entityUpdate.asset = registerAssetIfNotExist(entityUpdate.asset);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
gameMethods.update(entityUpdateArray as NativeEntityUpdate[]);
|
|
83
|
+
};
|
package/src/index.tsx
CHANGED
|
@@ -0,0 +1,83 @@
|
|
|
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;
|
|
17
|
+
/** X position in game units. */
|
|
18
|
+
px: number;
|
|
19
|
+
/** Y position in game units. */
|
|
20
|
+
py: number;
|
|
21
|
+
/** Width in game units. */
|
|
22
|
+
width: number;
|
|
23
|
+
/** Height in game units. */
|
|
24
|
+
height: number;
|
|
25
|
+
/** Fill color as a hex string e.g. `'#00ff00'`. */
|
|
26
|
+
color?: string;
|
|
27
|
+
/** Asset to render, use `require` with the file path to get the id. */
|
|
28
|
+
asset?: number;
|
|
29
|
+
/** Animation progress between 0 and 1, automatically advanced each tick for Lottie assets. */
|
|
30
|
+
progress?: number;
|
|
31
|
+
/** Velocity on the X axis in game units per second. */
|
|
32
|
+
vx?: number;
|
|
33
|
+
/** Velocity on the Y axis in game units per second. */
|
|
34
|
+
vy?: number;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type CollisionPair = {
|
|
38
|
+
/** Entity id or prefix of the first entity to watch. */
|
|
39
|
+
a: string;
|
|
40
|
+
/** Entity id or prefix of the second entity to watch. */
|
|
41
|
+
b: string;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type Collision = {
|
|
45
|
+
/** Id of the first entity involved in the collision. */
|
|
46
|
+
a: string;
|
|
47
|
+
/** Id of the second entity involved in the collision. */
|
|
48
|
+
b: string;
|
|
49
|
+
/** Penetration depth of the collision. */
|
|
50
|
+
depth: number;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type System = {
|
|
54
|
+
/** Entity ids or prefixes this system subscribes to. */
|
|
55
|
+
entities?: string[];
|
|
56
|
+
/** Collision pairs to watch for every tick. */
|
|
57
|
+
collisions?: CollisionPair[];
|
|
58
|
+
/** Called every tick with the resolved entities and collisions. */
|
|
59
|
+
onTick: (entities: Entity[], collisions: Collision[]) => void;
|
|
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
|
+
};
|