rngine 0.3.1 → 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.
Files changed (75) hide show
  1. package/README.md +19 -16
  2. package/android/build.gradle +6 -4
  3. package/android/kls_database.db +0 -0
  4. package/android/src/main/cpp/GameLoopJNI.cpp +20 -9
  5. package/android/src/main/java/com/margelo/nitro/rngine/Asset.kt +9 -0
  6. package/android/src/main/java/com/margelo/nitro/rngine/GameAssets.kt +47 -0
  7. package/android/src/main/java/com/margelo/nitro/rngine/GameView.kt +46 -8
  8. package/android/src/main/java/com/margelo/nitro/rngine/Rect.kt +7 -5
  9. package/android/src/main/java/com/margelo/nitro/rngine/RectSerializer.kt +8 -6
  10. package/lib/module/GameAssets.nitro.js +5 -0
  11. package/lib/module/GameAssets.nitro.js.map +1 -0
  12. package/lib/module/GameMethods.js +1 -31
  13. package/lib/module/GameMethods.js.map +1 -1
  14. package/lib/module/GameMethods.nitro.js +2 -1
  15. package/lib/module/GameMethods.nitro.js.map +1 -1
  16. package/lib/module/Shared.js +72 -0
  17. package/lib/module/Shared.js.map +1 -0
  18. package/lib/module/index.js +1 -0
  19. package/lib/module/index.js.map +1 -1
  20. package/lib/module/nativeTypes.js +2 -0
  21. package/lib/module/nativeTypes.js.map +1 -0
  22. package/lib/module/types.js +2 -0
  23. package/lib/typescript/src/GameAssets.nitro.d.ts +12 -0
  24. package/lib/typescript/src/GameAssets.nitro.d.ts.map +1 -0
  25. package/lib/typescript/src/GameMethods.d.ts +0 -7
  26. package/lib/typescript/src/GameMethods.d.ts.map +1 -1
  27. package/lib/typescript/src/GameMethods.nitro.d.ts +5 -3
  28. package/lib/typescript/src/GameMethods.nitro.d.ts.map +1 -1
  29. package/lib/typescript/src/Shared.d.ts +8 -0
  30. package/lib/typescript/src/Shared.d.ts.map +1 -0
  31. package/lib/typescript/src/index.d.ts +2 -0
  32. package/lib/typescript/src/index.d.ts.map +1 -1
  33. package/lib/typescript/src/nativeTypes.d.ts +79 -0
  34. package/lib/typescript/src/nativeTypes.d.ts.map +1 -0
  35. package/lib/typescript/src/types.d.ts +13 -49
  36. package/lib/typescript/src/types.d.ts.map +1 -1
  37. package/nitro.json +10 -0
  38. package/nitrogen/generated/android/c++/JHybridGameAssetsSpec.cpp +61 -0
  39. package/nitrogen/generated/android/c++/JHybridGameAssetsSpec.hpp +65 -0
  40. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngine/HybridGameAssetsSpec.kt +62 -0
  41. package/nitrogen/generated/android/rngine+autolinking.cmake +2 -0
  42. package/nitrogen/generated/android/rngineOnLoad.cpp +16 -0
  43. package/nitrogen/generated/ios/Rngine-Swift-Cxx-Bridge.cpp +17 -0
  44. package/nitrogen/generated/ios/Rngine-Swift-Cxx-Bridge.hpp +37 -0
  45. package/nitrogen/generated/ios/Rngine-Swift-Cxx-Umbrella.hpp +8 -0
  46. package/nitrogen/generated/ios/RngineAutolinking.mm +8 -0
  47. package/nitrogen/generated/ios/RngineAutolinking.swift +12 -0
  48. package/nitrogen/generated/ios/c++/HybridGameAssetsSpecSwift.cpp +11 -0
  49. package/nitrogen/generated/ios/c++/HybridGameAssetsSpecSwift.hpp +94 -0
  50. package/nitrogen/generated/ios/swift/HybridGameAssetsSpec.swift +57 -0
  51. package/nitrogen/generated/ios/swift/HybridGameAssetsSpec_cxx.swift +160 -0
  52. package/nitrogen/generated/shared/c++/{World.hpp → Collision.hpp} +23 -23
  53. package/nitrogen/generated/shared/c++/CollisionPair.hpp +87 -0
  54. package/nitrogen/generated/shared/c++/Entity.hpp +13 -5
  55. package/nitrogen/generated/shared/c++/EntityUpdate.hpp +9 -1
  56. package/nitrogen/generated/shared/c++/HybridGameAssetsSpec.cpp +23 -0
  57. package/nitrogen/generated/shared/c++/HybridGameAssetsSpec.hpp +64 -0
  58. package/nitrogen/generated/shared/c++/HybridGameMethodsSpec.cpp +1 -1
  59. package/nitrogen/generated/shared/c++/HybridGameMethodsSpec.hpp +4 -4
  60. package/nitrogen/generated/shared/c++/Screen.hpp +100 -0
  61. package/nitrogen/generated/shared/c++/System.hpp +20 -9
  62. package/package.json +1 -1
  63. package/shared/ColorUtils.hpp +29 -17
  64. package/shared/GameLoop.cpp +77 -14
  65. package/shared/GameLoop.hpp +5 -3
  66. package/shared/GameMethods.cpp +24 -11
  67. package/shared/GameMethods.hpp +1 -1
  68. package/shared/Rect.hpp +8 -5
  69. package/src/GameAssets.nitro.ts +14 -0
  70. package/src/GameMethods.nitro.ts +7 -3
  71. package/src/GameMethods.ts +1 -34
  72. package/src/Shared.ts +83 -0
  73. package/src/index.tsx +2 -0
  74. package/src/nativeTypes.ts +83 -0
  75. package/src/types.ts +19 -51
