mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
31 Commits
v5.2.177
...
condition-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
689676e058 | ||
![]() |
1ed6b4889a | ||
![]() |
ccec9e9b8b | ||
![]() |
2a036368f5 | ||
![]() |
3bc8b1839f | ||
![]() |
d8f2ced5f5 | ||
![]() |
5373406177 | ||
![]() |
3d1142f7c7 | ||
![]() |
2d7e6248f7 | ||
![]() |
85dd04e430 | ||
![]() |
c25252ce33 | ||
![]() |
685b2105e1 | ||
![]() |
cd0bfa9281 | ||
![]() |
297fade0bd | ||
![]() |
84d7500eab | ||
![]() |
f99c4ab948 | ||
![]() |
5fe4f23c83 | ||
![]() |
8820bd45e4 | ||
![]() |
5e16968f37 | ||
![]() |
6b6179ff22 | ||
![]() |
94bcd87a9f | ||
![]() |
356a1974ef | ||
![]() |
345bad9876 | ||
![]() |
0b8d843a73 | ||
![]() |
9f0c987ec7 | ||
![]() |
0e79209d2b | ||
![]() |
f991c09c39 | ||
![]() |
6e24dfa9b8 | ||
![]() |
a3cd00dc94 | ||
![]() |
300c011151 | ||
![]() |
230d410469 |
@@ -46,10 +46,6 @@ void EffectsCodeGenerator::GenerateEffectsIncludeFiles(
|
||||
// TODO Add unit tests on this function.
|
||||
|
||||
// TODO Merge with UsedExtensionsFinder.
|
||||
// Default lights rely on the fact that UsedExtensionsFinder doesn't find
|
||||
// extension usages for effects. This has the happy side effect of not
|
||||
// including Three.js when no 3D object are in the scenes.
|
||||
// We need to make something explicit to avoid future bugs.
|
||||
|
||||
// See also gd::Project::ExposeResources for a method that traverse the whole
|
||||
// project (this time for resources) and
|
||||
|
@@ -66,6 +66,19 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("SetReturnObject",
|
||||
_("Set returned objects"),
|
||||
_("Set currently picked instances as the ones returned for the object. These instances will be picked for actions, conditions and sub-events that follow this function call."),
|
||||
_("Set currently picked instances of _PARAM0_ to be returned"),
|
||||
_("Functions"),
|
||||
"res/function24.png",
|
||||
"res/function16.png")
|
||||
.SetHelpPath("/events/functions/return")
|
||||
.AddParameter("object", "Picked instances object")
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("CopyArgumentToVariable",
|
||||
_("Copy function parameter to variable"),
|
||||
|
@@ -396,7 +396,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Z order"),
|
||||
_("Modify the Z-order of an object"),
|
||||
_("the z-order"),
|
||||
_("Z order"),
|
||||
_("Layers and cameras"),
|
||||
"res/actions/planicon24.png",
|
||||
"res/actions/planicon.png")
|
||||
|
||||
@@ -550,7 +550,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Z-order"),
|
||||
_("Compare the Z-order of the specified object."),
|
||||
_("the Z-order"),
|
||||
_("Z-order"),
|
||||
_("Layer"),
|
||||
"res/conditions/planicon24.png",
|
||||
"res/conditions/planicon.png")
|
||||
|
||||
@@ -1151,7 +1151,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
obj.AddExpression("ZOrder",
|
||||
_("Z-order"),
|
||||
_("Z-order of an object"),
|
||||
_("Visibility"),
|
||||
"",
|
||||
"res/actions/planicon.png")
|
||||
.AddParameter("object", _("Object"));
|
||||
|
||||
|
@@ -46,7 +46,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsScalableExtension(
|
||||
_("Scale"),
|
||||
_("the scale of the object (default scale is 1)"),
|
||||
_("the scale"),
|
||||
_("Scale"),
|
||||
_("Size"),
|
||||
"res/actions/scale24_black.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "ScalableBehavior")
|
||||
@@ -63,7 +63,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsScalableExtension(
|
||||
_("Scale on X axis"),
|
||||
_("the scale on X axis of the object (default scale is 1)"),
|
||||
_("the scale on X axis"),
|
||||
_("Scale"),
|
||||
_("Size"),
|
||||
"res/actions/scaleWidth24_black.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "ScalableBehavior")
|
||||
@@ -80,7 +80,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsScalableExtension(
|
||||
_("Scale on Y axis"),
|
||||
_("the scale on Y axis of the object (default scale is 1)"),
|
||||
_("the scale on Y axis"),
|
||||
_("Scale"),
|
||||
_("Size"),
|
||||
"res/actions/scaleHeight24_black.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "ScalableBehavior")
|
||||
|
@@ -30,7 +30,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
.AddObject<SpriteObject>("Sprite",
|
||||
_("Sprite"),
|
||||
_("Animated object which can be used for "
|
||||
"most elements of a game"),
|
||||
"most elements of a game."),
|
||||
"CppPlatform/Extensions/spriteicon.png")
|
||||
.SetCategoryFullName(_("General"))
|
||||
.AddDefaultBehavior("EffectCapability::EffectBehavior")
|
||||
@@ -408,6 +408,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
.SetHidden()
|
||||
.MarkAsSimple();
|
||||
|
||||
// Deprecated
|
||||
obj.AddCondition("ScaleWidth",
|
||||
_("Scale on X axis"),
|
||||
_("Compare the scale of the width of an object."),
|
||||
@@ -415,7 +416,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Size"),
|
||||
"res/conditions/scaleWidth24_black.png",
|
||||
"res/conditions/scaleWidth_black.png")
|
||||
|
||||
.SetHidden()
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number",
|
||||
@@ -423,6 +424,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Scale (1 by default)")))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
// Deprecated
|
||||
obj.AddCondition("ScaleHeight",
|
||||
_("Scale on Y axis"),
|
||||
_("Compare the scale of the height of an object."),
|
||||
@@ -430,7 +432,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Size"),
|
||||
"res/conditions/scaleHeight24_black.png",
|
||||
"res/conditions/scaleHeight_black.png")
|
||||
|
||||
.SetHidden()
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number",
|
||||
|
@@ -303,12 +303,24 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return true if the instruction must be hidden in the IDE.
|
||||
* \brief Return true if the object must be hidden in the IDE.
|
||||
*/
|
||||
bool IsHidden() const { return hidden; }
|
||||
|
||||
/**
|
||||
* \brief Declare a usage of the 3D renderer.
|
||||
*/
|
||||
ObjectMetadata &MarkAsRenderedIn3D() {
|
||||
isRenderedIn3D = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the object uses the 3D renderer.
|
||||
*/
|
||||
bool IsRenderedIn3D() const { return isRenderedIn3D; }
|
||||
|
||||
std::map<gd::String, gd::InstructionMetadata> conditionsInfos;
|
||||
std::map<gd::String, gd::InstructionMetadata> actionsInfos;
|
||||
std::map<gd::String, gd::ExpressionMetadata> expressionsInfos;
|
||||
@@ -329,6 +341,7 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
|
||||
gd::String categoryFullName;
|
||||
std::set<gd::String> defaultBehaviorTypes;
|
||||
bool hidden = false;
|
||||
bool isRenderedIn3D = false;
|
||||
|
||||
std::shared_ptr<gd::ObjectConfiguration>
|
||||
blueprintObject; ///< The "blueprint" object to be copied when a new
|
||||
|
@@ -25,6 +25,9 @@ const UsedExtensionsResult UsedExtensionsFinder::ScanProject(gd::Project& projec
|
||||
void UsedExtensionsFinder::DoVisitObject(gd::Object &object) {
|
||||
auto metadata = gd::MetadataProvider::GetExtensionAndObjectMetadata(
|
||||
project.GetCurrentPlatform(), object.GetType());
|
||||
if (metadata.GetMetadata().IsRenderedIn3D()) {
|
||||
result.MarkAsHaving3DObjects();
|
||||
}
|
||||
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());
|
||||
for (auto &&includeFile : metadata.GetMetadata().includeFiles) {
|
||||
result.GetUsedIncludeFiles().insert(includeFile);
|
||||
|
@@ -44,6 +44,13 @@ public:
|
||||
return usedRequiredFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true when at least 1 object uses the 3D renderer.
|
||||
*/
|
||||
bool Has3DObjects() const {
|
||||
return has3DObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* The extensions used by the project (or part of it).
|
||||
*/
|
||||
@@ -59,10 +66,15 @@ public:
|
||||
*/
|
||||
std::set<gd::String> &GetUsedRequiredFiles() { return usedRequiredFiles; }
|
||||
|
||||
void MarkAsHaving3DObjects() {
|
||||
has3DObjects = true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<gd::String> usedExtensions;
|
||||
std::set<gd::String> usedIncludeFiles;
|
||||
std::set<gd::String> usedRequiredFiles;
|
||||
bool has3DObjects = false;
|
||||
};
|
||||
|
||||
class GD_CORE_API UsedExtensionsFinder
|
||||
|
@@ -27,6 +27,9 @@ EventsBasedObject::EventsBasedObject(const gd::EventsBasedObject &_eventBasedObj
|
||||
|
||||
void EventsBasedObject::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("defaultName", defaultName);
|
||||
if (isRenderedIn3D) {
|
||||
element.SetBoolAttribute("is3D", true);
|
||||
}
|
||||
|
||||
AbstractEventsBasedEntity::SerializeTo(element);
|
||||
SerializeObjectsTo(element.AddChild("objects"));
|
||||
@@ -36,6 +39,7 @@ void EventsBasedObject::SerializeTo(SerializerElement& element) const {
|
||||
void EventsBasedObject::UnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element) {
|
||||
defaultName = element.GetStringAttribute("defaultName");
|
||||
isRenderedIn3D = element.GetBoolAttribute("is3D", false);
|
||||
|
||||
AbstractEventsBasedEntity::UnserializeFrom(project, element);
|
||||
UnserializeObjectsFrom(project, element.GetChild("objects"));
|
||||
|
@@ -72,6 +72,19 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public Ob
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Declare a usage of the 3D renderer.
|
||||
*/
|
||||
EventsBasedObject& MarkAsRenderedIn3D(bool isRenderedIn3D_) {
|
||||
isRenderedIn3D = isRenderedIn3D_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the object uses the 3D renderer.
|
||||
*/
|
||||
bool IsRenderedIn3D() const { return isRenderedIn3D; }
|
||||
|
||||
void SerializeTo(SerializerElement& element) const override;
|
||||
|
||||
void UnserializeFrom(gd::Project& project,
|
||||
@@ -79,6 +92,7 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public Ob
|
||||
|
||||
private:
|
||||
gd::String defaultName;
|
||||
bool isRenderedIn3D;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -107,7 +107,7 @@ module.exports = {
|
||||
_('Scale on Z axis'),
|
||||
_("the scale on Z axis of an object (default scale is 1)"),
|
||||
_("the scale on Z axis scale"),
|
||||
_('Scale'),
|
||||
_('Size'),
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D object'))
|
||||
@@ -244,17 +244,18 @@ module.exports = {
|
||||
.addObject(
|
||||
'Model3DObject',
|
||||
_('3D Model'),
|
||||
_('A 3D model.'),
|
||||
_('An animated 3D model.'),
|
||||
'JsPlatform/Extensions/3d_box.svg',
|
||||
new gd.Model3DObjectConfiguration()
|
||||
)
|
||||
.setCategoryFullName(_('3D'))
|
||||
.setCategoryFullName(_('General'))
|
||||
// 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')
|
||||
.markAsRenderedIn3D()
|
||||
.setIncludeFile('Extensions/3D/A_RuntimeObject3D.js')
|
||||
.addIncludeFile('Extensions/3D/A_RuntimeObject3DRenderer.js')
|
||||
.addIncludeFile('Extensions/3D/Model3DRuntimeObject.js')
|
||||
@@ -1125,16 +1126,17 @@ module.exports = {
|
||||
.addObject(
|
||||
'Cube3DObject',
|
||||
_('3D Box'),
|
||||
_('A 3D box.'),
|
||||
_('A box with images for each face'),
|
||||
'JsPlatform/Extensions/3d_box.svg',
|
||||
Cube3DObject
|
||||
)
|
||||
.setCategoryFullName(_('3D'))
|
||||
.setCategoryFullName(_('General'))
|
||||
// Effects are unsupported because the object is not rendered with PIXI.
|
||||
.addDefaultBehavior('ResizableCapability::ResizableBehavior')
|
||||
.addDefaultBehavior('ScalableCapability::ScalableBehavior')
|
||||
.addDefaultBehavior('FlippableCapability::FlippableBehavior')
|
||||
.addDefaultBehavior('Scene3D::Base3DBehavior')
|
||||
.markAsRenderedIn3D()
|
||||
.setIncludeFile('Extensions/3D/A_RuntimeObject3D.js')
|
||||
.addIncludeFile('Extensions/3D/A_RuntimeObject3DRenderer.js')
|
||||
.addIncludeFile('Extensions/3D/Cube3DRuntimeObject.js')
|
||||
|
@@ -1465,7 +1465,7 @@ module.exports = {
|
||||
'ApplyForce',
|
||||
_('Apply force'),
|
||||
_(
|
||||
'Apply a force to the object. You need to specify the point of application (you can get the body mass center through expressions).'
|
||||
'Apply a force to the object over time. It "accelerates" an object and must be used every frame during a time period.'
|
||||
),
|
||||
_('Apply to _PARAM0_ a force of _PARAM2_;_PARAM3_'),
|
||||
_('Forces & impulses'),
|
||||
@@ -1476,8 +1476,10 @@ module.exports = {
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter('expression', _('X component (N)'))
|
||||
.addParameter('expression', _('Y component (N)'))
|
||||
.addParameter('expression', _('Applying X position'))
|
||||
.addParameter('expression', _('Applying Y position'))
|
||||
.setParameterLongDescription(_('A force is like an acceleration but depends on the mass.'))
|
||||
.addParameter('expression', _('Application point on X axis'))
|
||||
.addParameter('expression', _('Application point on Y axis'))
|
||||
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('applyForce');
|
||||
|
||||
@@ -1486,7 +1488,7 @@ module.exports = {
|
||||
'ApplyPolarForce',
|
||||
_('Apply force (angle)'),
|
||||
_(
|
||||
'Apply a force to the object using polar coordinates. You need to specify the point of application (you can get the body mass center through expressions).'
|
||||
'Apply a force to the object over time using polar coordinates. It "accelerates" an object and must be used every frame during a time period.'
|
||||
),
|
||||
_('Apply to _PARAM0_ a force of angle _PARAM2_ and length _PARAM3_'),
|
||||
_('Forces & impulses'),
|
||||
@@ -1497,8 +1499,10 @@ module.exports = {
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter('expression', _('Angle'))
|
||||
.addParameter('expression', _('Length (N)'))
|
||||
.addParameter('expression', _('Applying X position'))
|
||||
.addParameter('expression', _('Applying Y position'))
|
||||
.setParameterLongDescription(_('A force is like an acceleration but depends on the mass.'))
|
||||
.addParameter('expression', _('Application point on X axis'))
|
||||
.addParameter('expression', _('Application point on Y axis'))
|
||||
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('applyPolarForce');
|
||||
|
||||
@@ -1507,7 +1511,7 @@ module.exports = {
|
||||
'ApplyForceTowardPosition',
|
||||
_('Apply force toward position'),
|
||||
_(
|
||||
'Apply a force to the object to move it toward a position. You need to specify the point of application (you can get the body mass center through expressions).'
|
||||
'Apply a force to the object over time to move it toward a position. It "accelerates" an object and must be used every frame during a time period.'
|
||||
),
|
||||
_(
|
||||
'Apply to _PARAM0_ a force of length _PARAM2_ towards _PARAM3_;_PARAM4_'
|
||||
@@ -1519,10 +1523,12 @@ module.exports = {
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter('expression', _('Length (N)'))
|
||||
.setParameterLongDescription(_('A force is like an acceleration but depends on the mass.'))
|
||||
.addParameter('expression', _('X position'))
|
||||
.addParameter('expression', _('Y position'))
|
||||
.addParameter('expression', _('Applying X position'))
|
||||
.addParameter('expression', _('Applying Y position'))
|
||||
.addParameter('expression', _('Application point on X axis'))
|
||||
.addParameter('expression', _('Application point on Y axis'))
|
||||
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('applyForceTowardPosition');
|
||||
|
||||
@@ -1531,7 +1537,7 @@ module.exports = {
|
||||
'ApplyImpulse',
|
||||
_('Apply impulse'),
|
||||
_(
|
||||
'Apply an impulse to the object. You need to specify the point of application (you can get the body mass center through expressions).'
|
||||
'Apply an impulse to the object. It instantly changes the speed, to give an initial speed for instance.'
|
||||
),
|
||||
_('Apply to _PARAM0_ an impulse of _PARAM2_;_PARAM3_'),
|
||||
_('Forces & impulses'),
|
||||
@@ -1542,14 +1548,16 @@ module.exports = {
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter(
|
||||
'expression',
|
||||
_('X component (in Newton * seconds or kilogram * meter per second)')
|
||||
_('X component (N·s or kg·m·s⁻¹)')
|
||||
)
|
||||
.addParameter(
|
||||
'expression',
|
||||
_('Y component (in Newton * seconds or kilogram * meter per second)')
|
||||
_('Y component (N·s or kg·m·s⁻¹)')
|
||||
)
|
||||
.addParameter('expression', _('Applying X position'))
|
||||
.addParameter('expression', _('Applying Y position'))
|
||||
.setParameterLongDescription(_('An impulse is like a speed addition but depends on the mass.'))
|
||||
.addParameter('expression', _('Application point on X axis'))
|
||||
.addParameter('expression', _('Application point on Y axis'))
|
||||
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('applyImpulse');
|
||||
|
||||
@@ -1558,7 +1566,7 @@ module.exports = {
|
||||
'ApplyPolarImpulse',
|
||||
_('Apply impulse (angle)'),
|
||||
_(
|
||||
'Apply an impulse to the object using polar coordinates. You need to specify the point of application (you can get the body mass center through expressions).'
|
||||
'Apply an impulse to the object using polar coordinates. It instantly changes the speed, to give an initial speed for instance.'
|
||||
),
|
||||
_(
|
||||
'Apply to _PARAM0_ an impulse of angle _PARAM2_ and length _PARAM3_ (applied at _PARAM4_;_PARAM5_)'
|
||||
@@ -1572,10 +1580,12 @@ module.exports = {
|
||||
.addParameter('expression', _('Angle'))
|
||||
.addParameter(
|
||||
'expression',
|
||||
_('Length (in Newton * seconds or kilogram * meter per second)')
|
||||
_('Length (N·s or kg·m·s⁻¹)')
|
||||
)
|
||||
.addParameter('expression', _('Applying X position'))
|
||||
.addParameter('expression', _('Applying Y position'))
|
||||
.setParameterLongDescription(_('An impulse is like a speed addition but depends on the mass.'))
|
||||
.addParameter('expression', _('Application point on X axis'))
|
||||
.addParameter('expression', _('Application point on Y axis'))
|
||||
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('applyPolarImpulse');
|
||||
|
||||
@@ -1584,7 +1594,7 @@ module.exports = {
|
||||
'ApplyImpulseTowardPosition',
|
||||
_('Apply impulse toward position'),
|
||||
_(
|
||||
'Apply an impulse to the object to move it toward a position. You need to specify the point of application (you can get the body mass center through expressions).'
|
||||
'Apply an impulse to the object to move it toward a position. It instantly changes the speed, to give an initial speed for instance.'
|
||||
),
|
||||
_(
|
||||
'Apply to _PARAM0_ an impulse of length _PARAM2_ towards _PARAM3_;_PARAM4_ (applied at _PARAM5_;_PARAM6_)'
|
||||
@@ -1597,12 +1607,14 @@ module.exports = {
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter(
|
||||
'expression',
|
||||
_('Length (in Newton * seconds or kilogram * meter per second)')
|
||||
_('Length (N·s or kg·m·s⁻¹)')
|
||||
)
|
||||
.setParameterLongDescription(_('An impulse is like a speed addition but depends on the mass.'))
|
||||
.addParameter('expression', _('X position'))
|
||||
.addParameter('expression', _('Y position'))
|
||||
.addParameter('expression', _('Applying X position'))
|
||||
.addParameter('expression', _('Applying Y position'))
|
||||
.addParameter('expression', _('Application point on X axis'))
|
||||
.addParameter('expression', _('Application point on Y axis'))
|
||||
.setParameterLongDescription(_('Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'))
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('applyImpulseTowardPosition');
|
||||
|
||||
@@ -1611,7 +1623,7 @@ module.exports = {
|
||||
'ApplyTorque',
|
||||
_('Apply torque (rotational force)'),
|
||||
_(
|
||||
'Apply a torque (also called "rotational force") to the object. This will make the object rotate without moving it.'
|
||||
'Apply a torque (also called "rotational force") to the object. It "accelerates" an object rotation and must be used every frame during a time period.'
|
||||
),
|
||||
_('Apply to _PARAM0_ a torque of _PARAM2_'),
|
||||
_('Forces & impulses'),
|
||||
@@ -1620,7 +1632,8 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter('expression', _('Torque (N.m)'))
|
||||
.addParameter('expression', _('Torque (N·m)'))
|
||||
.setParameterLongDescription(_('A torque is like a rotation acceleration but depends on the mass.'))
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('applyTorque');
|
||||
|
||||
@@ -1629,7 +1642,7 @@ module.exports = {
|
||||
'ApplyAngularImpulse',
|
||||
_('Apply angular impulse (rotational impulse)'),
|
||||
_(
|
||||
'Apply an angular impulse (also called a "rotational impulse") to the object. This will make the object rotate without moving it.'
|
||||
'Apply an angular impulse (also called a "rotational impulse") to the object. It instantly changes the rotation speed, to give an initial speed for instance.'
|
||||
),
|
||||
_('Apply to _PARAM0_ an angular impulse of _PARAM2_'),
|
||||
_('Forces & impulses'),
|
||||
@@ -1638,7 +1651,8 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||
.addParameter('expression', _('Angular impulse (N.m.s'))
|
||||
.addParameter('expression', _('Angular impulse (N·m·s'))
|
||||
.setParameterLongDescription(_('An impulse is like a rotation speed addition but depends on the mass.'))
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('applyAngularImpulse');
|
||||
|
||||
|
@@ -142,6 +142,23 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
||||
.AddParameter("expression", _("Radius (in pixels)"))
|
||||
.SetFunctionName("DrawRoundedRectangle");
|
||||
|
||||
obj.AddAction("ChamferRectangle",
|
||||
_("Chamfer Rectangle"),
|
||||
_("Draw a chamfer rectangle on screen"),
|
||||
_("Draw from _PARAM1_;_PARAM2_ to _PARAM3_;_PARAM4_ a chamfer "
|
||||
"rectangle (chamfer: _PARAM5_) "
|
||||
"with _PARAM0_"),
|
||||
_("Drawing"),
|
||||
"res/actions/chamferRectangle24.png",
|
||||
"res/actions/chamferRectangle.png")
|
||||
.AddParameter("object", _("Shape Painter object"), "Drawer")
|
||||
.AddParameter("expression", _("Left X position"))
|
||||
.AddParameter("expression", _("Top Y position"))
|
||||
.AddParameter("expression", _("Right X position"))
|
||||
.AddParameter("expression", _("Bottom Y position"))
|
||||
.AddParameter("expression", _("Chamfer (in pixels)"))
|
||||
.SetFunctionName("DrawChamferRectangle");
|
||||
|
||||
obj.AddAction(
|
||||
"Star",
|
||||
_("Star"),
|
||||
|
@@ -50,6 +50,8 @@ class PrimitiveDrawingJsExtension : public gd::PlatformExtension {
|
||||
GetAllActionsForObject(
|
||||
"PrimitiveDrawing::Drawer")["PrimitiveDrawing::RoundedRectangle"]
|
||||
.SetFunctionName("drawRoundedRectangle");
|
||||
GetAllActionsForObject("PrimitiveDrawing::Drawer")["PrimitiveDrawing::ChamferRectangle"]
|
||||
.SetFunctionName("drawChamferRectangle");
|
||||
GetAllActionsForObject("PrimitiveDrawing::Drawer")["PrimitiveDrawing::Star"]
|
||||
.SetFunctionName("drawStar");
|
||||
GetAllActionsForObject("PrimitiveDrawing::Drawer")["PrimitiveDrawing::Arc"]
|
||||
@@ -85,14 +87,7 @@ class PrimitiveDrawingJsExtension : public gd::PlatformExtension {
|
||||
"PrimitiveDrawing::Drawer")["PrimitiveDrawing::ClosePath"]
|
||||
.SetFunctionName("closePath");
|
||||
|
||||
GetAllActionsForObject(
|
||||
"PrimitiveDrawing::Drawer")["PrimitiveDrawing::Ellipse"]
|
||||
.SetFunctionName("drawEllipse");
|
||||
GetAllActionsForObject(
|
||||
"PrimitiveDrawing::Drawer")["PrimitiveDrawing::RoundedRectangle"]
|
||||
.SetFunctionName("drawRoundedRectangle");
|
||||
GetAllActionsForObject("PrimitiveDrawing::Drawer")["PrimitiveDrawing::Star"]
|
||||
.SetFunctionName("drawStar");
|
||||
|
||||
// These actions are not exposed yet as the way they work is unsure. See
|
||||
// https://github.com/4ian/GDevelop/pull/1256
|
||||
/*GetAllActionsForObject(
|
||||
|
@@ -136,6 +136,25 @@ namespace gdjs {
|
||||
this.invalidateBounds();
|
||||
}
|
||||
|
||||
drawChamferRectangle(
|
||||
x1: float,
|
||||
y1: float,
|
||||
x2: float,
|
||||
y2: float,
|
||||
chamfer: float
|
||||
) {
|
||||
this.updateOutline();
|
||||
this._graphics.beginFill(
|
||||
this._object._fillColor,
|
||||
this._object._fillOpacity / 255
|
||||
);
|
||||
//@ts-ignore from @pixi/graphics-extras
|
||||
this._graphics.drawChamferRect(x1, y1, x2 - x1, y2 - y1, chamfer);
|
||||
this._graphics.closePath();
|
||||
this._graphics.endFill();
|
||||
this.invalidateBounds();
|
||||
}
|
||||
|
||||
drawStar(
|
||||
x1: float,
|
||||
y1: float,
|
||||
|
@@ -221,6 +221,22 @@ namespace gdjs {
|
||||
);
|
||||
}
|
||||
|
||||
drawChamferRectangle(
|
||||
startX1: float,
|
||||
startY1: float,
|
||||
endX2: float,
|
||||
endY2: float,
|
||||
chamfer: float
|
||||
) {
|
||||
this._renderer.drawChamferRectangle(
|
||||
startX1,
|
||||
startY1,
|
||||
endX2,
|
||||
endY2,
|
||||
chamfer
|
||||
);
|
||||
}
|
||||
|
||||
drawStar(
|
||||
centerX: float,
|
||||
centerY: float,
|
||||
|
@@ -96,7 +96,6 @@ module.exports = {
|
||||
.setParameterLongDescription(_('From 0 to 1.'))
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.ease');
|
||||
|
||||
// Deprecated
|
||||
@@ -124,6 +123,7 @@ module.exports = {
|
||||
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.tweenVariableNumber');
|
||||
|
||||
@@ -151,6 +151,7 @@ module.exports = {
|
||||
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.tweenVariableNumber2');
|
||||
|
||||
@@ -177,6 +178,7 @@ module.exports = {
|
||||
.addParameter('expression', _('Duration (in seconds)'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.tweenVariableNumber3');
|
||||
|
||||
@@ -206,6 +208,7 @@ module.exports = {
|
||||
.markAsAdvanced()
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.addLayoutValueTween');
|
||||
|
||||
@@ -236,6 +239,7 @@ module.exports = {
|
||||
.markAsAdvanced()
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.addLayerValueTween');
|
||||
|
||||
@@ -262,6 +266,7 @@ module.exports = {
|
||||
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.tweenCamera');
|
||||
|
||||
@@ -287,6 +292,7 @@ module.exports = {
|
||||
.addParameter('expression', _('Duration (in seconds)'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.tweenCamera2');
|
||||
|
||||
@@ -312,6 +318,7 @@ module.exports = {
|
||||
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.tweenCameraZoom');
|
||||
|
||||
@@ -336,6 +343,7 @@ module.exports = {
|
||||
.addParameter('expression', _('Duration (in seconds)'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.tweenCameraZoom2');
|
||||
|
||||
@@ -361,6 +369,7 @@ module.exports = {
|
||||
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.tweenCameraRotation');
|
||||
|
||||
@@ -385,6 +394,7 @@ module.exports = {
|
||||
.addParameter('expression', _('Duration (in seconds)'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.tweenCameraRotation2');
|
||||
|
||||
@@ -402,6 +412,7 @@ module.exports = {
|
||||
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.sceneTweenExists');
|
||||
|
||||
@@ -419,6 +430,7 @@ module.exports = {
|
||||
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.sceneTweenIsPlaying');
|
||||
|
||||
@@ -436,6 +448,7 @@ module.exports = {
|
||||
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.sceneTweenHasFinished');
|
||||
|
||||
@@ -453,6 +466,7 @@ module.exports = {
|
||||
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.pauseSceneTween');
|
||||
|
||||
@@ -471,6 +485,7 @@ module.exports = {
|
||||
.addParameter('yesorno', _('Jump to the end'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.stopSceneTween');
|
||||
|
||||
@@ -488,6 +503,7 @@ module.exports = {
|
||||
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.resumeSceneTween');
|
||||
|
||||
@@ -507,6 +523,7 @@ module.exports = {
|
||||
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.removeSceneTween');
|
||||
|
||||
@@ -521,8 +538,11 @@ module.exports = {
|
||||
'JsPlatform/Extensions/tween_behavior32.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
|
||||
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.getProgress');
|
||||
|
||||
extension
|
||||
@@ -536,8 +556,11 @@ module.exports = {
|
||||
'JsPlatform/Extensions/tween_behavior32.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
|
||||
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/standard-easing-functions.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweenruntimebehavior.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.getValue');
|
||||
|
||||
const tweenBehavior = new gd.BehaviorJsImplementation();
|
||||
@@ -1189,7 +1212,7 @@ module.exports = {
|
||||
'AddObjectScaleTween2',
|
||||
_('Tween object scale'),
|
||||
_(
|
||||
'Tweens an object scale from its current scale to a new one (note: the scale can never be less than 0).'
|
||||
'Tweens an object scale from its current scale to a new one (note: the scale can never be 0 or less).'
|
||||
),
|
||||
_(
|
||||
'Tween the scale of _PARAM0_ to X-scale: _PARAM3_, Y-scale: _PARAM4_ (from center: _PARAM8_) with easing _PARAM5_ over _PARAM6_ seconds as _PARAM2_'
|
||||
|
@@ -18,6 +18,29 @@
|
||||
namespace gdjs {
|
||||
export namespace evtTools {
|
||||
export namespace tween {
|
||||
/**
|
||||
* Tween between 2 values according to an easing function.
|
||||
* @param fromValue Start value
|
||||
* @param toValue End value
|
||||
* @param easingValue Type of easing
|
||||
* @param weighting from 0 to 1
|
||||
*/
|
||||
export const ease = (
|
||||
easingValue: string,
|
||||
fromValue: float,
|
||||
toValue: float,
|
||||
weighting: float
|
||||
) => {
|
||||
// This local declaration is needed because otherwise the transpiled
|
||||
// code doesn't know it.
|
||||
const easingFunctions = gdjs.evtTools.tween.easingFunctions;
|
||||
|
||||
const easingFunction = easingFunctions.hasOwnProperty(easingValue)
|
||||
? easingFunctions[easingValue]
|
||||
: easingFunctions.linear;
|
||||
return fromValue + (toValue - fromValue) * easingFunction(weighting);
|
||||
};
|
||||
|
||||
export type EasingFunction = (progress: float) => float;
|
||||
|
||||
export const easingFunctions: Record<string, EasingFunction> = {
|
||||
|
@@ -8,29 +8,6 @@ namespace gdjs {
|
||||
}
|
||||
export namespace evtTools {
|
||||
export namespace tween {
|
||||
/**
|
||||
* Tween between 2 values according to an easing function.
|
||||
* @param fromValue Start value
|
||||
* @param toValue End value
|
||||
* @param easingValue Type of easing
|
||||
* @param weighting from 0 to 1
|
||||
*/
|
||||
export const ease = (
|
||||
easingValue: string,
|
||||
fromValue: float,
|
||||
toValue: float,
|
||||
weighting: float
|
||||
) => {
|
||||
// This local declaration is needed because otherwise the transpiled
|
||||
// code doesn't know it.
|
||||
const easingFunctions = gdjs.evtTools.tween.easingFunctions;
|
||||
|
||||
const easingFunction = easingFunctions.hasOwnProperty(easingValue)
|
||||
? easingFunctions[easingValue]
|
||||
: easingFunctions.linear;
|
||||
return fromValue + (toValue - fromValue) * easingFunction(weighting);
|
||||
};
|
||||
|
||||
export const getTweensMap = (runtimeScene: RuntimeScene) =>
|
||||
runtimeScene._tweens ||
|
||||
(runtimeScene._tweens = new gdjs.TweenRuntimeBehavior.TweenManager());
|
||||
|
@@ -49,10 +49,11 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called when the object is removed from the scene: will pause the video.
|
||||
* To be called when the object is removed from the scene: will stop the video
|
||||
* (goes back to beginning).
|
||||
*/
|
||||
onDestroy() {
|
||||
this.pause();
|
||||
this.stop();
|
||||
}
|
||||
|
||||
ensureUpToDate() {
|
||||
@@ -172,6 +173,18 @@ namespace gdjs {
|
||||
source.pause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the video and comes back to first frame.
|
||||
*/
|
||||
stop() {
|
||||
const source = this._getHTMLVideoElementSource();
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
source.pause();
|
||||
source.currentTime = 0;
|
||||
}
|
||||
|
||||
// Autoplay was prevented.
|
||||
/**
|
||||
* Set the loop on video in renderer
|
||||
|
@@ -131,6 +131,9 @@ gd::ObjectMetadata &MetadataDeclarationHelper::DeclareObjectMetadata(
|
||||
.AddDefaultBehavior("ScalableCapability::ScalableBehavior")
|
||||
.AddDefaultBehavior("FlippableCapability::FlippableBehavior")
|
||||
.AddDefaultBehavior("OpacityCapability::OpacityBehavior");
|
||||
if (eventsBasedObject.IsRenderedIn3D()) {
|
||||
objectMetadata.MarkAsRenderedIn3D();
|
||||
}
|
||||
|
||||
// TODO EBO Use full type to identify object to avoid collision.
|
||||
// Objects are identified by their name alone.
|
||||
|
@@ -99,6 +99,28 @@ AdvancedExtension::AdvancedExtension() {
|
||||
"}\n";
|
||||
});
|
||||
|
||||
GetAllActions()["SetReturnObject"]
|
||||
.GetCodeExtraInformation()
|
||||
.SetCustomCodeGenerator([](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
gd::String objectsPickingCode;
|
||||
|
||||
for (const auto& objectName : codeGenerator.GetObjectsContainersList().ExpandObjectName(
|
||||
instruction.GetParameter(0).GetPlainString(), context.GetCurrentObject())) {
|
||||
const gd::String& objectNameString = codeGenerator.ConvertToStringExplicit(objectName);
|
||||
const gd::String& objectList = codeGenerator.GetObjectListName(objectName, context);
|
||||
objectsPickingCode += "gdjs.evtTools.object.pickObjects("
|
||||
"eventsFunctionContext.getObjectsLists(" +
|
||||
objectNameString + "), " + objectList + ");\n";
|
||||
}
|
||||
|
||||
return "if (typeof eventsFunctionContext !== 'undefined') {\n"
|
||||
" eventsFunctionContext.returnValue = true;\n"
|
||||
+ objectsPickingCode +
|
||||
"}\n";
|
||||
});
|
||||
|
||||
GetAllConditions()["GetArgumentAsBoolean"]
|
||||
.SetCustomCodeGenerator([](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
|
@@ -90,14 +90,10 @@ bool Exporter::ExportWholePixiProject(const ExportOptions &options) {
|
||||
fs, exportedProject.GetResourcesManager(), exportDir);
|
||||
// end of compatibility code
|
||||
|
||||
bool isUsingScene3DExtension =
|
||||
usedExtensionsResult.GetUsedExtensions().find("Scene3D") !=
|
||||
usedExtensionsResult.GetUsedExtensions().end();
|
||||
|
||||
// Export engine libraries
|
||||
helper.AddLibsInclude(
|
||||
/*pixiRenderers=*/true,
|
||||
/*pixiInThreeRenderers=*/isUsingScene3DExtension,
|
||||
usedExtensionsResult.Has3DObjects(),
|
||||
/*includeWebsocketDebuggerClient=*/false,
|
||||
/*includeWindowMessageDebuggerClient=*/false,
|
||||
exportedProject.GetLoadingScreen().GetGDevelopLogoStyle(),
|
||||
|
@@ -146,13 +146,9 @@ bool ExporterHelper::ExportProjectForPixiPreview(
|
||||
auto usedExtensionsResult =
|
||||
gd::UsedExtensionsFinder::ScanProject(exportedProject);
|
||||
|
||||
bool isUsingScene3DExtension =
|
||||
usedExtensionsResult.GetUsedExtensions().find("Scene3D") !=
|
||||
usedExtensionsResult.GetUsedExtensions().end();
|
||||
|
||||
// Export engine libraries
|
||||
AddLibsInclude(/*pixiRenderers=*/true,
|
||||
/*pixiInThreeRenderers=*/isUsingScene3DExtension,
|
||||
usedExtensionsResult.Has3DObjects(),
|
||||
/*includeWebsocketDebuggerClient=*/
|
||||
!options.websocketDebuggerServerAddress.empty(),
|
||||
/*includeWindowMessageDebuggerClient=*/
|
||||
|
@@ -218,6 +218,37 @@ namespace gdjs {
|
||||
arr.length = finalSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pick the objects from a given `Array`.
|
||||
* @param objectsLists the picking list to filter
|
||||
* @param objects the objects to pick
|
||||
*/
|
||||
export const pickObjects = (
|
||||
objectsLists: ObjectsLists,
|
||||
objects: gdjs.RuntimeObject[]
|
||||
) => {
|
||||
// Clear the `pick` flag on every objects.
|
||||
for (const objectsName in objectsLists.items) {
|
||||
if (objectsLists.items.hasOwnProperty(objectsName)) {
|
||||
for (const object of objectsLists.items[objectsName]) {
|
||||
object.pick = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Mark objects that need to be picked.
|
||||
for (const object of objects) {
|
||||
object.pick = true;
|
||||
}
|
||||
// Trim not picked objects from lists.
|
||||
for (const objectsName in objectsLists.items) {
|
||||
if (objectsLists.items.hasOwnProperty(objectsName)) {
|
||||
gdjs.evtTools.object.filterPickedObjectsList(
|
||||
objectsLists.items[objectsName]
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const hitBoxesCollisionTest = function (
|
||||
objectsLists1: ObjectsLists,
|
||||
objectsLists2: ObjectsLists,
|
||||
|
2
GDJS/package-lock.json
generated
2
GDJS/package-lock.json
generated
@@ -3489,4 +3489,4 @@
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -86,6 +86,28 @@ describe('gdjs.evtTools.object.pickObjectsIf', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('gdjs.evtTools.object.pickObjects', function() {
|
||||
it('should properly pick objects', function(){
|
||||
const runtimeScene = new gdjs.RuntimeScene(null);
|
||||
const objectA1 = new gdjs.RuntimeObject(runtimeScene, {name: "ObjectA", type: "", behaviors: [], effects: []});
|
||||
const objectA2 = new gdjs.RuntimeObject(runtimeScene, {name: "ObjectA", type: "", behaviors: [], effects: []});
|
||||
const objectA3 = new gdjs.RuntimeObject(runtimeScene, {name: "ObjectA", type: "", behaviors: [], effects: []});
|
||||
const objectB1 = new gdjs.RuntimeObject(runtimeScene, {name: "ObjectB", type: "", behaviors: [], effects: []});
|
||||
const objectB2 = new gdjs.RuntimeObject(runtimeScene, {name: "ObjectB", type: "", behaviors: [], effects: []});
|
||||
|
||||
const pickedObjectMap = Hashtable.newFrom({
|
||||
ObjectA: [objectA1, objectA2, objectA3],
|
||||
ObjectB: [objectB1, objectB2]
|
||||
});
|
||||
|
||||
gdjs.evtTools.object.pickObjects(pickedObjectMap, [objectA3, objectB2, objectA1]);
|
||||
expect(pickedObjectMap.get("ObjectA")).to.have.length(2);
|
||||
expect(pickedObjectMap.get("ObjectB")).to.have.length(1);
|
||||
expect(pickedObjectMap.get("ObjectA")).to.eql([objectA1, objectA3]);
|
||||
expect(pickedObjectMap.get("ObjectB")).to.eql([objectB2]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('gdjs.evtTools.object.pickRandomObject', function() {
|
||||
it('should pick only one object', function(){
|
||||
var runtimeScene = new gdjs.RuntimeScene(null);
|
||||
|
@@ -1716,6 +1716,9 @@ interface ObjectMetadata {
|
||||
|
||||
[Ref] ObjectMetadata SetHidden();
|
||||
boolean IsHidden();
|
||||
|
||||
[Ref] ObjectMetadata MarkAsRenderedIn3D();
|
||||
boolean IsRenderedIn3D();
|
||||
};
|
||||
|
||||
interface BehaviorMetadata {
|
||||
@@ -2768,6 +2771,9 @@ interface EventsBasedObject {
|
||||
[Ref] EventsBasedObject SetDefaultName([Const] DOMString defaultName);
|
||||
[Const, Ref] DOMString GetDefaultName();
|
||||
|
||||
[Ref] EventsBasedObject MarkAsRenderedIn3D(boolean isRenderedIn3D);
|
||||
boolean IsRenderedIn3D();
|
||||
|
||||
[Const, Value] DOMString STATIC_GetPropertyActionName([Const] DOMString propertyName);
|
||||
[Const, Value] DOMString STATIC_GetPropertyConditionName([Const] DOMString propertyName);
|
||||
[Const, Value] DOMString STATIC_GetPropertyExpressionName([Const] DOMString propertyName);
|
||||
|
@@ -290,6 +290,22 @@ class VariablesContainer {
|
||||
has(variableName) {
|
||||
return this._variables.containsKey(variableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {Variable} newVariable
|
||||
*/
|
||||
add(name, newVariable) {
|
||||
const oldVariable = this._variables.get(name);
|
||||
|
||||
this._variables.put(name, newVariable);
|
||||
if (oldVariable) {
|
||||
const variableIndex = this._variablesArray.indexOf(oldVariable);
|
||||
if (variableIndex !== -1) {
|
||||
this._variablesArray[variableIndex] = newVariable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RuntimeObject {
|
||||
@@ -565,6 +581,54 @@ const getPickedInstancesCount = (objectsLists) => {
|
||||
return count;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {RuntimeObject[]} arr
|
||||
*/
|
||||
const filterPickedObjectsList = function (
|
||||
arr
|
||||
) {
|
||||
let finalSize = 0;
|
||||
for (let k = 0, lenk = arr.length; k < lenk; ++k) {
|
||||
const obj = arr[k];
|
||||
if (obj.pick) {
|
||||
arr[finalSize] = obj;
|
||||
finalSize++;
|
||||
}
|
||||
}
|
||||
arr.length = finalSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Hashtable<RuntimeObject[]>} objectsLists
|
||||
* @param {RuntimeObject[]} objects
|
||||
*/
|
||||
const pickObjects = (
|
||||
objectsLists,
|
||||
objects
|
||||
) => {
|
||||
// Clear the `pick` flag on every objects.
|
||||
for (const objectsName in objectsLists.items) {
|
||||
if (objectsLists.items.hasOwnProperty(objectsName)) {
|
||||
for (const object of objectsLists.items[objectsName]) {
|
||||
object.pick = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Mark objects that need to be picked.
|
||||
for (const object of objects) {
|
||||
object.pick = true;
|
||||
}
|
||||
// Trim not picked objects from lists.
|
||||
for (const objectsName in objectsLists.items) {
|
||||
if (objectsLists.items.hasOwnProperty(objectsName)) {
|
||||
filterPickedObjectsList(
|
||||
objectsLists.items[objectsName]
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** A minimal implementation of gdjs.RuntimeScene for testing. */
|
||||
class RuntimeScene {
|
||||
constructor(sceneData) {
|
||||
@@ -729,6 +793,7 @@ function makeMinimalGDJSMock(options) {
|
||||
createObjectOnScene,
|
||||
getSceneInstancesCount,
|
||||
getPickedInstancesCount,
|
||||
pickObjects,
|
||||
},
|
||||
runtimeScene: {
|
||||
wait: () => new FakeAsyncTask(),
|
||||
|
@@ -219,4 +219,121 @@ describe('libGD.js - GDJS Code Generation integration tests', function () {
|
||||
.getAsNumber()
|
||||
).toBe(123);
|
||||
});
|
||||
|
||||
it('can generate function returning objects', function () {
|
||||
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
|
||||
|
||||
const myObjectA1 = runtimeScene.createObject('MyObjectA');
|
||||
const myObjectA2 = runtimeScene.createObject('MyObjectA');
|
||||
const myObjectB1 = runtimeScene.createObject('MyObjectB');
|
||||
const myObjectB2 = runtimeScene.createObject('MyObjectB');
|
||||
const myObjectB3 = runtimeScene.createObject('MyObjectB');
|
||||
|
||||
const variableA1 = new gdjs.Variable();
|
||||
variableA1.setNumber(1);
|
||||
myObjectA1.getVariables().add('Pick', variableA1);
|
||||
const variableB3 = new gdjs.Variable();
|
||||
variableB3.setNumber(1);
|
||||
myObjectB3.getVariables().add('Pick', variableB3);
|
||||
|
||||
// Run the function passing some objects as parameters.
|
||||
const objectsLists = gdjs.Hashtable.newFrom({
|
||||
MyObjectA: [myObjectA1],
|
||||
MyObjectB: [myObjectB2, myObjectB3],
|
||||
MyObjectC: [],
|
||||
});
|
||||
|
||||
const serializerElement = gd.Serializer.fromJSObject([
|
||||
{
|
||||
type: 'BuiltinCommonInstructions::Standard',
|
||||
conditions: [
|
||||
{
|
||||
type: { value: 'VarObjet' },
|
||||
parameters: ["Object","Pick","!=","0"],
|
||||
},
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
type: { value: 'SetReturnObject' },
|
||||
parameters: ['Object'],
|
||||
},
|
||||
],
|
||||
events: [],
|
||||
},
|
||||
]);
|
||||
const runCompiledEvents = generateCompiledEventsFromSerializedEvents(
|
||||
gd,
|
||||
serializerElement,
|
||||
{ parameterTypes: { Object: 'object' }, logCode: false }
|
||||
);
|
||||
runCompiledEvents(gdjs, runtimeScene, [objectsLists]);
|
||||
|
||||
expect(objectsLists.get('MyObjectA')).toEqual([myObjectA1]);
|
||||
expect(objectsLists.get('MyObjectB')).toEqual([myObjectB3]);
|
||||
expect(objectsLists.get('MyObjectC')).toEqual([]);
|
||||
});
|
||||
|
||||
it('can generate function creating 2 instances and returning only one', function () {
|
||||
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
|
||||
|
||||
const myObjectA1 = runtimeScene.createObject('MyObjectA');
|
||||
const myObjectA2 = runtimeScene.createObject('MyObjectA');
|
||||
const myObjectB1 = runtimeScene.createObject('MyObjectB');
|
||||
|
||||
// According to the parameter type objectListOrEmptyIfJustDeclared,
|
||||
// no instances is passed to the function because the ObjectsLists has not
|
||||
// been filtered before.
|
||||
const objectsLists = gdjs.Hashtable.newFrom({
|
||||
MyObjectA: [],
|
||||
MyObjectB: [],
|
||||
MyObjectC: [],
|
||||
});
|
||||
|
||||
const serializerElement = gd.Serializer.fromJSObject([
|
||||
{
|
||||
type: 'BuiltinCommonInstructions::Standard',
|
||||
conditions: [
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
type: { value: 'Create' },
|
||||
parameters: ['', 'Object', '0','0',''],
|
||||
},
|
||||
{
|
||||
type: {'value':'ModVarObjet'},
|
||||
parameters: ['Object','Pick','=','1']
|
||||
},
|
||||
{
|
||||
type: { value: 'Create' },
|
||||
parameters: ['', 'Object', '0','0',''],
|
||||
},
|
||||
],
|
||||
events: [],
|
||||
},
|
||||
{
|
||||
type: 'BuiltinCommonInstructions::Standard',
|
||||
conditions: [
|
||||
{
|
||||
type: { value: 'VarObjet' },
|
||||
parameters: ['Object','Pick','!=','0'],
|
||||
},
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
type: { value: 'SetReturnObject' },
|
||||
parameters: ['Object'],
|
||||
},
|
||||
],
|
||||
events: [],
|
||||
},
|
||||
]);
|
||||
const runCompiledEvents = generateCompiledEventsFromSerializedEvents(
|
||||
gd,
|
||||
serializerElement,
|
||||
{ parameterTypes: { Object: 'objectListOrEmptyIfJustDeclared' }, logCode: false }
|
||||
);
|
||||
runCompiledEvents(gdjs, runtimeScene, [objectsLists]);
|
||||
|
||||
expect(objectsLists.get('MyObjectA').length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
@@ -9,6 +9,8 @@ declare class gdEventsBasedObject extends gdAbstractEventsBasedEntity {
|
||||
getFullName(): string;
|
||||
setDefaultName(defaultName: string): gdEventsBasedObject;
|
||||
getDefaultName(): string;
|
||||
markAsRenderedIn3D(isRenderedIn3D: boolean): gdEventsBasedObject;
|
||||
isRenderedIn3D(): boolean;
|
||||
static getPropertyActionName(propertyName: string): string;
|
||||
static getPropertyConditionName(propertyName: string): string;
|
||||
static getPropertyExpressionName(propertyName: string): string;
|
||||
|
@@ -26,6 +26,8 @@ declare class gdObjectMetadata {
|
||||
addDefaultBehavior(behaviorType: string): gdObjectMetadata;
|
||||
setHidden(): gdObjectMetadata;
|
||||
isHidden(): boolean;
|
||||
markAsRenderedIn3D(): gdObjectMetadata;
|
||||
isRenderedIn3D(): boolean;
|
||||
delete(): void;
|
||||
ptr: number;
|
||||
};
|
BIN
newIDE/app/public/res/actions/chamferRectangle.png
Normal file
BIN
newIDE/app/public/res/actions/chamferRectangle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 619 B |
BIN
newIDE/app/public/res/actions/chamferRectangle24.png
Normal file
BIN
newIDE/app/public/res/actions/chamferRectangle24.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1020 B |
@@ -139,6 +139,12 @@ const getMergedInstalledWithDefaultEnumeratedObjectMetadataByCategory = ({
|
||||
{
|
||||
name: 'PanelSpriteObject::PanelSprite',
|
||||
},
|
||||
{
|
||||
name: 'Scene3D::Cube3DObject',
|
||||
},
|
||||
{
|
||||
name: 'Scene3D::Model3DObject',
|
||||
},
|
||||
],
|
||||
[translateExtensionCategory('Input', i18n)]: [
|
||||
{
|
||||
@@ -257,6 +263,24 @@ const getMergedInstalledWithDefaultEnumeratedObjectMetadataByCategory = ({
|
||||
},
|
||||
{
|
||||
name: 'ParticleSystem::ParticleEmitter',
|
||||
assetStorePackTag: 'particles emitter',
|
||||
requiredExtensions: [],
|
||||
},
|
||||
{
|
||||
name: 'ParticleEmitter3D::ParticleEmitter3D',
|
||||
fullName: i18n._(t`3D particle emitter`),
|
||||
description: i18n._(
|
||||
t`Displays a large number of particles to create visual effects.`
|
||||
),
|
||||
iconFilename:
|
||||
'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLWZpcmUiIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTcuNjYgMTEuMkMxNy40MyAxMC45IDE3LjE1IDEwLjY0IDE2Ljg5IDEwLjM4QzE2LjIyIDkuNzggMTUuNDYgOS4zNSAxNC44MiA4LjcyQzEzLjMzIDcuMjYgMTMgNC44NSAxMy45NSAzQzEzIDMuMjMgMTIuMTcgMy43NSAxMS40NiA0LjMyQzguODcgNi40IDcuODUgMTAuMDcgOS4wNyAxMy4yMkM5LjExIDEzLjMyIDkuMTUgMTMuNDIgOS4xNSAxMy41NUM5LjE1IDEzLjc3IDkgMTMuOTcgOC44IDE0LjA1QzguNTcgMTQuMTUgOC4zMyAxNC4wOSA4LjE0IDEzLjkzQzguMDggMTMuODggOC4wNCAxMy44MyA4IDEzLjc2QzYuODcgMTIuMzMgNi42OSAxMC4yOCA3LjQ1IDguNjRDNS43OCAxMCA0Ljg3IDEyLjMgNSAxNC40N0M1LjA2IDE0Ljk3IDUuMTIgMTUuNDcgNS4yOSAxNS45N0M1LjQzIDE2LjU3IDUuNyAxNy4xNyA2IDE3LjdDNy4wOCAxOS40MyA4Ljk1IDIwLjY3IDEwLjk2IDIwLjkyQzEzLjEgMjEuMTkgMTUuMzkgMjAuOCAxNy4wMyAxOS4zMkMxOC44NiAxNy42NiAxOS41IDE1IDE4LjU2IDEyLjcyTDE4LjQzIDEyLjQ2QzE4LjIyIDEyIDE3LjY2IDExLjIgMTcuNjYgMTEuMk0xNC41IDE3LjVDMTQuMjIgMTcuNzQgMTMuNzYgMTggMTMuNCAxOC4xQzEyLjI4IDE4LjUgMTEuMTYgMTcuOTQgMTAuNSAxNy4yOEMxMS42OSAxNyAxMi40IDE2LjEyIDEyLjYxIDE1LjIzQzEyLjc4IDE0LjQzIDEyLjQ2IDEzLjc3IDEyLjMzIDEzQzEyLjIxIDEyLjI2IDEyLjIzIDExLjYzIDEyLjUgMTAuOTRDMTIuNjkgMTEuMzIgMTIuODkgMTEuNyAxMy4xMyAxMkMxMy45IDEzIDE1LjExIDEzLjQ0IDE1LjM3IDE0LjhDMTUuNDEgMTQuOTQgMTUuNDMgMTUuMDggMTUuNDMgMTUuMjNDMTUuNDYgMTYuMDUgMTUuMSAxNi45NSAxNC41IDE3LjVIMTQuNVoiIC8+PC9zdmc+',
|
||||
assetStorePackTag: '3d particles',
|
||||
requiredExtensions: [
|
||||
{
|
||||
extensionName: 'ParticleEmitter3D',
|
||||
extensionVersion: '1.0.0',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
[translateExtensionCategory('Advanced', i18n)]: [
|
||||
|
@@ -1,7 +1,6 @@
|
||||
// @flow
|
||||
import { Trans } from '@lingui/macro';
|
||||
import { t } from '@lingui/macro';
|
||||
import { I18n } from '@lingui/react';
|
||||
|
||||
import * as React from 'react';
|
||||
import TextField from '../UI/TextField';
|
||||
@@ -10,6 +9,7 @@ import DismissableAlertMessage from '../UI/DismissableAlertMessage';
|
||||
import AlertMessage from '../UI/AlertMessage';
|
||||
import { ColumnStackLayout } from '../UI/Layout';
|
||||
import useForceUpdate from '../Utils/UseForceUpdate';
|
||||
import Checkbox from '../UI/Checkbox';
|
||||
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
@@ -69,22 +69,26 @@ export default function EventsBasedObjectEditor({ eventsBasedObject }: Props) {
|
||||
fullWidth
|
||||
rows={3}
|
||||
/>
|
||||
<I18n>
|
||||
{({ i18n }) => (
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Default name for created objects</Trans>}
|
||||
value={
|
||||
eventsBasedObject.getDefaultName() || eventsBasedObject.getName()
|
||||
}
|
||||
onChange={newName => {
|
||||
eventsBasedObject.setDefaultName(gd.Project.getSafeName(newName));
|
||||
forceUpdate();
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
</I18n>
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Default name for created objects</Trans>}
|
||||
value={
|
||||
eventsBasedObject.getDefaultName() || eventsBasedObject.getName()
|
||||
}
|
||||
onChange={newName => {
|
||||
eventsBasedObject.setDefaultName(gd.Project.getSafeName(newName));
|
||||
forceUpdate();
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
<Checkbox
|
||||
label={<Trans>Use 3D rendering</Trans>}
|
||||
checked={eventsBasedObject.isRenderedIn3D()}
|
||||
onCheck={(e, checked) => {
|
||||
eventsBasedObject.markAsRenderedIn3D(checked);
|
||||
forceUpdate();
|
||||
}}
|
||||
/>
|
||||
{eventsBasedObject.getEventsFunctions().getEventsFunctionsCount() ===
|
||||
0 && (
|
||||
<DismissableAlertMessage
|
||||
|
@@ -2,7 +2,7 @@
|
||||
import * as React from 'react';
|
||||
import {
|
||||
enumerateObjectAndBehaviorsInstructions,
|
||||
enumerateAllInstructions,
|
||||
isObjectInstruction,
|
||||
getObjectParameterIndex,
|
||||
} from '../../InstructionOrExpression/EnumerateInstructions';
|
||||
import {
|
||||
@@ -129,19 +129,25 @@ export const useInstructionEditor = ({
|
||||
if (!isNewInstruction) {
|
||||
// Check if the instruction is an object/behavior instruction. If yes
|
||||
// select the object, which is the first parameter of the instruction.
|
||||
const allInstructions = enumerateAllInstructions(isCondition);
|
||||
const instructionType: string = instruction.getType();
|
||||
const enumeratedInstructionMetadata = findInstruction(
|
||||
allInstructions,
|
||||
instructionType
|
||||
);
|
||||
const instructionMetadata = isCondition
|
||||
? gd.MetadataProvider.getConditionMetadata(
|
||||
project.getCurrentPlatform(),
|
||||
instructionType
|
||||
)
|
||||
: gd.MetadataProvider.getActionMetadata(
|
||||
project.getCurrentPlatform(),
|
||||
instructionType
|
||||
);
|
||||
if (
|
||||
enumeratedInstructionMetadata &&
|
||||
(enumeratedInstructionMetadata.scope.objectMetadata ||
|
||||
enumeratedInstructionMetadata.scope.behaviorMetadata)
|
||||
isObjectInstruction(
|
||||
project.getCurrentPlatform(),
|
||||
instruction,
|
||||
isCondition
|
||||
)
|
||||
) {
|
||||
const objectParameterIndex = getObjectParameterIndex(
|
||||
enumeratedInstructionMetadata.metadata
|
||||
instructionMetadata
|
||||
);
|
||||
if (objectParameterIndex !== -1) {
|
||||
return getChosenObjectState(
|
||||
|
@@ -377,7 +377,7 @@ const InviteHome = ({ cloudProjectId }: Props) => {
|
||||
<GetSubscriptionCard subscriptionDialogOpeningReason="Add collaborators on project">
|
||||
<Text>
|
||||
<Trans>
|
||||
Get a startup subscription to invite collaborators on your
|
||||
Get a startup subscription to invite collaborators into your
|
||||
project.
|
||||
</Trans>
|
||||
</Text>
|
||||
|
@@ -68,6 +68,44 @@ const freeInstructionsToRemove = {
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns `true` if the instruction in shown as an object instruction.
|
||||
*/
|
||||
export const isObjectInstruction = (
|
||||
platform: gdPlatform,
|
||||
instruction: gdInstruction,
|
||||
isCondition: boolean
|
||||
) => {
|
||||
const instructionType: string = instruction.getType();
|
||||
const extensionAndInstructionMetadata = isCondition
|
||||
? gd.MetadataProvider.getExtensionAndConditionMetadata(
|
||||
platform,
|
||||
instructionType
|
||||
)
|
||||
: gd.MetadataProvider.getExtensionAndActionMetadata(
|
||||
platform,
|
||||
instructionType
|
||||
);
|
||||
const extension = extensionAndInstructionMetadata.getExtension();
|
||||
const instructionMetadata = extensionAndInstructionMetadata.getMetadata();
|
||||
for (const extensionName in freeInstructionsToRemove) {
|
||||
if (extensionName !== extension.getName()) {
|
||||
continue;
|
||||
}
|
||||
for (const instructionToRemoveName of freeInstructionsToRemove[
|
||||
extensionName
|
||||
]) {
|
||||
if (instructionType === instructionToRemoveName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (
|
||||
instructionMetadata.getParametersCount() >= 1 &&
|
||||
gd.ParameterMetadata.isObject(instructionMetadata.getParameter(0).getType())
|
||||
);
|
||||
};
|
||||
|
||||
export const getExtensionPrefix = (extension: gdPlatformExtension): string => {
|
||||
return extension.getCategory() + GROUP_DELIMITER + extension.getFullName();
|
||||
};
|
||||
|
@@ -49,6 +49,7 @@ import KeyboardShortcuts from '../UI/KeyboardShortcuts';
|
||||
import Link from '../UI/Link';
|
||||
import { getHelpLink } from '../Utils/HelpLink';
|
||||
import useAlertDialog from '../UI/Alert/useAlertDialog';
|
||||
import { useResponsiveWindowWidth } from '../UI/Reponsive/ResponsiveWindowMeasurer';
|
||||
|
||||
const gd: libGDevelop = global.gd;
|
||||
const sceneObjectsRootFolderId = 'scene-objects';
|
||||
@@ -264,6 +265,8 @@ const ObjectsList = React.forwardRef<Props, ObjectsListInterface>(
|
||||
const { showDeleteConfirmation } = useAlertDialog();
|
||||
const treeViewRef = React.useRef<?TreeViewInterface<TreeViewItem>>(null);
|
||||
const forceUpdate = useForceUpdate();
|
||||
const windowWidth = useResponsiveWindowWidth();
|
||||
const isMobileScreen = windowWidth === 'small';
|
||||
|
||||
const forceUpdateList = React.useCallback(
|
||||
() => {
|
||||
@@ -653,10 +656,17 @@ const ObjectsList = React.forwardRef<Props, ObjectsListInterface>(
|
||||
const editName = React.useCallback(
|
||||
(objectFolderOrObjectWithContext: ?ObjectFolderOrObjectWithContext) => {
|
||||
if (!objectFolderOrObjectWithContext) return;
|
||||
if (treeViewRef.current)
|
||||
treeViewRef.current.renameItem(objectFolderOrObjectWithContext);
|
||||
const treeView = treeViewRef.current;
|
||||
if (treeView) {
|
||||
if (isMobileScreen) {
|
||||
// Position item at top of the screen to make sure it will be visible
|
||||
// once the keyboard is open.
|
||||
treeView.scrollToItem(objectFolderOrObjectWithContext, 'start');
|
||||
}
|
||||
treeView.renameItem(objectFolderOrObjectWithContext);
|
||||
}
|
||||
},
|
||||
[]
|
||||
[isMobileScreen]
|
||||
);
|
||||
|
||||
const duplicateObject = React.useCallback(
|
||||
@@ -1533,7 +1543,6 @@ const ObjectsList = React.forwardRef<Props, ObjectsListInterface>(
|
||||
canMoveSelectionToItem={canMoveSelectionTo}
|
||||
reactDndType={objectWithContextReactDndType}
|
||||
initiallyOpenedNodeIds={initiallyOpenedNodeIds}
|
||||
renderHiddenElements={!!currentlyRunningInAppTutorial}
|
||||
arrowKeyNavigationProps={arrowKeyNavigationProps}
|
||||
/>
|
||||
)}
|
||||
|
@@ -639,7 +639,10 @@ export default class SceneEditor extends React.Component<Props, State> {
|
||||
|
||||
_onInstancesSelected = (instances: Array<gdInitialInstance>) => {
|
||||
if (instances.length === 0) {
|
||||
this.setState({ selectedObjectFolderOrObjectsWithContext: [] });
|
||||
this.setState(
|
||||
{ selectedObjectFolderOrObjectsWithContext: [] },
|
||||
this.updateToolbar
|
||||
);
|
||||
return;
|
||||
}
|
||||
const { project, layout } = this.props;
|
||||
@@ -648,27 +651,33 @@ export default class SceneEditor extends React.Component<Props, State> {
|
||||
const lastSelectedInstance = instances[instances.length - 1];
|
||||
const objectName = lastSelectedInstance.getObjectName();
|
||||
if (project.hasObjectNamed(objectName)) {
|
||||
this.setState({
|
||||
selectedObjectFolderOrObjectsWithContext: [
|
||||
{
|
||||
objectFolderOrObject: project
|
||||
.getRootFolder()
|
||||
.getObjectNamed(objectName),
|
||||
global: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
this.setState(
|
||||
{
|
||||
selectedObjectFolderOrObjectsWithContext: [
|
||||
{
|
||||
objectFolderOrObject: project
|
||||
.getRootFolder()
|
||||
.getObjectNamed(objectName),
|
||||
global: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
this.updateToolbar
|
||||
);
|
||||
} else if (layout.hasObjectNamed(objectName)) {
|
||||
this.setState({
|
||||
selectedObjectFolderOrObjectsWithContext: [
|
||||
{
|
||||
objectFolderOrObject: layout
|
||||
.getRootFolder()
|
||||
.getObjectNamed(objectName),
|
||||
global: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
this.setState(
|
||||
{
|
||||
selectedObjectFolderOrObjectsWithContext: [
|
||||
{
|
||||
objectFolderOrObject: layout
|
||||
.getRootFolder()
|
||||
.getObjectNamed(objectName),
|
||||
global: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
this.updateToolbar
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -79,7 +79,7 @@ export const getFuseSearchQueryForMultipleKeys = (
|
||||
});
|
||||
|
||||
return {
|
||||
$and: searchQuery,
|
||||
$or: searchQuery,
|
||||
};
|
||||
};
|
||||
|
||||
|
@@ -103,7 +103,7 @@ const getItemProps = memoizeOne(
|
||||
|
||||
export type TreeViewInterface<Item> = {|
|
||||
forceUpdateList: () => void,
|
||||
scrollToItem: Item => void,
|
||||
scrollToItem: (Item, placement?: 'smart' | 'start') => void,
|
||||
renameItem: Item => void,
|
||||
openItems: (string[]) => void,
|
||||
closeItems: (string[]) => void,
|
||||
@@ -136,7 +136,6 @@ type Props<Item> = {|
|
||||
reactDndType: string,
|
||||
forceAllOpened?: boolean,
|
||||
initiallyOpenedNodeIds?: string[],
|
||||
renderHiddenElements?: boolean,
|
||||
arrowKeyNavigationProps?: {|
|
||||
onGetItemInside: (item: Item) => ?Item,
|
||||
onGetItemOutside: (item: Item) => ?Item,
|
||||
@@ -166,7 +165,6 @@ const TreeView = <Item: ItemBaseAttributes>(
|
||||
reactDndType,
|
||||
forceAllOpened,
|
||||
initiallyOpenedNodeIds,
|
||||
renderHiddenElements,
|
||||
arrowKeyNavigationProps,
|
||||
}: Props<Item>,
|
||||
ref: TreeViewInterface<Item>
|
||||
@@ -365,7 +363,7 @@ const TreeView = <Item: ItemBaseAttributes>(
|
||||
);
|
||||
|
||||
const scrollToItem = React.useCallback(
|
||||
(item: Item) => {
|
||||
(item: Item, placement?: 'smart' | 'start' = 'smart') => {
|
||||
const list = listRef.current;
|
||||
if (list) {
|
||||
const itemId = getItemId(item);
|
||||
@@ -374,7 +372,7 @@ const TreeView = <Item: ItemBaseAttributes>(
|
||||
// $FlowFixMe - Method introduced in 2022.
|
||||
const index = flattenedData.findLastIndex(node => node.id === itemId);
|
||||
if (index >= 0) {
|
||||
list.scrollToItem(index, 'smart');
|
||||
list.scrollToItem(index, placement);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -637,7 +635,13 @@ const TreeView = <Item: ItemBaseAttributes>(
|
||||
// $FlowFixMe
|
||||
itemData={itemData}
|
||||
ref={listRef}
|
||||
overscanCount={renderHiddenElements ? 20 : 2}
|
||||
// Keep overscanCount relatively high so that:
|
||||
// - during in-app tutorials we make sure the tooltip displayer finds
|
||||
// the elements to highlight
|
||||
// - on mobile it avoids jumping screens. This can happen when an item
|
||||
// name is edited, the keyboard opens and reduces the window height
|
||||
// making the item disappear (because or virtualization).
|
||||
overscanCount={20}
|
||||
>
|
||||
{TreeViewRow}
|
||||
</FixedSizeList>
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"name": "gdevelop",
|
||||
"productName": "GDevelop 5",
|
||||
"description": "GDevelop 5 IDE - the open-source, cross-platform game engine designed for everyone",
|
||||
"version": "5.2.177",
|
||||
"version": "5.2.178",
|
||||
"author": "GDevelop Team <hello@gdevelop.io>",
|
||||
"license": "MIT",
|
||||
"homepage": "https://gdevelop.io",
|
||||
|
Reference in New Issue
Block a user