From 18e8020bf5c62577de1fefbe0730a76739fffa0b Mon Sep 17 00:00:00 2001 From: D8H Date: Fri, 25 Aug 2023 11:11:55 +0200 Subject: [PATCH] Simplify the list of actions/conditions by removing duplicated actions/conditions that are common between objects (#5494) * Actions, conditions and expressions related to opacity, size (width/height), scale, animations and other common features are now visible only once when you search for them in actions/conditions (instead of being shown once for every type of object supporting them). This reduces the risk of confusion for new or existing users, notably when multiple versions of the same action were returned by the search and was making it difficult to choose the proper one. * Internally, this works thanks to default, built-in behaviors that are supported by the objects. --- .../CodeGeneration/EventsCodeGenerator.cpp | 11 - .../ExpressionCodeGenerator.cpp | 6 - .../Extensions/Builtin/AllBuiltinExtensions.h | 6 + .../Builtin/BaseObjectExtension.cpp | 27 +- .../Capabilities/AnimatableExtension.cpp | 135 ++++++++ .../Builtin/Capabilities/EffectExtension.cpp | 116 +++++++ .../Capabilities/FlippableExtension.cpp | 86 +++++ .../Builtin/Capabilities/OpacityExtension.cpp | 59 ++++ .../Capabilities/ResizableExtension.cpp | 110 +++++++ .../Capabilities/ScalableExtension.cpp | 90 ++++++ .../SpriteExtension/SpriteExtension.cpp | 102 ++++-- .../Extensions/Metadata/BehaviorMetadata.cpp | 47 +-- .../Extensions/Metadata/BehaviorMetadata.h | 23 +- .../Extensions/Metadata/MetadataProvider.h | 4 + .../Extensions/Metadata/ObjectMetadata.h | 34 +- Core/GDCore/Extensions/PlatformExtension.cpp | 19 -- .../IDE/Events/BehaviorDefaultFlagClearer.cpp | 23 ++ .../IDE/Events/BehaviorDefaultFlagClearer.h | 34 ++ .../GDCore/IDE/Events/ExpressionValidator.cpp | 8 - Core/GDCore/IDE/ProjectStripper.cpp | 6 + Core/GDCore/Project/Behavior.h | 16 +- Core/GDCore/Project/Layout.cpp | 129 ++++++++ Core/GDCore/Project/Layout.h | 22 +- Core/GDCore/Project/Object.cpp | 6 +- Core/GDCore/Project/Project.cpp | 44 ++- Core/tests/DummyPlatform.cpp | 136 +++++++- Core/tests/ExpressionCodeGenerator.cpp | 29 +- Core/tests/ExpressionParser2.cpp | 26 +- Core/tests/Object.cpp | 45 +++ Core/tests/ObjectSerialization.cpp | 37 +++ Extensions/3D/A_RuntimeObject3D.ts | 13 +- Extensions/3D/Base3DBehavior.ts | 189 +++++++++++ Extensions/3D/JsExtension.js | 301 +++++++++++++++++- Extensions/3D/Model3DRuntimeObject.ts | 4 +- Extensions/BBText/JsExtension.js | 11 +- Extensions/BitmapText/JsExtension.js | 10 +- .../bitmaptextruntimeobject-pixi-renderer.ts | 7 +- .../BitmapText/bitmaptextruntimeobject.ts | 47 ++- Extensions/PanelSpriteObject/Extension.cpp | 13 +- .../panelspriteruntimeobject.ts | 33 +- Extensions/PrimitiveDrawing/Extension.cpp | 24 +- .../shapepainterruntimeobject.ts | 19 +- Extensions/TextInput/JsExtension.js | 11 +- .../TextInput/textinputruntimeobject.ts | 27 +- Extensions/TextObject/Extension.cpp | 22 +- Extensions/TextObject/JsExtension.cpp | 2 +- Extensions/TextObject/textruntimeobject.ts | 22 +- Extensions/TileMap/JsExtension.js | 27 ++ .../tilemapcollisionmaskruntimeobject.ts | 21 +- Extensions/TileMap/tilemapruntimeobject.ts | 28 +- Extensions/TiledSpriteObject/Extension.cpp | 25 +- .../tiledspriteruntimeobject.ts | 20 +- .../MetadataDeclarationHelper.cpp | 72 ++++- .../MetadataDeclarationHelper.h | 3 +- .../Builtin/BaseObjectExtension.cpp | 267 +++++----------- .../Capacities/AnimatableExtension.cpp | 72 +++++ .../Builtin/Capacities/AnimatableExtension.h | 22 ++ .../Builtin/Capacities/EffectExtension.cpp | 40 +++ .../Builtin/Capacities/EffectExtension.h | 22 ++ .../Builtin/Capacities/FlippableExtension.cpp | 37 +++ .../Builtin/Capacities/FlippableExtension.h | 22 ++ .../Builtin/Capacities/OpacityExtension.cpp | 35 ++ .../Builtin/Capacities/OpacityExtension.h | 22 ++ .../Builtin/Capacities/ResizableExtension.cpp | 43 +++ .../Builtin/Capacities/ResizableExtension.h | 22 ++ .../Builtin/Capacities/ScalableExtension.cpp | 57 ++++ .../Builtin/Capacities/ScalableExtension.h | 22 ++ .../Extensions/Builtin/SpriteExtension.cpp | 10 +- GDJS/GDJS/Extensions/JsPlatform.cpp | 24 ++ GDJS/Runtime/CustomRuntimeObject.ts | 43 ++- .../object-capabilities/AnimatableBehavior.ts | 133 ++++++++ .../object-capabilities/EffectBehavior.ts | 126 ++++++++ .../object-capabilities/FlippableBehavior.ts | 68 ++++ .../object-capabilities/OpacityBehavior.ts | 64 ++++ .../object-capabilities/ResizableBehavior.ts | 98 ++++++ .../object-capabilities/ScalableBehavior.ts | 112 +++++++ GDJS/Runtime/runtimeobject.ts | 3 +- GDJS/Runtime/spriteruntimeobject.ts | 116 ++++--- GDevelop.js/Bindings/Bindings.idl | 20 +- GDevelop.js/CMakeLists.txt | 2 +- GDevelop.js/TestUtils/TestExtensions.js | 10 - GDevelop.js/__tests__/Core.js | 24 +- GDevelop.js/__tests__/GDJS.js | 29 +- .../__tests__/MetadataDeclarationHelper.js | 10 +- GDevelop.js/scripts/generate-types.js | 2 + GDevelop.js/types/gdbehavior.js | 1 + GDevelop.js/types/gdbehaviormetadata.js | 3 + GDevelop.js/types/gdexpressionmetadata.js | 2 - GDevelop.js/types/gdinstructionmetadata.js | 2 - GDevelop.js/types/gdobjectmetadata.js | 6 +- GDevelop.js/types/gdproject.js | 2 + GDevelop.js/types/libgdevelop.js | 2 + .../BehaviorStore/BehaviorListItem.js | 26 +- .../BehaviorStore/BehaviorStoreContext.js | 4 + .../app/src/AssetStore/BehaviorStore/index.js | 1 + .../src/BehaviorsEditor/NewBehaviorDialog.js | 53 ++- newIDE/app/src/BehaviorsEditor/index.js | 9 +- .../EnumerateProperties.js | 1 + .../src/EventsSheet/EventsTree/Instruction.js | 17 +- .../EventsTree/InstructionsList.js | 3 + .../Renderers/ForEachChildVariableEvent.js | 2 + .../EventsTree/Renderers/ForEachEvent.js | 2 + .../EventsTree/Renderers/RepeatEvent.js | 2 + .../EventsTree/Renderers/StandardEvent.js | 2 + .../EventsTree/Renderers/WhileEvent.js | 3 + .../ParameterFields/BehaviorField.js | 22 +- .../ParameterFields/ObjectField.js | 72 ++++- .../ExpressionAutocompletion.spec.js | 18 +- .../EnumerateExpressions.js | 36 +-- .../EnumerateExpressions.spec.js | 3 +- .../EnumerateInstructions.js | 8 - .../EnumerateInstructions.spec.js | 111 +++---- .../SetupInstructionParameters.js | 23 +- .../SetupInstructionParameters.spec.js | 13 +- .../src/ObjectEditor/ObjectEditorDialog.js | 10 +- .../app/src/ObjectsList/EnumerateObjects.js | 56 +++- newIDE/app/src/ObjectsList/ObjectSelector.js | 47 +-- newIDE/app/src/ObjectsList/index.js | 4 +- newIDE/app/src/UI/Checkbox.js | 2 +- .../src/Utils/GDevelopServices/Extension.js | 4 + .../FakeBehaviorsRegistry.js | 17 + newIDE/app/src/fixtures/TestExtensions.js | 10 - .../ParameterFields/ObjectField.stories.js | 12 +- 123 files changed, 3743 insertions(+), 832 deletions(-) create mode 100644 Core/GDCore/Extensions/Builtin/Capabilities/AnimatableExtension.cpp create mode 100644 Core/GDCore/Extensions/Builtin/Capabilities/EffectExtension.cpp create mode 100644 Core/GDCore/Extensions/Builtin/Capabilities/FlippableExtension.cpp create mode 100644 Core/GDCore/Extensions/Builtin/Capabilities/OpacityExtension.cpp create mode 100644 Core/GDCore/Extensions/Builtin/Capabilities/ResizableExtension.cpp create mode 100644 Core/GDCore/Extensions/Builtin/Capabilities/ScalableExtension.cpp create mode 100644 Core/GDCore/IDE/Events/BehaviorDefaultFlagClearer.cpp create mode 100644 Core/GDCore/IDE/Events/BehaviorDefaultFlagClearer.h create mode 100644 Core/tests/Object.cpp create mode 100644 Extensions/3D/Base3DBehavior.ts create mode 100644 GDJS/GDJS/Extensions/Builtin/Capacities/AnimatableExtension.cpp create mode 100644 GDJS/GDJS/Extensions/Builtin/Capacities/AnimatableExtension.h create mode 100644 GDJS/GDJS/Extensions/Builtin/Capacities/EffectExtension.cpp create mode 100644 GDJS/GDJS/Extensions/Builtin/Capacities/EffectExtension.h create mode 100644 GDJS/GDJS/Extensions/Builtin/Capacities/FlippableExtension.cpp create mode 100644 GDJS/GDJS/Extensions/Builtin/Capacities/FlippableExtension.h create mode 100644 GDJS/GDJS/Extensions/Builtin/Capacities/OpacityExtension.cpp create mode 100644 GDJS/GDJS/Extensions/Builtin/Capacities/OpacityExtension.h create mode 100644 GDJS/GDJS/Extensions/Builtin/Capacities/ResizableExtension.cpp create mode 100644 GDJS/GDJS/Extensions/Builtin/Capacities/ResizableExtension.h create mode 100644 GDJS/GDJS/Extensions/Builtin/Capacities/ScalableExtension.cpp create mode 100644 GDJS/GDJS/Extensions/Builtin/Capacities/ScalableExtension.h create mode 100644 GDJS/Runtime/object-capabilities/AnimatableBehavior.ts create mode 100644 GDJS/Runtime/object-capabilities/EffectBehavior.ts create mode 100644 GDJS/Runtime/object-capabilities/FlippableBehavior.ts create mode 100644 GDJS/Runtime/object-capabilities/OpacityBehavior.ts create mode 100644 GDJS/Runtime/object-capabilities/ResizableBehavior.ts create mode 100644 GDJS/Runtime/object-capabilities/ScalableBehavior.ts diff --git a/Core/GDCore/Events/CodeGeneration/EventsCodeGenerator.cpp b/Core/GDCore/Events/CodeGeneration/EventsCodeGenerator.cpp index 79a6721d9c..e93d2276f1 100644 --- a/Core/GDCore/Events/CodeGeneration/EventsCodeGenerator.cpp +++ b/Core/GDCore/Events/CodeGeneration/EventsCodeGenerator.cpp @@ -323,11 +323,6 @@ gd::String EventsCodeGenerator::GenerateConditionCode( const ObjectMetadata& objInfo = MetadataProvider::GetObjectMetadata(platform, objectType); - if (objInfo.IsUnsupportedBaseObjectCapability( - instrInfos.GetRequiredBaseObjectCapability())) { - conditionCode += - "/* Object with unsupported capability - skipped. */\n"; - } else { AddIncludeFiles(objInfo.includeFiles); context.SetCurrentObject(realObjects[i]); context.ObjectsListNeeded(realObjects[i]); @@ -344,7 +339,6 @@ gd::String EventsCodeGenerator::GenerateConditionCode( context); context.SetNoCurrentObject(); - } } } } else if (instrInfos.IsBehaviorInstruction()) { @@ -515,10 +509,6 @@ gd::String EventsCodeGenerator::GenerateActionCode( const ObjectMetadata& objInfo = MetadataProvider::GetObjectMetadata(platform, objectType); - if (objInfo.IsUnsupportedBaseObjectCapability( - instrInfos.GetRequiredBaseObjectCapability())) { - actionCode += "/* Object with unsupported capability - skipped. */\n"; - } else { AddIncludeFiles(objInfo.includeFiles); context.SetCurrentObject(realObjects[i]); context.ObjectsListNeeded(realObjects[i]); @@ -535,7 +525,6 @@ gd::String EventsCodeGenerator::GenerateActionCode( optionalAsyncCallbackName); context.SetNoCurrentObject(); - } } } } else if (instrInfos.IsBehaviorInstruction()) { diff --git a/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.cpp b/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.cpp index eec0f24bd4..969e3d24ea 100644 --- a/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.cpp +++ b/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.cpp @@ -270,11 +270,6 @@ gd::String ExpressionCodeGenerator::GenerateObjectFunctionCode( const ObjectMetadata& objInfo = MetadataProvider::GetObjectMetadata( codeGenerator.GetPlatform(), objectType); - if (objInfo.IsUnsupportedBaseObjectCapability( - expressionMetadata.GetRequiredBaseObjectCapability())) { - // Do nothing, skipping objects not supporting the capability required by - // this expression. - } else { codeGenerator.AddIncludeFiles(objInfo.includeFiles); functionOutput = codeGenerator.GenerateObjectFunctionCall( realObjects[i], @@ -283,7 +278,6 @@ gd::String ExpressionCodeGenerator::GenerateObjectFunctionCode( parametersCode, functionOutput, context); - } } return functionOutput; diff --git a/Core/GDCore/Extensions/Builtin/AllBuiltinExtensions.h b/Core/GDCore/Extensions/Builtin/AllBuiltinExtensions.h index 17c374b719..a10a356acf 100644 --- a/Core/GDCore/Extensions/Builtin/AllBuiltinExtensions.h +++ b/Core/GDCore/Extensions/Builtin/AllBuiltinExtensions.h @@ -43,6 +43,12 @@ class GD_CORE_API BuiltinExtensionsImplementer { static void ImplementsVariablesExtension(gd::PlatformExtension& extension); static void ImplementsWindowExtension(gd::PlatformExtension& extension); static void ImplementsAsyncExtension(gd::PlatformExtension& extension); + static void ImplementsResizableExtension(gd::PlatformExtension& extension); + static void ImplementsScalableExtension(gd::PlatformExtension& extension); + static void ImplementsFlippableExtension(gd::PlatformExtension& extension); + static void ImplementsAnimatableExtension(gd::PlatformExtension& extension); + static void ImplementsEffectExtension(gd::PlatformExtension& extension); + static void ImplementsOpacityExtension(gd::PlatformExtension& extension); }; } // namespace gd diff --git a/Core/GDCore/Extensions/Builtin/BaseObjectExtension.cpp b/Core/GDCore/Extensions/Builtin/BaseObjectExtension.cpp index 094da833bd..8ee7546b66 100644 --- a/Core/GDCore/Extensions/Builtin/BaseObjectExtension.cpp +++ b/Core/GDCore/Extensions/Builtin/BaseObjectExtension.cpp @@ -29,8 +29,16 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension( .SetIcon("res/actions/force24.png"); extension.AddInstructionOrExpressionGroupMetadata(_("Variables")) .SetIcon("res/conditions/var24.png"); + extension.AddInstructionOrExpressionGroupMetadata(_("Timers")) + .SetIcon("res/actions/timer24.png"); + extension.AddInstructionOrExpressionGroupMetadata(_("Visibility")) + .SetIcon("res/actions/visibilite24.png"); extension.AddInstructionOrExpressionGroupMetadata(_("Position")) .SetIcon("res/actions/position24_black.png"); + extension.AddInstructionOrExpressionGroupMetadata(_("Angle")) + .SetIcon("res/actions/direction24_black.png"); + extension.AddInstructionOrExpressionGroupMetadata(_("Size")) + .SetIcon("res/actions/scale24_black.png"); gd::ObjectMetadata& obj = extension.AddObject( "", _("Base object"), _("Base object"), "res/objeticon24.png"); @@ -1101,6 +1109,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension( "res/actions/scaleWidth_black.png") .AddParameter("object", _("Object")); + // Deprecated obj.AddExpression("Largeur", _("Width"), _("Width of the object"), @@ -1116,6 +1125,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension( "res/actions/scaleHeight_black.png") .AddParameter("object", _("Object")); + // Deprecated obj.AddExpression("Hauteur", _("Height"), _("Height of the object"), @@ -1201,7 +1211,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension( obj.AddExpression("ObjectTimerElapsedTime", _("Object timer value"), _("Value of an object timer"), - _("Object timers"), + _("Timers"), "res/actions/time.png") .AddParameter("object", _("Object")) .AddParameter("identifier", _("Timer's name"), "objectTimer"); @@ -1251,6 +1261,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension( .AddParameter("expression", _("Target X position")) .AddParameter("expression", _("Target Y position")); + // Deprecated obj.AddAction("EnableEffect", _("Enable an object effect"), _("Enable an effect on the object"), @@ -1262,8 +1273,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension( .AddParameter("objectEffectName", _("Effect name")) .AddParameter("yesorno", _("Enable?")) .MarkAsSimple() - .SetRequiresBaseObjectCapability("effect"); + .SetHidden(); + // Deprecated obj.AddAction("SetEffectDoubleParameter", _("Effect parameter (number)"), _("Change the value of a parameter of an effect.") + "\n" + @@ -1278,8 +1290,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension( .AddParameter("objectEffectParameterName", _("Parameter name")) .AddParameter("expression", _("New value")) .MarkAsSimple() - .SetRequiresBaseObjectCapability("effect"); + .SetHidden(); + // Deprecated obj.AddAction("SetEffectStringParameter", _("Effect parameter (string)"), _("Change the value (string) of a parameter of an effect.") + @@ -1295,8 +1308,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension( .AddParameter("objectEffectParameterName", _("Parameter name")) .AddParameter("string", _("New value")) .MarkAsSimple() - .SetRequiresBaseObjectCapability("effect"); + .SetHidden(); + // Deprecated obj.AddAction("SetEffectBooleanParameter", _("Effect parameter (enable or disable)"), _("Enable or disable a parameter of an effect.") + "\n" + @@ -1311,8 +1325,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension( .AddParameter("objectEffectParameterName", _("Parameter name")) .AddParameter("yesorno", _("Enable?")) .MarkAsSimple() - .SetRequiresBaseObjectCapability("effect"); + .SetHidden(); + // Deprecated obj.AddCondition("IsEffectEnabled", _("Effect is enabled"), _("Check if the effect on an object is enabled."), @@ -1323,7 +1338,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension( .AddParameter("object", _("Object")) .AddParameter("objectEffectName", _("Effect name")) .MarkAsSimple() - .SetRequiresBaseObjectCapability("effect"); + .SetHidden(); obj.AddAction("SetIncludedInParentCollisionMask", _("Include in parent collision mask"), diff --git a/Core/GDCore/Extensions/Builtin/Capabilities/AnimatableExtension.cpp b/Core/GDCore/Extensions/Builtin/Capabilities/AnimatableExtension.cpp new file mode 100644 index 0000000000..72d1e6bb35 --- /dev/null +++ b/Core/GDCore/Extensions/Builtin/Capabilities/AnimatableExtension.cpp @@ -0,0 +1,135 @@ +/* + * GDevelop Core + * Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the GNU Lesser General Public + * License. + */ +#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h" +#include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h" +#include "GDCore/Project/Behavior.h" +#include "GDCore/Project/BehaviorsSharedData.h" +#include "GDCore/Project/Object.h" +#include "GDCore/Tools/Localization.h" + +using namespace std; +namespace gd { + +void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAnimatableExtension( + gd::PlatformExtension& extension) { + extension + .SetExtensionInformation("AnimatableCapability", + _("Animatable capability"), + _("Animate objects."), + "Florian Rival", + "Open source (MIT License)") + .SetExtensionHelpPath("/objects"); + extension.AddInstructionOrExpressionGroupMetadata(_("Animations and images")) + .SetIcon("res/actions/animation24.png"); + + gd::BehaviorMetadata& aut = extension.AddBehavior( + "AnimatableBehavior", + _("Animatable capability"), + "Animation", + _("Animate objects."), + "", + "res/actions/animation24.png", + "AnimatableBehavior", + std::make_shared(), + std::make_shared()) + .SetHidden(); + + aut.AddExpressionAndConditionAndAction( + "number", + "Index", + _("Animation (by number)"), + _("the number of the animation played by the object (the number from " + "the animations list)"), + _("the number of the animation"), + _("Animations and images"), + "res/actions/animation24.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "AnimatableBehavior") + .UseStandardParameters( + "number", gd::ParameterOptions::MakeNewOptions().SetDescription( + _("Animation index"))) + .MarkAsSimple(); + + aut.AddExpressionAndConditionAndAction( + "string", + "Name", + _("Animation (by name)"), + _("the animation played by the object using the name of the " + "animation."), + _("the animation"), + _("Animations and images"), + "res/actions/animation24.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "AnimatableBehavior") + .UseStandardParameters( + "objectAnimationName", gd::ParameterOptions::MakeNewOptions().SetDescription( + _("Animation name"))) + .MarkAsSimple(); + + aut.AddScopedAction("PauseAnimation", + _("Pause the animation"), + _("Pause the animation of the object"), + _("Pause the animation of _PARAM0_"), + _("Animations and images"), + "res/actions/animation24.png", + "res/actions/animation.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "AnimatableBehavior") + .MarkAsSimple(); + + aut.AddScopedAction("PlayAnimation", + _("Resume the animation"), + _("Resume the animation of the object"), + _("Resume the animation of _PARAM0_"), + _("Animations and images"), + "res/actions/animation24.png", + "res/actions/animation.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "AnimatableBehavior") + .MarkAsSimple(); + + aut.AddExpressionAndConditionAndAction( + "number", + "SpeedScale", + _("Animation speed scale"), + _("the animation speed scale (1 = the default speed, >1 = faster and " + "<1 = slower)"), + _("the animation speed scale"), + _("Animations and images"), + "res/actions/animation24.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "AnimatableBehavior") + .UseStandardParameters( + "number", gd::ParameterOptions::MakeNewOptions().SetDescription( + _("Speed scale"))) + .MarkAsSimple(); + + aut.AddScopedCondition("IsAnimationPaused", + _("Animation paused"), + _("Check if the animation of an object is paused."), + _("The animation of _PARAM0_ is paused"), + _("Animations and images"), + "res/conditions/animation24.png", + "res/conditions/animation.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "AnimatableBehavior") + .MarkAsSimple(); + + aut.AddScopedCondition("HasAnimationEnded", + _("Animation finished"), + _("Check if the animation being played by the Sprite object " + "is finished."), + _("The animation of _PARAM0_ is finished"), + _("Animations and images"), + "res/conditions/animation24.png", + "res/conditions/animation.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "AnimatableBehavior") + .MarkAsSimple(); +} + +} // namespace gd diff --git a/Core/GDCore/Extensions/Builtin/Capabilities/EffectExtension.cpp b/Core/GDCore/Extensions/Builtin/Capabilities/EffectExtension.cpp new file mode 100644 index 0000000000..1a77765a7f --- /dev/null +++ b/Core/GDCore/Extensions/Builtin/Capabilities/EffectExtension.cpp @@ -0,0 +1,116 @@ +/* + * GDevelop Core + * Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the GNU Lesser General Public + * License. + */ +#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h" +#include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h" +#include "GDCore/Project/Behavior.h" +#include "GDCore/Project/BehaviorsSharedData.h" +#include "GDCore/Project/Object.h" +#include "GDCore/Tools/Localization.h" + +using namespace std; +namespace gd { + +void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension( + gd::PlatformExtension& extension) { + extension + .SetExtensionInformation("EffectCapability", + _("Effect capability"), + _("Apply visual effects to objects."), + "Florian Rival", + "Open source (MIT License)") + .SetExtensionHelpPath("/objects"); + extension.AddInstructionOrExpressionGroupMetadata(_("Effects")) + .SetIcon("res/actions/effect24.png"); + + gd::BehaviorMetadata& aut = extension.AddBehavior( + "EffectBehavior", + _("Effect capability"), + "Effect", + _("Apply visual effects to objects."), + "", + "res/actions/effect24.png", + "EffectBehavior", + std::make_shared(), + std::make_shared()) + .SetHidden(); + + aut.AddScopedAction("EnableEffect", + _("Enable an object effect"), + _("Enable an effect on the object"), + _("Enable effect _PARAM2_ on _PARAM0_: _PARAM3_"), + _("Effects"), + "res/actions/effect24.png", + "res/actions/effect.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "EffectBehavior") + .AddParameter("objectEffectName", _("Effect name")) + .AddParameter("yesorno", _("Enable?")) + .MarkAsSimple(); + + aut.AddScopedAction("SetEffectDoubleParameter", + _("Effect parameter (number)"), + _("Change the value of a parameter of an effect.") + "\n" + + _("You can find the parameter names (and change the effect " + "names) in the effects window."), + _("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"), + _("Effects"), + "res/actions/effect24.png", + "res/actions/effect.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "EffectBehavior") + .AddParameter("objectEffectName", _("Effect name")) + .AddParameter("objectEffectParameterName", _("Parameter name")) + .AddParameter("expression", _("New value")) + .MarkAsSimple(); + + aut.AddScopedAction("SetEffectStringParameter", + _("Effect parameter (string)"), + _("Change the value (string) of a parameter of an effect.") + + "\n" + + _("You can find the parameter names (and change the effect " + "names) in the effects window."), + _("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"), + _("Effects"), + "res/actions/effect24.png", + "res/actions/effect.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "EffectBehavior") + .AddParameter("objectEffectName", _("Effect name")) + .AddParameter("objectEffectParameterName", _("Parameter name")) + .AddParameter("string", _("New value")) + .MarkAsSimple(); + + aut.AddScopedAction("SetEffectBooleanParameter", + _("Effect parameter (enable or disable)"), + _("Enable or disable a parameter of an effect.") + "\n" + + _("You can find the parameter names (and change the effect " + "names) in the effects window."), + _("Enable _PARAM3_ for effect _PARAM2_ of _PARAM0_: _PARAM4_"), + _("Effects"), + "res/actions/effect24.png", + "res/actions/effect.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "EffectBehavior") + .AddParameter("objectEffectName", _("Effect name")) + .AddParameter("objectEffectParameterName", _("Parameter name")) + .AddParameter("yesorno", _("Enable?")) + .MarkAsSimple(); + + aut.AddScopedCondition("IsEffectEnabled", + _("Effect is enabled"), + _("Check if the effect on an object is enabled."), + _("Effect _PARAM2_ of _PARAM0_ is enabled"), + _("Effects"), + "res/actions/effect24.png", + "res/actions/effect.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "EffectBehavior") + .AddParameter("objectEffectName", _("Effect name")) + .MarkAsSimple(); +} + +} // namespace gd diff --git a/Core/GDCore/Extensions/Builtin/Capabilities/FlippableExtension.cpp b/Core/GDCore/Extensions/Builtin/Capabilities/FlippableExtension.cpp new file mode 100644 index 0000000000..e64abd6042 --- /dev/null +++ b/Core/GDCore/Extensions/Builtin/Capabilities/FlippableExtension.cpp @@ -0,0 +1,86 @@ +/* + * GDevelop Core + * Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the GNU Lesser General Public + * License. + */ +#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h" +#include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h" +#include "GDCore/Project/Behavior.h" +#include "GDCore/Project/BehaviorsSharedData.h" +#include "GDCore/Project/Object.h" +#include "GDCore/Tools/Localization.h" + +using namespace std; +namespace gd { + +void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFlippableExtension( + gd::PlatformExtension& extension) { + extension + .SetExtensionInformation("FlippableCapability", + _("Flippable capability"), + _("Flip objects."), + "Florian Rival", + "Open source (MIT License)") + .SetExtensionHelpPath("/objects"); + extension.AddInstructionOrExpressionGroupMetadata(_("Effects")) + .SetIcon("res/actions/effect24.png"); + + gd::BehaviorMetadata& aut = extension.AddBehavior( + "FlippableBehavior", + _("Flippable capability"), + "Flippable", + _("Flip objects."), + "", + "res/actions/flipX24.png", + "FlippableBehavior", + std::make_shared(), + std::make_shared()) + .SetHidden(); + + aut.AddScopedAction("FlipX", + _("Flip the object horizontally"), + _("Flip the object horizontally"), + _("Flip horizontally _PARAM0_: _PARAM2_"), + _("Effects"), + "res/actions/flipX24.png", + "res/actions/flipX.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "FlippableBehavior") + .AddParameter("yesorno", _("Activate flipping")) + .MarkAsSimple(); + + aut.AddScopedAction("FlipY", + _("Flip the object vertically"), + _("Flip the object vertically"), + _("Flip vertically _PARAM0_: _PARAM2_"), + _("Effects"), + "res/actions/flipY24.png", + "res/actions/flipY.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "FlippableBehavior") + .AddParameter("yesorno", _("Activate flipping")) + .MarkAsSimple(); + + aut.AddScopedCondition("FlippedX", + _("Horizontally flipped"), + _("Check if the object is horizontally flipped"), + _("_PARAM0_ is horizontally flipped"), + _("Effects"), + "res/actions/flipX24.png", + "res/actions/flipX.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "FlippableBehavior"); + + aut.AddScopedCondition("FlippedY", + _("Vertically flipped"), + _("Check if the object is vertically flipped"), + _("_PARAM0_ is vertically flipped"), + _("Effects"), + "res/actions/flipY24.png", + "res/actions/flipY.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "FlippableBehavior"); +} + +} // namespace gd diff --git a/Core/GDCore/Extensions/Builtin/Capabilities/OpacityExtension.cpp b/Core/GDCore/Extensions/Builtin/Capabilities/OpacityExtension.cpp new file mode 100644 index 0000000000..70c3f96b32 --- /dev/null +++ b/Core/GDCore/Extensions/Builtin/Capabilities/OpacityExtension.cpp @@ -0,0 +1,59 @@ +/* + * GDevelop Core + * Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the GNU Lesser General Public + * License. + */ +#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h" +#include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h" +#include "GDCore/Project/Behavior.h" +#include "GDCore/Project/BehaviorsSharedData.h" +#include "GDCore/Project/Object.h" +#include "GDCore/Tools/Localization.h" + +using namespace std; +namespace gd { + +void GD_CORE_API BuiltinExtensionsImplementer::ImplementsOpacityExtension( + gd::PlatformExtension& extension) { + extension + .SetExtensionInformation("OpacityCapability", + _("Opacity capability"), + _("Change the object opacity."), + "Florian Rival", + "Open source (MIT License)") + .SetExtensionHelpPath("/objects"); + 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(), + std::make_shared()) + .SetHidden(); + + aut.AddExpressionAndConditionAndAction( + "number", + "Value", + _("Opacity"), + _("the opacity of an object, between 0 (fully transparent) to 255 " + "(opaque)"), + _("the opacity"), + _("Visibility"), + "res/actions/opacity24.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "OpacityBehavior") + .UseStandardParameters( + "number", gd::ParameterOptions::MakeNewOptions().SetDescription( + _("Opacity (0-255)"))) + .SetFunctionName("setOpacity") + .SetGetter("getOpacity"); +} + +} // namespace gd diff --git a/Core/GDCore/Extensions/Builtin/Capabilities/ResizableExtension.cpp b/Core/GDCore/Extensions/Builtin/Capabilities/ResizableExtension.cpp new file mode 100644 index 0000000000..80b4d3f5e8 --- /dev/null +++ b/Core/GDCore/Extensions/Builtin/Capabilities/ResizableExtension.cpp @@ -0,0 +1,110 @@ +/* + * GDevelop Core + * Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the GNU Lesser General Public + * License. + */ +#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h" +#include "GDCore/Project/Behavior.h" +#include "GDCore/Project/BehaviorsSharedData.h" +#include "GDCore/Project/Object.h" +#include "GDCore/Tools/Localization.h" + +using namespace std; +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)") + .SetExtensionHelpPath("/objects"); + extension.AddInstructionOrExpressionGroupMetadata(_("Size")) + .SetIcon("res/actions/scale24_black.png"); + + gd::BehaviorMetadata& aut = extension.AddBehavior( + "ResizableBehavior", + _("Resizable capability"), + "Resizable", + _("Change the object dimensions."), + "", + "res/actions/scale24_black.png", + "ResizableBehavior", + std::make_shared(), + std::make_shared()) + .SetHidden(); + + aut.AddScopedAction("SetWidth", + _("Width"), + _("Change the width of the object."), + _("the width"), + _("Size"), + "res/actions/scaleWidth24_black.png", + "res/actions/scaleWidth_black.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "ResizableBehavior") + .UseStandardOperatorParameters("number", + ParameterOptions::MakeNewOptions().SetDescription( + _("Width"))) + .MarkAsAdvanced(); + + aut.AddScopedCondition("Width", + _("Width"), + _("Compare the width of the object."), + _("the width"), + _("Size"), + "res/conditions/scaleWidth24_black.png", + "res/conditions/scaleWidth_black.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "ResizableBehavior") + .UseStandardRelationalOperatorParameters( + "number", ParameterOptions::MakeNewOptions().SetDescription( + _("Width"))) + .MarkAsAdvanced(); + + aut.AddScopedAction("SetHeight", + _("Height"), + _("Change the height of the object."), + _("the height"), + _("Size"), + "res/actions/scaleHeight24_black.png", + "res/actions/scaleHeight_black.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "ResizableBehavior") + .UseStandardOperatorParameters("number", + ParameterOptions::MakeNewOptions().SetDescription( + _("Height"))) + .MarkAsAdvanced(); + + aut.AddScopedCondition("Height", + _("Height"), + _("Compare the height of the object."), + _("the height"), + _("Size"), + "res/conditions/scaleHeight24_black.png", + "res/conditions/scaleHeight_black.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "ResizableBehavior") + .UseStandardRelationalOperatorParameters( + "number", ParameterOptions::MakeNewOptions().SetDescription( + _("Height"))) + .MarkAsAdvanced(); + + aut.AddScopedAction("SetSize", + _("Size"), + _("Change the size of an object."), + _("Change the size of _PARAM0_: set to _PARAM1_ x _PARAM2_"), + _("Size"), + "res/actions/scale24_black.png", + "res/actions/scale_black.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "ResizableBehavior") + .AddParameter("expression", _("Width")) + .AddParameter("expression", _("Height")) + .MarkAsAdvanced(); +} + +} // namespace gd diff --git a/Core/GDCore/Extensions/Builtin/Capabilities/ScalableExtension.cpp b/Core/GDCore/Extensions/Builtin/Capabilities/ScalableExtension.cpp new file mode 100644 index 0000000000..a7020aaaef --- /dev/null +++ b/Core/GDCore/Extensions/Builtin/Capabilities/ScalableExtension.cpp @@ -0,0 +1,90 @@ +/* + * GDevelop Core + * Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the GNU Lesser General Public + * License. + */ +#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h" +#include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h" +#include "GDCore/Project/Behavior.h" +#include "GDCore/Project/BehaviorsSharedData.h" +#include "GDCore/Project/Object.h" +#include "GDCore/Tools/Localization.h" + +using namespace std; +namespace gd { + +void GD_CORE_API BuiltinExtensionsImplementer::ImplementsScalableExtension( + gd::PlatformExtension& extension) { + extension + .SetExtensionInformation("ScalableCapability", + _("Scalable capability"), + _("Change the object scale."), + "Florian Rival", + "Open source (MIT License)") + .SetExtensionHelpPath("/objects"); + 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(), + std::make_shared()) + .SetHidden(); + + aut.AddExpressionAndConditionAndAction( + "number", + "Value", + _("Scale"), + _("the scale of the object (default scale is 1)"), + _("the scale"), + _("Scale"), + "res/actions/scale24_black.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "ScalableBehavior") + .UseStandardParameters( + "number", + gd::ParameterOptions::MakeNewOptions().SetDescription( + _("Scale (1 by default)"))) + .MarkAsAdvanced(); + + aut.AddExpressionAndConditionAndAction( + "number", + "X", + _("Scale on X axis"), + _("the scale on X axis of the object (default scale is 1)"), + _("the scale on X axis"), + _("Scale"), + "res/actions/scale24_black.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "ScalableBehavior") + .UseStandardParameters( + "number", + gd::ParameterOptions::MakeNewOptions().SetDescription( + _("Scale (1 by default)"))) + .MarkAsAdvanced(); + + aut.AddExpressionAndConditionAndAction( + "number", + "Y", + _("Scale on Y axis"), + _("the scale on Y axis of the object (default scale is 1)"), + _("the scale on Y axis"), + _("Scale"), + "res/actions/scale24_black.png") + .AddParameter("object", _("Object")) + .AddParameter("behavior", _("Behavior"), "ScalableBehavior") + .UseStandardParameters( + "number", + gd::ParameterOptions::MakeNewOptions().SetDescription( + _("Scale (1 by default)"))) + .MarkAsAdvanced(); +} + +} // namespace gd diff --git a/Core/GDCore/Extensions/Builtin/SpriteExtension/SpriteExtension.cpp b/Core/GDCore/Extensions/Builtin/SpriteExtension/SpriteExtension.cpp index 2d33a51f99..5e69b717fb 100644 --- a/Core/GDCore/Extensions/Builtin/SpriteExtension/SpriteExtension.cpp +++ b/Core/GDCore/Extensions/Builtin/SpriteExtension/SpriteExtension.cpp @@ -2,7 +2,7 @@ * GDevelop Core * Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights * reserved. This project is released under the GNU Lesser General Public - * LicenFse. + * License. */ #include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h" #include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h" @@ -32,8 +32,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( _("Animated object which can be used for " "most elements of a game"), "CppPlatform/Extensions/spriteicon.png") - .SetCategoryFullName(_("General")); + .SetCategoryFullName(_("General")) + .AddDefaultBehavior("EffectCapability::EffectBehavior") + .AddDefaultBehavior("ResizableCapability::ResizableBehavior") + .AddDefaultBehavior("ScalableCapability::ScalableBehavior") + .AddDefaultBehavior("FlippableCapability::FlippableBehavior") + .AddDefaultBehavior("OpacityCapability::OpacityBehavior") + .AddDefaultBehavior("AnimatableCapability::AnimatableBehavior"); + // Deprecated obj.AddAction("Opacity", _("Sprite opacity"), _("Change the opacity of a Sprite. 0 is fully transparent, 255 " @@ -48,8 +55,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( "number", ParameterOptions::MakeNewOptions().SetDescription( _("Opacity (0-255)"))) - .MarkAsSimple(); + .MarkAsSimple() + .SetHidden(); + // Deprecated obj.AddAction("ChangeAnimation", _("Change the animation"), _("Change the animation of the object, using the animation " @@ -62,8 +71,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .AddParameter("object", _("Object"), "Sprite") .UseStandardOperatorParameters("number", ParameterOptions::MakeNewOptions()) + .SetHidden() .MarkAsSimple(); + // Deprecated obj.AddAction("SetAnimationName", _("Change the animation (by name)"), _("Change the animation of the object, using the name of the " @@ -75,6 +86,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .AddParameter("object", _("Object"), "Sprite") .AddParameter("objectAnimationName", _("Animation name")) + .SetHidden() .MarkAsAdvanced(); obj.AddAction( @@ -107,6 +119,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( ParameterOptions::MakeNewOptions()) .MarkAsAdvanced(); + // Deprecated obj.AddAction("PauseAnimation", _("Pause the animation"), _("Pause the animation of the object"), @@ -116,8 +129,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( "res/actions/animation.png") .AddParameter("object", _("Object"), "Sprite") + .SetHidden() .MarkAsSimple(); + // Deprecated obj.AddAction("PlayAnimation", _("Play the animation"), _("Play the animation of the object"), @@ -127,8 +142,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( "res/actions/animation.png") .AddParameter("object", _("Object"), "Sprite") + .SetHidden() .MarkAsSimple(); + // Deprecated obj.AddAction( "ChangeAnimationSpeedScale", _("Animation speed scale"), @@ -143,8 +160,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .UseStandardOperatorParameters( "number", ParameterOptions::MakeNewOptions().SetDescription(_("Speed scale"))) + .SetHidden() .MarkAsSimple(); + // Deprecated obj.AddAction("TourneVersPos", "Rotate an object toward a position", "Rotate an object towards a position.", @@ -159,8 +178,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .AddParameter("expression", _("Angular speed (degrees per second)")) .SetDefaultValue("0") .AddCodeOnlyParameter("currentScene", "") - .SetHidden(); // Deprecated + .SetHidden(); + // Deprecated obj.AddAction("ChangeScale", _("Scale"), _("Modify the scale of the specified object."), @@ -174,8 +194,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( "number", ParameterOptions::MakeNewOptions().SetDescription( _("Scale (1 by default)"))) - .MarkAsAdvanced(); + .MarkAsAdvanced() + .SetHidden(); + // Deprecated obj.AddAction("ChangeScaleWidth", _("Scale on X axis"), _("Modify the scale of the width of an object."), @@ -189,8 +211,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( "number", ParameterOptions::MakeNewOptions().SetDescription( _("Scale (1 by default)"))) - .MarkAsAdvanced(); + .MarkAsAdvanced() + .SetHidden(); + // Deprecated obj.AddAction("ChangeScaleHeight", _("Scale on Y axis"), _("Modify the scale of the height of an object."), @@ -204,8 +228,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( "number", ParameterOptions::MakeNewOptions().SetDescription( _("Scale (1 by default)"))) - .MarkAsAdvanced(); + .MarkAsAdvanced() + .SetHidden(); + // Deprecated obj.AddAction("ChangeWidth", _("Width"), _("Change the width of a Sprite object."), @@ -217,8 +243,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .AddParameter("object", _("Object"), "Sprite") .UseStandardOperatorParameters("number", ParameterOptions::MakeNewOptions()) - .MarkAsAdvanced(); + .MarkAsAdvanced() + .SetHidden(); + // Deprecated obj.AddCondition("Width", _("Width"), _("Compare the width of a Sprite object."), @@ -230,8 +258,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .AddParameter("object", _("Object"), "Sprite") .UseStandardRelationalOperatorParameters( "number", ParameterOptions::MakeNewOptions()) - .MarkAsAdvanced(); + .MarkAsAdvanced() + .SetHidden(); + // Deprecated obj.AddAction("ChangeHeight", _("Height"), _("Change the height of a Sprite object."), @@ -243,8 +273,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .AddParameter("object", _("Object"), "Sprite") .UseStandardOperatorParameters("number", ParameterOptions::MakeNewOptions()) - .MarkAsAdvanced(); + .MarkAsAdvanced() + .SetHidden(); + // Deprecated obj.AddCondition("Height", _("Height"), _("Compare the height of a Sprite object."), @@ -256,8 +288,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .AddParameter("object", _("Object"), "Sprite") .UseStandardRelationalOperatorParameters( "number", ParameterOptions::MakeNewOptions()) - .MarkAsAdvanced(); + .MarkAsAdvanced() + .SetHidden(); + // Deprecated obj.AddAction("SetSize", _("Size"), _("Change the size of an object."), @@ -269,8 +303,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .AddParameter("object", _("Object")) .AddParameter("expression", _("Width")) .AddParameter("expression", _("Height")) - .MarkAsAdvanced(); + .MarkAsAdvanced() + .SetHidden(); + // Deprecated obj.AddCondition( "Animation", _("Current animation"), @@ -283,8 +319,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .AddParameter("object", _("Object"), "Sprite") .UseStandardRelationalOperatorParameters( "number", ParameterOptions::MakeNewOptions()) + .SetHidden() .MarkAsAdvanced(); + // Deprecated obj.AddCondition("AnimationName", _("Current animation name"), _("Check the animation played by the object."), @@ -295,6 +333,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .AddParameter("object", _("Object"), "Sprite") .AddParameter("objectAnimationName", _("Animation name")) + .SetHidden() .MarkAsAdvanced(); obj.AddCondition( @@ -328,6 +367,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( "number", ParameterOptions::MakeNewOptions()) .MarkAsAdvanced(); + // Deprecated obj.AddCondition("AnimStopped", _("Animation paused"), _("Check if the animation of an object is paused."), @@ -337,8 +377,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( "res/conditions/animation.png") .AddParameter("object", _("Object"), "Sprite") + .SetHidden() .MarkAsSimple(); + // Deprecated obj.AddCondition("AnimationEnded", _("Animation finished"), _("Check if the animation being played by the Sprite object " @@ -352,6 +394,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .MarkAsSimple() .SetHidden(); + // Deprecated obj.AddCondition("AnimationEnded2", _("Animation finished"), _("Check if the animation being played by the Sprite object " @@ -362,6 +405,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( "res/conditions/animation.png") .AddParameter("object", _("Object"), "Sprite") + .SetHidden() .MarkAsSimple(); obj.AddCondition("ScaleWidth", @@ -394,6 +438,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( _("Scale (1 by default)"))) .MarkAsAdvanced(); + // Deprecated obj.AddCondition("Opacity", _("Opacity"), _("Compare the opacity of a Sprite, between 0 (fully " @@ -408,7 +453,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( "number", ParameterOptions::MakeNewOptions().SetDescription( _("Opacity to compare to (0-255)"))) - .MarkAsSimple(); + .MarkAsSimple() + .SetHidden(); obj.AddCondition( "BlendMode", @@ -456,9 +502,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( _("Effects"), "res/actions/flipX24.png", "res/actions/flipX.png") - .AddParameter("object", _("Object"), "Sprite") .AddParameter("yesorno", _("Activate flipping")) + .SetHidden() .MarkAsSimple(); obj.AddAction("FlipY", @@ -468,9 +514,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( _("Effects"), "res/actions/flipY24.png", "res/actions/flipY.png") - .AddParameter("object", _("Object"), "Sprite") .AddParameter("yesorno", _("Activate flipping")) + .SetHidden() .MarkAsSimple(); obj.AddCondition("FlippedX", @@ -480,8 +526,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( _("Effects"), "res/actions/flipX24.png", "res/actions/flipX.png") - - .AddParameter("object", _("Object"), "Sprite"); + .AddParameter("object", _("Object"), "Sprite") + .SetHidden(); obj.AddCondition("FlippedY", _("Vertically flipped"), @@ -490,9 +536,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( _("Effects"), "res/actions/flipY24.png", "res/actions/flipY.png") + .AddParameter("object", _("Object"), "Sprite") + .SetHidden(); - .AddParameter("object", _("Object"), "Sprite"); - + // Deprecated obj.AddAction("TourneVers", "Rotate an object toward another", "Rotate an object towards another.", @@ -504,7 +551,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .AddParameter("object", _("Object"), "Sprite") .AddParameter("objectPtr", "Rotate toward this object") .AddCodeOnlyParameter("currentScene", "") - .SetHidden(); // Deprecated + .SetHidden(); obj.AddExpression("X", _("X position of a point"), @@ -542,6 +589,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .AddParameter("object", _("Object"), "Sprite") .AddParameter("objectPointName", _("Name of the point")); + // Deprecated obj.AddExpression("Direc", _("Direction"), _("Direction of the object"), @@ -550,6 +598,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .SetHidden() .AddParameter("object", _("Object"), "Sprite"); + // Deprecated obj.AddExpression("Direction", _("Direction"), _("Direction of the object"), @@ -559,6 +608,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( // interface. .AddParameter("object", _("Object"), "Sprite"); + // Deprecated obj.AddExpression("Anim", _("Animation"), _("Animation of the object"), @@ -567,18 +617,22 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( .SetHidden() .AddParameter("object", _("Object"), "Sprite"); + // Deprecated obj.AddExpression("Animation", _("Animation"), _("Animation of the object"), _("Animations and images"), "res/actions/animation.png") + .SetHidden() .AddParameter("object", _("Object"), "Sprite"); + // Deprecated obj.AddStrExpression("AnimationName", _("Animation name"), _("Name of the animation of the object"), _("Animations and images"), "res/actions/animation.png") + .SetHidden() .AddParameter("object", _("Object"), "Sprite"); obj.AddExpression("Sprite", @@ -595,11 +649,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( "res/actions/sprite.png") .AddParameter("object", _("Object"), "Sprite"); + // Deprecated obj.AddExpression("AnimationSpeedScale", _("Animation speed scale"), _("Animation speed scale"), _("Animations and images"), "res/actions/animation.png") + .SetHidden() .AddParameter("object", _("Object"), "Sprite"); obj.AddExpression("ScaleX", @@ -607,6 +663,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( _("Scale of the width of an object"), _("Size"), "res/actions/scaleWidth_black.png") + .SetHidden() .AddParameter("object", _("Object"), "Sprite"); obj.AddExpression("ScaleY", @@ -614,14 +671,17 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension( _("Scale of the height of an object"), _("Size"), "res/actions/scaleHeight_black.png") + .SetHidden() .AddParameter("object", _("Object"), "Sprite"); + // Deprecated obj.AddExpression("Opacity", _("Opacity"), _("Opacity"), _("Opacity"), "res/actions/opacity.png") - .AddParameter("object", _("Object"), "Sprite"); + .AddParameter("object", _("Object"), "Sprite") + .SetHidden(); extension .AddCondition("Collision", diff --git a/Core/GDCore/Extensions/Metadata/BehaviorMetadata.cpp b/Core/GDCore/Extensions/Metadata/BehaviorMetadata.cpp index e8caf1ff3b..9c50d41a23 100644 --- a/Core/GDCore/Extensions/Metadata/BehaviorMetadata.cpp +++ b/Core/GDCore/Extensions/Metadata/BehaviorMetadata.cpp @@ -34,8 +34,7 @@ BehaviorMetadata::BehaviorMetadata( className(className_), iconFilename(icon24x24), instance(instance_), - sharedDatasInstance(sharedDatasInstance_), - isEventBased(false) { + sharedDatasInstance(sharedDatasInstance_) { SetFullName(gd::String(fullname_)); SetDescription(gd::String(description_)); SetDefaultName(gd::String(defaultName_)); @@ -52,29 +51,6 @@ BehaviorMetadata::BehaviorMetadata( if (sharedDatasInstance) sharedDatasInstance->SetTypeName(nameWithNamespace); } -BehaviorMetadata::BehaviorMetadata( - const gd::String& extensionNamespace, - const gd::String& nameWithNamespace, - const gd::String& fullname_, - const gd::String& defaultName_, - const gd::String& description_, - const gd::String& group_, - const gd::String& icon24x24_): BehaviorMetadata( - extensionNamespace, - nameWithNamespace, - fullname_, - defaultName_, - description_, - group_, - icon24x24_, - // Class name is the name, actually unused - defaultName_, - // It is only used to get the name for GetName. - gd::make_unique("", nameWithNamespace), - nullptr){ - isEventBased = true; -}; - gd::InstructionMetadata& BehaviorMetadata::AddCondition( const gd::String& name, const gd::String& fullname, @@ -420,10 +396,6 @@ const gd::String& BehaviorMetadata::GetName() const { } gd::Behavior& BehaviorMetadata::Get() const { - if (isEventBased) { - gd::LogFatalError("Error: Event-based behaviors don't have blueprint. " - "This method should not never be called."); - } if (!instance) { gd::LogFatalError( "Trying to get a behavior from a BehaviorMetadata that has no " @@ -434,11 +406,20 @@ gd::Behavior& BehaviorMetadata::Get() const { } gd::BehaviorsSharedData* BehaviorMetadata::GetSharedDataInstance() const { - if (isEventBased) { - gd::LogFatalError("Error: Event-based behaviors don't have blueprint. " - "This method should not never be called."); - } return sharedDatasInstance.get(); } +const std::vector& BehaviorMetadata::GetRequiredBehaviorTypes() const { + requiredBehaviors.clear(); + for (auto& property : Get().GetProperties()) { + const String& propertyName = property.first; + const gd::PropertyDescriptor& propertyDescriptor = property.second; + + if (propertyDescriptor.GetType() == "Behavior") { + requiredBehaviors.push_back(propertyDescriptor.GetExtraInfo()[0]); + } + } + return requiredBehaviors; +} + } // namespace gd diff --git a/Core/GDCore/Extensions/Metadata/BehaviorMetadata.h b/Core/GDCore/Extensions/Metadata/BehaviorMetadata.h index f5085f57f9..f9a5aee83f 100644 --- a/Core/GDCore/Extensions/Metadata/BehaviorMetadata.h +++ b/Core/GDCore/Extensions/Metadata/BehaviorMetadata.h @@ -259,6 +259,11 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta */ const gd::String& GetObjectType() const { return objectType; } + /** + * \brief Get the types of the behaviors that are required by this behavior. + */ + const std::vector& GetRequiredBehaviorTypes() const; + /** * Check if the behavior is private - it can't be used outside of its * extension. @@ -274,6 +279,21 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta return *this; } + /** + * Check if the behavior is hidden - it can be used but not attached to + * objects by users. + */ + bool IsHidden() const { return isHidden; } + + /** + * Set that the behavior is hidden - it can be used but not attached to + * objects by users. + */ + BehaviorMetadata &SetHidden() { + isHidden = true; + return *this; + } + /** * \brief Return the associated gd::Behavior, handling behavior contents. * @@ -330,12 +350,13 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta gd::String group; gd::String iconFilename; gd::String objectType; + mutable std::vector requiredBehaviors; bool isPrivate = false; + bool isHidden = false; // TODO: Nitpicking: convert these to std::unique_ptr to clarify ownership. std::shared_ptr instance; std::shared_ptr sharedDatasInstance; - bool isEventBased; }; } // namespace gd diff --git a/Core/GDCore/Extensions/Metadata/MetadataProvider.h b/Core/GDCore/Extensions/Metadata/MetadataProvider.h index 4a36f17678..92601e8fdd 100644 --- a/Core/GDCore/Extensions/Metadata/MetadataProvider.h +++ b/Core/GDCore/Extensions/Metadata/MetadataProvider.h @@ -275,6 +275,10 @@ class GD_CORE_API MetadataProvider { return &metadata == &badBehaviorMetadata; } + static bool IsBadObjectMetadata(const gd::ObjectMetadata& metadata) { + return &metadata == &badObjectInfo; + } + virtual ~MetadataProvider(); private: diff --git a/Core/GDCore/Extensions/Metadata/ObjectMetadata.h b/Core/GDCore/Extensions/Metadata/ObjectMetadata.h index 90aac5482a..239c2992bd 100644 --- a/Core/GDCore/Extensions/Metadata/ObjectMetadata.h +++ b/Core/GDCore/Extensions/Metadata/ObjectMetadata.h @@ -224,32 +224,28 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada } /** - * \brief The "capabilities" that are offered by the base object that are - * *not* supported by this object, and should be hidden in the editor - * interface. + * \brief The "capabilities" that are offered by through behaviors. */ - const std::set& GetUnsupportedBaseObjectCapabilities() const { - return unsupportedBaseObjectCapabilities; + const std::set& GetDefaultBehaviors() const { + return defaultBehaviorTypes; } /** - * \brief Add a "capability" that is offered by the base object that is *not* - * supported by this object, and should be hidden in the editor interface. + * \brief Return true if object has a default behavior of the given type. */ - ObjectMetadata& AddUnsupportedBaseObjectCapability( - const gd::String& capability) { - unsupportedBaseObjectCapabilities.insert(capability); + bool HasDefaultBehavior(const gd::String& behaviorType) const { + return defaultBehaviorTypes.find(behaviorType) != defaultBehaviorTypes.end(); + } + + /** + * \brief Add a "capability" that is offered by through a behavior. + */ + ObjectMetadata& AddDefaultBehavior( + const gd::String& behaviorType) { + defaultBehaviorTypes.insert(behaviorType); return *this; } - /** - * \brief Check if a "capability" that is offered by the base object is *not* - * supported by this object, and should be hidden in the editor interface. - */ - bool IsUnsupportedBaseObjectCapability(const gd::String& capability) const { - return unsupportedBaseObjectCapabilities.find(capability) != unsupportedBaseObjectCapabilities.end(); - } - const gd::String& GetName() const override { return name; } const gd::String& GetFullName() const override { return fullname; } const gd::String& GetCategoryFullName() const { return categoryFullName; } @@ -331,7 +327,7 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada gd::String description; gd::String iconFilename; gd::String categoryFullName; - std::set unsupportedBaseObjectCapabilities; + std::set defaultBehaviorTypes; bool hidden = false; std::shared_ptr diff --git a/Core/GDCore/Extensions/PlatformExtension.cpp b/Core/GDCore/Extensions/PlatformExtension.cpp index 532e0ac595..3628b952c5 100644 --- a/Core/GDCore/Extensions/PlatformExtension.cpp +++ b/Core/GDCore/Extensions/PlatformExtension.cpp @@ -273,25 +273,6 @@ gd::BehaviorMetadata& PlatformExtension::AddBehavior( return behaviorsInfo[nameWithNamespace]; } -gd::BehaviorMetadata& PlatformExtension::AddEventsBasedBehavior( - const gd::String& name, - const gd::String& fullname, - const gd::String& description, - const gd::String& group, - const gd::String& icon24x24) { - gd::String nameWithNamespace = GetNameSpace() + name; - behaviorsInfo[nameWithNamespace] = BehaviorMetadata(GetNameSpace(), - nameWithNamespace, - fullname, - // Default name is the name - name, - description, - group, - icon24x24) - .SetHelpPath(GetHelpPath()); - return behaviorsInfo[nameWithNamespace]; -} - gd::EffectMetadata& PlatformExtension::AddEffect(const gd::String& name) { gd::String nameWithNamespace = GetNameSpace() + name; effectsMetadata[nameWithNamespace] = EffectMetadata(nameWithNamespace); diff --git a/Core/GDCore/IDE/Events/BehaviorDefaultFlagClearer.cpp b/Core/GDCore/IDE/Events/BehaviorDefaultFlagClearer.cpp new file mode 100644 index 0000000000..c70131d1a1 --- /dev/null +++ b/Core/GDCore/IDE/Events/BehaviorDefaultFlagClearer.cpp @@ -0,0 +1,23 @@ +#include "BehaviorDefaultFlagClearer.h" + +#include "GDCore/Events/Instruction.h" +#include "GDCore/Extensions/Metadata/MetadataProvider.h" +#include "GDCore/Extensions/PlatformExtension.h" +#include "GDCore/IDE/WholeProjectRefactorer.h" +#include "GDCore/IDE/Events/ExpressionTypeFinder.h" +#include "GDCore/Project/Behavior.h" +#include "GDCore/Project/Object.h" +#include "GDCore/Project/Project.h" + +namespace gd { + +void BehaviorDefaultFlagClearer::DoVisitObject(gd::Object& object) { +}; + +void BehaviorDefaultFlagClearer::DoVisitBehavior(gd::Behavior& behavior) { + behavior.SetDefaultBehavior(false); +}; + +BehaviorDefaultFlagClearer::~BehaviorDefaultFlagClearer() {} + +} // namespace gd diff --git a/Core/GDCore/IDE/Events/BehaviorDefaultFlagClearer.h b/Core/GDCore/IDE/Events/BehaviorDefaultFlagClearer.h new file mode 100644 index 0000000000..4a6cc06d7d --- /dev/null +++ b/Core/GDCore/IDE/Events/BehaviorDefaultFlagClearer.h @@ -0,0 +1,34 @@ +/* + * GDevelop Core + * Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the MIT License. + */ + +#pragma once +#include + +#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h" +#include "GDCore/String.h" + +namespace gd { +class Object; +class Behavior; +} // namespace gd + +namespace gd { + +/** + * @brief This is used for project exports to keep default behaviors in + * serialized data used by Runtime. + */ +class GD_CORE_API BehaviorDefaultFlagClearer : public ArbitraryObjectsWorker { + public: + BehaviorDefaultFlagClearer() {}; + virtual ~BehaviorDefaultFlagClearer(); + + private: + void DoVisitObject(gd::Object& object) override; + void DoVisitBehavior(gd::Behavior& behavior) override; +}; + +}; // namespace gd diff --git a/Core/GDCore/IDE/Events/ExpressionValidator.cpp b/Core/GDCore/IDE/Events/ExpressionValidator.cpp index fde97dd281..a3d69c9612 100644 --- a/Core/GDCore/IDE/Events/ExpressionValidator.cpp +++ b/Core/GDCore/IDE/Events/ExpressionValidator.cpp @@ -104,14 +104,6 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(const gd::Functi !metadata.GetRequiredBaseObjectCapability().empty()) { const gd::ObjectMetadata &objectMetadata = MetadataProvider::GetObjectMetadata(platform, objectType); - - if (objectMetadata.IsUnsupportedBaseObjectCapability( - metadata.GetRequiredBaseObjectCapability())) { - RaiseTypeError( - _("This expression exists, but it can't be used on this object."), - function.objectNameLocation); - return returnType; - } } if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) { diff --git a/Core/GDCore/IDE/ProjectStripper.cpp b/Core/GDCore/IDE/ProjectStripper.cpp index 2ae6a285ee..3778ccf808 100644 --- a/Core/GDCore/IDE/ProjectStripper.cpp +++ b/Core/GDCore/IDE/ProjectStripper.cpp @@ -11,6 +11,8 @@ #include "GDCore/Project/ExternalLayout.h" #include "GDCore/Project/Layout.h" #include "GDCore/Project/Project.h" +#include "GDCore/IDE/WholeProjectBrowser.h" +#include "GDCore/IDE/Events/BehaviorDefaultFlagClearer.h" namespace gd { @@ -19,6 +21,10 @@ void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project &project) { while (project.GetExternalEventsCount() > 0) project.RemoveExternalEvents(project.GetExternalEvents(0).GetName()); + gd::BehaviorDefaultFlagClearer behaviorDefaultFlagClearer; + gd::WholeProjectBrowser wholeProjectBrowser; + wholeProjectBrowser.ExposeObjects(project, behaviorDefaultFlagClearer); + for (unsigned int i = 0; i < project.GetLayoutsCount(); ++i) { project.GetLayout(i).GetObjectGroups().Clear(); project.GetLayout(i).GetEvents().Clear(); diff --git a/Core/GDCore/Project/Behavior.h b/Core/GDCore/Project/Behavior.h index a570982c45..70f1ccbc6b 100644 --- a/Core/GDCore/Project/Behavior.h +++ b/Core/GDCore/Project/Behavior.h @@ -23,11 +23,23 @@ namespace gd { class GD_CORE_API Behavior: public BehaviorConfigurationContainer { public: - Behavior(): BehaviorConfigurationContainer() {}; + Behavior(): BehaviorConfigurationContainer(), isDefaultBehavior(false) {}; Behavior(const gd::String& name_, const gd::String& type_) - : BehaviorConfigurationContainer(name_, type_) {}; + : BehaviorConfigurationContainer(name_, type_), + isDefaultBehavior(false) {}; virtual ~Behavior(); virtual Behavior* Clone() const override { return new Behavior(*this); } + + bool IsDefaultBehavior() const { + return isDefaultBehavior; + } + + void SetDefaultBehavior(bool isDefaultBehavior_) { + isDefaultBehavior = isDefaultBehavior_; + } + + private: + bool isDefaultBehavior; }; } // namespace gd diff --git a/Core/GDCore/Project/Layout.cpp b/Core/GDCore/Project/Layout.cpp index d1b33c8657..12c30bbbcb 100644 --- a/Core/GDCore/Project/Layout.cpp +++ b/Core/GDCore/Project/Layout.cpp @@ -507,6 +507,81 @@ gd::String GD_CORE_API GetTypeOfObject(const gd::ObjectsContainer& project, return type; } +void GD_CORE_API FilterBehaviorNamesFromObject( + const gd::Object &object, const gd::String &behaviorType, + std::vector &behaviorNames) { + for (size_t i = 0; i < behaviorNames.size(); i++) { + auto &behaviorName = behaviorNames[i]; + if (!object.HasBehaviorNamed(behaviorName) || + object.GetBehavior(behaviorName).GetTypeName() != behaviorType) { + behaviorNames.erase(behaviorNames.begin() + i); + } + } +} + +std::vector GD_CORE_API GetBehaviorNamesInObjectOrGroup( + const gd::ObjectsContainer &project, const gd::ObjectsContainer &layout, + const gd::String &objectOrGroupName, const gd::String &behaviorType, + bool searchInGroups) { + // Search in objects + if (layout.HasObjectNamed(objectOrGroupName)) { + auto &object = layout.GetObject(objectOrGroupName); + auto behaviorNames = object.GetAllBehaviorNames(); + FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames); + return behaviorNames; + } + if (project.HasObjectNamed(objectOrGroupName)) { + auto &object = project.GetObject(objectOrGroupName); + auto behaviorNames = object.GetAllBehaviorNames(); + FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames); + return behaviorNames; + } + + if (!searchInGroups) { + std::vector behaviorNames; + return behaviorNames; + } + + // Search in groups + const gd::ObjectsContainer *container; + if (layout.GetObjectGroups().Has(objectOrGroupName)) { + container = &layout; + } else if (project.GetObjectGroups().Has(objectOrGroupName)) { + container = &project; + } else { + std::vector behaviorNames; + return behaviorNames; + } + const vector &groupsObjects = + container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames(); + // Empty groups don't contain any behavior. + if (groupsObjects.empty()) { + std::vector behaviorNames; + return behaviorNames; + } + + auto behaviorNames = GetBehaviorNamesInObjectOrGroup( + project, layout, groupsObjects[0], behaviorType, false); + for (size_t i = 1; i < groupsObjects.size(); i++) { + auto &objectName = groupsObjects[i]; + + if (layout.HasObjectNamed(objectName)) { + auto &object = layout.GetObject(objectName); + FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames); + return behaviorNames; + } + if (project.HasObjectNamed(objectName)) { + auto &object = project.GetObject(objectName); + FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames); + return behaviorNames; + } + if (behaviorNames.size() == 0) { + return behaviorNames; + } + } + return behaviorNames; +} + bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project, const gd::ObjectsContainer &layout, const gd::String &objectOrGroupName, @@ -520,6 +595,10 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project, return project.GetObject(objectOrGroupName).HasBehaviorNamed(behaviorName); } + if (!searchInGroups) { + return false; + } + // Search in groups const gd::ObjectsContainer *container; if (layout.GetObjectGroups().Has(objectOrGroupName)) { @@ -545,6 +624,52 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project, return true; } +bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project, + const gd::ObjectsContainer& layout, + gd::String objectOrGroupName, + gd::String behaviorName, + bool searchInGroups) { + // Search in objects + if (layout.HasObjectNamed(objectOrGroupName)) { + auto &object = layout.GetObject(objectOrGroupName); + return object.HasBehaviorNamed(behaviorName) && + object.GetBehavior(behaviorName).IsDefaultBehavior(); + } + if (project.HasObjectNamed(objectOrGroupName)) { + auto &object = project.GetObject(objectOrGroupName); + return object.HasBehaviorNamed(behaviorName) && + object.GetBehavior(behaviorName).IsDefaultBehavior(); + } + + if (!searchInGroups) { + return false; + } + + // Search in groups + const gd::ObjectsContainer *container; + if (layout.GetObjectGroups().Has(objectOrGroupName)) { + container = &layout; + } else if (project.GetObjectGroups().Has(objectOrGroupName)) { + container = &project; + } else { + return false; + } + const vector &groupsObjects = + container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames(); + // Empty groups don't contain any behavior. + if (groupsObjects.empty()) { + return false; + } + // Check that all objects have the same type. + for (auto &&object : groupsObjects) { + if (!IsDefaultBehavior(project, layout, object, behaviorName, + false)) { + return false; + } + } + return true; +} + gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContainer& project, const gd::ObjectsContainer& layout, const gd::String& objectOrGroupName, @@ -562,6 +687,10 @@ gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContain object.GetBehavior(behaviorName).GetTypeName() : ""; } + if (!searchInGroups) { + return ""; + } + // Search in groups const gd::ObjectsContainer *container; if (layout.GetObjectGroups().Has(objectOrGroupName)) { diff --git a/Core/GDCore/Project/Layout.h b/Core/GDCore/Project/Layout.h index cd21d7cdb1..4360544b6b 100644 --- a/Core/GDCore/Project/Layout.h +++ b/Core/GDCore/Project/Layout.h @@ -443,7 +443,7 @@ gd::String GD_CORE_API GetTypeOfObject(const ObjectsContainer& game, gd::String objectName, bool searchInGroups = true); /** - * \brief Check if an object or all object of a group has a behavior. + * \brief Check if an object or all objects of a group has a behavior. */ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project, const gd::ObjectsContainer &layout, @@ -451,7 +451,25 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project, const gd::String &behaviorName, bool searchInGroups = true); /** - * \brief Get the type of a behavior if an object or some object of a group has it. + * \brief Get the names of behavior of a given type if an object or all objects of a group has it. + */ +std::vector GD_CORE_API GetBehaviorNamesInObjectOrGroup( + const gd::ObjectsContainer &project, const gd::ObjectsContainer &layout, + const gd::String &objectOrGroupName, const gd::String &behaviorType, + bool searchInGroups); + +/** + * \brief Check if a behavior is a default one or doesn't exist in an object or + * all objects of a group. + */ +bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project, + const gd::ObjectsContainer& layout, + gd::String objectOrGroupName, + gd::String behaviorName, + bool searchInGroups = true); + +/** + * \brief Get the type of a behavior if an object or all objects of a group has it. */ gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContainer &project, const gd::ObjectsContainer &layout, diff --git a/Core/GDCore/Project/Object.cpp b/Core/GDCore/Project/Object.cpp index ab0f0eb104..8868c99560 100644 --- a/Core/GDCore/Project/Object.cpp +++ b/Core/GDCore/Project/Object.cpp @@ -134,7 +134,6 @@ void Object::UnserializeFrom(gd::Project& project, objectVariables.UnserializeFrom( element.GetChild("variables", 0, "Variables")); - behaviors.clear(); if (element.HasChild("effects")) { const SerializerElement& effectsElement = element.GetChild("effects"); @@ -210,6 +209,11 @@ void Object::SerializeTo(SerializerElement& element) const { std::vector allBehaviors = GetAllBehaviorNames(); for (std::size_t i = 0; i < allBehaviors.size(); ++i) { const gd::Behavior& behavior = GetBehavior(allBehaviors[i]); + // Default behaviors are added at the object creation according to metadata. + // They don't need to be serialized. + if (behavior.IsDefaultBehavior()) { + continue; + } SerializerElement& behaviorElement = behaviorsElement.AddChild("behavior"); behavior.SerializeTo(behaviorElement); diff --git a/Core/GDCore/Project/Project.cpp b/Core/GDCore/Project/Project.cpp index eb1549a6f0..079ac1b4fa 100644 --- a/Core/GDCore/Project/Project.cpp +++ b/Core/GDCore/Project/Project.cpp @@ -86,9 +86,47 @@ Project::~Project() {} void Project::ResetProjectUuid() { projectUuid = UUID::MakeUuid4(); } -std::unique_ptr Project::CreateObject( - const gd::String& type, const gd::String& name) const { - return gd::make_unique(name, type, CreateObjectConfiguration(type)); +std::unique_ptr +Project::CreateObject(const gd::String &objectType, const gd::String &name) const { + std::unique_ptr object = + gd::make_unique(name, objectType, CreateObjectConfiguration(objectType)); + + auto &platform = GetCurrentPlatform(); + auto &project = *this; + auto addDefaultBehavior = + [&platform, + &project, + &object, + &objectType](const gd::String& behaviorType) { + auto &behaviorMetadata = + gd::MetadataProvider::GetBehaviorMetadata(platform, behaviorType); + if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) { + gd::LogWarning("Object: " + objectType + " has an unknown default behavior: " + behaviorType); + return; + } + auto* behavior = object->AddNewBehavior(project, behaviorType, + behaviorMetadata.GetDefaultName()); + behavior->SetDefaultBehavior(true); + }; + + if (Project::HasEventsBasedObject(objectType)) { + addDefaultBehavior("EffectCapability::EffectBehavior"); + addDefaultBehavior("ResizableCapability::ResizableBehavior"); + addDefaultBehavior("ScalableCapability::ScalableBehavior"); + addDefaultBehavior("FlippableCapability::FlippableBehavior"); + } + else { + auto &objectMetadata = gd::MetadataProvider::GetObjectMetadata(platform, objectType); + if (MetadataProvider::IsBadObjectMetadata(objectMetadata)) { + gd::LogWarning("Object: " + name + " has an unknown type: " + objectType); + } + for (auto &behaviorType : objectMetadata.GetDefaultBehaviors()) { + addDefaultBehavior(behaviorType); + } + } + + + return std::move(object); } std::unique_ptr Project::CreateObjectConfiguration( diff --git a/Core/tests/DummyPlatform.cpp b/Core/tests/DummyPlatform.cpp index 0ea780a027..cffe6a8586 100644 --- a/Core/tests/DummyPlatform.cpp +++ b/Core/tests/DummyPlatform.cpp @@ -113,17 +113,6 @@ void SetupProjectWithDummyPlatform(gd::Project& project, auto& baseObject = baseObjectExtension->AddObject( "", "Dummy Base Object", "Dummy Base Object", ""); - // Add this expression for all objects. But it requires a "capability". - baseObject - .AddStrExpression("GetSomethingRequiringEffectCapability", - "Get something, but this requires the effect capability for the object.", - "", - "", - "") - .AddParameter("object", _("Object"), "") - .AddParameter("expression", _("Number parameter")) - .SetRequiresBaseObjectCapability("effect") - .SetFunctionName("getSomethingRequiringEffectCapability"); baseObject .AddExpression("GetFromBaseExpression", "This works on any object.", @@ -133,6 +122,84 @@ void SetupProjectWithDummyPlatform(gd::Project& project, .AddParameter("object", _("Object"), "") .SetFunctionName("getFromBaseExpression"); +// Declare default behaviors that are used by event-based objects to avoid +// warnings. +{ + std::shared_ptr extension = + std::shared_ptr(new gd::PlatformExtension); + extension + ->SetExtensionInformation("ResizableCapability", + _("Resizable capability"), + _("Change the object dimensions."), + "", ""); + gd::BehaviorMetadata& aut = extension->AddBehavior( + "ResizableBehavior", + _("Resizable capability"), + "Resizable", + _("Change the object dimensions."), + "", "", "", + std::make_shared(), + std::make_shared()) + .SetHidden(); + platform.AddExtension(extension); +} +{ + std::shared_ptr extension = + std::shared_ptr(new gd::PlatformExtension); + extension + ->SetExtensionInformation("ScalableCapability", + _("Scalable capability"), + _("Change the object scale."), + "", ""); + gd::BehaviorMetadata& aut = extension->AddBehavior( + "ScalableBehavior", + _("Scalable capability"), + "Scale", + _("Change the object scale."), + "", "", "", + std::make_shared(), + std::make_shared()) + .SetHidden(); + platform.AddExtension(extension); +} +{ + std::shared_ptr extension = + std::shared_ptr(new gd::PlatformExtension); + extension + ->SetExtensionInformation("FlippableCapability", + _("Flippable capability"), + _("Flip objects."), + "", ""); + gd::BehaviorMetadata& aut = extension->AddBehavior( + "FlippableBehavior", + _("Flippable capability"), + "Flippable", + _("Flip objects."), + "", "", "", + std::make_shared(), + std::make_shared()) + .SetHidden(); + platform.AddExtension(extension); +} +{ + std::shared_ptr extension = + std::shared_ptr(new gd::PlatformExtension); + extension + ->SetExtensionInformation("EffectCapability", + _("Effect capability"), + _("Apply visual effects to objects."), + "", ""); + gd::BehaviorMetadata& aut = extension->AddBehavior( + "EffectBehavior", + _("Effect capability"), + "Effect", + _("Apply visual effects to objects."), + "", "", "", + std::make_shared(), + std::make_shared()) + .SetHidden(); + platform.AddExtension(extension); +} // Create an extension with various stuff inside. std::shared_ptr extension = std::shared_ptr(new gd::PlatformExtension); @@ -396,14 +463,53 @@ void SetupProjectWithDummyPlatform(gd::Project& project, gd::make_unique()); } + { + gd::BehaviorMetadata &effectBehavior = + extension + ->AddBehavior("EffectBehavior", + _("Effect capability"), + "Effect", + _("Apply visual effects to objects."), + "", + "res/actions/effect24.png", "EffectBehavior", + std::make_shared(), + std::make_shared()) + .SetHidden(); + + // Add this expression for the effect capability. + effectBehavior + .AddStrExpression("GetSomethingRequiringEffectCapability", + "Get something, but this requires the effect " + "capability for the object.", + "", + "", + "") + .AddParameter("object", _("Object"), "") + .AddParameter("behavior", _("Behavior"), "EffectBehavior") + .AddParameter("expression", _("Number parameter")) + .SetFunctionName("getSomethingRequiringEffectCapability"); + } { auto& object = extension ->AddObject( - "FakeObjectWithUnsupportedCapability", - "FakeObjectWithUnsupportedCapability", - "This is FakeObjectWithUnsupportedCapability", + "FakeObjectWithDefaultBehavior", + "FakeObjectWithDefaultBehavior", + "This is FakeObjectWithDefaultBehavior", "") - .AddUnsupportedBaseObjectCapability("effect"); + .AddDefaultBehavior("MyExtension::EffectBehavior"); + } + + // Declare an event-based behavior to avoid warnings. + { + extension->AddBehavior("MyEventsBasedBehavior", + "My event-based behavior", + "MyEventsBasedBehavior", + "Avoid warnings", + "Group", + "Icon.png", + "MyEventsBasedBehavior", + gd::make_unique(), + gd::make_unique()); } // Actions and expressions with several parameter types. diff --git a/Core/tests/ExpressionCodeGenerator.cpp b/Core/tests/ExpressionCodeGenerator.cpp index c06797fa7e..c6a566b250 100644 --- a/Core/tests/ExpressionCodeGenerator.cpp +++ b/Core/tests/ExpressionCodeGenerator.cpp @@ -24,13 +24,13 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") { layout1.InsertNewObject( project, "MyExtension::Sprite", "MyOtherSpriteObject", 1); layout1.InsertNewObject(project, - "MyExtension::FakeObjectWithUnsupportedCapability", - "MyFakeObjectWithUnsupportedCapability", + "MyExtension::FakeObjectWithDefaultBehavior", + "FakeObjectWithDefaultBehavior", 2); auto &group = layout1.GetObjectGroups().InsertNew("AllObjects"); group.AddObject("MySpriteObject"); group.AddObject("MyOtherSpriteObject"); - group.AddObject("MyFakeObjectWithUnsupportedCapability"); + group.AddObject("FakeObjectWithDefaultBehavior"); gd::ExpressionParser2 parser; @@ -342,7 +342,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") { SECTION("supported capability") { // Capability is supported, so the expression is valid. auto node = parser.ParseExpression( - "MySpriteObject.GetSomethingRequiringEffectCapability(123)"); + "FakeObjectWithDefaultBehavior.Effect::GetSomethingRequiringEffectCapability(123)"); gd::ExpressionCodeGenerator expressionCodeGenerator("string", "", codeGenerator, @@ -352,12 +352,12 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") { node->Visit(expressionCodeGenerator); REQUIRE( expressionCodeGenerator.GetOutput() == - "MySpriteObject.getSomethingRequiringEffectCapability(123) ?? \"\""); + "FakeObjectWithDefaultBehavior::Effect.getSomethingRequiringEffectCapability(123) ?? \"\""); } SECTION("unsupported capability") { // Capability is not supported, so the expression is not even valid. auto node = - parser.ParseExpression("MyFakeObjectWithUnsupportedCapability." + parser.ParseExpression("MySpriteObject::Effect." "GetSomethingRequiringEffectCapability(123)"); gd::ExpressionCodeGenerator expressionCodeGenerator("string", "", @@ -366,14 +366,16 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") { REQUIRE(node); node->Visit(expressionCodeGenerator); - REQUIRE(expressionCodeGenerator.GetOutput() == "\"\""); + REQUIRE( + expressionCodeGenerator.GetOutput() == + "/* Error during generation, function not found: GetSomethingRequiringEffectCapability */ \"\""); } SECTION("group with partial support") { // We use a group, capability is supported only by one object of the // group. The expression itself is valid, but code generation should skip // the objects with unsupported capability. auto node = parser.ParseExpression( - "AllObjects.GetSomethingRequiringEffectCapability(123)"); + "AllObjects.Effect::GetSomethingRequiringEffectCapability(123)"); gd::ExpressionCodeGenerator expressionCodeGenerator("string", "", codeGenerator, @@ -381,10 +383,13 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") { REQUIRE(node); node->Visit(expressionCodeGenerator); - REQUIRE( - expressionCodeGenerator.GetOutput() == - "MyOtherSpriteObject.getSomethingRequiringEffectCapability(123) ?? " - "MySpriteObject.getSomethingRequiringEffectCapability(123) ?? \"\""); + REQUIRE(expressionCodeGenerator.GetOutput() == + "FakeObjectWithDefaultBehavior::Effect." + "getSomethingRequiringEffectCapability(123) ?? " + "MyOtherSpriteObject::Effect." + "getSomethingRequiringEffectCapability(123) ?? " + "MySpriteObject::Effect.getSomethingRequiringEffectCapability(" + "123) ?? \"\""); } } SECTION("Function name") { diff --git a/Core/tests/ExpressionParser2.cpp b/Core/tests/ExpressionParser2.cpp index de63bbaad3..327715c9ca 100644 --- a/Core/tests/ExpressionParser2.cpp +++ b/Core/tests/ExpressionParser2.cpp @@ -21,7 +21,9 @@ TEST_CASE("ExpressionParser2", "[common][events]") { SetupProjectWithDummyPlatform(project, platform); auto &layout1 = project.InsertNewLayout("Layout1", 0); - auto &myObject = layout1.InsertNewObject(project, "BuiltinObject", "MyObject", 0); + // Create an instance of BuiltinObject. + // This is not possible in practice. + auto &myObject = layout1.InsertNewObject(project, "", "MyObject", 0); myObject.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior"); auto &myGroup = layout1.GetObjectGroups().InsertNew("MyGroup", 0); @@ -29,8 +31,8 @@ TEST_CASE("ExpressionParser2", "[common][events]") { layout1.InsertNewObject(project, "MyExtension::Sprite", "MySpriteObject", 1); layout1.InsertNewObject(project, - "MyExtension::FakeObjectWithUnsupportedCapability", - "MyFakeObjectWithUnsupportedCapability", + "MyExtension::FakeObjectWithDefaultBehavior", + "FakeObjectWithDefaultBehavior", 2); gd::ExpressionParser2 parser; @@ -1984,29 +1986,29 @@ TEST_CASE("ExpressionParser2", "[common][events]") { } SECTION( - "Valid function call with an object expression requiring a capability") { + "Valid function call with a default behavior") { auto node = parser.ParseExpression( - "MySpriteObject.GetSomethingRequiringEffectCapability(123)"); + "FakeObjectWithDefaultBehavior.Effect::GetSomethingRequiringEffectCapability(123)"); REQUIRE(node != nullptr); gd::ExpressionValidator validator(platform, project, layout1, "string"); node->Visit(validator); - REQUIRE(validator.GetFatalErrors().size() == 0); + REQUIRE(validator.GetAllErrors().size() == 0); } SECTION( - "Invalid function call with an object expression requiring a " - "capability") { + "Invalid function call with an object that doesn't have a default behavior") { auto node = - parser.ParseExpression("MyFakeObjectWithUnsupportedCapability." + parser.ParseExpression("MySpriteObject.Effect::" "GetSomethingRequiringEffectCapability(123)"); REQUIRE(node != nullptr); gd::ExpressionValidator validator(platform, project, layout1, "string"); node->Visit(validator); - REQUIRE(validator.GetFatalErrors().size() == 1); - REQUIRE(validator.GetFatalErrors()[0]->GetMessage() == - "This expression exists, but it can't be used on this object."); + REQUIRE(validator.GetFatalErrors().size() == 0); + REQUIRE(validator.GetAllErrors().size() == 1); + REQUIRE(validator.GetAllErrors()[0]->GetMessage() == + "This behavior is not attached to this object."); } SECTION("Fuzzy/random tests") { diff --git a/Core/tests/Object.cpp b/Core/tests/Object.cpp new file mode 100644 index 0000000000..c20bd1ab2f --- /dev/null +++ b/Core/tests/Object.cpp @@ -0,0 +1,45 @@ +/* + * GDevelop Core + * Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the MIT License. + */ +/** + * @file Tests covering serialization to JSON. + */ +#include "GDCore/Project/Object.h" +#include "DummyPlatform.h" +#include "GDCore/CommonTools.h" +#include "GDCore/Events/Builtin/StandardEvent.h" +#include "GDCore/Events/Event.h" +#include "GDCore/Events/EventsList.h" +#include "GDCore/Events/Serialization.h" +#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h" +#include "GDCore/Extensions/Platform.h" +#include "GDCore/Project/CustomObjectConfiguration.h" +#include "GDCore/Project/EventsFunctionsExtension.h" +#include "GDCore/Project/Layout.h" +#include "GDCore/Project/ObjectsContainer.h" +#include "GDCore/Project/Project.h" +#include "GDCore/Project/Variable.h" +#include "GDCore/Serialization/Serializer.h" +#include "GDCore/Tools/SystemStats.h" +#include "GDCore/Tools/VersionWrapper.h" +#include "catch.hpp" + +using namespace gd; + +TEST_CASE("Object", "[common]") { + + SECTION("Create an object with default behaviors") { + gd::Platform platform; + gd::Project project; + SetupProjectWithDummyPlatform(project, platform); + + gd::Layout &layout = project.InsertNewLayout("Scene", 0); + gd::Object &object = layout.InsertNewObject( + project, "MyExtension::FakeObjectWithDefaultBehavior", "MyObject", 0); + + REQUIRE(object.HasBehaviorNamed("Effect")); + REQUIRE(object.GetBehavior("Effect").IsDefaultBehavior()); + } +} \ No newline at end of file diff --git a/Core/tests/ObjectSerialization.cpp b/Core/tests/ObjectSerialization.cpp index 912ff673db..8a712b8bc3 100644 --- a/Core/tests/ObjectSerialization.cpp +++ b/Core/tests/ObjectSerialization.cpp @@ -225,4 +225,41 @@ TEST_CASE("ObjectSerialization", "[common]") { auto clonedObject = object.Clone(); CheckCustomObjectConfiguration(*(clonedObject.get())); } + + SECTION("Exclude default behaviors from serialization") { + gd::Platform platform; + gd::Project project; + SetupProjectWithDummyPlatform(project, platform); + + gd::Layout &layout = project.InsertNewLayout("Scene", 0); + gd::Object &object = layout.InsertNewObject( + project, "MyExtension::FakeObjectWithDefaultBehavior", "MyObject", 0); + REQUIRE(object.HasBehaviorNamed("Effect")); + + object.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior"); + REQUIRE(object.HasBehaviorNamed("MyBehavior")); + + SerializerElement projectElement; + project.SerializeTo(projectElement); + + // Check serialized behaviors. + auto &layoutsElement = projectElement.GetChild("layouts"); + layoutsElement.ConsiderAsArrayOf("layout"); + REQUIRE(layoutsElement.GetChildrenCount() == 1); + auto &layoutElement = layoutsElement.GetChild(0); + + REQUIRE(layoutElement.GetStringAttribute("name") == "Scene"); + REQUIRE(layoutElement.HasChild("objects")); + + auto &objectsElement = layoutElement.GetChild("objects"); + objectsElement.ConsiderAsArrayOf("object"); + REQUIRE(objectsElement.GetChildrenCount() == 1); + auto &objectElement = objectsElement.GetChild(0); + + auto &behaviorsElement = objectElement.GetChild("behaviors"); + behaviorsElement.ConsiderAsArrayOf("behavior"); + REQUIRE(behaviorsElement.GetChildrenCount() == 1); + auto &behaviorElement = behaviorsElement.GetChild(0); + REQUIRE(behaviorElement.GetStringAttribute("name") == "MyBehavior"); + } } \ No newline at end of file diff --git a/Extensions/3D/A_RuntimeObject3D.ts b/Extensions/3D/A_RuntimeObject3D.ts index 1d2cc0cfc3..5aa2af4868 100644 --- a/Extensions/3D/A_RuntimeObject3D.ts +++ b/Extensions/3D/A_RuntimeObject3D.ts @@ -16,7 +16,13 @@ namespace gdjs { /** * Base class for 3D objects. */ - export abstract class RuntimeObject3D extends gdjs.RuntimeObject { + export abstract class RuntimeObject3D + extends gdjs.RuntimeObject + implements + gdjs.Resizable, + gdjs.Scalable, + gdjs.Flippable, + gdjs.Base3DHandler { /** * Position on the Z axis. */ @@ -257,6 +263,11 @@ namespace gdjs { this.invalidateHitboxes(); } + setSize(newWidth: number, newHeight: number): void { + this.setWidth(newWidth); + this.setHeight(newHeight); + } + /** * Set the object size on the Z axis (called "depth"). */ diff --git a/Extensions/3D/Base3DBehavior.ts b/Extensions/3D/Base3DBehavior.ts new file mode 100644 index 0000000000..8af42d2949 --- /dev/null +++ b/Extensions/3D/Base3DBehavior.ts @@ -0,0 +1,189 @@ +/* + * GDevelop JS Platform + * Copyright 2013-2023 Florian Rival (Florian.Rival@gmail.com). All rights reserved. + * This project is released under the MIT License. + */ +namespace gdjs { + export interface Base3DHandler { + /** + * Set the object position on the Z axis. + */ + setZ(z: float): void; + + /** + * Get the object position on the Z axis. + */ + getZ(): float; + + /** + * Set the object rotation on the X axis. + * + * This is an Euler angle. Objects use the `ZYX` order. + * + * @param angle the rotation angle on the X axis in degree + */ + setRotationX(angle: float): void; + + /** + * Set the object rotation on the Y axis. + * + * This is an Euler angle. Objects use the `ZYX` order. + * + * @param angle the rotation angle on the Y axis in degree + */ + setRotationY(angle: float): void; + + /** + * Get the object rotation on the X axis in degree. + * + * This is an Euler angle. Objects use the `ZYX` order. + */ + getRotationX(): float; + + /** + * Get the object rotation on the Y axis in degree. + * + * This is an Euler angle. Objects use the `ZYX` order. + */ + getRotationY(): float; + + /** + * Turn the object around the scene X axis at its center. + * @param deltaAngle the rotation angle in degree + */ + turnAroundX(deltaAngle: float): void; + + /** + * Turn the object around the scene Y axis at its center. + * @param deltaAngle the rotation angle in degree + */ + turnAroundY(deltaAngle: float): void; + + /** + * Turn the object around the scene Z axis at its center. + * @param deltaAngle the rotation angle in degree + */ + turnAroundZ(deltaAngle: float): void; + + /** + * Get the object size on the Z axis (called "depth"). + */ + getDepth(): float; + + /** + * Set the object size on the Z axis (called "depth"). + */ + setDepth(depth: float): void; + + /** + * Change the scale on Z axis of the object (changing its depth). + * + * @param newScale The new scale (must be greater than 0). + */ + setScaleZ(newScale: number): void; + + /** + * Get the scale of the object on Z axis. + * + * @return the scale of the object on Z axis + */ + getScaleZ(): float; + + flipZ(enable: boolean): void; + + isFlippedZ(): boolean; + } + + /** + * A behavior that forwards the Base3D interface to its object. + */ + export class Base3DBehavior + extends gdjs.RuntimeBehavior + implements Base3DHandler { + private object: gdjs.RuntimeObject & Base3DHandler; + + constructor( + instanceContainer: gdjs.RuntimeInstanceContainer, + behaviorData, + owner: gdjs.RuntimeObject & Base3DHandler + ) { + super(instanceContainer, behaviorData, owner); + this.object = owner; + } + + updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean { + // Nothing to update. + return true; + } + + onDeActivate() {} + + onDestroy() {} + + doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {} + + doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {} + + setZ(z: float): void { + this.object.setZ(z); + } + + getZ(): float { + return this.object.getZ(); + } + + setRotationX(angle: float): void { + this.object.setRotationX(angle); + } + + setRotationY(angle: float): void { + this.object.setRotationY(angle); + } + + getRotationX(): float { + return this.object.getRotationX(); + } + + getRotationY(): float { + return this.object.getRotationY(); + } + + turnAroundX(deltaAngle: float): void { + this.object.turnAroundX(deltaAngle); + } + + turnAroundY(deltaAngle: float): void { + this.object.turnAroundY(deltaAngle); + } + + turnAroundZ(deltaAngle: float): void { + this.object.turnAroundZ(deltaAngle); + } + + getDepth(): float { + return this.object.getDepth(); + } + + setDepth(depth: float): void { + this.object.setDepth(depth); + } + + setScaleZ(newScale: number): void { + this.object.setScaleZ(newScale); + } + + getScaleZ(): float { + return this.object.getScaleZ(); + } + + flipZ(enable: boolean): void { + this.object.flipZ(enable); + } + + isFlippedZ(): boolean { + return this.object.isFlippedZ(); + } + } + + gdjs.registerBehavior('Scene3D::Base3DBehavior', gdjs.Base3DBehavior); +} diff --git a/Extensions/3D/JsExtension.js b/Extensions/3D/JsExtension.js index 98434ad556..7020646577 100644 --- a/Extensions/3D/JsExtension.js +++ b/Extensions/3D/JsExtension.js @@ -38,6 +38,191 @@ module.exports = { .addInstructionOrExpressionGroupMetadata(_('3D')) .setIcon('res/conditions/3d_box.svg'); + { + const base3D = extension.addBehavior( + "Base3DBehavior", + _("3D capability"), + "Object3D", + _("Move the object in 3D space."), + "", + "res/conditions/3d_box.svg", + "Base3DBehavior", + new gd.Behavior(), + new gd.BehaviorsSharedData()) + .setHidden() + .setIncludeFile('Extensions/3D/Base3DBehavior.js'); + + base3D + .addExpressionAndConditionAndAction( + 'number', + 'Z', + _('Z (elevation)'), + _('the Z position (the "elevation")'), + _('the Z position'), + _('Position'), + 'res/conditions/3d_box.svg' + ) + .addParameter('object', _('3D object')) + .addParameter("behavior", _("Behavior"), "Base3DBehavior") + .useStandardParameters('number', gd.ParameterOptions.makeNewOptions()) + .setFunctionName('setZ') + .setGetter('getZ'); + + base3D + .addExpressionAndConditionAndAction( + 'number', + 'Depth', + _('Depth (size on Z axis)'), + _('the depth (size on Z axis)'), + _('the depth'), + _('Size'), + 'res/conditions/3d_box.svg' + ) + .addParameter('object', _('3D object')) + .addParameter("behavior", _("Behavior"), "Base3DBehavior") + .useStandardParameters('number', gd.ParameterOptions.makeNewOptions()) + .setFunctionName('setDepth') + .setGetter('getDepth'); + + base3D + .addExpressionAndConditionAndAction( + 'number', + 'ScaleZ', + _('Scale on Z axis'), + _("the scale on Z axis of an object (default scale is 1)"), + _("the scale on Z axis scale"), + _('Scale'), + 'res/conditions/3d_box.svg' + ) + .addParameter('object', _('3D object')) + .addParameter("behavior", _("Behavior"), "Base3DBehavior") + .useStandardParameters( + 'number', + gd.ParameterOptions.makeNewOptions().setDescription( + _('Scale (1 by default)') + ) + ) + .markAsAdvanced() + .setFunctionName('setScaleZ') + .setGetter('getScaleZ'); + + base3D + .addScopedAction( + 'FlipZ', + _('Flip the object on Z'), + _('Flip the object on Z axis'), + _('Flip on Z axis _PARAM0_: _PARAM2_'), + _('Effects'), + 'res/conditions/3d_box.svg', + 'res/conditions/3d_box.svg' + ) + .addParameter('object', _('3D object')) + .addParameter("behavior", _("Behavior"), "Base3DBehavior") + .addParameter('yesorno', _('Activate flipping')) + .markAsSimple() + .setFunctionName('flipZ'); + + base3D + .addScopedCondition( + 'FlippedZ', + _('Flipped on Z'), + _('Check if the object is flipped on Z axis'), + _('_PARAM0_ is flipped on Z axis'), + _('Effects'), + 'res/conditions/3d_box.svg', + 'res/conditions/3d_box.svg' + ) + .addParameter('object', _('3D object')) + .addParameter("behavior", _("Behavior"), "Base3DBehavior") + .setFunctionName('isFlippedZ'); + + base3D + .addExpressionAndConditionAndAction( + 'number', + 'RotationX', + _('Rotation on X axis'), + _('the rotation on X axis'), + _('the rotation on X axis'), + _('Angle'), + 'res/conditions/3d_box.svg' + ) + .addParameter('object', _('3D object')) + .addParameter("behavior", _("Behavior"), "Base3DBehavior") + .useStandardParameters('number', gd.ParameterOptions.makeNewOptions()) + .setFunctionName('setRotationX') + .setGetter('getRotationX'); + + base3D + .addExpressionAndConditionAndAction( + 'number', + 'RotationY', + _('Rotation on Y axis'), + _('the rotation on Y axis'), + _('the rotation on Y axis'), + _('Angle'), + 'res/conditions/3d_box.svg' + ) + .addParameter('object', _('3D object')) + .addParameter("behavior", _("Behavior"), "Base3DBehavior") + .useStandardParameters('number', gd.ParameterOptions.makeNewOptions()) + .setFunctionName('setRotationY') + .setGetter('getRotationY'); + + base3D + .addScopedAction( + 'TurnAroundX', + _('Turn around X axis'), + _( + "Turn the object around X axis. This axis doesn't move with the object rotation." + ), + _('Turn _PARAM0_ from _PARAM2_° around X axis'), + _('Angle'), + 'res/conditions/3d_box.svg', + 'res/conditions/3d_box.svg' + ) + .addParameter('object', _('3D object')) + .addParameter("behavior", _("Behavior"), "Base3DBehavior") + .addParameter('number', _('Rotation angle'), '', false) + .markAsAdvanced() + .setFunctionName('turnAroundX'); + + base3D + .addScopedAction( + 'TurnAroundY', + _('Turn around Y axis'), + _( + "Turn the object around Y axis. This axis doesn't move with the object rotation." + ), + _('Turn _PARAM0_ from _PARAM2_° around Y axis'), + _('Angle'), + 'res/conditions/3d_box.svg', + 'res/conditions/3d_box.svg' + ) + .addParameter('object', _('3D object')) + .addParameter("behavior", _("Behavior"), "Base3DBehavior") + .addParameter('number', _('Rotation angle'), '', false) + .markAsAdvanced() + .setFunctionName('turnAroundY'); + + base3D + .addScopedAction( + 'TurnAroundZ', + _('Turn around Z axis'), + _( + "Turn the object around Z axis. This axis doesn't move with the object rotation." + ), + _('Turn _PARAM0_ from _PARAM2_° around Z axis'), + _('Angle'), + 'res/conditions/3d_box.svg', + 'res/conditions/3d_box.svg' + ) + .addParameter('object', _('3D object')) + .addParameter("behavior", _("Behavior"), "Base3DBehavior") + .addParameter('number', _('Rotation angle'), '', false) + .markAsAdvanced() + .setFunctionName('turnAroundZ'); + } + { const object = extension .addObject( @@ -48,13 +233,20 @@ module.exports = { new gd.Model3DObjectConfiguration() ) .setCategoryFullName(_('3D')) - .addUnsupportedBaseObjectCapability('effect') + // Effects are unsupported because the object is not rendered with PIXI. + .addDefaultBehavior('ResizableCapability::ResizableBehavior') + .addDefaultBehavior('ScalableCapability::ScalableBehavior') + .addDefaultBehavior('FlippableCapability::FlippableBehavior') + .addDefaultBehavior('AnimatableCapability::AnimatableBehavior') + .addDefaultBehavior('Scene3D::Base3DBehavior') .setIncludeFile('Extensions/3D/A_RuntimeObject3D.js') .addIncludeFile('Extensions/3D/A_RuntimeObject3DRenderer.js') .addIncludeFile('Extensions/3D/Model3DRuntimeObject.js') .addIncludeFile('Extensions/3D/Model3DRuntimeObject3DRenderer.js'); // Properties expressions/conditions/actions: + + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -67,9 +259,12 @@ module.exports = { ) .addParameter('object', _('3D model'), 'Model3DObject', false) .useStandardParameters('number', gd.ParameterOptions.makeNewOptions()) + .setHidden() .setFunctionName('setZ') .setGetter('getZ'); + + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -82,9 +277,11 @@ module.exports = { ) .addParameter('object', _('3D model'), 'Model3DObject', false) .useStandardParameters('number', gd.ParameterOptions.makeNewOptions()) + .setHidden() .setFunctionName('setDepth') .setGetter('getDepth'); + // Deprecated object .addScopedAction( 'SetWidth', @@ -100,10 +297,12 @@ module.exports = { 'number', gd.ParameterOptions.makeNewOptions() ) + .setHidden() .markAsAdvanced() .setFunctionName('setWidth') .setGetter('getWidth'); + // Deprecated object .addScopedCondition( 'Width', @@ -119,9 +318,11 @@ module.exports = { 'number', gd.ParameterOptions.makeNewOptions() ) + .setHidden() .markAsAdvanced() .setFunctionName('getWidth'); + // Deprecated object .addScopedAction( 'SetHeight', @@ -137,10 +338,12 @@ module.exports = { 'number', gd.ParameterOptions.makeNewOptions() ) + .setHidden() .markAsAdvanced() .setFunctionName('setHeight') .setGetter('getHeight'); + // Deprecated object .addScopedCondition( 'Height', @@ -156,9 +359,11 @@ module.exports = { 'number', gd.ParameterOptions.makeNewOptions() ) + .setHidden() .markAsAdvanced() .setFunctionName('getHeight'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -171,9 +376,11 @@ module.exports = { ) .addParameter('object', _('3D model'), 'Model3DObject', false) .useStandardParameters('number', gd.ParameterOptions.makeNewOptions()) + .setHidden() .setFunctionName('setHeight') .setGetter('getHeight'); + // Deprecated object .addScopedAction( 'Scale', @@ -191,10 +398,12 @@ module.exports = { _('Scale (1 by default)') ) ) + .setHidden() .markAsAdvanced() .setFunctionName('setScale') .setGetter('getScale'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -212,10 +421,12 @@ module.exports = { _('Scale (1 by default)') ) ) + .setHidden() .markAsAdvanced() .setFunctionName('setScaleX') .setGetter('getScaleX'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -233,10 +444,12 @@ module.exports = { _('Scale (1 by default)') ) ) + .setHidden() .markAsAdvanced() .setFunctionName('setScaleY') .setGetter('getScaleY'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -255,9 +468,11 @@ module.exports = { ) ) .markAsAdvanced() + .setHidden() .setFunctionName('setScaleZ') .setGetter('getScaleZ'); + // Deprecated object .addScopedAction( 'FlipX', @@ -270,9 +485,11 @@ module.exports = { ) .addParameter('object', _('3D model'), 'Model3DObject') .addParameter('yesorno', _('Activate flipping')) + .setHidden() .markAsSimple() .setFunctionName('flipX'); + // Deprecated object .addScopedAction( 'FlipY', @@ -285,9 +502,11 @@ module.exports = { ) .addParameter('object', _('3D model'), 'Model3DObject') .addParameter('yesorno', _('Activate flipping')) + .setHidden() .markAsSimple() .setFunctionName('flipY'); + // Deprecated object .addScopedAction( 'FlipZ', @@ -301,8 +520,10 @@ module.exports = { .addParameter('object', _('3D model'), 'Model3DObject') .addParameter('yesorno', _('Activate flipping')) .markAsSimple() + .setHidden() .setFunctionName('flipZ'); + // Deprecated object .addScopedCondition( 'FlippedX', @@ -314,8 +535,10 @@ module.exports = { 'res/actions/flipX.png' ) .addParameter('object', _('3D model'), 'Model3DObject') + .setHidden() .setFunctionName('isFlippedX'); + // Deprecated object .addScopedCondition( 'FlippedY', @@ -327,8 +550,10 @@ module.exports = { 'res/actions/flipY.png' ) .addParameter('object', _('3D model'), 'Model3DObject') + .setHidden() .setFunctionName('isFlippedY'); + // Deprecated object .addScopedCondition( 'FlippedZ', @@ -340,8 +565,10 @@ module.exports = { 'res/conditions/3d_box.svg' ) .addParameter('object', _('3D model'), 'Model3DObject') + .setHidden() .setFunctionName('isFlippedZ'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -354,9 +581,11 @@ module.exports = { ) .addParameter('object', _('3D model'), 'Model3DObject', false) .useStandardParameters('number', gd.ParameterOptions.makeNewOptions()) + .setHidden() .setFunctionName('setRotationX') .setGetter('getRotationX'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -369,9 +598,11 @@ module.exports = { ) .addParameter('object', _('3D model'), 'Model3DObject', false) .useStandardParameters('number', gd.ParameterOptions.makeNewOptions()) + .setHidden() .setFunctionName('setRotationY') .setGetter('getRotationY'); + // Deprecated object .addScopedAction( 'TurnAroundX', @@ -387,8 +618,10 @@ module.exports = { .addParameter('object', _('3D model'), 'Model3DObject', false) .addParameter('number', _('Rotation angle'), '', false) .markAsAdvanced() + .setHidden() .setFunctionName('turnAroundX'); + // Deprecated object .addScopedAction( 'TurnAroundY', @@ -404,8 +637,10 @@ module.exports = { .addParameter('object', _('3D model'), 'Model3DObject', false) .addParameter('number', _('Rotation angle'), '', false) .markAsAdvanced() + .setHidden() .setFunctionName('turnAroundY'); + // Deprecated object .addScopedAction( 'TurnAroundZ', @@ -421,8 +656,10 @@ module.exports = { .addParameter('object', _('3D model'), 'Model3DObject', false) .addParameter('number', _('Rotation angle'), '', false) .markAsAdvanced() + .setHidden() .setFunctionName('turnAroundZ'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -438,9 +675,11 @@ module.exports = { .addParameter('object', _('3D model'), 'Model3DObject') .useStandardParameters('number', gd.ParameterOptions.makeNewOptions()) .markAsSimple() + .setHidden() .setFunctionName('setAnimationIndex') .setGetter('getAnimationIndex'); + // Deprecated object .addExpressionAndConditionAndAction( 'string', @@ -459,9 +698,11 @@ module.exports = { ) ) .markAsAdvanced() + .setHidden() .setFunctionName('setAnimationName') .setGetter('getAnimationName'); + // Deprecated object .addAction( 'PauseAnimation', @@ -474,8 +715,10 @@ module.exports = { ) .addParameter('object', _('3D model'), 'Model3DObject') .markAsSimple() + .setHidden() .setFunctionName('pauseAnimation'); + // Deprecated object .addAction( 'ResumeAnimation', @@ -488,8 +731,10 @@ module.exports = { ) .addParameter('object', _('3D model'), 'Model3DObject') .markAsSimple() + .setHidden() .setFunctionName('resumeAnimation'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -508,9 +753,11 @@ module.exports = { gd.ParameterOptions.makeNewOptions().setDescription(_('Speed scale')) ) .markAsSimple() + .setHidden() .setFunctionName('setAnimationSpeedScale') .setGetter('getAnimationSpeedScale'); + // Deprecated object .addCondition( 'IsAnimationPaused', @@ -523,8 +770,10 @@ module.exports = { ) .addParameter('object', _('3D model'), 'Model3DObject') .markAsSimple() + .setHidden() .setFunctionName('isAnimationPaused'); + // Deprecated object .addCondition( 'HasAnimationEnded', @@ -539,6 +788,7 @@ module.exports = { ) .addParameter('object', _('3D model'), 'Model3DObject') .markAsSimple() + .setHidden() .setFunctionName('hasAnimationEnded'); } @@ -864,13 +1114,19 @@ module.exports = { Cube3DObject ) .setCategoryFullName(_('3D')) - .addUnsupportedBaseObjectCapability('effect') + // Effects are unsupported because the object is not rendered with PIXI. + .addDefaultBehavior('ResizableCapability::ResizableBehavior') + .addDefaultBehavior('ScalableCapability::ScalableBehavior') + .addDefaultBehavior('FlippableCapability::FlippableBehavior') + .addDefaultBehavior('Scene3D::Base3DBehavior') .setIncludeFile('Extensions/3D/A_RuntimeObject3D.js') .addIncludeFile('Extensions/3D/A_RuntimeObject3DRenderer.js') .addIncludeFile('Extensions/3D/Cube3DRuntimeObject.js') .addIncludeFile('Extensions/3D/Cube3DRuntimeObjectPixiRenderer.js'); // Properties expressions/conditions/actions: + + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -883,9 +1139,11 @@ module.exports = { ) .addParameter('object', _('3D cube'), 'Cube3DObject', false) .useStandardParameters('number', gd.ParameterOptions.makeNewOptions()) + .setHidden() .setFunctionName('setZ') .setGetter('getZ'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -898,9 +1156,11 @@ module.exports = { ) .addParameter('object', _('3D cube'), 'Cube3DObject', false) .useStandardParameters('number', gd.ParameterOptions.makeNewOptions()) + .setHidden() .setFunctionName('setDepth') .setGetter('getDepth'); + // Deprecated object .addScopedAction( 'SetWidth', @@ -916,10 +1176,12 @@ module.exports = { 'number', gd.ParameterOptions.makeNewOptions() ) + .setHidden() .markAsAdvanced() .setFunctionName('setWidth') .setGetter('getWidth'); + // Deprecated object .addScopedCondition( 'Width', @@ -935,9 +1197,11 @@ module.exports = { 'number', gd.ParameterOptions.makeNewOptions() ) + .setHidden() .markAsAdvanced() .setFunctionName('getWidth'); + // Deprecated object .addScopedAction( 'SetHeight', @@ -953,10 +1217,12 @@ module.exports = { 'number', gd.ParameterOptions.makeNewOptions() ) + .setHidden() .markAsAdvanced() .setFunctionName('setHeight') .setGetter('getHeight'); + // Deprecated object .addScopedCondition( 'Height', @@ -972,9 +1238,11 @@ module.exports = { 'number', gd.ParameterOptions.makeNewOptions() ) + .setHidden() .markAsAdvanced() .setFunctionName('getHeight'); + // Deprecated object .addScopedAction( 'Scale', @@ -992,10 +1260,12 @@ module.exports = { _('Scale (1 by default)') ) ) + .setHidden() .markAsAdvanced() .setFunctionName('setScale') .setGetter('getScale'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -1013,10 +1283,12 @@ module.exports = { _('Scale (1 by default)') ) ) + .setHidden() .markAsAdvanced() .setFunctionName('setScaleX') .setGetter('getScaleX'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -1034,10 +1306,12 @@ module.exports = { _('Scale (1 by default)') ) ) + .setHidden() .markAsAdvanced() .setFunctionName('setScaleY') .setGetter('getScaleY'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -1056,9 +1330,11 @@ module.exports = { ) ) .markAsAdvanced() + .setHidden() .setFunctionName('setScaleZ') .setGetter('getScaleZ'); + // Deprecated object .addScopedAction( 'FlipX', @@ -1072,8 +1348,10 @@ module.exports = { .addParameter('object', _('3D cube'), 'Cube3DObject') .addParameter('yesorno', _('Activate flipping')) .markAsSimple() + .setHidden() .setFunctionName('flipX'); + // Deprecated object .addScopedAction( 'FlipY', @@ -1087,8 +1365,10 @@ module.exports = { .addParameter('object', _('3D cube'), 'Cube3DObject') .addParameter('yesorno', _('Activate flipping')) .markAsSimple() + .setHidden() .setFunctionName('flipY'); + // Deprecated object .addScopedAction( 'FlipZ', @@ -1102,8 +1382,10 @@ module.exports = { .addParameter('object', _('3D cube'), 'Cube3DObject') .addParameter('yesorno', _('Activate flipping')) .markAsSimple() + .setHidden() .setFunctionName('flipZ'); + // Deprecated object .addScopedCondition( 'FlippedX', @@ -1115,8 +1397,10 @@ module.exports = { 'res/actions/flipX.png' ) .addParameter('object', _('3D cube'), 'Cube3DObject') + .setHidden() .setFunctionName('isFlippedX'); + // Deprecated object .addScopedCondition( 'FlippedY', @@ -1128,8 +1412,10 @@ module.exports = { 'res/actions/flipY.png' ) .addParameter('object', _('3D cube'), 'Cube3DObject') + .setHidden() .setFunctionName('isFlippedY'); + // Deprecated object .addScopedCondition( 'FlippedZ', @@ -1141,8 +1427,10 @@ module.exports = { 'res/conditions/3d_box.svg' ) .addParameter('object', _('3D cube'), 'Cube3DObject') + .setHidden() .setFunctionName('isFlippedZ'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -1156,8 +1444,10 @@ module.exports = { .addParameter('object', _('3D cube'), 'Cube3DObject', false) .useStandardParameters('number', gd.ParameterOptions.makeNewOptions()) .setFunctionName('setRotationX') + .setHidden() .setGetter('getRotationX'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -1171,6 +1461,7 @@ module.exports = { .addParameter('object', _('3D cube'), 'Cube3DObject', false) .useStandardParameters('number', gd.ParameterOptions.makeNewOptions()) .setFunctionName('setRotationY') + .setHidden() .setGetter('getRotationY'); object @@ -1197,6 +1488,7 @@ module.exports = { .setFunctionName('setFaceVisibility') .setGetter('isFaceVisible'); + // Deprecated object .addScopedAction( 'TurnAroundX', @@ -1212,8 +1504,10 @@ module.exports = { .addParameter('object', _('3D cube'), 'Cube3DObject', false) .addParameter('number', _('Rotation angle'), '', false) .markAsAdvanced() + .setHidden() .setFunctionName('turnAroundX'); + // Deprecated object .addScopedAction( 'TurnAroundY', @@ -1229,8 +1523,10 @@ module.exports = { .addParameter('object', _('3D cube'), 'Cube3DObject', false) .addParameter('number', _('Rotation angle'), '', false) .markAsAdvanced() + .setHidden() .setFunctionName('turnAroundY'); + // Deprecated object .addScopedAction( 'TurnAroundZ', @@ -1246,6 +1542,7 @@ module.exports = { .addParameter('object', _('3D cube'), 'Cube3DObject', false) .addParameter('number', _('Rotation angle'), '', false) .markAsAdvanced() + .setHidden() .setFunctionName('turnAroundZ'); object diff --git a/Extensions/3D/Model3DRuntimeObject.ts b/Extensions/3D/Model3DRuntimeObject.ts index f6a2f69adc..311a4b69ff 100644 --- a/Extensions/3D/Model3DRuntimeObject.ts +++ b/Extensions/3D/Model3DRuntimeObject.ts @@ -48,7 +48,9 @@ namespace gdjs { /** * A 3D object which displays a 3D model. */ - export class Model3DRuntimeObject extends gdjs.RuntimeObject3D { + export class Model3DRuntimeObject + extends gdjs.RuntimeObject3D + implements gdjs.Animatable { _renderer: gdjs.Model3DRuntimeObjectRenderer; _modelResourceName: string; diff --git a/Extensions/BBText/JsExtension.js b/Extensions/BBText/JsExtension.js index 450bd3c022..3a3050ba8d 100644 --- a/Extensions/BBText/JsExtension.js +++ b/Extensions/BBText/JsExtension.js @@ -174,7 +174,8 @@ module.exports = { .addIncludeFile( 'Extensions/BBText/pixi-multistyle-text/dist/pixi-multistyle-text.umd.js' ) - .setCategoryFullName(_('Text')); + .setCategoryFullName(_('Text')) + .addDefaultBehavior("OpacityCapability::OpacityBehavior"); /** * Utility function to add both a setter and a getter to a property from a list. @@ -434,6 +435,14 @@ module.exports = { addSettersAndGettersToObject(object, setterAndGetterProperties, 'BBText'); + const actions = object.getAllActions(); + const conditions = object.getAllConditions(); + const expressions = object.getAllExpressions(); + + actions.get('BBText::SetOpacity').setHidden(); + conditions.get('BBText::IsOpacity').setHidden(); + expressions.get('GetOpacity').setHidden(); + return extension; }, diff --git a/Extensions/BitmapText/JsExtension.js b/Extensions/BitmapText/JsExtension.js index c45bf2603b..51df0f02f2 100644 --- a/Extensions/BitmapText/JsExtension.js +++ b/Extensions/BitmapText/JsExtension.js @@ -175,7 +175,9 @@ module.exports = { .addIncludeFile( 'Extensions/BitmapText/bitmaptextruntimeobject-pixi-renderer.js' ) - .setCategoryFullName(_('Text')); + .setCategoryFullName(_('Text')) + .addDefaultBehavior('OpacityCapability::OpacityBehavior') + .addDefaultBehavior('ScalableCapability::ScalableBehavior'); object .addExpressionAndConditionAndAction( @@ -192,6 +194,7 @@ module.exports = { .setFunctionName('setText') .setGetter('getText'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -210,7 +213,8 @@ module.exports = { ) ) .setFunctionName('setOpacity') - .setGetter('getOpacity'); + .setGetter('getOpacity') + .setHidden(); object .addExpressionAndCondition( @@ -226,6 +230,7 @@ module.exports = { .useStandardParameters('number', gd.ParameterOptions.makeNewOptions()) .setFunctionName('getFontSize'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -243,6 +248,7 @@ module.exports = { _('Scale (1 by default)') ) ) + .setHidden() .setFunctionName('setScale') .setGetter('getScale'); diff --git a/Extensions/BitmapText/bitmaptextruntimeobject-pixi-renderer.ts b/Extensions/BitmapText/bitmaptextruntimeobject-pixi-renderer.ts index 74b16df0cf..0f44ba0190 100644 --- a/Extensions/BitmapText/bitmaptextruntimeobject-pixi-renderer.ts +++ b/Extensions/BitmapText/bitmaptextruntimeobject-pixi-renderer.ts @@ -120,7 +120,10 @@ namespace gdjs { } updateScale(): void { - this._pixiObject.scale.set(Math.max(this._object._scale, 0)); + this._pixiObject.scale.set( + Math.max(this._object._scaleX, 0), + Math.max(this._object._scaleY, 0) + ); this.updatePosition(); } @@ -131,7 +134,7 @@ namespace gdjs { updateWrappingWidth(): void { if (this._object._wordWrap) { this._pixiObject.maxWidth = - this._object._wrappingWidth / this._object._scale; + this._object._wrappingWidth / this._object._scaleX; this._pixiObject.dirty = true; } else { this._pixiObject.maxWidth = 0; diff --git a/Extensions/BitmapText/bitmaptextruntimeobject.ts b/Extensions/BitmapText/bitmaptextruntimeobject.ts index 76f6ba56f3..eb4b5debad 100644 --- a/Extensions/BitmapText/bitmaptextruntimeobject.ts +++ b/Extensions/BitmapText/bitmaptextruntimeobject.ts @@ -35,14 +35,17 @@ namespace gdjs { * * Glyph Designer (OS X, commercial): http://www.71squared.com/en/glyphdesigner|http://www.71squared.com/en/glyphdesigner * * Littera (Web-based, free): http://kvazars.com/littera/|http://kvazars.com/littera/ */ - export class BitmapTextRuntimeObject extends gdjs.RuntimeObject { + export class BitmapTextRuntimeObject + extends gdjs.RuntimeObject + implements gdjs.OpacityHandler, gdjs.Scalable { _opacity: float; _text: string; /** color in format [r, g, b], where each component is in the range [0, 255] */ _tint: integer[]; _bitmapFontResourceName: string; _textureAtlasResourceName: string; - _scale: number; + _scaleX: number; + _scaleY: number; _wordWrap: boolean; _wrappingWidth: float; _align: string; @@ -66,7 +69,8 @@ namespace gdjs { this._bitmapFontResourceName = objectData.content.bitmapFontResourceName; // fnt/xml files this._textureAtlasResourceName = objectData.content.textureAtlasResourceName; // texture file used with fnt/xml (bitmap font file) - this._scale = objectData.content.scale; + this._scaleX = objectData.content.scale; + this._scaleY = objectData.content.scale; this._wordWrap = objectData.content.wordWrap; this._wrappingWidth = 0; this._align = objectData.content.align; @@ -167,14 +171,45 @@ namespace gdjs { return this._tint[0] + ';' + this._tint[1] + ';' + this._tint[2]; } + getScale(): number { + const scaleX = this.getScaleX(); + const scaleY = this.getScaleY(); + return scaleX === scaleY ? scaleX : Math.sqrt(scaleX * scaleY); + } + + getScaleX(): float { + return this._scaleX; + } + + getScaleY(): float { + return this._scaleY; + } + setScale(scale: float): void { - this._scale = scale; + this.setScaleX(scale); + this.setScaleY(scale); + } + + setScaleX(scaleX: float): void { + if (scaleX < 0) { + scaleX = 0; + } + if (this._scaleX === scaleX) return; + + this._scaleX = scaleX; this._renderer.updateScale(); this.invalidateHitboxes(); } - getScale(): float { - return this._scale; + setScaleY(scaleY: float): void { + if (scaleY < 0) { + scaleY = 0; + } + if (this._scaleY === scaleY) return; + + this._scaleY = scaleY; + this._renderer.updateScale(); + this.invalidateHitboxes(); } getFontSize(): float { diff --git a/Extensions/PanelSpriteObject/Extension.cpp b/Extensions/PanelSpriteObject/Extension.cpp index 4c342961d6..c4ac9b2bdd 100644 --- a/Extensions/PanelSpriteObject/Extension.cpp +++ b/Extensions/PanelSpriteObject/Extension.cpp @@ -38,7 +38,10 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) { "from " "the full image."), "CppPlatform/Extensions/PanelSpriteIcon.png") - .SetCategoryFullName(_("General")); + .SetCategoryFullName(_("General")) + .AddDefaultBehavior("EffectCapability::EffectBehavior") + .AddDefaultBehavior("ResizableCapability::ResizableBehavior") + .AddDefaultBehavior("OpacityCapability::OpacityBehavior"); obj.AddCondition("Opacity", _("Opacity"), @@ -90,6 +93,7 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) { .AddParameter("object", _("Object"), "PanelSprite") .AddParameter("color", _("Tint")); + // Deprecated obj.AddAction("Width", _("Width"), _("Modify the width of a Panel Sprite."), @@ -101,9 +105,11 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) { .AddParameter("object", _("Object"), "PanelSprite") .UseStandardOperatorParameters("number", gd::ParameterOptions::MakeNewOptions()) + .SetHidden() .SetFunctionName("SetWidth") .SetGetter("GetWidth"); + // Deprecated obj.AddCondition("Width", _("Width"), _("Check the width of a Panel Sprite."), @@ -115,8 +121,10 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) { .AddParameter("object", _("Object"), "PanelSprite") .UseStandardRelationalOperatorParameters( "number", gd::ParameterOptions::MakeNewOptions()) + .SetHidden() .SetFunctionName("GetWidth"); + // Deprecated obj.AddAction("Height", _("Height"), _("Modify the height of a Panel Sprite."), @@ -128,9 +136,11 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) { .AddParameter("object", _("Object"), "PanelSprite") .UseStandardOperatorParameters("number", gd::ParameterOptions::MakeNewOptions()) + .SetHidden() .SetFunctionName("SetHeight") .SetGetter("GetHeight"); + // Deprecated obj.AddCondition("Height", _("Height"), _("Check the height of a Panel Sprite."), @@ -142,6 +152,7 @@ void DeclarePanelSpriteObjectExtension(gd::PlatformExtension& extension) { .AddParameter("object", _("Object"), "PanelSprite") .UseStandardRelationalOperatorParameters( "number", gd::ParameterOptions::MakeNewOptions()) + .SetHidden() .SetFunctionName("SetHeight") .SetGetter("GetHeight"); diff --git a/Extensions/PanelSpriteObject/panelspriteruntimeobject.ts b/Extensions/PanelSpriteObject/panelspriteruntimeobject.ts index 18b441ce38..9ea08ce802 100644 --- a/Extensions/PanelSpriteObject/panelspriteruntimeobject.ts +++ b/Extensions/PanelSpriteObject/panelspriteruntimeobject.ts @@ -27,7 +27,9 @@ namespace gdjs { /** * The PanelSpriteRuntimeObject displays a tiled texture. */ - export class PanelSpriteRuntimeObject extends gdjs.RuntimeObject { + export class PanelSpriteRuntimeObject + extends gdjs.RuntimeObject + implements gdjs.Resizable, gdjs.OpacityHandler { _rBorder: integer; _lBorder: integer; _tBorder: integer; @@ -190,10 +192,6 @@ namespace gdjs { return this._height; } - /** - * Set the width of the panel sprite. - * @param width The new width in pixels. - */ setWidth(width: float): void { if (this._width === width) return; @@ -202,10 +200,6 @@ namespace gdjs { this.invalidateHitboxes(); } - /** - * Set the height of the panel sprite. - * @param height The new height in pixels. - */ setHeight(height: float): void { if (this._height === height) return; @@ -214,10 +208,11 @@ namespace gdjs { this.invalidateHitboxes(); } - /** - * Change the transparency of the object. - * @param opacity The new opacity, between 0 (transparent) and 255 (opaque). - */ + setSize(newWidth: float, newHeight: float): void { + this.setWidth(newWidth); + this.setHeight(newHeight); + } + setOpacity(opacity: float): void { if (opacity < 0) { opacity = 0; @@ -229,10 +224,6 @@ namespace gdjs { this._renderer.updateOpacity(); } - /** - * Get the transparency of the object. - * @return The opacity, between 0 (transparent) and 255 (opaque). - */ getOpacity(): number { return this.opacity; } @@ -258,10 +249,14 @@ namespace gdjs { // Implement support for get/set scale: /** - * Get scale of the tiled sprite object. + * Get the scale of the object (or the geometric mean of the X and Y scale in case they are different). + * + * @return the scale of the object (or the geometric mean of the X and Y scale in case they are different). */ getScale(): float { - return (this.getScaleX() + this.getScaleY()) / 2.0; + const scaleX = Math.abs(this.getScaleX()); + const scaleY = Math.abs(this.getScaleY()); + return scaleX === scaleY ? scaleX : Math.sqrt(scaleX * scaleY); } /** diff --git a/Extensions/PrimitiveDrawing/Extension.cpp b/Extensions/PrimitiveDrawing/Extension.cpp index 4f537dd768..7b64814da9 100644 --- a/Extensions/PrimitiveDrawing/Extension.cpp +++ b/Extensions/PrimitiveDrawing/Extension.cpp @@ -31,7 +31,11 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) { _("Allows you to draw simple shapes on the screen using the " "events."), "CppPlatform/Extensions/primitivedrawingicon.png") - .SetCategoryFullName(_("Advanced")); + .SetCategoryFullName(_("Advanced")) + .AddDefaultBehavior("EffectCapability::EffectBehavior") + .AddDefaultBehavior("ResizableCapability::ResizableBehavior") + .AddDefaultBehavior("ScalableCapability::ScalableBehavior") + .AddDefaultBehavior("FlippableCapability::FlippableBehavior"); #if defined(GD_IDE_ONLY) obj.AddAction( @@ -612,6 +616,7 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) { .AddParameter("object", _("Shape Painter object"), "Drawer") .SetFunctionName("AreCoordinatesRelative"); + // Deprecated obj.AddAction("Scale", _("Scale"), _("Modify the scale of the specified object."), @@ -624,8 +629,10 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) { "number", gd::ParameterOptions::MakeNewOptions().SetDescription( _("Scale (1 by default)"))) + .SetHidden() .MarkAsAdvanced(); + // Deprecated obj.AddExpressionAndConditionAndAction("number", "ScaleX", _("Scale on X axis"), @@ -638,8 +645,10 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) { "number", gd::ParameterOptions::MakeNewOptions().SetDescription( _("Scale (1 by default)"))) + .SetHidden() .MarkAsAdvanced(); + // Deprecated obj.AddExpressionAndConditionAndAction("number", "ScaleY", _("Scale on Y axis"), @@ -652,6 +661,7 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) { "number", gd::ParameterOptions::MakeNewOptions().SetDescription( _("Scale (1 by default)"))) + .SetHidden() .MarkAsAdvanced(); obj.AddAction("FlipX", @@ -663,6 +673,7 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) { "res/actions/flipX.png") .AddParameter("object", _("Object"), "Drawer") .AddParameter("yesorno", _("Activate flipping")) + .SetHidden() .MarkAsSimple(); obj.AddAction("FlipY", @@ -674,6 +685,7 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) { "res/actions/flipY.png") .AddParameter("object", _("Object"), "Drawer") .AddParameter("yesorno", _("Activate flipping")) + .SetHidden() .MarkAsSimple(); obj.AddCondition("FlippedX", @@ -683,7 +695,8 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) { _("Effects"), "res/actions/flipX24.png", "res/actions/flipX.png") - .AddParameter("object", _("Object"), "Drawer"); + .AddParameter("object", _("Object"), "Drawer") + .SetHidden(); obj.AddCondition("FlippedY", _("Vertically flipped"), @@ -692,8 +705,10 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) { _("Effects"), "res/actions/flipY24.png", "res/actions/flipY.png") - .AddParameter("object", _("Object"), "Drawer"); + .AddParameter("object", _("Object"), "Drawer") + .SetHidden(); + // Deprecated obj.AddAction("Width", _("Width"), _("Change the width of an object."), @@ -704,8 +719,10 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) { .AddParameter("object", _("Object"), "Drawer") .UseStandardOperatorParameters("number", gd::ParameterOptions::MakeNewOptions()) + .SetHidden() .MarkAsAdvanced(); + // Deprecated obj.AddAction("Height", _("Height"), _("Change the height of an object."), @@ -716,6 +733,7 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) { .AddParameter("object", _("Object"), "Drawer") .UseStandardOperatorParameters("number", gd::ParameterOptions::MakeNewOptions()) + .SetHidden() .MarkAsAdvanced(); obj.AddAction( diff --git a/Extensions/PrimitiveDrawing/shapepainterruntimeobject.ts b/Extensions/PrimitiveDrawing/shapepainterruntimeobject.ts index 308f62f6bd..e8944e0126 100644 --- a/Extensions/PrimitiveDrawing/shapepainterruntimeobject.ts +++ b/Extensions/PrimitiveDrawing/shapepainterruntimeobject.ts @@ -40,7 +40,9 @@ namespace gdjs { /** * The ShapePainterRuntimeObject allows to draw graphics shapes on screen. */ - export class ShapePainterRuntimeObject extends gdjs.RuntimeObject { + export class ShapePainterRuntimeObject + extends gdjs.RuntimeObject + implements gdjs.Resizable, gdjs.Scalable, gdjs.Flippable { _scaleX: number = 1; _scaleY: number = 1; _blendMode: number = 0; @@ -555,11 +557,6 @@ namespace gdjs { ); } - /** - * Change the width of the object. This changes the scale on X axis of the object. - * - * @param newWidth The new width of the object, in pixels. - */ setWidth(newWidth: float): void { const unscaledWidth = this._renderer.getUnscaledWidth(); if (unscaledWidth !== 0) { @@ -567,11 +564,6 @@ namespace gdjs { } } - /** - * Change the height of the object. This changes the scale on Y axis of the object. - * - * @param newHeight The new height of the object, in pixels. - */ setHeight(newHeight: float): void { const unscaledHeight = this._renderer.getUnscaledHeight(); if (unscaledHeight !== 0) { @@ -579,6 +571,11 @@ namespace gdjs { } } + setSize(newWidth: float, newHeight: float): void { + this.setWidth(newWidth); + this.setHeight(newHeight); + } + /** * Change the scale on X and Y axis of the object. * diff --git a/Extensions/TextInput/JsExtension.js b/Extensions/TextInput/JsExtension.js index 8cc128febe..2e05466ee4 100644 --- a/Extensions/TextInput/JsExtension.js +++ b/Extensions/TextInput/JsExtension.js @@ -283,11 +283,13 @@ module.exports = { textInputObject ) .setCategoryFullName(_('User interface')) - .addUnsupportedBaseObjectCapability('effect') + // Effects are unsupported because the object is not rendered with PIXI. .setIncludeFile('Extensions/TextInput/textinputruntimeobject.js') .addIncludeFile( 'Extensions/TextInput/textinputruntimeobject-pixi-renderer.js' - ); + ) + .addDefaultBehavior('ResizableCapability::ResizableBehavior') + .addDefaultBehavior('OpacityCapability::OpacityBehavior'); // Properties expressions/conditions/actions: object @@ -525,6 +527,8 @@ module.exports = { .setGetter('isDisabled'); // Other expressions/conditions/actions: + + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -543,7 +547,8 @@ module.exports = { ) ) .setFunctionName('setOpacity') - .setGetter('getOpacity'); + .setGetter('getOpacity') + .setHidden(); object .addScopedCondition( diff --git a/Extensions/TextInput/textinputruntimeobject.ts b/Extensions/TextInput/textinputruntimeobject.ts index 89d1fa4949..1d49270ff3 100644 --- a/Extensions/TextInput/textinputruntimeobject.ts +++ b/Extensions/TextInput/textinputruntimeobject.ts @@ -48,7 +48,9 @@ namespace gdjs { /** * Shows a text input on the screen the player can type text into. */ - export class TextInputRuntimeObject extends gdjs.RuntimeObject { + export class TextInputRuntimeObject + extends gdjs.RuntimeObject + implements gdjs.Resizable, gdjs.OpacityHandler { private _string: string; private _placeholder: string; private opacity: float = 255; @@ -202,33 +204,24 @@ namespace gdjs { this._renderer.onDestroy(); } - /** - * Set object opacity. - */ - setOpacity(opacity): void { + setOpacity(opacity: float): void { this.opacity = Math.max(0, Math.min(255, opacity)); this._renderer.updateOpacity(); } - /** - * Get object opacity. - */ - getOpacity() { + getOpacity(): float { return this.opacity; } - /** - * Set the width of the object, if applicable. - * @param width The new width in pixels. - */ + setSize(width: number, height: number): void { + this.setWidth(width); + this.setHeight(height); + } + setWidth(width: float): void { this._width = width; } - /** - * Set the height of the object, if applicable. - * @param height The new height in pixels. - */ setHeight(height: float): void { this._height = height; } diff --git a/Extensions/TextObject/Extension.cpp b/Extensions/TextObject/Extension.cpp index 3172f94dc2..a52e1de026 100644 --- a/Extensions/TextObject/Extension.cpp +++ b/Extensions/TextObject/Extension.cpp @@ -34,7 +34,10 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) { _("Text"), _("Displays a text on the screen."), "CppPlatform/Extensions/texticon.png") - .SetCategoryFullName(_("Text")); + .SetCategoryFullName(_("Text")) + .AddDefaultBehavior("EffectCapability::EffectBehavior") + .AddDefaultBehavior("ScalableCapability::ScalableBehavior") + .AddDefaultBehavior("OpacityCapability::OpacityBehavior"); obj.AddAction("String", _("Modify the text"), @@ -78,6 +81,7 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) { .AddParameter("police", _("Font")) .SetFunctionName("ChangeFont"); + // Deprecated obj.AddCondition("ScaleX", _("Scale on X axis"), _("Compare the scale of the text on the X axis"), @@ -91,8 +95,10 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) { "number", gd::ParameterOptions::MakeNewOptions().SetDescription( _("Scale to compare to (1 by default)"))) + .SetHidden() .SetFunctionName("GetScaleX"); + // Deprecated obj.AddAction( "ScaleX", _("Scale on X axis"), @@ -107,8 +113,10 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) { "number", gd::ParameterOptions::MakeNewOptions().SetDescription( _("Scale (1 by default)"))) + .SetHidden() .SetFunctionName("SetScaleX"); + // Deprecated obj.AddCondition("ScaleY", _("Scale on Y axis"), _("Compare the scale of the text on the Y axis"), @@ -122,8 +130,10 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) { "number", gd::ParameterOptions::MakeNewOptions().SetDescription( _("Scale to compare to (1 by default)"))) + .SetHidden() .SetFunctionName("GetScaleY"); + // Deprecated obj.AddAction( "ScaleY", _("Scale on Y axis"), @@ -138,8 +148,10 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) { "number", gd::ParameterOptions::MakeNewOptions().SetDescription( _("Scale (1 by default)"))) + .SetHidden() .SetFunctionName("SetScaleY"); + // Deprecated obj.AddAction( "Scale", _("Scale"), @@ -154,6 +166,7 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) { "number", gd::ParameterOptions::MakeNewOptions().SetDescription( _("Scale (1 by default)"))) + .SetHidden() .SetFunctionName("SetScale"); obj.AddAction( @@ -228,6 +241,7 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) { .AddParameter("object", _("Object"), "Text") .AddParameter("yesorno", _("Show the shadow")); + // Deprecated obj.AddAction("Opacity", _("Text opacity"), _("Change the opacity of a Text. 0 is fully transparent, 255 " @@ -245,6 +259,7 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) { .SetFunctionName("SetOpacity") .SetGetter("GetOpacity"); + // Deprecated obj.AddCondition("Opacity", _("Opacity"), _("Compare the opacity of a Text object, between 0 (fully " @@ -497,22 +512,27 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) { "res/actions/textPadding_black.png") .AddParameter("object", _("Object"), "Text"); + // Deprecated obj.AddExpression("ScaleX", _("X Scale of a Text object"), _("X Scale of a Text object"), _("Scale"), "res/actions/scaleWidth_black.png") .AddParameter("object", _("Object"), "Text") + .SetHidden() .SetFunctionName("GetScaleX"); + // Deprecated obj.AddExpression("ScaleY", _("Y Scale of a Text object"), _("Y Scale of a Text object"), _("Scale"), "res/actions/scaleHeight_black.png") .AddParameter("object", _("Object"), "Text") + .SetHidden() .SetFunctionName("GetScaleY"); + // Deprecated obj.AddExpression("Opacity", _("Opacity of a Text object"), _("Opacity of a Text object"), diff --git a/Extensions/TextObject/JsExtension.cpp b/Extensions/TextObject/JsExtension.cpp index a90e2edfba..f76fb77cbe 100644 --- a/Extensions/TextObject/JsExtension.cpp +++ b/Extensions/TextObject/JsExtension.cpp @@ -31,7 +31,7 @@ class TextObjectJsExtension : public gd::PlatformExtension { "Extensions/TextObject/textruntimeobject-pixi-renderer.js"); GetAllActionsForObject("TextObject::Text")["TextObject::Scale"] .SetFunctionName("setScale") - .SetGetter("getScale"); + .SetGetter("getScaleMean"); GetAllActionsForObject("TextObject::Text")["TextObject::ScaleX"] .SetFunctionName("setScaleX") .SetGetter("getScaleX"); diff --git a/Extensions/TextObject/textruntimeobject.ts b/Extensions/TextObject/textruntimeobject.ts index 079bcb3d62..946bbfd329 100644 --- a/Extensions/TextObject/textruntimeobject.ts +++ b/Extensions/TextObject/textruntimeobject.ts @@ -34,7 +34,9 @@ namespace gdjs { /** * Displays a text. */ - export class TextRuntimeObject extends gdjs.RuntimeObject { + export class TextRuntimeObject + extends gdjs.RuntimeObject + implements gdjs.OpacityHandler { _characterSize: number; _fontName: string; _bold: boolean; @@ -304,10 +306,24 @@ namespace gdjs { } /** - * Get scale of the text. + * Get the scale of the object (or the arithmetic mean of the X and Y scale in case they are different). + * + * @return the scale of the object (or the arithmetic mean of the X and Y scale in case they are different). + * @deprecated Use `getScale` instead. + */ + getScaleMean(): float { + return (Math.abs(this._scaleX) + Math.abs(this._scaleY)) / 2.0; + } + + /** + * Get the scale of the object (or the geometric mean of the X and Y scale in case they are different). + * + * @return the scale of the object (or the geometric mean of the X and Y scale in case they are different). */ getScale(): float { - return (Math.abs(this._scaleX) + Math.abs(this._scaleY)) / 2.0; + const scaleX = Math.abs(this._scaleX); + const scaleY = Math.abs(this._scaleY); + return scaleX === scaleY ? scaleX : Math.sqrt(scaleX * scaleY); } /** diff --git a/Extensions/TileMap/JsExtension.js b/Extensions/TileMap/JsExtension.js index 9586a849ac..6468d4492d 100644 --- a/Extensions/TileMap/JsExtension.js +++ b/Extensions/TileMap/JsExtension.js @@ -205,6 +205,10 @@ const defineTileMap = function ( objectTileMap ) .setCategoryFullName(_('Advanced')) + .addDefaultBehavior('EffectCapability::EffectBehavior') + .addDefaultBehavior('ResizableCapability::ResizableBehavior') + .addDefaultBehavior('ScalableCapability::ScalableBehavior') + .addDefaultBehavior('OpacityCapability::OpacityBehavior') .setIncludeFile('Extensions/TileMap/tilemapruntimeobject.js') .addIncludeFile('Extensions/TileMap/TileMapRuntimeManager.js') .addIncludeFile('Extensions/TileMap/tilemapruntimeobject-pixi-renderer.js') @@ -495,6 +499,7 @@ const defineTileMap = function ( .getCodeExtraInformation() .setFunctionName('getAnimationFps'); + // Deprecated object .addAction( 'Scale', @@ -513,10 +518,12 @@ const defineTileMap = function ( ) ) .markAsAdvanced() + .setHidden() .getCodeExtraInformation() .setFunctionName('setScale') .setGetter('getScale'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -535,9 +542,11 @@ const defineTileMap = function ( ) ) .markAsAdvanced() + .setHidden() .setFunctionName('setScaleX') .setGetter('getScaleX'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -556,9 +565,11 @@ const defineTileMap = function ( ) ) .markAsAdvanced() + .setHidden() .setFunctionName('setScaleY') .setGetter('getScaleY'); + // Deprecated object .addAction( 'Width', @@ -575,9 +586,11 @@ const defineTileMap = function ( gd.ParameterOptions.makeNewOptions() ) .markAsAdvanced() + .setHidden() .getCodeExtraInformation() .setFunctionName('setWidth'); + // Deprecated object .addAction( 'Height', @@ -594,6 +607,7 @@ const defineTileMap = function ( gd.ParameterOptions.makeNewOptions() ) .markAsAdvanced() + .setHidden() .getCodeExtraInformation() .setFunctionName('setHeight'); }; @@ -789,6 +803,9 @@ const defineCollisionMask = function ( collisionMaskObject ) .setCategoryFullName(_('Advanced')) + .addDefaultBehavior('EffectCapability::EffectBehavior') + .addDefaultBehavior('ResizableCapability::ResizableBehavior') + .addDefaultBehavior('ScalableCapability::ScalableBehavior') .setIncludeFile('Extensions/TileMap/tilemapcollisionmaskruntimeobject.js') .addIncludeFile('Extensions/TileMap/TileMapRuntimeManager.js') .addIncludeFile('Extensions/TileMap/pako/dist/pako.min.js') @@ -882,6 +899,7 @@ const defineCollisionMask = function ( .getCodeExtraInformation() .setFunctionName('setTilesetJsonFile'); + // Deprecated object .addScopedAction( 'Scale', @@ -905,10 +923,12 @@ const defineCollisionMask = function ( ) ) .markAsAdvanced() + .setHidden() .getCodeExtraInformation() .setFunctionName('setScale') .setGetter('getScale'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -932,9 +952,11 @@ const defineCollisionMask = function ( ) ) .markAsAdvanced() + .setHidden() .setFunctionName('setScaleX') .setGetter('getScaleX'); + // Deprecated object .addExpressionAndConditionAndAction( 'number', @@ -958,9 +980,11 @@ const defineCollisionMask = function ( ) ) .markAsAdvanced() + .setHidden() .setFunctionName('setScaleY') .setGetter('getScaleY'); + // Deprecated object .addScopedAction( 'Width', @@ -982,9 +1006,11 @@ const defineCollisionMask = function ( gd.ParameterOptions.makeNewOptions() ) .markAsAdvanced() + .setHidden() .getCodeExtraInformation() .setFunctionName('setWidth'); + // Deprecated object .addScopedAction( 'Height', @@ -1006,6 +1032,7 @@ const defineCollisionMask = function ( gd.ParameterOptions.makeNewOptions() ) .markAsAdvanced() + .setHidden() .getCodeExtraInformation() .setFunctionName('setHeight'); }; diff --git a/Extensions/TileMap/tilemapcollisionmaskruntimeobject.ts b/Extensions/TileMap/tilemapcollisionmaskruntimeobject.ts index 7593a0bd4f..5492bc6537 100644 --- a/Extensions/TileMap/tilemapcollisionmaskruntimeobject.ts +++ b/Extensions/TileMap/tilemapcollisionmaskruntimeobject.ts @@ -4,7 +4,9 @@ namespace gdjs { * An object that handle hitboxes for a tile map. * @extends gdjs.RuntimeObject */ - export class TileMapCollisionMaskRuntimeObject extends gdjs.RuntimeObject { + export class TileMapCollisionMaskRuntimeObject + extends gdjs.RuntimeObject + implements gdjs.Resizable, gdjs.Scalable { private _tilemapJsonFile: string; private _tilesetJsonFile: string; private _renderer: gdjs.TileMap.TileMapCollisionMaskRenderer; @@ -460,11 +462,6 @@ namespace gdjs { this._transformationIsUpToDate = false; } - /** - * Change the width of the object. This changes the scale on X axis of the object. - * - * @param width The new width of the object, in pixels. - */ setWidth(width: float): void { if (this._width === width) { return; @@ -475,11 +472,6 @@ namespace gdjs { this.invalidateHitboxes(); } - /** - * Change the height of the object. This changes the scale on Y axis of the object. - * - * @param height The new height of the object, in pixels. - */ setHeight(height: float): void { if (this._height === height) { return; @@ -490,12 +482,17 @@ namespace gdjs { this.invalidateHitboxes(); } + setSize(newWidth: float, newHeight: float): void { + this.setWidth(newWidth); + this.setHeight(newHeight); + } + /** * Get the scale of the object (or the geometric mean of the X and Y scale in case they are different). * * @return the scale of the object (or the geometric mean of the X and Y scale in case they are different). */ - getScale(): number { + getScale(): float { const scaleX = this.getScaleX(); const scaleY = this.getScaleY(); return scaleX === scaleY ? scaleX : Math.sqrt(scaleX * scaleY); diff --git a/Extensions/TileMap/tilemapruntimeobject.ts b/Extensions/TileMap/tilemapruntimeobject.ts index 115eba4f10..247681b77d 100644 --- a/Extensions/TileMap/tilemapruntimeobject.ts +++ b/Extensions/TileMap/tilemapruntimeobject.ts @@ -5,7 +5,9 @@ namespace gdjs { /** * Displays a Tilemap object (mapeditor.org supported). */ - export class TileMapRuntimeObject extends gdjs.RuntimeObject { + export class TileMapRuntimeObject + extends gdjs.RuntimeObject + implements gdjs.Resizable, gdjs.Scalable, gdjs.OpacityHandler { _frameElapsedTime: float = 0; _opacity: float; _tilemapJsonFile: string; @@ -234,11 +236,6 @@ namespace gdjs { return this._animationSpeedScale; } - /** - * Change the width of the object. This changes the scale on X axis of the object. - * - * @param width The new width of the object, in pixels. - */ setWidth(width: float): void { if (this.getWidth() === width) return; @@ -246,11 +243,6 @@ namespace gdjs { this.invalidateHitboxes(); } - /** - * Change the height of the object. This changes the scale on Y axis of the object. - * - * @param height The new height of the object, in pixels. - */ setHeight(height: float): void { if (this.getHeight() === height) return; @@ -258,12 +250,17 @@ namespace gdjs { this.invalidateHitboxes(); } + setSize(newWidth: float, newHeight: float): void { + this.setWidth(newWidth); + this.setHeight(newHeight); + } + /** * Get the scale of the object (or the geometric mean of the X and Y scale in case they are different). * * @return the scale of the object (or the geometric mean of the X and Y scale in case they are different). */ - getScale(): number { + getScale(): float { const scaleX = this.getScaleX(); const scaleY = this.getScaleY(); return scaleX === scaleY ? scaleX : Math.sqrt(scaleX * scaleY); @@ -324,18 +321,11 @@ namespace gdjs { this._renderer.updateAngle(); } - /** - * Set object opacity. - * @param opacity The new opacity of the object (0-255). - */ setOpacity(opacity: float): void { this._opacity = opacity; this._renderer.updateOpacity(); } - /** - * Get object opacity. - */ getOpacity(): float { return this._opacity; } diff --git a/Extensions/TiledSpriteObject/Extension.cpp b/Extensions/TiledSpriteObject/Extension.cpp index a2748cc4b2..645ca7dcd7 100644 --- a/Extensions/TiledSpriteObject/Extension.cpp +++ b/Extensions/TiledSpriteObject/Extension.cpp @@ -34,8 +34,12 @@ void DeclareTiledSpriteObjectExtension(gd::PlatformExtension& extension) { _("Tiled Sprite"), _("Displays an image repeated over an area."), "CppPlatform/Extensions/TiledSpriteIcon.png") + .AddDefaultBehavior("EffectCapability::EffectBehavior") + .AddDefaultBehavior("ResizableCapability::ResizableBehavior") + .AddDefaultBehavior("OpacityCapability::OpacityBehavior") .SetCategoryFullName(_("General")); + // Deprecated obj.AddCondition("Opacity", _("Opacity"), _("Compare the opacity of a Tiled Sprite, between 0 (fully " @@ -49,8 +53,10 @@ void DeclareTiledSpriteObjectExtension(gd::PlatformExtension& extension) { .UseStandardRelationalOperatorParameters( "number", gd::ParameterOptions::MakeNewOptions().SetDescription( - _("Opacity to compare to (0-255)"))); + _("Opacity to compare to (0-255)"))) + .SetHidden(); + // Deprecated obj.AddAction( "SetOpacity", _("Change Tiled Sprite opacity"), @@ -65,14 +71,17 @@ void DeclareTiledSpriteObjectExtension(gd::PlatformExtension& extension) { .UseStandardOperatorParameters( "number", gd::ParameterOptions::MakeNewOptions().SetDescription( - _("Opacity (0-255)"))); + _("Opacity (0-255)"))) + .SetHidden(); + // Deprecated obj.AddExpression("Opacity", _("Opacity"), _("Opacity"), _("Visibility"), "res/actions/opacity.png") - .AddParameter("object", _("Object"), "TiledSprite"); + .AddParameter("object", _("Object"), "TiledSprite") + .SetHidden(); obj.AddAction( "SetColor", @@ -86,6 +95,7 @@ void DeclareTiledSpriteObjectExtension(gd::PlatformExtension& extension) { .AddParameter("object", _("Object"), "TiledSprite") .AddParameter("color", _("Tint")); + // Deprecated obj.AddAction("Width", _("Width"), _("Modify the width of a Tiled Sprite."), @@ -97,9 +107,11 @@ void DeclareTiledSpriteObjectExtension(gd::PlatformExtension& extension) { .AddParameter("object", _("Object"), "TiledSprite") .UseStandardOperatorParameters("number", gd::ParameterOptions::MakeNewOptions()) + .SetHidden() .SetFunctionName("SetWidth") .SetGetter("GetWidth"); + // Deprecated obj.AddCondition("Width", _("Width"), _("Test the width of a Tiled Sprite."), @@ -111,8 +123,10 @@ void DeclareTiledSpriteObjectExtension(gd::PlatformExtension& extension) { .UseStandardRelationalOperatorParameters( "number", gd::ParameterOptions::MakeNewOptions()) .MarkAsAdvanced() + .SetHidden() .SetFunctionName("GetWidth"); + // Deprecated obj.AddAction("Height", _("Height"), _("Modify the height of a Tiled Sprite."), @@ -124,9 +138,11 @@ void DeclareTiledSpriteObjectExtension(gd::PlatformExtension& extension) { .AddParameter("object", _("Object"), "TiledSprite") .UseStandardOperatorParameters("number", gd::ParameterOptions::MakeNewOptions()) + .SetHidden() .SetFunctionName("SetHeight") .SetGetter("GetHeight"); + // Deprecated obj.AddCondition("Height", _("Height"), _("Test the height of a Tiled Sprite."), @@ -138,8 +154,10 @@ void DeclareTiledSpriteObjectExtension(gd::PlatformExtension& extension) { .UseStandardRelationalOperatorParameters( "number", gd::ParameterOptions::MakeNewOptions()) .MarkAsAdvanced() + .SetHidden() .SetFunctionName("GetHeight"); + // Deprecated obj.AddAction("SetSize", _("Size"), _("Modify the size of a Tiled Sprite."), @@ -151,6 +169,7 @@ void DeclareTiledSpriteObjectExtension(gd::PlatformExtension& extension) { .AddParameter("object", _("Object"), "TiledSprite") .AddParameter("expression", _("Width")) .AddParameter("expression", _("Height")) + .SetHidden() .SetFunctionName("SetSize"); // Deprecated: now available for all objects. diff --git a/Extensions/TiledSpriteObject/tiledspriteruntimeobject.ts b/Extensions/TiledSpriteObject/tiledspriteruntimeobject.ts index 2b13298349..bf6cccdf9c 100644 --- a/Extensions/TiledSpriteObject/tiledspriteruntimeobject.ts +++ b/Extensions/TiledSpriteObject/tiledspriteruntimeobject.ts @@ -17,7 +17,9 @@ namespace gdjs { /** * The TiledSpriteRuntimeObject displays a tiled texture. */ - export class TiledSpriteRuntimeObject extends gdjs.RuntimeObject { + export class TiledSpriteRuntimeObject + extends gdjs.RuntimeObject + implements gdjs.Resizable, gdjs.OpacityHandler { _xOffset: float = 0; _yOffset: float = 0; opacity: float = 255; @@ -209,10 +211,6 @@ namespace gdjs { return this._yOffset; } - /** - * Change the transparency of the object. - * @param opacity The new opacity, between 0 (transparent) and 255 (opaque). - */ setOpacity(opacity: float): void { if (opacity < 0) { opacity = 0; @@ -224,10 +222,6 @@ namespace gdjs { this._renderer.updateOpacity(); } - /** - * Get the transparency of the object. - * @return The opacity, between 0 (transparent) and 255 (opaque). - */ getOpacity(): number { return this.opacity; } @@ -253,10 +247,14 @@ namespace gdjs { // Implement support for get/set scale: /** - * Get scale of the tiled sprite object. + * Get the scale of the object (or the geometric mean of the X and Y scale in case they are different). + * + * @return the scale of the object (or the geometric mean of the X and Y scale in case they are different). */ getScale(): float { - return (this.getScaleX() + this.getScaleY()) / 2.0; + const scaleX = Math.abs(this.getScaleX()); + const scaleY = Math.abs(this.getScaleY()); + return scaleX === scaleY ? scaleX : Math.sqrt(scaleX * scaleY); } /** diff --git a/GDJS/GDJS/Events/CodeGeneration/MetadataDeclarationHelper.cpp b/GDJS/GDJS/Events/CodeGeneration/MetadataDeclarationHelper.cpp index dcffc5ddda..9f8b44812a 100644 --- a/GDJS/GDJS/Events/CodeGeneration/MetadataDeclarationHelper.cpp +++ b/GDJS/GDJS/Events/CodeGeneration/MetadataDeclarationHelper.cpp @@ -8,6 +8,8 @@ #include "GDCore/Events/Tools/EventsCodeNameMangler.h" #include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h" #include "GDCore/Extensions/PlatformExtension.h" +#include "GDCore/Project/CustomBehavior.h" +#include "GDCore/Project/CustomBehaviorsSharedData.h" #include "GDCore/Project/EventsBasedObject.h" #include "GDCore/Project/EventsFunctionsExtension.h" #include "GDCore/Project/Project.h" @@ -75,15 +77,26 @@ const gd::String &MetadataDeclarationHelper::GetExtensionIconUrl( * events based behavior. */ gd::BehaviorMetadata &MetadataDeclarationHelper::DeclareBehaviorMetadata( + const gd::Project &project, gd::PlatformExtension &extension, const gd::EventsBasedBehavior &eventsBasedBehavior) { auto &behaviorMetadata = extension - .AddEventsBasedBehavior(eventsBasedBehavior.GetName(), - eventsBasedBehavior.GetFullName() || - eventsBasedBehavior.GetName(), - eventsBasedBehavior.GetDescription(), "", - GetExtensionIconUrl(extension)) + .AddBehavior( + eventsBasedBehavior.GetName(), + eventsBasedBehavior.GetFullName() || + eventsBasedBehavior.GetName(), + eventsBasedBehavior.GetName(), + eventsBasedBehavior.GetDescription(), "", + GetExtensionIconUrl(extension), "", + std::make_shared( + eventsBasedBehavior.GetName(), project, + PlatformExtension::GetBehaviorFullType( + extension.GetName(), eventsBasedBehavior.GetName())), + std::make_shared( + eventsBasedBehavior.GetName(), project, + PlatformExtension::GetBehaviorFullType( + extension.GetName(), eventsBasedBehavior.GetName()))) .SetObjectType(eventsBasedBehavior.GetObjectType()); if (eventsBasedBehavior.IsPrivate()) @@ -111,12 +124,19 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( // several categories, we can assume it"s not scoped correctly. // Note: EventsFunctionsExtension should be used instead of // PlatformExtension but this line will be removed soon. - .SetCategoryFullName(extension.GetCategory()); + .SetCategoryFullName(extension.GetCategory()) + // Update Project::CreateObject when default behavior are added. + .AddDefaultBehavior("EffectCapability::EffectBehavior") + .AddDefaultBehavior("ResizableCapability::ResizableBehavior") + .AddDefaultBehavior("ScalableCapability::ScalableBehavior") + .AddDefaultBehavior("FlippableCapability::FlippableBehavior") + .AddDefaultBehavior("OpacityCapability::OpacityBehavior"); // TODO EBO Use full type to identify object to avoid collision. // Objects are identified by their name alone. const gd::String &objectType = eventsBasedObject.GetName(); + // Deprecated objectMetadata .AddScopedAction("Width", _("Width"), _("Change the width of an object."), _("the width"), _("Size"), @@ -126,6 +146,7 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( .UseStandardOperatorParameters("number", gd::ParameterOptions::MakeNewOptions()) .MarkAsAdvanced() + .SetHidden() .SetFunctionName("setWidth") .SetGetter("getWidth"); @@ -135,14 +156,15 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( _("the width"), _("Size"), "res/actions/scaleWidth24_black.png", "res/actions/scale_black.png") - .SetHidden() .AddParameter("object", _("Object"), objectType) .UseStandardOperatorParameters("number", gd::ParameterOptions::MakeNewOptions()) .MarkAsAdvanced() + .SetHidden() .SetFunctionName("setWidth") .SetGetter("getWidth"); + // Deprecated objectMetadata .AddScopedAction("Height", _("Height"), _("Change the height of an object."), _("the height"), @@ -152,6 +174,7 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( .UseStandardOperatorParameters("number", gd::ParameterOptions::MakeNewOptions()) .MarkAsAdvanced() + .SetHidden() .SetFunctionName("setHeight") .SetGetter("getHeight"); @@ -161,14 +184,15 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( _("the height"), _("Size"), "res/actions/scaleHeight24_black.png", "res/actions/scale_black.png") - .SetHidden() .AddParameter("object", _("Object"), objectType) .UseStandardOperatorParameters("number", gd::ParameterOptions::MakeNewOptions()) .MarkAsAdvanced() + .SetHidden() .SetFunctionName("setHeight") .SetGetter("getHeight"); + // Deprecated objectMetadata .AddScopedAction( "Scale", _("Scale"), _("Modify the scale of the specified object."), @@ -178,8 +202,9 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( .UseStandardOperatorParameters("number", gd::ParameterOptions::MakeNewOptions()) .MarkAsAdvanced() + .SetHidden() .SetFunctionName("setScale") - .SetGetter("getScale"); + .SetGetter("getScaleMean"); // Deprecated objectMetadata @@ -187,14 +212,15 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( _("Modify the scale of the specified object."), _("the scale"), _("Size"), "res/actions/scale24_black.png", "res/actions/scale_black.png") - .SetHidden() .AddParameter("object", _("Object"), objectType) .UseStandardOperatorParameters("number", gd::ParameterOptions::MakeNewOptions()) .MarkAsAdvanced() + .SetHidden() .SetFunctionName("setScale") - .SetGetter("getScale"); + .SetGetter("getScaleMean"); + // Deprecated objectMetadata .AddExpressionAndConditionAndAction( "number", "ScaleX", _("Scale on X axis"), @@ -203,9 +229,11 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( .AddParameter("object", _("Object"), objectType) .UseStandardParameters("number", gd::ParameterOptions::MakeNewOptions()) .MarkAsAdvanced() + .SetHidden() .SetFunctionName("setScaleX") .SetGetter("getScaleX"); + // Deprecated objectMetadata .AddExpressionAndConditionAndAction( "number", "ScaleY", _("Scale on Y axis"), @@ -214,9 +242,11 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( .AddParameter("object", _("Object"), objectType) .UseStandardParameters("number", gd::ParameterOptions::MakeNewOptions()) .MarkAsAdvanced() + .SetHidden() .SetFunctionName("setScaleY") .SetGetter("getScaleY"); + // Deprecated objectMetadata .AddScopedAction("FlipX", _("Flip the object horizontally"), _("Flip the object horizontally"), @@ -225,6 +255,7 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( .AddParameter("object", _("Object"), objectType) .AddParameter("yesorno", _("Activate flipping")) .MarkAsSimple() + .SetHidden() .SetFunctionName("flipX"); // Deprecated @@ -233,12 +264,13 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( _("Flip the object horizontally"), _("Flip horizontally _PARAM0_: _PARAM1_"), _("Effects"), "res/actions/flipX24.png", "res/actions/flipX.png") - .SetHidden() .AddParameter("object", _("Object"), objectType) .AddParameter("yesorno", _("Activate flipping")) .MarkAsSimple() + .SetHidden() .SetFunctionName("flipX"); + // Deprecated objectMetadata .AddScopedAction("FlipY", _("Flip the object vertically"), _("Flip the object vertically"), @@ -247,8 +279,10 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( .AddParameter("object", _("Object"), objectType) .AddParameter("yesorno", _("Activate flipping")) .MarkAsSimple() + .SetHidden() .SetFunctionName("flipY"); + // Deprecated objectMetadata .AddAction("FlipY", _("Flip the object vertically"), _("Flip the object vertically"), @@ -258,14 +292,17 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( .AddParameter("object", _("Object"), objectType) .AddParameter("yesorno", _("Activate flipping")) .MarkAsSimple() + .SetHidden() .SetFunctionName("flipY"); + // Deprecated objectMetadata .AddScopedCondition("FlippedX", _("Horizontally flipped"), _("Check if the object is horizontally flipped"), _("_PARAM0_ is horizontally flipped"), _("Effects"), "res/actions/flipX24.png", "res/actions/flipX.png") .AddParameter("object", _("Object"), objectType) + .SetHidden() .SetFunctionName("isFlippedX"); // Deprecated @@ -274,16 +311,18 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( _("Check if the object is horizontally flipped"), _("_PARAM0_ is horizontally flipped"), _("Effects"), "res/actions/flipX24.png", "res/actions/flipX.png") - .SetHidden() .AddParameter("object", _("Object"), objectType) + .SetHidden() .SetFunctionName("isFlippedX"); + // Deprecated objectMetadata .AddScopedCondition("FlippedY", _("Vertically flipped"), _("Check if the object is vertically flipped"), _("_PARAM0_ is vertically flipped"), _("Effects"), "res/actions/flipY24.png", "res/actions/flipY.png") .AddParameter("object", _("Object"), objectType) + .SetHidden() .SetFunctionName("isFlippedY"); // Deprecated @@ -292,8 +331,8 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( _("Check if the object is vertically flipped"), _("_PARAM0_ is vertically flipped"), _("Effects"), "res/actions/flipY24.png", "res/actions/flipY.png") - .SetHidden() .AddParameter("object", _("Object"), objectType) + .SetHidden() .SetFunctionName("isFlippedY"); objectMetadata @@ -305,7 +344,8 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata( .AddParameter("object", _("Object"), objectType) .UseStandardParameters("number", gd::ParameterOptions::MakeNewOptions()) .SetFunctionName("setOpacity") - .SetGetter("getOpacity"); + .SetGetter("getOpacity") + .SetHidden(); return objectMetadata; } @@ -1415,7 +1455,7 @@ gd::BehaviorMetadata &MetadataDeclarationHelper::GenerateBehaviorMetadata( const gd::EventsBasedBehavior &eventsBasedBehavior, std::map &behaviorMethodMangledNames) { auto &behaviorMetadata = - DeclareBehaviorMetadata(extension, eventsBasedBehavior); + DeclareBehaviorMetadata(project, extension, eventsBasedBehavior); auto &eventsFunctionsContainer = eventsBasedBehavior.GetEventsFunctions(); diff --git a/GDJS/GDJS/Events/CodeGeneration/MetadataDeclarationHelper.h b/GDJS/GDJS/Events/CodeGeneration/MetadataDeclarationHelper.h index f70e6323b3..cfcfdd1717 100644 --- a/GDJS/GDJS/Events/CodeGeneration/MetadataDeclarationHelper.h +++ b/GDJS/GDJS/Events/CodeGeneration/MetadataDeclarationHelper.h @@ -184,7 +184,8 @@ private: * events based behavior. */ static gd::BehaviorMetadata & - DeclareBehaviorMetadata(gd::PlatformExtension &extension, + DeclareBehaviorMetadata(const gd::Project &project, + gd::PlatformExtension &extension, const gd::EventsBasedBehavior &eventsBasedBehavior); /** diff --git a/GDJS/GDJS/Extensions/Builtin/BaseObjectExtension.cpp b/GDJS/GDJS/Extensions/Builtin/BaseObjectExtension.cpp index 9b91d0fb0c..31bc001d88 100644 --- a/GDJS/GDJS/Extensions/Builtin/BaseObjectExtension.cpp +++ b/GDJS/GDJS/Extensions/Builtin/BaseObjectExtension.cpp @@ -27,14 +27,8 @@ BaseObjectExtension::BaseObjectExtension() { std::map &objectStrExpressions = GetAllStrExpressionsForObject(""); - objectActions["MettreX"] - .SetFunctionName("setX") - .SetGetter("getX") - .SetIncludeFile("runtimeobject.js"); - objectActions["MettreY"] - .SetFunctionName("setY") - .SetGetter("getY") - .SetIncludeFile("runtimeobject.js"); + objectActions["MettreX"].SetFunctionName("setX").SetGetter("getX"); + objectActions["MettreY"].SetFunctionName("setY").SetGetter("getY"); objectConditions["PosX"].SetFunctionName("getX").SetIncludeFile( "runtimeobject.js"); objectConditions["PosY"].SetFunctionName("getY").SetIncludeFile( @@ -47,13 +41,8 @@ BaseObjectExtension::BaseObjectExtension() { objectActions["SetCenterY"] .SetFunctionName("setCenterYInScene") .SetGetter("getCenterYInScene"); - objectActions["SetAngle"] - .SetFunctionName("setAngle") - .SetGetter("getAngle") - .SetIncludeFile("runtimeobject.js"); - objectConditions["Angle"] - .SetFunctionName("getAngle") - .SetIncludeFile("runtimeobject.js"); + objectActions["SetAngle"].SetFunctionName("setAngle").SetGetter("getAngle"); + objectConditions["Angle"].SetFunctionName("getAngle"); objectConditions["BoundingBoxLeft"].SetFunctionName("getAABBLeft"); objectConditions["BoundingBoxTop"].SetFunctionName("getAABBTop"); objectConditions["BoundingBoxRight"].SetFunctionName("getAABBRight"); @@ -62,142 +51,71 @@ BaseObjectExtension::BaseObjectExtension() { objectConditions["BoundingBoxCenterY"].SetFunctionName("getAABBCenterY"); objectActions["Rotate"].SetFunctionName("rotate").SetIncludeFile( "runtimeobject.js"); - objectActions["RotateTowardAngle"] - .SetFunctionName("rotateTowardAngle") - .SetIncludeFile("runtimeobject.js"); - objectActions["RotateTowardPosition"] - .SetFunctionName("rotateTowardPosition") - .SetIncludeFile("runtimeobject.js"); - objectActions["ChangeLayer"] - .SetFunctionName("setLayer") - .SetIncludeFile("runtimeobject.js"); - objectConditions["Layer"] - .SetFunctionName("isOnLayer") - .SetIncludeFile("runtimeobject.js"); + objectActions["RotateTowardAngle"].SetFunctionName("rotateTowardAngle"); + objectActions["RotateTowardPosition"].SetFunctionName("rotateTowardPosition"); + objectActions["ChangeLayer"].SetFunctionName("setLayer"); + objectConditions["Layer"].SetFunctionName("isOnLayer"); objectActions["ChangePlan"] .SetFunctionName("setZOrder") - .SetGetter("getZOrder") - .SetIncludeFile("runtimeobject.js"); - objectConditions["Plan"] - .SetFunctionName("getZOrder") - .SetIncludeFile("runtimeobject.js"); + .SetGetter("getZOrder"); + objectConditions["Plan"].SetFunctionName("getZOrder"); objectActions["Cache"].SetFunctionName("hide").SetIncludeFile( "runtimeobject.js"); objectActions["Montre"].SetFunctionName("hide").SetIncludeFile( "runtimeobject.js"); - objectConditions["Visible"] - .SetFunctionName("isVisible") - .SetIncludeFile("runtimeobject.js"); - objectConditions["Invisible"] - .SetFunctionName("isHidden") - .SetIncludeFile("runtimeobject.js"); - objectConditions["IsEffectEnabled"] - .SetFunctionName("isEffectEnabled") - .SetIncludeFile("runtimeobject.js"); + objectConditions["Visible"].SetFunctionName("isVisible"); + objectConditions["Invisible"].SetFunctionName("isHidden"); + objectConditions["IsEffectEnabled"].SetFunctionName("isEffectEnabled"); objectActions["Delete"].SetFunctionName("deleteFromScene"); objectActions["MettreAutourPos"].SetFunctionName("putAround"); - objectActions["MettreAutour"] - .SetFunctionName("putAroundObject") - .SetIncludeFile("runtimeobject.js"); - objectConditions["VarObjet"] - .SetFunctionName("getVariableNumber") - .SetIncludeFile("runtimeobject.js"); - objectConditions["VarObjetTxt"] - .SetFunctionName("getVariableString") - .SetIncludeFile("runtimeobject.js"); - objectConditions["ObjectVariableAsBoolean"] - .SetFunctionName("getVariableBoolean") - .SetIncludeFile("runtimeobject.js"); - objectConditions["VarObjetDef"] - .SetFunctionName("hasVariable") - .SetIncludeFile("runtimeobject.js"); - objectActions["AddForceXY"] - .SetFunctionName("addForce") - .SetIncludeFile("runtimeobject.js"); - objectActions["AddForceAL"] - .SetFunctionName("addPolarForce") - .SetIncludeFile("runtimeobject.js"); - objectActions["AddForceVersPos"] - .SetFunctionName("addForceTowardPosition") - .SetIncludeFile("runtimeobject.js"); - objectActions["AddForceVers"] - .SetFunctionName("addForceTowardObject") - .SetIncludeFile("runtimeobject.js"); - objectActions["Arreter"] - .SetFunctionName("clearForces") - .SetIncludeFile("runtimeobject.js"); - objectConditions["Arret"] - .SetFunctionName("hasNoForces") - .SetIncludeFile("runtimeobject.js"); - objectConditions["Vitesse"] - .SetFunctionName("getAverageForce().getLength") - .SetIncludeFile("runtimeobject.js"); - objectConditions["AngleOfDisplacement"] - .SetFunctionName("averageForceAngleIs") - .SetIncludeFile("runtimeobject.js"); - objectActions["SeparateFromObjects"] - .SetFunctionName("separateFromObjectsList") - .SetIncludeFile("runtimeobject.js"); - objectActions["Ecarter"] // Deprecated - .SetFunctionName("separateObjectsWithoutForces") - .SetIncludeFile("runtimeobject.js"); - objectActions["Rebondir"] // Deprecated - .SetFunctionName("separateObjectsWithForces") - .SetIncludeFile("runtimeobject.js"); - objectConditions["BehaviorActivated"] - .SetFunctionName("behaviorActivated") - .SetIncludeFile("runtimeobject.js"); - objectActions["ActivateBehavior"] - .SetFunctionName("activateBehavior") - .SetIncludeFile("runtimeobject.js"); - objectConditions["ObjectVariableChildExists"] - .SetFunctionName("variableChildExists") - .SetIncludeFile("runtimeobject.js"); - objectActions["ObjectVariableRemoveChild"] - .SetFunctionName("variableRemoveChild") - .SetIncludeFile("runtimeobject.js"); - objectActions["ObjectVariableClearChildren"] - .SetFunctionName("variableClearChildren") - .SetIncludeFile("runtimeobject.js"); - objectConditions["CollisionPoint"] - .SetFunctionName("isCollidingWithPoint") - .SetIncludeFile("runtimeobject.js"); - objectConditions["ObjectTimer"] // deprecated - .SetFunctionName("timerElapsedTime") - .SetIncludeFile("runtimeobject.js"); - objectConditions["CompareObjectTimer"] - .SetFunctionName("getTimerElapsedTimeInSecondsOrNaN") - .SetIncludeFile("runtimeobject.js"); - objectConditions["ObjectTimerPaused"] - .SetFunctionName("timerPaused") - .SetIncludeFile("runtimeobject.js"); - objectActions["ResetObjectTimer"] - .SetFunctionName("resetTimer") - .SetIncludeFile("runtimeobject.js"); - objectActions["PauseObjectTimer"] - .SetFunctionName("pauseTimer") - .SetIncludeFile("runtimeobject.js"); - objectActions["UnPauseObjectTimer"] - .SetFunctionName("unpauseTimer") - .SetIncludeFile("runtimeobject.js"); - objectActions["RemoveObjectTimer"] - .SetFunctionName("removeTimer") - .SetIncludeFile("runtimeobject.js"); - objectActions["EnableEffect"] - .SetFunctionName("enableEffect") - .SetIncludeFile("runtimeobject.js"); - objectActions["SetEffectDoubleParameter"] - .SetFunctionName("setEffectDoubleParameter") - .SetIncludeFile("runtimeobject.js"); - objectActions["SetEffectStringParameter"] - .SetFunctionName("setEffectStringParameter") - .SetIncludeFile("runtimeobject.js"); - objectActions["SetEffectBooleanParameter"] - .SetFunctionName("setEffectBooleanParameter") - .SetIncludeFile("runtimeobject.js"); - objectActions["SetIncludedInParentCollisionMask"] - .SetFunctionName("setIncludedInParentCollisionMask") - .SetIncludeFile("runtimeobject.js"); + objectActions["MettreAutour"].SetFunctionName("putAroundObject"); + objectConditions["VarObjet"].SetFunctionName("getVariableNumber"); + objectConditions["VarObjetTxt"].SetFunctionName("getVariableString"); + objectConditions["ObjectVariableAsBoolean"].SetFunctionName( + "getVariableBoolean"); + objectConditions["VarObjetDef"].SetFunctionName("hasVariable"); + objectActions["AddForceXY"].SetFunctionName("addForce"); + objectActions["AddForceAL"].SetFunctionName("addPolarForce"); + objectActions["AddForceVersPos"].SetFunctionName("addForceTowardPosition"); + objectActions["AddForceVers"].SetFunctionName("addForceTowardObject"); + objectActions["Arreter"].SetFunctionName("clearForces"); + objectConditions["Arret"].SetFunctionName("hasNoForces"); + objectConditions["Vitesse"].SetFunctionName("getAverageForce().getLength"); + objectConditions["AngleOfDisplacement"].SetFunctionName( + "averageForceAngleIs"); + objectActions["SeparateFromObjects"].SetFunctionName( + "separateFromObjectsList"); + // Deprecated + objectActions["Ecarter"].SetFunctionName("separateObjectsWithoutForces"); + // Deprecated + objectActions["Rebondir"].SetFunctionName("separateObjectsWithForces"); + objectConditions["BehaviorActivated"].SetFunctionName("behaviorActivated"); + objectActions["ActivateBehavior"].SetFunctionName("activateBehavior"); + objectConditions["ObjectVariableChildExists"].SetFunctionName( + "variableChildExists"); + objectActions["ObjectVariableRemoveChild"].SetFunctionName( + "variableRemoveChild"); + objectActions["ObjectVariableClearChildren"].SetFunctionName( + "variableClearChildren"); + objectConditions["CollisionPoint"].SetFunctionName("isCollidingWithPoint"); + // deprecated + objectConditions["ObjectTimer"].SetFunctionName("timerElapsedTime"); + objectConditions["CompareObjectTimer"].SetFunctionName( + "getTimerElapsedTimeInSecondsOrNaN"); + objectConditions["ObjectTimerPaused"].SetFunctionName("timerPaused"); + objectActions["ResetObjectTimer"].SetFunctionName("resetTimer"); + objectActions["PauseObjectTimer"].SetFunctionName("pauseTimer"); + objectActions["UnPauseObjectTimer"].SetFunctionName("unpauseTimer"); + objectActions["RemoveObjectTimer"].SetFunctionName("removeTimer"); + objectActions["EnableEffect"].SetFunctionName("enableEffect"); + objectActions["SetEffectDoubleParameter"].SetFunctionName( + "setEffectDoubleParameter"); + objectActions["SetEffectStringParameter"].SetFunctionName( + "setEffectStringParameter"); + objectActions["SetEffectBooleanParameter"].SetFunctionName( + "setEffectBooleanParameter"); + objectActions["SetIncludedInParentCollisionMask"].SetFunctionName( + "setIncludedInParentCollisionMask"); objectExpressions["X"].SetFunctionName("getX"); objectExpressions["Y"].SetFunctionName("getY"); @@ -210,11 +128,14 @@ BaseObjectExtension::BaseObjectExtension() { objectExpressions["BoundingBoxCenterX"].SetFunctionName("getAABBCenterX"); objectExpressions["BoundingBoxCenterY"].SetFunctionName("getAABBCenterY"); objectExpressions["ZOrder"].SetFunctionName("getZOrder"); - objectExpressions["Plan"].SetFunctionName("getZOrder"); // Deprecated + // Deprecated + objectExpressions["Plan"].SetFunctionName("getZOrder"); objectExpressions["Width"].SetFunctionName("getWidth"); objectExpressions["Height"].SetFunctionName("getHeight"); - objectExpressions["Largeur"].SetFunctionName("getWidth"); // Deprecated - objectExpressions["Hauteur"].SetFunctionName("getHeight"); // Deprecated + // Deprecated + objectExpressions["Largeur"].SetFunctionName("getWidth"); + // Deprecated + objectExpressions["Hauteur"].SetFunctionName("getHeight"); objectExpressions["Variable"] .SetFunctionName("gdjs.RuntimeObject.getVariableNumber") .SetStatic(); @@ -242,8 +163,8 @@ BaseObjectExtension::BaseObjectExtension() { objectExpressions["Angle"].SetFunctionName("getAngle"); objectExpressions["ForceLength"].SetFunctionName( "getAverageForce().getLength"); - objectExpressions["Longueur"].SetFunctionName( - "getAverageForce().getLength"); // Deprecated + // Deprecated + objectExpressions["Longueur"].SetFunctionName("getAverageForce().getLength"); objectExpressions["Distance"].SetFunctionName("getDistanceToObject"); objectExpressions["SqDistance"].SetFunctionName("getSqDistanceToObject"); objectExpressions["DistanceToPosition"].SetFunctionName( @@ -265,11 +186,12 @@ BaseObjectExtension::BaseObjectExtension() { "gdjs.evtTools.object.createObjectOnScene"); GetAllActions()["CreateByName"].SetFunctionName( "gdjs.evtTools.object.createObjectFromGroupOnScene"); - + // Deprecated GetAllExpressions()["Count"].SetFunctionName( - "gdjs.evtTools.object.pickedObjectsCount"); // Deprecated + "gdjs.evtTools.object.pickedObjectsCount"); + // Deprecated GetAllConditions()["NbObjet"].SetFunctionName( - "gdjs.evtTools.object.pickedObjectsCount"); // Deprecated + "gdjs.evtTools.object.pickedObjectsCount"); GetAllExpressions()["SceneInstancesCount"].SetFunctionName( "gdjs.evtTools.object.getSceneInstancesCount"); @@ -315,42 +237,27 @@ BaseObjectExtension::BaseObjectExtension() { {"-", "sub"}, {"*", "mul"}, {"/", "div"}, - }) - .SetIncludeFile("runtimeobject.js"); + }); objectActions["ModVarObjetTxt"] .SetFunctionName("returnVariable") .SetManipulatedType("string") .SetMutators({ {"=", "setString"}, {"+", "concatenate"}, - }) - .SetIncludeFile("runtimeobject.js"); + }); - objectActions["SetObjectVariableAsBoolean"] - .SetFunctionName("setVariableBoolean") - .SetIncludeFile("runtimeobject.js"); - objectActions["ToggleObjectVariableAsBoolean"] - .SetFunctionName("toggleVariableBoolean") - .SetIncludeFile("runtimeobject.js"); + objectActions["SetObjectVariableAsBoolean"].SetFunctionName( + "setVariableBoolean"); + objectActions["ToggleObjectVariableAsBoolean"].SetFunctionName( + "toggleVariableBoolean"); - objectActions["ObjectVariablePush"] - .SetFunctionName("variablePushCopy") - .SetIncludeFile("runtimeobject.js"); - objectActions["ObjectVariablePushString"] - .SetFunctionName("valuePush") - .SetIncludeFile("runtimeobject.js"); - objectActions["ObjectVariablePushNumber"] - .SetFunctionName("valuePush") - .SetIncludeFile("runtimeobject.js"); - objectActions["ObjectVariablePushBool"] - .SetFunctionName("valuePush") - .SetIncludeFile("runtimeobject.js"); - objectActions["ObjectVariableRemoveAt"] - .SetFunctionName("variableRemoveAt") - .SetIncludeFile("runtimeobject.js"); - objectConditions["ObjectVariableChildCount"] - .SetFunctionName("getVariableChildCount") - .SetIncludeFile("runtimeobject.js"); + objectActions["ObjectVariablePush"].SetFunctionName("variablePushCopy"); + objectActions["ObjectVariablePushString"].SetFunctionName("valuePush"); + objectActions["ObjectVariablePushNumber"].SetFunctionName("valuePush"); + objectActions["ObjectVariablePushBool"].SetFunctionName("valuePush"); + objectActions["ObjectVariableRemoveAt"].SetFunctionName("variableRemoveAt"); + objectConditions["ObjectVariableChildCount"].SetFunctionName( + "getVariableChildCount"); GetAllActions()["MoveObjects"].SetCustomCodeGenerator( [](gd::Instruction &, @@ -481,4 +388,4 @@ BaseObjectExtension::BaseObjectExtension() { StripUnimplementedInstructionsAndExpressions(); } -} // namespace gdjs +} // namespace gdjs diff --git a/GDJS/GDJS/Extensions/Builtin/Capacities/AnimatableExtension.cpp b/GDJS/GDJS/Extensions/Builtin/Capacities/AnimatableExtension.cpp new file mode 100644 index 0000000000..3328b4935a --- /dev/null +++ b/GDJS/GDJS/Extensions/Builtin/Capacities/AnimatableExtension.cpp @@ -0,0 +1,72 @@ +/* + * GDevelop JS Platform + * Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the MIT License. + */ +#include "GDJS/Extensions/Builtin/Capacities/AnimatableExtension.h" +#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h" +#include "GDCore/Extensions/Metadata/InstructionMetadata.h" +#include "GDCore/Tools/Localization.h" + +namespace gdjs { + +AnimatableExtension::AnimatableExtension() { + gd::BuiltinExtensionsImplementer::ImplementsAnimatableExtension(*this); + + GetBehaviorMetadata("AnimatableCapability::AnimatableBehavior") + .SetIncludeFile("object-capabilities/AnimatableBehavior.js"); + + auto& actions = GetAllActionsForBehavior("AnimatableCapability::AnimatableBehavior"); + auto& conditions = GetAllConditionsForBehavior("AnimatableCapability::AnimatableBehavior"); + auto& expressions = GetAllExpressionsForBehavior("AnimatableCapability::AnimatableBehavior"); + auto& strExpressions = GetAllStrExpressionsForBehavior("AnimatableCapability::AnimatableBehavior"); + + actions["AnimatableCapability::AnimatableBehavior::SetIndex"] + .SetFunctionName("setAnimationIndex") + .SetGetter("getAnimationIndex") + .SetIncludeFile("object-capabilities/AnimatableBehavior.js"); + conditions["AnimatableCapability::AnimatableBehavior::Index"] + .SetFunctionName("getAnimationIndex") + .SetIncludeFile("object-capabilities/AnimatableBehavior.js"); + expressions["Index"] + .SetFunctionName("getAnimationIndex") + .SetIncludeFile("object-capabilities/AnimatableBehavior.js"); + + actions["AnimatableCapability::AnimatableBehavior::SetName"] + .SetFunctionName("setAnimationName") + .SetGetter("getAnimationName") + .SetIncludeFile("object-capabilities/AnimatableBehavior.js"); + conditions["AnimatableCapability::AnimatableBehavior::Name"] + .SetFunctionName("getAnimationName") + .SetIncludeFile("object-capabilities/AnimatableBehavior.js"); + strExpressions["Name"] + .SetFunctionName("getAnimationName") + .SetIncludeFile("object-capabilities/AnimatableBehavior.js"); + + actions["AnimatableCapability::AnimatableBehavior::SetSpeedScale"] + .SetFunctionName("setAnimationSpeedScale") + .SetGetter("getAnimationSpeedScale") + .SetIncludeFile("object-capabilities/AnimatableBehavior.js"); + conditions["AnimatableCapability::AnimatableBehavior::SpeedScale"] + .SetFunctionName("getAnimationSpeedScale") + .SetIncludeFile("object-capabilities/AnimatableBehavior.js"); + expressions["SpeedScale"] + .SetFunctionName("getAnimationSpeedScale") + .SetIncludeFile("object-capabilities/AnimatableBehavior.js"); + + actions["AnimatableCapability::AnimatableBehavior::PauseAnimation"] + .SetFunctionName("pauseAnimation") + .SetIncludeFile("object-capabilities/AnimatableBehavior.js"); + actions["AnimatableCapability::AnimatableBehavior::PlayAnimation"] + .SetFunctionName("resumeAnimation") + .SetIncludeFile("object-capabilities/AnimatableBehavior.js"); + + conditions["AnimatableCapability::AnimatableBehavior::IsAnimationPaused"] + .SetFunctionName("isAnimationPaused") + .SetIncludeFile("object-capabilities/AnimatableBehavior.js"); + conditions["AnimatableCapability::AnimatableBehavior::HasAnimationEnded"] + .SetFunctionName("hasAnimationEnded") + .SetIncludeFile("object-capabilities/AnimatableBehavior.js"); +} + +} // namespace gdjs diff --git a/GDJS/GDJS/Extensions/Builtin/Capacities/AnimatableExtension.h b/GDJS/GDJS/Extensions/Builtin/Capacities/AnimatableExtension.h new file mode 100644 index 0000000000..04914dec5c --- /dev/null +++ b/GDJS/GDJS/Extensions/Builtin/Capacities/AnimatableExtension.h @@ -0,0 +1,22 @@ +/* + * GDevelop JS Platform + * Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the MIT License. + */ +#pragma once +#include "GDCore/Extensions/PlatformExtension.h" + +namespace gdjs { + +/** + * \brief Built-in extension providing Animatable object capacity. + * + * \ingroup BuiltinExtensions + */ +class AnimatableExtension : public gd::PlatformExtension { + public: + AnimatableExtension(); + virtual ~AnimatableExtension(){}; +}; + +} // namespace gdjs diff --git a/GDJS/GDJS/Extensions/Builtin/Capacities/EffectExtension.cpp b/GDJS/GDJS/Extensions/Builtin/Capacities/EffectExtension.cpp new file mode 100644 index 0000000000..823a293789 --- /dev/null +++ b/GDJS/GDJS/Extensions/Builtin/Capacities/EffectExtension.cpp @@ -0,0 +1,40 @@ +/* + * GDevelop JS Platform + * Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the MIT License. + */ +#include "GDJS/Extensions/Builtin/Capacities/EffectExtension.h" +#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h" +#include "GDCore/Extensions/Metadata/InstructionMetadata.h" +#include "GDCore/Tools/Localization.h" + +namespace gdjs { + +EffectExtension::EffectExtension() { + gd::BuiltinExtensionsImplementer::ImplementsEffectExtension(*this); + + GetBehaviorMetadata("EffectCapability::EffectBehavior") + .SetIncludeFile("object-capabilities/EffectBehavior.js"); + + auto& actions = GetAllActionsForBehavior("EffectCapability::EffectBehavior"); + auto& conditions = GetAllConditionsForBehavior("EffectCapability::EffectBehavior"); + + actions["EffectCapability::EffectBehavior::SetEffectDoubleParameter"] + .SetFunctionName("setEffectDoubleParameter") + .SetIncludeFile("object-capabilities/EffectBehavior.js"); + actions["EffectCapability::EffectBehavior::SetEffectStringParameter"] + .SetFunctionName("setEffectStringParameter") + .SetIncludeFile("object-capabilities/EffectBehavior.js"); + actions["EffectCapability::EffectBehavior::SetEffectBooleanParameter"] + .SetFunctionName("setEffectBooleanParameter") + .SetIncludeFile("object-capabilities/EffectBehavior.js"); + + actions["EffectCapability::EffectBehavior::EnableEffect"] + .SetFunctionName("enableEffect") + .SetIncludeFile("object-capabilities/EffectBehavior.js"); + conditions["EffectCapability::EffectBehavior::IsEffectEnabled"] + .SetFunctionName("isEffectEnabled") + .SetIncludeFile("object-capabilities/EffectBehavior.js"); +} + +} // namespace gdjs diff --git a/GDJS/GDJS/Extensions/Builtin/Capacities/EffectExtension.h b/GDJS/GDJS/Extensions/Builtin/Capacities/EffectExtension.h new file mode 100644 index 0000000000..6817d16dc9 --- /dev/null +++ b/GDJS/GDJS/Extensions/Builtin/Capacities/EffectExtension.h @@ -0,0 +1,22 @@ +/* + * GDevelop JS Platform + * Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the MIT License. + */ +#pragma once +#include "GDCore/Extensions/PlatformExtension.h" + +namespace gdjs { + +/** + * \brief Built-in extension providing Effect object capacity. + * + * \ingroup BuiltinExtensions + */ +class EffectExtension : public gd::PlatformExtension { + public: + EffectExtension(); + virtual ~EffectExtension(){}; +}; + +} // namespace gdjs diff --git a/GDJS/GDJS/Extensions/Builtin/Capacities/FlippableExtension.cpp b/GDJS/GDJS/Extensions/Builtin/Capacities/FlippableExtension.cpp new file mode 100644 index 0000000000..dee2e82376 --- /dev/null +++ b/GDJS/GDJS/Extensions/Builtin/Capacities/FlippableExtension.cpp @@ -0,0 +1,37 @@ +/* + * GDevelop JS Platform + * Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the MIT License. + */ +#include "GDJS/Extensions/Builtin/Capacities/FlippableExtension.h" +#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h" +#include "GDCore/Extensions/Metadata/InstructionMetadata.h" +#include "GDCore/Tools/Localization.h" + +namespace gdjs { + +FlippableExtension::FlippableExtension() { + gd::BuiltinExtensionsImplementer::ImplementsFlippableExtension(*this); + + GetBehaviorMetadata("FlippableCapability::FlippableBehavior") + .SetIncludeFile("object-capabilities/FlippableBehavior.js"); + + auto& actions = GetAllActionsForBehavior("FlippableCapability::FlippableBehavior"); + auto& conditions = GetAllConditionsForBehavior("FlippableCapability::FlippableBehavior"); + + actions["FlippableCapability::FlippableBehavior::FlipX"] + .SetFunctionName("flipX") + .SetIncludeFile("object-capabilities/FlippableBehavior.js"); + conditions["FlippableCapability::FlippableBehavior::FlippedX"] + .SetFunctionName("isFlippedX") + .SetIncludeFile("object-capabilities/FlippableBehavior.js"); + + actions["FlippableCapability::FlippableBehavior::FlipY"] + .SetFunctionName("flipY") + .SetIncludeFile("object-capabilities/FlippableBehavior.js"); + conditions["FlippableCapability::FlippableBehavior::FlippedY"] + .SetFunctionName("isFlippedY") + .SetIncludeFile("object-capabilities/FlippableBehavior.js"); +} + +} // namespace gdjs diff --git a/GDJS/GDJS/Extensions/Builtin/Capacities/FlippableExtension.h b/GDJS/GDJS/Extensions/Builtin/Capacities/FlippableExtension.h new file mode 100644 index 0000000000..1b2666f137 --- /dev/null +++ b/GDJS/GDJS/Extensions/Builtin/Capacities/FlippableExtension.h @@ -0,0 +1,22 @@ +/* + * GDevelop JS Platform + * Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the MIT License. + */ +#pragma once +#include "GDCore/Extensions/PlatformExtension.h" + +namespace gdjs { + +/** + * \brief Built-in extension providing Flippable object capacity. + * + * \ingroup BuiltinExtensions + */ +class FlippableExtension : public gd::PlatformExtension { + public: + FlippableExtension(); + virtual ~FlippableExtension(){}; +}; + +} // namespace gdjs diff --git a/GDJS/GDJS/Extensions/Builtin/Capacities/OpacityExtension.cpp b/GDJS/GDJS/Extensions/Builtin/Capacities/OpacityExtension.cpp new file mode 100644 index 0000000000..e187b32aa0 --- /dev/null +++ b/GDJS/GDJS/Extensions/Builtin/Capacities/OpacityExtension.cpp @@ -0,0 +1,35 @@ +/* + * GDevelop JS Platform + * Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the MIT License. + */ +#include "GDJS/Extensions/Builtin/Capacities/OpacityExtension.h" +#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h" +#include "GDCore/Extensions/Metadata/InstructionMetadata.h" +#include "GDCore/Tools/Localization.h" + +namespace gdjs { + +OpacityExtension::OpacityExtension() { + gd::BuiltinExtensionsImplementer::ImplementsOpacityExtension(*this); + + GetBehaviorMetadata("OpacityCapability::OpacityBehavior") + .SetIncludeFile("object-capabilities/OpacityBehavior.js"); + + auto& actions = GetAllActionsForBehavior("OpacityCapability::OpacityBehavior"); + auto& conditions = GetAllConditionsForBehavior("OpacityCapability::OpacityBehavior"); + auto& expressions = GetAllExpressionsForBehavior("OpacityCapability::OpacityBehavior"); + + actions["OpacityCapability::OpacityBehavior::SetValue"] + .SetFunctionName("setOpacity") + .SetGetter("getOpacity") + .SetIncludeFile("object-capabilities/OpacityBehavior.js"); + conditions["OpacityCapability::OpacityBehavior::Value"] + .SetFunctionName("getOpacity") + .SetIncludeFile("object-capabilities/OpacityBehavior.js"); + expressions["Value"] + .SetFunctionName("getOpacity") + .SetIncludeFile("object-capabilities/ScalableBehavior.js"); +} + +} // namespace gdjs diff --git a/GDJS/GDJS/Extensions/Builtin/Capacities/OpacityExtension.h b/GDJS/GDJS/Extensions/Builtin/Capacities/OpacityExtension.h new file mode 100644 index 0000000000..364dc59735 --- /dev/null +++ b/GDJS/GDJS/Extensions/Builtin/Capacities/OpacityExtension.h @@ -0,0 +1,22 @@ +/* + * GDevelop JS Platform + * Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the MIT License. + */ +#pragma once +#include "GDCore/Extensions/PlatformExtension.h" + +namespace gdjs { + +/** + * \brief Built-in extension providing Opacity object capacity. + * + * \ingroup BuiltinExtensions + */ +class OpacityExtension : public gd::PlatformExtension { + public: + OpacityExtension(); + virtual ~OpacityExtension(){}; +}; + +} // namespace gdjs diff --git a/GDJS/GDJS/Extensions/Builtin/Capacities/ResizableExtension.cpp b/GDJS/GDJS/Extensions/Builtin/Capacities/ResizableExtension.cpp new file mode 100644 index 0000000000..e75a5c1ad4 --- /dev/null +++ b/GDJS/GDJS/Extensions/Builtin/Capacities/ResizableExtension.cpp @@ -0,0 +1,43 @@ +/* + * GDevelop JS Platform + * Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the MIT License. + */ +#include "GDJS/Extensions/Builtin/Capacities/ResizableExtension.h" +#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h" +#include "GDCore/Extensions/Metadata/InstructionMetadata.h" +#include "GDCore/Tools/Localization.h" + +namespace gdjs { + +ResizableExtension::ResizableExtension() { + gd::BuiltinExtensionsImplementer::ImplementsResizableExtension(*this); + + GetBehaviorMetadata("ResizableCapability::ResizableBehavior") + .SetIncludeFile("object-capabilities/ResizableBehavior.js"); + + auto& actions = GetAllActionsForBehavior("ResizableCapability::ResizableBehavior"); + auto& conditions = GetAllConditionsForBehavior("ResizableCapability::ResizableBehavior"); + + actions["ResizableCapability::ResizableBehavior::SetWidth"] + .SetFunctionName("setWidth") + .SetGetter("getWidth") + .SetIncludeFile("object-capabilities/ResizableBehavior.js"); + conditions["ResizableCapability::ResizableBehavior::Width"] + .SetFunctionName("getWidth") + .SetIncludeFile("object-capabilities/ResizableBehavior.js"); + + actions["ResizableCapability::ResizableBehavior::SetHeight"] + .SetFunctionName("setHeight") + .SetGetter("getHeight") + .SetIncludeFile("object-capabilities/ResizableBehavior.js"); + conditions["ResizableCapability::ResizableBehavior::Height"] + .SetFunctionName("getHeight") + .SetIncludeFile("object-capabilities/ResizableBehavior.js"); + + actions["ResizableCapability::ResizableBehavior::SetSize"] + .SetFunctionName("setSize") + .SetIncludeFile("object-capabilities/ResizableBehavior.js"); +} + +} // namespace gdjs diff --git a/GDJS/GDJS/Extensions/Builtin/Capacities/ResizableExtension.h b/GDJS/GDJS/Extensions/Builtin/Capacities/ResizableExtension.h new file mode 100644 index 0000000000..d08435cbd2 --- /dev/null +++ b/GDJS/GDJS/Extensions/Builtin/Capacities/ResizableExtension.h @@ -0,0 +1,22 @@ +/* + * GDevelop JS Platform + * Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the MIT License. + */ +#pragma once +#include "GDCore/Extensions/PlatformExtension.h" + +namespace gdjs { + +/** + * \brief Built-in extension providing Resizable object capacity. + * + * \ingroup BuiltinExtensions + */ +class ResizableExtension : public gd::PlatformExtension { + public: + ResizableExtension(); + virtual ~ResizableExtension(){}; +}; + +} // namespace gdjs diff --git a/GDJS/GDJS/Extensions/Builtin/Capacities/ScalableExtension.cpp b/GDJS/GDJS/Extensions/Builtin/Capacities/ScalableExtension.cpp new file mode 100644 index 0000000000..3e4ea4d9dc --- /dev/null +++ b/GDJS/GDJS/Extensions/Builtin/Capacities/ScalableExtension.cpp @@ -0,0 +1,57 @@ +/* + * GDevelop JS Platform + * Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the MIT License. + */ +#include "GDJS/Extensions/Builtin/Capacities/ScalableExtension.h" +#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h" +#include "GDCore/Extensions/Metadata/InstructionMetadata.h" +#include "GDCore/Tools/Localization.h" + +namespace gdjs { + +ScalableExtension::ScalableExtension() { + gd::BuiltinExtensionsImplementer::ImplementsScalableExtension(*this); + + GetBehaviorMetadata("ScalableCapability::ScalableBehavior") + .SetIncludeFile("object-capabilities/ScalableBehavior.js"); + + auto& actions = GetAllActionsForBehavior("ScalableCapability::ScalableBehavior"); + auto& conditions = GetAllConditionsForBehavior("ScalableCapability::ScalableBehavior"); + auto& expressions = GetAllExpressionsForBehavior("ScalableCapability::ScalableBehavior"); + + actions["ScalableCapability::ScalableBehavior::SetValue"] + .SetFunctionName("setScale") + .SetGetter("getScale") + .SetIncludeFile("object-capabilities/ScalableBehavior.js"); + conditions["ScalableCapability::ScalableBehavior::Value"] + .SetFunctionName("getScale") + .SetIncludeFile("object-capabilities/ScalableBehavior.js"); + expressions["Value"] + .SetFunctionName("getScale") + .SetIncludeFile("object-capabilities/ScalableBehavior.js"); + + actions["ScalableCapability::ScalableBehavior::SetX"] + .SetFunctionName("setScaleX") + .SetGetter("getScaleX") + .SetIncludeFile("object-capabilities/ScalableBehavior.js"); + conditions["ScalableCapability::ScalableBehavior::X"] + .SetFunctionName("getScaleX") + .SetIncludeFile("object-capabilities/ScalableBehavior.js"); + expressions["X"] + .SetFunctionName("getScaleX") + .SetIncludeFile("object-capabilities/ScalableBehavior.js"); + + actions["ScalableCapability::ScalableBehavior::SetY"] + .SetFunctionName("setScaleY") + .SetGetter("getScaleY") + .SetIncludeFile("object-capabilities/ScalableBehavior.js"); + conditions["ScalableCapability::ScalableBehavior::Y"] + .SetFunctionName("getScaleY") + .SetIncludeFile("object-capabilities/ScalableBehavior.js"); + expressions["Y"] + .SetFunctionName("getScaleY") + .SetIncludeFile("object-capabilities/ScalableBehavior.js"); +} + +} // namespace gdjs diff --git a/GDJS/GDJS/Extensions/Builtin/Capacities/ScalableExtension.h b/GDJS/GDJS/Extensions/Builtin/Capacities/ScalableExtension.h new file mode 100644 index 0000000000..3eaf9d4494 --- /dev/null +++ b/GDJS/GDJS/Extensions/Builtin/Capacities/ScalableExtension.h @@ -0,0 +1,22 @@ +/* + * GDevelop JS Platform + * Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights + * reserved. This project is released under the MIT License. + */ +#pragma once +#include "GDCore/Extensions/PlatformExtension.h" + +namespace gdjs { + +/** + * \brief Built-in extension providing Scalable object capacity. + * + * \ingroup BuiltinExtensions + */ +class ScalableExtension : public gd::PlatformExtension { + public: + ScalableExtension(); + virtual ~ScalableExtension(){}; +}; + +} // namespace gdjs diff --git a/GDJS/GDJS/Extensions/Builtin/SpriteExtension.cpp b/GDJS/GDJS/Extensions/Builtin/SpriteExtension.cpp index 4ad982791a..e99a904601 100644 --- a/GDJS/GDJS/Extensions/Builtin/SpriteExtension.cpp +++ b/GDJS/GDJS/Extensions/Builtin/SpriteExtension.cpp @@ -45,7 +45,7 @@ SpriteExtension::SpriteExtension() { spriteConditions["AnimationName"].SetFunctionName("isCurrentAnimationName"); spriteConditions["Direction"].SetFunctionName("getDirectionOrAngle"); spriteConditions["Sprite"].SetFunctionName("getAnimationFrame"); - spriteConditions["AnimationEnded"].SetFunctionName("hasAnimationEnded"); + spriteConditions["AnimationEnded"].SetFunctionName("hasAnimationEndedLegacy"); spriteConditions["AnimationEnded2"].SetFunctionName("hasAnimationEnded2"); spriteActions["PauseAnimation"].SetFunctionName("pauseAnimation"); spriteActions["PlayAnimation"].SetFunctionName("playAnimation"); @@ -64,7 +64,7 @@ SpriteExtension::SpriteExtension() { .SetGetter("getScaleY"); spriteActions["ChangeScale"] .SetFunctionName("setScale") - .SetGetter("getScale"); + .SetGetter("getScaleMean"); spriteConditions["ScaleWidth"].SetFunctionName("getScaleX"); spriteConditions["ScaleHeight"].SetFunctionName("getScaleY"); spriteActions["ChangeWidth"] @@ -105,14 +105,8 @@ SpriteExtension::SpriteExtension() { "getDirectionOrAngle"); // Deprecated spriteExpressions["Direction"].SetFunctionName("getDirectionOrAngle"); spriteExpressions["Anim"].SetFunctionName("getAnimation"); // Deprecated - spriteExpressions["Animation"].SetFunctionName("getAnimation"); - spriteStrExpressions["AnimationName"].SetFunctionName("getAnimationName"); spriteExpressions["Sprite"].SetFunctionName("getAnimationFrame"); spriteExpressions["AnimationFrameCount"].SetFunctionName("getAnimationFrameCount"); - spriteExpressions["AnimationSpeedScale"].SetFunctionName( - "getAnimationSpeedScale"); - spriteExpressions["ScaleX"].SetFunctionName("getScaleX"); - spriteExpressions["ScaleY"].SetFunctionName("getScaleY"); spriteExpressions["Opacity"].SetFunctionName("getOpacity"); } diff --git a/GDJS/GDJS/Extensions/JsPlatform.cpp b/GDJS/GDJS/Extensions/JsPlatform.cpp index 10ef2316d1..85e27b0543 100644 --- a/GDJS/GDJS/Extensions/JsPlatform.cpp +++ b/GDJS/GDJS/Extensions/JsPlatform.cpp @@ -31,6 +31,12 @@ #include "GDJS/Extensions/Builtin/TimeExtension.h" #include "GDJS/Extensions/Builtin/VariablesExtension.h" #include "GDJS/Extensions/Builtin/WindowExtension.h" +#include "GDJS/Extensions/Builtin/Capacities/AnimatableExtension.h" +#include "GDJS/Extensions/Builtin/Capacities/EffectExtension.h" +#include "GDJS/Extensions/Builtin/Capacities/FlippableExtension.h" +#include "GDJS/Extensions/Builtin/Capacities/ResizableExtension.h" +#include "GDJS/Extensions/Builtin/Capacities/ScalableExtension.h" +#include "GDJS/Extensions/Builtin/Capacities/OpacityExtension.h" namespace gdjs { @@ -107,6 +113,24 @@ void JsPlatform::ReloadBuiltinExtensions() { AddExtension( std::shared_ptr(new ExternalLayoutsExtension)); std::cout.flush(); + AddExtension( + std::shared_ptr(new AnimatableExtension)); + std::cout.flush(); + AddExtension( + std::shared_ptr(new EffectExtension)); + std::cout.flush(); + AddExtension( + std::shared_ptr(new FlippableExtension)); + std::cout.flush(); + AddExtension( + std::shared_ptr(new ResizableExtension)); + std::cout.flush(); + AddExtension( + std::shared_ptr(new ScalableExtension)); + std::cout.flush(); + AddExtension( + std::shared_ptr(new OpacityExtension)); + std::cout.flush(); std::cout << "done." << std::endl; #if defined(EMSCRIPTEN) // When compiling with emscripten, hardcode extensions diff --git a/GDJS/Runtime/CustomRuntimeObject.ts b/GDJS/Runtime/CustomRuntimeObject.ts index 48a07799cc..2f44667db4 100644 --- a/GDJS/Runtime/CustomRuntimeObject.ts +++ b/GDJS/Runtime/CustomRuntimeObject.ts @@ -19,7 +19,13 @@ namespace gdjs { * * @see gdjs.CustomRuntimeObjectInstanceContainer */ - export class CustomRuntimeObject extends gdjs.RuntimeObject { + export class CustomRuntimeObject + extends gdjs.RuntimeObject + implements + gdjs.Resizable, + gdjs.Scalable, + gdjs.Flippable, + gdjs.OpacityHandler { /** It contains the children of this object. */ _instanceContainer: gdjs.CustomRuntimeObjectInstanceContainer; _isUntransformedHitBoxesDirty: boolean = true; @@ -496,7 +502,7 @@ namespace gdjs { * * @param newScale The new scale (must be greater than 0). */ - setScale(newScale: number): void { + setScale(newScale: float): void { if (newScale < 0) { newScale = 0; } @@ -518,7 +524,7 @@ namespace gdjs { * * @param newScale The new scale (must be greater than 0). */ - setScaleX(newScale: number): void { + setScaleX(newScale: float): void { if (newScale < 0) { newScale = 0; } @@ -536,7 +542,7 @@ namespace gdjs { * * @param newScale The new scale (must be greater than 0). */ - setScaleY(newScale: number): void { + setScaleY(newScale: float): void { if (newScale < 0) { newScale = 0; } @@ -549,16 +555,26 @@ namespace gdjs { } /** - * Get the scale of the object (or the average of the X and Y scale in case - * they are different). + * Get the scale of the object (or the arithmetic mean of the X and Y scale in case they are different). * - * @return the scale of the object (or the average of the X and Y scale in - * case they are different). + * @return the scale of the object (or the arithmetic mean of the X and Y scale in case they are different). + * @deprecated Use `getScale` instead. */ - getScale(): number { + getScaleMean(): float { return (Math.abs(this._scaleX) + Math.abs(this._scaleY)) / 2.0; } + /** + * Get the scale of the object (or the geometric mean of the X and Y scale in case they are different). + * + * @return the scale of the object (or the geometric mean of the X and Y scale in case they are different). + */ + getScale(): float { + const scaleX = Math.abs(this._scaleX); + const scaleY = Math.abs(this._scaleY); + return scaleX === scaleY ? scaleX : Math.sqrt(scaleX * scaleY); + } + /** * Get the scale of the object on Y axis. * @@ -578,10 +594,7 @@ namespace gdjs { } // Visibility and display : - /** - * Change the transparency of the object. - * @param opacity The new opacity, between 0 (transparent) and 255 (opaque). - */ + setOpacity(opacity: float): void { if (opacity < 0) { opacity = 0; @@ -593,10 +606,6 @@ namespace gdjs { this.getRenderer().updateOpacity(); } - /** - * Get the transparency of the object. - * @return The opacity, between 0 (transparent) and 255 (opaque). - */ getOpacity(): number { return this.opacity; } diff --git a/GDJS/Runtime/object-capabilities/AnimatableBehavior.ts b/GDJS/Runtime/object-capabilities/AnimatableBehavior.ts new file mode 100644 index 0000000000..80a1889463 --- /dev/null +++ b/GDJS/Runtime/object-capabilities/AnimatableBehavior.ts @@ -0,0 +1,133 @@ +/* + * GDevelop JS Platform + * Copyright 2013-2023 Florian Rival (Florian.Rival@gmail.com). All rights reserved. + * This project is released under the MIT License. + */ +namespace gdjs { + export interface Animatable { + /** + * Get the index of the animation being played. + * @return The index of the new animation being played + */ + getAnimationIndex(): integer; + + /** + * Change the animation being played. + * @param animationIndex The index of the new animation to be played + */ + setAnimationIndex(animationIndex: integer): void; + + /** + * Get the name of the animation being played. + * @return The name of the new animation being played + */ + getAnimationName(): string; + + /** + * Change the animation being played. + * @param newAnimationName The name of the new animation to be played + */ + setAnimationName(newAnimationName: string): void; + + isCurrentAnimationName(name: string): boolean; + + /** + * Return true if animation has ended. + * The animation had ended if: + * - it's not configured as a loop; + * - the current frame is the last frame; + * - the last frame has been displayed long enough. + */ + hasAnimationEnded(): boolean; + + isAnimationPaused(): boolean; + + pauseAnimation(): void; + + resumeAnimation(): void; + + getAnimationSpeedScale(): float; + + setAnimationSpeedScale(ratio: float): void; + } + + /** + * A behavior that forwards the Animatable interface to its object. + */ + export class AnimatableBehavior + extends gdjs.RuntimeBehavior + implements Animatable { + private object: gdjs.RuntimeObject & Animatable; + + constructor( + instanceContainer: gdjs.RuntimeInstanceContainer, + behaviorData, + owner: gdjs.RuntimeObject & Animatable + ) { + super(instanceContainer, behaviorData, owner); + this.object = owner; + } + + updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean { + // Nothing to update. + return true; + } + + onDeActivate() {} + + onDestroy() {} + + doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {} + + doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {} + + getAnimationIndex(): integer { + return this.object.getAnimationIndex(); + } + + setAnimationIndex(animationIndex: integer): void { + this.object.setAnimationIndex(animationIndex); + } + + getAnimationName(): string { + return this.object.getAnimationName(); + } + + setAnimationName(newAnimationName: string): void { + this.object.setAnimationName(newAnimationName); + } + + isCurrentAnimationName(name: string): boolean { + return this.object.isCurrentAnimationName(name); + } + + hasAnimationEnded(): boolean { + return this.object.hasAnimationEnded(); + } + + isAnimationPaused(): boolean { + return this.object.isAnimationPaused(); + } + + pauseAnimation(): void { + this.object.pauseAnimation(); + } + + resumeAnimation(): void { + this.object.resumeAnimation(); + } + + getAnimationSpeedScale(): float { + return this.object.getAnimationSpeedScale(); + } + + setAnimationSpeedScale(ratio: float): void { + this.object.setAnimationSpeedScale(ratio); + } + } + + gdjs.registerBehavior( + 'AnimatableCapability::AnimatableBehavior', + gdjs.AnimatableBehavior + ); +} diff --git a/GDJS/Runtime/object-capabilities/EffectBehavior.ts b/GDJS/Runtime/object-capabilities/EffectBehavior.ts new file mode 100644 index 0000000000..7a8c4ea499 --- /dev/null +++ b/GDJS/Runtime/object-capabilities/EffectBehavior.ts @@ -0,0 +1,126 @@ +/* + * GDevelop JS Platform + * Copyright 2013-2023 Florian Rival (Florian.Rival@gmail.com). All rights reserved. + * This project is released under the MIT License. + */ +namespace gdjs { + export interface EffectHandler { + /** + * Change an effect parameter value (for parameters that are numbers). + * @param name The name of the effect to update. + * @param parameterName The name of the parameter to update. + * @param value The new value (number). + */ + setEffectDoubleParameter( + name: string, + parameterName: string, + value: float + ): boolean; + + /** + * Change an effect parameter value (for parameters that are strings). + * @param name The name of the effect to update. + * @param parameterName The name of the parameter to update. + * @param value The new value (string). + */ + setEffectStringParameter( + name: string, + parameterName: string, + value: string + ): boolean; + + /** + * Change an effect parameter value (for parameters that are booleans). + * @param name The name of the effect to update. + * @param parameterName The name of the parameter to update. + * @param value The new value (boolean). + */ + setEffectBooleanParameter( + name: string, + parameterName: string, + value: boolean + ): boolean; + + /** + * Enable or disable an effect. + * @param name The name of the effect to enable or disable. + * @param enable true to enable, false to disable + */ + enableEffect(name: string, enable: boolean): void; + + /** + * Check if an effect is enabled + * @param name The name of the effect + * @return true if the effect is enabled, false otherwise. + */ + isEffectEnabled(name: string): boolean; + } + + /** + * A behavior that forwards the EffectBehavior interface to its object. + */ + export class EffectBehavior + extends gdjs.RuntimeBehavior + implements EffectHandler { + private object: gdjs.RuntimeObject & EffectHandler; + + constructor( + instanceContainer: gdjs.RuntimeInstanceContainer, + behaviorData, + owner: gdjs.RuntimeObject & EffectHandler + ) { + super(instanceContainer, behaviorData, owner); + this.object = owner; + } + + updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean { + // Nothing to update. + return true; + } + + onDeActivate() {} + + onDestroy() {} + + doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {} + + doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {} + + setEffectDoubleParameter( + name: string, + parameterName: string, + value: float + ): boolean { + return this.object.setEffectDoubleParameter(name, parameterName, value); + } + + setEffectStringParameter( + name: string, + parameterName: string, + value: string + ): boolean { + return this.object.setEffectStringParameter(name, parameterName, value); + } + + setEffectBooleanParameter( + name: string, + parameterName: string, + value: boolean + ): boolean { + return this.object.setEffectBooleanParameter(name, parameterName, value); + } + + enableEffect(name: string, enable: boolean): void { + this.object.enableEffect(name, enable); + } + + isEffectEnabled(name: string): boolean { + return this.object.isEffectEnabled(name); + } + } + + gdjs.registerBehavior( + 'EffectCapability::EffectBehavior', + gdjs.EffectBehavior + ); +} diff --git a/GDJS/Runtime/object-capabilities/FlippableBehavior.ts b/GDJS/Runtime/object-capabilities/FlippableBehavior.ts new file mode 100644 index 0000000000..0c460ec024 --- /dev/null +++ b/GDJS/Runtime/object-capabilities/FlippableBehavior.ts @@ -0,0 +1,68 @@ +/* + * GDevelop JS Platform + * Copyright 2013-2023 Florian Rival (Florian.Rival@gmail.com). All rights reserved. + * This project is released under the MIT License. + */ +namespace gdjs { + export interface Flippable { + flipX(enable: boolean): void; + + flipY(enable: boolean): void; + + isFlippedX(): boolean; + + isFlippedY(): boolean; + } + + /** + * A behavior that forwards the Flippable interface to its object. + */ + export class FlippableBehavior + extends gdjs.RuntimeBehavior + implements Flippable { + private object: gdjs.RuntimeObject & Flippable; + + constructor( + instanceContainer: gdjs.RuntimeInstanceContainer, + behaviorData, + owner: gdjs.RuntimeObject & Flippable + ) { + super(instanceContainer, behaviorData, owner); + this.object = owner; + } + + updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean { + // Nothing to update. + return true; + } + + onDeActivate() {} + + onDestroy() {} + + doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {} + + doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {} + + flipX(enable: boolean): void { + this.object.flipX(enable); + } + + flipY(enable: boolean): void { + this.object.flipY(enable); + } + + isFlippedX(): boolean { + return this.object.isFlippedX(); + } + + isFlippedY(): boolean { + return this.object.isFlippedY(); + } + } + + gdjs.registerBehavior( + 'FlippableCapability::FlippableBehavior', + gdjs.FlippableBehavior + ); +} diff --git a/GDJS/Runtime/object-capabilities/OpacityBehavior.ts b/GDJS/Runtime/object-capabilities/OpacityBehavior.ts new file mode 100644 index 0000000000..b24edf5c14 --- /dev/null +++ b/GDJS/Runtime/object-capabilities/OpacityBehavior.ts @@ -0,0 +1,64 @@ +/* + * GDevelop JS Platform + * Copyright 2013-2023 Florian Rival (Florian.Rival@gmail.com). All rights reserved. + * This project is released under the MIT License. + */ +namespace gdjs { + export interface OpacityHandler { + /** + * Change the transparency of the object. + * @param opacity The new opacity, between 0 (transparent) and 255 (opaque). + */ + setOpacity(opacity: float): void; + + /** + * Get the transparency of the object. + * @return The opacity, between 0 (transparent) and 255 (opaque). + */ + getOpacity(): float; + } + + /** + * A behavior that forwards the Opacity interface to its object. + */ + export class OpacityBehavior + extends gdjs.RuntimeBehavior + implements OpacityHandler { + private object: gdjs.RuntimeObject & OpacityHandler; + + constructor( + instanceContainer: gdjs.RuntimeInstanceContainer, + behaviorData, + owner: gdjs.RuntimeObject & OpacityHandler + ) { + super(instanceContainer, behaviorData, owner); + this.object = owner; + } + + updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean { + // Nothing to update. + return true; + } + + onDeActivate() {} + + onDestroy() {} + + doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {} + + doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {} + + setOpacity(opacity: float): void { + this.object.setOpacity(opacity); + } + + getOpacity(): float { + return this.object.getOpacity(); + } + } + + gdjs.registerBehavior( + 'OpacityCapability::OpacityBehavior', + gdjs.OpacityBehavior + ); +} diff --git a/GDJS/Runtime/object-capabilities/ResizableBehavior.ts b/GDJS/Runtime/object-capabilities/ResizableBehavior.ts new file mode 100644 index 0000000000..04d3a60735 --- /dev/null +++ b/GDJS/Runtime/object-capabilities/ResizableBehavior.ts @@ -0,0 +1,98 @@ +/* + * GDevelop JS Platform + * Copyright 2013-2023 Florian Rival (Florian.Rival@gmail.com). All rights reserved. + * This project is released under the MIT License. + */ +namespace gdjs { + export interface Resizable { + /** + * Change the width of the object. This changes the scale on X axis of the object. + * + * @param newWidth The new width of the object, in pixels. + */ + setWidth(newWidth: float): void; + + /** + * Change the height of the object. This changes the scale on Y axis of the object. + * + * @param newHeight The new height of the object, in pixels. + */ + setHeight(newHeight: float): void; + + /** + * Change the size of the object. + * + * @param newWidth The new width of the object, in pixels. + * @param newHeight The new height of the object, in pixels. + */ + setSize(newWidth: float, newHeight: float): void; + + /** + * Return the width of the object. + * @return The width of the object + */ + getWidth(): float; + + /** + * Return the width of the object. + * @return The height of the object + */ + getHeight(): float; + } + + /** + * A behavior that forwards the Resizable interface to its object. + */ + export class ResizableBehavior + extends gdjs.RuntimeBehavior + implements Resizable { + private object: gdjs.RuntimeObject & Resizable; + + constructor( + instanceContainer: gdjs.RuntimeInstanceContainer, + behaviorData, + owner: gdjs.RuntimeObject & Resizable + ) { + super(instanceContainer, behaviorData, owner); + this.object = owner; + } + + updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean { + // Nothing to update. + return true; + } + + onDeActivate() {} + + onDestroy() {} + + doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {} + + doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {} + + setWidth(newWidth: float): void { + this.object.setWidth(newWidth); + } + + setHeight(newHeight: float): void { + this.object.setHeight(newHeight); + } + + setSize(newWidth: float, newHeight: float): void { + this.object.setSize(newWidth, newHeight); + } + + getWidth(): float { + return this.object.getWidth(); + } + + getHeight(): float { + return this.object.getHeight(); + } + } + + gdjs.registerBehavior( + 'ResizableCapability::ResizableBehavior', + gdjs.ResizableBehavior + ); +} diff --git a/GDJS/Runtime/object-capabilities/ScalableBehavior.ts b/GDJS/Runtime/object-capabilities/ScalableBehavior.ts new file mode 100644 index 0000000000..79e0462bcd --- /dev/null +++ b/GDJS/Runtime/object-capabilities/ScalableBehavior.ts @@ -0,0 +1,112 @@ +/* + * GDevelop JS Platform + * Copyright 2013-2023 Florian Rival (Florian.Rival@gmail.com). All rights reserved. + * This project is released under the MIT License. + */ +namespace gdjs { + export interface Scalable { + /** + * Change the scale on X and Y axis of the object. + * + * @param newScale The new scale (must be greater than 0). + */ + setScale(newScale: float): void; + + /** + * Change the scale on X axis of the object (changing its width). + * + * @param newScale The new scale (must be greater than 0). + */ + setScaleX(newScale: float): void; + + /** + * Change the scale on Y axis of the object (changing its height). + * + * @param newScale The new scale (must be greater than 0). + */ + setScaleY(newScale: float): void; + + /** + * Get the scale of the object (or the geometric mean of the X and Y scale + * in case they are different). + * + * @return the scale of the object (or the geometric mean of the X and + * Y scale in case they are different). + */ + getScale(): float; + + /** + * Get the scale of the object on Y axis. + * + * @return the scale of the object on Y axis + */ + getScaleY(): float; + + /** + * Get the scale of the object on X axis. + * + * @return the scale of the object on X axis + */ + getScaleX(): float; + } + + /** + * A behavior that forwards the Scalable interface to its object. + */ + export class ScalableBehavior + extends gdjs.RuntimeBehavior + implements Scalable { + private object: gdjs.RuntimeObject & Scalable; + + constructor( + instanceContainer: gdjs.RuntimeInstanceContainer, + behaviorData, + owner: gdjs.RuntimeObject & Scalable + ) { + super(instanceContainer, behaviorData, owner); + this.object = owner; + } + + updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean { + // Nothing to update. + return true; + } + + onDeActivate() {} + + onDestroy() {} + + doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {} + + doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {} + + setScale(newScale: float): void { + this.object.setScale(newScale); + } + + setScaleX(newScale: float): void { + this.object.setScaleX(newScale); + } + + setScaleY(newScale: float): void { + this.object.setScaleY(newScale); + } + + getScale(): float { + return this.object.getScale(); + } + + getScaleY(): float { + return this.object.getScaleY(); + } + + getScaleX(): float { + return this.object.getScaleX(); + } + } + + gdjs.registerBehavior( + 'ScalableCapability::ScalableBehavior', + gdjs.ScalableBehavior + ); +} diff --git a/GDJS/Runtime/runtimeobject.ts b/GDJS/Runtime/runtimeobject.ts index 6e09aadb5e..a083900256 100644 --- a/GDJS/Runtime/runtimeobject.ts +++ b/GDJS/Runtime/runtimeobject.ts @@ -153,7 +153,7 @@ namespace gdjs { * A `gdjs.RuntimeObject` should not be instantiated directly, always a child class * (because gdjs.RuntimeObject don't call onCreated at the end of its constructor). */ - export class RuntimeObject implements EffectsTarget { + export class RuntimeObject implements EffectsTarget, gdjs.EffectHandler { name: string; type: string; x: float = 0; @@ -236,7 +236,6 @@ namespace gdjs { .initializeEffect(objectData.effects[i], this._rendererEffects, this); this.updateAllEffectParameters(objectData.effects[i]); } - //Also contains the behaviors: Used when a behavior is accessed by its name ( see getBehavior ). for (let i = 0, len = objectData.behaviors.length; i < len; ++i) { const autoData = objectData.behaviors[i]; diff --git a/GDJS/Runtime/spriteruntimeobject.ts b/GDJS/Runtime/spriteruntimeobject.ts index 88a577d6ad..184a09c03a 100644 --- a/GDJS/Runtime/spriteruntimeobject.ts +++ b/GDJS/Runtime/spriteruntimeobject.ts @@ -288,7 +288,14 @@ namespace gdjs { /** * The SpriteRuntimeObject represents an object that can display images. */ - export class SpriteRuntimeObject extends gdjs.RuntimeObject { + export class SpriteRuntimeObject + extends gdjs.RuntimeObject + implements + gdjs.Resizable, + gdjs.Scalable, + gdjs.Flippable, + gdjs.Animatable, + gdjs.OpacityHandler { _currentAnimation: number = 0; _currentDirection: number = 0; _currentFrame: number = 0; @@ -416,7 +423,7 @@ namespace gdjs { //Make sure to delete already existing animations which are not used anymore. this._updateAnimationFrame(); if (!this._animationFrame) { - this.setAnimation(0); + this.setAnimationIndex(0); } this.invalidateHitboxes(); return true; @@ -435,7 +442,7 @@ namespace gdjs { ) { const extraData = initialInstanceData.numberProperties[i]; if (extraData.name === 'animation') { - this.setAnimation(extraData.value); + this.setAnimationIndex(extraData.value); } } } @@ -614,8 +621,13 @@ namespace gdjs { /** * Change the animation being played. * @param newAnimation The index of the new animation to be played + * @deprecated Use `setAnimationIndex` instead */ setAnimation(newAnimation: number): void { + this.setAnimationIndex(newAnimation); + } + + setAnimationIndex(newAnimation: number): void { newAnimation = newAnimation | 0; if ( newAnimation < this._animations.length && @@ -633,17 +645,14 @@ namespace gdjs { } } - /** - * Change the animation being played. - * @param newAnimationName The name of the new animation to be played - */ setAnimationName(newAnimationName: string): void { if (!newAnimationName) { return; } for (let i = 0; i < this._animations.length; ++i) { if (this._animations[i].name === newAnimationName) { - return this.setAnimation(i); + this.setAnimationIndex(i); + return; } } } @@ -651,15 +660,16 @@ namespace gdjs { /** * Get the index of the animation being played. * @return The index of the new animation being played + * @deprecated Use `getAnimationIndex` instead */ getAnimation(): number { + return this.getAnimationIndex(); + } + + getAnimationIndex(): number { return this._currentAnimation; } - /** - * Get the name of the animation being played. - * @return The name of the new animation being played - */ getAnimationName(): string { if (this._currentAnimation >= this._animations.length) { return ''; @@ -667,7 +677,7 @@ namespace gdjs { return this._animations[this._currentAnimation].name; } - isCurrentAnimationName(name): boolean { + isCurrentAnimationName(name: string): boolean { return this.getAnimationName() === name; } @@ -768,10 +778,10 @@ namespace gdjs { /** * @deprecated * Return true if animation has ended. - * Prefer using hasAnimationEnded2. This method returns true as soon as + * Prefer using `hasAnimationEnded2`. This method returns true as soon as * the animation enters the last frame, not at the end of the last frame. */ - hasAnimationEnded(): boolean { + hasAnimationEndedLegacy(): boolean { if ( this._currentAnimation >= this._animations.length || this._currentDirection >= @@ -794,8 +804,14 @@ namespace gdjs { * - it's not configured as a loop; * - the current frame is the last frame; * - the last frame has been displayed long enough. + * + * @deprecated Use `hasAnimationEnded` instead. */ hasAnimationEnded2(): boolean { + return this.hasAnimationEnded(); + } + + hasAnimationEnded(): boolean { if ( this._currentAnimation >= this._animations.length || this._currentDirection >= @@ -815,15 +831,29 @@ namespace gdjs { ); } - animationPaused() { + /** + * @deprecated Use `isAnimationPaused` instead. + */ + animationPaused(): boolean { + return this.isAnimationPaused(); + } + + isAnimationPaused(): boolean { return this._animationPaused; } - pauseAnimation() { + pauseAnimation(): void { this._animationPaused = true; } - playAnimation() { + /** + * @deprecated Use `resumeAnimation` instead. + */ + playAnimation(): void { + this.resumeAnimation(); + } + + resumeAnimation(): void { this._animationPaused = false; } @@ -831,7 +861,7 @@ namespace gdjs { return this._animationSpeedScale; } - setAnimationSpeedScale(ratio): void { + setAnimationSpeedScale(ratio: float): void { this._animationSpeedScale = ratio; } @@ -1115,10 +1145,6 @@ namespace gdjs { return this._blendMode; } - /** - * Change the transparency of the object. - * @param opacity The new opacity, between 0 (transparent) and 255 (opaque). - */ setOpacity(opacity: float): void { if (opacity < 0) { opacity = 0; @@ -1130,10 +1156,6 @@ namespace gdjs { this._renderer.updateOpacity(); } - /** - * Get the transparency of the object. - * @return The opacity, between 0 (transparent) and 255 (opaque). - */ getOpacity(): number { return this.opacity; } @@ -1219,11 +1241,6 @@ namespace gdjs { return this._renderer.getHeight(); } - /** - * Change the width of the object. This changes the scale on X axis of the object. - * - * @param newWidth The new width of the object, in pixels. - */ setWidth(newWidth: float): void { if (this._animationFrameDirty) { this._updateAnimationFrame(); @@ -1234,11 +1251,6 @@ namespace gdjs { } } - /** - * Change the height of the object. This changes the scale on Y axis of the object. - * - * @param newHeight The new height of the object, in pixels. - */ setHeight(newHeight: float): void { if (this._animationFrameDirty) { this._updateAnimationFrame(); @@ -1249,12 +1261,6 @@ namespace gdjs { } } - /** - * Change the size of the object. - * - * @param newWidth The new width of the object, in pixels. - * @param newHeight The new height of the object, in pixels. - */ setSize(newWidth: float, newHeight: float): void { this.setWidth(newWidth); this.setHeight(newHeight); @@ -1265,7 +1271,7 @@ namespace gdjs { * * @param newScale The new scale (must be greater than 0). */ - setScale(newScale: number): void { + setScale(newScale: float): void { if (newScale < 0) { newScale = 0; } @@ -1286,7 +1292,7 @@ namespace gdjs { * * @param newScale The new scale (must be greater than 0). */ - setScaleX(newScale: number): void { + setScaleX(newScale: float): void { if (newScale < 0) { newScale = 0; } @@ -1303,7 +1309,7 @@ namespace gdjs { * * @param newScale The new scale (must be greater than 0). */ - setScaleY(newScale: number): void { + setScaleY(newScale: float): void { if (newScale < 0) { newScale = 0; } @@ -1316,14 +1322,26 @@ namespace gdjs { } /** - * Get the scale of the object (or the average of the X and Y scale in case they are different). + * Get the scale of the object (or the arithmetic mean of the X and Y scale in case they are different). * - * @return the scale of the object (or the average of the X and Y scale in case they are different). + * @return the scale of the object (or the arithmetic mean of the X and Y scale in case they are different). + * @deprecated Use `getScale` instead. */ - getScale(): number { + getScaleMean(): float { return (Math.abs(this._scaleX) + Math.abs(this._scaleY)) / 2.0; } + /** + * Get the scale of the object (or the geometric mean of the X and Y scale in case they are different). + * + * @return the scale of the object (or the geometric mean of the X and Y scale in case they are different). + */ + getScale(): float { + const scaleX = Math.abs(this._scaleX); + const scaleY = Math.abs(this._scaleY); + return scaleX === scaleY ? scaleX : Math.sqrt(scaleX * scaleY); + } + /** * Get the scale of the object on Y axis. * diff --git a/GDevelop.js/Bindings/Bindings.idl b/GDevelop.js/Bindings/Bindings.idl index 9e0a9db9e3..c4a0037f0e 100644 --- a/GDevelop.js/Bindings/Bindings.idl +++ b/GDevelop.js/Bindings/Bindings.idl @@ -527,7 +527,9 @@ interface Project { [Const, Value] DOMString FREE_GetTypeOfBehavior([Const, Ref] Layout layout, [Const] DOMString name, boolean searchInGroups); [Const, Value] DOMString FREE_GetTypeOfObject([Const, Ref] Layout layout, [Const] DOMString name, boolean searchInGroups); [Value] VectorString FREE_GetBehaviorsOfObject([Const, Ref] Layout layout, [Const] DOMString name, boolean searchInGroups); + boolean FREE_IsDefaultBehavior([Const, Ref] Layout layout, [Const] DOMString objectOrGroupName, [Const] DOMString behaviorName, boolean searchInGroups); [Const, Value] DOMString FREE_GetTypeOfBehaviorInObjectOrGroup([Const, Ref] Layout layout, [Const] DOMString objectOrGroupName, [Const] DOMString behaviorName, boolean searchInGroups); + [Value] VectorString FREE_GetBehaviorNamesInObjectOrGroup([Const, Ref] Layout layout, [Const] DOMString objectOrGroupName, [Const] DOMString behaviorType, boolean searchInGroups); //Inherited from gd::ObjectsContainer [Ref] gdObject InsertNewObject([Ref] Project project, [Const] DOMString type, [Const] DOMString name, unsigned long pos); @@ -570,6 +572,8 @@ interface Behavior { void SerializeTo([Ref] SerializerElement element); void UnserializeFrom([Const, Ref] SerializerElement element); + + boolean IsDefaultBehavior(); }; [JSImplementation=Behavior] @@ -1346,9 +1350,6 @@ interface InstructionMetadata { [Ref] InstructionMetadata UseStandardOperatorParameters([Const] DOMString type, [Const, Ref] ParameterOptions options); [Ref] InstructionMetadata UseStandardRelationalOperatorParameters([Const] DOMString type, [Const, Ref] ParameterOptions options); - [Ref] InstructionMetadata SetRequiresBaseObjectCapability([Const] DOMString capability); - [Const, Ref] DOMString GetRequiredBaseObjectCapability(); - [Ref] InstructionMetadata MarkAsSimple(); [Ref] InstructionMetadata MarkAsAdvanced(); [Ref] InstructionMetadata MarkAsComplex(); @@ -1411,9 +1412,6 @@ interface ExpressionMetadata { [Ref] ExpressionMetadata SetParameterLongDescription([Const] DOMString longDescription); [Ref] ExpressionMetadata SetParameterExtraInfo([Const] DOMString extraInfo); - [Ref] ExpressionMetadata SetRequiresBaseObjectCapability([Const] DOMString capability); - [Const, Ref] DOMString GetRequiredBaseObjectCapability(); - [Ref] ExpressionMetadata GetCodeExtraInformation(); [Ref] ExpressionMetadata SetFunctionName([Const] DOMString functionName); @@ -1639,9 +1637,9 @@ interface ObjectMetadata { [Ref] ObjectMetadata SetIncludeFile([Const] DOMString includeFile); [Ref] ObjectMetadata AddIncludeFile([Const] DOMString includeFile); - [Const, Ref] SetString GetUnsupportedBaseObjectCapabilities(); - [Ref] ObjectMetadata AddUnsupportedBaseObjectCapability([Const] DOMString capability); - boolean IsUnsupportedBaseObjectCapability([Const] DOMString capability); + [Const, Ref] SetString GetDefaultBehaviors(); + boolean HasDefaultBehavior([Const] DOMString behaviorType); + [Ref] ObjectMetadata AddDefaultBehavior([Const] DOMString behaviorType); [Ref] ObjectMetadata SetHidden(); boolean IsHidden(); @@ -1744,10 +1742,14 @@ interface BehaviorMetadata { [Ref] BehaviorMetadata SetObjectType([Const] DOMString objectType); [Const, Ref] DOMString GetObjectType(); + [Const, Ref] VectorString GetRequiredBehaviorTypes(); boolean IsPrivate(); [Ref] BehaviorMetadata SetPrivate(); + boolean IsHidden(); + [Ref] BehaviorMetadata SetHidden(); + [Ref] Behavior Get(); BehaviorsSharedData GetSharedDataInstance(); }; diff --git a/GDevelop.js/CMakeLists.txt b/GDevelop.js/CMakeLists.txt index 70d3d148a1..23f53a7f01 100644 --- a/GDevelop.js/CMakeLists.txt +++ b/GDevelop.js/CMakeLists.txt @@ -13,7 +13,7 @@ endif() # Compilation flags (https://emscripten.org/docs/tools_reference/emcc.html): add_compile_options(-O2) # Optimizations during compilation -# add_compile_options(-g --profiling) # Uncomment for debugging + profiling support +#add_compile_options(-g --profiling) # Uncomment for debugging + profiling support # add_compile_options(--profiling) # Uncomment for profiling support # Common directories: diff --git a/GDevelop.js/TestUtils/TestExtensions.js b/GDevelop.js/TestUtils/TestExtensions.js index 18593cf17e..383f4e9df0 100644 --- a/GDevelop.js/TestUtils/TestExtensions.js +++ b/GDevelop.js/TestUtils/TestExtensions.js @@ -129,16 +129,6 @@ module.exports = { return instanceProperties; }; - const object = extension - .addObject( - 'FakeObjectWithUnsupportedCapability', - 'FakeObjectWithUnsupportedCapability', - 'This is FakeObjectWithUnsupportedCapability', - '', - fakeObject - ) - .addUnsupportedBaseObjectCapability('effect'); - platform.addNewExtension(extension); extension.delete(); // Release the extension as it was copied inside gd.JsPlatform }; diff --git a/GDevelop.js/__tests__/Core.js b/GDevelop.js/__tests__/Core.js index d84bcfcb65..d34e0aa05c 100644 --- a/GDevelop.js/__tests__/Core.js +++ b/GDevelop.js/__tests__/Core.js @@ -148,7 +148,15 @@ describe('libGD.js', function () { .getUsedExtensions() .toNewVectorString() .toJSArray() - ).toEqual(['Sprite']); + ).toEqual([ + 'AnimatableCapability', + 'EffectCapability', + 'FlippableCapability', + 'OpacityCapability', + 'ResizableCapability', + 'ScalableCapability', + 'Sprite', + ]); }); it('handles events functions extensions', function () { @@ -1819,6 +1827,8 @@ describe('libGD.js', function () { expect(object.getBehavior('Draggable')).toBe(behavior); }); + const spriteDefaultBehaviorCount = 6; + it('can have its behaviors retrieved with gd.getBehaviorsOfObject', function () { let behaviors = gd.getBehaviorsOfObject( project, @@ -1826,8 +1836,8 @@ describe('libGD.js', function () { 'TheObject', true ); - expect(behaviors.size()).toBe(1); - expect(behaviors.get(0)).toBe('Draggable'); + expect(behaviors.size()).toBe(1 + spriteDefaultBehaviorCount); + expect(behaviors.get(1)).toBe('Draggable'); }); it('can be un/serialized (basic)', function () { @@ -1840,8 +1850,8 @@ describe('libGD.js', function () { //Check that behaviors were persisted and restored let behaviors = object2.getAllBehaviorNames(); - expect(behaviors.size()).toBe(1); - expect(behaviors.at(0)).toBe('Draggable'); + expect(behaviors.size()).toBe(1 + spriteDefaultBehaviorCount); + expect(behaviors.at(1)).toBe('Draggable'); }); it('can be un/serialized (with behavior content)', function () { @@ -1857,8 +1867,8 @@ describe('libGD.js', function () { //Check that behaviors were persisted and restored let behaviors = object2.getAllBehaviorNames(); - expect(behaviors.size()).toBe(1); - expect(behaviors.at(0)).toBe('Draggable'); + expect(behaviors.size()).toBe(1 + spriteDefaultBehaviorCount); + expect(behaviors.at(1)).toBe('Draggable'); const behaviorContent2 = object2.getBehavior('Draggable'); expect(behaviorContent2.getProperties() diff --git a/GDevelop.js/__tests__/GDJS.js b/GDevelop.js/__tests__/GDJS.js index 8c0b55d96a..0cf23f863b 100644 --- a/GDevelop.js/__tests__/GDJS.js +++ b/GDevelop.js/__tests__/GDJS.js @@ -282,12 +282,10 @@ describe('libGD.js - GDJS related tests', function () { // Action for an object not having the required capability. const unsupportedCapabilityAction = new gd.Instruction(); - unsupportedCapabilityAction.setType('EnableEffect'); - unsupportedCapabilityAction.setParametersCount(3); - unsupportedCapabilityAction.setParameter( - 0, - 'MyFakeObjectWithUnsupportedCapability' - ); + unsupportedCapabilityAction.setType('EffectCapability::EffectBehavior::EnableEffect'); + unsupportedCapabilityAction.setParametersCount(4); + unsupportedCapabilityAction.setParameter(0, 'MyFakeObjectWithUnsupportedCapability'); + unsupportedCapabilityAction.setParameter(1, 'Effect'); unsupportedCapabilityAction.setParameter(1, '"MyEffect"'); unsupportedCapabilityAction.setParameter(2, 'yes'); gd.asStandardEvent(evt) @@ -316,8 +314,8 @@ describe('libGD.js - GDJS related tests', function () { expect(code).toMatch('/* Unknown instruction - skipped. */'); // Check that the action for an object not having the required capability was not generated. - expect(code).toMatch( - '/* Object with unsupported capability - skipped. */' + expect(code).toEqual(expect.not.stringContaining( + 'gdjs.SceneCode.GDMyFakeObjectWithUnsupportedCapabilityObjects1[i].getBehavior(\"Effect\")') ); action.delete(); @@ -350,11 +348,12 @@ describe('libGD.js - GDJS related tests', function () { // Action for an object not having the required capability. const unsupportedCapabilityAction = new gd.Instruction(); - unsupportedCapabilityAction.setType('EnableEffect'); - unsupportedCapabilityAction.setParametersCount(3); + unsupportedCapabilityAction.setType('EffectCapability::EffectBehavior::EnableEffect'); + unsupportedCapabilityAction.setParametersCount(4); unsupportedCapabilityAction.setParameter(0, 'MyGroup'); - unsupportedCapabilityAction.setParameter(1, '"MyEffect"'); - unsupportedCapabilityAction.setParameter(2, 'yes'); + unsupportedCapabilityAction.setParameter(1, 'Effect'); + unsupportedCapabilityAction.setParameter(2, '"MyEffect"'); + unsupportedCapabilityAction.setParameter(3, 'yes'); gd.asStandardEvent(evt) .getActions() .insert(unsupportedCapabilityAction, 1); @@ -378,10 +377,10 @@ describe('libGD.js - GDJS related tests', function () { // was not generated for this object, // but generated for the Sprite supporting this capability. expect(code).toMatch( - 'gdjs.SceneCode.GDMySpriteObjects1[i].enableEffect("MyEffect", true);' + 'gdjs.SceneCode.GDMySpriteObjects1[i].getBehavior(\"Effect\").enableEffect(\"MyEffect\", true);' ); - expect(code).toMatch( - '/* Object with unsupported capability - skipped. */' + expect(code).toEqual(expect.not.stringContaining( + 'gdjs.SceneCode.GDMyFakeObjectWithUnsupportedCapabilityObjects1[i].getBehavior(\"Effect\")') ); action.delete(); diff --git a/GDevelop.js/__tests__/MetadataDeclarationHelper.js b/GDevelop.js/__tests__/MetadataDeclarationHelper.js index 383e0aeaed..f9a3df2d9f 100644 --- a/GDevelop.js/__tests__/MetadataDeclarationHelper.js +++ b/GDevelop.js/__tests__/MetadataDeclarationHelper.js @@ -1356,7 +1356,7 @@ describe('MetadataDeclarationHelper', () => { expect(action.getParametersCount()).toBe(3); expect(action.getParameter(0).getType()).toBe('object'); - expect(action.getParameter(0).getExtraInfo()).toBe('MyObject'); + expect(action.getParameter(0).getValueTypeMetadata().getExtraInfo()).toBe('MyObject'); expect(action.getParameter(1).getType()).toBe('operator'); expect(action.getParameter(2).getType()).toBe('string'); @@ -1379,7 +1379,7 @@ describe('MetadataDeclarationHelper', () => { expect(condition.getParametersCount()).toBe(3); expect(condition.getParameter(0).getType()).toBe('object'); - expect(condition.getParameter(0).getExtraInfo()).toBe('MyObject'); + expect(condition.getParameter(0).getValueTypeMetadata().getExtraInfo()).toBe('MyObject'); expect(condition.getParameter(1).getType()).toBe('relationalOperator'); expect(condition.getParameter(2).getType()).toBe('string'); @@ -1397,7 +1397,7 @@ describe('MetadataDeclarationHelper', () => { expect(expression.getParametersCount()).toBe(1); expect(expression.getParameter(0).getType()).toBe('object'); - expect(expression.getParameter(0).getExtraInfo()).toBe('MyObject'); + expect(expression.getParameter(0).getValueTypeMetadata().getExtraInfo()).toBe('MyObject'); extension.delete(); project.delete(); @@ -1450,7 +1450,7 @@ describe('MetadataDeclarationHelper', () => { expect(action.getParametersCount()).toBe(2); expect(action.getParameter(0).getType()).toBe('object'); - expect(action.getParameter(0).getExtraInfo()).toBe('MyObject'); + expect(action.getParameter(0).getValueTypeMetadata().getExtraInfo()).toBe('MyObject'); expect(action.getParameter(1).getType()).toBe('yesorno'); expect( @@ -1471,7 +1471,7 @@ describe('MetadataDeclarationHelper', () => { expect(condition.getParametersCount()).toBe(1); expect(condition.getParameter(0).getType()).toBe('object'); - expect(condition.getParameter(0).getExtraInfo()).toBe('MyObject'); + expect(condition.getParameter(0).getValueTypeMetadata().getExtraInfo()).toBe('MyObject'); extension.delete(); project.delete(); diff --git a/GDevelop.js/scripts/generate-types.js b/GDevelop.js/scripts/generate-types.js index 47d45a6d14..4398465575 100644 --- a/GDevelop.js/scripts/generate-types.js +++ b/GDevelop.js/scripts/generate-types.js @@ -163,7 +163,9 @@ type ParticleEmitterObject_RendererType = 0 | 1 | 2` ' getTypeOfObject(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, searchInGroups: boolean): string;', ' getTypeOfBehavior(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, searchInGroups: boolean): string;', ' getBehaviorsOfObject(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, searchInGroups: boolean): gdVectorString;', + ' isDefaultBehavior(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, behaviorName: string, searchInGroups: boolean): boolean;', ' getTypeOfBehaviorInObjectOrGroup(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, behaviorName: string, searchInGroups: boolean): string;', + ' getBehaviorNamesInObjectOrGroup(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, behaviorName: string, searchInGroups: boolean): gdVectorString;', '', ' removeFromVectorParameterMetadata(gdVectorParameterMetadata, index: number): void;', ' swapInVectorParameterMetadata(gdVectorParameterMetadata, oldIndex: number, newIndex: number): void;', diff --git a/GDevelop.js/types/gdbehavior.js b/GDevelop.js/types/gdbehavior.js index 847c9d51eb..91d86e8626 100644 --- a/GDevelop.js/types/gdbehavior.js +++ b/GDevelop.js/types/gdbehavior.js @@ -10,6 +10,7 @@ declare class gdBehavior { initializeContent(): void; serializeTo(element: gdSerializerElement): void; unserializeFrom(element: gdSerializerElement): void; + isDefaultBehavior(): boolean; delete(): void; ptr: number; }; \ No newline at end of file diff --git a/GDevelop.js/types/gdbehaviormetadata.js b/GDevelop.js/types/gdbehaviormetadata.js index 21d773caae..2b203a3d16 100644 --- a/GDevelop.js/types/gdbehaviormetadata.js +++ b/GDevelop.js/types/gdbehaviormetadata.js @@ -28,8 +28,11 @@ declare class gdBehaviorMetadata { addRequiredFile(resourceFile: string): gdBehaviorMetadata; setObjectType(objectType: string): gdBehaviorMetadata; getObjectType(): string; + getRequiredBehaviorTypes(): gdVectorString; isPrivate(): boolean; setPrivate(): gdBehaviorMetadata; + isHidden(): boolean; + setHidden(): gdBehaviorMetadata; get(): gdBehavior; getSharedDataInstance(): gdBehaviorsSharedData; delete(): void; diff --git a/GDevelop.js/types/gdexpressionmetadata.js b/GDevelop.js/types/gdexpressionmetadata.js index e8b6dc0edc..a0a51639a0 100644 --- a/GDevelop.js/types/gdexpressionmetadata.js +++ b/GDevelop.js/types/gdexpressionmetadata.js @@ -27,8 +27,6 @@ declare class gdExpressionMetadata extends gdAbstractFunctionMetadata { setDefaultValue(defaultValue: string): gdExpressionMetadata; setParameterLongDescription(longDescription: string): gdExpressionMetadata; setParameterExtraInfo(extraInfo: string): gdExpressionMetadata; - setRequiresBaseObjectCapability(capability: string): gdExpressionMetadata; - getRequiredBaseObjectCapability(): string; getCodeExtraInformation(): gdExpressionMetadata; setFunctionName(functionName: string): gdExpressionMetadata; getFunctionName(): string; diff --git a/GDevelop.js/types/gdinstructionmetadata.js b/GDevelop.js/types/gdinstructionmetadata.js index a6451be8b6..c763050324 100644 --- a/GDevelop.js/types/gdinstructionmetadata.js +++ b/GDevelop.js/types/gdinstructionmetadata.js @@ -36,8 +36,6 @@ declare class gdInstructionMetadata extends gdAbstractFunctionMetadata { setParameterExtraInfo(extraInfo: string): gdInstructionMetadata; useStandardOperatorParameters(type: string, options: gdParameterOptions): gdInstructionMetadata; useStandardRelationalOperatorParameters(type: string, options: gdParameterOptions): gdInstructionMetadata; - setRequiresBaseObjectCapability(capability: string): gdInstructionMetadata; - getRequiredBaseObjectCapability(): string; markAsSimple(): gdInstructionMetadata; markAsAdvanced(): gdInstructionMetadata; markAsComplex(): gdInstructionMetadata; diff --git a/GDevelop.js/types/gdobjectmetadata.js b/GDevelop.js/types/gdobjectmetadata.js index 76f73e5def..3c89a14821 100644 --- a/GDevelop.js/types/gdobjectmetadata.js +++ b/GDevelop.js/types/gdobjectmetadata.js @@ -21,9 +21,9 @@ declare class gdObjectMetadata { getAllStrExpressions(): gdMapStringExpressionMetadata; setIncludeFile(includeFile: string): gdObjectMetadata; addIncludeFile(includeFile: string): gdObjectMetadata; - getUnsupportedBaseObjectCapabilities(): gdSetString; - addUnsupportedBaseObjectCapability(capability: string): gdObjectMetadata; - isUnsupportedBaseObjectCapability(capability: string): boolean; + getDefaultBehaviors(): gdSetString; + hasDefaultBehavior(behaviorType: string): boolean; + addDefaultBehavior(behaviorType: string): gdObjectMetadata; setHidden(): gdObjectMetadata; isHidden(): boolean; delete(): void; diff --git a/GDevelop.js/types/gdproject.js b/GDevelop.js/types/gdproject.js index 11cc2adbf0..8aac31b5aa 100644 --- a/GDevelop.js/types/gdproject.js +++ b/GDevelop.js/types/gdproject.js @@ -110,7 +110,9 @@ declare class gdProject extends gdObjectsContainer { getTypeOfBehavior(layout: gdLayout, name: string, searchInGroups: boolean): string; getTypeOfObject(layout: gdLayout, name: string, searchInGroups: boolean): string; getBehaviorsOfObject(layout: gdLayout, name: string, searchInGroups: boolean): gdVectorString; + isDefaultBehavior(layout: gdLayout, objectOrGroupName: string, behaviorName: string, searchInGroups: boolean): boolean; getTypeOfBehaviorInObjectOrGroup(layout: gdLayout, objectOrGroupName: string, behaviorName: string, searchInGroups: boolean): string; + getBehaviorNamesInObjectOrGroup(layout: gdLayout, objectOrGroupName: string, behaviorType: string, searchInGroups: boolean): gdVectorString; insertNewObject(project: gdProject, type: string, name: string, pos: number): gdObject; insertObject(obj: gdObject, pos: number): gdObject; hasObjectNamed(name: string): boolean; diff --git a/GDevelop.js/types/libgdevelop.js b/GDevelop.js/types/libgdevelop.js index 65a80a73a6..66c67768b4 100644 --- a/GDevelop.js/types/libgdevelop.js +++ b/GDevelop.js/types/libgdevelop.js @@ -7,7 +7,9 @@ declare class libGDevelop { getTypeOfObject(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, searchInGroups: boolean): string; getTypeOfBehavior(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, searchInGroups: boolean): string; getBehaviorsOfObject(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, searchInGroups: boolean): gdVectorString; + isDefaultBehavior(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, behaviorName: string, searchInGroups: boolean): boolean; getTypeOfBehaviorInObjectOrGroup(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, behaviorName: string, searchInGroups: boolean): string; + getBehaviorNamesInObjectOrGroup(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, behaviorName: string, searchInGroups: boolean): gdVectorString; removeFromVectorParameterMetadata(gdVectorParameterMetadata, index: number): void; swapInVectorParameterMetadata(gdVectorParameterMetadata, oldIndex: number, newIndex: number): void; diff --git a/newIDE/app/src/AssetStore/BehaviorStore/BehaviorListItem.js b/newIDE/app/src/AssetStore/BehaviorStore/BehaviorListItem.js index 87621e2b2b..298fc8f725 100644 --- a/newIDE/app/src/AssetStore/BehaviorStore/BehaviorListItem.js +++ b/newIDE/app/src/AssetStore/BehaviorStore/BehaviorListItem.js @@ -16,6 +16,8 @@ import Tooltip from '@material-ui/core/Tooltip'; import CircledInfo from '../../UI/CustomSvgIcons/SmallCircledInfo'; import IconButton from '../../UI/IconButton'; +const gd: libGDevelop = global.gd; + const styles = { button: { width: '100%' }, container: { @@ -35,6 +37,7 @@ type Props = {| onChoose: () => void, onShowDetails: () => void, onHeightComputed: number => void, + platform: gdPlatform, |}; export const BehaviorListItem = ({ @@ -46,12 +49,23 @@ export const BehaviorListItem = ({ onChoose, onShowDetails, onHeightComputed, + platform, }: Props) => { const alreadyAdded = objectBehaviorsTypes.includes(behaviorShortHeader.type); // An empty object type means the base object, i.e: any object. - const isObjectIncompatible = - behaviorShortHeader.objectType && - objectType !== behaviorShortHeader.objectType; + const isObjectCompatible = + (!behaviorShortHeader.objectType || + objectType === behaviorShortHeader.objectType) && + behaviorShortHeader.allRequiredBehaviorTypes.every(requiredBehaviorType => { + const behaviorMetadata = gd.MetadataProvider.getBehaviorMetadata( + platform, + requiredBehaviorType + ); + return ( + !behaviorMetadata.isHidden() || + objectBehaviorsTypes.includes(requiredBehaviorType) + ); + }); // Report the height of the item once it's known. const containerRef = React.useRef(null); @@ -75,7 +89,7 @@ export const BehaviorListItem = ({ ); }; - const isEnabled = !alreadyAdded && !isObjectIncompatible; + const isEnabled = !alreadyAdded && isObjectCompatible; const chooseBehavior = React.useCallback( () => { @@ -88,7 +102,7 @@ export const BehaviorListItem = ({ const hasChip = alreadyAdded || - isObjectIncompatible || + !isObjectCompatible || behaviorShortHeader.tier === 'community' || (behaviorShortHeader.isDeprecated || false); const hasInfoButton = behaviorShortHeader.authors || false; @@ -134,7 +148,7 @@ export const BehaviorListItem = ({ variant="outlined" /> )} - {isObjectIncompatible && ( + {!isObjectCompatible && ( Incompatible with the object} diff --git a/newIDE/app/src/AssetStore/BehaviorStore/BehaviorStoreContext.js b/newIDE/app/src/AssetStore/BehaviorStore/BehaviorStoreContext.js index aa817cdf03..99c4b060c4 100644 --- a/newIDE/app/src/AssetStore/BehaviorStore/BehaviorStoreContext.js +++ b/newIDE/app/src/AssetStore/BehaviorStore/BehaviorStoreContext.js @@ -25,6 +25,10 @@ export type SearchableBehaviorMetadata = {| fullName: string, description: string, objectType: string, + /** + * All required behaviors including transitive ones. + */ + allRequiredBehaviorTypes: Array, previewIconUrl: string, category: string, tags: string[], diff --git a/newIDE/app/src/AssetStore/BehaviorStore/index.js b/newIDE/app/src/AssetStore/BehaviorStore/index.js index f9b040cdb8..ff17569d43 100644 --- a/newIDE/app/src/AssetStore/BehaviorStore/index.js +++ b/newIDE/app/src/AssetStore/BehaviorStore/index.js @@ -268,6 +268,7 @@ export const BehaviorStore = ({ setSelectedBehaviorShortHeader(behaviorShortHeader); } }} + platform={project.getCurrentPlatform()} /> )} /> diff --git a/newIDE/app/src/BehaviorsEditor/NewBehaviorDialog.js b/newIDE/app/src/BehaviorsEditor/NewBehaviorDialog.js index dcd43c5fd8..275d5c002b 100644 --- a/newIDE/app/src/BehaviorsEditor/NewBehaviorDialog.js +++ b/newIDE/app/src/BehaviorsEditor/NewBehaviorDialog.js @@ -21,6 +21,7 @@ import { TRIVIAL_FIRST_BEHAVIOR, TRIVIAL_FIRST_EXTENSION, } from '../Utils/GDevelopServices/Badge'; +import { mapVector } from '../Utils/MapFor'; const gd: libGDevelop = global.gd; @@ -60,6 +61,33 @@ export default function NewBehaviorDialog({ [] ); + const getAllRequiredBehaviorTypes = React.useCallback( + ( + behaviorMetadata: gdBehaviorMetadata, + allRequiredBehaviorTypes: Array = [] + ): Array => { + mapVector( + behaviorMetadata.getRequiredBehaviorTypes(), + requiredBehaviorType => { + if (allRequiredBehaviorTypes.includes(requiredBehaviorType)) { + return; + } + allRequiredBehaviorTypes.push(requiredBehaviorType); + const requiredBehaviorMetadata = gd.MetadataProvider.getBehaviorMetadata( + project.getCurrentPlatform(), + requiredBehaviorType + ); + getAllRequiredBehaviorTypes( + requiredBehaviorMetadata, + allRequiredBehaviorTypes + ); + } + ); + return allRequiredBehaviorTypes; + }, + [project] + ); + const allInstalledBehaviorMetadataList: Array = React.useMemo( () => { const platform = project.getCurrentPlatform(); @@ -71,17 +99,22 @@ export default function NewBehaviorDialog({ eventsFunctionsExtension ) : []; - return behaviorMetadataList.map(behavior => ({ - type: behavior.type, - fullName: behavior.fullName, - description: behavior.description, - previewIconUrl: behavior.previewIconUrl, - objectType: behavior.objectType, - category: behavior.category, - tags: behavior.tags, - })); + return behaviorMetadataList + .filter(behavior => !behavior.behaviorMetadata.isHidden()) + .map(behavior => ({ + type: behavior.type, + fullName: behavior.fullName, + description: behavior.description, + previewIconUrl: behavior.previewIconUrl, + objectType: behavior.objectType, + category: behavior.category, + allRequiredBehaviorTypes: getAllRequiredBehaviorTypes( + behavior.behaviorMetadata + ), + tags: behavior.tags, + })); }, - [project, eventsFunctionsExtension] + [project, eventsFunctionsExtension, getAllRequiredBehaviorTypes] ); const installedBehaviorMetadataList: Array = React.useMemo( diff --git a/newIDE/app/src/BehaviorsEditor/index.js b/newIDE/app/src/BehaviorsEditor/index.js index ef8c83e94a..d5ff1f9d11 100644 --- a/newIDE/app/src/BehaviorsEditor/index.js +++ b/newIDE/app/src/BehaviorsEditor/index.js @@ -217,12 +217,15 @@ const BehaviorsEditor = (props: Props) => { BEHAVIORS_CLIPBOARD_KIND, mapVector(object.getAllBehaviorNames(), behaviorName => { const behavior = object.getBehavior(behaviorName); + if (behavior.isDefaultBehavior()) { + return null; + } return { name: behaviorName, type: behavior.getTypeName(), serializedBehavior: serializeToJSObject(behavior), }; - }) + }).filter(Boolean) ); forceUpdate(); }, @@ -405,6 +408,10 @@ const BehaviorsEditor = (props: Props) => { const behavior = object.getBehavior(behaviorName); const behaviorTypeName = behavior.getTypeName(); + if (behavior.isDefaultBehavior()) { + return null; + } + const behaviorMetadata = gd.MetadataProvider.getBehaviorMetadata( gd.JsPlatform.get(), behaviorTypeName diff --git a/newIDE/app/src/EventsFunctionsExtensionsLoader/EnumerateProperties.js b/newIDE/app/src/EventsFunctionsExtensionsLoader/EnumerateProperties.js index b7bb0ff344..ab720917ea 100644 --- a/newIDE/app/src/EventsFunctionsExtensionsLoader/EnumerateProperties.js +++ b/newIDE/app/src/EventsFunctionsExtensionsLoader/EnumerateProperties.js @@ -13,6 +13,7 @@ type EnumeratedProperty = {| isHidden: boolean, |}; +// TODO Remove this function as it seems to be a dead code. /** * Transform a gdNamedPropertyDescriptorsList into a JS object. * **Don't use this** unless you explicitly need to deal with JS objects. diff --git a/newIDE/app/src/EventsSheet/EventsTree/Instruction.js b/newIDE/app/src/EventsSheet/EventsTree/Instruction.js index a4f11c24b8..fd8144b090 100644 --- a/newIDE/app/src/EventsSheet/EventsTree/Instruction.js +++ b/newIDE/app/src/EventsSheet/EventsTree/Instruction.js @@ -42,6 +42,8 @@ import { type EventsScope } from '../../InstructionOrExpression/EventsScope.flow import { enumerateParametersUsableInExpressions } from '../ParameterFields/EnumerateFunctionParameters'; import { getFunctionNameFromType } from '../../EventsFunctionsExtensionsLoader'; import { ExtensionStoreContext } from '../../AssetStore/ExtensionStore/ExtensionStoreContext'; +import { getRequiredBehaviorTypes } from '../ParameterFields/ObjectField'; +import { checkHasRequiredCapability } from '../../ObjectsList/ObjectSelector'; const gd: libGDevelop = global.gd; @@ -61,6 +63,7 @@ const DragSourceAndDropTarget = makeDragSourceAndDropTarget<{ }>(reactDndInstructionType); type Props = {| + platform: gdPlatform, instruction: gdInstruction, isCondition: boolean, onClick: Function, @@ -190,6 +193,7 @@ const InstructionMissing = (props: {| const Instruction = (props: Props) => { const { + platform, instruction, isCondition, onClick, @@ -303,7 +307,17 @@ const Instruction = (props: Props) => { objectsContainer, objectOrGroupName, /*searchInGroups=*/ true - ) === parameterMetadata.getExtraInfo()); + ) === parameterMetadata.getExtraInfo()) && + checkHasRequiredCapability({ + globalObjectsContainer, + objectsContainer, + objectName: objectOrGroupName, + requiredBehaviorTypes: getRequiredBehaviorTypes( + platform, + metadata, + parameterIndex + ), + }); } else if ( gd.ParameterMetadata.isExpression('resource', parameterType) ) { @@ -557,6 +571,7 @@ const Instruction = (props: Props) => { {instructionDragSourceDropTargetElement} {metadata.canHaveSubInstructions() && ( void, @@ -72,6 +73,7 @@ const addButtonTooltipLabelMouse = t`Right-click for quick menu`; const addButtonTooltipLabelTouch = t`Long press for quick menu`; export default function InstructionsList({ + platform, addButtonId, addButtonLabel, areConditions, @@ -132,6 +134,7 @@ export default function InstructionsList({ return ( ( ( ( ( ( ( ( ( { While these conditions are true: { windowWidth={this.props.windowWidth} renderConditionsList={({ style, className }) => ( { )} renderActionsList={({ className }) => ( ( .toJSArray() .filter(behaviorName => { return ( - !allowedBehaviorType || - gd.getTypeOfBehavior( - globalObjectsContainer, - objectsContainer, - behaviorName, - false - ) === allowedBehaviorType + (!allowedBehaviorType || + gd.getTypeOfBehavior( + globalObjectsContainer, + objectsContainer, + behaviorName, + false + ) === allowedBehaviorType) && + (allowedBehaviorType || + !gd.isDefaultBehavior( + globalObjectsContainer, + objectsContainer, + objectName, + behaviorName, + true + )) ); }); diff --git a/newIDE/app/src/EventsSheet/ParameterFields/ObjectField.js b/newIDE/app/src/EventsSheet/ParameterFields/ObjectField.js index b18522dff6..932d1d46b5 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/ObjectField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/ObjectField.js @@ -14,6 +14,35 @@ import { Trans } from '@lingui/macro'; import { nameAndIconContainer } from '../EventsTree/ClassNames'; import InAppTutorialContext from '../../InAppTutorial/InAppTutorialContext'; +const gd: libGDevelop = global.gd; + +export const getRequiredBehaviorTypes = ( + platform: gdPlatform, + functionMetadata: gdInstructionMetadata | gdExpressionMetadata, + parameterIndex: number +) => { + const requiredBehaviorTypes: Array = []; + for ( + let index = parameterIndex + 1; + index < functionMetadata.getParametersCount(); + index++ + ) { + const behaviorParameter = functionMetadata.getParameter(index); + if (behaviorParameter.getType() !== 'behavior') { + break; + } + const behaviorType = behaviorParameter.getExtraInfo(); + const behaviorMetadata = gd.MetadataProvider.getBehaviorMetadata( + platform, + behaviorType + ); + if (behaviorMetadata.isHidden()) { + requiredBehaviorTypes.push(behaviorType); + } + } + return requiredBehaviorTypes; +}; + export default React.forwardRef( function ObjectField(props: ParameterFieldProps, ref) { const { currentlyRunningInAppTutorial } = React.useContext( @@ -31,7 +60,13 @@ export default React.forwardRef( focus, })); - const { parameterMetadata } = props; + const { + project, + parameterMetadata, + parameterIndex, + instructionMetadata, + expressionMetadata, + } = props; const description = parameterMetadata ? parameterMetadata.getDescription() @@ -45,36 +80,45 @@ export default React.forwardRef( ? parameterMetadata.getExtraInfo() : undefined; + const requiredBehaviorTypes = React.useMemo( + () => { + const functionMetadata = instructionMetadata || expressionMetadata; + if (!project || !functionMetadata || parameterIndex === undefined) { + return []; + } + return getRequiredBehaviorTypes( + project.getCurrentPlatform(), + functionMetadata, + parameterIndex + ); + }, + [expressionMetadata, instructionMetadata, parameterIndex, project] + ); + return ( 0 ? ( The object does not exist or can't be used here. ) : ( Enter the name of an object. diff --git a/newIDE/app/src/ExpressionAutocompletion/ExpressionAutocompletion.spec.js b/newIDE/app/src/ExpressionAutocompletion/ExpressionAutocompletion.spec.js index 051d6e70f9..00806cbf68 100644 --- a/newIDE/app/src/ExpressionAutocompletion/ExpressionAutocompletion.spec.js +++ b/newIDE/app/src/ExpressionAutocompletion/ExpressionAutocompletion.spec.js @@ -242,17 +242,11 @@ describe('ExpressionAutocompletion', () => { expect(autocompletions).toEqual( expect.arrayContaining([ expect.objectContaining({ - completion: 'Animation', + completion: 'AnimationFrameCount', addParenthesis: true, isExact: false, shouldConvertToString: true, }), - expect.objectContaining({ - completion: 'AnimationName', - addParenthesis: true, - isExact: false, - shouldConvertToString: false, - }), ]) ); }); @@ -292,6 +286,16 @@ describe('ExpressionAutocompletion', () => { }), ]) ); + expect(autocompletions).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + completion: 'Animation::SpeedScale', + addParenthesis: true, + isExact: false, + shouldConvertToString: true, + }), + ]) + ); }); it('can autocomplete object points', () => { diff --git a/newIDE/app/src/InstructionOrExpression/EnumerateExpressions.js b/newIDE/app/src/InstructionOrExpression/EnumerateExpressions.js index f4c4ee1e96..b24a7fb8bf 100644 --- a/newIDE/app/src/InstructionOrExpression/EnumerateExpressions.js +++ b/newIDE/app/src/InstructionOrExpression/EnumerateExpressions.js @@ -23,16 +23,8 @@ const enumerateExpressionMetadataMap = ( return null; // Skip hidden expressions } - if ( - scope.objectMetadata && - scope.objectMetadata.isUnsupportedBaseObjectCapability( - exprMetadata.getRequiredBaseObjectCapability() - ) - ) - return null; // Skip expressions not supported by the object. - - var parameters = []; - for (var i = 0; i < exprMetadata.getParametersCount(); i++) { + let parameters = []; + for (let i = 0; i < exprMetadata.getParametersCount(); i++) { if (scope.objectMetadata && i === 0) continue; if (scope.behaviorMetadata && i <= 1) continue; //Skip object and behavior parameters if (exprMetadata.getParameter(i).isCodeOnly()) continue; @@ -109,13 +101,13 @@ export const enumerateObjectExpressions = ( const scope = { extension, objectMetadata }; let objectsExpressions = [ - ...(!shouldOnlyBeNumberType(type) - ? enumerateExpressionMetadataMap( + ...(shouldOnlyBeNumberType(type) + ? [] + : enumerateExpressionMetadataMap( '', extension.getAllStrExpressionsForObject(objectType), scope - ) - : []), + )), ...enumerateExpressionMetadataMap( '', extension.getAllExpressionsForObject(objectType), @@ -133,13 +125,13 @@ export const enumerateObjectExpressions = ( objectsExpressions = [ ...objectsExpressions, - ...(!shouldOnlyBeNumberType(type) - ? enumerateExpressionMetadataMap( + ...(shouldOnlyBeNumberType(type) + ? [] + : enumerateExpressionMetadataMap( '', extension.getAllStrExpressionsForObject(baseObjectType), scope - ) - : []), + )), ...enumerateExpressionMetadataMap( '', extension.getAllExpressionsForObject(baseObjectType), @@ -165,13 +157,13 @@ export const enumerateBehaviorExpressions = ( const scope = { extension, behaviorMetadata }; return [ - ...(!shouldOnlyBeNumberType(type) - ? enumerateExpressionMetadataMap( + ...(shouldOnlyBeNumberType(type) + ? [] + : enumerateExpressionMetadataMap( '', extension.getAllStrExpressionsForBehavior(behaviorType), scope - ) - : []), + )), ...enumerateExpressionMetadataMap( '', extension.getAllExpressionsForBehavior(behaviorType), diff --git a/newIDE/app/src/InstructionOrExpression/EnumerateExpressions.spec.js b/newIDE/app/src/InstructionOrExpression/EnumerateExpressions.spec.js index b940921323..595ffc9eae 100644 --- a/newIDE/app/src/InstructionOrExpression/EnumerateExpressions.spec.js +++ b/newIDE/app/src/InstructionOrExpression/EnumerateExpressions.spec.js @@ -67,8 +67,9 @@ describe('EnumerateExpressions', () => { expect(filterExpressions(spriteObjectExpressions, 'PointX')).toHaveLength( 1 ); + expect(filterExpressions(spriteObjectExpressions, 'Layer')).toHaveLength(1); expect( - filterExpressions(spriteObjectExpressions, 'AnimationName') + filterExpressions(spriteObjectExpressions, 'AnimationFrameCount') ).toHaveLength(1); const objectExpressions = enumerateObjectExpressions('string', ''); diff --git a/newIDE/app/src/InstructionOrExpression/EnumerateInstructions.js b/newIDE/app/src/InstructionOrExpression/EnumerateInstructions.js index 331ba6b5b9..fbb3ac9d0a 100644 --- a/newIDE/app/src/InstructionOrExpression/EnumerateInstructions.js +++ b/newIDE/app/src/InstructionOrExpression/EnumerateInstructions.js @@ -218,14 +218,6 @@ const enumerateExtensionInstructions = ( const instrMetadata = instructions.get(type); if (instrMetadata.isHidden()) continue; - if ( - scope.objectMetadata && - scope.objectMetadata.isUnsupportedBaseObjectCapability( - instrMetadata.getRequiredBaseObjectCapability() - ) - ) - continue; // Skip instructions not supported by the object. - allInstructions.push( enumerateInstruction(prefix, type, instrMetadata, scope) ); diff --git a/newIDE/app/src/InstructionOrExpression/EnumerateInstructions.spec.js b/newIDE/app/src/InstructionOrExpression/EnumerateInstructions.spec.js index 9d8b457d26..60ee51e660 100644 --- a/newIDE/app/src/InstructionOrExpression/EnumerateInstructions.spec.js +++ b/newIDE/app/src/InstructionOrExpression/EnumerateInstructions.spec.js @@ -13,24 +13,47 @@ describe('EnumerateInstructions', () => { const instructions = enumerateAllInstructions(true); // Test for the proper presence of a few conditions - expect(instructions).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - displayedName: 'Animation finished', - fullGroupName: 'General/Sprite/Animations and images', - type: 'AnimationEnded2', - }), - expect.objectContaining({ - displayedName: 'Trigger once while true', - fullGroupName: 'Advanced/Events and control flow', - type: 'BuiltinCommonInstructions::Once', - }), - expect.objectContaining({ - displayedName: 'The cursor/touch is on an object', - fullGroupName: 'General/Objects/Mouse and touch', - type: 'SourisSurObjet', - }), - ]) + expect( + instructions.find( + instruction => + instruction.type === + 'AnimatableCapability::AnimatableBehavior::HasAnimationEnded' + ) + ).toEqual( + expect.objectContaining({ + displayedName: 'Animation finished', + fullGroupName: 'General/Animatable capability/Animations and images', + type: 'AnimatableCapability::AnimatableBehavior::HasAnimationEnded', + }) + ); + expect( + instructions.find(instruction => instruction.type === 'Sprite') + ).toEqual( + expect.objectContaining({ + displayedName: 'Current frame', + fullGroupName: 'General/Sprite/Animations and images', + type: 'Sprite', + }) + ); + expect( + instructions.find( + instruction => instruction.type === 'BuiltinCommonInstructions::Once' + ) + ).toEqual( + expect.objectContaining({ + displayedName: 'Trigger once while true', + fullGroupName: 'Advanced/Events and control flow', + type: 'BuiltinCommonInstructions::Once', + }) + ); + expect( + instructions.find(instruction => instruction.type === 'SourisSurObjet') + ).toEqual( + expect.objectContaining({ + displayedName: 'The cursor/touch is on an object', + fullGroupName: 'General/Objects/Mouse and touch', + type: 'SourisSurObjet', + }) ); }); @@ -106,7 +129,8 @@ describe('EnumerateInstructions', () => { expect(getObjectParameterIndex(triggerOnce.metadata)).toBe(-1); const spriteAnimationEnded = conditions.filter( - ({ type }) => type === 'AnimationEnded2' + ({ type }) => + type === 'AnimatableCapability::AnimatableBehavior::HasAnimationEnded' )[0]; expect(spriteAnimationEnded).not.toBeUndefined(); expect(getObjectParameterIndex(spriteAnimationEnded.metadata)).toBe(0); @@ -129,7 +153,7 @@ describe('EnumerateInstructions', () => { expect.arrayContaining([ expect.objectContaining({ displayedName: 'Animation finished', - type: 'AnimationEnded2', + type: 'AnimatableCapability::AnimatableBehavior::HasAnimationEnded', }), expect.objectContaining({ displayedName: 'The cursor/touch is on an object', @@ -138,51 +162,4 @@ describe('EnumerateInstructions', () => { ]) ); }); - - it('can enumerate instructions for an object (with an unsupported capability)', () => { - makeTestExtensions(gd); - const project = new gd.ProjectHelper.createNewGDJSProject(); - const layout = project.insertNewLayout('Scene', 0); - layout.insertNewObject(project, 'Sprite', 'MySpriteObject', 0); - layout.insertNewObject( - project, - 'FakeObjectWithUnsupportedCapability::FakeObjectWithUnsupportedCapability', - 'MyFakeObjectWithUnsupportedCapability', - 0 - ); - - // Test the sprite can have effects related condition. - const spriteInstructions = enumerateObjectAndBehaviorsInstructions( - true, - project, - layout, - 'MySpriteObject' - ); - expect(spriteInstructions).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - displayedName: 'Effect is enabled', - fullGroupName: 'Effects', - type: 'IsEffectEnabled', - }), - ]) - ); - - // Test an object not supporting effects don't have this condition. - const withUnsupportedCapabilityInstructions = enumerateObjectAndBehaviorsInstructions( - true, - project, - layout, - 'MyFakeObjectWithUnsupportedCapability' - ); - expect(withUnsupportedCapabilityInstructions).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ - displayedName: 'Effect is enabled', - fullGroupName: 'Effects', - type: 'IsEffectEnabled', - }), - ]) - ); - }); }); diff --git a/newIDE/app/src/InstructionOrExpression/SetupInstructionParameters.js b/newIDE/app/src/InstructionOrExpression/SetupInstructionParameters.js index 70f230ef24..80de2a4441 100644 --- a/newIDE/app/src/InstructionOrExpression/SetupInstructionParameters.js +++ b/newIDE/app/src/InstructionOrExpression/SetupInstructionParameters.js @@ -45,6 +45,7 @@ export const setupInstructionParameters = ( } const allowedBehaviorType = maybeBehaviorParameterMetadata.getExtraInfo(); + // TODO Factorize it with BehaviorField const behaviorNames = gd .getBehaviorsOfObject( globalObjectsContainer, @@ -55,13 +56,21 @@ export const setupInstructionParameters = ( .toJSArray() .filter(behaviorName => { return ( - !allowedBehaviorType || - gd.getTypeOfBehavior( - globalObjectsContainer, - objectsContainer, - behaviorName, - false - ) === allowedBehaviorType + (!allowedBehaviorType || + gd.getTypeOfBehavior( + globalObjectsContainer, + objectsContainer, + behaviorName, + false + ) === allowedBehaviorType) && + (allowedBehaviorType || + !gd.isDefaultBehavior( + globalObjectsContainer, + objectsContainer, + objectName, + behaviorName, + true + )) ); }); diff --git a/newIDE/app/src/InstructionOrExpression/SetupInstructionParameters.spec.js b/newIDE/app/src/InstructionOrExpression/SetupInstructionParameters.spec.js index b0f43bcd51..b360804298 100644 --- a/newIDE/app/src/InstructionOrExpression/SetupInstructionParameters.spec.js +++ b/newIDE/app/src/InstructionOrExpression/SetupInstructionParameters.spec.js @@ -46,6 +46,7 @@ describe('setupInstructionParameters', () => { const project = new gd.ProjectHelper.createNewGDJSProject(); const layout = project.insertNewLayout('Scene', 0); const objectName = 'MySpriteObject'; + const behaviorName = 'Animation'; layout.insertNewObject(project, 'Sprite', objectName, 0); // Simulate that we select an instruction for the object @@ -56,7 +57,9 @@ describe('setupInstructionParameters', () => { objectName ); const setAnimationNameInstruction = enumeratedInstructions.find( - enumeratedInstruction => enumeratedInstruction.type === 'SetAnimationName' + enumeratedInstruction => + enumeratedInstruction.type === + 'AnimatableCapability::AnimatableBehavior::SetName' ); if (!setAnimationNameInstruction) { @@ -73,9 +76,13 @@ describe('setupInstructionParameters', () => { ); // Check that parameters were created and the object name set - expect(instruction.getParametersCount()).toBe(2); + expect(instruction.getParametersCount()).toBe(4); expect(instruction.getParameter(0).getPlainString()).toBe(objectName); - expect(instruction.getParameter(1).getPlainString()).toBe(''); + expect(instruction.getParameter(1).getPlainString()).toBe(behaviorName); + // Operator + expect(instruction.getParameter(2).getPlainString()).toBe(''); + // Operand + expect(instruction.getParameter(3).getPlainString()).toBe(''); }); it('sets the proper parameters for a behavior', () => { diff --git a/newIDE/app/src/ObjectEditor/ObjectEditorDialog.js b/newIDE/app/src/ObjectEditor/ObjectEditorDialog.js index 40e3b1301a..8a5a90c4ad 100644 --- a/newIDE/app/src/ObjectEditor/ObjectEditorDialog.js +++ b/newIDE/app/src/ObjectEditor/ObjectEditorDialog.js @@ -184,12 +184,14 @@ const InnerDialog = (props: InnerDialogProps) => { label: Variables, value: 'variables', }, - objectMetadata.isUnsupportedBaseObjectCapability('effect') - ? null - : { + objectMetadata.hasDefaultBehavior( + 'EffectCapability::EffectBehavior' + ) + ? { label: Effects, value: 'effects', - }, + } + : null, ].filter(Boolean)} /> } diff --git a/newIDE/app/src/ObjectsList/EnumerateObjects.js b/newIDE/app/src/ObjectsList/EnumerateObjects.js index dbd9c7a287..ff604718ea 100644 --- a/newIDE/app/src/ObjectsList/EnumerateObjects.js +++ b/newIDE/app/src/ObjectsList/EnumerateObjects.js @@ -3,6 +3,7 @@ import { mapFor } from '../Utils/MapFor'; import flatten from 'lodash/flatten'; import { type SelectedTags, hasStringAllTags } from '../Utils/TagsHelper'; import { type RequiredExtension } from '../AssetStore/InstallAsset'; + const gd: libGDevelop = global.gd; export type EnumeratedObjectMetadata = {| @@ -221,28 +222,53 @@ export const enumerateGroups = ( export const enumerateObjectsAndGroups = ( globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, - type: ?string = undefined + objectType: ?string = undefined, + requiredBehaviorTypes?: Array = [] ) => { const filterObject = (object: gdObject): boolean => { return ( - !type || - gd.getTypeOfObject( - globalObjectsContainer, - objectsContainer, - object.getName(), - false - ) === type + (!objectType || + gd.getTypeOfObject( + globalObjectsContainer, + objectsContainer, + object.getName(), + false + ) === objectType) && + requiredBehaviorTypes.every( + requiredBehaviorType => + gd + .getBehaviorNamesInObjectOrGroup( + globalObjectsContainer, + objectsContainer, + object.getName(), + requiredBehaviorType, + false + ) + .size() > 0 + ) ); }; const filterGroup = (group: gdObjectGroup): boolean => { return ( - !type || - gd.getTypeOfObject( - globalObjectsContainer, - objectsContainer, - group.getName(), - true - ) === type + (!objectType || + gd.getTypeOfObject( + globalObjectsContainer, + objectsContainer, + group.getName(), + true + ) === objectType) && + requiredBehaviorTypes.every( + behaviorType => + gd + .getBehaviorNamesInObjectOrGroup( + globalObjectsContainer, + objectsContainer, + group.getName(), + behaviorType, + true + ) + .size() > 0 + ) ); }; diff --git a/newIDE/app/src/ObjectsList/ObjectSelector.js b/newIDE/app/src/ObjectsList/ObjectSelector.js index 22079df273..4f708cca00 100644 --- a/newIDE/app/src/ObjectsList/ObjectSelector.js +++ b/newIDE/app/src/ObjectsList/ObjectSelector.js @@ -15,6 +15,7 @@ import { type MessageDescriptor } from '../Utils/i18n/MessageDescriptor.flow'; import { useShouldAutofocusInput } from '../UI/Reponsive/ScreenTypeMeasurer'; import SelectField from '../UI/SelectField'; import SelectOption from '../UI/SelectOption'; + const gd: libGDevelop = global.gd; type Props = {| @@ -25,10 +26,10 @@ type Props = {| /** If specified, only this object type should be allowed to be selected. */ allowedObjectType?: ?string, /** - * If specified, an object without this required capability won't be selectable. - * Note that this does not work with groups - which are assumed to have all capabilities. + * If specified, an object without these behaviors won't be selectable. + * Note that groups with at least 1 incompatible object won't be shown. */ - requiredObjectCapability?: ?string, + requiredBehaviorTypes?: Array, noGroups?: boolean, @@ -60,6 +61,7 @@ const getObjectsAndGroupsDataSource = ({ objectsContainer, noGroups, allowedObjectType, + requiredBehaviorTypes, excludedObjectOrGroupNames, }: {| project: ?gdProject, @@ -67,12 +69,14 @@ const getObjectsAndGroupsDataSource = ({ objectsContainer: gdObjectsContainer, noGroups: ?boolean, allowedObjectType: ?string, + requiredBehaviorTypes?: Array, excludedObjectOrGroupNames: ?Array, |}): DataSource => { const list = enumerateObjectsAndGroups( globalObjectsContainer, objectsContainer, - allowedObjectType || undefined + allowedObjectType || undefined, + requiredBehaviorTypes || [] ); const objects = list.allObjectsList.map(({ object }) => { return { @@ -113,21 +117,18 @@ const getObjectsAndGroupsDataSource = ({ : fullList; }; -const checkHasRequiredCapability = ({ - project, +export const checkHasRequiredCapability = ({ globalObjectsContainer, objectsContainer, - requiredObjectCapability, + requiredBehaviorTypes, objectName, }: {| - project: ?gdProject, globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, - requiredObjectCapability: ?string, objectName: string, + requiredBehaviorTypes?: Array, |}) => { - if (!requiredObjectCapability) return true; - if (!project) return true; + if (!requiredBehaviorTypes || requiredBehaviorTypes.length === 0) return true; const object = getObjectByName( globalObjectsContainer, @@ -141,12 +142,17 @@ const checkHasRequiredCapability = ({ return true; } - const objectMetadata = gd.MetadataProvider.getObjectMetadata( - project.getCurrentPlatform(), - object.getType() - ); - return !objectMetadata.isUnsupportedBaseObjectCapability( - requiredObjectCapability + return requiredBehaviorTypes.every( + behaviorType => + gd + .getBehaviorNamesInObjectOrGroup( + globalObjectsContainer, + objectsContainer, + objectName, + behaviorType, + false + ) + .size() > 0 ); }; @@ -171,7 +177,6 @@ const ObjectSelector = React.forwardRef( globalObjectsContainer, objectsContainer, allowedObjectType, - requiredObjectCapability, noGroups, errorTextIfInvalid, margin, @@ -180,6 +185,7 @@ const ObjectSelector = React.forwardRef( id, excludedObjectOrGroupNames, hintText, + requiredBehaviorTypes, ...otherProps } = props; @@ -189,6 +195,7 @@ const ObjectSelector = React.forwardRef( objectsContainer, noGroups, allowedObjectType, + requiredBehaviorTypes, excludedObjectOrGroupNames, }); @@ -198,13 +205,11 @@ const ObjectSelector = React.forwardRef( ).length !== 0; const hasObjectWithRequiredCapability = checkHasRequiredCapability({ - project, - requiredObjectCapability, globalObjectsContainer, objectsContainer, objectName: value, + requiredBehaviorTypes, }); - const errorText = !hasObjectWithRequiredCapability ? ( This object exists, but can't be used here. ) : !hasValidChoice ? ( diff --git a/newIDE/app/src/ObjectsList/index.js b/newIDE/app/src/ObjectsList/index.js index 3179eb4016..05011a0410 100644 --- a/newIDE/app/src/ObjectsList/index.js +++ b/newIDE/app/src/ObjectsList/index.js @@ -742,8 +742,8 @@ const ObjectsList = React.forwardRef( { label: i18n._(t`Edit effects`), click: () => onEditObject(object, 'effects'), - enabled: !objectMetadata.isUnsupportedBaseObjectCapability( - 'effect' + enabled: objectMetadata.hasDefaultBehavior( + 'EffectCapacity::EffectBehavior' ), }, eventsFunctionsExtensionWriter && diff --git a/newIDE/app/src/UI/Checkbox.js b/newIDE/app/src/UI/Checkbox.js index 029845eec1..72e0d2ea4e 100644 --- a/newIDE/app/src/UI/Checkbox.js +++ b/newIDE/app/src/UI/Checkbox.js @@ -43,7 +43,7 @@ type Props = {| |}; /** - * A text field based on Material-UI text field. + * A checkbox based on Material-UI checkbox. */ const Checkbox = (props: Props) => { const { onCheck } = props; diff --git a/newIDE/app/src/Utils/GDevelopServices/Extension.js b/newIDE/app/src/Utils/GDevelopServices/Extension.js index 5d1f1e644f..b3258a7afd 100644 --- a/newIDE/app/src/Utils/GDevelopServices/Extension.js +++ b/newIDE/app/src/Utils/GDevelopServices/Extension.js @@ -43,6 +43,10 @@ export type BehaviorShortHeader = {| description: string, extensionName: string, objectType: string, + /** + * All required behaviors including transitive ones. + */ + allRequiredBehaviorTypes: Array, /** This attribute is calculated. * @see adaptBehaviorHeader */ diff --git a/newIDE/app/src/fixtures/GDevelopServicesTestData/FakeBehaviorsRegistry.js b/newIDE/app/src/fixtures/GDevelopServicesTestData/FakeBehaviorsRegistry.js index f5e0c12a59..50a5941699 100644 --- a/newIDE/app/src/fixtures/GDevelopServicesTestData/FakeBehaviorsRegistry.js +++ b/newIDE/app/src/fixtures/GDevelopServicesTestData/FakeBehaviorsRegistry.js @@ -40,6 +40,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { description: 'Rotate to always face the camera (only the front face of the cube should be enabled).', objectType: 'Scene3D::Cube3DObject', + allRequiredBehaviorTypes: [], type: null, }, { @@ -60,6 +61,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { description: 'Provides an action to make the object bounce from another object it just touched. Add a permanent force to the object and, when in collision with another one, use the action to make it bounce realistically.', objectType: '', + allRequiredBehaviorTypes: [], type: null, authors: [ { @@ -91,6 +93,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { extensionName: 'FireBullet', description: 'Fire bullets, manage ammo, reloading, and overheating.', objectType: '', + allRequiredBehaviorTypes: [], type: null, authors: [ { @@ -127,6 +130,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { description: 'Make the object flash (blink) for a period of time, so that it is alternately visible and invisible.\nTrigger the effect by using the Flash action.', objectType: '', + allRequiredBehaviorTypes: [], type: null, }, { @@ -146,6 +150,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { extensionName: 'Gamepads', description: 'Control a platformer character with a gamepad.', objectType: '', + allRequiredBehaviorTypes: [], type: null, authors: [ { @@ -174,6 +179,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { extensionName: 'Gamepads', description: 'Control a top-down character with a gamepad.', objectType: '', + allRequiredBehaviorTypes: [], type: null, authors: [ { @@ -206,6 +212,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { description: 'Manage health (life) points including a protective shield and armor.', objectType: '', + allRequiredBehaviorTypes: [], type: null, authors: [ { @@ -241,6 +248,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { extensionName: 'SmoothCamera', description: 'Smoothly scroll to follow an object.', objectType: '', + allRequiredBehaviorTypes: [], type: null, authors: [ { @@ -270,6 +278,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { description: 'Smoothly scroll to follow a character and stabilize the camera when jumping.', objectType: '', + allRequiredBehaviorTypes: [], type: null, authors: [ { @@ -304,6 +313,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { description: 'Control a platformer character with a multitouch controller.', objectType: '', + allRequiredBehaviorTypes: [], type: null, authors: [ { @@ -344,6 +354,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { extensionName: 'SpriteMultitouchJoystick', description: 'Control a top-down character with a multitouch controller.', objectType: '', + allRequiredBehaviorTypes: [], type: null, authors: [ { @@ -383,6 +394,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { description: 'Force the object to stay visible on the screen by setting back its position inside the viewport of the camera.', objectType: '', + allRequiredBehaviorTypes: [], type: null, authors: [ { @@ -419,6 +431,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { description: 'Set the depth (Z-order) of the instance to the value of its Y position in the scene, creating an illusion of depth. The origin point of the object is used to determine the Z-order.', objectType: '', + allRequiredBehaviorTypes: [], type: null, authors: [], }, @@ -443,6 +456,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { description: 'Create and manage revolute joints between two objects.\nAlso known as a hinge joint because the objects act like they are connected with a hinge that pivots.', objectType: '', + allRequiredBehaviorTypes: [], type: null, authors: [ { @@ -482,6 +496,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { description: 'Create and manage weld joints between two objects.\nAlso known as a static joint because the objects stay glued in the same relative position to each other.', objectType: '', + allRequiredBehaviorTypes: [], type: null, authors: [ { @@ -521,6 +536,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { description: 'Create and manage distance joints between two objects. \nActs like a spring because the objects try to stay the same distance apart.', objectType: '', + allRequiredBehaviorTypes: [], type: null, authors: [ { @@ -560,6 +576,7 @@ export const fakeBehaviorsRegistry: BehaviorsRegistry & { description: 'Create and manage rope joints between two objects. \nObjects can get closer, but they cannot exceed the starting distance from each other.\n', objectType: '', + allRequiredBehaviorTypes: [], type: null, authors: [ { diff --git a/newIDE/app/src/fixtures/TestExtensions.js b/newIDE/app/src/fixtures/TestExtensions.js index a9e05bced5..9f54bed063 100644 --- a/newIDE/app/src/fixtures/TestExtensions.js +++ b/newIDE/app/src/fixtures/TestExtensions.js @@ -336,16 +336,6 @@ export const makeTestExtensions = (gd: libGDevelop) => { return instanceProperties; }; - const object = extension - .addObject( - 'FakeObjectWithUnsupportedCapability', - 'FakeObjectWithUnsupportedCapability', - 'This is FakeObjectWithUnsupportedCapability', - '', - fakeObject - ) - .addUnsupportedBaseObjectCapability('effect'); - platform.addNewExtension(extension); extension.delete(); // Release the extension as it was copied inside gd.JsPlatform } diff --git a/newIDE/app/src/stories/componentStories/ParameterFields/ObjectField.stories.js b/newIDE/app/src/stories/componentStories/ParameterFields/ObjectField.stories.js index 6ebb83f1fe..3cfe9a7378 100644 --- a/newIDE/app/src/stories/componentStories/ParameterFields/ObjectField.stories.js +++ b/newIDE/app/src/stories/componentStories/ParameterFields/ObjectField.stories.js @@ -83,16 +83,11 @@ export const WrongObjectType = () => { }; WrongObjectType.storyName = 'Error: wrong object type'; -export const WithRequiredCapability = () => { +export const WithRequiredBehavior = () => { const instructionMetadata = gd.MetadataProvider.getActionMetadata( gd.JsPlatform.get(), - 'EnableEffect' + 'EffectCapability::EffectBehavior::EnableEffect' ); - if (instructionMetadata.getRequiredBaseObjectCapability() !== 'effect') { - throw new Error( - "The required base object capability is not 'effect' for the instruction used in this story." - ); - } return ( { globalObjectsContainer={testProject.project} objectsContainer={testProject.testLayout} instructionMetadata={instructionMetadata} + parameterIndex={0} value={value} onChange={onChange} /> @@ -111,5 +107,5 @@ export const WithRequiredCapability = () => { /> ); }; -WithRequiredCapability.storyName = +WithRequiredBehavior.storyName = 'Error: object not having a required capability';