@@ -15,7 +15,7 @@ namespace margelo::nitro::rngine {
15
15
  // load custom methods/properties
16
16
  registerHybrids(this, [](Prototype& prototype) {
17
17
  prototype.registerHybridMethod("setTickRate", &HybridGameMethodsSpec::setTickRate);
18
- prototype.registerHybridMethod("setWorld", &HybridGameMethodsSpec::setWorld);
18
+ prototype.registerHybridMethod("setScreen", &HybridGameMethodsSpec::setScreen);
19
19
  prototype.registerHybridMethod("setEntities", &HybridGameMethodsSpec::setEntities);
20
20
  prototype.registerHybridMethod("setSystems", &HybridGameMethodsSpec::setSystems);
21
21
  prototype.registerHybridMethod("pause", &HybridGameMethodsSpec::pause);
@@ -13,8 +13,8 @@
13
13
  #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
14
14
  #endif
15
15
 
16
- // Forward declaration of `World` to properly resolve imports.
17
- namespace margelo::nitro::rngine { struct World; }
16
+ // Forward declaration of `Screen` to properly resolve imports.
17
+ namespace margelo::nitro::rngine { struct Screen; }
18
18
  // Forward declaration of `Entity` to properly resolve imports.
19
19
  namespace margelo::nitro::rngine { struct Entity; }
20
20
  // Forward declaration of `System` to properly resolve imports.
@@ -22,7 +22,7 @@ namespace margelo::nitro::rngine { struct System; }
22
22
  // Forward declaration of `EntityUpdate` to properly resolve imports.
23
23
  namespace margelo::nitro::rngine { struct EntityUpdate; }
24
24
 
25
- #include "World.hpp"
25
+ #include "Screen.hpp"
26
26
  #include "Entity.hpp"
27
27
  #include <vector>
28
28
  #include "System.hpp"
@@ -61,7 +61,7 @@ namespace margelo::nitro::rngine {
61
61
  public:
62
62
  // Methods
63
63
  virtual void setTickRate(double tickRate) = 0;
64
- virtual void setWorld(const World& world) = 0;
64
+ virtual void setScreen(const Screen& screen) = 0;
65
65
  virtual void setEntities(const std::vector<Entity>& entities) = 0;
66
66
  virtual void setSystems(const std::vector<System>& systems) = 0;
67
67
  virtual void pause() = 0;
@@ -0,0 +1,100 @@
1
+ ///
2
+ /// Screen.hpp
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ #pragma once
9
+
10
+ #if __has_include(<NitroModules/JSIConverter.hpp>)
11
+ #include <NitroModules/JSIConverter.hpp>
12
+ #else
13
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
14
+ #endif
15
+ #if __has_include(<NitroModules/NitroDefines.hpp>)
16
+ #include <NitroModules/NitroDefines.hpp>
17
+ #else
18
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
19
+ #endif
20
+ #if __has_include(<NitroModules/JSIHelpers.hpp>)
21
+ #include <NitroModules/JSIHelpers.hpp>
22
+ #else
23
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
24
+ #endif
25
+ #if __has_include(<NitroModules/PropNameIDCache.hpp>)
26
+ #include <NitroModules/PropNameIDCache.hpp>
27
+ #else
28
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
29
+ #endif
30
+
31
+
32
+
33
+ #include <string>
34
+ #include <optional>
35
+
36
+ namespace margelo::nitro::rngine {
37
+
38
+ /**
39
+ * A struct which can be represented as a JavaScript object (Screen).
40
+ */
41
+ struct Screen final {
42
+ public:
43
+ double width SWIFT_PRIVATE;
44
+ double height SWIFT_PRIVATE;
45
+ std::optional<std::string> color SWIFT_PRIVATE;
46
+ std::optional<double> asset SWIFT_PRIVATE;
47
+ std::optional<double> progress SWIFT_PRIVATE;
48
+
49
+ public:
50
+ Screen() = default;
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) {}
52
+
53
+ public:
54
+ friend bool operator==(const Screen& lhs, const Screen& rhs) = default;
55
+ };
56
+
57
+ } // namespace margelo::nitro::rngine
58
+
59
+ namespace margelo::nitro {
60
+
61
+ // C++ Screen <> JS Screen (object)
62
+ template <>
63
+ struct JSIConverter<margelo::nitro::rngine::Screen> final {
64
+ static inline margelo::nitro::rngine::Screen fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
65
+ jsi::Object obj = arg.asObject(runtime);
66
+ return margelo::nitro::rngine::Screen(
67
+ JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width"))),
68
+ JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height"))),
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")))
72
+ );
73
+ }
74
+ static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::rngine::Screen& arg) {
75
+ jsi::Object obj(runtime);
76
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "width"), JSIConverter<double>::toJSI(runtime, arg.width));
77
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "height"), JSIConverter<double>::toJSI(runtime, arg.height));
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));
81
+ return obj;
82
+ }
83
+ static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
84
+ if (!value.isObject()) {
85
+ return false;
86
+ }
87
+ jsi::Object obj = value.getObject(runtime);
88
+ if (!nitro::isPlainObject(runtime, obj)) {
89
+ return false;
90
+ }
91
+ if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width")))) return false;
92
+ if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height")))) return false;
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;
96
+ return true;
97
+ }
98
+ };
99
+
100
+ } // namespace margelo::nitro
@@ -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> ids SWIFT_PRIVATE;
47
- std::function<void(const std::vector<Entity>& /* entities */)> onTick SWIFT_PRIVATE;
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> ids, std::function<void(const std::vector<Entity>& /* entities */)> onTick): ids(ids), onTick(onTick) {}
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>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "ids"))),
68
- JSIConverter<std::function<void(const std::vector<margelo::nitro::rngine::Entity>&)>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "onTick")))
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, "ids"), JSIConverter<std::vector<std::string>>::toJSI(runtime, arg.ids));
74
- obj.setProperty(runtime, PropNameIDCache::get(runtime, "onTick"), JSIConverter<std::function<void(const std::vector<margelo::nitro::rngine::Entity>&)>>::toJSI(runtime, arg.onTick));
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>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "ids")))) return false;
86
- if (!JSIConverter<std::function<void(const std::vector<margelo::nitro::rngine::Entity>&)>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "onTick")))) return false;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rngine",
3
- "version": "0.3.1",
3
+ "version": "0.4.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,25 +1,37 @@
1
1
  #pragma once
