mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
119 Commits
v5.5.232
...
feat/full-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7232311fa3 | ||
![]() |
48d35a50b5 | ||
![]() |
3a0888046f | ||
![]() |
7917994835 | ||
![]() |
9e2bab43f7 | ||
![]() |
7e03f47f08 | ||
![]() |
7c6137a4fc | ||
![]() |
0cbd6e2fe9 | ||
![]() |
5acc1f5560 | ||
![]() |
887693a90d | ||
![]() |
fbb985833f | ||
![]() |
1b3734ff6b | ||
![]() |
6288b30ac3 | ||
![]() |
ee435f7081 | ||
![]() |
d75b4eb2a9 | ||
![]() |
5eeb505807 | ||
![]() |
30566e35ce | ||
![]() |
e058b7f295 | ||
![]() |
902a30a9f8 | ||
![]() |
8669b94fb0 | ||
![]() |
7fb08aea62 | ||
![]() |
e7a1548b0e | ||
![]() |
bdcb6f0533 | ||
![]() |
97849ce6f1 | ||
![]() |
d1c937caf4 | ||
![]() |
5ffe6279a2 | ||
![]() |
9260e2b77a | ||
![]() |
593465e2ec | ||
![]() |
8820350760 | ||
![]() |
7e1668229a | ||
![]() |
387b96b9a0 | ||
![]() |
5f52d786c6 | ||
![]() |
e0db597f9d | ||
![]() |
41b0315ec6 | ||
![]() |
a930a4085e | ||
![]() |
d0dbbfac07 | ||
![]() |
3dc24b46f4 | ||
![]() |
8e44a357b4 | ||
![]() |
dd462310cc | ||
![]() |
a1935fa0cd | ||
![]() |
b45c57246b | ||
![]() |
c481ecd6b5 | ||
![]() |
e0898dd9b0 | ||
![]() |
5561334efa | ||
![]() |
6c4bb4f79e | ||
![]() |
8b2d2e2fe7 | ||
![]() |
49d128c964 | ||
![]() |
f24d1e0916 | ||
![]() |
9faa4c0c69 | ||
![]() |
a04b8f65db | ||
![]() |
e1cf7d23cd | ||
![]() |
b74b221844 | ||
![]() |
38affc15b4 | ||
![]() |
948488d92b | ||
![]() |
f5902d0346 | ||
![]() |
f28dc8e88a | ||
![]() |
1f41749fa3 | ||
![]() |
a4908a4d42 | ||
![]() |
aa7754e658 | ||
![]() |
58ea9387aa | ||
![]() |
775266c974 | ||
![]() |
eb9794cd1f | ||
![]() |
130732adde | ||
![]() |
7a98e73d61 | ||
![]() |
1f26b72b4b | ||
![]() |
a15ffb5b47 | ||
![]() |
1a5f72283a | ||
![]() |
0460b283ba | ||
![]() |
e212e7c780 | ||
![]() |
84100fc7cf | ||
![]() |
11a8682b07 | ||
![]() |
d3a0bbdfb1 | ||
![]() |
15f3a45d6a | ||
![]() |
f0a4f352cc | ||
![]() |
d16b3e8154 | ||
![]() |
614fb97288 | ||
![]() |
8a40d3645a | ||
![]() |
2b7dadf2a8 | ||
![]() |
c338e16e4f | ||
![]() |
aded08471d | ||
![]() |
cccb59b1c5 | ||
![]() |
3592fb7e62 | ||
![]() |
307c92991c | ||
![]() |
4b3f077669 | ||
![]() |
352bae518e | ||
![]() |
c958f4d522 | ||
![]() |
35bbb37ad2 | ||
![]() |
1d48acc841 | ||
![]() |
87702edccc | ||
![]() |
1f0ba7c19a | ||
![]() |
b4d08a99ad | ||
![]() |
8acaa06e42 | ||
![]() |
27ee85b5d4 | ||
![]() |
bbe2d1854e | ||
![]() |
d338690ff5 | ||
![]() |
571a6d8c1a | ||
![]() |
ddb5157c0a | ||
![]() |
64f01354bc | ||
![]() |
37fd99e542 | ||
![]() |
23be4a5849 | ||
![]() |
64c0ee8f98 | ||
![]() |
e5ecce3abf | ||
![]() |
5c71a4da56 | ||
![]() |
dff99b79cb | ||
![]() |
5fe46ea8ea | ||
![]() |
4a590adac4 | ||
![]() |
279d41cdb7 | ||
![]() |
5cf65a9f62 | ||
![]() |
08b05c13b6 | ||
![]() |
eb55c85f4e | ||
![]() |
8a243440db | ||
![]() |
b3e4e6b89c | ||
![]() |
a1a25f6df4 | ||
![]() |
6114a6cec1 | ||
![]() |
5058964937 | ||
![]() |
4488675540 | ||
![]() |
6a2d2c9e67 | ||
![]() |
b43c42d763 | ||
![]() |
69112183d4 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -33,3 +33,4 @@
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
Thumbs.db
|
||||
.claude
|
||||
|
3
.vscode/tasks.json
vendored
3
.vscode/tasks.json
vendored
@@ -38,8 +38,7 @@
|
||||
"presentation": {
|
||||
"reveal": "silent"
|
||||
},
|
||||
"isBackground": true,
|
||||
"runOptions": { "instanceLimit": 1, "runOn": "folderOpen" }
|
||||
"isBackground": true
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
|
@@ -37,8 +37,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.SetIcon("res/actions/position24_black.png");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Angle"))
|
||||
.SetIcon("res/actions/direction24_black.png");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Size"))
|
||||
.SetIcon("res/actions/scale24_black.png");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Size")).SetIcon(
|
||||
"res/actions/scale24_black.png");
|
||||
|
||||
gd::ObjectMetadata& obj = extension.AddObject<gd::ObjectConfiguration>(
|
||||
"", _("Base object"), _("Base object"), "res/objeticon24.png");
|
||||
@@ -838,14 +838,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction(
|
||||
"PushBooleanToObjectVariable",
|
||||
_("Add value to object array variable"),
|
||||
_("Adds a boolean to the end of an object array variable."),
|
||||
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables ❯ Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
obj.AddAction("PushBooleanToObjectVariable",
|
||||
_("Add value to object array variable"),
|
||||
_("Adds a boolean to the end of an object array variable."),
|
||||
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables ❯ Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
@@ -1575,7 +1574,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
extension
|
||||
.AddAction("Create",
|
||||
_("Create an object"),
|
||||
_("Create an object at specified position"),
|
||||
_("Create an instance of the object at the specified position."
|
||||
"The created object instance will be available for the next "
|
||||
"actions and sub-events."),
|
||||
_("Create object _PARAM1_ at position _PARAM2_;_PARAM3_ "
|
||||
"(layer: _PARAM4_)"),
|
||||
"",
|
||||
|
@@ -18,21 +18,21 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAnimatableExtension(
|
||||
gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation("AnimatableCapability",
|
||||
_("Animatable capability"),
|
||||
_("Animate objects."),
|
||||
_("Objects with animations"),
|
||||
_("Actions and conditions for objects having animations (sprite, 3D models...)."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Animatable capability"))
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Objects with animations"))
|
||||
.SetIcon("res/actions/animation24.png");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Animations and images"))
|
||||
.SetIcon("res/actions/animation24.png");
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
"AnimatableBehavior",
|
||||
_("Animatable capability"),
|
||||
_("Objects with animations"),
|
||||
"Animation",
|
||||
_("Animate objects."),
|
||||
_("Actions and conditions for objects having animations (sprite, 3D models...).."),
|
||||
"",
|
||||
"res/actions/animation24.png",
|
||||
"AnimatableBehavior",
|
||||
|
@@ -18,8 +18,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation("EffectCapability",
|
||||
_("Effect capability"),
|
||||
_("Apply visual effects to objects."),
|
||||
_("Objects with effects"),
|
||||
_("Actions/conditions to enable/disable and change parameters of visual effects applied on objects."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects");
|
||||
@@ -28,9 +28,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
"EffectBehavior",
|
||||
_("Effect capability"),
|
||||
_("Objects with effects"),
|
||||
"Effect",
|
||||
_("Apply visual effects to objects."),
|
||||
_("Actions/conditions to enable/disable and change parameters of visual effects applied on objects."),
|
||||
"",
|
||||
"res/actions/effect_black.svg",
|
||||
"EffectBehavior",
|
||||
|
@@ -18,8 +18,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFlippableExtension(
|
||||
gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation("FlippableCapability",
|
||||
_("Flippable capability"),
|
||||
_("Flip objects."),
|
||||
_("Flippable objects"),
|
||||
_("Actions/conditions for objects which can be flipped horizontally or vertically."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects");
|
||||
@@ -28,9 +28,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFlippableExtension(
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
"FlippableBehavior",
|
||||
_("Flippable capability"),
|
||||
_("Flippable objects"),
|
||||
"Flippable",
|
||||
_("Flip objects."),
|
||||
_("Actions/conditions for objects which can be flipped horizontally or vertically."),
|
||||
"",
|
||||
"res/actions/flipX24.png",
|
||||
"FlippableBehavior",
|
||||
|
@@ -18,27 +18,30 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsOpacityExtension(
|
||||
gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation("OpacityCapability",
|
||||
_("Opacity capability"),
|
||||
_("Change the object opacity."),
|
||||
_("Objects with opacity"),
|
||||
_("Action/condition/expression to change or "
|
||||
"check the opacity of an object (0-255)."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Opacity capability"))
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Objects with opacity"))
|
||||
.SetIcon("res/actions/opacity24.png");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Visibility"))
|
||||
.SetIcon("res/actions/opacity24.png");
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
"OpacityBehavior",
|
||||
_("Opacity capability"),
|
||||
"Opacity",
|
||||
_("Change the object opacity."),
|
||||
"",
|
||||
"res/actions/opacity24.png",
|
||||
"OpacityBehavior",
|
||||
std::make_shared<gd::Behavior>(),
|
||||
std::make_shared<gd::BehaviorsSharedData>())
|
||||
.SetHidden();
|
||||
gd::BehaviorMetadata& aut =
|
||||
extension
|
||||
.AddBehavior("OpacityBehavior",
|
||||
_("Objects with opacity"),
|
||||
"Opacity",
|
||||
_("Action/condition/expression to change or check the "
|
||||
"opacity of an object (0-255)."),
|
||||
"",
|
||||
"res/actions/opacity24.png",
|
||||
"OpacityBehavior",
|
||||
std::make_shared<gd::Behavior>(),
|
||||
std::make_shared<gd::BehaviorsSharedData>())
|
||||
.SetHidden();
|
||||
|
||||
aut.AddExpressionAndConditionAndAction(
|
||||
"number",
|
||||
@@ -52,8 +55,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsOpacityExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "OpacityBehavior")
|
||||
.UseStandardParameters(
|
||||
"number", gd::ParameterOptions::MakeNewOptions().SetDescription(
|
||||
_("Opacity (0-255)")))
|
||||
"number",
|
||||
gd::ParameterOptions::MakeNewOptions().SetDescription(
|
||||
_("Opacity (0-255)")))
|
||||
.SetFunctionName("setOpacity")
|
||||
.SetGetter("getOpacity");
|
||||
aut.GetAllExpressions()["Value"].SetGroup("");
|
||||
|
@@ -16,11 +16,13 @@ namespace gd {
|
||||
void GD_CORE_API BuiltinExtensionsImplementer::ImplementsResizableExtension(
|
||||
gd::PlatformExtension &extension) {
|
||||
extension
|
||||
.SetExtensionInformation("ResizableCapability",
|
||||
_("Resizable capability"),
|
||||
_("Change the object dimensions."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionInformation(
|
||||
"ResizableCapability",
|
||||
_("Resizable objects"),
|
||||
_("Change or compare the size (width/height) of an object which can "
|
||||
"be resized (i.e: most objects)."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Size")).SetIcon(
|
||||
"res/actions/scale24_black.png");
|
||||
@@ -28,9 +30,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsResizableExtension(
|
||||
gd::BehaviorMetadata &aut =
|
||||
extension
|
||||
.AddBehavior("ResizableBehavior",
|
||||
_("Resizable capability"),
|
||||
_("Resizable objects"),
|
||||
"Resizable",
|
||||
_("Change the object dimensions."),
|
||||
_("Change or compare the size (width/height) of an "
|
||||
"object which can be resized (i.e: most objects)."),
|
||||
"",
|
||||
"res/actions/scale24_black.png",
|
||||
"ResizableBehavior",
|
||||
|
@@ -18,27 +18,30 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsScalableExtension(
|
||||
gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation("ScalableCapability",
|
||||
_("Scalable capability"),
|
||||
_("Change the object scale."),
|
||||
_("Scalable objects"),
|
||||
_("Actions/conditions/expression to change or "
|
||||
"check the scale of an object (default: 1)."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Scalable capability"))
|
||||
.SetIcon("res/actions/scale24_black.png");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Size"))
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Scalable objects"))
|
||||
.SetIcon("res/actions/scale24_black.png");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Size")).SetIcon(
|
||||
"res/actions/scale24_black.png");
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
"ScalableBehavior",
|
||||
_("Scalable capability"),
|
||||
"Scale",
|
||||
_("Change the object scale."),
|
||||
"",
|
||||
"res/actions/scale24_black.png",
|
||||
"ResizableBehavior",
|
||||
std::make_shared<gd::Behavior>(),
|
||||
std::make_shared<gd::BehaviorsSharedData>())
|
||||
.SetHidden();
|
||||
gd::BehaviorMetadata& aut =
|
||||
extension
|
||||
.AddBehavior("ScalableBehavior",
|
||||
_("Scalable objects"),
|
||||
"Scale",
|
||||
_("Actions/conditions/expression to change or check the "
|
||||
"scale of an object (default: 1)."),
|
||||
"",
|
||||
"res/actions/scale24_black.png",
|
||||
"ResizableBehavior",
|
||||
std::make_shared<gd::Behavior>(),
|
||||
std::make_shared<gd::BehaviorsSharedData>())
|
||||
.SetHidden();
|
||||
|
||||
aut.AddExpressionAndConditionAndAction(
|
||||
"number",
|
||||
|
@@ -18,17 +18,17 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTextContainerExtension(
|
||||
gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation("TextContainerCapability",
|
||||
_("Text capability"),
|
||||
_("Objects containing a text"),
|
||||
_("Allows an object to contain a text, usually shown on screen, that can be modified."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Text capability"))
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Objects containing a text"))
|
||||
.SetIcon("res/conditions/text24_black.png");
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
"TextContainerBehavior",
|
||||
_("Text capability"),
|
||||
_("Objects containing a text"),
|
||||
"Text",
|
||||
_("Allows an object to contain a text, usually shown on screen, that can be modified."),
|
||||
"",
|
||||
|
@@ -16,7 +16,9 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
.SetExtensionInformation(
|
||||
"BuiltinCommonConversions",
|
||||
_("Conversion"),
|
||||
"Expressions to convert number, texts and quantities.",
|
||||
"Expressions to convert numbers to string, strings to numbers, "
|
||||
"angles (degrees from/to radians) and a GDevelop variable to/from a "
|
||||
"JSON string.",
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/common-conversions");
|
||||
@@ -41,7 +43,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
|
||||
extension
|
||||
.AddStrExpression("LargeNumberToString",
|
||||
_("Number > Text ( without scientific notation )"),
|
||||
_("Number > Text (without scientific notation)"),
|
||||
_("Convert the result of the expression to text, "
|
||||
"without using the scientific notation"),
|
||||
"",
|
||||
@@ -72,7 +74,8 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
_("Convert a variable to JSON"),
|
||||
_("JSON"),
|
||||
"res/conditions/toujours24_black.png")
|
||||
.AddParameter("variable", _("The variable to be stringified"),
|
||||
.AddParameter("variable",
|
||||
_("The variable to be stringified"),
|
||||
"AllowUndeclaredVariable");
|
||||
|
||||
// Deprecated
|
||||
|
@@ -15,10 +15,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsKeyboardExtension(
|
||||
.SetExtensionInformation(
|
||||
"BuiltinKeyboard",
|
||||
_("Keyboard"),
|
||||
_("Allows your game to respond to keyboard input. Note that this "
|
||||
_("Conditions to check keys pressed on a keyboard. Note that this "
|
||||
"does not work with on-screen keyboard on touch devices: use "
|
||||
"instead conditions related to touch when making a game for "
|
||||
"mobile/touchscreen devices."),
|
||||
"instead mouse/touch conditions when making a game for "
|
||||
"mobile/touchscreen devices or when making a new game from "
|
||||
"scratch."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/keyboard")
|
||||
@@ -84,7 +85,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsKeyboardExtension(
|
||||
"res/conditions/keyboard.png")
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
|
||||
extension
|
||||
extension
|
||||
.AddCondition("AnyKeyReleased",
|
||||
_("Any key released"),
|
||||
_("Check if any key is released"),
|
||||
|
@@ -72,7 +72,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
|
||||
extension
|
||||
.AddExpression("normalize",
|
||||
_("Normalize a value between `min` and `max` to a value between 0 and 1."),
|
||||
_("Normalize a value between `min` and `max` to a value "
|
||||
"between 0 and 1."),
|
||||
_("Remap a value between 0 and 1."),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
@@ -124,7 +125,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
extension
|
||||
.AddExpression("mod",
|
||||
_("Modulo"),
|
||||
_("x mod y"),
|
||||
_("Compute \"x mod y\". GDevelop does NOT support the \% "
|
||||
"operator. Use this mod(x, y) function instead."),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("x (as in x mod y)"))
|
||||
@@ -184,11 +186,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
.AddExpression("asinh",
|
||||
_("Arcsine"),
|
||||
_("Arcsine"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddExpression(
|
||||
"asinh", _("Arcsine"), _("Arcsine"), "", "res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
@@ -218,11 +217,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
.AddExpression("cbrt",
|
||||
_("Cube root"),
|
||||
_("Cube root"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddExpression(
|
||||
"cbrt", _("Cube root"), _("Cube root"), "", "res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
@@ -260,12 +256,13 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
.AddParameter("expression", _("Expression"), "", true);
|
||||
|
||||
extension
|
||||
.AddExpression("cos",
|
||||
_("Cosine"),
|
||||
_("Cosine of an angle (in radian). "
|
||||
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddExpression(
|
||||
"cos",
|
||||
_("Cosine"),
|
||||
_("Cosine of an angle (in radian). "
|
||||
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
@@ -293,29 +290,20 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
.AddExpression("int",
|
||||
_("Round"),
|
||||
_("Round a number"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddExpression(
|
||||
"int", _("Round"), _("Round a number"), "", "res/mathfunction.png")
|
||||
.SetHidden()
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
.AddExpression("rint",
|
||||
_("Round"),
|
||||
_("Round a number"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddExpression(
|
||||
"rint", _("Round"), _("Round a number"), "", "res/mathfunction.png")
|
||||
.SetHidden()
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
.AddExpression("round",
|
||||
_("Round"),
|
||||
_("Round a number"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddExpression(
|
||||
"round", _("Round"), _("Round a number"), "", "res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
@@ -324,8 +312,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
_("Round a number to the Nth decimal place"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"))
|
||||
.AddParameter("expression", _("Expression"), "", true);
|
||||
.AddParameter("expression", _("Number to Round"))
|
||||
.AddParameter("expression", _("Decimal Places"), "", true);
|
||||
|
||||
extension
|
||||
.AddExpression("exp",
|
||||
@@ -336,19 +324,13 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
.AddExpression("log",
|
||||
_("Logarithm"),
|
||||
_("Logarithm"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddExpression(
|
||||
"log", _("Logarithm"), _("Logarithm"), "", "res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
.AddExpression("ln",
|
||||
_("Logarithm"),
|
||||
_("Logarithm"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddExpression(
|
||||
"ln", _("Logarithm"), _("Logarithm"), "", "res/mathfunction.png")
|
||||
.SetHidden()
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
@@ -387,11 +369,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
.AddParameter("expression", _("The exponent (n in x^n)"));
|
||||
|
||||
extension
|
||||
.AddExpression("sec",
|
||||
_("Secant"),
|
||||
_("Secant"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddExpression(
|
||||
"sec", _("Secant"), _("Secant"), "", "res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
@@ -403,12 +382,13 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
.AddExpression("sin",
|
||||
_("Sine"),
|
||||
_("Sine of an angle (in radian). "
|
||||
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddExpression(
|
||||
"sin",
|
||||
_("Sine"),
|
||||
_("Sine of an angle (in radian). "
|
||||
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
@@ -428,12 +408,13 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
.AddExpression("tan",
|
||||
_("Tangent"),
|
||||
_("Tangent of an angle (in radian). "
|
||||
"If you want to use degrees, use`ToRad`: `tan(ToRad(45))`."),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddExpression(
|
||||
"tan",
|
||||
_("Tangent"),
|
||||
_("Tangent of an angle (in radian). "
|
||||
"If you want to use degrees, use`ToRad`: `tan(ToRad(45))`."),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
@@ -463,26 +444,28 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
.AddParameter("expression", _("x (in a+(b-a)*x)"));
|
||||
|
||||
extension
|
||||
.AddExpression("XFromAngleAndDistance",
|
||||
_("X position from angle and distance"),
|
||||
_("Compute the X position when given an angle and distance "
|
||||
"relative to the origin (0;0). This is also known as "
|
||||
"getting the cartesian coordinates of a 2D vector, using "
|
||||
"its polar coordinates."),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddExpression(
|
||||
"XFromAngleAndDistance",
|
||||
_("X position from angle and distance"),
|
||||
_("Compute the X position when given an angle and distance "
|
||||
"relative to the origin (0;0). This is also known as "
|
||||
"getting the cartesian coordinates of a 2D vector, using "
|
||||
"its polar coordinates."),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Angle, in degrees"))
|
||||
.AddParameter("expression", _("Distance"));
|
||||
|
||||
extension
|
||||
.AddExpression("YFromAngleAndDistance",
|
||||
_("Y position from angle and distance"),
|
||||
_("Compute the Y position when given an angle and distance "
|
||||
"relative to the origin (0;0). This is also known as "
|
||||
"getting the cartesian coordinates of a 2D vector, using "
|
||||
"its polar coordinates."),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddExpression(
|
||||
"YFromAngleAndDistance",
|
||||
_("Y position from angle and distance"),
|
||||
_("Compute the Y position when given an angle and distance "
|
||||
"relative to the origin (0;0). This is also known as "
|
||||
"getting the cartesian coordinates of a 2D vector, using "
|
||||
"its polar coordinates."),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Angle, in degrees"))
|
||||
.AddParameter("expression", _("Distance"));
|
||||
|
||||
@@ -497,7 +480,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
extension
|
||||
.AddExpression("lerpAngle",
|
||||
_("Lerp (Linear interpolation) between two angles"),
|
||||
_("Linearly interpolates between two angles (in degrees) by taking the shortest direction around the circle."),
|
||||
_("Linearly interpolates between two angles (in degrees) "
|
||||
"by taking the shortest direction around the circle."),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Starting angle, in degrees"))
|
||||
|
@@ -16,8 +16,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
.SetExtensionInformation(
|
||||
"BuiltinMouse",
|
||||
_("Mouse and touch"),
|
||||
"Conditions and actions to handle either the mouse or touches on "
|
||||
"touchscreen. By default, conditions related to the mouse will also "
|
||||
"Conditions, actions and expressions to handle either the mouse or "
|
||||
"touches on a touchscreen. Notably: cursor position, mouse wheel, "
|
||||
"mouse buttons, touch positions, started/end touches, etc...\n"
|
||||
"\n"
|
||||
"By default, conditions related to the mouse will also "
|
||||
"handle the touches - so that it's easier to handle both in your "
|
||||
"game. You can disable this behavior if you want to handle them "
|
||||
"separately in different events.",
|
||||
@@ -273,28 +276,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
.SetHidden();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"MouseButtonFromTextPressed",
|
||||
_("Mouse button pressed or touch held"),
|
||||
_("Check if the specified mouse button is pressed or "
|
||||
"if a touch is in contact with the screen."),
|
||||
_("Touch or _PARAM1_ mouse button is down"),
|
||||
"",
|
||||
"res/conditions/mouse24.png",
|
||||
"res/conditions/mouse.png")
|
||||
.AddCondition("MouseButtonFromTextPressed",
|
||||
_("Mouse button pressed or touch held"),
|
||||
_("Check if the specified mouse button is pressed or "
|
||||
"if a touch is in contact with the screen."),
|
||||
_("Touch or _PARAM1_ mouse button is down"),
|
||||
"",
|
||||
"res/conditions/mouse24.png",
|
||||
"res/conditions/mouse.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("mouseButton", _("Button to check"))
|
||||
.MarkAsSimple();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"MouseButtonFromTextReleased",
|
||||
_("Mouse button released"),
|
||||
_("Check if the specified mouse button was released."),
|
||||
_("Touch or _PARAM1_ mouse button is released"),
|
||||
"",
|
||||
"res/conditions/mouse24.png",
|
||||
"res/conditions/mouse.png")
|
||||
.AddCondition("MouseButtonFromTextReleased",
|
||||
_("Mouse button released"),
|
||||
_("Check if the specified mouse button was released."),
|
||||
_("Touch or _PARAM1_ mouse button is released"),
|
||||
"",
|
||||
"res/conditions/mouse24.png",
|
||||
"res/conditions/mouse.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("mouseButton", _("Button to check"))
|
||||
.MarkAsSimple();
|
||||
|
@@ -15,8 +15,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
|
||||
.SetExtensionInformation(
|
||||
"BuiltinNetwork",
|
||||
_("Network"),
|
||||
_("Features to send web requests, communicate with external \"APIs\" "
|
||||
"and other network related tasks."),
|
||||
_("Actions to send web requests, communicate with external \"APIs\" "
|
||||
"and other network related tasks. Also contains an action to open "
|
||||
"a URL on the device browser."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/network")
|
||||
|
@@ -4,8 +4,8 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "AllBuiltinExtensions.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
using namespace std;
|
||||
namespace gd {
|
||||
@@ -16,7 +16,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
|
||||
.SetExtensionInformation(
|
||||
"BuiltinScene",
|
||||
_("Scene"),
|
||||
_("Actions and conditions to manipulate the scenes during the game."),
|
||||
_("Actions/conditions to change the current scene (or pause it and "
|
||||
"launch another one, or go back to the previous one), check if a "
|
||||
"scene or the game has just started/resumed, preload assets of a "
|
||||
"scene, get the current scene name or loading progress, quit the "
|
||||
"game, set background color, or disable input when focus is lost."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("" /*TODO: Add a documentation page for this */);
|
||||
@@ -166,25 +170,28 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
|
||||
extension
|
||||
.AddAction("PrioritizeLoadingOfScene",
|
||||
_("Preload scene"),
|
||||
_("Preload a scene resources as soon as possible in background."),
|
||||
_("Preload scene _PARAM1_ in background"),
|
||||
"",
|
||||
"res/actions/hourglass_black.svg",
|
||||
"res/actions/hourglass_black.svg")
|
||||
.AddAction(
|
||||
"PrioritizeLoadingOfScene",
|
||||
_("Preload scene"),
|
||||
_("Preload a scene resources as soon as possible in background."),
|
||||
_("Preload scene _PARAM1_ in background"),
|
||||
"",
|
||||
"res/actions/hourglass_black.svg",
|
||||
"res/actions/hourglass_black.svg")
|
||||
.SetHelpPath("/all-features/resources-loading")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("sceneName", _("Name of the new scene"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension.AddExpressionAndCondition("number",
|
||||
"SceneLoadingProgress",
|
||||
_("Scene loading progress"),
|
||||
_("The progress of resources loading in background for a scene (between 0 and 1)."),
|
||||
_("_PARAM1_ loading progress"),
|
||||
_(""),
|
||||
"res/actions/hourglass_black.svg")
|
||||
extension
|
||||
.AddExpressionAndCondition("number",
|
||||
"SceneLoadingProgress",
|
||||
_("Scene loading progress"),
|
||||
_("The progress of resources loading in "
|
||||
"background for a scene (between 0 and 1)."),
|
||||
_("_PARAM1_ loading progress"),
|
||||
_(""),
|
||||
"res/actions/hourglass_black.svg")
|
||||
.SetHelpPath("/all-features/resources-loading")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("sceneName", _("Scene name"))
|
||||
@@ -192,13 +199,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("AreSceneAssetsLoaded",
|
||||
_("Scene preloaded"),
|
||||
_("Check if scene resources have finished to load in background."),
|
||||
_("Scene _PARAM1_ was preloaded in background"),
|
||||
"",
|
||||
"res/actions/hourglass_black.svg",
|
||||
"res/actions/hourglass_black.svg")
|
||||
.AddCondition(
|
||||
"AreSceneAssetsLoaded",
|
||||
_("Scene preloaded"),
|
||||
_("Check if scene resources have finished to load in background."),
|
||||
_("Scene _PARAM1_ was preloaded in background"),
|
||||
"",
|
||||
"res/actions/hourglass_black.svg",
|
||||
"res/actions/hourglass_black.svg")
|
||||
.SetHelpPath("/all-features/resources-loading")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("sceneName", _("Scene name"))
|
||||
|
@@ -15,12 +15,13 @@ namespace gd {
|
||||
void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation("Sprite",
|
||||
_("Sprite"),
|
||||
_("Sprite are animated object which can be used "
|
||||
"for most elements of a game."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionInformation(
|
||||
"Sprite",
|
||||
_("Sprite"),
|
||||
_("Sprite are animated objects which can be used "
|
||||
"for most elements of a 2D game."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects/sprite");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Sprite"))
|
||||
.SetIcon("CppPlatform/Extensions/spriteicon.png");
|
||||
@@ -30,7 +31,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
.AddObject<SpriteObject>("Sprite",
|
||||
_("Sprite"),
|
||||
_("Animated object which can be used for "
|
||||
"most elements of a game."),
|
||||
"most elements of a 2D game."),
|
||||
"CppPlatform/Extensions/spriteicon.png")
|
||||
.SetCategoryFullName(_("General"))
|
||||
.SetOpenFullEditorLabel(_("Edit animations"))
|
||||
@@ -645,11 +646,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
"res/actions/sprite.png")
|
||||
.AddParameter("object", _("Object"), "Sprite");
|
||||
|
||||
obj.AddExpression("AnimationFrameCount",
|
||||
_("Number of frames"),
|
||||
_("Number of frames in the current animation of the object"),
|
||||
_("Animations and images"),
|
||||
"res/actions/sprite.png")
|
||||
obj.AddExpression(
|
||||
"AnimationFrameCount",
|
||||
_("Number of frames"),
|
||||
_("Number of frames in the current animation of the object"),
|
||||
_("Animations and images"),
|
||||
"res/actions/sprite.png")
|
||||
.AddParameter("object", _("Object"), "Sprite");
|
||||
|
||||
// Deprecated
|
||||
|
@@ -16,7 +16,8 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
.SetExtensionInformation(
|
||||
"BuiltinStringInstructions",
|
||||
_("Text manipulation"),
|
||||
"Provides expressions to manipulate strings (also called texts).",
|
||||
"Provides expressions to manipulate strings (also called texts): new "
|
||||
"line, upper/lowercase, substring, find, replace, etc...",
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("" /*TODO: Add a documentation page for this */);
|
||||
@@ -191,7 +192,8 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
"res/conditions/toujours24_black.png")
|
||||
.AddParameter("string", _("Text in which the replacement must be done"))
|
||||
.AddParameter("string", _("Text to find inside the first text"))
|
||||
.AddParameter("string", _("Replacement to put instead of the text to find"));
|
||||
.AddParameter("string",
|
||||
_("Replacement to put instead of the text to find"));
|
||||
|
||||
extension
|
||||
.AddStrExpression("StrReplaceAll",
|
||||
@@ -199,10 +201,11 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
_("Replace all occurrences of a text by another."),
|
||||
"",
|
||||
"res/conditions/toujours24_black.png")
|
||||
.AddParameter("string", _("Text in which the replacement(s) must be done"))
|
||||
.AddParameter("string",
|
||||
_("Text in which the replacement(s) must be done"))
|
||||
.AddParameter("string", _("Text to find inside the first text"))
|
||||
.AddParameter("string", _("Replacement to put instead of the text to find"));
|
||||
|
||||
.AddParameter("string",
|
||||
_("Replacement to put instead of the text to find"));
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -15,9 +15,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
.SetExtensionInformation(
|
||||
"BuiltinTime",
|
||||
_("Timers and time"),
|
||||
"Actions and conditions to run timers, get the current time or "
|
||||
"modify the time scale (speed at which the game is running - useful "
|
||||
"for slow motion effects).",
|
||||
"Actions and conditions to start, pause or reset scene timers, "
|
||||
"modify the time scale (speed at which the game "
|
||||
"is running - useful for slow motion effects). Also contains an "
|
||||
"action that wait for a delay before running the next actions and "
|
||||
"sub-events and expressions to read the time scale, time delta of "
|
||||
"the last frame or timer elapsed time.",
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/timers-and-time");
|
||||
@@ -192,26 +195,28 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
extension
|
||||
.AddExpression("TimerElapsedTime",
|
||||
_("Scene timer value"),
|
||||
_("Value of a scene timer"),
|
||||
_("Value of a scene timer (in seconds)"),
|
||||
"",
|
||||
"res/actions/time.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("identifier", _("Timer's name"), "sceneTimer");
|
||||
|
||||
extension
|
||||
.AddExpression("TimeFromStart",
|
||||
_("Time elapsed since the beginning of the scene"),
|
||||
_("Time elapsed since the beginning of the scene"),
|
||||
"",
|
||||
"res/actions/time.png")
|
||||
.AddExpression(
|
||||
"TimeFromStart",
|
||||
_("Time elapsed since the beginning of the scene (in seconds)."),
|
||||
_("Time elapsed since the beginning of the scene (in seconds)."),
|
||||
"",
|
||||
"res/actions/time.png")
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
|
||||
extension
|
||||
.AddExpression("TempsDebut",
|
||||
_("Time elapsed since the beginning of the scene"),
|
||||
_("Time elapsed since the beginning of the scene"),
|
||||
"",
|
||||
"res/actions/time.png")
|
||||
.AddExpression(
|
||||
"TempsDebut",
|
||||
_("Time elapsed since the beginning of the scene (in seconds)."),
|
||||
_("Time elapsed since the beginning of the scene (in seconds)."),
|
||||
"",
|
||||
"res/actions/time.png")
|
||||
.SetHidden()
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
|
||||
@@ -226,16 +231,21 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
extension
|
||||
.AddExpression("Time",
|
||||
_("Current time"),
|
||||
_("Current time"),
|
||||
_("Gives the current time"),
|
||||
"",
|
||||
"res/actions/time.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter(
|
||||
"stringWithSelector",
|
||||
_("Hour: hour - Minutes: min - Seconds: sec - Day of month: "
|
||||
"mday - Months since January: mon - Year since 1900: year - Days "
|
||||
"since Sunday: wday - Days since Jan 1st: yday - Timestamp (ms): "
|
||||
"timestamp\""),
|
||||
_("- Hour of the day: \"hour\"\n"
|
||||
"- Minutes: \"min\"\n"
|
||||
"- Seconds: \"sec\"\n"
|
||||
"- Day of month: \"mday\"\n"
|
||||
"- Months since January: \"mon\"\n"
|
||||
"- Year since 1900: \"year\"\n"
|
||||
"- Days since Sunday: \"wday\"\n"
|
||||
"- Days since Jan 1st: \"yday\"\n"
|
||||
"- Timestamp (ms): \"timestamp\""),
|
||||
"[\"hour\", \"min\", \"sec\", \"mon\", \"year\", \"wday\", \"mday\", "
|
||||
"\"yday\", \"timestamp\"]");
|
||||
}
|
||||
|
@@ -15,16 +15,17 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
|
||||
.SetExtensionInformation(
|
||||
"BuiltinWindow",
|
||||
_("Game window and resolution"),
|
||||
"Provides actions and conditions to manipulate the game window. "
|
||||
"Actions and conditions to manipulate the game window or change how "
|
||||
"the game is resized according to the screen size. "
|
||||
"Depending on the platform on which the game is running, not all of "
|
||||
"these features can be applied.",
|
||||
"these features can be applied.\n"
|
||||
"Also contains expressions to read the screen size.",
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("User interface")
|
||||
.SetExtensionHelpPath("/all-features/window");
|
||||
extension
|
||||
.AddInstructionOrExpressionGroupMetadata(
|
||||
_("Game window and resolution"))
|
||||
.AddInstructionOrExpressionGroupMetadata(_("Game window and resolution"))
|
||||
.SetIcon("res/actions/window24.png");
|
||||
|
||||
extension
|
||||
|
@@ -63,7 +63,6 @@ void EventsBasedObjectVariantHelper::ComplyVariantsToEventsBasedObject(
|
||||
}
|
||||
|
||||
// Copy missing behaviors
|
||||
auto &behaviors = object.GetAllBehaviorContents();
|
||||
for (const auto &pair : defaultBehaviors) {
|
||||
const auto &behaviorName = pair.first;
|
||||
const auto &defaultBehavior = pair.second;
|
||||
@@ -82,11 +81,9 @@ void EventsBasedObjectVariantHelper::ComplyVariantsToEventsBasedObject(
|
||||
}
|
||||
}
|
||||
// Delete extra behaviors
|
||||
for (auto it = behaviors.begin(); it != behaviors.end(); ++it) {
|
||||
const auto &behaviorName = it->first;
|
||||
for (auto &behaviorName : object.GetAllBehaviorNames()) {
|
||||
if (!defaultObject->HasBehaviorNamed(behaviorName)) {
|
||||
object.RemoveBehavior(behaviorName);
|
||||
--it;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,8 @@
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
gd::String Effect::badStringParameterValue;
|
||||
|
||||
void Effect::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", GetName());
|
||||
|
@@ -3,8 +3,7 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EFFECT_H
|
||||
#define GDCORE_EFFECT_H
|
||||
#pragma once
|
||||
#include <map>
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
@@ -35,28 +34,43 @@ class GD_CORE_API Effect {
|
||||
void SetFolded(bool fold = true) { folded = fold; }
|
||||
bool IsFolded() const { return folded; }
|
||||
|
||||
void SetDoubleParameter(const gd::String& name, double value) {
|
||||
void SetDoubleParameter(const gd::String &name, double value) {
|
||||
doubleParameters[name] = value;
|
||||
}
|
||||
|
||||
double GetDoubleParameter(const gd::String& name) {
|
||||
return doubleParameters[name];
|
||||
double GetDoubleParameter(const gd::String &name) const {
|
||||
auto itr = doubleParameters.find(name);
|
||||
return itr == doubleParameters.end() ? 0 : itr->second;
|
||||
}
|
||||
|
||||
void SetStringParameter(const gd::String& name, const gd::String& value) {
|
||||
bool HasDoubleParameter(const gd::String &name) const {
|
||||
return doubleParameters.find(name) != doubleParameters.end();
|
||||
}
|
||||
|
||||
void SetStringParameter(const gd::String &name, const gd::String &value) {
|
||||
stringParameters[name] = value;
|
||||
}
|
||||
|
||||
const gd::String& GetStringParameter(const gd::String& name) {
|
||||
return stringParameters[name];
|
||||
const gd::String &GetStringParameter(const gd::String &name) const {
|
||||
auto itr = stringParameters.find(name);
|
||||
return itr == stringParameters.end() ? badStringParameterValue : itr->second;
|
||||
}
|
||||
|
||||
void SetBooleanParameter(const gd::String& name, bool value) {
|
||||
bool HasStringParameter(const gd::String &name) const {
|
||||
return stringParameters.find(name) != stringParameters.end();
|
||||
}
|
||||
|
||||
void SetBooleanParameter(const gd::String &name, bool value) {
|
||||
booleanParameters[name] = value;
|
||||
}
|
||||
|
||||
bool GetBooleanParameter(const gd::String& name) {
|
||||
return booleanParameters[name];
|
||||
bool GetBooleanParameter(const gd::String &name) const {
|
||||
auto itr = booleanParameters.find(name);
|
||||
return itr == booleanParameters.end() ? false : itr->second;
|
||||
}
|
||||
|
||||
bool HasBooleanParameter(const gd::String &name) const {
|
||||
return booleanParameters.find(name) != booleanParameters.end();
|
||||
}
|
||||
|
||||
const std::map<gd::String, double>& GetAllDoubleParameters() const {
|
||||
@@ -94,7 +108,9 @@ class GD_CORE_API Effect {
|
||||
std::map<gd::String, double> doubleParameters; ///< Values of parameters being doubles, keyed by names.
|
||||
std::map<gd::String, gd::String> stringParameters; ///< Values of parameters being strings, keyed by names.
|
||||
std::map<gd::String, bool> booleanParameters; ///< Values of parameters being booleans, keyed by names.
|
||||
|
||||
static gd::String badStringParameterValue; ///< Empty string returned by
|
||||
///< GeStringParameter
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
#endif
|
||||
|
@@ -36,7 +36,7 @@ namespace gd {
|
||||
|
||||
gd::BehaviorsSharedData Layout::badBehaviorSharedData("", "");
|
||||
|
||||
Layout::Layout(const Layout &other)
|
||||
Layout::Layout(const Layout& other)
|
||||
: objectsContainer(gd::ObjectsContainer::SourceType::Scene) {
|
||||
Init(other);
|
||||
}
|
||||
@@ -54,6 +54,8 @@ Layout::Layout()
|
||||
backgroundColorG(209),
|
||||
backgroundColorB(209),
|
||||
stopSoundsOnStartup(true),
|
||||
resourcesPreloading("inherit"),
|
||||
resourcesUnloading("inherit"),
|
||||
standardSortMethod(true),
|
||||
disableInputWhenNotFocused(true),
|
||||
variables(gd::VariablesContainer::SourceType::Scene),
|
||||
@@ -244,6 +246,10 @@ void Layout::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("title", GetWindowDefaultTitle());
|
||||
element.SetAttribute("standardSortMethod", standardSortMethod);
|
||||
element.SetAttribute("stopSoundsOnStartup", stopSoundsOnStartup);
|
||||
if (resourcesPreloading != "inherit")
|
||||
element.SetAttribute("resourcesPreloading", resourcesPreloading);
|
||||
if (resourcesUnloading != "inherit")
|
||||
element.SetAttribute("resourcesUnloading", resourcesUnloading);
|
||||
element.SetAttribute("disableInputWhenNotFocused",
|
||||
disableInputWhenNotFocused);
|
||||
|
||||
@@ -304,6 +310,10 @@ void Layout::UnserializeFrom(gd::Project& project,
|
||||
element.GetStringAttribute("title", "(No title)", "titre"));
|
||||
standardSortMethod = element.GetBoolAttribute("standardSortMethod");
|
||||
stopSoundsOnStartup = element.GetBoolAttribute("stopSoundsOnStartup");
|
||||
resourcesPreloading =
|
||||
element.GetStringAttribute("resourcesPreloading", "inherit");
|
||||
resourcesUnloading =
|
||||
element.GetStringAttribute("resourcesUnloading", "inherit");
|
||||
disableInputWhenNotFocused =
|
||||
element.GetBoolAttribute("disableInputWhenNotFocused");
|
||||
|
||||
@@ -391,6 +401,8 @@ void Layout::Init(const Layout& other) {
|
||||
standardSortMethod = other.standardSortMethod;
|
||||
title = other.title;
|
||||
stopSoundsOnStartup = other.stopSoundsOnStartup;
|
||||
resourcesPreloading = other.resourcesPreloading;
|
||||
resourcesUnloading = other.resourcesUnloading;
|
||||
disableInputWhenNotFocused = other.disableInputWhenNotFocused;
|
||||
initialInstances = other.initialInstances;
|
||||
layers = other.layers;
|
||||
|
@@ -349,6 +349,36 @@ class GD_CORE_API Layout {
|
||||
* launched
|
||||
*/
|
||||
bool StopSoundsOnStartup() const { return stopSoundsOnStartup; }
|
||||
|
||||
/**
|
||||
* Set when the scene must preload its resources: `at-startup`, `never` or
|
||||
* `inherit` (default).
|
||||
*/
|
||||
void SetResourcesPreloading(gd::String resourcesPreloading_) {
|
||||
resourcesPreloading = resourcesPreloading_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get when the scene must preload its resources: `at-startup`, `never` or
|
||||
* `inherit` (default).
|
||||
*/
|
||||
const gd::String& GetResourcesPreloading() const {
|
||||
return resourcesPreloading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set when the scene must unload its resources: `at-scene-exit`, `never` or
|
||||
* `inherit` (default).
|
||||
*/
|
||||
void SetResourcesUnloading(gd::String resourcesUnloading_) {
|
||||
resourcesUnloading = resourcesUnloading_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get when the scene must unload its resources: `at-scene-exit`, `never` or
|
||||
* `inherit` (default).
|
||||
*/
|
||||
const gd::String& GetResourcesUnloading() const { return resourcesUnloading; }
|
||||
///@}
|
||||
|
||||
/** \name Saving and loading
|
||||
@@ -381,6 +411,10 @@ class GD_CORE_API Layout {
|
||||
behaviorsSharedData; ///< Initial shared datas of behaviors
|
||||
bool stopSoundsOnStartup = true; ///< True to make the scene stop all sounds at
|
||||
///< startup.
|
||||
gd::String
|
||||
resourcesPreloading; ///< `at-startup`, `never` or `inherit` (default).
|
||||
gd::String
|
||||
resourcesUnloading; ///< `at-scene-exit`, `never` or `inherit` (default).
|
||||
bool standardSortMethod = true; ///< True to sort objects using standard sort.
|
||||
bool disableInputWhenNotFocused = true; /// If set to true, the input must be
|
||||
/// disabled when the window do not have the
|
||||
|
@@ -74,7 +74,9 @@ Project::Project()
|
||||
gdMinorVersion(gd::VersionWrapper::Minor()),
|
||||
gdBuildVersion(gd::VersionWrapper::Build()),
|
||||
variables(gd::VariablesContainer::SourceType::Global),
|
||||
objectsContainer(gd::ObjectsContainer::SourceType::Global) {}
|
||||
objectsContainer(gd::ObjectsContainer::SourceType::Global),
|
||||
sceneResourcesPreloading("at-startup"),
|
||||
sceneResourcesUnloading("never") {}
|
||||
|
||||
Project::~Project() {}
|
||||
|
||||
@@ -1166,6 +1168,13 @@ void Project::SerializeTo(SerializerElement& element) const {
|
||||
else
|
||||
std::cout << "ERROR: The project current platform is NULL.";
|
||||
|
||||
if (sceneResourcesPreloading != "at-startup") {
|
||||
propElement.SetAttribute("sceneResourcesPreloading", sceneResourcesPreloading);
|
||||
}
|
||||
if (sceneResourcesUnloading != "never") {
|
||||
propElement.SetAttribute("sceneResourcesUnloading", sceneResourcesUnloading);
|
||||
}
|
||||
|
||||
resourcesManager.SerializeTo(element.AddChild("resources"));
|
||||
objectsContainer.SerializeObjectsTo(element.AddChild("objects"));
|
||||
objectsContainer.SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
|
||||
@@ -1307,6 +1316,9 @@ void Project::Init(const gd::Project& game) {
|
||||
variables = game.GetVariables();
|
||||
|
||||
projectFile = game.GetProjectFile();
|
||||
|
||||
sceneResourcesPreloading = game.sceneResourcesPreloading;
|
||||
sceneResourcesUnloading = game.sceneResourcesUnloading;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -964,6 +964,37 @@ class GD_CORE_API Project {
|
||||
*/
|
||||
ResourcesManager& GetResourcesManager() { return resourcesManager; }
|
||||
|
||||
/**
|
||||
* Set when the scenes must preload their resources: `at-startup`, `never`
|
||||
* (default).
|
||||
*/
|
||||
void SetSceneResourcesPreloading(gd::String sceneResourcesPreloading_) {
|
||||
sceneResourcesPreloading = sceneResourcesPreloading_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get when the scenes must preload their resources: `at-startup`, `never`
|
||||
* (default).
|
||||
*/
|
||||
const gd::String& GetSceneResourcesPreloading() const {
|
||||
return sceneResourcesPreloading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set when the scenes must unload their resources: `at-scene-exit`, `never`
|
||||
* (default).
|
||||
*/
|
||||
void SetSceneResourcesUnloading(gd::String sceneResourcesUnloading_) {
|
||||
sceneResourcesUnloading = sceneResourcesUnloading_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get when the scenes must unload their resources: `at-scene-exit`, `never`
|
||||
* (default).
|
||||
*/
|
||||
const gd::String& GetSceneResourcesUnloading() const {
|
||||
return sceneResourcesUnloading;
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name Variable management
|
||||
@@ -1121,6 +1152,10 @@ class GD_CORE_API Project {
|
||||
ExtensionProperties
|
||||
extensionProperties; ///< The properties of the extensions.
|
||||
gd::WholeProjectDiagnosticReport wholeProjectDiagnosticReport;
|
||||
gd::String sceneResourcesPreloading; ///< `at-startup` or `never`
|
||||
///< (default: `at-startup`).
|
||||
gd::String sceneResourcesUnloading; ///< `at-scene-exit` or `never`
|
||||
///< (default: `never`).
|
||||
mutable unsigned int gdMajorVersion =
|
||||
0; ///< The GD major version used the last
|
||||
///< time the project was saved.
|
||||
|
@@ -7,9 +7,9 @@
|
||||
#define GDCORE_PROPERTYDESCRIPTOR
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Project/MeasurementUnit.h"
|
||||
#include "GDCore/Project/QuickCustomization.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
@@ -17,6 +17,19 @@ class SerializerElement;
|
||||
|
||||
namespace gd {
|
||||
|
||||
class GD_CORE_API PropertyDescriptorChoice {
|
||||
public:
|
||||
PropertyDescriptorChoice(const gd::String& value, const gd::String& label)
|
||||
: value(value), label(label) {}
|
||||
|
||||
const gd::String& GetValue() const { return value; }
|
||||
const gd::String& GetLabel() const { return label; }
|
||||
|
||||
private:
|
||||
gd::String value;
|
||||
gd::String label;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Used to describe a property shown in a property grid.
|
||||
* \see gd::Object
|
||||
@@ -31,8 +44,12 @@ class GD_CORE_API PropertyDescriptor {
|
||||
* \param propertyValue The value of the property.
|
||||
*/
|
||||
PropertyDescriptor(gd::String propertyValue)
|
||||
: currentValue(propertyValue), type("string"), label(""), hidden(false),
|
||||
deprecated(false), advanced(false),
|
||||
: currentValue(propertyValue),
|
||||
type("string"),
|
||||
label(""),
|
||||
hidden(false),
|
||||
deprecated(false),
|
||||
advanced(false),
|
||||
hasImpactOnOtherProperties(false),
|
||||
measurementUnit(gd::MeasurementUnit::GetUndefined()),
|
||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {}
|
||||
@@ -41,10 +58,13 @@ class GD_CORE_API PropertyDescriptor {
|
||||
* \brief Empty constructor creating an empty property to be displayed.
|
||||
*/
|
||||
PropertyDescriptor()
|
||||
: hidden(false), deprecated(false), advanced(false),
|
||||
: hidden(false),
|
||||
deprecated(false),
|
||||
advanced(false),
|
||||
hasImpactOnOtherProperties(false),
|
||||
measurementUnit(gd::MeasurementUnit::GetUndefined()),
|
||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default){};
|
||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Destructor
|
||||
@@ -88,13 +108,20 @@ class GD_CORE_API PropertyDescriptor {
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Change the group where this property is displayed to the user, if any.
|
||||
* \brief Change the group where this property is displayed to the user, if
|
||||
* any.
|
||||
*/
|
||||
PropertyDescriptor& SetGroup(gd::String group_) {
|
||||
group = group_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PropertyDescriptor& AddChoice(const gd::String& value,
|
||||
const gd::String& label) {
|
||||
choices.push_back(PropertyDescriptorChoice(value, label));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set and replace the additional information for the property.
|
||||
*/
|
||||
@@ -118,7 +145,8 @@ class GD_CORE_API PropertyDescriptor {
|
||||
/**
|
||||
* \brief Change the unit of measurement of the property value.
|
||||
*/
|
||||
PropertyDescriptor& SetMeasurementUnit(const gd::MeasurementUnit &measurementUnit_) {
|
||||
PropertyDescriptor& SetMeasurementUnit(
|
||||
const gd::MeasurementUnit& measurementUnit_) {
|
||||
measurementUnit = measurementUnit_;
|
||||
return *this;
|
||||
}
|
||||
@@ -128,14 +156,18 @@ class GD_CORE_API PropertyDescriptor {
|
||||
const gd::String& GetLabel() const { return label; }
|
||||
const gd::String& GetDescription() const { return description; }
|
||||
const gd::String& GetGroup() const { return group; }
|
||||
const gd::MeasurementUnit& GetMeasurementUnit() const { return measurementUnit; }
|
||||
const gd::MeasurementUnit& GetMeasurementUnit() const {
|
||||
return measurementUnit;
|
||||
}
|
||||
|
||||
const std::vector<gd::String>& GetExtraInfo() const {
|
||||
return extraInformation;
|
||||
}
|
||||
|
||||
std::vector<gd::String>& GetExtraInfo() {
|
||||
return extraInformation;
|
||||
std::vector<gd::String>& GetExtraInfo() { return extraInformation; }
|
||||
|
||||
const std::vector<PropertyDescriptorChoice>& GetChoices() const {
|
||||
return choices;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,23 +210,26 @@ class GD_CORE_API PropertyDescriptor {
|
||||
bool IsAdvanced() const { return advanced; }
|
||||
|
||||
/**
|
||||
* \brief Check if the property has impact on other properties - which means a change
|
||||
* must re-render other properties.
|
||||
* \brief Check if the property has impact on other properties - which means a
|
||||
* change must re-render other properties.
|
||||
*/
|
||||
bool HasImpactOnOtherProperties() const { return hasImpactOnOtherProperties; }
|
||||
|
||||
/**
|
||||
* \brief Set if the property has impact on other properties - which means a change
|
||||
* must re-render other properties.
|
||||
* \brief Set if the property has impact on other properties - which means a
|
||||
* change must re-render other properties.
|
||||
*/
|
||||
PropertyDescriptor& SetHasImpactOnOtherProperties(bool enable) {
|
||||
hasImpactOnOtherProperties = enable;
|
||||
return *this;
|
||||
}
|
||||
|
||||
QuickCustomization::Visibility GetQuickCustomizationVisibility() const { return quickCustomizationVisibility; }
|
||||
QuickCustomization::Visibility GetQuickCustomizationVisibility() const {
|
||||
return quickCustomizationVisibility;
|
||||
}
|
||||
|
||||
PropertyDescriptor& SetQuickCustomizationVisibility(QuickCustomization::Visibility visibility) {
|
||||
PropertyDescriptor& SetQuickCustomizationVisibility(
|
||||
QuickCustomization::Visibility visibility) {
|
||||
quickCustomizationVisibility = visibility;
|
||||
return *this;
|
||||
}
|
||||
@@ -231,15 +266,17 @@ class GD_CORE_API PropertyDescriptor {
|
||||
gd::String label; //< The user-friendly property name
|
||||
gd::String description; //< The user-friendly property description
|
||||
gd::String group; //< The user-friendly property group
|
||||
std::vector<PropertyDescriptorChoice>
|
||||
choices; //< The optional choices for the property.
|
||||
std::vector<gd::String>
|
||||
extraInformation; ///< Can be used to store for example the available
|
||||
///< choices, if a property is a displayed as a combo
|
||||
///< box.
|
||||
extraInformation; ///< Can be used to store an additional information
|
||||
///< like an object type.
|
||||
bool hidden;
|
||||
bool deprecated;
|
||||
bool advanced;
|
||||
bool hasImpactOnOtherProperties;
|
||||
gd::MeasurementUnit measurementUnit; //< The unit of measurement of the property vale.
|
||||
gd::MeasurementUnit
|
||||
measurementUnit; //< The unit of measurement of the property vale.
|
||||
QuickCustomization::Visibility quickCustomizationVisibility;
|
||||
};
|
||||
|
||||
|
@@ -5,8 +5,6 @@ namespace gdjs {
|
||||
type Object3DNetworkSyncDataType = {
|
||||
// z is position on the Z axis, different from zo, which is Z order
|
||||
z: number;
|
||||
w: number;
|
||||
h: number;
|
||||
d: number;
|
||||
rx: number;
|
||||
ry: number;
|
||||
@@ -116,8 +114,6 @@ namespace gdjs {
|
||||
return {
|
||||
...super.getNetworkSyncData(),
|
||||
z: this.getZ(),
|
||||
w: this.getWidth(),
|
||||
h: this.getHeight(),
|
||||
d: this.getDepth(),
|
||||
rx: this.getRotationX(),
|
||||
ry: this.getRotationY(),
|
||||
@@ -130,8 +126,6 @@ namespace gdjs {
|
||||
updateFromNetworkSyncData(networkSyncData: Object3DNetworkSyncData) {
|
||||
super.updateFromNetworkSyncData(networkSyncData);
|
||||
if (networkSyncData.z !== undefined) this.setZ(networkSyncData.z);
|
||||
if (networkSyncData.w !== undefined) this.setWidth(networkSyncData.w);
|
||||
if (networkSyncData.h !== undefined) this.setHeight(networkSyncData.h);
|
||||
if (networkSyncData.d !== undefined) this.setDepth(networkSyncData.d);
|
||||
if (networkSyncData.rx !== undefined)
|
||||
this.setRotationX(networkSyncData.rx);
|
||||
|
@@ -25,6 +25,8 @@ namespace gdjs {
|
||||
topFaceVisible: boolean;
|
||||
bottomFaceVisible: boolean;
|
||||
tint: string | undefined;
|
||||
isCastingShadow: boolean;
|
||||
isReceivingShadow: boolean;
|
||||
materialType: 'Basic' | 'StandardWithoutMetalness';
|
||||
};
|
||||
}
|
||||
@@ -71,8 +73,10 @@ namespace gdjs {
|
||||
string,
|
||||
];
|
||||
_materialType: gdjs.Cube3DRuntimeObject.MaterialType =
|
||||
gdjs.Cube3DRuntimeObject.MaterialType.Basic;
|
||||
gdjs.Cube3DRuntimeObject.MaterialType.StandardWithoutMetalness;
|
||||
_tint: string;
|
||||
_isCastingShadow: boolean = true;
|
||||
_isReceivingShadow: boolean = true;
|
||||
|
||||
constructor(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
@@ -121,6 +125,8 @@ namespace gdjs {
|
||||
];
|
||||
|
||||
this._tint = objectData.content.tint || '255;255;255';
|
||||
this._isCastingShadow = objectData.content.isCastingShadow || false;
|
||||
this._isReceivingShadow = objectData.content.isReceivingShadow || false;
|
||||
|
||||
this._materialType = this._convertMaterialType(
|
||||
objectData.content.materialType
|
||||
@@ -430,6 +436,18 @@ namespace gdjs {
|
||||
) {
|
||||
this.setMaterialType(newObjectData.content.materialType);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.isCastingShadow !==
|
||||
newObjectData.content.isCastingShadow
|
||||
) {
|
||||
this.updateShadowCasting(newObjectData.content.isCastingShadow);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.isReceivingShadow !==
|
||||
newObjectData.content.isReceivingShadow
|
||||
) {
|
||||
this.updateShadowReceiving(newObjectData.content.isReceivingShadow);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -531,6 +549,14 @@ namespace gdjs {
|
||||
this._materialType = newMaterialType;
|
||||
this._renderer._updateMaterials();
|
||||
}
|
||||
updateShadowCasting(value: boolean) {
|
||||
this._isCastingShadow = value;
|
||||
this._renderer.updateShadowCasting();
|
||||
}
|
||||
updateShadowReceiving(value: boolean) {
|
||||
this._isReceivingShadow = value;
|
||||
this._renderer.updateShadowReceiving();
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Cube3DRuntimeObject {
|
||||
|
@@ -81,13 +81,14 @@ namespace gdjs {
|
||||
.map((_, index) =>
|
||||
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[index])
|
||||
);
|
||||
|
||||
const boxMesh = new THREE.Mesh(geometry, materials);
|
||||
|
||||
super(runtimeObject, instanceContainer, boxMesh);
|
||||
this._boxMesh = boxMesh;
|
||||
this._cube3DRuntimeObject = runtimeObject;
|
||||
|
||||
boxMesh.receiveShadow = this._cube3DRuntimeObject._isReceivingShadow;
|
||||
boxMesh.castShadow = this._cube3DRuntimeObject._isCastingShadow;
|
||||
this.updateSize();
|
||||
this.updatePosition();
|
||||
this.updateRotation();
|
||||
@@ -114,6 +115,13 @@ namespace gdjs {
|
||||
new THREE.BufferAttribute(new Float32Array(tints), 3)
|
||||
);
|
||||
}
|
||||
updateShadowCasting() {
|
||||
this._boxMesh.castShadow = this._cube3DRuntimeObject._isCastingShadow;
|
||||
}
|
||||
updateShadowReceiving() {
|
||||
this._boxMesh.receiveShadow =
|
||||
this._cube3DRuntimeObject._isReceivingShadow;
|
||||
}
|
||||
|
||||
updateFace(faceIndex: integer) {
|
||||
const materialIndex = faceIndexToMaterialIndex[faceIndex];
|
||||
|
@@ -1,4 +1,12 @@
|
||||
namespace gdjs {
|
||||
type CustomObject3DNetworkSyncDataType = CustomObjectNetworkSyncDataType & {
|
||||
z: float;
|
||||
d: float;
|
||||
rx: float;
|
||||
ry: float;
|
||||
ifz: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for 3D custom objects.
|
||||
*/
|
||||
@@ -77,6 +85,30 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
getNetworkSyncData(): CustomObject3DNetworkSyncDataType {
|
||||
return {
|
||||
...super.getNetworkSyncData(),
|
||||
z: this.getZ(),
|
||||
d: this.getDepth(),
|
||||
rx: this.getRotationX(),
|
||||
ry: this.getRotationY(),
|
||||
ifz: this.isFlippedZ(),
|
||||
};
|
||||
}
|
||||
|
||||
updateFromNetworkSyncData(
|
||||
networkSyncData: CustomObject3DNetworkSyncDataType
|
||||
): void {
|
||||
super.updateFromNetworkSyncData(networkSyncData);
|
||||
if (networkSyncData.z !== undefined) this.setZ(networkSyncData.z);
|
||||
if (networkSyncData.d !== undefined) this.setDepth(networkSyncData.d);
|
||||
if (networkSyncData.rx !== undefined)
|
||||
this.setRotationX(networkSyncData.rx);
|
||||
if (networkSyncData.ry !== undefined)
|
||||
this.setRotationY(networkSyncData.ry);
|
||||
if (networkSyncData.ifz !== undefined) this.flipZ(networkSyncData.ifz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object position on the Z axis.
|
||||
*/
|
||||
|
@@ -6,6 +6,7 @@ namespace gdjs {
|
||||
r: number;
|
||||
t: string;
|
||||
}
|
||||
const shadowHelper = false;
|
||||
gdjs.PixiFiltersTools.registerFilterCreator(
|
||||
'Scene3D::DirectionalLight',
|
||||
new (class implements gdjs.PixiFiltersTools.FilterCreator {
|
||||
@@ -17,19 +18,63 @@ namespace gdjs {
|
||||
return new gdjs.PixiFiltersTools.EmptyFilter();
|
||||
}
|
||||
return new (class implements gdjs.PixiFiltersTools.Filter {
|
||||
light: THREE.DirectionalLight;
|
||||
rotationObject: THREE.Group;
|
||||
_isEnabled: boolean = false;
|
||||
top: string = 'Y-';
|
||||
elevation: float = 45;
|
||||
rotation: float = 0;
|
||||
private _top: string = 'Z+';
|
||||
private _elevation: float = 45;
|
||||
private _rotation: float = 0;
|
||||
private _shadowMapSize: float = 1024;
|
||||
private _minimumShadowBias: float = 0;
|
||||
private _distanceFromCamera: float = 1500;
|
||||
private _frustumSize: float = 4000;
|
||||
|
||||
private _isEnabled: boolean = false;
|
||||
private _light: THREE.DirectionalLight;
|
||||
private _shadowMapDirty = true;
|
||||
private _shadowCameraDirty = true;
|
||||
private _shadowCameraHelper: THREE.CameraHelper | null;
|
||||
|
||||
constructor() {
|
||||
this.light = new THREE.DirectionalLight();
|
||||
this.light.position.set(1, 0, 0);
|
||||
this.rotationObject = new THREE.Group();
|
||||
this.rotationObject.add(this.light);
|
||||
this.updateRotation();
|
||||
this._light = new THREE.DirectionalLight();
|
||||
|
||||
if (shadowHelper) {
|
||||
this._shadowCameraHelper = new THREE.CameraHelper(
|
||||
this._light.shadow.camera
|
||||
);
|
||||
} else {
|
||||
this._shadowCameraHelper = null;
|
||||
}
|
||||
|
||||
this._light.shadow.camera.updateProjectionMatrix();
|
||||
}
|
||||
|
||||
private _updateShadowCamera(): void {
|
||||
if (!this._shadowCameraDirty) {
|
||||
return;
|
||||
}
|
||||
this._shadowCameraDirty = false;
|
||||
|
||||
this._light.shadow.camera.near = 1;
|
||||
this._light.shadow.camera.far = this._distanceFromCamera + 10000;
|
||||
this._light.shadow.camera.right = this._frustumSize / 2;
|
||||
this._light.shadow.camera.left = -this._frustumSize / 2;
|
||||
this._light.shadow.camera.top = this._frustumSize / 2;
|
||||
this._light.shadow.camera.bottom = -this._frustumSize / 2;
|
||||
}
|
||||
|
||||
private _updateShadowMapSize(): void {
|
||||
if (!this._shadowMapDirty) {
|
||||
return;
|
||||
}
|
||||
this._shadowMapDirty = false;
|
||||
|
||||
this._light.shadow.mapSize.set(
|
||||
this._shadowMapSize,
|
||||
this._shadowMapSize
|
||||
);
|
||||
|
||||
// Force the recreation of the shadow map texture:
|
||||
this._light.shadow.map?.dispose();
|
||||
this._light.shadow.map = null;
|
||||
this._light.shadow.needsUpdate = true;
|
||||
}
|
||||
|
||||
isEnabled(target: EffectsTarget): boolean {
|
||||
@@ -53,7 +98,12 @@ namespace gdjs {
|
||||
if (!scene) {
|
||||
return false;
|
||||
}
|
||||
scene.add(this.rotationObject);
|
||||
scene.add(this._light);
|
||||
scene.add(this._light.target);
|
||||
if (this._shadowCameraHelper) {
|
||||
scene.add(this._shadowCameraHelper);
|
||||
}
|
||||
|
||||
this._isEnabled = true;
|
||||
return true;
|
||||
}
|
||||
@@ -65,82 +115,164 @@ namespace gdjs {
|
||||
if (!scene) {
|
||||
return false;
|
||||
}
|
||||
scene.remove(this.rotationObject);
|
||||
scene.remove(this._light);
|
||||
scene.remove(this._light.target);
|
||||
if (this._shadowCameraHelper) {
|
||||
scene.remove(this._shadowCameraHelper);
|
||||
}
|
||||
this._isEnabled = false;
|
||||
return true;
|
||||
}
|
||||
updatePreRender(target: gdjs.EffectsTarget): any {}
|
||||
updatePreRender(target: gdjs.EffectsTarget): any {
|
||||
// Apply any update to the camera or shadow map size.
|
||||
this._updateShadowCamera();
|
||||
this._updateShadowMapSize();
|
||||
|
||||
// Avoid shadow acne due to depth buffer precision.
|
||||
const biasMultiplier =
|
||||
this._shadowMapSize < 1024
|
||||
? 2
|
||||
: this._shadowMapSize < 2048
|
||||
? 1.25
|
||||
: 1;
|
||||
this._light.shadow.bias = -this._minimumShadowBias * biasMultiplier;
|
||||
|
||||
// Apply update to the light position and its target.
|
||||
// By doing this, the shadows are "following" the GDevelop camera.
|
||||
if (!target.getRuntimeLayer) {
|
||||
return;
|
||||
}
|
||||
const layer = target.getRuntimeLayer();
|
||||
const x = layer.getCameraX();
|
||||
const y = layer.getCameraY();
|
||||
const z = layer.getCameraZ(layer.getInitialCamera3DFieldOfView());
|
||||
|
||||
const roundedX = Math.floor(x / 100) * 100;
|
||||
const roundedY = Math.floor(y / 100) * 100;
|
||||
const roundedZ = Math.floor(z / 100) * 100;
|
||||
if (this._top === 'Y-') {
|
||||
const posLightX =
|
||||
roundedX +
|
||||
this._distanceFromCamera *
|
||||
Math.cos(gdjs.toRad(-this._rotation + 90)) *
|
||||
Math.cos(gdjs.toRad(this._elevation));
|
||||
const posLightY =
|
||||
roundedY -
|
||||
this._distanceFromCamera *
|
||||
Math.sin(gdjs.toRad(this._elevation));
|
||||
const posLightZ =
|
||||
roundedZ +
|
||||
this._distanceFromCamera *
|
||||
Math.sin(gdjs.toRad(-this._rotation + 90)) *
|
||||
Math.cos(gdjs.toRad(this._elevation));
|
||||
this._light.position.set(posLightX, posLightY, posLightZ);
|
||||
this._light.target.position.set(roundedX, roundedY, roundedZ);
|
||||
} else {
|
||||
const posLightX =
|
||||
roundedX +
|
||||
this._distanceFromCamera *
|
||||
Math.cos(gdjs.toRad(this._rotation)) *
|
||||
Math.cos(gdjs.toRad(this._elevation));
|
||||
const posLightY =
|
||||
roundedY +
|
||||
this._distanceFromCamera *
|
||||
Math.sin(gdjs.toRad(this._rotation)) *
|
||||
Math.cos(gdjs.toRad(this._elevation));
|
||||
const posLightZ =
|
||||
roundedZ +
|
||||
this._distanceFromCamera *
|
||||
Math.sin(gdjs.toRad(this._elevation));
|
||||
|
||||
this._light.position.set(posLightX, posLightY, posLightZ);
|
||||
this._light.target.position.set(roundedX, roundedY, roundedZ);
|
||||
}
|
||||
}
|
||||
updateDoubleParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'intensity') {
|
||||
this.light.intensity = value;
|
||||
this._light.intensity = value;
|
||||
} else if (parameterName === 'elevation') {
|
||||
this.elevation = value;
|
||||
this.updateRotation();
|
||||
this._elevation = value;
|
||||
} else if (parameterName === 'rotation') {
|
||||
this.rotation = value;
|
||||
this.updateRotation();
|
||||
this._rotation = value;
|
||||
} else if (parameterName === 'distanceFromCamera') {
|
||||
this._distanceFromCamera = value;
|
||||
} else if (parameterName === 'frustumSize') {
|
||||
this._frustumSize = value;
|
||||
} else if (parameterName === 'minimumShadowBias') {
|
||||
this._minimumShadowBias = value;
|
||||
}
|
||||
}
|
||||
getDoubleParameter(parameterName: string): number {
|
||||
if (parameterName === 'intensity') {
|
||||
return this.light.intensity;
|
||||
return this._light.intensity;
|
||||
} else if (parameterName === 'elevation') {
|
||||
return this.elevation;
|
||||
return this._elevation;
|
||||
} else if (parameterName === 'rotation') {
|
||||
return this.rotation;
|
||||
return this._rotation;
|
||||
} else if (parameterName === 'distanceFromCamera') {
|
||||
return this._distanceFromCamera;
|
||||
} else if (parameterName === 'frustumSize') {
|
||||
return this._frustumSize;
|
||||
} else if (parameterName === 'minimumShadowBias') {
|
||||
return this._minimumShadowBias;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'color') {
|
||||
this.light.color = new THREE.Color(
|
||||
this._light.color = new THREE.Color(
|
||||
gdjs.rgbOrHexStringToNumber(value)
|
||||
);
|
||||
}
|
||||
if (parameterName === 'top') {
|
||||
this.top = value;
|
||||
this.updateRotation();
|
||||
this._top = value;
|
||||
}
|
||||
if (parameterName === 'shadowQuality') {
|
||||
if (value === 'low' && this._shadowMapSize !== 512) {
|
||||
this._shadowMapSize = 512;
|
||||
this._shadowMapDirty = true;
|
||||
}
|
||||
if (value === 'medium' && this._shadowMapSize !== 1024) {
|
||||
this._shadowMapSize = 1024;
|
||||
this._shadowMapDirty = true;
|
||||
}
|
||||
if (value === 'high' && this._shadowMapSize !== 2048) {
|
||||
this._shadowMapSize = 2048;
|
||||
this._shadowMapDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
updateColorParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'color') {
|
||||
this.light.color.setHex(value);
|
||||
this._light.color.setHex(value);
|
||||
}
|
||||
}
|
||||
getColorParameter(parameterName: string): number {
|
||||
if (parameterName === 'color') {
|
||||
return this.light.color.getHex();
|
||||
return this._light.color.getHex();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||
updateRotation() {
|
||||
if (this.top === 'Z+') {
|
||||
// 0° is a light from the right of the screen.
|
||||
this.rotationObject.rotation.z = gdjs.toRad(this.rotation);
|
||||
this.rotationObject.rotation.y = -gdjs.toRad(this.elevation);
|
||||
} else {
|
||||
// 0° becomes a light from Z+.
|
||||
this.rotationObject.rotation.y = gdjs.toRad(this.rotation - 90);
|
||||
this.rotationObject.rotation.z = -gdjs.toRad(this.elevation);
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {
|
||||
if (parameterName === 'isCastingShadow') {
|
||||
this._light.castShadow = value;
|
||||
}
|
||||
}
|
||||
getNetworkSyncData(): DirectionalLightFilterNetworkSyncData {
|
||||
return {
|
||||
i: this.light.intensity,
|
||||
c: this.light.color.getHex(),
|
||||
e: this.elevation,
|
||||
r: this.rotation,
|
||||
t: this.top,
|
||||
i: this._light.intensity,
|
||||
c: this._light.color.getHex(),
|
||||
e: this._elevation,
|
||||
r: this._rotation,
|
||||
t: this._top,
|
||||
};
|
||||
}
|
||||
updateFromNetworkSyncData(syncData: any): void {
|
||||
this.light.intensity = syncData.i;
|
||||
this.light.color.setHex(syncData.c);
|
||||
this.elevation = syncData.e;
|
||||
this.rotation = syncData.r;
|
||||
this.top = syncData.t;
|
||||
this.updateRotation();
|
||||
this._light.intensity = syncData.i;
|
||||
this._light.color.setHex(syncData.c);
|
||||
this._elevation = syncData.e;
|
||||
this._rotation = syncData.r;
|
||||
this._top = syncData.t;
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
@@ -18,18 +18,15 @@ namespace gdjs {
|
||||
return new gdjs.PixiFiltersTools.EmptyFilter();
|
||||
}
|
||||
return new (class implements gdjs.PixiFiltersTools.Filter {
|
||||
light: THREE.HemisphereLight;
|
||||
rotationObject: THREE.Group;
|
||||
_top: string = 'Z+';
|
||||
_elevation: float = 90;
|
||||
_rotation: float = 0;
|
||||
|
||||
_isEnabled: boolean = false;
|
||||
top: string = 'Y-';
|
||||
elevation: float = 45;
|
||||
rotation: float = 0;
|
||||
_light: THREE.HemisphereLight;
|
||||
|
||||
constructor() {
|
||||
this.light = new THREE.HemisphereLight();
|
||||
this.light.position.set(1, 0, 0);
|
||||
this.rotationObject = new THREE.Group();
|
||||
this.rotationObject.add(this.light);
|
||||
this._light = new THREE.HemisphereLight();
|
||||
this.updateRotation();
|
||||
}
|
||||
|
||||
@@ -54,7 +51,7 @@ namespace gdjs {
|
||||
if (!scene) {
|
||||
return false;
|
||||
}
|
||||
scene.add(this.rotationObject);
|
||||
scene.add(this._light);
|
||||
this._isEnabled = true;
|
||||
return true;
|
||||
}
|
||||
@@ -66,96 +63,106 @@ namespace gdjs {
|
||||
if (!scene) {
|
||||
return false;
|
||||
}
|
||||
scene.remove(this.rotationObject);
|
||||
scene.remove(this._light);
|
||||
this._isEnabled = false;
|
||||
return true;
|
||||
}
|
||||
updatePreRender(target: gdjs.EffectsTarget): any {}
|
||||
updateDoubleParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'intensity') {
|
||||
this.light.intensity = value;
|
||||
this._light.intensity = value;
|
||||
} else if (parameterName === 'elevation') {
|
||||
this.elevation = value;
|
||||
this._elevation = value;
|
||||
this.updateRotation();
|
||||
} else if (parameterName === 'rotation') {
|
||||
this.rotation = value;
|
||||
this._rotation = value;
|
||||
this.updateRotation();
|
||||
}
|
||||
}
|
||||
getDoubleParameter(parameterName: string): number {
|
||||
if (parameterName === 'intensity') {
|
||||
return this.light.intensity;
|
||||
return this._light.intensity;
|
||||
} else if (parameterName === 'elevation') {
|
||||
return this.elevation;
|
||||
return this._elevation;
|
||||
} else if (parameterName === 'rotation') {
|
||||
return this.rotation;
|
||||
return this._rotation;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'skyColor') {
|
||||
this.light.color = new THREE.Color(
|
||||
this._light.color = new THREE.Color(
|
||||
gdjs.rgbOrHexStringToNumber(value)
|
||||
);
|
||||
}
|
||||
if (parameterName === 'groundColor') {
|
||||
this.light.groundColor = new THREE.Color(
|
||||
this._light.groundColor = new THREE.Color(
|
||||
gdjs.rgbOrHexStringToNumber(value)
|
||||
);
|
||||
}
|
||||
if (parameterName === 'top') {
|
||||
this.top = value;
|
||||
this._top = value;
|
||||
this.updateRotation();
|
||||
}
|
||||
}
|
||||
updateColorParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'skyColor') {
|
||||
this.light.color.setHex(value);
|
||||
this._light.color.setHex(value);
|
||||
}
|
||||
if (parameterName === 'groundColor') {
|
||||
this.light.groundColor.setHex(value);
|
||||
this._light.groundColor.setHex(value);
|
||||
}
|
||||
}
|
||||
getColorParameter(parameterName: string): number {
|
||||
if (parameterName === 'skyColor') {
|
||||
return this.light.color.getHex();
|
||||
return this._light.color.getHex();
|
||||
}
|
||||
if (parameterName === 'groundColor') {
|
||||
return this.light.groundColor.getHex();
|
||||
return this._light.groundColor.getHex();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||
updateRotation() {
|
||||
if (this.top === 'Z+') {
|
||||
// 0° is a light from the right of the screen.
|
||||
this.rotationObject.rotation.z = gdjs.toRad(this.rotation);
|
||||
this.rotationObject.rotation.y = -gdjs.toRad(this.elevation);
|
||||
if (this._top === 'Y-') {
|
||||
// `rotation` at 0° becomes a light from Z+.
|
||||
this._light.position.set(
|
||||
Math.cos(gdjs.toRad(-this._rotation + 90)) *
|
||||
Math.cos(gdjs.toRad(this._elevation)),
|
||||
-Math.sin(gdjs.toRad(this._elevation)),
|
||||
Math.sin(gdjs.toRad(-this._rotation + 90)) *
|
||||
Math.cos(gdjs.toRad(this._elevation))
|
||||
);
|
||||
} else {
|
||||
// 0° becomes a light from Z+.
|
||||
this.rotationObject.rotation.y = gdjs.toRad(this.rotation - 90);
|
||||
this.rotationObject.rotation.z = -gdjs.toRad(this.elevation);
|
||||
// `rotation` at 0° is a light from the right of the screen.
|
||||
this._light.position.set(
|
||||
Math.cos(gdjs.toRad(this._rotation)) *
|
||||
Math.cos(gdjs.toRad(this._elevation)),
|
||||
Math.sin(gdjs.toRad(this._rotation)) *
|
||||
Math.cos(gdjs.toRad(this._elevation)),
|
||||
Math.sin(gdjs.toRad(this._elevation))
|
||||
);
|
||||
}
|
||||
}
|
||||
getNetworkSyncData(): HemisphereLightFilterNetworkSyncData {
|
||||
return {
|
||||
i: this.light.intensity,
|
||||
sc: this.light.color.getHex(),
|
||||
gc: this.light.groundColor.getHex(),
|
||||
e: this.elevation,
|
||||
r: this.rotation,
|
||||
t: this.top,
|
||||
i: this._light.intensity,
|
||||
sc: this._light.color.getHex(),
|
||||
gc: this._light.groundColor.getHex(),
|
||||
e: this._elevation,
|
||||
r: this._rotation,
|
||||
t: this._top,
|
||||
};
|
||||
}
|
||||
updateFromNetworkSyncData(
|
||||
syncData: HemisphereLightFilterNetworkSyncData
|
||||
): void {
|
||||
this.light.intensity = syncData.i;
|
||||
this.light.color.setHex(syncData.sc);
|
||||
this.light.groundColor.setHex(syncData.gc);
|
||||
this.elevation = syncData.e;
|
||||
this.rotation = syncData.r;
|
||||
this.top = syncData.t;
|
||||
this._light.intensity = syncData.i;
|
||||
this._light.color.setHex(syncData.sc);
|
||||
this._light.groundColor.setHex(syncData.gc);
|
||||
this._elevation = syncData.e;
|
||||
this._rotation = syncData.r;
|
||||
this._top = syncData.t;
|
||||
this.updateRotation();
|
||||
}
|
||||
})();
|
||||
|
@@ -162,7 +162,12 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.useStandardParameters(
|
||||
'number',
|
||||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||||
_('Angle (in degrees)')
|
||||
)
|
||||
)
|
||||
.setFunctionName('setRotationX')
|
||||
.setGetter('getRotationX');
|
||||
|
||||
@@ -178,7 +183,12 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.useStandardParameters(
|
||||
'number',
|
||||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||||
_('Angle (in degrees)')
|
||||
)
|
||||
)
|
||||
.setFunctionName('setRotationY')
|
||||
.setGetter('getRotationY');
|
||||
|
||||
@@ -196,7 +206,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.addParameter('number', _('Rotation angle'), '', false)
|
||||
.addParameter('number', _('Angle to add (in degrees)'), '', false)
|
||||
.markAsAdvanced()
|
||||
.setFunctionName('turnAroundX');
|
||||
|
||||
@@ -214,7 +224,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.addParameter('number', _('Rotation angle'), '', false)
|
||||
.addParameter('number', _('Angle to add (in degrees)'), '', false)
|
||||
.markAsAdvanced()
|
||||
.setFunctionName('turnAroundY');
|
||||
|
||||
@@ -232,7 +242,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.addParameter('number', _('Rotation angle'), '', false)
|
||||
.addParameter('number', _('Angle to add (in degrees)'), '', false)
|
||||
.markAsAdvanced()
|
||||
.setFunctionName('turnAroundZ');
|
||||
}
|
||||
@@ -242,7 +252,7 @@ module.exports = {
|
||||
.addObject(
|
||||
'Model3DObject',
|
||||
_('3D Model'),
|
||||
_('An animated 3D model.'),
|
||||
_('An animated 3D model, useful for most elements of a 3D game.'),
|
||||
'JsPlatform/Extensions/3d_model.svg',
|
||||
new gd.Model3DObjectConfiguration()
|
||||
)
|
||||
@@ -594,7 +604,12 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.useStandardParameters(
|
||||
'number',
|
||||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||||
_('Angle (in degrees)')
|
||||
)
|
||||
)
|
||||
.setHidden()
|
||||
.setFunctionName('setRotationX')
|
||||
.setGetter('getRotationX');
|
||||
@@ -611,7 +626,12 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.useStandardParameters(
|
||||
'number',
|
||||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||||
_('Angle (in degrees)')
|
||||
)
|
||||
)
|
||||
.setHidden()
|
||||
.setFunctionName('setRotationY')
|
||||
.setGetter('getRotationY');
|
||||
@@ -630,7 +650,7 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('number', _('Rotation angle'), '', false)
|
||||
.addParameter('number', _('Angle to add (in degrees)'), '', false)
|
||||
.markAsAdvanced()
|
||||
.setHidden()
|
||||
.setFunctionName('turnAroundX');
|
||||
@@ -649,7 +669,7 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('number', _('Rotation angle'), '', false)
|
||||
.addParameter('number', _('Angle to add (in degrees)'), '', false)
|
||||
.markAsAdvanced()
|
||||
.setHidden()
|
||||
.setFunctionName('turnAroundY');
|
||||
@@ -668,7 +688,7 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('number', _('Rotation angle'), '', false)
|
||||
.addParameter('number', _('Angle to add (in degrees)'), '', false)
|
||||
.markAsAdvanced()
|
||||
.setHidden()
|
||||
.setFunctionName('turnAroundZ');
|
||||
@@ -859,7 +879,9 @@ module.exports = {
|
||||
propertyName === 'rightFaceResourceRepeat' ||
|
||||
propertyName === 'topFaceResourceRepeat' ||
|
||||
propertyName === 'bottomFaceResourceRepeat' ||
|
||||
propertyName === 'enableTextureTransparency'
|
||||
propertyName === 'enableTextureTransparency' ||
|
||||
propertyName === 'isCastingShadow' ||
|
||||
propertyName === 'isReceivingShadow'
|
||||
) {
|
||||
objectContent[propertyName] = newValue === '1';
|
||||
return true;
|
||||
@@ -887,8 +909,8 @@ module.exports = {
|
||||
.getOrCreate('facesOrientation')
|
||||
.setValue(objectContent.facesOrientation || 'Y')
|
||||
.setType('choice')
|
||||
.addExtraInfo('Y')
|
||||
.addExtraInfo('Z')
|
||||
.addChoice('Y', 'Y')
|
||||
.addChoice('Z', 'Z')
|
||||
.setLabel(_('Faces orientation'))
|
||||
.setDescription(
|
||||
_(
|
||||
@@ -948,8 +970,8 @@ module.exports = {
|
||||
.getOrCreate('backFaceUpThroughWhichAxisRotation')
|
||||
.setValue(objectContent.backFaceUpThroughWhichAxisRotation || 'X')
|
||||
.setType('choice')
|
||||
.addExtraInfo('X')
|
||||
.addExtraInfo('Y')
|
||||
.addChoice('X', 'X')
|
||||
.addChoice('Y', 'Y')
|
||||
.setLabel(_('Back face orientation'))
|
||||
.setDescription(
|
||||
_(
|
||||
@@ -1083,11 +1105,29 @@ module.exports = {
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('materialType')
|
||||
.setValue(objectContent.materialType || 'Basic')
|
||||
.setValue(objectContent.materialType || 'StandardWithoutMetalness')
|
||||
.setType('choice')
|
||||
.addExtraInfo('Basic')
|
||||
.addExtraInfo('StandardWithoutMetalness')
|
||||
.setLabel(_('Material type'));
|
||||
.addChoice('Basic', _('Basic (no lighting, no shadows)'))
|
||||
.addChoice(
|
||||
'StandardWithoutMetalness',
|
||||
_('Standard (without metalness)')
|
||||
)
|
||||
.setLabel(_('Material type'))
|
||||
.setGroup(_('Lighting'));
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('isCastingShadow')
|
||||
.setValue(objectContent.isCastingShadow ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Shadow casting'))
|
||||
.setGroup(_('Lighting'));
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('isReceivingShadow')
|
||||
.setValue(objectContent.isReceivingShadow ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Shadow receiving'))
|
||||
.setGroup(_('Lighting'));
|
||||
|
||||
return objectProperties;
|
||||
};
|
||||
@@ -1105,7 +1145,7 @@ module.exports = {
|
||||
topFaceResourceName: '',
|
||||
bottomFaceResourceName: '',
|
||||
frontFaceVisible: true,
|
||||
backFaceVisible: false,
|
||||
backFaceVisible: true,
|
||||
leftFaceVisible: true,
|
||||
rightFaceVisible: true,
|
||||
topFaceVisible: true,
|
||||
@@ -1116,8 +1156,10 @@ module.exports = {
|
||||
rightFaceResourceRepeat: false,
|
||||
topFaceResourceRepeat: false,
|
||||
bottomFaceResourceRepeat: false,
|
||||
materialType: 'Basic',
|
||||
materialType: 'StandardWithoutMetalness',
|
||||
tint: '255;255;255',
|
||||
isCastingShadow: true,
|
||||
isReceivingShadow: true,
|
||||
};
|
||||
|
||||
Cube3DObject.updateInitialInstanceProperty = function (
|
||||
@@ -1471,7 +1513,12 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.useStandardParameters(
|
||||
'number',
|
||||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||||
_('Angle (in degrees)')
|
||||
)
|
||||
)
|
||||
.setFunctionName('setRotationX')
|
||||
.setHidden()
|
||||
.setGetter('getRotationX');
|
||||
@@ -1488,7 +1535,12 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.useStandardParameters(
|
||||
'number',
|
||||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||||
_('Angle (in degrees)')
|
||||
)
|
||||
)
|
||||
.setFunctionName('setRotationY')
|
||||
.setHidden()
|
||||
.setGetter('getRotationY');
|
||||
@@ -1894,11 +1946,11 @@ module.exports = {
|
||||
.setType('number');
|
||||
properties
|
||||
.getOrCreate('top')
|
||||
.setValue('Y-')
|
||||
.setValue('Z+')
|
||||
.setLabel(_('3D world top'))
|
||||
.setType('choice')
|
||||
.addExtraInfo('Y-')
|
||||
.addExtraInfo('Z+')
|
||||
.addExtraInfo('Y-')
|
||||
.setGroup(_('Orientation'));
|
||||
properties
|
||||
.getOrCreate('elevation')
|
||||
@@ -1913,6 +1965,47 @@ module.exports = {
|
||||
.setLabel(_('Rotation (in degrees)'))
|
||||
.setType('number')
|
||||
.setGroup(_('Orientation'));
|
||||
properties
|
||||
.getOrCreate('isCastingShadow')
|
||||
.setValue('false')
|
||||
.setLabel(_('Shadow casting'))
|
||||
.setType('boolean')
|
||||
.setGroup(_('Shadows'));
|
||||
properties
|
||||
.getOrCreate('shadowQuality')
|
||||
.setValue('medium')
|
||||
.addChoice('low', _('Low quality'))
|
||||
.addChoice('medium', _('Medium quality'))
|
||||
.addChoice('high', _('High quality'))
|
||||
.setLabel(_('Shadow quality'))
|
||||
.setType('choice')
|
||||
.setGroup(_('Shadows'));
|
||||
properties
|
||||
.getOrCreate('minimumShadowBias')
|
||||
.setValue('0')
|
||||
.setLabel(_('Shadow bias'))
|
||||
.setDescription(
|
||||
_(
|
||||
'Use this to avoid "shadow acne" due to depth buffer precision. Choose a value small enough like 0.001 to avoid creating distance between shadows and objects but not too small to avoid shadow glitches on low/medium quality. This value is used for high quality, and multiplied by 1.25 for medium quality and 2 for low quality.'
|
||||
)
|
||||
)
|
||||
.setType('number')
|
||||
.setGroup(_('Shadows'))
|
||||
.setAdvanced(true);
|
||||
properties
|
||||
.getOrCreate('frustumSize')
|
||||
.setValue('4000')
|
||||
.setLabel(_('Shadow frustum size'))
|
||||
.setType('number')
|
||||
.setGroup(_('Shadows'))
|
||||
.setAdvanced(true);
|
||||
properties
|
||||
.getOrCreate('distanceFromCamera')
|
||||
.setValue('1500')
|
||||
.setLabel(_("Distance from layer's camera"))
|
||||
.setType('number')
|
||||
.setGroup(_('Shadows'))
|
||||
.setAdvanced(true);
|
||||
}
|
||||
{
|
||||
const effect = extension
|
||||
@@ -1944,11 +2037,11 @@ module.exports = {
|
||||
.setType('number');
|
||||
properties
|
||||
.getOrCreate('top')
|
||||
.setValue('Y-')
|
||||
.setValue('Z+')
|
||||
.setLabel(_('3D world top'))
|
||||
.setType('choice')
|
||||
.addExtraInfo('Y-')
|
||||
.addExtraInfo('Z+')
|
||||
.addExtraInfo('Y-')
|
||||
.setGroup(_('Orientation'));
|
||||
properties
|
||||
.getOrCreate('elevation')
|
||||
@@ -3210,6 +3303,8 @@ module.exports = {
|
||||
|
||||
this._threeObject = new THREE.Group();
|
||||
this._threeObject.rotation.order = 'ZYX';
|
||||
this._threeObject.castShadow = true;
|
||||
this._threeObject.receiveShadow = true;
|
||||
this._threeGroup.add(this._threeObject);
|
||||
}
|
||||
|
||||
|
@@ -23,7 +23,7 @@ Model3DObjectConfiguration::Model3DObjectConfiguration()
|
||||
: width(100), height(100), depth(100), rotationX(0), rotationY(0),
|
||||
rotationZ(0), modelResourceName(""), materialType("StandardWithoutMetalness"),
|
||||
originLocation("ModelOrigin"), centerLocation("ModelOrigin"),
|
||||
keepAspectRatio(true), crossfadeDuration(0.1f) {}
|
||||
keepAspectRatio(true), crossfadeDuration(0.1f), isCastingShadow(true), isReceivingShadow(true) {}
|
||||
|
||||
bool Model3DObjectConfiguration::UpdateProperty(const gd::String &propertyName,
|
||||
const gd::String &newValue) {
|
||||
@@ -75,6 +75,16 @@ bool Model3DObjectConfiguration::UpdateProperty(const gd::String &propertyName,
|
||||
crossfadeDuration = newValue.To<double>();
|
||||
return true;
|
||||
}
|
||||
if(propertyName == "isCastingShadow")
|
||||
{
|
||||
isCastingShadow = newValue == "1";
|
||||
return true;
|
||||
}
|
||||
if(propertyName == "isReceivingShadow")
|
||||
{
|
||||
isReceivingShadow = newValue == "1";
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -143,19 +153,20 @@ Model3DObjectConfiguration::GetProperties() const {
|
||||
objectProperties["materialType"]
|
||||
.SetValue(materialType.empty() ? "Basic" : materialType)
|
||||
.SetType("choice")
|
||||
.AddExtraInfo("Basic")
|
||||
.AddExtraInfo("StandardWithoutMetalness")
|
||||
.AddExtraInfo("KeepOriginal")
|
||||
.SetLabel(_("Material"));
|
||||
.AddChoice("Basic", _("Basic (no lighting, no shadows)"))
|
||||
.AddChoice("StandardWithoutMetalness", _("Standard (without metalness)"))
|
||||
.AddChoice("KeepOriginal", _("Keep original"))
|
||||
.SetLabel(_("Material"))
|
||||
.SetGroup(_("Lighting"));
|
||||
|
||||
objectProperties["originLocation"]
|
||||
.SetValue(originLocation.empty() ? "TopLeft" : originLocation)
|
||||
.SetType("choice")
|
||||
.AddExtraInfo("ModelOrigin")
|
||||
.AddExtraInfo("TopLeft")
|
||||
.AddExtraInfo("ObjectCenter")
|
||||
.AddExtraInfo("BottomCenterZ")
|
||||
.AddExtraInfo("BottomCenterY")
|
||||
.AddChoice("ModelOrigin", _("Model origin"))
|
||||
.AddChoice("TopLeft", _("Top left"))
|
||||
.AddChoice("ObjectCenter", _("Object center"))
|
||||
.AddChoice("BottomCenterZ", _("Bottom center (Z)"))
|
||||
.AddChoice("BottomCenterY", _("Bottom center (Y)"))
|
||||
.SetLabel(_("Origin point"))
|
||||
.SetGroup(_("Points"))
|
||||
.SetAdvanced(true);
|
||||
@@ -163,10 +174,10 @@ Model3DObjectConfiguration::GetProperties() const {
|
||||
objectProperties["centerLocation"]
|
||||
.SetValue(centerLocation.empty() ? "ObjectCenter" : centerLocation)
|
||||
.SetType("choice")
|
||||
.AddExtraInfo("ModelOrigin")
|
||||
.AddExtraInfo("ObjectCenter")
|
||||
.AddExtraInfo("BottomCenterZ")
|
||||
.AddExtraInfo("BottomCenterY")
|
||||
.AddChoice("ModelOrigin", _("Model origin"))
|
||||
.AddChoice("ObjectCenter", _("Object center"))
|
||||
.AddChoice("BottomCenterZ", _("Bottom center (Z)"))
|
||||
.AddChoice("BottomCenterY", _("Bottom center (Y)"))
|
||||
.SetLabel(_("Center point"))
|
||||
.SetGroup(_("Points"))
|
||||
.SetAdvanced(true);
|
||||
@@ -178,6 +189,20 @@ Model3DObjectConfiguration::GetProperties() const {
|
||||
.SetGroup(_("Animations"))
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetSecond());
|
||||
|
||||
objectProperties["isCastingShadow"]
|
||||
.SetValue(isCastingShadow ? "true" : "false")
|
||||
.SetType("boolean")
|
||||
.SetLabel(_("Shadow casting"))
|
||||
.SetGroup(_("Lighting"));
|
||||
|
||||
objectProperties["isReceivingShadow"]
|
||||
.SetValue(isReceivingShadow ? "true" : "false")
|
||||
.SetType("boolean")
|
||||
.SetLabel(_("Shadow receiving"))
|
||||
.SetGroup(_("Lighting"));
|
||||
|
||||
|
||||
|
||||
return objectProperties;
|
||||
}
|
||||
|
||||
@@ -210,6 +235,8 @@ void Model3DObjectConfiguration::DoUnserializeFrom(
|
||||
centerLocation = content.GetStringAttribute("centerLocation");
|
||||
keepAspectRatio = content.GetBoolAttribute("keepAspectRatio");
|
||||
crossfadeDuration = content.GetDoubleAttribute("crossfadeDuration");
|
||||
isCastingShadow = content.GetBoolAttribute("isCastingShadow");
|
||||
isReceivingShadow = content.GetBoolAttribute("isReceivingShadow");
|
||||
|
||||
RemoveAllAnimations();
|
||||
auto &animationsElement = content.GetChild("animations");
|
||||
@@ -239,6 +266,8 @@ void Model3DObjectConfiguration::DoSerializeTo(
|
||||
content.SetAttribute("centerLocation", centerLocation);
|
||||
content.SetAttribute("keepAspectRatio", keepAspectRatio);
|
||||
content.SetAttribute("crossfadeDuration", crossfadeDuration);
|
||||
content.SetAttribute("isCastingShadow", isCastingShadow);
|
||||
content.SetAttribute("isReceivingShadow", isReceivingShadow);
|
||||
|
||||
auto &animationsElement = content.AddChild("animations");
|
||||
animationsElement.ConsiderAsArrayOf("animation");
|
||||
|
@@ -160,6 +160,8 @@ public:
|
||||
const gd::String& GetCenterLocation() const { return centerLocation; };
|
||||
|
||||
bool shouldKeepAspectRatio() const { return keepAspectRatio; };
|
||||
bool shouldCastShadow() const { return isCastingShadow; };
|
||||
bool shouldReceiveShadow() const { return isReceivingShadow; };
|
||||
///@}
|
||||
|
||||
protected:
|
||||
@@ -182,6 +184,8 @@ private:
|
||||
gd::String centerLocation;
|
||||
|
||||
bool keepAspectRatio;
|
||||
bool isCastingShadow;
|
||||
bool isReceivingShadow;
|
||||
|
||||
std::vector<Model3DAnimation> animations;
|
||||
static Model3DAnimation badAnimation; //< Bad animation when an out of bound
|
||||
|
@@ -38,6 +38,8 @@ namespace gdjs {
|
||||
| 'BottomCenterY';
|
||||
animations: Model3DAnimation[];
|
||||
crossfadeDuration: float;
|
||||
isCastingShadow: boolean;
|
||||
isReceivingShadow: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -101,6 +103,8 @@ namespace gdjs {
|
||||
_animationSpeedScale: float = 1;
|
||||
_animationPaused: boolean = false;
|
||||
_crossfadeDuration: float = 0;
|
||||
_isCastingShadow: boolean = true;
|
||||
_isReceivingShadow: boolean = true;
|
||||
|
||||
constructor(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
@@ -123,6 +127,8 @@ namespace gdjs {
|
||||
objectData.content.materialType
|
||||
);
|
||||
|
||||
this.setIsCastingShadow(objectData.content.isCastingShadow);
|
||||
this.setIsReceivingShadow(objectData.content.isReceivingShadow);
|
||||
this.onModelChanged(objectData);
|
||||
|
||||
this._crossfadeDuration = objectData.content.crossfadeDuration || 0;
|
||||
@@ -195,6 +201,18 @@ namespace gdjs {
|
||||
newObjectData.content.centerLocation
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.isCastingShadow !==
|
||||
newObjectData.content.isCastingShadow
|
||||
) {
|
||||
this.setIsCastingShadow(newObjectData.content.isCastingShadow);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.isReceivingShadow !==
|
||||
newObjectData.content.isReceivingShadow
|
||||
) {
|
||||
this.setIsReceivingShadow(newObjectData.content.isReceivingShadow);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -358,6 +376,16 @@ namespace gdjs {
|
||||
return this._renderer.hasAnimationEnded();
|
||||
}
|
||||
|
||||
setIsCastingShadow(value: boolean): void {
|
||||
this._isCastingShadow = value;
|
||||
this._renderer._updateShadow();
|
||||
}
|
||||
|
||||
setIsReceivingShadow(value: boolean): void {
|
||||
this._isReceivingShadow = value;
|
||||
this._renderer._updateShadow();
|
||||
}
|
||||
|
||||
setCrossfadeDuration(duration: number): void {
|
||||
if (this._crossfadeDuration === duration) return;
|
||||
this._crossfadeDuration = duration;
|
||||
|
@@ -286,6 +286,7 @@ namespace gdjs {
|
||||
this.get3DRendererObject().remove(this._threeObject);
|
||||
this.get3DRendererObject().add(threeObject);
|
||||
this._threeObject = threeObject;
|
||||
this._updateShadow();
|
||||
|
||||
// Start the current animation on the new 3D object.
|
||||
this._animationMixer = new THREE.AnimationMixer(root);
|
||||
@@ -323,6 +324,13 @@ namespace gdjs {
|
||||
return this._originalModel.animations[animationIndex].name;
|
||||
}
|
||||
|
||||
_updateShadow() {
|
||||
this._threeObject.traverse((child) => {
|
||||
child.castShadow = this._model3DRuntimeObject._isCastingShadow;
|
||||
child.receiveShadow = this._model3DRuntimeObject._isReceivingShadow;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if animation has ended.
|
||||
* The animation had ended if:
|
||||
|
@@ -75,9 +75,9 @@ module.exports = {
|
||||
.getOrCreate('align')
|
||||
.setValue(objectContent.align)
|
||||
.setType('choice')
|
||||
.addExtraInfo('left')
|
||||
.addExtraInfo('center')
|
||||
.addExtraInfo('right')
|
||||
.addChoice('left', _('Left'))
|
||||
.addChoice('center', _('Center'))
|
||||
.addChoice('right', _('Right'))
|
||||
.setLabel(_('Base alignment'))
|
||||
.setGroup(_('Appearance'));
|
||||
|
||||
@@ -88,9 +88,9 @@ module.exports = {
|
||||
.getOrCreate('verticalTextAlignment')
|
||||
.setValue(objectContent.verticalTextAlignment)
|
||||
.setType('choice')
|
||||
.addExtraInfo('top')
|
||||
.addExtraInfo('center')
|
||||
.addExtraInfo('bottom')
|
||||
.addChoice('top', _('Top'))
|
||||
.addChoice('center', _('Center'))
|
||||
.addChoice('bottom', _('Bottom'))
|
||||
.setLabel(_('Vertical alignment'))
|
||||
.setGroup(_('Appearance'));
|
||||
|
||||
@@ -508,7 +508,7 @@ module.exports = {
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader,
|
||||
propertyOverridings
|
||||
getPropertyOverridings
|
||||
) {
|
||||
super(
|
||||
project,
|
||||
@@ -516,7 +516,7 @@ module.exports = {
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader,
|
||||
propertyOverridings
|
||||
getPropertyOverridings
|
||||
);
|
||||
|
||||
const bbTextStyles = {
|
||||
@@ -555,9 +555,11 @@ module.exports = {
|
||||
gd.ObjectJsImplementation
|
||||
);
|
||||
|
||||
const rawText = this._propertyOverridings.has('Text')
|
||||
? this._propertyOverridings.get('Text')
|
||||
: object.content.text;
|
||||
const propertyOverridings = this.getPropertyOverridings();
|
||||
const rawText =
|
||||
propertyOverridings && propertyOverridings.has('Text')
|
||||
? propertyOverridings.get('Text')
|
||||
: object.content.text;
|
||||
if (rawText !== this._pixiObject.text) {
|
||||
this._pixiObject.text = rawText;
|
||||
}
|
||||
|
@@ -383,6 +383,10 @@ namespace gdjs {
|
||||
return this._renderer.getHeight();
|
||||
}
|
||||
|
||||
override setWidth(width: float): void {
|
||||
this.setWrappingWidth(width);
|
||||
}
|
||||
|
||||
override getDrawableY(): float {
|
||||
return (
|
||||
this.getY() -
|
||||
|
@@ -61,9 +61,9 @@ module.exports = {
|
||||
.getOrCreate('align')
|
||||
.setValue(objectContent.align)
|
||||
.setType('choice')
|
||||
.addExtraInfo('left')
|
||||
.addExtraInfo('center')
|
||||
.addExtraInfo('right')
|
||||
.addChoice('left', _('Left'))
|
||||
.addChoice('center', _('Center'))
|
||||
.addChoice('right', _('Right'))
|
||||
.setLabel(_('Alignment'))
|
||||
.setGroup(_('Appearance'));
|
||||
|
||||
@@ -74,9 +74,9 @@ module.exports = {
|
||||
.getOrCreate('verticalTextAlignment')
|
||||
.setValue(objectContent.verticalTextAlignment)
|
||||
.setType('choice')
|
||||
.addExtraInfo('top')
|
||||
.addExtraInfo('center')
|
||||
.addExtraInfo('bottom')
|
||||
.addChoice('top', _('Top'))
|
||||
.addChoice('center', _('Center'))
|
||||
.addChoice('bottom', _('Bottom'))
|
||||
.setLabel(_('Vertical alignment'))
|
||||
.setGroup(_('Appearance'));
|
||||
|
||||
@@ -631,7 +631,7 @@ module.exports = {
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader,
|
||||
propertyOverridings
|
||||
getPropertyOverridings
|
||||
) {
|
||||
super(
|
||||
project,
|
||||
@@ -639,7 +639,7 @@ module.exports = {
|
||||
associatedObjectConfiguration,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader,
|
||||
propertyOverridings
|
||||
getPropertyOverridings
|
||||
);
|
||||
|
||||
// We'll track changes of the font to trigger the loading of the new font.
|
||||
@@ -665,9 +665,11 @@ module.exports = {
|
||||
|
||||
// Update the rendered text properties (note: Pixi is only
|
||||
// applying changes if there were changed).
|
||||
this._pixiObject.text = this._propertyOverridings.has('Text')
|
||||
? this._propertyOverridings.get('Text')
|
||||
: object.content.text;
|
||||
const propertyOverridings = this.getPropertyOverridings();
|
||||
this._pixiObject.text =
|
||||
propertyOverridings && propertyOverridings.has('Text')
|
||||
? propertyOverridings.get('Text')
|
||||
: object.content.text;
|
||||
|
||||
const align = object.content.align;
|
||||
this._pixiObject.align = align;
|
||||
|
@@ -426,6 +426,10 @@ namespace gdjs {
|
||||
return this._renderer.getHeight();
|
||||
}
|
||||
|
||||
override setWidth(width: float): void {
|
||||
this.setWrappingWidth(width);
|
||||
}
|
||||
|
||||
override getDrawableY(): float {
|
||||
return (
|
||||
this.getY() -
|
||||
|
@@ -21,7 +21,9 @@ module.exports = {
|
||||
.setExtensionInformation(
|
||||
'FileSystem',
|
||||
_('File system'),
|
||||
_('Access the filesystem of the operating system.'),
|
||||
_(
|
||||
'Access the filesystem of the operating system - only works on native, desktop games exported to Windows, Linux or macOS.'
|
||||
),
|
||||
'Matthias Meike',
|
||||
'Open source (MIT License)'
|
||||
)
|
||||
|
@@ -5,23 +5,25 @@ Copyright (c) 2008-2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void DeclareInventoryExtension(gd::PlatformExtension& extension) {
|
||||
extension.SetExtensionInformation(
|
||||
"Inventory",
|
||||
_("Inventories"),
|
||||
_("Provides actions and conditions to add an inventory to your game, "
|
||||
"with items in memory."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
extension
|
||||
.SetExtensionInformation(
|
||||
"Inventory",
|
||||
_("Inventories"),
|
||||
_("Actions and conditions to store named inventories in memory, "
|
||||
"with items (indexed by their name), a count for each of them, "
|
||||
"a maximum count and an equipped state. Can be loaded/saved "
|
||||
"from/to a GDevelop variable."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/inventory")
|
||||
.SetCategory("Game mechanic");
|
||||
extension
|
||||
.AddInstructionOrExpressionGroupMetadata(_("Inventories"))
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Inventories"))
|
||||
.SetIcon("CppPlatform/Extensions/Inventoryicon.png");
|
||||
|
||||
extension
|
||||
@@ -164,14 +166,15 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
|
||||
.SetFunctionName("InventoryTools::IsEquipped");
|
||||
|
||||
extension
|
||||
.AddAction("SerializeToVariable",
|
||||
_("Save an inventory in a scene variable"),
|
||||
_("Save all the items of the inventory in a scene variable, so that "
|
||||
"it can be restored later."),
|
||||
_("Save inventory _PARAM1_ in variable _PARAM2_"),
|
||||
_("Variables"),
|
||||
"CppPlatform/Extensions/Inventoryicon.png",
|
||||
"CppPlatform/Extensions/Inventoryicon.png")
|
||||
.AddAction(
|
||||
"SerializeToVariable",
|
||||
_("Save an inventory in a scene variable"),
|
||||
_("Save all the items of the inventory in a scene variable, so that "
|
||||
"it can be restored later."),
|
||||
_("Save inventory _PARAM1_ in variable _PARAM2_"),
|
||||
_("Variables"),
|
||||
"CppPlatform/Extensions/Inventoryicon.png",
|
||||
"CppPlatform/Extensions/Inventoryicon.png")
|
||||
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("string", _("Inventory name"))
|
||||
@@ -204,13 +207,14 @@ void DeclareInventoryExtension(gd::PlatformExtension& extension) {
|
||||
.SetFunctionName("InventoryTools::Count");
|
||||
|
||||
extension
|
||||
.AddExpression("Maximum",
|
||||
_("Item maximum"),
|
||||
_("Get the maximum of an item in the inventory, or 0 if it is unlimited"),
|
||||
"",
|
||||
"CppPlatform/Extensions/Inventoryicon.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("string", _("Inventory name"))
|
||||
.AddParameter("string", _("Item name"))
|
||||
.SetFunctionName("InventoryTools::Maximum");
|
||||
.AddExpression("Maximum",
|
||||
_("Item maximum"),
|
||||
_("Get the maximum of an item in the inventory, or 0 if "
|
||||
"it is unlimited"),
|
||||
"",
|
||||
"CppPlatform/Extensions/Inventoryicon.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("string", _("Inventory name"))
|
||||
.AddParameter("string", _("Item name"))
|
||||
.SetFunctionName("InventoryTools::Maximum");
|
||||
}
|
||||
|
9
Extensions/JsExtensionTypes.d.ts
vendored
9
Extensions/JsExtensionTypes.d.ts
vendored
@@ -27,7 +27,7 @@ class RenderedInstance {
|
||||
associatedObjectConfiguration: gdObjectConfiguration,
|
||||
pixiContainer: PIXI.Container,
|
||||
pixiResourcesLoader: Class<PixiResourcesLoader>,
|
||||
propertyOverridings: Map<string, string> = new Map<string, string>()
|
||||
getPropertyOverridings: (() => Map<string, string>) | null = null
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -80,6 +80,8 @@ class RenderedInstance {
|
||||
getDefaultHeight(): number;
|
||||
|
||||
getDefaultDepth(): number;
|
||||
|
||||
getPropertyOverridings(): Map<string, string> | null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,7 +109,8 @@ class Rendered3DInstance {
|
||||
associatedObjectConfiguration: gdObjectConfiguration,
|
||||
pixiContainer: PIXI.Container,
|
||||
threeGroup: THREE.Group,
|
||||
pixiResourcesLoader: Class<PixiResourcesLoader>
|
||||
pixiResourcesLoader: Class<PixiResourcesLoader>,
|
||||
getPropertyOverridings: (() => Map<string, string>) | null = null
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -174,6 +177,8 @@ class Rendered3DInstance {
|
||||
* Return the depth of the instance when the instance doesn't have a custom size.
|
||||
*/
|
||||
getDefaultDepth(): number;
|
||||
|
||||
getPropertyOverridings(): Map<string, string> | null;
|
||||
}
|
||||
|
||||
declare type ObjectsRenderingService = {
|
||||
|
@@ -21,7 +21,9 @@ module.exports = {
|
||||
.setExtensionInformation(
|
||||
'Leaderboards',
|
||||
_('Leaderboards'),
|
||||
_('Allow your game to send scores to your leaderboards.'),
|
||||
_(
|
||||
'Allow your game to send scores to your leaderboards (anonymously or from the logged-in player) or display existing leaderboards to the player.'
|
||||
),
|
||||
'Florian Rival',
|
||||
'Open source (MIT License)'
|
||||
)
|
||||
@@ -30,6 +32,12 @@ module.exports = {
|
||||
.addInstructionOrExpressionGroupMetadata(_('Leaderboards'))
|
||||
.setIcon('JsPlatform/Extensions/leaderboard.svg');
|
||||
|
||||
extension
|
||||
.addDependency()
|
||||
.setName('Safari View Controller Cordova plugin')
|
||||
.setDependencyType('cordova')
|
||||
.setExportName('@gdevelop/cordova-plugin-safariviewcontroller');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SavePlayerScore',
|
||||
|
@@ -22,7 +22,7 @@ module.exports = {
|
||||
'Lighting',
|
||||
_('Lights'),
|
||||
|
||||
'This provides a light object, and a behavior to mark other objects as being obstacles for the lights. This is a great way to create a special atmosphere to your game, along with effects, make it more realistic or to create gameplays based on lights.',
|
||||
'This provides a 2D light object, and a behavior to mark other 2D objects as being obstacles for the lights. This is a great way to create a special atmosphere to your game, along with effects, make it more realistic or to create gameplays based on lights.',
|
||||
'Harsimran Virk',
|
||||
'MIT'
|
||||
)
|
||||
@@ -51,7 +51,7 @@ module.exports = {
|
||||
_('Light Obstacle Behavior'),
|
||||
'LightObstacleBehavior',
|
||||
_(
|
||||
'Flag objects as being obstacles to light. The light emitted by light objects will be stopped by the object.'
|
||||
'Flag objects as being obstacles to 2D lights. The light emitted by light objects will be stopped by the object. This does not work on 3D objects and 3D games.'
|
||||
),
|
||||
'',
|
||||
'CppPlatform/Extensions/lightObstacleIcon32.png',
|
||||
@@ -164,7 +164,7 @@ module.exports = {
|
||||
'LightObject',
|
||||
_('Light'),
|
||||
_(
|
||||
'Displays a light on the scene, with a customizable radius and color. Add then the Light Obstacle behavior to the objects that must act as obstacle to the lights.'
|
||||
'Displays a 2D light on the scene, with a customizable radius and color. Add then the Light Obstacle behavior to the objects that must act as obstacle to the lights.'
|
||||
),
|
||||
'CppPlatform/Extensions/lightIcon32.png',
|
||||
lightObject
|
||||
|
@@ -239,7 +239,7 @@ namespace gdjs {
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
objectsLists: Hashtable<gdjs.RuntimeObject[]>,
|
||||
obj: gdjs.RuntimeObject | null,
|
||||
eventsFunctionContext: EventsFunctionContext | undefined
|
||||
eventsFunctionContext: EventsFunctionContext | null | undefined
|
||||
) {
|
||||
if (obj === null) {
|
||||
return false;
|
||||
|
@@ -21,7 +21,9 @@ module.exports = {
|
||||
.setExtensionInformation(
|
||||
'Multiplayer',
|
||||
_('Multiplayer'),
|
||||
_('Allow players to connect to lobbies and play together.'),
|
||||
_(
|
||||
'This allows players to join online lobbies and synchronize gameplay across devices without needing to manage servers or networking.\n\nUse the "Open game lobbies" action to let players join a game, and use conditions like "Lobby game has just started" to begin gameplay. Add the "Multiplayer object" behavior to game objects that should be synchronized, and assign or change their ownership using player numbers. Variables and game state (like scenes, scores, or timers) are automatically synced by the host, with options to change ownership or disable sync when needed. Common multiplayer logic —like handling joins/leaves, collisions, and host migration— is supported out-of-the-box for up to 8 players per game.'
|
||||
),
|
||||
'Florian Rival',
|
||||
'Open source (MIT License)'
|
||||
)
|
||||
@@ -31,6 +33,79 @@ module.exports = {
|
||||
.addInstructionOrExpressionGroupMetadata(_('Multiplayer'))
|
||||
.setIcon('JsPlatform/Extensions/multiplayer.svg');
|
||||
|
||||
extension
|
||||
.addDependency()
|
||||
.setName('Safari View Controller Cordova plugin')
|
||||
.setDependencyType('cordova')
|
||||
.setExportName('@gdevelop/cordova-plugin-safariviewcontroller');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'CurrentLobbyID',
|
||||
_('Current lobby ID'),
|
||||
_('Returns current lobby ID.'),
|
||||
_('Lobbies'),
|
||||
'JsPlatform/Extensions/multiplayer.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Multiplayer/peer.js')
|
||||
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
|
||||
)
|
||||
.addIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
|
||||
)
|
||||
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
|
||||
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
|
||||
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
|
||||
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
|
||||
.setFunctionName('gdjs.multiplayer.getLobbyID');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'QuickJoinWithLobbyID',
|
||||
_('Join a specific lobby by its ID'),
|
||||
_(
|
||||
'Join a specific lobby. The player will join the game instantly if this is possible.'
|
||||
),
|
||||
_('Join a specific lobby by its ID _PARAM1_'),
|
||||
_('Lobbies'),
|
||||
'JsPlatform/Extensions/multiplayer.svg',
|
||||
'JsPlatform/Extensions/multiplayer.svg'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.addParameter('string', _('Lobby ID'), '', false)
|
||||
.addParameter(
|
||||
'yesorno',
|
||||
_('Display loader while joining a lobby.'),
|
||||
'',
|
||||
true
|
||||
)
|
||||
.setDefaultValue('yes')
|
||||
.addParameter(
|
||||
'yesorno',
|
||||
_('Display game lobbies if unable to join a specific one.'),
|
||||
'',
|
||||
true
|
||||
)
|
||||
.setDefaultValue('yes')
|
||||
.setHelpPath('/all-features/multiplayer')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Multiplayer/peer.js')
|
||||
.addIncludeFile('Extensions/Multiplayer/peerJsHelper.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
|
||||
)
|
||||
.addIncludeFile(
|
||||
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
|
||||
)
|
||||
.addIncludeFile('Extensions/Multiplayer/multiplayercomponents.js')
|
||||
.addIncludeFile('Extensions/Multiplayer/messageManager.js')
|
||||
.addIncludeFile('Extensions/Multiplayer/multiplayerVariablesManager.js')
|
||||
.addIncludeFile('Extensions/Multiplayer/multiplayertools.js')
|
||||
.setFunctionName('gdjs.multiplayer.authenticateAndQuickJoinWithLobbyID');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'QuickJoinLobby',
|
||||
|
@@ -293,6 +293,8 @@ namespace gdjs {
|
||||
x: objectNetworkSyncData.x,
|
||||
y: objectNetworkSyncData.y,
|
||||
z: objectNetworkSyncData.z,
|
||||
w: objectNetworkSyncData.w,
|
||||
h: objectNetworkSyncData.h,
|
||||
zo: objectNetworkSyncData.zo,
|
||||
a: objectNetworkSyncData.a,
|
||||
hid: objectNetworkSyncData.hid,
|
||||
@@ -369,6 +371,9 @@ namespace gdjs {
|
||||
this._lastSentBasicObjectSyncData = {
|
||||
x: objectNetworkSyncData.x,
|
||||
y: objectNetworkSyncData.y,
|
||||
z: objectNetworkSyncData.z,
|
||||
w: objectNetworkSyncData.w,
|
||||
h: objectNetworkSyncData.h,
|
||||
zo: objectNetworkSyncData.zo,
|
||||
a: objectNetworkSyncData.a,
|
||||
hid: objectNetworkSyncData.hid,
|
||||
|
@@ -17,9 +17,29 @@ namespace gdjs {
|
||||
}[];
|
||||
};
|
||||
|
||||
type LobbyStatus =
|
||||
| 'waiting'
|
||||
| 'starting'
|
||||
| 'playing'
|
||||
| 'migrating'
|
||||
| 'migrated';
|
||||
type LobbyConnectionStatus = 'waiting' | 'ready' | 'connected';
|
||||
type InGamePlayerStatus = 'playing' | 'left';
|
||||
type PlayerStatus = LobbyConnectionStatus | InGamePlayerStatus;
|
||||
|
||||
type LobbyPlayer = {
|
||||
playerId: string;
|
||||
status: PlayerStatus;
|
||||
playerNumber: number;
|
||||
};
|
||||
|
||||
type Lobby = {
|
||||
id: string;
|
||||
status: 'waiting' | 'starting' | 'playing' | 'migrating' | 'migrated';
|
||||
minPlayers: number;
|
||||
maxPlayers: number;
|
||||
canJoinAfterStart: boolean;
|
||||
players: LobbyPlayer[];
|
||||
status: LobbyStatus;
|
||||
};
|
||||
|
||||
type QuickJoinLobbyResponse =
|
||||
@@ -105,6 +125,7 @@ namespace gdjs {
|
||||
let _quickJoinLobbyFailureReason:
|
||||
| 'FULL'
|
||||
| 'NOT_ENOUGH_PLAYERS'
|
||||
| 'DOES_NOT_EXIST'
|
||||
| 'UNKNOWN'
|
||||
| null = null;
|
||||
let _lobbyId: string | null = null;
|
||||
@@ -1697,11 +1718,87 @@ namespace gdjs {
|
||||
}
|
||||
};
|
||||
|
||||
export const authenticateAndQuickJoinLobby = async (
|
||||
export const getLobbyID = (): string => {
|
||||
return _lobbyId || '';
|
||||
};
|
||||
|
||||
const quickJoinWithLobbyID = async (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
lobbyID: string,
|
||||
displayLoader: boolean,
|
||||
openLobbiesPageIfFailure: boolean
|
||||
) => {
|
||||
if (_isQuickJoiningOrStartingAGame) return;
|
||||
const _gameId = gdjs.projectData.properties.projectUuid;
|
||||
if (!_gameId) {
|
||||
logger.error(
|
||||
'The game ID is missing, the quick join lobby action cannot continue.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
_quickJoinLobbyFailureReason = null;
|
||||
_isQuickJoiningOrStartingAGame = true;
|
||||
if (displayLoader) {
|
||||
gdjs.multiplayerComponents.displayLoader(runtimeScene, true);
|
||||
}
|
||||
|
||||
const quickJoinWithLobbyIDRelativeUrl = `/play/game/${_gameId}/public-lobby/${lobbyID}`;
|
||||
|
||||
try {
|
||||
const lobby: Lobby = await gdjs.evtTools.network.retryIfFailed(
|
||||
{ times: 2 },
|
||||
() =>
|
||||
fetchAsPlayer({
|
||||
relativeUrl: quickJoinWithLobbyIDRelativeUrl,
|
||||
method: 'GET',
|
||||
dev: isUsingGDevelopDevelopmentEnvironment,
|
||||
})
|
||||
);
|
||||
|
||||
const isFull = lobby.players.length === lobby.maxPlayers;
|
||||
if (isFull) {
|
||||
logger.error('Lobby is full - cannot quick join it.');
|
||||
_quickJoinLobbyJustFailed = true;
|
||||
_quickJoinLobbyFailureReason = 'FULL';
|
||||
onLobbyQuickJoinFinished(runtimeScene);
|
||||
if (openLobbiesPageIfFailure) {
|
||||
openLobbiesWindow(runtimeScene);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (lobby.status === 'playing') {
|
||||
_actionAfterJoiningLobby = 'JOIN_GAME';
|
||||
} else if (lobby.status === 'waiting') {
|
||||
if (lobby.players.length === 0) {
|
||||
_actionAfterJoiningLobby = 'START_GAME';
|
||||
} else {
|
||||
_actionAfterJoiningLobby = 'OPEN_LOBBY_PAGE';
|
||||
}
|
||||
} else {
|
||||
throw new Error(`Lobby in wrong status: ${lobby.status}`);
|
||||
}
|
||||
|
||||
handleJoinLobbyEvent(runtimeScene, lobbyID);
|
||||
} catch (error) {
|
||||
const errorCode = parseInt(error.message.match(/\d{3}/)?.[0]);
|
||||
if (errorCode === 404) {
|
||||
logger.error('Lobby does not exist.');
|
||||
_quickJoinLobbyFailureReason = 'DOES_NOT_EXIST';
|
||||
} else {
|
||||
logger.error('An error occurred while joining a lobby:', error);
|
||||
_quickJoinLobbyFailureReason = 'UNKNOWN';
|
||||
}
|
||||
_quickJoinLobbyJustFailed = true;
|
||||
onLobbyQuickJoinFinished(runtimeScene);
|
||||
if (openLobbiesPageIfFailure) {
|
||||
openLobbiesWindow(runtimeScene);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const isQuickJoiningTooFast = () => {
|
||||
const requestDoneAt = Date.now();
|
||||
if (_lastQuickJoinRequestDoneAt) {
|
||||
if (requestDoneAt - _lastQuickJoinRequestDoneAt < 500) {
|
||||
@@ -1709,12 +1806,18 @@ namespace gdjs {
|
||||
logger.warn(
|
||||
'Last request to quick join a lobby was sent too little time ago. Ignoring this one.'
|
||||
);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
_lastQuickJoinRequestDoneAt = requestDoneAt;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const isNotCorrectlyAuthenticatedForQuickJoin = async (
|
||||
runtimeScene: RuntimeScene
|
||||
) => {
|
||||
const playerId = gdjs.playerAuthentication.getUserId();
|
||||
const playerToken = gdjs.playerAuthentication.getUserToken();
|
||||
if (!playerId || !playerToken) {
|
||||
@@ -1724,14 +1827,43 @@ namespace gdjs {
|
||||
.promise;
|
||||
_isWaitingForLogin = false;
|
||||
|
||||
if (status === 'logged') {
|
||||
await quickJoinLobby(
|
||||
runtimeScene,
|
||||
displayLoader,
|
||||
openLobbiesPageIfFailure
|
||||
);
|
||||
if (status !== 'logged') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
export const authenticateAndQuickJoinWithLobbyID = async (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
lobbyID: string,
|
||||
displayLoader: boolean,
|
||||
openLobbiesPageIfFailure: boolean
|
||||
) => {
|
||||
if (isQuickJoiningTooFast()) {
|
||||
return;
|
||||
}
|
||||
if (await isNotCorrectlyAuthenticatedForQuickJoin(runtimeScene)) {
|
||||
return;
|
||||
}
|
||||
await quickJoinWithLobbyID(
|
||||
runtimeScene,
|
||||
lobbyID,
|
||||
displayLoader,
|
||||
openLobbiesPageIfFailure
|
||||
);
|
||||
};
|
||||
|
||||
export const authenticateAndQuickJoinLobby = async (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
displayLoader: boolean,
|
||||
openLobbiesPageIfFailure: boolean
|
||||
) => {
|
||||
if (isQuickJoiningTooFast()) {
|
||||
return;
|
||||
}
|
||||
if (await isNotCorrectlyAuthenticatedForQuickJoin(runtimeScene)) {
|
||||
return;
|
||||
}
|
||||
await quickJoinLobby(
|
||||
|
@@ -389,26 +389,15 @@ namespace gdjs {
|
||||
this.updatePosition();
|
||||
}
|
||||
|
||||
setColor(rgbColor): void {
|
||||
const colors = rgbColor.split(';');
|
||||
if (colors.length < 3) {
|
||||
return;
|
||||
}
|
||||
this._centerSprite.tint = gdjs.rgbToHexNumber(
|
||||
parseInt(colors[0], 10),
|
||||
parseInt(colors[1], 10),
|
||||
parseInt(colors[2], 10)
|
||||
);
|
||||
setColor(rgbOrHexColor: string): void {
|
||||
const tint = gdjs.rgbOrHexStringToNumber(rgbOrHexColor);
|
||||
this._centerSprite.tint = tint;
|
||||
for (
|
||||
let borderCounter = 0;
|
||||
borderCounter < this._borderSprites.length;
|
||||
borderCounter++
|
||||
) {
|
||||
this._borderSprites[borderCounter].tint = gdjs.rgbToHexNumber(
|
||||
parseInt(colors[0], 10),
|
||||
parseInt(colors[1], 10),
|
||||
parseInt(colors[2], 10)
|
||||
);
|
||||
this._borderSprites[borderCounter].tint = tint;
|
||||
}
|
||||
this._spritesContainer.cacheAsBitmap = false;
|
||||
}
|
||||
@@ -416,11 +405,11 @@ namespace gdjs {
|
||||
getColor() {
|
||||
const rgb = new PIXI.Color(this._centerSprite.tint).toRgbArray();
|
||||
return (
|
||||
Math.floor(rgb[0] * 255) +
|
||||
Math.round(rgb[0] * 255) +
|
||||
';' +
|
||||
Math.floor(rgb[1] * 255) +
|
||||
Math.round(rgb[1] * 255) +
|
||||
';' +
|
||||
Math.floor(rgb[2] * 255)
|
||||
Math.round(rgb[2] * 255)
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -25,8 +25,6 @@ namespace gdjs {
|
||||
export type PanelSpriteObjectData = ObjectData & PanelSpriteObjectDataType;
|
||||
|
||||
export type PanelSpriteNetworkSyncDataType = {
|
||||
wid: number;
|
||||
hei: number;
|
||||
op: number;
|
||||
color: string;
|
||||
};
|
||||
@@ -124,8 +122,6 @@ namespace gdjs {
|
||||
getNetworkSyncData(): PanelSpriteNetworkSyncData {
|
||||
return {
|
||||
...super.getNetworkSyncData(),
|
||||
wid: this.getWidth(),
|
||||
hei: this.getHeight(),
|
||||
op: this.getOpacity(),
|
||||
color: this.getColor(),
|
||||
};
|
||||
@@ -138,12 +134,6 @@ namespace gdjs {
|
||||
|
||||
// Texture is not synchronized, see if this is asked or not.
|
||||
|
||||
if (networkSyncData.wid !== undefined) {
|
||||
this.setWidth(networkSyncData.wid);
|
||||
}
|
||||
if (networkSyncData.hei !== undefined) {
|
||||
this.setHeight(networkSyncData.hei);
|
||||
}
|
||||
if (networkSyncData.op !== undefined) {
|
||||
this.setOpacity(networkSyncData.op);
|
||||
}
|
||||
|
@@ -194,9 +194,9 @@ ParticleEmitterObject::GetProperties() const {
|
||||
: GetRendererType() == Line ? "Line"
|
||||
: "Image")
|
||||
.SetType("choice")
|
||||
.AddExtraInfo("Circle")
|
||||
.AddExtraInfo("Line")
|
||||
.AddExtraInfo("Image")
|
||||
.AddChoice("Circle", _("Circle"))
|
||||
.AddChoice("Line", _("Line"))
|
||||
.AddChoice("Image", _("Image"))
|
||||
.SetLabel(_("Particle type"))
|
||||
.SetHasImpactOnOtherProperties(true);
|
||||
|
||||
|
@@ -818,7 +818,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter('yesorno', _('Treat as bullet?'), '', false)
|
||||
.addParameter('yesorno', _('Treat as bullet'), '', false)
|
||||
.setDefaultValue('false')
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('setBullet');
|
||||
@@ -852,7 +852,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter('yesorno', _('Fixed rotation?'), '', false)
|
||||
.addParameter('yesorno', _('Fixed rotation'), '', false)
|
||||
.setDefaultValue('false')
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('setFixedRotation');
|
||||
@@ -886,7 +886,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter('yesorno', _('Can sleep?'), '', false)
|
||||
.addParameter('yesorno', _('Can sleep'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('setSleepingAllowed');
|
||||
@@ -1296,7 +1296,7 @@ module.exports = {
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter('expression', _('Layer (1 - 16)'))
|
||||
.addParameter('yesorno', _('Enable?'), '', false)
|
||||
.addParameter('yesorno', _('Enable'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('enableLayer');
|
||||
@@ -1332,7 +1332,7 @@ module.exports = {
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter('expression', _('Mask (1 - 16)'))
|
||||
.addParameter('yesorno', _('Enable?'), '', false)
|
||||
.addParameter('yesorno', _('Enable'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('enableMask');
|
||||
@@ -2409,7 +2409,7 @@ module.exports = {
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter('expression', _('Joint ID'))
|
||||
.addParameter('yesorno', _('Enable?'))
|
||||
.addParameter('yesorno', _('Enable'))
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('enableRevoluteJointLimits');
|
||||
|
||||
@@ -2488,7 +2488,7 @@ module.exports = {
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter('expression', _('Joint ID'))
|
||||
.addParameter('yesorno', _('Enable?'))
|
||||
.addParameter('yesorno', _('Enable'))
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('enableRevoluteJointMotor');
|
||||
|
||||
@@ -2727,7 +2727,7 @@ module.exports = {
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter('expression', _('Joint ID'))
|
||||
.addParameter('yesorno', _('Enable?'))
|
||||
.addParameter('yesorno', _('Enable'))
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('enablePrismaticJointLimits');
|
||||
|
||||
@@ -2806,7 +2806,7 @@ module.exports = {
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter('expression', _('Joint ID'))
|
||||
.addParameter('yesorno', _('Enable?'))
|
||||
.addParameter('yesorno', _('Enable'))
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('enablePrismaticJointMotor');
|
||||
|
||||
@@ -3486,7 +3486,7 @@ module.exports = {
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter('expression', _('Joint ID'))
|
||||
.addParameter('yesorno', _('Enable?'))
|
||||
.addParameter('yesorno', _('Enable'))
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('enableWheelJointMotor');
|
||||
|
||||
|
@@ -274,7 +274,7 @@ module.exports = {
|
||||
.setLabel('Fixed Rotation')
|
||||
.setDescription(
|
||||
_(
|
||||
"If enabled, the object won't rotate and will stay at the same angle. Useful for characters for example."
|
||||
"If enabled, the object won't rotate and will stay at the same angle."
|
||||
)
|
||||
)
|
||||
.setGroup(_('Movement'));
|
||||
@@ -845,7 +845,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||
.addParameter('yesorno', _('Treat as bullet?'), '', false)
|
||||
.addParameter('yesorno', _('Treat as bullet'), '', false)
|
||||
.setDefaultValue('false')
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('setBullet');
|
||||
@@ -870,7 +870,7 @@ module.exports = {
|
||||
'SetFixedRotation',
|
||||
_('Fixed rotation'),
|
||||
_(
|
||||
"Enable or disable an object fixed rotation. If enabled the object won't be able to rotate."
|
||||
"Enable or disable an object fixed rotation. If enabled the object won't be able to rotate. This action has no effect on characters."
|
||||
),
|
||||
_('Set _PARAM0_ fixed rotation: _PARAM2_'),
|
||||
_('Dynamics'),
|
||||
@@ -879,7 +879,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||
.addParameter('yesorno', _('Fixed rotation?'), '', false)
|
||||
.addParameter('yesorno', _('Fixed rotation'), '', false)
|
||||
.setDefaultValue('false')
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('setFixedRotation');
|
||||
@@ -927,6 +927,54 @@ module.exports = {
|
||||
.setFunctionName('setDensity')
|
||||
.setGetter('getDensity');
|
||||
|
||||
aut
|
||||
.addExpressionAndConditionAndAction(
|
||||
'number',
|
||||
'ShapeOffsetX',
|
||||
_('Shape offset X'),
|
||||
_('the object shape offset on X.'),
|
||||
_('the shape offset on X'),
|
||||
_('Body settings'),
|
||||
'JsPlatform/Extensions/physics3d.svg'
|
||||
)
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.setFunctionName('setShapeOffsetX')
|
||||
.setGetter('getShapeOffsetX');
|
||||
|
||||
aut
|
||||
.addExpressionAndConditionAndAction(
|
||||
'number',
|
||||
'ShapeOffsetY',
|
||||
_('Shape offset Y'),
|
||||
_('the object shape offset on Y.'),
|
||||
_('the shape offset on Y'),
|
||||
_('Body settings'),
|
||||
'JsPlatform/Extensions/physics3d.svg'
|
||||
)
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.setFunctionName('setShapeOffsetY')
|
||||
.setGetter('getShapeOffsetY');
|
||||
|
||||
aut
|
||||
.addExpressionAndConditionAndAction(
|
||||
'number',
|
||||
'ShapeOffsetZ',
|
||||
_('Shape offset Z'),
|
||||
_('the object shape offset on Z.'),
|
||||
_('the shape offset on Z'),
|
||||
_('Body settings'),
|
||||
'JsPlatform/Extensions/physics3d.svg'
|
||||
)
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.setFunctionName('setShapeOffsetZ')
|
||||
.setGetter('getShapeOffsetZ');
|
||||
|
||||
aut
|
||||
.addExpressionAndConditionAndAction(
|
||||
'number',
|
||||
@@ -1054,7 +1102,7 @@ module.exports = {
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||
.addParameter('expression', _('Layer (1 - 8)'))
|
||||
.addParameter('yesorno', _('Enable?'), '', false)
|
||||
.addParameter('yesorno', _('Enable'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('enableLayer');
|
||||
@@ -1090,7 +1138,7 @@ module.exports = {
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||
.addParameter('expression', _('Mask (1 - 8)'))
|
||||
.addParameter('yesorno', _('Enable?'), '', false)
|
||||
.addParameter('yesorno', _('Enable'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('enableMask');
|
||||
@@ -1270,7 +1318,7 @@ module.exports = {
|
||||
.addParameter('expression', _('Application point on Z axis'))
|
||||
.setParameterLongDescription(
|
||||
_(
|
||||
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
|
||||
'Use `MassCenterX`, `MassCenterY` and `MassCenterZ` expressions to avoid any rotation.'
|
||||
)
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
@@ -1544,6 +1592,19 @@ module.exports = {
|
||||
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('getMassCenterY');
|
||||
|
||||
aut
|
||||
.addExpression(
|
||||
'MassCenterZ',
|
||||
_('Mass center Z'),
|
||||
_('Mass center Z'),
|
||||
'',
|
||||
'JsPlatform/Extensions/physics3d.svg'
|
||||
)
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('getMassCenterZ');
|
||||
}
|
||||
// Collision
|
||||
extension
|
||||
|
@@ -630,24 +630,34 @@ namespace gdjs {
|
||||
|
||||
override onDeActivate() {
|
||||
this._sharedData.removeFromBehaviorsList(this);
|
||||
this._destroyBody();
|
||||
}
|
||||
|
||||
override onActivate() {
|
||||
this._sharedData.addToBehaviorsList(this);
|
||||
}
|
||||
|
||||
override onDestroy() {
|
||||
this._destroyedDuringFrameLogic = true;
|
||||
this.onDeActivate();
|
||||
}
|
||||
|
||||
_destroyBody() {
|
||||
this.bodyUpdater.destroyBody();
|
||||
this._contactsEndedThisFrame.length = 0;
|
||||
this._contactsStartedThisFrame.length = 0;
|
||||
this._currentContacts.length = 0;
|
||||
}
|
||||
|
||||
override onActivate() {
|
||||
this._sharedData.addToBehaviorsList(this);
|
||||
|
||||
this._contactsEndedThisFrame.length = 0;
|
||||
this._contactsStartedThisFrame.length = 0;
|
||||
this._currentContacts.length = 0;
|
||||
this.updateBodyFromObject();
|
||||
resetToDefaultBodyUpdater() {
|
||||
this.bodyUpdater = new gdjs.Physics3DRuntimeBehavior.DefaultBodyUpdater(
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
override onDestroy() {
|
||||
this._destroyedDuringFrameLogic = true;
|
||||
this.onDeActivate();
|
||||
resetToDefaultCollisionChecker() {
|
||||
this.collisionChecker =
|
||||
new gdjs.Physics3DRuntimeBehavior.DefaultCollisionChecker(this);
|
||||
}
|
||||
|
||||
createShape(): Jolt.Shape {
|
||||
@@ -927,9 +937,7 @@ namespace gdjs {
|
||||
const angularVelocityY = angularVelocity.GetY();
|
||||
const angularVelocityZ = angularVelocity.GetZ();
|
||||
|
||||
let bodyID = this._body.GetID();
|
||||
bodyInterface.RemoveBody(bodyID);
|
||||
bodyInterface.DestroyBody(bodyID);
|
||||
this.bodyUpdater.destroyBody();
|
||||
this._contactsEndedThisFrame.length = 0;
|
||||
this._contactsStartedThisFrame.length = 0;
|
||||
this._currentContacts.length = 0;
|
||||
@@ -938,7 +946,7 @@ namespace gdjs {
|
||||
if (!this._body) {
|
||||
return;
|
||||
}
|
||||
bodyID = this._body.GetID();
|
||||
const bodyID = this._body.GetID();
|
||||
bodyInterface.SetLinearVelocity(
|
||||
bodyID,
|
||||
this.getVec3(linearVelocityX, linearVelocityY, linearVelocityZ)
|
||||
@@ -1178,6 +1186,33 @@ namespace gdjs {
|
||||
this._needToRecreateBody = true;
|
||||
}
|
||||
|
||||
getShapeOffsetX(): float {
|
||||
return this.shapeOffsetX;
|
||||
}
|
||||
|
||||
setShapeOffsetX(shapeOffsetX: float): void {
|
||||
this.shapeOffsetX = shapeOffsetX;
|
||||
this._needToRecreateShape = true;
|
||||
}
|
||||
|
||||
getShapeOffsetY(): float {
|
||||
return this.shapeOffsetY;
|
||||
}
|
||||
|
||||
setShapeOffsetY(shapeOffsetY: float): void {
|
||||
this.shapeOffsetY = shapeOffsetY;
|
||||
this._needToRecreateShape = true;
|
||||
}
|
||||
|
||||
getShapeOffsetZ(): float {
|
||||
return this.shapeOffsetZ;
|
||||
}
|
||||
|
||||
setShapeOffsetZ(shapeOffsetZ: float): void {
|
||||
this.shapeOffsetZ = shapeOffsetZ;
|
||||
this._needToRecreateShape = true;
|
||||
}
|
||||
|
||||
getFriction(): float {
|
||||
return this.friction;
|
||||
}
|
||||
@@ -1542,9 +1577,9 @@ namespace gdjs {
|
||||
}
|
||||
const body = this._body!;
|
||||
|
||||
const deltaX = towardX - body.GetPosition().GetX();
|
||||
const deltaY = towardY - body.GetPosition().GetY();
|
||||
const deltaZ = towardZ - body.GetPosition().GetZ();
|
||||
const deltaX = towardX - this.owner3D.getX();
|
||||
const deltaY = towardY - this.owner3D.getY();
|
||||
const deltaZ = towardZ - this.owner3D.getZ();
|
||||
const distanceSq = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
|
||||
if (distanceSq === 0) {
|
||||
return;
|
||||
@@ -1602,19 +1637,16 @@ namespace gdjs {
|
||||
length: float,
|
||||
towardX: float,
|
||||
towardY: float,
|
||||
towardZ: float,
|
||||
originX: float,
|
||||
originY: float,
|
||||
originZ: float
|
||||
towardZ: float
|
||||
): void {
|
||||
if (this._body === null) {
|
||||
if (!this._createBody()) return;
|
||||
}
|
||||
const body = this._body!;
|
||||
|
||||
const deltaX = towardX - originX;
|
||||
const deltaY = towardY - originY;
|
||||
const deltaZ = towardZ - originZ;
|
||||
const deltaX = towardX - this.owner3D.getX();
|
||||
const deltaY = towardY - this.owner3D.getY();
|
||||
const deltaZ = towardZ - this.owner3D.getZ();
|
||||
const distanceSq = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
|
||||
if (distanceSq === 0) {
|
||||
return;
|
||||
@@ -1623,12 +1655,7 @@ namespace gdjs {
|
||||
|
||||
this._sharedData.bodyInterface.AddImpulse(
|
||||
body.GetID(),
|
||||
this.getVec3(deltaX * ratio, deltaY * ratio, deltaZ * ratio),
|
||||
this.getRVec3(
|
||||
originX * this._sharedData.worldInvScale,
|
||||
originY * this._sharedData.worldInvScale,
|
||||
originZ * this._sharedData.worldInvScale
|
||||
)
|
||||
this.getVec3(deltaX * ratio, deltaY * ratio, deltaZ * ratio)
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -29,6 +29,7 @@ namespace gdjs {
|
||||
owner3D: gdjs.RuntimeObject3D;
|
||||
private _physics3DBehaviorName: string;
|
||||
private _physics3D: Physics3D | null = null;
|
||||
private _isHookedToPhysicsStep = false;
|
||||
_vehicleController: Jolt.WheeledVehicleController | null = null;
|
||||
_stepListener: Jolt.VehicleConstraintStepListener | null = null;
|
||||
_vehicleCollisionTester: Jolt.VehicleCollisionTesterCastCylinder | null =
|
||||
@@ -153,13 +154,19 @@ namespace gdjs {
|
||||
const behavior = this.owner.getBehavior(
|
||||
this._physics3DBehaviorName
|
||||
) as gdjs.Physics3DRuntimeBehavior;
|
||||
if (!behavior.activated()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sharedData = behavior._sharedData;
|
||||
|
||||
this._physics3D = {
|
||||
behavior,
|
||||
};
|
||||
sharedData.registerHook(this);
|
||||
if (!this._isHookedToPhysicsStep) {
|
||||
sharedData.registerHook(this);
|
||||
this._isHookedToPhysicsStep = true;
|
||||
}
|
||||
|
||||
behavior.bodyUpdater =
|
||||
new gdjs.PhysicsCar3DRuntimeBehavior.VehicleBodyUpdater(
|
||||
@@ -330,25 +337,33 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
override onDeActivate() {
|
||||
if (this._stepListener) {
|
||||
this._sharedData.physicsSystem.RemoveStepListener(this._stepListener);
|
||||
if (!this._physics3D) {
|
||||
return;
|
||||
}
|
||||
this._destroyBody();
|
||||
}
|
||||
|
||||
override onActivate() {
|
||||
if (this._stepListener) {
|
||||
this._sharedData.physicsSystem.AddStepListener(this._stepListener);
|
||||
const behavior = this.owner.getBehavior(
|
||||
this._physics3DBehaviorName
|
||||
) as gdjs.Physics3DRuntimeBehavior;
|
||||
if (!behavior) {
|
||||
return;
|
||||
}
|
||||
behavior._destroyBody();
|
||||
}
|
||||
|
||||
override onDestroy() {
|
||||
this._destroyedDuringFrameLogic = true;
|
||||
this._destroyBody();
|
||||
}
|
||||
|
||||
_destroyBody() {
|
||||
if (!this._vehicleController) {
|
||||
return;
|
||||
}
|
||||
this._destroyedDuringFrameLogic = true;
|
||||
this.onDeActivate();
|
||||
if (this._stepListener) {
|
||||
// stepListener is removed by onDeActivate
|
||||
this._sharedData.physicsSystem.RemoveStepListener(this._stepListener);
|
||||
Jolt.destroy(this._stepListener);
|
||||
this._stepListener = null;
|
||||
}
|
||||
@@ -360,6 +375,8 @@ namespace gdjs {
|
||||
// It is destroyed with the constraint.
|
||||
this._vehicleCollisionTester = null;
|
||||
if (this._physics3D) {
|
||||
const { behavior } = this._physics3D;
|
||||
behavior.resetToDefaultBodyUpdater();
|
||||
this._physics3D = null;
|
||||
}
|
||||
}
|
||||
@@ -733,7 +750,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
setWheelOffsetZ(wheelOffsetZ: float): void {
|
||||
this._wheelOffsetY = wheelOffsetZ;
|
||||
this._wheelOffsetZ = wheelOffsetZ;
|
||||
this._updateWheels();
|
||||
}
|
||||
|
||||
@@ -783,11 +800,11 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
hasFrontWheelDrive(): boolean {
|
||||
return this._hasBackWheelDrive;
|
||||
return this._hasFrontWheelDrive;
|
||||
}
|
||||
|
||||
setFrontWheelDrive(hasFrontWheelDrive: boolean): void {
|
||||
this._hasBackWheelDrive = hasFrontWheelDrive;
|
||||
this._hasFrontWheelDrive = hasFrontWheelDrive;
|
||||
this.invalidateShape();
|
||||
}
|
||||
|
||||
@@ -1110,7 +1127,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
destroyBody() {
|
||||
this.carBehavior.onDestroy();
|
||||
this.carBehavior._destroyBody();
|
||||
this.physicsBodyUpdater.destroyBody();
|
||||
}
|
||||
}
|
||||
|
@@ -41,6 +41,7 @@ namespace gdjs {
|
||||
owner3D: gdjs.RuntimeObject3D;
|
||||
private _physics3DBehaviorName: string;
|
||||
private _physics3D: Physics3D | null = null;
|
||||
private _isHookedToPhysicsStep = false;
|
||||
character: Jolt.CharacterVirtual | null = null;
|
||||
/**
|
||||
* sharedData is a reference to the shared data of the scene, that registers
|
||||
@@ -169,10 +170,15 @@ namespace gdjs {
|
||||
if (this._physics3D) {
|
||||
return this._physics3D;
|
||||
}
|
||||
if (!this.activated()) {
|
||||
return null;
|
||||
}
|
||||
const behavior = this.owner.getBehavior(
|
||||
this._physics3DBehaviorName
|
||||
) as gdjs.Physics3DRuntimeBehavior;
|
||||
|
||||
if (!behavior.activated()) {
|
||||
return null;
|
||||
}
|
||||
const sharedData = behavior._sharedData;
|
||||
const jolt = sharedData.jolt;
|
||||
const extendedUpdateSettings = new Jolt.ExtendedUpdateSettings();
|
||||
@@ -196,7 +202,10 @@ namespace gdjs {
|
||||
shapeFilter,
|
||||
};
|
||||
this.setStairHeightMax(this._stairHeightMax);
|
||||
sharedData.registerHook(this);
|
||||
if (!this._isHookedToPhysicsStep) {
|
||||
sharedData.registerHook(this);
|
||||
this._isHookedToPhysicsStep = true;
|
||||
}
|
||||
|
||||
behavior.bodyUpdater =
|
||||
new gdjs.PhysicsCharacter3DRuntimeBehavior.CharacterBodyUpdater(this);
|
||||
@@ -390,36 +399,48 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
override onDeActivate() {
|
||||
this.collisionChecker.clearContacts();
|
||||
if (!this._physics3D) {
|
||||
return;
|
||||
}
|
||||
this._destroyBody();
|
||||
}
|
||||
|
||||
override onActivate() {}
|
||||
override onActivate() {
|
||||
const behavior = this.owner.getBehavior(
|
||||
this._physics3DBehaviorName
|
||||
) as gdjs.Physics3DRuntimeBehavior;
|
||||
if (!behavior) {
|
||||
return;
|
||||
}
|
||||
behavior._destroyBody();
|
||||
}
|
||||
|
||||
override onDestroy() {
|
||||
this._destroyedDuringFrameLogic = true;
|
||||
this.onDeActivate();
|
||||
this._destroyCharacter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the character and its body from the physics engine.
|
||||
* This method is called when:
|
||||
* - The Physics3D behavior is deactivated
|
||||
* - This behavior is deactivated
|
||||
* - The object is destroyed
|
||||
*
|
||||
* Only deactivating the character behavior won't destroy the character.
|
||||
* Indeed, deactivated characters don't move as characters but still have collisions.
|
||||
*/
|
||||
_destroyCharacter() {
|
||||
_destroyBody() {
|
||||
if (this.character) {
|
||||
if (this._canBePushed) {
|
||||
this.charactersManager.removeCharacter(this.character);
|
||||
Jolt.destroy(this.character.GetListener());
|
||||
}
|
||||
this.collisionChecker.clearContacts();
|
||||
// The body is destroyed with the character.
|
||||
Jolt.destroy(this.character);
|
||||
this.character = null;
|
||||
if (this._physics3D) {
|
||||
const { behavior } = this._physics3D;
|
||||
behavior.resetToDefaultBodyUpdater();
|
||||
behavior.resetToDefaultCollisionChecker();
|
||||
this._physics3D.behavior._body = null;
|
||||
const {
|
||||
extendedUpdateSettings,
|
||||
@@ -1780,7 +1801,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
destroyBody() {
|
||||
this.characterBehavior._destroyCharacter();
|
||||
this.characterBehavior._destroyBody();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -486,7 +486,16 @@ namespace gdjs {
|
||||
this._state.beforeMovingX();
|
||||
|
||||
//Ensure the object is not stuck
|
||||
if (this._separateFromPlatforms(this._potentialCollidingObjects, true)) {
|
||||
const hasPopOutOfPlatform = this._separateFromPlatforms(
|
||||
this._potentialCollidingObjects,
|
||||
true
|
||||
);
|
||||
if (hasPopOutOfPlatform && !this._jumpKey) {
|
||||
// TODO This is probably unnecessary because `_canJump` is already set
|
||||
// to true when entering the `OnFloor` state.
|
||||
// This is wrongly allowing double jumps when characters are flipped
|
||||
// with an offset center.
|
||||
|
||||
//After being unstuck, the object must be able to jump again.
|
||||
this._canJump = true;
|
||||
}
|
||||
|
@@ -35,7 +35,7 @@ module.exports = {
|
||||
.addDependency()
|
||||
.setName('Safari View Controller Cordova plugin')
|
||||
.setDependencyType('cordova')
|
||||
.setExportName('cordova-plugin-safariviewcontroller');
|
||||
.setExportName('@gdevelop/cordova-plugin-safariviewcontroller');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
|
@@ -834,34 +834,51 @@ namespace gdjs {
|
||||
authWindowOptions,
|
||||
});
|
||||
|
||||
if (typeof SafariViewController === 'undefined') {
|
||||
logger.error(
|
||||
'Cordova plugin SafariViewController is not installed.'
|
||||
);
|
||||
resolve('errored');
|
||||
return;
|
||||
}
|
||||
|
||||
SafariViewController.isAvailable(function (available: boolean) {
|
||||
if (available) {
|
||||
SafariViewController.show(
|
||||
{
|
||||
url: targetUrl,
|
||||
hidden: false,
|
||||
animated: true,
|
||||
transition: 'slide',
|
||||
enterReaderModeIfAvailable: false,
|
||||
barColor: '#000000',
|
||||
tintColor: '#ffffff',
|
||||
controlTintColor: '#ffffff',
|
||||
},
|
||||
function (result: any) {
|
||||
// Other events are `opened` and `loaded`.
|
||||
if (result.event === 'closed') {
|
||||
resolve('dismissed');
|
||||
}
|
||||
},
|
||||
function (error: any) {
|
||||
logger.log('Error opening webview: ' + JSON.stringify(error));
|
||||
resolve('errored');
|
||||
}
|
||||
if (!available) {
|
||||
logger.error(
|
||||
'Cordova plugin SafariViewController is installed but not available'
|
||||
);
|
||||
} else {
|
||||
logger.error('Plugin SafariViewController is not available');
|
||||
resolve('errored');
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info(
|
||||
'Opening authentication window for Cordova with SafariViewController.'
|
||||
);
|
||||
SafariViewController.show(
|
||||
{
|
||||
url: targetUrl,
|
||||
hidden: false,
|
||||
animated: true,
|
||||
transition: 'slide',
|
||||
enterReaderModeIfAvailable: false,
|
||||
barColor: '#000000',
|
||||
tintColor: '#ffffff',
|
||||
controlTintColor: '#ffffff',
|
||||
},
|
||||
function (result: any) {
|
||||
// Other events are `opened` and `loaded`.
|
||||
if (result.event === 'closed') {
|
||||
resolve('dismissed');
|
||||
}
|
||||
},
|
||||
function (error: any) {
|
||||
logger.log(
|
||||
'Error opening authentication window: ' +
|
||||
JSON.stringify(error)
|
||||
);
|
||||
resolve('errored');
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@@ -15,7 +15,7 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
.SetExtensionInformation(
|
||||
"PrimitiveDrawing",
|
||||
_("Shape painter"),
|
||||
_("This provides an object that can be used to draw arbitrary shapes "
|
||||
_("An object that can be used to draw arbitrary 2D shapes "
|
||||
"on the screen using events."),
|
||||
"Florian Rival and Aurélien Vivet",
|
||||
"Open source (MIT License)")
|
||||
@@ -28,7 +28,7 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
.AddObject<ShapePainterObject>(
|
||||
"Drawer", //"Drawer" is kept for compatibility with GD<=3.6.76
|
||||
_("Shape painter"),
|
||||
_("Allows you to draw simple shapes on the screen using the "
|
||||
_("Allows to draw simple 2D shapes on the screen using the "
|
||||
"events."),
|
||||
"CppPlatform/Extensions/primitivedrawingicon.png")
|
||||
.SetCategoryFullName(_("Advanced"))
|
||||
@@ -125,11 +125,11 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
.SetFunctionName("DrawEllipse");
|
||||
|
||||
obj.AddAction("FilletRectangle",
|
||||
_("Fillet Rectangle"),
|
||||
_("Draw a fillet rectangle on screen"),
|
||||
_("Draw from _PARAM1_;_PARAM2_ to _PARAM3_;_PARAM4_ a fillet "
|
||||
"rectangle (fillet: _PARAM5_)"
|
||||
"with _PARAM0_"),
|
||||
_("Fillet Rectangle"),
|
||||
_("Draw a fillet rectangle on screen"),
|
||||
_("Draw from _PARAM1_;_PARAM2_ to _PARAM3_;_PARAM4_ a fillet "
|
||||
"rectangle (fillet: _PARAM5_)"
|
||||
"with _PARAM0_"),
|
||||
_("Drawing"),
|
||||
"res/actions/filletRectangle24.png",
|
||||
"res/actions/filletRectangle.png")
|
||||
@@ -142,7 +142,6 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
.AddParameter("expression", _("Fillet (in pixels)"))
|
||||
.SetFunctionName("DrawFilletRectangle");
|
||||
|
||||
|
||||
obj.AddAction("RoundedRectangle",
|
||||
_("Rounded rectangle"),
|
||||
_("Draw a rounded rectangle on screen"),
|
||||
@@ -170,54 +169,53 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
_("Drawing"),
|
||||
"res/actions/chamferRectangle24.png",
|
||||
"res/actions/chamferRectangle.png")
|
||||
.AddParameter("object", _("Shape Painter object"), "Drawer")
|
||||
.AddParameter("expression", _("Left X position"))
|
||||
.AddParameter("expression", _("Top Y position"))
|
||||
.AddParameter("expression", _("Right X position"))
|
||||
.AddParameter("expression", _("Bottom Y position"))
|
||||
.AddParameter("expression", _("Chamfer (in pixels)"))
|
||||
.SetFunctionName("DrawChamferRectangle");
|
||||
|
||||
.AddParameter("object", _("Shape Painter object"), "Drawer")
|
||||
.AddParameter("expression", _("Left X position"))
|
||||
.AddParameter("expression", _("Top Y position"))
|
||||
.AddParameter("expression", _("Right X position"))
|
||||
.AddParameter("expression", _("Bottom Y position"))
|
||||
.AddParameter("expression", _("Chamfer (in pixels)"))
|
||||
.SetFunctionName("DrawChamferRectangle");
|
||||
|
||||
obj.AddAction("Torus",
|
||||
_("Torus"),
|
||||
_("Draw a torus on screen"),
|
||||
_("Draw at _PARAM1_;_PARAM2_ a torus with "
|
||||
"inner radius: _PARAM3_, outer radius: _PARAM4_ and "
|
||||
"with start arc angle: _PARAM5_°, end angle: _PARAM6_° "
|
||||
"with _PARAM0_"),
|
||||
_("Drawing"),
|
||||
"res/actions/torus24.png",
|
||||
"res/actions/torus.png")
|
||||
|
||||
.AddParameter("object", _("Shape Painter object"), "Drawer")
|
||||
.AddParameter("expression", _("X position of center"))
|
||||
.AddParameter("expression", _("Y position of center"))
|
||||
.AddParameter("expression", _("Inner Radius (in pixels)"))
|
||||
.AddParameter("expression", _("Outer Radius (in pixels)"))
|
||||
.AddParameter("expression", _("Start Arc (in degrees)"))
|
||||
.AddParameter("expression", _("End Arc (in degrees)"))
|
||||
.SetFunctionName("DrawTorus");
|
||||
|
||||
|
||||
_("Torus"),
|
||||
_("Draw a torus on screen"),
|
||||
_("Draw at _PARAM1_;_PARAM2_ a torus with "
|
||||
"inner radius: _PARAM3_, outer radius: _PARAM4_ and "
|
||||
"with start arc angle: _PARAM5_°, end angle: _PARAM6_° "
|
||||
"with _PARAM0_"),
|
||||
_("Drawing"),
|
||||
"res/actions/torus24.png",
|
||||
"res/actions/torus.png")
|
||||
|
||||
.AddParameter("object", _("Shape Painter object"), "Drawer")
|
||||
.AddParameter("expression", _("X position of center"))
|
||||
.AddParameter("expression", _("Y position of center"))
|
||||
.AddParameter("expression", _("Inner Radius (in pixels)"))
|
||||
.AddParameter("expression", _("Outer Radius (in pixels)"))
|
||||
.AddParameter("expression", _("Start Arc (in degrees)"))
|
||||
.AddParameter("expression", _("End Arc (in degrees)"))
|
||||
.SetFunctionName("DrawTorus");
|
||||
|
||||
obj.AddAction("RegularPolygon",
|
||||
_("Regular Polygon"),
|
||||
_("Draw a regular polygon on screen"),
|
||||
_("Draw at _PARAM1_;_PARAM2_ a regular polygon with _PARAM3_ sides and radius: "
|
||||
_("Draw at _PARAM1_;_PARAM2_ a regular polygon with _PARAM3_ "
|
||||
"sides and radius: "
|
||||
"_PARAM4_ (rotation: _PARAM5_) "
|
||||
"with _PARAM0_"),
|
||||
_("Drawing"),
|
||||
"res/actions/regularPolygon24.png",
|
||||
"res/actions/regularPolygon.png")
|
||||
_("Drawing"),
|
||||
"res/actions/regularPolygon24.png",
|
||||
"res/actions/regularPolygon.png")
|
||||
|
||||
.AddParameter("object", _("Shape Painter object"), "Drawer")
|
||||
.AddParameter("expression", _("X position of center"))
|
||||
.AddParameter("expression", _("Y position of center"))
|
||||
.AddParameter("expression",
|
||||
_("Number of sides of the polygon (minimum: 3)"))
|
||||
.AddParameter("expression", _("Radius (in pixels)"))
|
||||
.AddParameter("expression", _("Rotation (in degrees)"))
|
||||
.SetFunctionName("DrawRegularPolygon");
|
||||
.AddParameter("object", _("Shape Painter object"), "Drawer")
|
||||
.AddParameter("expression", _("X position of center"))
|
||||
.AddParameter("expression", _("Y position of center"))
|
||||
.AddParameter("expression",
|
||||
_("Number of sides of the polygon (minimum: 3)"))
|
||||
.AddParameter("expression", _("Radius (in pixels)"))
|
||||
.AddParameter("expression", _("Rotation (in degrees)"))
|
||||
.SetFunctionName("DrawRegularPolygon");
|
||||
|
||||
obj.AddAction(
|
||||
"Star",
|
||||
|
@@ -246,10 +246,10 @@ std::map<gd::String, gd::PropertyDescriptor> ShapePainterObject::GetProperties()
|
||||
objectProperties["antialiasing"]
|
||||
.SetValue(GetAntialiasing())
|
||||
.SetType("choice")
|
||||
.AddExtraInfo("none")
|
||||
.AddExtraInfo("low")
|
||||
.AddExtraInfo("medium")
|
||||
.AddExtraInfo("high")
|
||||
.AddChoice("none", _("None"))
|
||||
.AddChoice("low", _("Low quality"))
|
||||
.AddChoice("medium", _("Medium quality"))
|
||||
.AddChoice("high", _("High quality"))
|
||||
.SetGroup(_("Drawing"))
|
||||
.SetLabel(_("Antialiasing"))
|
||||
.SetDescription(_("Antialiasing mode"));
|
||||
|
@@ -195,11 +195,25 @@ namespace gdjs {
|
||||
}
|
||||
/**
|
||||
* To be called when the game is disposed.
|
||||
* Clear the Spine Atlases loaded in this manager.
|
||||
* Clear the Spine atlases loaded in this manager.
|
||||
*/
|
||||
dispose(): void {
|
||||
this._loadedSpineAtlases.clear();
|
||||
this._loadingSpineAtlases.clear();
|
||||
}
|
||||
|
||||
unloadResource(resourceData: ResourceData): void {
|
||||
const loadedSpineAtlas = this._loadedSpineAtlases.get(resourceData);
|
||||
if (loadedSpineAtlas) {
|
||||
loadedSpineAtlas.dispose();
|
||||
this._loadedSpineAtlases.delete(resourceData);
|
||||
}
|
||||
|
||||
const loadingSpineAtlas = this._loadingSpineAtlases.get(resourceData);
|
||||
if (loadingSpineAtlas) {
|
||||
loadingSpineAtlas.then((atl) => atl.dispose());
|
||||
this._loadingSpineAtlases.delete(resourceData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -126,5 +126,12 @@ namespace gdjs {
|
||||
dispose(): void {
|
||||
this._loadedSpines.clear();
|
||||
}
|
||||
|
||||
unloadResource(resourceData: ResourceData): void {
|
||||
const loadedSpine = this._loadedSpines.get(resourceData);
|
||||
if (loadedSpine) {
|
||||
this._loadedSpines.delete(resourceData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -14,8 +14,6 @@ namespace gdjs {
|
||||
|
||||
export type SpineNetworkSyncDataType = {
|
||||
opa: float;
|
||||
wid: float;
|
||||
hei: float;
|
||||
scaX: float;
|
||||
scaY: float;
|
||||
flipX: boolean;
|
||||
@@ -117,8 +115,6 @@ namespace gdjs {
|
||||
return {
|
||||
...super.getNetworkSyncData(),
|
||||
opa: this._opacity,
|
||||
wid: this.getWidth(),
|
||||
hei: this.getHeight(),
|
||||
scaX: this.getScaleX(),
|
||||
scaY: this.getScaleY(),
|
||||
flipX: this.isFlippedX(),
|
||||
@@ -137,12 +133,6 @@ namespace gdjs {
|
||||
if (syncData.opa !== undefined && syncData.opa !== this._opacity) {
|
||||
this.setOpacity(syncData.opa);
|
||||
}
|
||||
if (syncData.wid !== undefined && syncData.wid !== this.getWidth()) {
|
||||
this.setWidth(syncData.wid);
|
||||
}
|
||||
if (syncData.hei !== undefined && syncData.hei !== this.getHeight()) {
|
||||
this.setHeight(syncData.hei);
|
||||
}
|
||||
if (syncData.scaX !== undefined && syncData.scaX !== this.getScaleX()) {
|
||||
this.setScaleX(syncData.scaX);
|
||||
}
|
||||
|
@@ -13,7 +13,8 @@ void DeclareSystemInfoExtension(gd::PlatformExtension& extension) {
|
||||
.SetExtensionInformation(
|
||||
"SystemInfo",
|
||||
_("System information"),
|
||||
_("Get information about the system and device running the game."),
|
||||
_("Conditions to check if the device has a touchscreen, is a mobile, "
|
||||
"or if the game runs as a preview."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("Advanced");
|
||||
|
@@ -78,6 +78,9 @@ module.exports = {
|
||||
} else if (propertyName === 'disabled') {
|
||||
objectContent.disabled = newValue === '1';
|
||||
return true;
|
||||
} else if (propertyName === 'spellCheck') {
|
||||
objectContent.spellCheck = newValue === '1';
|
||||
return true;
|
||||
} else if (propertyName === 'maxLength') {
|
||||
objectContent.maxLength = newValue;
|
||||
return true;
|
||||
@@ -131,14 +134,14 @@ module.exports = {
|
||||
.getOrCreate('inputType')
|
||||
.setValue(objectContent.inputType || '')
|
||||
.setType('choice')
|
||||
.addExtraInfo('text')
|
||||
.addExtraInfo('text area')
|
||||
.addExtraInfo('email')
|
||||
.addExtraInfo('password')
|
||||
.addExtraInfo('number')
|
||||
.addExtraInfo('telephone number')
|
||||
.addExtraInfo('url')
|
||||
.addExtraInfo('search')
|
||||
.addChoice('text', _('Text'))
|
||||
.addChoice('text area', _('Text area'))
|
||||
.addChoice('email', _('Email'))
|
||||
.addChoice('password', _('Password'))
|
||||
.addChoice('number', _('Number'))
|
||||
.addChoice('telephone number', _('Telephone number'))
|
||||
.addChoice('url', _('URL'))
|
||||
.addChoice('search', _('Search'))
|
||||
.setLabel(_('Input type'))
|
||||
.setDescription(
|
||||
_(
|
||||
@@ -160,6 +163,13 @@ module.exports = {
|
||||
.setLabel(_('Disabled'))
|
||||
.setGroup(_('Field'));
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('spellCheck')
|
||||
.setValue(objectContent.spellCheck ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Enable spell check'))
|
||||
.setGroup(_('Field'));
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('textColor')
|
||||
.setValue(objectContent.textColor || '0;0;0')
|
||||
@@ -250,9 +260,9 @@ module.exports = {
|
||||
.getOrCreate('textAlign')
|
||||
.setValue(objectContent.textAlign || 'left')
|
||||
.setType('choice')
|
||||
.addExtraInfo('left')
|
||||
.addExtraInfo('center')
|
||||
.addExtraInfo('right')
|
||||
.addChoice('left', _('Left'))
|
||||
.addChoice('center', _('Center'))
|
||||
.addChoice('right', _('Right'))
|
||||
.setLabel(_('Text alignment'))
|
||||
.setGroup(_('Field appearance'));
|
||||
|
||||
@@ -272,6 +282,7 @@ module.exports = {
|
||||
borderWidth: 1,
|
||||
readOnly: false,
|
||||
disabled: false,
|
||||
spellCheck: false,
|
||||
paddingX: 2,
|
||||
paddingY: 1,
|
||||
textAlign: 'left',
|
||||
@@ -592,6 +603,21 @@ module.exports = {
|
||||
.setFunctionName('setDisabled')
|
||||
.setGetter('isDisabled');
|
||||
|
||||
object
|
||||
.addExpressionAndConditionAndAction(
|
||||
'boolean',
|
||||
'SpellCheck',
|
||||
_('Spell check enabled'),
|
||||
_('spell check is enabled'),
|
||||
_('spell check enabled'),
|
||||
'',
|
||||
'res/conditions/text24_black.png'
|
||||
)
|
||||
.addParameter('object', _('Text input'), 'TextInputObject', false)
|
||||
.useStandardParameters('boolean', gd.ParameterOptions.makeNewOptions())
|
||||
.setFunctionName('setSpellCheck')
|
||||
.setGetter('isSpellCheckEnabled');
|
||||
|
||||
// Other expressions/conditions/actions:
|
||||
|
||||
// Deprecated
|
||||
|
@@ -106,6 +106,7 @@ namespace gdjs {
|
||||
this.updateBorderWidth();
|
||||
this.updateDisabled();
|
||||
this.updateReadOnly();
|
||||
this.updateSpellCheck();
|
||||
this.updateTextAlign();
|
||||
this.updateMaxLength();
|
||||
this.updatePadding();
|
||||
@@ -342,6 +343,12 @@ namespace gdjs {
|
||||
this._input.readOnly = this._object.isReadOnly();
|
||||
}
|
||||
|
||||
updateSpellCheck() {
|
||||
if (!this._input) return;
|
||||
|
||||
this._input.spellcheck = this._object.isSpellCheckEnabled();
|
||||
}
|
||||
|
||||
updateMaxLength() {
|
||||
const input = this._input;
|
||||
if (!input) return;
|
||||
|
@@ -54,6 +54,7 @@ namespace gdjs {
|
||||
disabled: boolean;
|
||||
readOnly: boolean;
|
||||
// ---- Values can be undefined because of support for these feature was added in v5.5.222.
|
||||
spellCheck?: boolean;
|
||||
paddingX?: float;
|
||||
paddingY?: float;
|
||||
textAlign?: SupportedTextAlign;
|
||||
@@ -64,8 +65,6 @@ namespace gdjs {
|
||||
|
||||
export type TextInputNetworkSyncDataType = {
|
||||
opa: float;
|
||||
wid: float;
|
||||
hei: float;
|
||||
txt: string;
|
||||
frn: string;
|
||||
fs: number;
|
||||
@@ -79,6 +78,7 @@ namespace gdjs {
|
||||
bw: float;
|
||||
dis: boolean;
|
||||
ro: boolean;
|
||||
sc: boolean;
|
||||
};
|
||||
|
||||
export type TextInputNetworkSyncData = ObjectNetworkSyncData &
|
||||
@@ -118,6 +118,7 @@ namespace gdjs {
|
||||
private _borderWidth: float;
|
||||
private _disabled: boolean;
|
||||
private _readOnly: boolean;
|
||||
private _spellCheck: boolean;
|
||||
private _isSubmitted: boolean;
|
||||
_renderer: TextInputRuntimeObjectRenderer;
|
||||
|
||||
@@ -142,6 +143,10 @@ namespace gdjs {
|
||||
this._borderWidth = objectData.content.borderWidth;
|
||||
this._disabled = objectData.content.disabled;
|
||||
this._readOnly = objectData.content.readOnly;
|
||||
this._spellCheck =
|
||||
objectData.content.spellCheck !== undefined
|
||||
? objectData.content.spellCheck
|
||||
: false;
|
||||
this._textAlign = parseTextAlign(objectData.content.textAlign);
|
||||
this._maxLength = objectData.content.maxLength || 0;
|
||||
this._paddingX =
|
||||
@@ -228,6 +233,12 @@ namespace gdjs {
|
||||
if (oldObjectData.content.readOnly !== newObjectData.content.readOnly) {
|
||||
this.setReadOnly(newObjectData.content.readOnly);
|
||||
}
|
||||
if (
|
||||
newObjectData.content.spellCheck !== undefined &&
|
||||
oldObjectData.content.spellCheck !== newObjectData.content.spellCheck
|
||||
) {
|
||||
this.setSpellCheck(newObjectData.content.spellCheck);
|
||||
}
|
||||
if (
|
||||
newObjectData.content.maxLength !== undefined &&
|
||||
oldObjectData.content.maxLength !== newObjectData.content.maxLength
|
||||
@@ -260,8 +271,6 @@ namespace gdjs {
|
||||
return {
|
||||
...super.getNetworkSyncData(),
|
||||
opa: this.getOpacity(),
|
||||
wid: this.getWidth(),
|
||||
hei: this.getHeight(),
|
||||
txt: this.getText(),
|
||||
frn: this.getFontResourceName(),
|
||||
fs: this.getFontSize(),
|
||||
@@ -275,6 +284,7 @@ namespace gdjs {
|
||||
bw: this.getBorderWidth(),
|
||||
dis: this.isDisabled(),
|
||||
ro: this.isReadOnly(),
|
||||
sc: this.isSpellCheckEnabled(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -282,8 +292,6 @@ namespace gdjs {
|
||||
super.updateFromNetworkSyncData(syncData);
|
||||
|
||||
if (syncData.opa !== undefined) this.setOpacity(syncData.opa);
|
||||
if (syncData.wid !== undefined) this.setWidth(syncData.wid);
|
||||
if (syncData.hei !== undefined) this.setHeight(syncData.hei);
|
||||
if (syncData.txt !== undefined) this.setText(syncData.txt);
|
||||
if (syncData.frn !== undefined) this.setFontResourceName(syncData.frn);
|
||||
if (syncData.fs !== undefined) this.setFontSize(syncData.fs);
|
||||
@@ -297,6 +305,7 @@ namespace gdjs {
|
||||
if (syncData.bw !== undefined) this.setBorderWidth(syncData.bw);
|
||||
if (syncData.dis !== undefined) this.setDisabled(syncData.dis);
|
||||
if (syncData.ro !== undefined) this.setReadOnly(syncData.ro);
|
||||
if (syncData.sc !== undefined) this.setSpellCheck(syncData.sc);
|
||||
}
|
||||
|
||||
updatePreRender(instanceContainer: RuntimeInstanceContainer): void {
|
||||
@@ -569,6 +578,15 @@ namespace gdjs {
|
||||
return this._readOnly;
|
||||
}
|
||||
|
||||
setSpellCheck(value: boolean) {
|
||||
this._spellCheck = value;
|
||||
this._renderer.updateSpellCheck();
|
||||
}
|
||||
|
||||
isSpellCheckEnabled(): boolean {
|
||||
return this._spellCheck;
|
||||
}
|
||||
|
||||
isFocused(): boolean {
|
||||
return this._renderer.isFocused();
|
||||
}
|
||||
|
@@ -449,6 +449,16 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardParameters("number", gd::ParameterOptions::MakeNewOptions());
|
||||
|
||||
obj.AddExpressionAndConditionAndAction("number",
|
||||
"LineHeight",
|
||||
_("Line height"),
|
||||
_("the line height of a text object"),
|
||||
_("the line height"),
|
||||
"",
|
||||
"res/actions/font24.png")
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardParameters("number", gd::ParameterOptions::MakeNewOptions());
|
||||
|
||||
// Support for deprecated "Size" actions/conditions:
|
||||
obj.AddDuplicatedAction("Size", "Text::SetFontSize").SetHidden();
|
||||
obj.AddDuplicatedCondition("Size", "Text::FontSize").SetHidden();
|
||||
|
@@ -96,6 +96,14 @@ class TextObjectJsExtension : public gd::PlatformExtension {
|
||||
.SetFunctionName("setOutlineThickness")
|
||||
.SetGetter("getOutlineThickness");
|
||||
|
||||
GetAllExpressionsForObject("TextObject::Text")["LineHeight"]
|
||||
.SetFunctionName("getLineHeight");
|
||||
GetAllConditionsForObject("TextObject::Text")["TextObject::Text::LineHeight"]
|
||||
.SetFunctionName("getLineHeight");
|
||||
GetAllActionsForObject("TextObject::Text")["TextObject::Text::SetLineHeight"]
|
||||
.SetFunctionName("setLineHeight")
|
||||
.SetGetter("getLineHeight");
|
||||
|
||||
GetAllActionsForObject("TextObject::Text")["TextObject::ShowShadow"]
|
||||
.SetFunctionName("showShadow");
|
||||
GetAllConditionsForObject("TextObject::Text")["TextObject::Text::IsShadowEnabled"]
|
||||
|
@@ -20,6 +20,7 @@ using namespace std;
|
||||
TextObject::TextObject()
|
||||
: text("Text"),
|
||||
characterSize(20),
|
||||
lineHeight(0),
|
||||
fontName(""),
|
||||
smoothed(true),
|
||||
bold(false),
|
||||
@@ -50,6 +51,10 @@ bool TextObject::UpdateProperty(const gd::String& propertyName,
|
||||
characterSize = newValue.To<double>();
|
||||
return true;
|
||||
}
|
||||
if (propertyName == "lineHeight") {
|
||||
lineHeight = newValue.To<double>();
|
||||
return true;
|
||||
}
|
||||
if (propertyName == "font") {
|
||||
fontName = newValue;
|
||||
return true;
|
||||
@@ -129,6 +134,13 @@ std::map<gd::String, gd::PropertyDescriptor> TextObject::GetProperties() const {
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetGroup(_("Font"));
|
||||
|
||||
objectProperties["lineHeight"]
|
||||
.SetValue(gd::String::From(lineHeight))
|
||||
.SetType("number")
|
||||
.SetLabel(_("Line height"))
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetGroup(_("Font"));
|
||||
|
||||
objectProperties["font"]
|
||||
.SetValue(fontName)
|
||||
.SetType("resource")
|
||||
@@ -160,9 +172,9 @@ std::map<gd::String, gd::PropertyDescriptor> TextObject::GetProperties() const {
|
||||
objectProperties["textAlignment"]
|
||||
.SetValue(textAlignment)
|
||||
.SetType("choice")
|
||||
.AddExtraInfo("left")
|
||||
.AddExtraInfo("center")
|
||||
.AddExtraInfo("right")
|
||||
.AddChoice("left", _("Left"))
|
||||
.AddChoice("center", _("Center"))
|
||||
.AddChoice("right", _("Right"))
|
||||
.SetLabel(_("Alignment"))
|
||||
.SetDescription(_("Alignment of the text when multiple lines are displayed"))
|
||||
.SetGroup(_("Font"))
|
||||
@@ -171,9 +183,9 @@ std::map<gd::String, gd::PropertyDescriptor> TextObject::GetProperties() const {
|
||||
objectProperties["verticalTextAlignment"]
|
||||
.SetValue(verticalTextAlignment)
|
||||
.SetType("choice")
|
||||
.AddExtraInfo("top")
|
||||
.AddExtraInfo("center")
|
||||
.AddExtraInfo("bottom")
|
||||
.AddChoice("top", _("Top"))
|
||||
.AddChoice("center", _("Center"))
|
||||
.AddChoice("bottom", _("Bottom"))
|
||||
.SetLabel(_("Vertical alignment"))
|
||||
.SetGroup(_("Font"))
|
||||
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden);
|
||||
@@ -271,6 +283,7 @@ void TextObject::DoUnserializeFrom(gd::Project& project,
|
||||
SetCharacterSize(content.GetChild("characterSize", 0, "CharacterSize")
|
||||
.GetValue()
|
||||
.GetInt());
|
||||
SetLineHeight(content.GetDoubleAttribute("lineHeight", 0));
|
||||
smoothed = content.GetBoolAttribute("smoothed");
|
||||
bold = content.GetBoolAttribute("bold");
|
||||
italic = content.GetBoolAttribute("italic");
|
||||
@@ -339,6 +352,7 @@ void TextObject::DoSerializeTo(gd::SerializerElement& element) const {
|
||||
content.AddChild("textAlignment").SetValue(GetTextAlignment());
|
||||
content.AddChild("verticalTextAlignment").SetValue(GetVerticalTextAlignment());
|
||||
content.AddChild("characterSize").SetValue(GetCharacterSize());
|
||||
content.AddChild("lineHeight").SetValue(GetLineHeight());
|
||||
content.AddChild("color").SetValue(GetColor());
|
||||
|
||||
content.SetAttribute("smoothed", smoothed);
|
||||
|
@@ -49,6 +49,12 @@ class GD_EXTENSION_API TextObject : public gd::ObjectConfiguration {
|
||||
*/
|
||||
inline double GetCharacterSize() const { return characterSize; };
|
||||
|
||||
/** \brief Change the line height. */
|
||||
inline void SetLineHeight(double value) { lineHeight = value; };
|
||||
|
||||
/** \brief Get the line height. */
|
||||
inline double GetLineHeight() const { return lineHeight; };
|
||||
|
||||
/** \brief Return the name of the font resource used for the text.
|
||||
*/
|
||||
inline const gd::String& GetFontName() const { return fontName; };
|
||||
@@ -120,6 +126,7 @@ class GD_EXTENSION_API TextObject : public gd::ObjectConfiguration {
|
||||
|
||||
gd::String text;
|
||||
double characterSize;
|
||||
double lineHeight;
|
||||
gd::String fontName;
|
||||
bool smoothed;
|
||||
bool bold, italic, underlined;
|
||||
|
@@ -86,6 +86,7 @@ namespace gdjs {
|
||||
? style.dropShadowDistance + style.dropShadowBlur
|
||||
: 0;
|
||||
style.padding = Math.ceil(this._object._padding + extraPaddingForShadow);
|
||||
style.lineHeight = this._object._lineHeight;
|
||||
|
||||
// Prevent spikey outlines by adding a miter limit
|
||||
style.miterLimit = 3;
|
||||
|
@@ -22,6 +22,8 @@ namespace gdjs {
|
||||
text: string;
|
||||
textAlignment: string;
|
||||
verticalTextAlignment: string;
|
||||
/** The line height */
|
||||
lineHeight: float;
|
||||
|
||||
isOutlineEnabled: boolean;
|
||||
outlineThickness: float;
|
||||
@@ -62,6 +64,7 @@ namespace gdjs {
|
||||
sha: float;
|
||||
shb: float;
|
||||
pad: integer;
|
||||
lh: float;
|
||||
};
|
||||
|
||||
export type TextObjectNetworkSyncData = ObjectNetworkSyncData &
|
||||
@@ -101,6 +104,8 @@ namespace gdjs {
|
||||
_shadowAngle: float;
|
||||
_shadowBlur: float;
|
||||
|
||||
_lineHeight: float;
|
||||
|
||||
_padding: integer = 5;
|
||||
_str: string;
|
||||
_renderer: gdjs.TextRuntimeObjectRenderer;
|
||||
@@ -139,6 +144,7 @@ namespace gdjs {
|
||||
this._shadowDistance = content.shadowDistance;
|
||||
this._shadowBlur = content.shadowBlurRadius;
|
||||
this._shadowAngle = content.shadowAngle;
|
||||
this._lineHeight = content.lineHeight || 0;
|
||||
|
||||
this._renderer = new gdjs.TextRuntimeObjectRenderer(
|
||||
this,
|
||||
@@ -149,7 +155,7 @@ namespace gdjs {
|
||||
this.onCreated();
|
||||
}
|
||||
|
||||
updateFromObjectData(
|
||||
override updateFromObjectData(
|
||||
oldObjectData: TextObjectData,
|
||||
newObjectData: TextObjectData
|
||||
): boolean {
|
||||
@@ -211,10 +217,13 @@ namespace gdjs {
|
||||
if (oldContent.shadowBlurRadius !== newContent.shadowBlurRadius) {
|
||||
this.setShadowBlurRadius(newContent.shadowBlurRadius);
|
||||
}
|
||||
if ((oldContent.lineHeight || 0) !== (newContent.lineHeight || 0)) {
|
||||
this.setLineHeight(newContent.lineHeight || 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
getNetworkSyncData(): TextObjectNetworkSyncData {
|
||||
override getNetworkSyncData(): TextObjectNetworkSyncData {
|
||||
return {
|
||||
...super.getNetworkSyncData(),
|
||||
str: this._str,
|
||||
@@ -238,11 +247,12 @@ namespace gdjs {
|
||||
shd: this._shadowDistance,
|
||||
sha: this._shadowAngle,
|
||||
shb: this._shadowBlur,
|
||||
lh: this._lineHeight,
|
||||
pad: this._padding,
|
||||
};
|
||||
}
|
||||
|
||||
updateFromNetworkSyncData(
|
||||
override updateFromNetworkSyncData(
|
||||
networkSyncData: TextObjectNetworkSyncData
|
||||
): void {
|
||||
super.updateFromNetworkSyncData(networkSyncData);
|
||||
@@ -312,28 +322,30 @@ namespace gdjs {
|
||||
if (networkSyncData.shb !== undefined) {
|
||||
this.setShadowBlurRadius(networkSyncData.shb);
|
||||
}
|
||||
if (networkSyncData.lh !== undefined) {
|
||||
this.setLineHeight(networkSyncData.lh);
|
||||
}
|
||||
if (networkSyncData.pad !== undefined) {
|
||||
this.setPadding(networkSyncData.pad);
|
||||
}
|
||||
}
|
||||
|
||||
getRendererObject() {
|
||||
override getRendererObject() {
|
||||
return this._renderer.getRendererObject();
|
||||
}
|
||||
|
||||
update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
override update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
this._renderer.ensureUpToDate();
|
||||
}
|
||||
|
||||
onDestroyed(): void {
|
||||
override onDestroyed(): void {
|
||||
super.onDestroyed();
|
||||
this._renderer.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the extra parameters that could be set for an instance.
|
||||
*/
|
||||
extraInitializationFromInitialInstance(initialInstanceData: InstanceData) {
|
||||
override extraInitializationFromInitialInstance(
|
||||
initialInstanceData: InstanceData
|
||||
) {
|
||||
if (initialInstanceData.customSize) {
|
||||
this.setWrappingWidth(initialInstanceData.width);
|
||||
this.setWrapping(true);
|
||||
@@ -353,27 +365,17 @@ namespace gdjs {
|
||||
this._renderer.updatePosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set object position on X axis.
|
||||
*/
|
||||
setX(x: float): void {
|
||||
override setX(x: float): void {
|
||||
super.setX(x);
|
||||
this._updateTextPosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set object position on Y axis.
|
||||
*/
|
||||
setY(y: float): void {
|
||||
override setY(y: float): void {
|
||||
super.setY(y);
|
||||
this._updateTextPosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the angle of the object.
|
||||
* @param angle The new angle of the object
|
||||
*/
|
||||
setAngle(angle: float): void {
|
||||
override setAngle(angle: float): void {
|
||||
super.setAngle(angle);
|
||||
this._renderer.updateAngle();
|
||||
}
|
||||
@@ -455,6 +457,22 @@ namespace gdjs {
|
||||
this._renderer.updateStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line height of the text.
|
||||
*/
|
||||
getLineHeight(): float {
|
||||
return this._lineHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the line height of the text.
|
||||
* @param value The new line height for the text.
|
||||
*/
|
||||
setLineHeight(value: float): void {
|
||||
this._lineHeight = value;
|
||||
this._renderer.updateStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the resource to use for the font.
|
||||
* @param fontResourceName The name of the font resource.
|
||||
@@ -499,14 +517,14 @@ namespace gdjs {
|
||||
/**
|
||||
* Get width of the text.
|
||||
*/
|
||||
getWidth(): float {
|
||||
override getWidth(): float {
|
||||
return this._wrapping ? this._wrappingWidth : this._renderer.getWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get height of the text.
|
||||
*/
|
||||
getHeight(): float {
|
||||
override getHeight(): float {
|
||||
return this._renderer.getHeight();
|
||||
}
|
||||
|
||||
@@ -584,16 +602,10 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Change the text color.
|
||||
* @param colorString color as a "R;G;B" string, for example: "255;0;0"
|
||||
* @param rgbOrHexColor color as a "R;G;B" string, for example: "255;0;0"
|
||||
*/
|
||||
setColor(colorString: string): void {
|
||||
const color = colorString.split(';');
|
||||
if (color.length < 3) {
|
||||
return;
|
||||
}
|
||||
this._color[0] = parseInt(color[0], 10);
|
||||
this._color[1] = parseInt(color[1], 10);
|
||||
this._color[2] = parseInt(color[2], 10);
|
||||
setColor(rgbOrHexColor: string): void {
|
||||
this._color = gdjs.rgbOrHexToRGBColor(rgbOrHexColor);
|
||||
this._useGradient = false;
|
||||
this._renderer.updateStyle();
|
||||
}
|
||||
@@ -685,11 +697,11 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
setWidth(width: float): void {
|
||||
override setWidth(width: float): void {
|
||||
this.setWrappingWidth(width);
|
||||
}
|
||||
|
||||
getDrawableY(): float {
|
||||
override getDrawableY(): float {
|
||||
return (
|
||||
this.getY() -
|
||||
(this._verticalTextAlignment === 'center'
|
||||
@@ -702,18 +714,12 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Set the outline for the text object.
|
||||
* @param str color as a "R;G;B" string, for example: "255;0;0"
|
||||
* @param rgbOrHexColor color as a "R;G;B" string, for example: "255;0;0"
|
||||
* @param thickness thickness of the outline (0 = disabled)
|
||||
* @deprecated Prefer independent setters.
|
||||
*/
|
||||
setOutline(str: string, thickness: number): void {
|
||||
const color = str.split(';');
|
||||
if (color.length < 3) {
|
||||
return;
|
||||
}
|
||||
this._outlineColor[0] = parseInt(color[0], 10);
|
||||
this._outlineColor[1] = parseInt(color[1], 10);
|
||||
this._outlineColor[2] = parseInt(color[2], 10);
|
||||
setOutline(rgbOrHexColor: string, thickness: number): void {
|
||||
this._outlineColor = gdjs.rgbOrHexToRGBColor(rgbOrHexColor);
|
||||
this._outlineThickness = thickness;
|
||||
this._renderer.updateStyle();
|
||||
}
|
||||
@@ -755,25 +761,19 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Set the shadow for the text object.
|
||||
* @param str color as a "R;G;B" string, for example: "255;0;0"
|
||||
* @param rgbOrHexColor color as a "R;G;B" string, for example: "255;0;0"
|
||||
* @param distance distance between the shadow and the text, in pixels.
|
||||
* @param blur amount of shadow blur, in pixels.
|
||||
* @param angle shadow offset direction, in degrees.
|
||||
* @deprecated Prefer independent setters.
|
||||
*/
|
||||
setShadow(
|
||||
str: string,
|
||||
rgbOrHexColor: string,
|
||||
distance: number,
|
||||
blur: integer,
|
||||
angle: float
|
||||
): void {
|
||||
const color = str.split(';');
|
||||
if (color.length < 3) {
|
||||
return;
|
||||
}
|
||||
this._shadowColor[0] = parseInt(color[0], 10);
|
||||
this._shadowColor[1] = parseInt(color[1], 10);
|
||||
this._shadowColor[2] = parseInt(color[2], 10);
|
||||
this._shadowColor = gdjs.rgbOrHexToRGBColor(rgbOrHexColor);
|
||||
this._shadowDistance = distance;
|
||||
this._shadowBlur = blur;
|
||||
this._shadowAngle = angle;
|
||||
@@ -886,38 +886,18 @@ namespace gdjs {
|
||||
strThirdColor: string,
|
||||
strFourthColor: string
|
||||
): void {
|
||||
const colorFirst = strFirstColor.split(';');
|
||||
const colorSecond = strSecondColor.split(';');
|
||||
const colorThird = strThirdColor.split(';');
|
||||
const colorFourth = strFourthColor.split(';');
|
||||
this._gradient = [];
|
||||
if (colorFirst.length == 3) {
|
||||
this._gradient.push([
|
||||
parseInt(colorFirst[0], 10),
|
||||
parseInt(colorFirst[1], 10),
|
||||
parseInt(colorFirst[2], 10),
|
||||
]);
|
||||
if (strFirstColor) {
|
||||
this._gradient.push(gdjs.rgbOrHexToRGBColor(strFirstColor));
|
||||
}
|
||||
if (colorSecond.length == 3) {
|
||||
this._gradient.push([
|
||||
parseInt(colorSecond[0], 10),
|
||||
parseInt(colorSecond[1], 10),
|
||||
parseInt(colorSecond[2], 10),
|
||||
]);
|
||||
if (strSecondColor) {
|
||||
this._gradient.push(gdjs.rgbOrHexToRGBColor(strSecondColor));
|
||||
}
|
||||
if (colorThird.length == 3) {
|
||||
this._gradient.push([
|
||||
parseInt(colorThird[0], 10),
|
||||
parseInt(colorThird[1], 10),
|
||||
parseInt(colorThird[2], 10),
|
||||
]);
|
||||
if (strThirdColor) {
|
||||
this._gradient.push(gdjs.rgbOrHexToRGBColor(strThirdColor));
|
||||
}
|
||||
if (colorFourth.length == 3) {
|
||||
this._gradient.push([
|
||||
parseInt(colorFourth[0], 10),
|
||||
parseInt(colorFourth[1], 10),
|
||||
parseInt(colorFourth[2], 10),
|
||||
]);
|
||||
if (strFourthColor) {
|
||||
this._gradient.push(gdjs.rgbOrHexToRGBColor(strFourthColor));
|
||||
}
|
||||
this._gradientType = strGradientType;
|
||||
this._useGradient = this._gradient.length > 1 ? true : false;
|
||||
|
@@ -102,9 +102,9 @@ const defineTileMap = function (extension, _, gd) {
|
||||
'displayMode',
|
||||
new gd.PropertyDescriptor(objectContent.displayMode)
|
||||
.setType('choice')
|
||||
.addExtraInfo('visible')
|
||||
.addExtraInfo('all')
|
||||
.addExtraInfo('index')
|
||||
.addChoice('visible', _('Visible layers'))
|
||||
.addChoice('all', _('All layers'))
|
||||
.addChoice('index', _('Only the layer with the specified index'))
|
||||
.setLabel(_('Display mode'))
|
||||
.setGroup(_('Appearance'))
|
||||
);
|
||||
|
@@ -17,8 +17,6 @@ namespace gdjs {
|
||||
export type SimpleTileMapNetworkSyncDataType = {
|
||||
op: number;
|
||||
ai: string;
|
||||
wid: number;
|
||||
hei: number;
|
||||
// TODO: Support tilemap synchronization. Find an efficient way to send tiles changes.
|
||||
};
|
||||
|
||||
@@ -170,8 +168,6 @@ namespace gdjs {
|
||||
...super.getNetworkSyncData(),
|
||||
op: this._opacity,
|
||||
ai: this._atlasImage,
|
||||
wid: this.getWidth(),
|
||||
hei: this.getHeight(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -186,18 +182,6 @@ namespace gdjs {
|
||||
) {
|
||||
this.setOpacity(networkSyncData.op);
|
||||
}
|
||||
if (
|
||||
networkSyncData.wid !== undefined &&
|
||||
networkSyncData.wid !== this.getWidth()
|
||||
) {
|
||||
this.setWidth(networkSyncData.wid);
|
||||
}
|
||||
if (
|
||||
networkSyncData.hei !== undefined &&
|
||||
networkSyncData.hei !== this.getHeight()
|
||||
) {
|
||||
this.setHeight(networkSyncData.hei);
|
||||
}
|
||||
if (networkSyncData.ai !== undefined) {
|
||||
// TODO: support changing the atlas texture
|
||||
}
|
||||
|
@@ -26,8 +26,6 @@ namespace gdjs {
|
||||
os: float;
|
||||
fo: float;
|
||||
oo: float;
|
||||
wid: float;
|
||||
hei: float;
|
||||
};
|
||||
|
||||
export type TilemapCollisionMaskNetworkSyncData = ObjectNetworkSyncData &
|
||||
@@ -202,8 +200,6 @@ namespace gdjs {
|
||||
os: this.getOutlineSize(),
|
||||
fo: this.getFillOpacity(),
|
||||
oo: this.getOutlineOpacity(),
|
||||
wid: this.getWidth(),
|
||||
hei: this.getHeight(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -236,12 +232,6 @@ namespace gdjs {
|
||||
if (networkSyncData.oo !== undefined) {
|
||||
this.setOutlineOpacity(networkSyncData.oo);
|
||||
}
|
||||
if (networkSyncData.wid !== undefined) {
|
||||
this.setWidth(networkSyncData.wid);
|
||||
}
|
||||
if (networkSyncData.hei !== undefined) {
|
||||
this.setHeight(networkSyncData.hei);
|
||||
}
|
||||
}
|
||||
|
||||
extraInitializationFromInitialInstance(initialInstanceData): void {
|
||||
|
@@ -25,8 +25,6 @@ namespace gdjs {
|
||||
lai: number;
|
||||
lei: number;
|
||||
asps: number;
|
||||
wid: number;
|
||||
hei: number;
|
||||
};
|
||||
|
||||
export type TilemapNetworkSyncData = ObjectNetworkSyncData &
|
||||
@@ -158,8 +156,6 @@ namespace gdjs {
|
||||
lai: this._layerIndex,
|
||||
lei: this._levelIndex,
|
||||
asps: this._animationSpeedScale,
|
||||
wid: this.getWidth(),
|
||||
hei: this.getHeight(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -190,12 +186,6 @@ namespace gdjs {
|
||||
if (networkSyncData.asps !== undefined) {
|
||||
this.setAnimationSpeedScale(networkSyncData.asps);
|
||||
}
|
||||
if (networkSyncData.wid !== undefined) {
|
||||
this.setWidth(networkSyncData.wid);
|
||||
}
|
||||
if (networkSyncData.hei !== undefined) {
|
||||
this.setHeight(networkSyncData.hei);
|
||||
}
|
||||
}
|
||||
|
||||
extraInitializationFromInitialInstance(initialInstanceData): void {
|
||||
|
@@ -17,7 +17,7 @@ void DeclareTiledSpriteObjectExtension(gd::PlatformExtension& extension) {
|
||||
.SetExtensionInformation(
|
||||
"TiledSpriteObject",
|
||||
_("Tiled Sprite Object"),
|
||||
"Displays an image in a repeating pattern over an area. Useful for "
|
||||
"Displays a 2D image in a repeating pattern over an area. Useful for "
|
||||
"making backgrounds, including background that are scrolling when "
|
||||
"the camera moves. This is more performant than using multiple "
|
||||
"Sprite objects.",
|
||||
|
@@ -92,28 +92,18 @@ namespace gdjs {
|
||||
-this._object._yOffset % this._tiledSprite.texture.height;
|
||||
}
|
||||
|
||||
setColor(rgbColor: string): void {
|
||||
const colors = rgbColor.split(';');
|
||||
if (colors.length < 3) {
|
||||
return;
|
||||
}
|
||||
this._tiledSprite.tint =
|
||||
'0x' +
|
||||
gdjs.rgbToHex(
|
||||
parseInt(colors[0], 10),
|
||||
parseInt(colors[1], 10),
|
||||
parseInt(colors[2], 10)
|
||||
);
|
||||
setColor(rgbOrHexColor: string): void {
|
||||
this._tiledSprite.tint = gdjs.rgbOrHexStringToNumber(rgbOrHexColor);
|
||||
}
|
||||
|
||||
getColor() {
|
||||
const rgb = new PIXI.Color(this._tiledSprite.tint).toRgbArray();
|
||||
return (
|
||||
Math.floor(rgb[0] * 255) +
|
||||
Math.round(rgb[0] * 255) +
|
||||
';' +
|
||||
Math.floor(rgb[1] * 255) +
|
||||
Math.round(rgb[1] * 255) +
|
||||
';' +
|
||||
Math.floor(rgb[2] * 255)
|
||||
Math.round(rgb[2] * 255)
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -15,8 +15,6 @@ namespace gdjs {
|
||||
export type TiledSpriteObjectData = ObjectData & TiledSpriteObjectDataType;
|
||||
|
||||
export type TiledSpriteNetworkSyncDataType = {
|
||||
wid: number;
|
||||
hei: number;
|
||||
xo: number;
|
||||
yo: number;
|
||||
op: number;
|
||||
@@ -83,8 +81,6 @@ namespace gdjs {
|
||||
getNetworkSyncData(): TiledSpriteNetworkSyncData {
|
||||
return {
|
||||
...super.getNetworkSyncData(),
|
||||
wid: this.getWidth(),
|
||||
hei: this.getHeight(),
|
||||
xo: this.getXOffset(),
|
||||
yo: this.getYOffset(),
|
||||
op: this.getOpacity(),
|
||||
@@ -99,12 +95,6 @@ namespace gdjs {
|
||||
|
||||
// Texture is not synchronized, see if this is asked or not.
|
||||
|
||||
if (networkSyncData.wid !== undefined) {
|
||||
this.setWidth(networkSyncData.wid);
|
||||
}
|
||||
if (networkSyncData.hei !== undefined) {
|
||||
this.setHeight(networkSyncData.hei);
|
||||
}
|
||||
if (networkSyncData.xo !== undefined) {
|
||||
this.setXOffset(networkSyncData.xo);
|
||||
}
|
||||
|
@@ -16,8 +16,11 @@ void DeclareTopDownMovementBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
.SetExtensionInformation(
|
||||
"TopDownMovementBehavior",
|
||||
_("Top-down movement"),
|
||||
_("Allows to move objects in either 4 or 8 directions, with the "
|
||||
"keyboard or using events."),
|
||||
_("Allows to move an object in either 4 or 8 directions, with the "
|
||||
"keyboard (default), a virtual stick (for this, also add the "
|
||||
"\"Top-down multitouch controller mapper\" behavior and a"
|
||||
"\"Multitouch Joystick\" object), gamepad or manually using "
|
||||
"events."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("Movement")
|
||||
@@ -26,17 +29,17 @@ void DeclareTopDownMovementBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Top-down movement"))
|
||||
.SetIcon("CppPlatform/Extensions/topdownmovementicon16.png");
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
"TopDownMovementBehavior",
|
||||
_("Top-down movement (4 or 8 directions)"),
|
||||
"TopDownMovement",
|
||||
_("Move objects left, up, right, and "
|
||||
"down (and, optionally, diagonally)."),
|
||||
"",
|
||||
"CppPlatform/Extensions/topdownmovementicon.png",
|
||||
"TopDownMovementBehavior",
|
||||
std::make_shared<TopDownMovementBehavior>(),
|
||||
std::make_shared<gd::BehaviorsSharedData>());
|
||||
gd::BehaviorMetadata& aut =
|
||||
extension.AddBehavior("TopDownMovementBehavior",
|
||||
_("Top-down movement (4 or 8 directions)"),
|
||||
"TopDownMovement",
|
||||
_("Move objects left, up, right, and "
|
||||
"down (and, optionally, diagonally)."),
|
||||
"",
|
||||
"CppPlatform/Extensions/topdownmovementicon.png",
|
||||
"TopDownMovementBehavior",
|
||||
std::make_shared<TopDownMovementBehavior>(),
|
||||
std::make_shared<gd::BehaviorsSharedData>());
|
||||
|
||||
aut.AddAction("SimulateLeftKey",
|
||||
_("Simulate left key press"),
|
||||
@@ -119,7 +122,8 @@ void DeclareTopDownMovementBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
aut.AddAction("SimulateStick",
|
||||
_("Simulate stick control"),
|
||||
_("Simulate a stick control."),
|
||||
_("Simulate a stick control for _PARAM0_ with a _PARAM2_ angle and a _PARAM3_ force"),
|
||||
_("Simulate a stick control for _PARAM0_ with a _PARAM2_ angle "
|
||||
"and a _PARAM3_ force"),
|
||||
_("Top-down controls"),
|
||||
"res/conditions/keyboard24.png",
|
||||
"res/conditions/keyboard.png")
|
||||
@@ -130,25 +134,28 @@ void DeclareTopDownMovementBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
.MarkAsAdvanced()
|
||||
.SetFunctionName("SimulateStick");
|
||||
|
||||
aut.AddScopedCondition("IsUsingControl",
|
||||
_("Control pressed or simulated"),
|
||||
_("A control was applied from a default control or simulated by an action."),
|
||||
_("_PARAM0_ has the _PARAM2_ key pressed or simulated"),
|
||||
_("Top-down state"),
|
||||
"res/conditions/keyboard24.png",
|
||||
"res/conditions/keyboard.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "TopDownMovementBehavior")
|
||||
.AddParameter("stringWithSelector",
|
||||
aut.AddScopedCondition(
|
||||
"IsUsingControl",
|
||||
_("Control pressed or simulated"),
|
||||
_("A control was applied from a default control or simulated by an "
|
||||
"action."),
|
||||
_("_PARAM0_ has the _PARAM2_ key pressed or simulated"),
|
||||
_("Top-down state"),
|
||||
"res/conditions/keyboard24.png",
|
||||
"res/conditions/keyboard.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "TopDownMovementBehavior")
|
||||
.AddParameter("stringWithSelector",
|
||||
_("Key"),
|
||||
"[\"Left\", \"Right\", \"Up\", \"Down\", \"Stick\"]")
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced();
|
||||
|
||||
aut.AddExpression("StickAngle",
|
||||
_("Stick angle"),
|
||||
_("Return the angle of the simulated stick input (in degrees)"),
|
||||
_("Top-down controls"),
|
||||
"CppPlatform/Extensions/topdownmovementicon16.png")
|
||||
aut.AddExpression(
|
||||
"StickAngle",
|
||||
_("Stick angle"),
|
||||
_("Return the angle of the simulated stick input (in degrees)"),
|
||||
_("Top-down controls"),
|
||||
"CppPlatform/Extensions/topdownmovementicon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "TopDownMovementBehavior");
|
||||
|
||||
@@ -361,19 +368,19 @@ void DeclareTopDownMovementBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
.MarkAsAdvanced()
|
||||
.SetHidden()
|
||||
.SetFunctionName("GetAngle");
|
||||
|
||||
aut.AddScopedCondition(
|
||||
"IsMovementAngleAround",
|
||||
_("Angle of movement"),
|
||||
_("Compare the angle of the top-down movement of the object."),
|
||||
_("Angle of movement of _PARAM0_ is _PARAM2_ ± _PARAM3_°"),
|
||||
|
||||
aut.AddScopedCondition(
|
||||
"IsMovementAngleAround",
|
||||
_("Angle of movement"),
|
||||
_("Compare the angle of the top-down movement of the object."),
|
||||
_("Angle of movement of _PARAM0_ is _PARAM2_ ± _PARAM3_°"),
|
||||
_("Top-down state"),
|
||||
"CppPlatform/Extensions/topdownmovementicon24.png",
|
||||
"CppPlatform/Extensions/topdownmovementicon16.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "TopDownMovementBehavior")
|
||||
.AddParameter("expression", _("Angle (in degrees)"))
|
||||
.AddParameter("expression", _("Tolerance (in degrees)"));
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "TopDownMovementBehavior")
|
||||
.AddParameter("expression", _("Angle (in degrees)"))
|
||||
.AddParameter("expression", _("Tolerance (in degrees)"));
|
||||
|
||||
aut.AddCondition("XVelocity",
|
||||
_("Speed on X axis"),
|
||||
|
@@ -507,10 +507,6 @@ namespace gdjs {
|
||||
cos = 0;
|
||||
}
|
||||
|
||||
const getAcceleratedSpeed = this._useLegacyTurnBack
|
||||
? TopDownMovementRuntimeBehavior.getLegacyAcceleratedSpeed
|
||||
: TopDownMovementRuntimeBehavior.getAcceleratedSpeed;
|
||||
|
||||
let currentSpeed = Math.hypot(this._xVelocity, this._yVelocity);
|
||||
const dotProduct = this._xVelocity * cos + this._yVelocity * sin;
|
||||
if (dotProduct < 0) {
|
||||
@@ -518,13 +514,14 @@ namespace gdjs {
|
||||
// Keep the negative velocity projected on the new direction.
|
||||
currentSpeed = dotProduct;
|
||||
}
|
||||
const speed = getAcceleratedSpeed(
|
||||
const speed = TopDownMovementRuntimeBehavior.getAcceleratedSpeed(
|
||||
currentSpeed,
|
||||
targetedSpeed,
|
||||
this._maxSpeed,
|
||||
this._acceleration,
|
||||
this._deceleration,
|
||||
timeDelta
|
||||
timeDelta,
|
||||
this._useLegacyTurnBack
|
||||
);
|
||||
this._xVelocity = speed * cos;
|
||||
this._yVelocity = speed * sin;
|
||||
@@ -599,10 +596,13 @@ namespace gdjs {
|
||||
speedMax: float,
|
||||
acceleration: float,
|
||||
deceleration: float,
|
||||
timeDelta: float
|
||||
timeDelta: float,
|
||||
useLegacyTurnBack: boolean = false
|
||||
): float {
|
||||
let newSpeed = currentSpeed;
|
||||
const turningBackAcceleration = Math.max(acceleration, deceleration);
|
||||
const turningBackAcceleration = useLegacyTurnBack
|
||||
? acceleration
|
||||
: Math.max(acceleration, deceleration);
|
||||
if (targetedSpeed < 0) {
|
||||
if (currentSpeed <= targetedSpeed) {
|
||||
// Reduce the speed to match the stick force.
|
||||
@@ -652,62 +652,6 @@ namespace gdjs {
|
||||
return newSpeed;
|
||||
}
|
||||
|
||||
private static getLegacyAcceleratedSpeed(
|
||||
currentSpeed: float,
|
||||
targetedSpeed: float,
|
||||
speedMax: float,
|
||||
acceleration: float,
|
||||
deceleration: float,
|
||||
timeDelta: float
|
||||
): float {
|
||||
let newSpeed = currentSpeed;
|
||||
if (targetedSpeed < 0) {
|
||||
if (currentSpeed <= targetedSpeed) {
|
||||
// Reduce the speed to match the stick force.
|
||||
newSpeed = Math.min(
|
||||
targetedSpeed,
|
||||
currentSpeed + deceleration * timeDelta
|
||||
);
|
||||
} else if (currentSpeed <= 0) {
|
||||
// Accelerate
|
||||
newSpeed -= Math.max(-speedMax, acceleration * timeDelta);
|
||||
} else {
|
||||
newSpeed = Math.max(
|
||||
targetedSpeed,
|
||||
currentSpeed - deceleration * timeDelta
|
||||
);
|
||||
}
|
||||
} else if (targetedSpeed > 0) {
|
||||
if (currentSpeed >= targetedSpeed) {
|
||||
// Reduce the speed to match the stick force.
|
||||
newSpeed = Math.max(
|
||||
targetedSpeed,
|
||||
currentSpeed - deceleration * timeDelta
|
||||
);
|
||||
} else if (currentSpeed >= 0) {
|
||||
// Accelerate
|
||||
newSpeed = Math.min(
|
||||
speedMax,
|
||||
currentSpeed + acceleration * timeDelta
|
||||
);
|
||||
} else {
|
||||
newSpeed = Math.min(
|
||||
targetedSpeed,
|
||||
currentSpeed + deceleration * timeDelta
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Decelerate and stop.
|
||||
if (currentSpeed < 0) {
|
||||
newSpeed = Math.min(currentSpeed + deceleration * timeDelta, 0);
|
||||
}
|
||||
if (currentSpeed > 0) {
|
||||
newSpeed = Math.max(currentSpeed - deceleration * timeDelta, 0);
|
||||
}
|
||||
}
|
||||
return newSpeed;
|
||||
}
|
||||
|
||||
simulateControl(input: string) {
|
||||
if (input === 'Left') {
|
||||
this._leftKey = true;
|
||||
|
@@ -347,17 +347,21 @@ describe('gdjs.TweenRuntimeBehavior', () => {
|
||||
// Check that there is no NaN.
|
||||
for (let i = 0; i < 11; i++) {
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
expect(camera.getCameraZoom(runtimeScene, '', 0)).to.be(0);
|
||||
// The tween tries to set the camera zoom to 0, but it has no effect
|
||||
// because it doesn't make sense.
|
||||
expect(camera.getCameraZoom(runtimeScene, '', 0)).to.be(1);
|
||||
}
|
||||
});
|
||||
|
||||
it('can tween a layer camera zoom from 0', () => {
|
||||
// The zoom stays at 1 because 0 doesn't make sense.
|
||||
camera.setCameraZoom(runtimeScene, 0, '', 0);
|
||||
// Here, it actually tweens from 1 to 1.
|
||||
tween.tweenCameraZoom2(runtimeScene, 'MyTween', 1, '', 'linear', 0.25);
|
||||
// A camera zoom of 0 doesn't make sense.
|
||||
// Check that there is no NaN.
|
||||
for (let i = 0; i < 11; i++) {
|
||||
expect(camera.getCameraZoom(runtimeScene, '', 0)).to.be(0);
|
||||
expect(camera.getCameraZoom(runtimeScene, '', 0)).to.be(1);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
}
|
||||
expect(camera.getCameraZoom(runtimeScene, '', 0)).to.be(1);
|
||||
|
@@ -145,6 +145,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
|
||||
shadowDistance: 4,
|
||||
shadowAngle: 90,
|
||||
shadowBlurRadius: 2,
|
||||
lineHeight: 0,
|
||||
},
|
||||
});
|
||||
runtimeScene.addObject(object);
|
||||
|
@@ -145,6 +145,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
|
||||
shadowDistance: 4,
|
||||
shadowAngle: 90,
|
||||
shadowBlurRadius: 2,
|
||||
lineHeight: 0,
|
||||
},
|
||||
});
|
||||
runtimeScene.addObject(object);
|
||||
|
@@ -1326,11 +1326,11 @@ namespace gdjs {
|
||||
lightness
|
||||
);
|
||||
owner.setColor(
|
||||
Math.floor(rgbFromHslColor[0]) +
|
||||
Math.round(rgbFromHslColor[0]) +
|
||||
';' +
|
||||
Math.floor(rgbFromHslColor[1]) +
|
||||
Math.round(rgbFromHslColor[1]) +
|
||||
';' +
|
||||
Math.floor(rgbFromHslColor[2])
|
||||
Math.round(rgbFromHslColor[2])
|
||||
);
|
||||
};
|
||||
} else {
|
||||
@@ -1439,12 +1439,11 @@ namespace gdjs {
|
||||
if (!isColorable(this.owner)) return;
|
||||
const owner = this.owner;
|
||||
|
||||
const rgbFromColor: string[] = owner.getColor().split(';');
|
||||
if (rgbFromColor.length < 3) return;
|
||||
const rgbFromColor = gdjs.rgbOrHexToRGBColor(owner.getColor());
|
||||
const hslFromColor = gdjs.evtTools.tween.rgbToHsl(
|
||||
parseFloat(rgbFromColor[0]),
|
||||
parseFloat(rgbFromColor[1]),
|
||||
parseFloat(rgbFromColor[2])
|
||||
rgbFromColor[0],
|
||||
rgbFromColor[1],
|
||||
rgbFromColor[2]
|
||||
);
|
||||
|
||||
const toH = animateHue ? toHue : hslFromColor[0];
|
||||
@@ -1474,11 +1473,11 @@ namespace gdjs {
|
||||
);
|
||||
|
||||
owner.setColor(
|
||||
Math.floor(rgbFromHslColor[0]) +
|
||||
Math.round(rgbFromHslColor[0]) +
|
||||
';' +
|
||||
Math.floor(rgbFromHslColor[1]) +
|
||||
Math.round(rgbFromHslColor[1]) +
|
||||
';' +
|
||||
Math.floor(rgbFromHslColor[2])
|
||||
Math.round(rgbFromHslColor[2])
|
||||
);
|
||||
},
|
||||
|
||||
|
@@ -18,8 +18,6 @@ namespace gdjs {
|
||||
|
||||
export type VideoNetworkSyncDataType = {
|
||||
op: float;
|
||||
wid: float;
|
||||
hei: float;
|
||||
// We don't sync volume, as it's probably a user setting?
|
||||
pla: boolean;
|
||||
loop: boolean;
|
||||
@@ -105,8 +103,6 @@ namespace gdjs {
|
||||
return {
|
||||
...super.getNetworkSyncData(),
|
||||
op: this._opacity,
|
||||
wid: this.getWidth(),
|
||||
hei: this.getHeight(),
|
||||
pla: this.isPlayed(),
|
||||
loop: this.isLooped(),
|
||||
ct: this.getCurrentTime(),
|
||||
@@ -120,12 +116,6 @@ namespace gdjs {
|
||||
if (this._opacity !== undefined && this._opacity && syncData.op) {
|
||||
this.setOpacity(syncData.op);
|
||||
}
|
||||
if (this.getWidth() !== undefined && this.getWidth() !== syncData.wid) {
|
||||
this.setWidth(syncData.wid);
|
||||
}
|
||||
if (this.getHeight() !== undefined && this.getHeight() !== syncData.hei) {
|
||||
this.setHeight(syncData.hei);
|
||||
}
|
||||
if (syncData.pla !== undefined && this.isPlayed() !== syncData.pla) {
|
||||
syncData.pla ? this.play() : this.pause();
|
||||
}
|
||||
|
@@ -1228,14 +1228,11 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
// Code only parameter type
|
||||
else if (metadata.GetType() == "objectsContext") {
|
||||
argOutput =
|
||||
"(typeof eventsFunctionContext !== 'undefined' ? eventsFunctionContext "
|
||||
": runtimeScene)";
|
||||
HasProjectAndLayout() ? "runtimeScene" : "eventsFunctionContext";
|
||||
}
|
||||
// Code only parameter type
|
||||
else if (metadata.GetType() == "eventsFunctionContext") {
|
||||
argOutput =
|
||||
"(typeof eventsFunctionContext !== 'undefined' ? eventsFunctionContext "
|
||||
": undefined)";
|
||||
argOutput = HasProjectAndLayout() ? "null" : "eventsFunctionContext";
|
||||
} else
|
||||
return gd::EventsCodeGenerator::GenerateParameterCodes(
|
||||
parameter,
|
||||
|
@@ -21,6 +21,9 @@ AdvancedExtension::AdvancedExtension() {
|
||||
.SetCustomCodeGenerator([](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
if (codeGenerator.HasProjectAndLayout()) {
|
||||
return gd::String("");
|
||||
}
|
||||
gd::String expressionCode =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
@@ -28,15 +31,16 @@ AdvancedExtension::AdvancedExtension() {
|
||||
"number",
|
||||
instruction.GetParameter(0).GetPlainString());
|
||||
|
||||
return "if (typeof eventsFunctionContext !== 'undefined') { "
|
||||
"eventsFunctionContext.returnValue = " +
|
||||
expressionCode + "; }";
|
||||
return "eventsFunctionContext.returnValue = " + expressionCode + ";";
|
||||
});
|
||||
|
||||
GetAllActions()["SetReturnString"]
|
||||
.SetCustomCodeGenerator([](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
if (codeGenerator.HasProjectAndLayout()) {
|
||||
return gd::String("");
|
||||
}
|
||||
gd::String expressionCode =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
@@ -44,29 +48,31 @@ AdvancedExtension::AdvancedExtension() {
|
||||
"string",
|
||||
instruction.GetParameter(0).GetPlainString());
|
||||
|
||||
return "if (typeof eventsFunctionContext !== 'undefined') { "
|
||||
"eventsFunctionContext.returnValue = " +
|
||||
expressionCode + "; }";
|
||||
return "eventsFunctionContext.returnValue = " + expressionCode + ";";
|
||||
});
|
||||
|
||||
GetAllActions()["SetReturnBoolean"]
|
||||
.SetCustomCodeGenerator([](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
if (codeGenerator.HasProjectAndLayout()) {
|
||||
return gd::String("");
|
||||
}
|
||||
// This is duplicated from EventsCodeGenerator::GenerateParameterCodes
|
||||
gd::String parameter = instruction.GetParameter(0).GetPlainString();
|
||||
gd::String booleanCode =
|
||||
(parameter == "True" || parameter == "Vrai") ? "true" : "false";
|
||||
|
||||
return "if (typeof eventsFunctionContext !== 'undefined') { "
|
||||
"eventsFunctionContext.returnValue = " +
|
||||
booleanCode + "; }";
|
||||
return "eventsFunctionContext.returnValue = " + booleanCode + ";";
|
||||
});
|
||||
|
||||
GetAllActions()["CopyArgumentToVariable"]
|
||||
.SetCustomCodeGenerator([](gd::Instruction &instruction,
|
||||
gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
if (codeGenerator.HasProjectAndLayout()) {
|
||||
return gd::String("");
|
||||
}
|
||||
// This is duplicated from EventsCodeGenerator::GenerateParameterCodes
|
||||
gd::String parameter = instruction.GetParameter(0).GetPlainString();
|
||||
gd::String variable =
|
||||
@@ -74,17 +80,17 @@ AdvancedExtension::AdvancedExtension() {
|
||||
codeGenerator, context, "scenevar", instruction.GetParameter(1),
|
||||
"");
|
||||
|
||||
return "if (typeof eventsFunctionContext !== 'undefined') {\n"
|
||||
"gdjs.Variable.copy(eventsFunctionContext.getArgument(" +
|
||||
parameter + "), " + variable +
|
||||
", false);\n"
|
||||
"}\n";
|
||||
return "gdjs.Variable.copy(eventsFunctionContext.getArgument(" +
|
||||
parameter + "), " + variable + ", false);\n";
|
||||
});
|
||||
|
||||
GetAllActions()["CopyArgumentToVariable2"]
|
||||
.SetCustomCodeGenerator([](gd::Instruction &instruction,
|
||||
gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
if (codeGenerator.HasProjectAndLayout()) {
|
||||
return gd::String("");
|
||||
}
|
||||
// This is duplicated from EventsCodeGenerator::GenerateParameterCodes
|
||||
gd::String parameter = instruction.GetParameter(0).GetPlainString();
|
||||
gd::String variable =
|
||||
@@ -92,17 +98,17 @@ AdvancedExtension::AdvancedExtension() {
|
||||
codeGenerator, context, "variable", instruction.GetParameter(1),
|
||||
"");
|
||||
|
||||
return "if (typeof eventsFunctionContext !== 'undefined') {\n"
|
||||
"gdjs.Variable.copy(eventsFunctionContext.getArgument(" +
|
||||
parameter + "), " + variable +
|
||||
", false);\n"
|
||||
"}\n";
|
||||
return "gdjs.Variable.copy(eventsFunctionContext.getArgument(" +
|
||||
parameter + "), " + variable + ", false);\n";
|
||||
});
|
||||
|
||||
GetAllActions()["CopyVariableToArgument"]
|
||||
.SetCustomCodeGenerator([](gd::Instruction &instruction,
|
||||
gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
if (codeGenerator.HasProjectAndLayout()) {
|
||||
return gd::String("");
|
||||
}
|
||||
// This is duplicated from EventsCodeGenerator::GenerateParameterCodes
|
||||
gd::String parameter = instruction.GetParameter(0).GetPlainString();
|
||||
gd::String variable =
|
||||
@@ -110,17 +116,18 @@ AdvancedExtension::AdvancedExtension() {
|
||||
codeGenerator, context, "scenevar", instruction.GetParameter(1),
|
||||
"");
|
||||
|
||||
return "if (typeof eventsFunctionContext !== 'undefined') {\n"
|
||||
"gdjs.Variable.copy(" +
|
||||
variable + ", eventsFunctionContext.getArgument(" + parameter +
|
||||
"), false);\n"
|
||||
"}\n";
|
||||
return "gdjs.Variable.copy(" + variable +
|
||||
", eventsFunctionContext.getArgument(" + parameter +
|
||||
"), false);\n";
|
||||
});
|
||||
|
||||
GetAllActions()["CopyVariableToArgument2"]
|
||||
.SetCustomCodeGenerator([](gd::Instruction &instruction,
|
||||
gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
if (codeGenerator.HasProjectAndLayout()) {
|
||||
return gd::String("");
|
||||
}
|
||||
// This is duplicated from EventsCodeGenerator::GenerateParameterCodes
|
||||
gd::String parameter = instruction.GetParameter(0).GetPlainString();
|
||||
gd::String variable =
|
||||
@@ -128,17 +135,18 @@ AdvancedExtension::AdvancedExtension() {
|
||||
codeGenerator, context, "variable", instruction.GetParameter(1),
|
||||
"");
|
||||
|
||||
return "if (typeof eventsFunctionContext !== 'undefined') {\n"
|
||||
"gdjs.Variable.copy(" +
|
||||
variable + ", eventsFunctionContext.getArgument(" + parameter +
|
||||
"), false);\n"
|
||||
"}\n";
|
||||
return "gdjs.Variable.copy(" + variable +
|
||||
", eventsFunctionContext.getArgument(" + parameter +
|
||||
"), false);\n";
|
||||
});
|
||||
|
||||
GetAllConditions()["GetArgumentAsBoolean"]
|
||||
.SetCustomCodeGenerator([](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
if (codeGenerator.HasProjectAndLayout()) {
|
||||
return gd::String("false");
|
||||
}
|
||||
gd::String parameterNameCode =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
@@ -146,10 +154,8 @@ AdvancedExtension::AdvancedExtension() {
|
||||
"string",
|
||||
instruction.GetParameter(0).GetPlainString());
|
||||
gd::String valueCode =
|
||||
gd::String(instruction.IsInverted() ? "!" : "") +
|
||||
"(typeof eventsFunctionContext !== 'undefined' ? "
|
||||
"!!eventsFunctionContext.getArgument(" +
|
||||
parameterNameCode + ") : false)";
|
||||
gd::String(instruction.IsInverted() ? "!" : "!!") +
|
||||
"eventsFunctionContext.getArgument(" + parameterNameCode + ")";
|
||||
gd::String outputCode =
|
||||
codeGenerator.GenerateUpperScopeBooleanFullName("isConditionTrue", context) +
|
||||
" = " + valueCode + ";\n";
|
||||
@@ -161,6 +167,9 @@ AdvancedExtension::AdvancedExtension() {
|
||||
.SetCustomCodeGenerator([](const std::vector<gd::Expression>& parameters,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
if (codeGenerator.HasProjectAndLayout()) {
|
||||
return gd::String("0");
|
||||
}
|
||||
gd::String parameterNameCode =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
@@ -168,9 +177,8 @@ AdvancedExtension::AdvancedExtension() {
|
||||
"string",
|
||||
!parameters.empty() ? parameters[0].GetPlainString() : "");
|
||||
|
||||
return "(typeof eventsFunctionContext !== 'undefined' ? "
|
||||
"Number(eventsFunctionContext.getArgument(" +
|
||||
parameterNameCode + ")) || 0 : 0)";
|
||||
return "(Number(eventsFunctionContext.getArgument(" + parameterNameCode +
|
||||
")) || 0)";
|
||||
});
|
||||
|
||||
GetAllStrExpressions()["GetArgumentAsString"]
|
||||
@@ -178,6 +186,9 @@ AdvancedExtension::AdvancedExtension() {
|
||||
.SetCustomCodeGenerator([](const std::vector<gd::Expression>& parameters,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
if (codeGenerator.HasProjectAndLayout()) {
|
||||
return gd::String("\"\"");
|
||||
}
|
||||
gd::String parameterNameCode =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
@@ -185,9 +196,8 @@ AdvancedExtension::AdvancedExtension() {
|
||||
"string",
|
||||
!parameters.empty() ? parameters[0].GetPlainString() : "");
|
||||
|
||||
return "(typeof eventsFunctionContext !== 'undefined' ? \"\" + "
|
||||
"eventsFunctionContext.getArgument(" +
|
||||
parameterNameCode + ") : \"\")";
|
||||
return "\"\" + eventsFunctionContext.getArgument(" + parameterNameCode +
|
||||
")";
|
||||
});
|
||||
|
||||
GetAllConditions()["CompareArgumentAsNumber"]
|
||||
@@ -210,12 +220,13 @@ AdvancedExtension::AdvancedExtension() {
|
||||
codeGenerator.GenerateUpperScopeBooleanFullName("isConditionTrue", context);
|
||||
|
||||
return resultingBoolean + " = " +
|
||||
gd::String(instruction.IsInverted() ? "!" : "") +
|
||||
gd::String(instruction.IsInverted() ? "!" : "") + "(" +
|
||||
codeGenerator.GenerateRelationalOperation(
|
||||
operatorString,
|
||||
"((typeof eventsFunctionContext !== 'undefined' ? "
|
||||
"Number(eventsFunctionContext.getArgument(" +
|
||||
parameterNameCode + ")) || 0 : 0)",
|
||||
codeGenerator.HasProjectAndLayout()
|
||||
? "0"
|
||||
: "(Number(eventsFunctionContext.getArgument(" +
|
||||
parameterNameCode + ")) || 0)",
|
||||
operandCode) +
|
||||
");\n";
|
||||
});
|
||||
@@ -240,12 +251,13 @@ AdvancedExtension::AdvancedExtension() {
|
||||
codeGenerator.GenerateUpperScopeBooleanFullName("isConditionTrue", context);
|
||||
|
||||
return resultingBoolean + " = " +
|
||||
gd::String(instruction.IsInverted() ? "!" : "") +
|
||||
gd::String(instruction.IsInverted() ? "!" : "") + "(" +
|
||||
codeGenerator.GenerateRelationalOperation(
|
||||
operatorString,
|
||||
"((typeof eventsFunctionContext !== 'undefined' ? "
|
||||
"\"\" + eventsFunctionContext.getArgument(" +
|
||||
parameterNameCode + ") : \"\")",
|
||||
codeGenerator.HasProjectAndLayout()
|
||||
? "\"\""
|
||||
: "(\"\" + eventsFunctionContext.getArgument(" +
|
||||
parameterNameCode + "))",
|
||||
operandCode) +
|
||||
");\n";
|
||||
});
|
||||
|
@@ -821,8 +821,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
}
|
||||
if (!codeGenerator.HasProjectAndLayout()) {
|
||||
functionParameters += ", eventsFunctionContext";
|
||||
callArguments += ", typeof eventsFunctionContext !== \'undefined\' ? "
|
||||
"eventsFunctionContext : undefined";
|
||||
callArguments += ", eventsFunctionContext";
|
||||
}
|
||||
|
||||
// Generate the function code
|
||||
@@ -842,13 +841,23 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
event.GetParameterObjects(),
|
||||
parentContext.GetCurrentObject());
|
||||
|
||||
callingCode += "var objects = [];\n";
|
||||
for (unsigned int i = 0; i < realObjects.size(); ++i) {
|
||||
parentContext.ObjectsListNeeded(realObjects[i]);
|
||||
if (realObjects.size() == 1) {
|
||||
parentContext.ObjectsListNeeded(realObjects[0]);
|
||||
callingCode +=
|
||||
"objects.push.apply(objects," +
|
||||
codeGenerator.GetObjectListName(realObjects[i], parentContext) +
|
||||
");\n";
|
||||
"const objects = " +
|
||||
codeGenerator.GetObjectListName(realObjects[0], parentContext) +
|
||||
";\n";
|
||||
} else {
|
||||
// Groups are rarely used in JS events so it's fine to make
|
||||
// allocations.
|
||||
callingCode += "const objects = [];\n";
|
||||
for (unsigned int i = 0; i < realObjects.size(); ++i) {
|
||||
parentContext.ObjectsListNeeded(realObjects[i]);
|
||||
callingCode += "objects.push.apply(objects," +
|
||||
codeGenerator.GetObjectListName(realObjects[i],
|
||||
parentContext) +
|
||||
");\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -43,6 +43,10 @@ StringInstructionsExtension::StringInstructionsExtension() {
|
||||
"gdjs.evtTools.string.strFindLastFrom");
|
||||
GetAllExpressions()["StrFindLastFrom"].SetFunctionName(
|
||||
"gdjs.evtTools.string.strFindLastFrom");
|
||||
GetAllStrExpressions()["StrReplaceOne"].SetFunctionName(
|
||||
"gdjs.evtTools.string.strReplaceOne");
|
||||
GetAllStrExpressions()["StrReplaceAll"].SetFunctionName(
|
||||
"gdjs.evtTools.string.strReplaceAll");
|
||||
|
||||
StripUnimplementedInstructionsAndExpressions();
|
||||
}
|
||||
|
@@ -26,6 +26,28 @@ The game engine is in the _Runtime_ folder. If you want to work on the engine di
|
||||
|
||||
- To launch type checking with TypeScript, run `npm install` and `npm run check-types` in `GDJS` folder.
|
||||
|
||||
#### Building GDJS Runtime
|
||||
|
||||
To build the GDJS Runtime, run `npm run build` in the `GDJS` folder.
|
||||
|
||||
**Build Options:**
|
||||
|
||||
- **Production build (default)**: `npm run build` - builds with minification enabled
|
||||
- **Debug build**: `npm run build -- --debug` - builds without minification for easier debugging
|
||||
- **Custom output path**: `npm run build -- --out=/path/to/output` - specify custom output directory
|
||||
|
||||
**Examples:**
|
||||
```bash
|
||||
# Standard production build
|
||||
npm run build
|
||||
|
||||
# Debug build for development (no minification)
|
||||
npm run build -- --debug
|
||||
|
||||
# Debug build with custom output path
|
||||
npm run build -- --debug --out=./debug-build
|
||||
```
|
||||
|
||||
### GDJS Platform (exporters, code generation...)
|
||||
|
||||
Check the [GDJS Platform](https://docs.gdevelop.io/GDJS%20Documentation/index.html) documentation or the [full GDevelop developers documentation](https://docs.gdevelop.io/).
|
||||
|
@@ -17,6 +17,11 @@ namespace gdjs {
|
||||
isInnerAreaFollowingParentSize: boolean;
|
||||
};
|
||||
|
||||
export type CustomObjectNetworkSyncDataType = ObjectNetworkSyncData & {
|
||||
ifx: boolean;
|
||||
ify: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* An object that contains other object.
|
||||
*
|
||||
@@ -216,6 +221,26 @@ namespace gdjs {
|
||||
return true;
|
||||
}
|
||||
|
||||
getNetworkSyncData(): CustomObjectNetworkSyncDataType {
|
||||
return {
|
||||
...super.getNetworkSyncData(),
|
||||
ifx: this.isFlippedX(),
|
||||
ify: this.isFlippedY(),
|
||||
};
|
||||
}
|
||||
|
||||
updateFromNetworkSyncData(
|
||||
networkSyncData: CustomObjectNetworkSyncDataType
|
||||
) {
|
||||
super.updateFromNetworkSyncData(networkSyncData);
|
||||
if (networkSyncData.ifx !== undefined) {
|
||||
this.flipX(networkSyncData.ifx);
|
||||
}
|
||||
if (networkSyncData.ify !== undefined) {
|
||||
this.flipY(networkSyncData.ify);
|
||||
}
|
||||
}
|
||||
|
||||
override extraInitializationFromInitialInstance(
|
||||
initialInstanceData: InstanceData
|
||||
) {
|
||||
@@ -253,7 +278,12 @@ namespace gdjs {
|
||||
// Let behaviors do something before the object is destroyed.
|
||||
super.onDeletedFromScene();
|
||||
// Destroy the children.
|
||||
this._instanceContainer.onDestroyFromScene(this._runtimeScene);
|
||||
this._instanceContainer.onDeletedFromScene(this._runtimeScene);
|
||||
}
|
||||
|
||||
override onDestroyed(): void {
|
||||
this._instanceContainer._destroy();
|
||||
super.onDestroyed();
|
||||
}
|
||||
|
||||
override update(parent: gdjs.RuntimeInstanceContainer): void {
|
||||
@@ -276,6 +306,8 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* This method is called when the preview is being hot-reloaded.
|
||||
*
|
||||
* Custom objects implement this method with code generated from events.
|
||||
*/
|
||||
onHotReloading(parent: gdjs.RuntimeInstanceContainer) {}
|
||||
|
||||
@@ -284,6 +316,8 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* This method is called each tick after events are done.
|
||||
*
|
||||
* Custom objects implement this method with code generated from events.
|
||||
* @param parent The instanceContainer owning the object
|
||||
*/
|
||||
doStepPostEvents(parent: gdjs.RuntimeInstanceContainer) {}
|
||||
@@ -291,6 +325,8 @@ namespace gdjs {
|
||||
/**
|
||||
* This method is called when the object is being removed from its parent
|
||||
* container and is about to be destroyed/reused later.
|
||||
*
|
||||
* Custom objects implement this method with code generated from events.
|
||||
*/
|
||||
onDestroy(parent: gdjs.RuntimeInstanceContainer) {}
|
||||
|
||||
|
@@ -71,7 +71,7 @@ namespace gdjs {
|
||||
eventsBasedObjectVariantData: EventsBasedObjectVariantData
|
||||
) {
|
||||
if (this._isLoaded) {
|
||||
this.onDestroyFromScene(this._parent);
|
||||
this.onDeletedFromScene(this._parent);
|
||||
}
|
||||
|
||||
const isForcedToOverrideEventsBasedObjectChildrenConfiguration =
|
||||
@@ -186,26 +186,25 @@ namespace gdjs {
|
||||
*
|
||||
* @param instanceContainer The container owning the object.
|
||||
*/
|
||||
onDestroyFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
onDeletedFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
if (!this._isLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Notify the objects they are being destroyed
|
||||
const allInstancesList = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
|
||||
const object = allInstancesList[i];
|
||||
object.onDeletedFromScene();
|
||||
// The object can free all its resource directly...
|
||||
object.onDestroyed();
|
||||
}
|
||||
// ...as its container cache `_instancesRemoved` is also destroy.
|
||||
this._destroy();
|
||||
|
||||
this._isLoaded = false;
|
||||
}
|
||||
|
||||
_destroy() {
|
||||
override _destroy() {
|
||||
const allInstancesList = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
|
||||
const object = allInstancesList[i];
|
||||
object.onDestroyed();
|
||||
}
|
||||
// It should not be necessary to reset these variables, but this help
|
||||
// ensuring that all memory related to the container is released immediately.
|
||||
super._destroy();
|
||||
@@ -383,11 +382,9 @@ namespace gdjs {
|
||||
): FloatPoint {
|
||||
const position = result || [0, 0];
|
||||
this._customObject.applyObjectTransformation(sceneX, sceneY, position);
|
||||
return this._parent.convertInverseCoords(
|
||||
position[0],
|
||||
position[1],
|
||||
position
|
||||
);
|
||||
return this._parent
|
||||
.getLayer(this._customObject.getLayer())
|
||||
.convertInverseCoords(position[0], position[1], 0, position);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -162,5 +162,19 @@ namespace gdjs {
|
||||
this._invalidModel.scene.clear();
|
||||
}
|
||||
}
|
||||
|
||||
unloadResource(resourceData: ResourceData): void {
|
||||
const loadedThreeModel = this._loadedThreeModels.get(resourceData);
|
||||
if (loadedThreeModel) {
|
||||
loadedThreeModel.scene.clear();
|
||||
this._loadedThreeModels.delete(resourceData);
|
||||
}
|
||||
|
||||
const downloadedArrayBuffer =
|
||||
this._downloadedArrayBuffers.get(resourceData);
|
||||
if (downloadedArrayBuffer) {
|
||||
this._downloadedArrayBuffers.delete(resourceData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user