2
- #include <stdexcept>
3
2
  #include <string>
4
3
 
5
4
  namespace margelo::nitro::rngine {
6
5
 
7
- inline uint32_t parseHexColor(const std::string &color) {
8
- if (color.empty() || color[0] != '#') {
9
- throw std::invalid_argument("Only hex colors supported");
10
- }
11
- std::string hex = color.substr(1);
12
- if (hex.size() == 6) {
13
- return 0xFF000000 | std::stoul(hex, nullptr, 16);
14
- } else if (hex.size() == 8) {
15
- uint32_t rgba = std::stoul(hex, nullptr, 16);
16
- uint32_t r = (rgba >> 24) & 0xFF;
17
- uint32_t g = (rgba >> 16) & 0xFF;
18
- uint32_t b = (rgba >> 8) & 0xFF;
19
- uint32_t a = rgba & 0xFF;
20
- return (a << 24) | (r << 16) | (g << 8) | b;
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);
12
+
13
+ if (hex.size() == 3 || hex.size() == 4) {
14
+ std::string expanded;
15
+ expanded.reserve(hex.size() * 2);
16
+ for (char c : hex) {
17
+ expanded += c;
18
+ expanded += c;
19
+ }
20
+ hex = std::move(expanded);
21
+ }
22
+
23
+ if (hex.size() == 6) {
24
+ return 0xFF000000 | std::stoul(hex, nullptr, 16);
25
+ } else if (hex.size() == 8) {
26
+ uint32_t rgba = std::stoul(hex, nullptr, 16);
27
+ uint32_t r = (rgba >> 24) & 0xFF;
28
+ uint32_t g = (rgba >> 16) & 0xFF;
29
+ uint32_t b = (rgba >> 8) & 0xFF;
30
+ uint32_t a = rgba & 0xFF;
31
+ return (a << 24) | (r << 16) | (g << 8) | b;
32
+ }
21
33
  }
22
- throw std::invalid_argument("Invalid hex color: " + color);
23
- }
24
34
 
35
+ return 0x00000000;
36
+ }
25
37
  } // namespace margelo::nitro::rngine
@@ -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,25 +52,38 @@ 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
- {0, _world.width, 0, _world.height, parseHexColor(_world.color)});
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
- if (entity.px + entity.width < 0 || entity.px > _world.width ||
63
- entity.py + entity.height < 0 || entity.py > _world.height) {
75
+ if (entity.px + entity.width < 0 || entity.px > _screen.width ||
76
+ entity.py + entity.height < 0 || entity.py > _screen.height) {
64
77
  continue;
65
78
  }
66
79
 
67
- rects.push_back({std::clamp(entity.px, 0.0, _world.width),
68
- std::clamp(entity.px + entity.width, 0.0, _world.width),
69
- std::clamp(entity.py, 0.0, _world.height),
70
- std::clamp(entity.py + entity.height, 0.0, _world.height),
71
- parseHexColor(entity.color)});
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
- for (const auto &id : system.ids) {
114
- auto resolvedEntitiesInternal = resolveEntitiesInternal(id);
115
- for (auto *entity : resolvedEntitiesInternal)
116
- entities.push_back(*entity);
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.onTick(entities);
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
@@ -3,8 +3,8 @@
3
3
  #include "Entity.hpp"
4
4
  #include "GameStats.hpp"
5
5
  #include "Rect.hpp"
6
+ #include "Screen.hpp"
6
7
  #include "System.hpp"
7
- #include "World.hpp"
8
8
  #include <atomic>
9
9
  #include <memory>
10
10
  #include <thread>
@@ -25,9 +25,10 @@ public:
25
25
  std::map<string, Entity> &getEntitiesInternal() { return _entities; };
26
26
  std::vector<System> &getSystemsInternal() { return _systems; };
27
27
  std::atomic<bool> &getIsPausedInternal() { return _isPaused; };
28
- World &getWorldInternal() { return _world; };
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,11 +37,12 @@ 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};
42
44
  double _tickRate{60.0};
43
- World _world;
45
+ Screen _screen;
44
46
  GameStats _gameStats;
45
47
  std::unique_ptr<std::thread> _gameThread;
46
48
 
@@ -12,13 +12,13 @@ void GameMethods::setTickRate(double tickRate) {
12
12
  "setTickRate: tickRate=%.1f", tickRate);
13
13
  }
14
14
 
15
- void GameMethods::setWorld(const World &world) {
15
+ void GameMethods::setScreen(const Screen &screen) {
16
16
  auto &instance = GameLoop::getInstance();
17
17
  std::lock_guard<std::mutex> lock(instance.getMutexInternal());
18
- instance.getWorldInternal() = world;
18
+ instance.getScreenInternal() = screen;
19
19
  __android_log_print(ANDROID_LOG_INFO, "GameMethods",
20
- "setWorld: width=%.0f height=%.0f", world.width,
21
- world.height);
20
+ "setWorld: width=%.0f height=%.0f", screen.width,
21
+ screen.height);
22
22
  }
23
23
 
24
24
  void GameMethods::setEntities(const std::vector<Entity> &entities) {
@@ -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
- if (update.py.has_value())
119
+ }
120
+ if (update.py.has_value()) {
120
121
  entity->py = update.py.value();
121
- if (update.width.has_value())
122
+ }
123
+ if (update.width.has_value()) {
122
124
  entity->width = update.width.value();
123
- if (update.height.has_value())
125
+ }
126
+ if (update.height.has_value()) {
124
127
  entity->height = update.height.value();
125
- if (update.color.has_value())
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
- if (update.vx.has_value())
137
+ }
138
+ if (update.vx.has_value()) {
128
139
  entity->vx = update.vx.value();
129
- if (update.vy.has_value())
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",
@@ -7,7 +7,7 @@ class GameMethods : public HybridGameMethodsSpec {
7
7
  public:
8
8
  GameMethods() : HybridObject(TAG) {}
9
9
  void setTickRate(double tickRate) override;
10
- void setWorld(const World &world) override;
10
+ void setScreen(const Screen &screen) override;
11
11
  void setEntities(const std::vector<Entity> &entities) override;
12
12
  void setSystems(const std::vector<System> &systems) override;
13
13
  void pause() override;
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 = sizeof(double) * 4 + sizeof(uint32_t);
4
+ static constexpr int RECT_SIZE =
5
+ sizeof(float) * 5 + sizeof(uint32_t) + sizeof(int32_t);
5
6
 
6
7
  struct Rect {
7
- double left;
8
- double right;
9
- double top;
10
- double bottom;
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');
@@ -1,12 +1,13 @@
1
1
  import type { HybridObject } from 'react-native-nitro-modules';
2
- import type { Entity, EntityUpdate, System, World } from './types';
2
+ import type { Entity, EntityUpdate, System, Screen } from './nativeTypes';
3
+ import { NitroModules } from 'react-native-nitro-modules';
3
4
 
4
- export interface GameMethods extends HybridObject<{
5
+ interface GameMethods extends HybridObject<{
5
6
  ios: 'c++';
6
7
  android: 'c++';
7
8
  }> {
8
9
  setTickRate(tickRate: number): void;
9
- setWorld(world: World): void;
10
+ setScreen(screen: Screen): void;
10
11
  setEntities(entities: Entity[]): void;
11
12
  setSystems(systems: System[]): void;
12
13
  pause(): void;
@@ -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');
@@ -1,27 +1,4 @@
1
- import { NitroModules } from 'react-native-nitro-modules';
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
- world,
11
- entities = [],
12
- systems = [],
13
- paused = true,
14
- }: Config) {
15
- gameMethods.setTickRate(tickRate);
16
- gameMethods.setWorld(world);
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
- };