mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
28 Commits
v5.1.153
...
Expression
Author | SHA1 | Date | |
---|---|---|---|
![]() |
55fc686a5b | ||
![]() |
5580189f88 | ||
![]() |
9a6d1d6d32 | ||
![]() |
6c9739c01d | ||
![]() |
cd3c997b28 | ||
![]() |
8064c4de57 | ||
![]() |
8666851f54 | ||
![]() |
6d568b2f2c | ||
![]() |
180d4318aa | ||
![]() |
65a57f86da | ||
![]() |
6a3e7f9c58 | ||
![]() |
74f1d571ba | ||
![]() |
a7cb3fc5a2 | ||
![]() |
08d3c3323a | ||
![]() |
fec603b811 | ||
![]() |
d68affc117 | ||
![]() |
77cd6c44d6 | ||
![]() |
2b4c8813e4 | ||
![]() |
2ef9266ec4 | ||
![]() |
ceba6cf739 | ||
![]() |
18f2085de7 | ||
![]() |
b586fb87ed | ||
![]() |
8aed02ab17 | ||
![]() |
8c383fc448 | ||
![]() |
af3a2016f2 | ||
![]() |
7a20161794 | ||
![]() |
0feb4ef321 | ||
![]() |
5cbcd16523 |
@@ -670,18 +670,6 @@ gd::String EventsCodeGenerator::GenerateActionsListCode(
|
||||
return outputCode;
|
||||
}
|
||||
|
||||
const gd::String EventsCodeGenerator::GenerateRelationalOperatorCodes(const gd::String &operatorString) {
|
||||
if (operatorString == "=") {
|
||||
return "==";
|
||||
}
|
||||
if (operatorString != "<" && operatorString != ">" &&
|
||||
operatorString != "<=" && operatorString != ">=" && operatorString != "!=") {
|
||||
cout << "Warning: Bad relational operator: Set to == by default." << endl;
|
||||
return "==";
|
||||
}
|
||||
return operatorString;
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
const gd::Expression& parameter,
|
||||
const gd::ParameterMetadata& metadata,
|
||||
@@ -706,7 +694,14 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
argOutput =
|
||||
GenerateObject(parameter.GetPlainString(), metadata.GetType(), context);
|
||||
} else if (metadata.GetType() == "relationalOperator") {
|
||||
argOutput += GenerateRelationalOperatorCodes(parameter.GetPlainString());
|
||||
auto parameterString = parameter.GetPlainString();
|
||||
argOutput += parameterString == "=" ? "==" : parameterString;
|
||||
if (argOutput != "==" && argOutput != "<" && argOutput != ">" &&
|
||||
argOutput != "<=" && argOutput != ">=" && argOutput != "!=") {
|
||||
cout << "Warning: Bad relational operator: Set to == by default." << endl;
|
||||
argOutput = "==";
|
||||
}
|
||||
|
||||
argOutput = "\"" + argOutput + "\"";
|
||||
} else if (metadata.GetType() == "operator") {
|
||||
argOutput += parameter.GetPlainString();
|
||||
|
@@ -481,9 +481,6 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
*/
|
||||
size_t GenerateSingleUsageUniqueIdForEventsList();
|
||||
|
||||
virtual const gd::String GenerateRelationalOperatorCodes(
|
||||
const gd::String& operatorString);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief Generate the code for a single parameter.
|
||||
|
@@ -55,10 +55,6 @@ void Instruction::SetParameter(std::size_t nb, const gd::Expression& val) {
|
||||
parameters[nb] = val;
|
||||
}
|
||||
|
||||
void Instruction::AddParameter(const gd::Expression& val) {
|
||||
parameters.push_back(val);
|
||||
}
|
||||
|
||||
std::shared_ptr<Instruction> GD_CORE_API
|
||||
CloneRememberingOriginalElement(std::shared_ptr<Instruction> instruction) {
|
||||
std::shared_ptr<Instruction> copy =
|
||||
|
@@ -123,11 +123,6 @@ class GD_CORE_API Instruction {
|
||||
*/
|
||||
void SetParameter(std::size_t nb, const gd::Expression& val);
|
||||
|
||||
/** Add a parameter at the end
|
||||
* \param val The new value of the parameter
|
||||
*/
|
||||
void AddParameter(const gd::Expression& val);
|
||||
|
||||
/** \brief Get a reference to the std::vector containing the parameters.
|
||||
* \return A std::vector containing the parameters
|
||||
*/
|
||||
|
@@ -81,7 +81,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
.AddExpression(
|
||||
"GetArgumentAsNumber",
|
||||
_("Get function parameter value"),
|
||||
_("Get function parameter (also called \"argument\") value."),
|
||||
_("Get function parameter (also called \"argument\") value"),
|
||||
"",
|
||||
"res/function16.png")
|
||||
.AddParameter("functionParameterName", "Parameter name");
|
||||
@@ -90,34 +90,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
.AddStrExpression(
|
||||
"GetArgumentAsString",
|
||||
_("Get function parameter text"),
|
||||
_("Get function parameter (also called \"argument\") text."),
|
||||
_("Get function parameter (also called \"argument\") text "),
|
||||
"",
|
||||
"res/function16.png")
|
||||
.AddParameter("functionParameterName", "Parameter name");
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"CompareArgumentAsNumber",
|
||||
_("Compare function parameter value"),
|
||||
_("Compare function parameter (also called \"argument\") value."),
|
||||
_("Parameter _PARAM0_"),
|
||||
"",
|
||||
"res/function32.png",
|
||||
"res/function16.png")
|
||||
.AddParameter("functionParameterName", "Parameter name")
|
||||
.UseStandardRelationalOperatorParameters("number");
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"CompareArgumentAsString",
|
||||
_("Compare function parameter text"),
|
||||
_("Compare function parameter (also called \"argument\") text."),
|
||||
_("Parameter _PARAM0_"),
|
||||
"",
|
||||
"res/function32.png",
|
||||
"res/function16.png")
|
||||
.AddParameter("functionParameterName", "Parameter name")
|
||||
.UseStandardRelationalOperatorParameters("string");
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -96,7 +96,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
"JSONToVariableStructure",
|
||||
_("Convert JSON to a scene variable"),
|
||||
_("Parse a JSON object and store it into a scene variable"),
|
||||
_("Convert JSON string _PARAM0_ and store it into variable _PARAM1_"),
|
||||
_("Parse JSON string _PARAM0_ and store it into variable _PARAM1_"),
|
||||
"",
|
||||
"res/actions/net24.png",
|
||||
"res/actions/net.png")
|
||||
@@ -108,7 +108,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
.AddAction("JSONToGlobalVariableStructure",
|
||||
_("Convert JSON to global variable"),
|
||||
_("Parse a JSON object and store it into a global variable"),
|
||||
_("Convert JSON string _PARAM0_ and store it into global "
|
||||
_("Parse JSON string _PARAM0_ and store it into global "
|
||||
"variable _PARAM1_"),
|
||||
"",
|
||||
"res/actions/net24.png",
|
||||
|
@@ -492,16 +492,6 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.SetHelpPath("/all-features/expressions");
|
||||
|
||||
extension
|
||||
.AddExpression("lerpAngle",
|
||||
_("Lerp (Linear interpolation) between two angles"),
|
||||
_("Linearly interpolates between two angles (in degrees) by taking the shortest direction around the circle."),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Starting angle, in degrees"))
|
||||
.AddParameter("expression", _("Destination angle, in degrees"))
|
||||
.AddParameter("expression", _("Interpolation value between 0 and 1."));
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -324,19 +324,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
"res/conditions/animation24.png",
|
||||
"res/conditions/animation.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.MarkAsSimple()
|
||||
.SetHidden();
|
||||
|
||||
obj.AddCondition("AnimationEnded2",
|
||||
_("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"), "Sprite")
|
||||
.MarkAsSimple();
|
||||
|
||||
|
@@ -155,7 +155,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
"",
|
||||
"res/timer_black.svg",
|
||||
"res/timer_black.svg")
|
||||
.AddParameter("expression", _("Time to wait in seconds"))
|
||||
.AddParameter("expression", "Time to wait in seconds")
|
||||
.SetHelpPath("/all-features/timers-and-time/wait-action");
|
||||
|
||||
extension
|
||||
|
@@ -236,6 +236,7 @@ class GD_CORE_API BehaviorMetadata {
|
||||
}
|
||||
|
||||
const gd::String& GetName() const;
|
||||
#if defined(GD_IDE_ONLY)
|
||||
const gd::String& GetFullName() const { return fullname; }
|
||||
const gd::String& GetDefaultName() const { return defaultName; }
|
||||
const gd::String& GetDescription() const { return description; }
|
||||
@@ -256,21 +257,7 @@ class GD_CORE_API BehaviorMetadata {
|
||||
* \note An empty string means the base object, so any object.
|
||||
*/
|
||||
const gd::String& GetObjectType() const { return objectType; }
|
||||
|
||||
/**
|
||||
* Check if the behavior is private - it can't be used outside of its
|
||||
* extension.
|
||||
*/
|
||||
bool IsPrivate() const { return isPrivate; }
|
||||
|
||||
/**
|
||||
* Set that the behavior is private - it can't be used outside of its
|
||||
* extension.
|
||||
*/
|
||||
BehaviorMetadata &SetPrivate() {
|
||||
isPrivate = true;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Return the associated gd::Behavior, handling behavior contents.
|
||||
@@ -328,7 +315,6 @@ class GD_CORE_API BehaviorMetadata {
|
||||
gd::String group;
|
||||
gd::String iconFilename;
|
||||
gd::String objectType;
|
||||
bool isPrivate = false;
|
||||
|
||||
// TODO: Nitpicking: convert these to std::unique_ptr to clarify ownership.
|
||||
std::shared_ptr<gd::Behavior> instance;
|
||||
|
@@ -179,7 +179,8 @@ class GD_CORE_API MultipleInstructionMetadata {
|
||||
}
|
||||
|
||||
/**
|
||||
* \see gd::InstructionMetadata::SetPrivate
|
||||
* Set that the instruction is private - it can't be used outside of the
|
||||
* object/ behavior that it is attached too.
|
||||
*/
|
||||
MultipleInstructionMetadata &SetPrivate() {
|
||||
if (expression)
|
||||
|
@@ -15,12 +15,9 @@ ParameterMetadata::ParameterMetadata() : codeOnly(false) {}
|
||||
void ParameterMetadata::SerializeTo(SerializerElement& element) const {
|
||||
valueTypeMetadata.SerializeTo(element);
|
||||
element.SetAttribute("description", description);
|
||||
if (!longDescription.empty()) {
|
||||
element.SetAttribute("longDescription", longDescription);
|
||||
}
|
||||
if (codeOnly) {
|
||||
element.SetAttribute("codeOnly", codeOnly);
|
||||
}
|
||||
element.SetAttribute("longDescription", longDescription);
|
||||
element.SetAttribute("codeOnly", codeOnly);
|
||||
element.SetAttribute("defaultValue", defaultValue);
|
||||
element.SetAttribute("name", name);
|
||||
}
|
||||
|
||||
@@ -29,6 +26,7 @@ void ParameterMetadata::UnserializeFrom(const SerializerElement& element) {
|
||||
description = element.GetStringAttribute("description");
|
||||
longDescription = element.GetStringAttribute("longDescription");
|
||||
codeOnly = element.GetBoolAttribute("codeOnly");
|
||||
defaultValue = element.GetStringAttribute("defaultValue");
|
||||
name = element.GetStringAttribute("name");
|
||||
}
|
||||
|
||||
|
@@ -144,15 +144,13 @@ class GD_CORE_API ParameterMetadata {
|
||||
/**
|
||||
* \brief Get the default value for the parameter.
|
||||
*/
|
||||
const gd::String &GetDefaultValue() const {
|
||||
return valueTypeMetadata.GetDefaultValue();
|
||||
}
|
||||
const gd::String &GetDefaultValue() const { return defaultValue; }
|
||||
|
||||
/**
|
||||
* \brief Set the default value, if the parameter is optional.
|
||||
*/
|
||||
ParameterMetadata &SetDefaultValue(const gd::String &defaultValue_) {
|
||||
valueTypeMetadata.SetDefaultValue(defaultValue_);
|
||||
defaultValue = defaultValue_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -238,6 +236,8 @@ class GD_CORE_API ParameterMetadata {
|
||||
private:
|
||||
gd::ValueTypeMetadata valueTypeMetadata; ///< Parameter type
|
||||
gd::String longDescription; ///< Long description shown in the editor.
|
||||
gd::String defaultValue; ///< Used as a default value in editor or if an
|
||||
///< optional parameter is empty.
|
||||
gd::String name; ///< The name of the parameter to be used in code
|
||||
///< generation. Optional.
|
||||
};
|
||||
|
@@ -46,25 +46,4 @@ const gd::String &ValueTypeMetadata::GetPrimitiveValueType(const gd::String &par
|
||||
return parameterType;
|
||||
}
|
||||
|
||||
const gd::String ValueTypeMetadata::numberValueType = "number";
|
||||
const gd::String ValueTypeMetadata::booleanValueType = "boolean";
|
||||
const gd::String ValueTypeMetadata::colorValueType = "color";
|
||||
const gd::String ValueTypeMetadata::choiceValueType = "stringWithSelector";
|
||||
const gd::String ValueTypeMetadata::stringValueType = "string";
|
||||
|
||||
const gd::String &ValueTypeMetadata::ConvertPropertyTypeToValueType(
|
||||
const gd::String &propertyType) {
|
||||
if (propertyType == "Number") {
|
||||
return numberValueType;
|
||||
} else if (propertyType == "Boolean") {
|
||||
return booleanValueType;
|
||||
} else if (propertyType == "Color") {
|
||||
return colorValueType;
|
||||
} else if (propertyType == "Choice") {
|
||||
return choiceValueType;
|
||||
}
|
||||
// For "String" or default
|
||||
return stringValueType;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -192,12 +192,6 @@ class GD_CORE_API ValueTypeMetadata {
|
||||
static const gd::String numberType;
|
||||
static const gd::String stringType;
|
||||
|
||||
/**
|
||||
* \brief Return the ValueTypeMetadata name for a property type.
|
||||
* \see gd::PropertyDescriptor
|
||||
*/
|
||||
static const gd::String &ConvertPropertyTypeToValueType(const gd::String &propertyType);
|
||||
|
||||
/** \name Serialization
|
||||
*/
|
||||
///@{
|
||||
@@ -218,12 +212,6 @@ class GD_CORE_API ValueTypeMetadata {
|
||||
bool optional; ///< True if the parameter is optional
|
||||
gd::String defaultValue; ///< Used as a default value in editor or if an
|
||||
///< optional parameter is empty.
|
||||
|
||||
static const gd::String numberValueType;
|
||||
static const gd::String booleanValueType;
|
||||
static const gd::String colorValueType;
|
||||
static const gd::String choiceValueType;
|
||||
static const gd::String stringValueType;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -24,12 +24,14 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
std::map<gd::String, gd::InstructionMetadata>
|
||||
PlatformExtension::badConditionsMetadata;
|
||||
std::map<gd::String, gd::InstructionMetadata>
|
||||
PlatformExtension::badActionsMetadata;
|
||||
std::map<gd::String, gd::ExpressionMetadata>
|
||||
PlatformExtension::badExpressionsMetadata;
|
||||
#endif
|
||||
|
||||
gd::InstructionMetadata& PlatformExtension::AddCondition(
|
||||
const gd::String& name,
|
||||
@@ -39,6 +41,7 @@ gd::InstructionMetadata& PlatformExtension::AddCondition(
|
||||
const gd::String& group,
|
||||
const gd::String& icon,
|
||||
const gd::String& smallicon) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gd::String nameWithNamespace = GetNameSpace() + name;
|
||||
conditionsInfos[nameWithNamespace] = InstructionMetadata(GetNameSpace(),
|
||||
nameWithNamespace,
|
||||
@@ -50,6 +53,7 @@ gd::InstructionMetadata& PlatformExtension::AddCondition(
|
||||
smallicon)
|
||||
.SetHelpPath(GetHelpPath());
|
||||
return conditionsInfos[nameWithNamespace];
|
||||
#endif
|
||||
}
|
||||
|
||||
gd::InstructionMetadata& PlatformExtension::AddAction(
|
||||
@@ -60,6 +64,7 @@ gd::InstructionMetadata& PlatformExtension::AddAction(
|
||||
const gd::String& group,
|
||||
const gd::String& icon,
|
||||
const gd::String& smallicon) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gd::String nameWithNamespace = GetNameSpace() + name;
|
||||
actionsInfos[nameWithNamespace] = InstructionMetadata(GetNameSpace(),
|
||||
nameWithNamespace,
|
||||
@@ -71,6 +76,7 @@ gd::InstructionMetadata& PlatformExtension::AddAction(
|
||||
smallicon)
|
||||
.SetHelpPath(GetHelpPath());
|
||||
return actionsInfos[nameWithNamespace];
|
||||
#endif
|
||||
}
|
||||
|
||||
gd::ExpressionMetadata& PlatformExtension::AddExpression(
|
||||
@@ -79,6 +85,7 @@ gd::ExpressionMetadata& PlatformExtension::AddExpression(
|
||||
const gd::String& description,
|
||||
const gd::String& group,
|
||||
const gd::String& smallicon) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gd::String nameWithNamespace = GetNameSpace() + name;
|
||||
expressionsInfos[nameWithNamespace] = ExpressionMetadata("number",
|
||||
GetNameSpace(),
|
||||
@@ -89,6 +96,7 @@ gd::ExpressionMetadata& PlatformExtension::AddExpression(
|
||||
smallicon)
|
||||
.SetHelpPath(GetHelpPath());
|
||||
return expressionsInfos[nameWithNamespace];
|
||||
#endif
|
||||
}
|
||||
|
||||
gd::ExpressionMetadata& PlatformExtension::AddStrExpression(
|
||||
@@ -97,6 +105,7 @@ gd::ExpressionMetadata& PlatformExtension::AddStrExpression(
|
||||
const gd::String& description,
|
||||
const gd::String& group,
|
||||
const gd::String& smallicon) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gd::String nameWithNamespace = GetNameSpace() + name;
|
||||
strExpressionsInfos[nameWithNamespace] = ExpressionMetadata("string",
|
||||
GetNameSpace(),
|
||||
@@ -107,6 +116,7 @@ gd::ExpressionMetadata& PlatformExtension::AddStrExpression(
|
||||
smallicon)
|
||||
.SetHelpPath(GetHelpPath());
|
||||
return strExpressionsInfos[nameWithNamespace];
|
||||
#endif
|
||||
}
|
||||
|
||||
gd::MultipleInstructionMetadata PlatformExtension::AddExpressionAndCondition(
|
||||
@@ -210,10 +220,12 @@ PlatformExtension::AddExpressionAndConditionAndAction(
|
||||
expression, condition, action);
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gd::DependencyMetadata& PlatformExtension::AddDependency() {
|
||||
extensionDependenciesMetadata.push_back(DependencyMetadata());
|
||||
return extensionDependenciesMetadata.back();
|
||||
}
|
||||
#endif
|
||||
|
||||
gd::ObjectMetadata& PlatformExtension::AddObject(
|
||||
const gd::String& name,
|
||||
@@ -305,6 +317,7 @@ gd::EventMetadata& PlatformExtension::AddEvent(
|
||||
const gd::String& group_,
|
||||
const gd::String& smallicon_,
|
||||
std::shared_ptr<gd::BaseEvent> instance_) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gd::String nameWithNamespace = GetNameSpace() + name_;
|
||||
eventsInfos[nameWithNamespace] = gd::EventMetadata(nameWithNamespace,
|
||||
fullname_,
|
||||
@@ -313,6 +326,7 @@ gd::EventMetadata& PlatformExtension::AddEvent(
|
||||
smallicon_,
|
||||
instance_);
|
||||
return eventsInfos[nameWithNamespace];
|
||||
#endif
|
||||
}
|
||||
|
||||
PlatformExtension& PlatformExtension::SetExtensionInformation(
|
||||
@@ -392,6 +406,8 @@ std::vector<gd::String> PlatformExtension::GetBehaviorsTypes() const {
|
||||
return behaviors;
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
|
||||
gd::InstructionMetadata& PlatformExtension::AddDuplicatedAction(
|
||||
const gd::String& newActionName, const gd::String& copiedActionName) {
|
||||
gd::String newNameWithNamespace = GetNameSpace() + newActionName;
|
||||
@@ -570,6 +586,7 @@ gd::BaseEventSPtr PlatformExtension::CreateEvent(
|
||||
|
||||
return std::shared_ptr<gd::BaseEvent>();
|
||||
}
|
||||
#endif
|
||||
|
||||
CreateFunPtr PlatformExtension::GetObjectCreationFunctionPtr(
|
||||
const gd::String& objectType) const {
|
||||
@@ -648,6 +665,7 @@ bool PlatformExtension::IsBuiltin() const {
|
||||
builtinExtensions.end();
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
|
||||
for (std::map<gd::String, gd::InstructionMetadata>::iterator it =
|
||||
GetAllActions().begin();
|
||||
@@ -792,40 +810,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
gd::String
|
||||
PlatformExtension::GetEventsFunctionFullType(const gd::String &extensionName,
|
||||
const gd::String &functionName) {
|
||||
const auto &separator = GetNamespaceSeparator();
|
||||
return extensionName + separator + functionName;
|
||||
}
|
||||
|
||||
gd::String PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
const gd::String &extensionName, const gd::String &behaviorName,
|
||||
const gd::String &functionName) {
|
||||
const auto &separator = GetNamespaceSeparator();
|
||||
return extensionName + separator + behaviorName + separator + functionName;
|
||||
}
|
||||
|
||||
gd::String
|
||||
PlatformExtension::GetBehaviorFullType(const gd::String &extensionName,
|
||||
const gd::String &behaviorName) {
|
||||
const auto &separator = GetNamespaceSeparator();
|
||||
return extensionName + separator + behaviorName;
|
||||
}
|
||||
|
||||
gd::String PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
const gd::String &extensionName, const gd::String &objectName,
|
||||
const gd::String &functionName) {
|
||||
const auto &separator = GetNamespaceSeparator();
|
||||
return extensionName + separator + objectName + separator + functionName;
|
||||
}
|
||||
|
||||
gd::String PlatformExtension::GetObjectFullType(const gd::String &extensionName,
|
||||
const gd::String &objectName) {
|
||||
const auto &separator = GetNamespaceSeparator();
|
||||
return extensionName + separator + objectName;
|
||||
}
|
||||
#endif
|
||||
|
||||
PlatformExtension::PlatformExtension()
|
||||
: deprecated(false), category(_("General")) {}
|
||||
|
@@ -620,26 +620,7 @@ class GD_CORE_API PlatformExtension {
|
||||
*/
|
||||
static gd::String GetNamespaceSeparator() { return "::"; }
|
||||
|
||||
static gd::String GetEventsFunctionFullType(const gd::String &extensionName,
|
||||
const gd::String &functionName);
|
||||
|
||||
static gd::String
|
||||
GetBehaviorEventsFunctionFullType(const gd::String &extensionName,
|
||||
const gd::String &behaviorName,
|
||||
const gd::String &functionName);
|
||||
|
||||
static gd::String GetBehaviorFullType(const gd::String &extensionName,
|
||||
const gd::String &behaviorName);
|
||||
|
||||
static gd::String
|
||||
GetObjectEventsFunctionFullType(const gd::String &extensionName,
|
||||
const gd::String &objectName,
|
||||
const gd::String &functionName);
|
||||
|
||||
static gd::String GetObjectFullType(const gd::String &extensionName,
|
||||
const gd::String &objectName);
|
||||
|
||||
private:
|
||||
private:
|
||||
/**
|
||||
* Set the namespace (the string all actions/conditions/expressions start
|
||||
* with).
|
||||
|
@@ -3,6 +3,7 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef SCENECANVASSETTINGS_H
|
||||
#define SCENECANVASSETTINGS_H
|
||||
#include "GDCore/String.h"
|
||||
@@ -42,3 +43,4 @@ private:
|
||||
} // namespace gd
|
||||
|
||||
#endif // SCENECANVASSETTINGS_H
|
||||
#endif
|
||||
|
@@ -773,18 +773,15 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
|
||||
const gd::String& ignored_characters =
|
||||
EventsRefactorer::searchIgnoredCharacters;
|
||||
|
||||
if (inEventSentences) {
|
||||
// Remove ignored characters only when searching in event sentences.
|
||||
search.replace_if(
|
||||
search.begin(),
|
||||
search.end(),
|
||||
[ignored_characters](const char& c) {
|
||||
return ignored_characters.find(c) != gd::String::npos;
|
||||
},
|
||||
"");
|
||||
search = search.LeftTrim().RightTrim();
|
||||
search.RemoveConsecutiveOccurrences(search.begin(), search.end(), ' ');
|
||||
}
|
||||
search.replace_if(
|
||||
search.begin(),
|
||||
search.end(),
|
||||
[ignored_characters](const char& c) {
|
||||
return ignored_characters.find(c) != gd::String::npos;
|
||||
},
|
||||
"");
|
||||
search = search.LeftTrim().RightTrim();
|
||||
search.RemoveConsecutiveOccurrences(search.begin(), search.end(), ' ');
|
||||
|
||||
for (std::size_t i = 0; i < events.size(); ++i) {
|
||||
bool eventAddedInResults = false;
|
||||
|
@@ -1,301 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2022 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "PropertyFunctionGenerator.h"
|
||||
|
||||
#include "GDCore/Events/Builtin/StandardEvent.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Extensions/Metadata/ValueTypeMetadata.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
void PropertyFunctionGenerator::GenerateBehaviorGetterAndSetter(
|
||||
gd::Project &project, gd::EventsFunctionsExtension &extension,
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::NamedPropertyDescriptor &property, bool isSharedProperties) {
|
||||
GenerateGetterAndSetter(project, extension, eventsBasedBehavior, property,
|
||||
eventsBasedBehavior.GetObjectType(), true,
|
||||
isSharedProperties);
|
||||
}
|
||||
|
||||
void PropertyFunctionGenerator::GenerateObjectGetterAndSetter(
|
||||
gd::Project &project, gd::EventsFunctionsExtension &extension,
|
||||
gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::NamedPropertyDescriptor &property) {
|
||||
GenerateGetterAndSetter(project, extension, eventsBasedObject, property, "",
|
||||
false, false);
|
||||
}
|
||||
|
||||
void PropertyFunctionGenerator::GenerateGetterAndSetter(
|
||||
gd::Project &project, gd::EventsFunctionsExtension &extension,
|
||||
gd::AbstractEventsBasedEntity &eventsBasedEntity,
|
||||
const gd::NamedPropertyDescriptor &property, const gd::String &objectType,
|
||||
bool isBehavior, bool isSharedProperties) {
|
||||
auto &propertyName = property.GetName();
|
||||
auto &functionsContainer = eventsBasedEntity.GetEventsFunctions();
|
||||
gd::String capitalizedName = CapitalizeFirstLetter(property.GetName());
|
||||
gd::String setterName = "Set" + capitalizedName;
|
||||
|
||||
gd::String functionGroupName =
|
||||
(eventsBasedEntity.GetFullName().empty()
|
||||
? eventsBasedEntity.GetName()
|
||||
: eventsBasedEntity.GetFullName()) +
|
||||
(property.GetGroup().empty()
|
||||
? ""
|
||||
: " " + UnCapitalizeFirstLetter(property.GetGroup())) +
|
||||
" configuration";
|
||||
|
||||
gd::String propertyLabel =
|
||||
property.GetLabel().empty() ? property.GetName() : property.GetLabel();
|
||||
|
||||
gd::String descriptionSubject =
|
||||
(property.GetType() == "Boolean" ? "if " : "the ") +
|
||||
UnCapitalizeFirstLetter(propertyLabel) +
|
||||
(isSharedProperties || property.GetType() == "Boolean"
|
||||
? "."
|
||||
: " of the object.") +
|
||||
(property.GetDescription().empty() ? ""
|
||||
: " " + property.GetDescription()) +
|
||||
(isSharedProperties
|
||||
? " While an object is needed, this will apply to all "
|
||||
"objects using the behavior."
|
||||
: "");
|
||||
|
||||
gd::String propertyGetterName =
|
||||
(isSharedProperties ? "SharedProperty" : "Property") + property.GetName();
|
||||
gd::String getterType =
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
extension.GetName(), eventsBasedEntity.GetName(), propertyGetterName);
|
||||
gd::String setterType =
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
extension.GetName(), eventsBasedEntity.GetName(),
|
||||
"Set" + propertyGetterName);
|
||||
|
||||
gd::String getterName = capitalizedName;
|
||||
gd::String numberOrString =
|
||||
property.GetType() == "Number" ? "Number" : "String";
|
||||
|
||||
if (!functionsContainer.HasEventsFunctionNamed(getterName)) {
|
||||
auto &getter = functionsContainer.InsertNewEventsFunction(
|
||||
getterName, functionsContainer.GetEventsFunctionsCount());
|
||||
auto &expressionType =
|
||||
gd::ValueTypeMetadata::ConvertPropertyTypeToValueType(
|
||||
property.GetType());
|
||||
// TODO Stop replacing number by expression when it"s handled by the UI
|
||||
// and released.
|
||||
auto &legacyExpressionType =
|
||||
expressionType == "number" ? "expression" : expressionType;
|
||||
getter.GetExpressionType()
|
||||
.SetName(legacyExpressionType)
|
||||
.SetExtraInfo(GetStringifiedExtraInfo(property));
|
||||
getter.SetFullName(propertyLabel).SetGroup(functionGroupName);
|
||||
if (property.GetType() == "Boolean") {
|
||||
getter.SetFunctionType(gd::EventsFunction::Condition)
|
||||
.SetDescription("Check " + descriptionSubject)
|
||||
.SetSentence("_PARAM0_ " + UnCapitalizeFirstLetter(propertyLabel));
|
||||
} else {
|
||||
getter.SetFunctionType(gd::EventsFunction::ExpressionAndCondition)
|
||||
.SetDescription(descriptionSubject)
|
||||
.SetSentence("the " + UnCapitalizeFirstLetter(propertyLabel));
|
||||
}
|
||||
|
||||
auto &event =
|
||||
dynamic_cast<gd::StandardEvent &>(getter.GetEvents().InsertNewEvent(
|
||||
project, "BuiltinCommonInstructions::Standard", 0));
|
||||
if (property.GetType() == "Boolean") {
|
||||
gd::Instruction condition;
|
||||
condition.SetType(getterType);
|
||||
condition.AddParameter("Object");
|
||||
if (isBehavior) {
|
||||
condition.AddParameter("Behavior");
|
||||
}
|
||||
event.GetConditions().Insert(condition, 0);
|
||||
|
||||
gd::Instruction action;
|
||||
action.SetType("SetReturnBoolean");
|
||||
action.AddParameter("True");
|
||||
event.GetActions().Insert(action, 0);
|
||||
} else {
|
||||
gd::Instruction action;
|
||||
action.SetType("SetReturn" + numberOrString);
|
||||
gd::String receiver = isBehavior ? "Object.Behavior::" : "Object.";
|
||||
gd::String propertyPrefix =
|
||||
(isSharedProperties ? "SharedProperty" : "Property");
|
||||
action.AddParameter(receiver + propertyPrefix + property.GetName() +
|
||||
"()");
|
||||
event.GetActions().Insert(action, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!functionsContainer.HasEventsFunctionNamed(setterName)) {
|
||||
auto &setter = functionsContainer.InsertNewEventsFunction(
|
||||
setterName, functionsContainer.GetEventsFunctionsCount());
|
||||
if (property.GetType() == "Boolean") {
|
||||
setter.SetFunctionType(gd::EventsFunction::Action)
|
||||
.SetFullName(propertyLabel)
|
||||
.SetGroup(functionGroupName)
|
||||
.SetDescription("Change " + descriptionSubject)
|
||||
.SetSentence("_PARAM0_ " + UnCapitalizeFirstLetter(propertyLabel) +
|
||||
(isBehavior ? ": _PARAM2_" : ": _PARAM1_"));
|
||||
gd::ParameterMetadata objectParameter;
|
||||
objectParameter.SetType("object")
|
||||
.SetName("Object")
|
||||
.SetDescription("Object")
|
||||
.SetExtraInfo(objectType);
|
||||
if (!isBehavior) {
|
||||
gd::String objectFullType = gd::PlatformExtension::GetObjectFullType(
|
||||
extension.GetName(), eventsBasedEntity.GetName());
|
||||
objectParameter.SetExtraInfo(objectFullType);
|
||||
}
|
||||
setter.GetParameters().push_back(objectParameter);
|
||||
if (isBehavior) {
|
||||
gd::ParameterMetadata behaviorParameter;
|
||||
gd::String behaviorFullType =
|
||||
gd::PlatformExtension::GetBehaviorFullType(
|
||||
extension.GetName(), eventsBasedEntity.GetName());
|
||||
behaviorParameter.SetType("behavior")
|
||||
.SetName("Behavior")
|
||||
.SetDescription("Behavior")
|
||||
.SetExtraInfo(behaviorFullType);
|
||||
setter.GetParameters().push_back(behaviorParameter);
|
||||
}
|
||||
gd::ParameterMetadata valueParameter;
|
||||
valueParameter.SetType("yesorno")
|
||||
.SetName("Value")
|
||||
.SetDescription(capitalizedName)
|
||||
.SetOptional(true)
|
||||
.SetDefaultValue("yes");
|
||||
setter.GetParameters().push_back(valueParameter);
|
||||
} else {
|
||||
setter.SetFunctionType(gd::EventsFunction::ActionWithOperator);
|
||||
setter.SetGetterName(getterName);
|
||||
}
|
||||
|
||||
if (property.GetType() == "Boolean") {
|
||||
{
|
||||
auto &event =
|
||||
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().InsertNewEvent(
|
||||
project, "BuiltinCommonInstructions::Standard", 0));
|
||||
|
||||
gd::Instruction condition;
|
||||
condition.SetType("GetArgumentAsBoolean");
|
||||
condition.AddParameter("\"Value\"");
|
||||
event.GetConditions().Insert(condition, 0);
|
||||
|
||||
gd::Instruction action;
|
||||
action.SetType(setterType);
|
||||
action.AddParameter("Object");
|
||||
if (isBehavior) {
|
||||
action.AddParameter("Behavior");
|
||||
action.AddParameter("yes");
|
||||
} else {
|
||||
action.AddParameter("yes");
|
||||
}
|
||||
event.GetActions().Insert(action, 0);
|
||||
}
|
||||
{
|
||||
auto &event =
|
||||
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().InsertNewEvent(
|
||||
project, "BuiltinCommonInstructions::Standard", 0));
|
||||
|
||||
gd::Instruction condition;
|
||||
condition.SetType("GetArgumentAsBoolean");
|
||||
condition.AddParameter("\"Value\"");
|
||||
condition.SetInverted(true);
|
||||
event.GetConditions().Insert(condition, 0);
|
||||
|
||||
gd::Instruction action;
|
||||
action.SetType(setterType);
|
||||
action.AddParameter("Object");
|
||||
if (isBehavior) {
|
||||
action.AddParameter("Behavior");
|
||||
action.AddParameter("no");
|
||||
} else {
|
||||
action.AddParameter("no");
|
||||
}
|
||||
event.GetActions().Insert(action, 0);
|
||||
}
|
||||
} else {
|
||||
auto &event =
|
||||
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().InsertNewEvent(
|
||||
project, "BuiltinCommonInstructions::Standard", 0));
|
||||
|
||||
gd::Instruction action;
|
||||
action.SetType(setterType);
|
||||
action.AddParameter("Object");
|
||||
gd::String parameterGetterCall =
|
||||
"GetArgumentAs" + numberOrString + "(\"Value\")";
|
||||
if (isBehavior) {
|
||||
action.AddParameter("Behavior");
|
||||
action.AddParameter("=");
|
||||
action.AddParameter(parameterGetterCall);
|
||||
} else {
|
||||
action.AddParameter("=");
|
||||
action.AddParameter(parameterGetterCall);
|
||||
}
|
||||
event.GetActions().Insert(action, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PropertyFunctionGenerator::CanGenerateGetterAndSetter(
|
||||
const gd::AbstractEventsBasedEntity &eventsBasedEntity,
|
||||
const gd::NamedPropertyDescriptor &property) {
|
||||
auto &type = property.GetType();
|
||||
if (type != "Boolean" && type != "Number" && type != "String" &&
|
||||
type != "Choice" && type != "Color") {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &functionsContainer = eventsBasedEntity.GetEventsFunctions();
|
||||
auto getterName = CapitalizeFirstLetter(property.GetName());
|
||||
auto setterName = "Set" + getterName;
|
||||
return !functionsContainer.HasEventsFunctionNamed(setterName) &&
|
||||
!functionsContainer.HasEventsFunctionNamed(getterName);
|
||||
};
|
||||
|
||||
gd::String PropertyFunctionGenerator::GetStringifiedExtraInfo(
|
||||
const gd::PropertyDescriptor &property) {
|
||||
if (property.GetType() == "Choice") {
|
||||
gd::String arrayString;
|
||||
arrayString += "[";
|
||||
bool isFirst = true;
|
||||
for (const gd::String &choice : property.GetExtraInfo()) {
|
||||
if (!isFirst) {
|
||||
arrayString += ",";
|
||||
}
|
||||
isFirst = false;
|
||||
arrayString += "\"" + choice + "\"";
|
||||
}
|
||||
arrayString += "]";
|
||||
return arrayString;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
gd::String
|
||||
PropertyFunctionGenerator::CapitalizeFirstLetter(const gd::String &string) {
|
||||
if (string.empty()) {
|
||||
return string;
|
||||
}
|
||||
return string.substr(0, 1).UpperCase() + string.substr(1);
|
||||
}
|
||||
|
||||
gd::String
|
||||
PropertyFunctionGenerator::UnCapitalizeFirstLetter(const gd::String &string) {
|
||||
if (string.empty()) {
|
||||
return string;
|
||||
}
|
||||
return string.substr(0, 1).LowerCase() + string.substr(1);
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2022 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_PROPERTYFUNCTIONGENERATOR_H
|
||||
#define GDCORE_PROPERTYFUNCTIONGENERATOR_H
|
||||
|
||||
namespace gd {
|
||||
class String;
|
||||
class Project;
|
||||
class EventsFunctionsExtension;
|
||||
class EventsBasedBehavior;
|
||||
class EventsBasedObject;
|
||||
class AbstractEventsBasedEntity;
|
||||
class PropertyDescriptor;
|
||||
class NamedPropertyDescriptor;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Generate a getter and a setter functions for properties.
|
||||
*/
|
||||
class GD_CORE_API PropertyFunctionGenerator {
|
||||
public:
|
||||
/**
|
||||
* \brief Generate a getter and a setter for the given behavior property.
|
||||
*/
|
||||
static void GenerateBehaviorGetterAndSetter(
|
||||
gd::Project &project, gd::EventsFunctionsExtension &extension,
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::NamedPropertyDescriptor &property, bool isSharedProperties);
|
||||
/**
|
||||
* \brief Generate a getter and a setter for the given object property.
|
||||
*/
|
||||
static void
|
||||
GenerateObjectGetterAndSetter(gd::Project &project,
|
||||
gd::EventsFunctionsExtension &extension,
|
||||
gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::NamedPropertyDescriptor &property);
|
||||
static bool CanGenerateGetterAndSetter(
|
||||
const gd::AbstractEventsBasedEntity &eventsBasedEntity,
|
||||
const gd::NamedPropertyDescriptor &property);
|
||||
|
||||
~PropertyFunctionGenerator();
|
||||
|
||||
private:
|
||||
static void GenerateGetterAndSetter(
|
||||
gd::Project &project, gd::EventsFunctionsExtension &extension,
|
||||
gd::AbstractEventsBasedEntity &eventsBasedEntity,
|
||||
const gd::NamedPropertyDescriptor &property, const gd::String &objectType,
|
||||
bool isBehavior, bool isSharedProperties);
|
||||
|
||||
static gd::String CapitalizeFirstLetter(const gd::String &string);
|
||||
static gd::String UnCapitalizeFirstLetter(const gd::String &string);
|
||||
static gd::String
|
||||
GetStringifiedExtraInfo(const gd::PropertyDescriptor &property);
|
||||
|
||||
PropertyFunctionGenerator();
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_PROPERTYFUNCTIONGENERATOR_H
|
@@ -35,6 +35,40 @@
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace {
|
||||
// These functions are doing the reverse of what is done when adding
|
||||
// instructions/expression to extension/behaviors. If needed, they could be
|
||||
// moved to gd::PlatformExtension to colocate the usage of the namespace
|
||||
// separator?
|
||||
gd::String GetEventsFunctionFullType(const gd::String& extensionName,
|
||||
const gd::String& functionName) {
|
||||
const auto& separator = gd::PlatformExtension::GetNamespaceSeparator();
|
||||
return extensionName + separator + functionName;
|
||||
}
|
||||
gd::String GetBehaviorEventsFunctionFullType(const gd::String& extensionName,
|
||||
const gd::String& behaviorName,
|
||||
const gd::String& functionName) {
|
||||
const auto& separator = gd::PlatformExtension::GetNamespaceSeparator();
|
||||
return extensionName + separator + behaviorName + separator + functionName;
|
||||
}
|
||||
gd::String GetBehaviorFullType(const gd::String& extensionName,
|
||||
const gd::String& behaviorName) {
|
||||
const auto& separator = gd::PlatformExtension::GetNamespaceSeparator();
|
||||
return extensionName + separator + behaviorName;
|
||||
}
|
||||
gd::String GetObjectEventsFunctionFullType(const gd::String& extensionName,
|
||||
const gd::String& objectName,
|
||||
const gd::String& functionName) {
|
||||
const auto& separator = gd::PlatformExtension::GetNamespaceSeparator();
|
||||
return extensionName + separator + objectName + separator + functionName;
|
||||
}
|
||||
gd::String GetObjectFullType(const gd::String& extensionName,
|
||||
const gd::String& objectName) {
|
||||
const auto& separator = gd::PlatformExtension::GetNamespaceSeparator();
|
||||
return extensionName + separator + objectName;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace gd {
|
||||
|
||||
// By convention, the first parameter of an events based behavior method is
|
||||
@@ -218,7 +252,7 @@ WholeProjectRefactorer::GetAllObjectTypesUsingEventsBasedBehavior(
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior) {
|
||||
std::set<gd::String> allTypes;
|
||||
const gd::String behaviorType = gd::PlatformExtension::GetBehaviorFullType(
|
||||
const gd::String behaviorType = GetBehaviorFullType(
|
||||
eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName());
|
||||
|
||||
auto addTypesOfObjectsIn =
|
||||
@@ -261,7 +295,7 @@ void WholeProjectRefactorer::EnsureBehaviorEventsFunctionsProperParameters(
|
||||
.SetType("behavior")
|
||||
.SetName("Behavior")
|
||||
.SetDescription("Behavior")
|
||||
.SetExtraInfo(gd::PlatformExtension::GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
.SetExtraInfo(GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName()));
|
||||
}
|
||||
}
|
||||
@@ -281,7 +315,7 @@ void WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
|
||||
.SetType("object")
|
||||
.SetName(parentObjectParameterName)
|
||||
.SetDescription("Object")
|
||||
.SetExtraInfo(gd::PlatformExtension::GetObjectFullType(eventsFunctionsExtension.GetName(),
|
||||
.SetExtraInfo(GetObjectFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedObject.GetName()));
|
||||
}
|
||||
}
|
||||
@@ -296,8 +330,8 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
DoRenameEventsFunction(
|
||||
project,
|
||||
eventsFunction,
|
||||
gd::PlatformExtension::GetEventsFunctionFullType(oldName, eventsFunction.GetName()),
|
||||
gd::PlatformExtension::GetEventsFunctionFullType(newName, eventsFunction.GetName()));
|
||||
GetEventsFunctionFullType(oldName, eventsFunction.GetName()),
|
||||
GetEventsFunctionFullType(newName, eventsFunction.GetName()));
|
||||
};
|
||||
|
||||
auto renameBehaviorEventsFunction =
|
||||
@@ -310,10 +344,10 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(oldName,
|
||||
GetBehaviorEventsFunctionFullType(oldName,
|
||||
eventsBasedBehavior.GetName(),
|
||||
eventsFunction.GetName()),
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(newName,
|
||||
GetBehaviorEventsFunctionFullType(newName,
|
||||
eventsBasedBehavior.GetName(),
|
||||
eventsFunction.GetName()));
|
||||
ExposeProjectEvents(project, renamer);
|
||||
@@ -326,12 +360,12 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
const gd::NamedPropertyDescriptor& property) {
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
oldName,
|
||||
eventsBasedBehavior.GetName(),
|
||||
gd::EventsBasedBehavior::GetPropertyActionName(
|
||||
property.GetName())),
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
newName,
|
||||
eventsBasedBehavior.GetName(),
|
||||
gd::EventsBasedBehavior::GetPropertyActionName(
|
||||
@@ -341,12 +375,12 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
gd::InstructionsTypeRenamer conditionRenamer =
|
||||
gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
oldName,
|
||||
eventsBasedBehavior.GetName(),
|
||||
gd::EventsBasedBehavior::GetPropertyConditionName(
|
||||
property.GetName())),
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
newName,
|
||||
eventsBasedBehavior.GetName(),
|
||||
gd::EventsBasedBehavior::GetPropertyConditionName(
|
||||
@@ -357,43 +391,6 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
// extension name
|
||||
};
|
||||
|
||||
auto renameBehaviorSharedPropertyFunctions =
|
||||
[&project, &oldName, &newName](
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::NamedPropertyDescriptor& property) {
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
oldName,
|
||||
eventsBasedBehavior.GetName(),
|
||||
gd::EventsBasedBehavior::GetSharedPropertyActionName(
|
||||
property.GetName())),
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
newName,
|
||||
eventsBasedBehavior.GetName(),
|
||||
gd::EventsBasedBehavior::GetSharedPropertyActionName(
|
||||
property.GetName())));
|
||||
ExposeProjectEvents(project, actionRenamer);
|
||||
|
||||
gd::InstructionsTypeRenamer conditionRenamer =
|
||||
gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
oldName,
|
||||
eventsBasedBehavior.GetName(),
|
||||
gd::EventsBasedBehavior::GetSharedPropertyConditionName(
|
||||
property.GetName())),
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
newName,
|
||||
eventsBasedBehavior.GetName(),
|
||||
gd::EventsBasedBehavior::GetSharedPropertyConditionName(
|
||||
property.GetName())));
|
||||
ExposeProjectEvents(project, conditionRenamer);
|
||||
|
||||
// Nothing to do for expressions, expressions are not including the
|
||||
// extension name
|
||||
};
|
||||
|
||||
auto renameObjectEventsFunction =
|
||||
[&project, &oldName, &newName](
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
@@ -404,10 +401,10 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(oldName,
|
||||
GetObjectEventsFunctionFullType(oldName,
|
||||
eventsBasedObject.GetName(),
|
||||
eventsFunction.GetName()),
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(newName,
|
||||
GetObjectEventsFunctionFullType(newName,
|
||||
eventsBasedObject.GetName(),
|
||||
eventsFunction.GetName()));
|
||||
ExposeProjectEvents(project, renamer);
|
||||
@@ -420,12 +417,12 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
const gd::NamedPropertyDescriptor& property) {
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
GetObjectEventsFunctionFullType(
|
||||
oldName,
|
||||
eventsBasedObject.GetName(),
|
||||
gd::EventsBasedObject::GetPropertyActionName(
|
||||
property.GetName())),
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
GetObjectEventsFunctionFullType(
|
||||
newName,
|
||||
eventsBasedObject.GetName(),
|
||||
gd::EventsBasedObject::GetPropertyActionName(
|
||||
@@ -435,12 +432,12 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
gd::InstructionsTypeRenamer conditionRenamer =
|
||||
gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
GetObjectEventsFunctionFullType(
|
||||
oldName,
|
||||
eventsBasedObject.GetName(),
|
||||
gd::EventsBasedObject::GetPropertyConditionName(
|
||||
property.GetName())),
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
GetObjectEventsFunctionFullType(
|
||||
newName,
|
||||
eventsBasedObject.GetName(),
|
||||
gd::EventsBasedObject::GetPropertyConditionName(
|
||||
@@ -491,19 +488,13 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
}
|
||||
|
||||
// Behavior properties
|
||||
for (auto &&eventsBasedBehavior :
|
||||
for (auto&& eventsBasedBehavior :
|
||||
eventsFunctionsExtension.GetEventsBasedBehaviors().GetInternalVector()) {
|
||||
for (auto &&propertyDescriptor :
|
||||
eventsBasedBehavior->GetPropertyDescriptors().GetInternalVector()) {
|
||||
auto& behaviorProperties = eventsBasedBehavior->GetPropertyDescriptors();
|
||||
for (auto&& propertyDescriptor : behaviorProperties.GetInternalVector()) {
|
||||
renameBehaviorPropertyFunctions(*eventsBasedBehavior,
|
||||
*propertyDescriptor);
|
||||
}
|
||||
for (auto &&propertyDescriptor :
|
||||
eventsBasedBehavior->GetSharedPropertyDescriptors()
|
||||
.GetInternalVector()) {
|
||||
renameBehaviorSharedPropertyFunctions(*eventsBasedBehavior,
|
||||
*propertyDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
// Object instructions
|
||||
@@ -532,8 +523,8 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
eventsFunctionsExtension.GetEventsBasedBehaviors().GetInternalVector()) {
|
||||
DoRenameBehavior(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorFullType(oldName, eventsBasedBehavior->GetName()),
|
||||
gd::PlatformExtension::GetBehaviorFullType(newName, eventsBasedBehavior->GetName()));
|
||||
GetBehaviorFullType(oldName, eventsBasedBehavior->GetName()),
|
||||
GetBehaviorFullType(newName, eventsBasedBehavior->GetName()));
|
||||
}
|
||||
|
||||
// Finally, rename custom objects type
|
||||
@@ -541,8 +532,8 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) {
|
||||
DoRenameObject(
|
||||
project,
|
||||
gd::PlatformExtension::GetObjectFullType(oldName, eventsBasedObject->GetName()),
|
||||
gd::PlatformExtension::GetObjectFullType(newName, eventsBasedObject->GetName()));
|
||||
GetObjectFullType(oldName, eventsBasedObject->GetName()),
|
||||
GetObjectFullType(newName, eventsBasedObject->GetName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,9 +550,9 @@ void WholeProjectRefactorer::RenameEventsFunction(
|
||||
DoRenameEventsFunction(
|
||||
project,
|
||||
eventsFunction,
|
||||
gd::PlatformExtension::GetEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
GetEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
oldFunctionName),
|
||||
gd::PlatformExtension::GetEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
GetEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
newFunctionName));
|
||||
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::ExpressionAndCondition) {
|
||||
@@ -594,7 +585,7 @@ void WholeProjectRefactorer::RenameBehaviorEventsFunction(
|
||||
gd::ExpressionsRenamer renamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
renamer.SetReplacedBehaviorExpression(
|
||||
gd::PlatformExtension::GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName()),
|
||||
oldFunctionName,
|
||||
newFunctionName);
|
||||
@@ -603,10 +594,10 @@ void WholeProjectRefactorer::RenameBehaviorEventsFunction(
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
GetBehaviorEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
oldFunctionName),
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
GetBehaviorEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
newFunctionName));
|
||||
ExposeProjectEvents(project, renamer);
|
||||
@@ -638,7 +629,7 @@ void WholeProjectRefactorer::RenameObjectEventsFunction(
|
||||
gd::ExpressionsRenamer renamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
renamer.SetReplacedObjectExpression(
|
||||
gd::PlatformExtension::GetObjectFullType(eventsFunctionsExtension.GetName(),
|
||||
GetObjectFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedObject.GetName()),
|
||||
oldFunctionName,
|
||||
newFunctionName);
|
||||
@@ -647,10 +638,10 @@ void WholeProjectRefactorer::RenameObjectEventsFunction(
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedObject.GetName(),
|
||||
oldFunctionName),
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedObject.GetName(),
|
||||
newFunctionName));
|
||||
ExposeProjectEvents(project, renamer);
|
||||
@@ -677,7 +668,7 @@ void WholeProjectRefactorer::MoveEventsFunctionParameter(
|
||||
const gd::EventsFunction& eventsFunction =
|
||||
eventsFunctionsExtension.GetEventsFunction(functionName);
|
||||
|
||||
const gd::String& eventsFunctionType = gd::PlatformExtension::GetEventsFunctionFullType(
|
||||
const gd::String& eventsFunctionType = GetEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), functionName);
|
||||
|
||||
if (eventsFunction.IsExpression()) {
|
||||
@@ -712,7 +703,7 @@ void WholeProjectRefactorer::MoveBehaviorEventsFunctionParameter(
|
||||
eventsFunctions.GetEventsFunction(functionName);
|
||||
|
||||
const gd::String& eventsFunctionType =
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
GetBehaviorEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
functionName);
|
||||
|
||||
@@ -720,7 +711,7 @@ void WholeProjectRefactorer::MoveBehaviorEventsFunctionParameter(
|
||||
gd::ExpressionsParameterMover mover =
|
||||
gd::ExpressionsParameterMover(project.GetCurrentPlatform());
|
||||
mover.SetBehaviorExpressionMovedParameter(
|
||||
gd::PlatformExtension::GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName()),
|
||||
functionName,
|
||||
oldIndex,
|
||||
@@ -752,7 +743,7 @@ void WholeProjectRefactorer::MoveObjectEventsFunctionParameter(
|
||||
eventsFunctions.GetEventsFunction(functionName);
|
||||
|
||||
const gd::String& eventsFunctionType =
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedObject.GetName(),
|
||||
functionName);
|
||||
|
||||
@@ -760,7 +751,7 @@ void WholeProjectRefactorer::MoveObjectEventsFunctionParameter(
|
||||
gd::ExpressionsParameterMover mover =
|
||||
gd::ExpressionsParameterMover(project.GetCurrentPlatform());
|
||||
mover.SetObjectExpressionMovedParameter(
|
||||
gd::PlatformExtension::GetObjectFullType(eventsFunctionsExtension.GetName(),
|
||||
GetObjectFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedObject.GetName()),
|
||||
functionName,
|
||||
oldIndex,
|
||||
@@ -812,7 +803,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
gd::ExpressionsRenamer expressionRenamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
expressionRenamer.SetReplacedBehaviorExpression(
|
||||
gd::PlatformExtension::GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName()),
|
||||
EventsBasedBehavior::GetPropertyExpressionName(oldPropertyName),
|
||||
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
|
||||
@@ -820,11 +811,11 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetPropertyActionName(oldPropertyName)),
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetPropertyActionName(newPropertyName)));
|
||||
@@ -832,11 +823,11 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
|
||||
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetPropertyConditionName(oldPropertyName)),
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetPropertyConditionName(newPropertyName)));
|
||||
@@ -844,72 +835,6 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::String& oldPropertyName,
|
||||
const gd::String& newPropertyName) {
|
||||
auto& properties = eventsBasedBehavior.GetPropertyDescriptors();
|
||||
if (!properties.Has(oldPropertyName)) return;
|
||||
|
||||
if (properties.Get(oldPropertyName).GetType() == "Behavior") {
|
||||
// This is a property representing another behavior that must exist on the
|
||||
// object.
|
||||
|
||||
// This other "required behavior" uses the property name, that is about to
|
||||
// change, as its name.
|
||||
// So we must change all reference to this name in the events of the
|
||||
// behavior functions.
|
||||
gd::EventsBehaviorRenamer behaviorRenamer(project.GetCurrentPlatform(),
|
||||
behaviorObjectParameterName,
|
||||
oldPropertyName,
|
||||
newPropertyName);
|
||||
|
||||
ExposeEventsBasedBehaviorEvents(
|
||||
project, eventsBasedBehavior, behaviorRenamer);
|
||||
} else {
|
||||
// Properties that represent primitive values will be used through
|
||||
// their related actions/conditions/expressions. Rename these.
|
||||
|
||||
// Order is important: we first rename the expressions then the
|
||||
// instructions, to avoid being unable to fetch the metadata (the types of
|
||||
// parameters) of instructions after they are renamed.
|
||||
gd::ExpressionsRenamer expressionRenamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
expressionRenamer.SetReplacedBehaviorExpression(
|
||||
gd::PlatformExtension::GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName()),
|
||||
EventsBasedBehavior::GetSharedPropertyExpressionName(oldPropertyName),
|
||||
EventsBasedBehavior::GetSharedPropertyExpressionName(newPropertyName));
|
||||
ExposeProjectEvents(project, expressionRenamer);
|
||||
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetSharedPropertyActionName(oldPropertyName)),
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetSharedPropertyActionName(newPropertyName)));
|
||||
ExposeProjectEvents(project, actionRenamer);
|
||||
|
||||
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetSharedPropertyConditionName(oldPropertyName)),
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetSharedPropertyConditionName(newPropertyName)));
|
||||
ExposeProjectEvents(project, conditionRenamer);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
@@ -928,7 +853,7 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
|
||||
gd::ExpressionsRenamer expressionRenamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
expressionRenamer.SetReplacedObjectExpression(
|
||||
gd::PlatformExtension::GetObjectFullType(eventsFunctionsExtension.GetName(),
|
||||
GetObjectFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedObject.GetName()),
|
||||
EventsBasedObject::GetPropertyExpressionName(oldPropertyName),
|
||||
EventsBasedObject::GetPropertyExpressionName(newPropertyName));
|
||||
@@ -936,11 +861,11 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
|
||||
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedObject.GetName(),
|
||||
EventsBasedObject::GetPropertyActionName(oldPropertyName)),
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedObject.GetName(),
|
||||
EventsBasedObject::GetPropertyActionName(newPropertyName)));
|
||||
@@ -948,11 +873,11 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
|
||||
|
||||
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedObject.GetName(),
|
||||
EventsBasedObject::GetPropertyConditionName(oldPropertyName)),
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedObject.GetName(),
|
||||
EventsBasedObject::GetPropertyConditionName(newPropertyName)));
|
||||
@@ -1189,11 +1114,11 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
oldBehaviorName,
|
||||
eventsFunction.GetName()),
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
newBehaviorName,
|
||||
eventsFunction.GetName()));
|
||||
@@ -1209,11 +1134,11 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
property) {
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
oldBehaviorName,
|
||||
EventsBasedBehavior::GetPropertyActionName(property.GetName())),
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
newBehaviorName,
|
||||
EventsBasedBehavior::GetPropertyActionName(property.GetName())));
|
||||
@@ -1221,11 +1146,11 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
|
||||
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
oldBehaviorName,
|
||||
EventsBasedBehavior::GetPropertyConditionName(property.GetName())),
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
newBehaviorName,
|
||||
EventsBasedBehavior::GetPropertyConditionName(property.GetName())));
|
||||
@@ -1235,40 +1160,6 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
// the behavior
|
||||
};
|
||||
|
||||
auto renameBehaviorSharedProperty = [&project,
|
||||
&eventsFunctionsExtension,
|
||||
&oldBehaviorName,
|
||||
&newBehaviorName](
|
||||
const gd::NamedPropertyDescriptor&
|
||||
property) {
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
oldBehaviorName,
|
||||
EventsBasedBehavior::GetSharedPropertyActionName(property.GetName())),
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
newBehaviorName,
|
||||
EventsBasedBehavior::GetSharedPropertyActionName(property.GetName())));
|
||||
ExposeProjectEvents(project, actionRenamer);
|
||||
|
||||
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
oldBehaviorName,
|
||||
EventsBasedBehavior::GetSharedPropertyConditionName(property.GetName())),
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
newBehaviorName,
|
||||
EventsBasedBehavior::GetSharedPropertyConditionName(property.GetName())));
|
||||
ExposeProjectEvents(project, conditionRenamer);
|
||||
|
||||
// Nothing to do for expression, expressions are not including the name of
|
||||
// the behavior
|
||||
};
|
||||
|
||||
// Order is important: we first rename the expressions then the instructions,
|
||||
// to avoid being unable to fetch the metadata (the types of parameters) of
|
||||
// instructions after they are renamed.
|
||||
@@ -1289,17 +1180,15 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
}
|
||||
|
||||
// Behavior properties
|
||||
for (auto&& property : eventsBasedBehavior.GetPropertyDescriptors().GetInternalVector()) {
|
||||
auto& properties = eventsBasedBehavior.GetPropertyDescriptors();
|
||||
for (auto&& property : properties.GetInternalVector()) {
|
||||
renameBehaviorProperty(*property);
|
||||
}
|
||||
for (auto&& property : eventsBasedBehavior.GetSharedPropertyDescriptors().GetInternalVector()) {
|
||||
renameBehaviorSharedProperty(*property);
|
||||
}
|
||||
|
||||
DoRenameBehavior(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorFullType(eventsFunctionsExtension.GetName(), oldBehaviorName),
|
||||
gd::PlatformExtension::GetBehaviorFullType(eventsFunctionsExtension.GetName(), newBehaviorName));
|
||||
GetBehaviorFullType(eventsFunctionsExtension.GetName(), oldBehaviorName),
|
||||
GetBehaviorFullType(eventsFunctionsExtension.GetName(), newBehaviorName));
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
@@ -1328,11 +1217,11 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
oldObjectName,
|
||||
eventsFunction.GetName()),
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
newObjectName,
|
||||
eventsFunction.GetName()));
|
||||
@@ -1348,11 +1237,11 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
property) {
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
oldObjectName,
|
||||
EventsBasedObject::GetPropertyActionName(property.GetName())),
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
newObjectName,
|
||||
EventsBasedObject::GetPropertyActionName(property.GetName())));
|
||||
@@ -1360,11 +1249,11 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
|
||||
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
oldObjectName,
|
||||
EventsBasedObject::GetPropertyConditionName(property.GetName())),
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
newObjectName,
|
||||
EventsBasedObject::GetPropertyConditionName(property.GetName())));
|
||||
@@ -1401,8 +1290,8 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
|
||||
DoRenameObject(
|
||||
project,
|
||||
gd::PlatformExtension::GetObjectFullType(eventsFunctionsExtension.GetName(), oldObjectName),
|
||||
gd::PlatformExtension::GetObjectFullType(eventsFunctionsExtension.GetName(), newObjectName));
|
||||
GetObjectFullType(eventsFunctionsExtension.GetName(), oldObjectName),
|
||||
GetObjectFullType(eventsFunctionsExtension.GetName(), newObjectName));
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::DoRenameEventsFunction(
|
||||
|
@@ -207,21 +207,6 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& oldPropertyName,
|
||||
const gd::String& newPropertyName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** a shared property of a behavior is
|
||||
* renamed.
|
||||
*
|
||||
* \warning Do the renaming of the specified shared property after calling
|
||||
* this. This is because the shared property is expected to have its old name
|
||||
* for the refactoring.
|
||||
*/
|
||||
static void RenameEventsBasedBehaviorSharedProperty(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::String& oldPropertyName,
|
||||
const gd::String& newPropertyName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** a property of an object is
|
||||
* renamed.
|
||||
|
@@ -13,8 +13,7 @@ namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Base class used to represents a behavior that can be applied to an
|
||||
* object. It stores the content (i.e: the properties) of a behavior of an object
|
||||
* and forward the properties related functions to Javascript with Emscripten.
|
||||
* object. It stores the content (i.e: the properties) of a behavior of an object.
|
||||
*
|
||||
* \see gd::BehaviorsSharedData
|
||||
* \see gd::Object
|
||||
|
@@ -11,7 +11,6 @@
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Project/CustomConfigurationHelper.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
@@ -22,26 +21,52 @@ CustomBehavior *CustomBehavior::Clone() const {
|
||||
return clone;
|
||||
}
|
||||
|
||||
void CustomBehavior::InitializeContent(gd::SerializerElement &behaviorContent) {
|
||||
if (!project.HasEventsBasedBehavior(GetTypeName())) {
|
||||
return;
|
||||
}
|
||||
const auto &eventsBasedBehavior = project.GetEventsBasedBehavior(GetTypeName());
|
||||
const auto &properties = eventsBasedBehavior.GetPropertyDescriptors();
|
||||
|
||||
gd::CustomConfigurationHelper::InitializeContent(properties, behaviorContent);
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> CustomBehavior::GetProperties(
|
||||
const gd::SerializerElement &behaviorContent) const {
|
||||
auto behaviorProperties = std::map<gd::String, gd::PropertyDescriptor>();
|
||||
if (!project.HasEventsBasedBehavior(GetTypeName())) {
|
||||
auto behaviorProperties = std::map<gd::String, gd::PropertyDescriptor>();
|
||||
return behaviorProperties;
|
||||
}
|
||||
const auto &eventsBasedBehavior = project.GetEventsBasedBehavior(GetTypeName());
|
||||
const auto &properties = eventsBasedBehavior.GetPropertyDescriptors();
|
||||
|
||||
return gd::CustomConfigurationHelper::GetProperties(properties, behaviorContent);
|
||||
for (auto &property : properties.GetInternalVector()) {
|
||||
const auto &propertyName = property->GetName();
|
||||
const auto &propertyType = property->GetType();
|
||||
|
||||
// TODO Move this into a PropertyDescriptor copy method.
|
||||
auto &newProperty = behaviorProperties[propertyName]
|
||||
.SetType(property->GetType())
|
||||
.SetDescription(property->GetDescription())
|
||||
.SetGroup(property->GetGroup())
|
||||
.SetLabel(property->GetLabel())
|
||||
.SetValue(property->GetValue())
|
||||
.SetHidden(property->IsHidden());
|
||||
|
||||
for (auto &extraInfo : property->GetExtraInfo()) {
|
||||
newProperty.AddExtraInfo(extraInfo);
|
||||
}
|
||||
|
||||
if (behaviorContent.HasChild(propertyName)) {
|
||||
if (propertyType == "String" || propertyType == "Choice" ||
|
||||
propertyType == "Color" || propertyType == "Behavior") {
|
||||
newProperty.SetValue(
|
||||
behaviorContent.GetChild(propertyName).GetStringValue());
|
||||
} else if (propertyType == "Number") {
|
||||
newProperty.SetValue(gd::String::From(
|
||||
behaviorContent.GetChild(propertyName).GetDoubleValue()));
|
||||
} else if (propertyType == "Boolean") {
|
||||
newProperty.SetValue(
|
||||
behaviorContent.GetChild(propertyName).GetBoolValue() ? "true"
|
||||
: "false");
|
||||
}
|
||||
} else {
|
||||
// No value was serialized for this property. `newProperty`
|
||||
// will have the default value coming from `enumeratedProperty`.
|
||||
}
|
||||
}
|
||||
|
||||
return behaviorProperties;
|
||||
}
|
||||
|
||||
bool CustomBehavior::UpdateProperty(gd::SerializerElement &behaviorContent,
|
||||
@@ -52,10 +77,43 @@ bool CustomBehavior::UpdateProperty(gd::SerializerElement &behaviorContent,
|
||||
}
|
||||
const auto &eventsBasedBehavior = project.GetEventsBasedBehavior(GetTypeName());
|
||||
const auto &properties = eventsBasedBehavior.GetPropertyDescriptors();
|
||||
if (!properties.Has(propertyName)) {
|
||||
return false;
|
||||
}
|
||||
const auto &property = properties.Get(propertyName);
|
||||
|
||||
return gd::CustomConfigurationHelper::UpdateProperty(
|
||||
properties,
|
||||
behaviorContent,
|
||||
propertyName,
|
||||
newValue);
|
||||
auto &element = behaviorContent.AddChild(propertyName);
|
||||
const gd::String &propertyType = property.GetType();
|
||||
|
||||
if (propertyType == "String" || propertyType == "Choice" ||
|
||||
propertyType == "Color" || propertyType == "Behavior") {
|
||||
element.SetStringValue(newValue);
|
||||
} else if (propertyType == "Number") {
|
||||
element.SetDoubleValue(newValue.To<double>());
|
||||
} else if (propertyType == "Boolean") {
|
||||
element.SetBoolValue(newValue == "1");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CustomBehavior::InitializeContent(gd::SerializerElement &behaviorContent) {
|
||||
if (!project.HasEventsBasedBehavior(GetTypeName())) {
|
||||
return;
|
||||
}
|
||||
const auto &eventsBasedBehavior = project.GetEventsBasedBehavior(GetTypeName());
|
||||
const auto &properties = eventsBasedBehavior.GetPropertyDescriptors();
|
||||
for (auto &&property : properties.GetInternalVector()) {
|
||||
auto &element = behaviorContent.AddChild(property->GetName());
|
||||
auto propertyType = property->GetType();
|
||||
|
||||
if (propertyType == "String" || propertyType == "Choice" ||
|
||||
propertyType == "Color" || propertyType == "Behavior") {
|
||||
element.SetStringValue(property->GetValue());
|
||||
} else if (propertyType == "Number") {
|
||||
element.SetDoubleValue(property->GetValue().To<double>());
|
||||
} else if (propertyType == "Boolean") {
|
||||
element.SetBoolValue(property->GetValue() == "true");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -17,7 +17,8 @@ using namespace gd;
|
||||
|
||||
namespace gd {
|
||||
/**
|
||||
* \brief A gd::Behavior that stores its content in JSON.
|
||||
* \brief A gd::Behavior that stores its content in JSON and forward the
|
||||
* properties related functions to Javascript with Emscripten.
|
||||
*/
|
||||
class CustomBehavior : public gd::Behavior {
|
||||
public:
|
||||
@@ -33,11 +34,13 @@ public:
|
||||
using Behavior::UpdateProperty;
|
||||
|
||||
protected:
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor>
|
||||
GetProperties(const gd::SerializerElement &behaviorContent) const override;
|
||||
bool UpdateProperty(gd::SerializerElement &behaviorContent,
|
||||
const gd::String &name, const gd::String &value) override;
|
||||
void InitializeContent(gd::SerializerElement &behaviorContent) override;
|
||||
virtual bool UpdateProperty(gd::SerializerElement &behaviorContent,
|
||||
const gd::String &name,
|
||||
const gd::String &value) override;
|
||||
virtual void
|
||||
InitializeContent(gd::SerializerElement &behaviorContent) override;
|
||||
|
||||
private:
|
||||
const Project &project; ///< The project is used to get the
|
||||
|
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "CustomBehaviorsSharedData.h"
|
||||
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Project/CustomConfigurationHelper.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
using namespace gd;
|
||||
|
||||
CustomBehaviorsSharedData *CustomBehaviorsSharedData::Clone() const {
|
||||
CustomBehaviorsSharedData *clone = new CustomBehaviorsSharedData(*this);
|
||||
return clone;
|
||||
}
|
||||
|
||||
void CustomBehaviorsSharedData::InitializeContent(gd::SerializerElement &behaviorContent) {
|
||||
if (!project.HasEventsBasedBehavior(GetTypeName())) {
|
||||
return;
|
||||
}
|
||||
const auto &eventsBasedBehavior = project.GetEventsBasedBehavior(GetTypeName());
|
||||
const auto &properties = eventsBasedBehavior.GetSharedPropertyDescriptors();
|
||||
|
||||
gd::CustomConfigurationHelper::InitializeContent(properties, behaviorContent);
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> CustomBehaviorsSharedData::GetProperties(
|
||||
const gd::SerializerElement &behaviorContent) const {
|
||||
if (!project.HasEventsBasedBehavior(GetTypeName())) {
|
||||
auto behaviorProperties = std::map<gd::String, gd::PropertyDescriptor>();
|
||||
return behaviorProperties;
|
||||
}
|
||||
const auto &eventsBasedBehavior = project.GetEventsBasedBehavior(GetTypeName());
|
||||
const auto &properties = eventsBasedBehavior.GetSharedPropertyDescriptors();
|
||||
|
||||
return gd::CustomConfigurationHelper::GetProperties(properties, behaviorContent);
|
||||
}
|
||||
|
||||
bool CustomBehaviorsSharedData::UpdateProperty(gd::SerializerElement &behaviorContent,
|
||||
const gd::String &propertyName,
|
||||
const gd::String &newValue) {
|
||||
if (!project.HasEventsBasedBehavior(GetTypeName())) {
|
||||
return false;
|
||||
}
|
||||
const auto &eventsBasedBehavior = project.GetEventsBasedBehavior(GetTypeName());
|
||||
const auto &properties = eventsBasedBehavior.GetSharedPropertyDescriptors();
|
||||
|
||||
return gd::CustomConfigurationHelper::UpdateProperty(
|
||||
properties,
|
||||
behaviorContent,
|
||||
propertyName,
|
||||
newValue);
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_CUSTOMBEHAVIORSSHAREDDATA_H
|
||||
#define GDCORE_CUSTOMBEHAVIORSSHAREDDATA_H
|
||||
|
||||
#include "GDCore/Project/BehaviorsSharedData.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
using namespace gd;
|
||||
|
||||
namespace gd {
|
||||
/**
|
||||
* \brief A gd::BehaviorsSharedData that stores its content in JSON.
|
||||
*/
|
||||
class CustomBehaviorsSharedData : public gd::BehaviorsSharedData {
|
||||
public:
|
||||
CustomBehaviorsSharedData(const gd::String &name, const Project &project_,
|
||||
const gd::String &fullType)
|
||||
: BehaviorsSharedData(name, fullType), project(project_) {}
|
||||
CustomBehaviorsSharedData *Clone() const override;
|
||||
|
||||
using BehaviorsSharedData::GetProperties;
|
||||
using BehaviorsSharedData::InitializeContent;
|
||||
using BehaviorsSharedData::UpdateProperty;
|
||||
|
||||
protected:
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
GetProperties(const gd::SerializerElement &behaviorContent) const override;
|
||||
bool UpdateProperty(gd::SerializerElement &behaviorContent,
|
||||
const gd::String &name, const gd::String &value) override;
|
||||
void InitializeContent(gd::SerializerElement &behaviorContent) override;
|
||||
|
||||
private:
|
||||
const Project &project; ///< The project is used to get the
|
||||
///< EventBasedBehavior from the fullType.
|
||||
};
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_CUSTOMBEHAVIORSSHAREDDATA_H
|
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "CustomConfigurationHelper.h"
|
||||
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
using namespace gd;
|
||||
|
||||
void CustomConfigurationHelper::InitializeContent(
|
||||
const gd::SerializableWithNameList<gd::NamedPropertyDescriptor> &properties,
|
||||
gd::SerializerElement &configurationContent) {
|
||||
for (auto &&property : properties.GetInternalVector()) {
|
||||
auto &element = configurationContent.AddChild(property->GetName());
|
||||
auto propertyType = property->GetType();
|
||||
|
||||
if (propertyType == "String" || propertyType == "Choice" ||
|
||||
propertyType == "Color" || propertyType == "Behavior") {
|
||||
element.SetStringValue(property->GetValue());
|
||||
} else if (propertyType == "Number") {
|
||||
element.SetDoubleValue(property->GetValue().To<double>());
|
||||
} else if (propertyType == "Boolean") {
|
||||
element.SetBoolValue(property->GetValue() == "true");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> CustomConfigurationHelper::GetProperties(
|
||||
const gd::SerializableWithNameList<gd::NamedPropertyDescriptor> &properties,
|
||||
const gd::SerializerElement &configurationContent) {
|
||||
auto behaviorProperties = std::map<gd::String, gd::PropertyDescriptor>();
|
||||
|
||||
for (auto &property : properties.GetInternalVector()) {
|
||||
const auto &propertyName = property->GetName();
|
||||
const auto &propertyType = property->GetType();
|
||||
|
||||
// TODO Move this into a PropertyDescriptor copy method.
|
||||
auto &newProperty = behaviorProperties[propertyName]
|
||||
.SetType(property->GetType())
|
||||
.SetDescription(property->GetDescription())
|
||||
.SetGroup(property->GetGroup())
|
||||
.SetLabel(property->GetLabel())
|
||||
.SetValue(property->GetValue())
|
||||
.SetHidden(property->IsHidden());
|
||||
|
||||
for (auto &extraInfo : property->GetExtraInfo()) {
|
||||
newProperty.AddExtraInfo(extraInfo);
|
||||
}
|
||||
|
||||
if (configurationContent.HasChild(propertyName)) {
|
||||
if (propertyType == "String" || propertyType == "Choice" ||
|
||||
propertyType == "Color" || propertyType == "Behavior") {
|
||||
newProperty.SetValue(
|
||||
configurationContent.GetChild(propertyName).GetStringValue());
|
||||
} else if (propertyType == "Number") {
|
||||
newProperty.SetValue(gd::String::From(
|
||||
configurationContent.GetChild(propertyName).GetDoubleValue()));
|
||||
} else if (propertyType == "Boolean") {
|
||||
newProperty.SetValue(
|
||||
configurationContent.GetChild(propertyName).GetBoolValue() ? "true"
|
||||
: "false");
|
||||
}
|
||||
} else {
|
||||
// No value was serialized for this property. `newProperty`
|
||||
// will have the default value coming from `enumeratedProperty`.
|
||||
}
|
||||
}
|
||||
|
||||
return behaviorProperties;
|
||||
}
|
||||
|
||||
bool CustomConfigurationHelper::UpdateProperty(
|
||||
const gd::SerializableWithNameList<gd::NamedPropertyDescriptor> &properties,
|
||||
gd::SerializerElement &configurationContent,
|
||||
const gd::String &propertyName,
|
||||
const gd::String &newValue) {
|
||||
if (!properties.Has(propertyName)) {
|
||||
return false;
|
||||
}
|
||||
const auto &property = properties.Get(propertyName);
|
||||
|
||||
auto &element = configurationContent.AddChild(propertyName);
|
||||
const gd::String &propertyType = property.GetType();
|
||||
|
||||
if (propertyType == "String" || propertyType == "Choice" ||
|
||||
propertyType == "Color" || propertyType == "Behavior") {
|
||||
element.SetStringValue(newValue);
|
||||
} else if (propertyType == "Number") {
|
||||
element.SetDoubleValue(newValue.To<double>());
|
||||
} else if (propertyType == "Boolean") {
|
||||
element.SetBoolValue(newValue == "1");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_CUSTOMCONFIGURATIONHELPER_H
|
||||
#define GDCORE_CUSTOMCONFIGURATIONHELPER_H
|
||||
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
using namespace gd;
|
||||
|
||||
namespace gd {
|
||||
/**
|
||||
* \brief Helper functions that gd::CustomBehavior and gd::CustomBehaviorsSharedData use to
|
||||
* store their content in JSON.
|
||||
*/
|
||||
class CustomConfigurationHelper {
|
||||
public:
|
||||
CustomConfigurationHelper() {}
|
||||
|
||||
static void InitializeContent(
|
||||
const gd::SerializableWithNameList<gd::NamedPropertyDescriptor> &properties,
|
||||
gd::SerializerElement &behaviorContent);
|
||||
|
||||
static std::map<gd::String, gd::PropertyDescriptor> GetProperties(
|
||||
const gd::SerializableWithNameList<gd::NamedPropertyDescriptor> &properties,
|
||||
const gd::SerializerElement &behaviorContent);
|
||||
|
||||
static bool UpdateProperty(
|
||||
const gd::SerializableWithNameList<gd::NamedPropertyDescriptor> &properties,
|
||||
gd::SerializerElement &behaviorContent,
|
||||
const gd::String &name,
|
||||
const gd::String &value);
|
||||
};
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_CUSTOMCONFIGURATIONHELPER_H
|
@@ -12,7 +12,6 @@
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
#include "GDCore/Project/CustomConfigurationHelper.h"
|
||||
|
||||
using namespace gd;
|
||||
|
||||
@@ -68,7 +67,50 @@ std::map<gd::String, gd::PropertyDescriptor> CustomObjectConfiguration::GetPrope
|
||||
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
|
||||
const auto &properties = eventsBasedObject.GetPropertyDescriptors();
|
||||
|
||||
return gd::CustomConfigurationHelper::GetProperties(properties, objectContent);
|
||||
for (auto &property : properties.GetInternalVector()) {
|
||||
const auto &propertyName = property->GetName();
|
||||
const auto &propertyType = property->GetType();
|
||||
|
||||
// TODO Move this into a PropertyDescriptor copy method.
|
||||
auto &newProperty = objectProperties[propertyName]
|
||||
.SetType(property->GetType())
|
||||
.SetDescription(property->GetDescription())
|
||||
.SetGroup(property->GetGroup())
|
||||
.SetLabel(property->GetLabel())
|
||||
.SetValue(property->GetValue())
|
||||
.SetHidden(property->IsHidden());
|
||||
|
||||
for (auto &extraInfo : property->GetExtraInfo()) {
|
||||
newProperty.AddExtraInfo(extraInfo);
|
||||
}
|
||||
|
||||
if (objectContent.HasChild(propertyName)) {
|
||||
if (
|
||||
propertyType == "String" ||
|
||||
propertyType == "Choice" ||
|
||||
propertyType == "Color"
|
||||
) {
|
||||
newProperty.SetValue(
|
||||
objectContent.GetChild(propertyName).GetStringValue()
|
||||
);
|
||||
} else if (propertyType == "Number") {
|
||||
newProperty.SetValue(
|
||||
gd::String::From(objectContent.GetChild(propertyName).GetDoubleValue())
|
||||
);
|
||||
} else if (propertyType == "Boolean") {
|
||||
newProperty.SetValue(
|
||||
objectContent.GetChild(propertyName).GetBoolValue()
|
||||
? "true"
|
||||
: "false"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// No value was serialized for this property. `newProperty`
|
||||
// will have the default value coming from `enumeratedProperty`.
|
||||
}
|
||||
}
|
||||
|
||||
return objectProperties;
|
||||
}
|
||||
|
||||
bool CustomObjectConfiguration::UpdateProperty(const gd::String& propertyName,
|
||||
@@ -78,12 +120,27 @@ bool CustomObjectConfiguration::UpdateProperty(const gd::String& propertyName,
|
||||
}
|
||||
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
|
||||
const auto &properties = eventsBasedObject.GetPropertyDescriptors();
|
||||
|
||||
return gd::CustomConfigurationHelper::UpdateProperty(
|
||||
properties,
|
||||
objectContent,
|
||||
propertyName,
|
||||
newValue);
|
||||
if (!properties.Has(propertyName)) {
|
||||
return false;
|
||||
}
|
||||
const auto &property = properties.Get(propertyName);
|
||||
|
||||
auto &element = objectContent.AddChild(propertyName);
|
||||
const gd::String &propertyType = property.GetType();
|
||||
|
||||
if (
|
||||
propertyType == "String" ||
|
||||
propertyType == "Choice" ||
|
||||
propertyType == "Color"
|
||||
) {
|
||||
element.SetStringValue(newValue);
|
||||
} else if (propertyType == "Number") {
|
||||
element.SetDoubleValue(newValue.To<double>());
|
||||
} else if (propertyType == "Boolean") {
|
||||
element.SetBoolValue(newValue == "1");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
|
@@ -18,20 +18,12 @@ EventsBasedBehavior::EventsBasedBehavior()
|
||||
void EventsBasedBehavior::SerializeTo(SerializerElement& element) const {
|
||||
AbstractEventsBasedEntity::SerializeTo(element);
|
||||
element.SetAttribute("objectType", objectType);
|
||||
if (isPrivate) {
|
||||
element.SetBoolAttribute("private", isPrivate);
|
||||
}
|
||||
sharedPropertyDescriptors.SerializeElementsTo(
|
||||
"propertyDescriptor", element.AddChild("sharedPropertyDescriptors"));
|
||||
}
|
||||
|
||||
void EventsBasedBehavior::UnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element) {
|
||||
AbstractEventsBasedEntity::UnserializeFrom(project, element);
|
||||
objectType = element.GetStringAttribute("objectType");
|
||||
isPrivate = element.GetBoolAttribute("private");
|
||||
sharedPropertyDescriptors.UnserializeElementsFrom(
|
||||
"propertyDescriptor", element.GetChild("sharedPropertyDescriptors"));
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -73,58 +73,6 @@ class GD_CORE_API EventsBasedBehavior: public AbstractEventsBasedEntity {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if the behavior is private - it can't be used outside of its
|
||||
* extension.
|
||||
*/
|
||||
bool IsPrivate() { return isPrivate; }
|
||||
|
||||
/**
|
||||
* \brief Set that the behavior is private - it can't be used outside of its
|
||||
* extension.
|
||||
*/
|
||||
EventsBasedBehavior& SetPrivate(bool _isPrivate) {
|
||||
isPrivate = _isPrivate;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the list of shared properties.
|
||||
*/
|
||||
SerializableWithNameList<NamedPropertyDescriptor>& GetSharedPropertyDescriptors() {
|
||||
return sharedPropertyDescriptors;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return a const reference to the list of shared properties.
|
||||
*/
|
||||
const SerializableWithNameList<NamedPropertyDescriptor>& GetSharedPropertyDescriptors()
|
||||
const {
|
||||
return sharedPropertyDescriptors;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the name of the action to change a shared property.
|
||||
*/
|
||||
static gd::String GetSharedPropertyActionName(const gd::String &propertyName) {
|
||||
return "SetSharedProperty" + propertyName;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get the name of the condition to compare a shared property.
|
||||
*/
|
||||
static gd::String GetSharedPropertyConditionName(const gd::String &propertyName) {
|
||||
return "SharedProperty" + propertyName;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get the name of the expression to get a shared property.
|
||||
*/
|
||||
static gd::String
|
||||
GetSharedPropertyExpressionName(const gd::String &propertyName) {
|
||||
return "SharedProperty" + propertyName;
|
||||
};
|
||||
|
||||
void SerializeTo(SerializerElement& element) const override;
|
||||
|
||||
void UnserializeFrom(gd::Project& project,
|
||||
@@ -132,8 +80,6 @@ class GD_CORE_API EventsBasedBehavior: public AbstractEventsBasedEntity {
|
||||
|
||||
private:
|
||||
gd::String objectType;
|
||||
bool isPrivate = false;
|
||||
SerializableWithNameList<NamedPropertyDescriptor> sharedPropertyDescriptors;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -59,19 +59,11 @@ const std::vector<gd::ParameterMetadata>& EventsFunction::GetParametersForEvents
|
||||
void EventsFunction::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", name);
|
||||
element.SetAttribute("fullName", fullName);
|
||||
if (!description.empty()) {
|
||||
element.SetAttribute("description", description);
|
||||
}
|
||||
element.SetAttribute("description", description);
|
||||
element.SetAttribute("sentence", sentence);
|
||||
if (!group.empty()) {
|
||||
element.SetAttribute("group", group);
|
||||
}
|
||||
if (!getterName.empty()) {
|
||||
element.SetAttribute("getterName", getterName);
|
||||
}
|
||||
if (isPrivate) {
|
||||
element.SetBoolAttribute("private", isPrivate);
|
||||
}
|
||||
element.SetAttribute("group", group);
|
||||
element.SetAttribute("getterName", getterName);
|
||||
element.SetBoolAttribute("private", isPrivate);
|
||||
events.SerializeTo(element.AddChild("events"));
|
||||
|
||||
gd::String functionTypeStr = "Action";
|
||||
|
@@ -145,11 +145,6 @@ class GD_CORE_API EventsFunction {
|
||||
*/
|
||||
const gd::ValueTypeMetadata& GetExpressionType() const { return expressionType; }
|
||||
|
||||
/**
|
||||
* \brief Get the type of the expression
|
||||
*/
|
||||
gd::ValueTypeMetadata& GetExpressionType() { return expressionType; }
|
||||
|
||||
enum FunctionType {
|
||||
Action,
|
||||
Condition,
|
||||
|
@@ -54,7 +54,7 @@ void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("version", version);
|
||||
element.SetAttribute("extensionNamespace", extensionNamespace);
|
||||
element.SetAttribute("shortDescription", shortDescription);
|
||||
element.AddChild("description").SetMultilineStringValue(description);
|
||||
element.SetAttribute("description", description);
|
||||
element.SetAttribute("name", name);
|
||||
element.SetAttribute("fullName", fullName);
|
||||
element.SetAttribute("category", category);
|
||||
@@ -100,7 +100,7 @@ void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
|
||||
version = element.GetStringAttribute("version");
|
||||
extensionNamespace = element.GetStringAttribute("extensionNamespace");
|
||||
shortDescription = element.GetStringAttribute("shortDescription");
|
||||
description = element.GetChild("description").GetMultilineStringValue();
|
||||
description = element.GetStringAttribute("description");
|
||||
name = element.GetStringAttribute("name");
|
||||
fullName = element.GetStringAttribute("fullName");
|
||||
category = element.GetStringAttribute("category");
|
||||
|
@@ -60,6 +60,7 @@ void InitialInstancesContainer::IterateOverInstancesWithZOrdering(
|
||||
for (auto& instance : sortedInstances) func(instance);
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gd::InitialInstance& InitialInstancesContainer::InsertNewInitialInstance() {
|
||||
gd::InitialInstance newInstance;
|
||||
initialInstances.push_back(newInstance);
|
||||
@@ -172,6 +173,7 @@ void InitialInstancesContainer::SerializeTo(SerializerElement& element) const {
|
||||
}
|
||||
|
||||
void InitialInstancesContainer::Clear() { initialInstances.clear(); }
|
||||
#endif
|
||||
|
||||
InitialInstanceFunctor::~InitialInstanceFunctor(){};
|
||||
|
||||
|
@@ -17,7 +17,6 @@
|
||||
#include "GDCore/IDE/SceneNameMangler.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/BehaviorsSharedData.h"
|
||||
#include "GDCore/Project/CustomBehaviorsSharedData.h"
|
||||
#include "GDCore/Project/InitialInstance.h"
|
||||
#include "GDCore/Project/Layer.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
@@ -27,7 +26,6 @@
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/PolymorphicClone.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -242,11 +240,11 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<gd::BehaviorsSharedData> Layout::CreateBehaviorsSharedData(
|
||||
gd::Project& project, const gd::String& name, const gd::String& behaviorsType) {
|
||||
std::unique_ptr<gd::BehaviorsSharedData> Layout::CreateBehaviorsSharedData(gd::Project& project, const gd::String& name, const gd::String& behaviorsType) {
|
||||
if (project.HasEventsBasedBehavior(behaviorsType)) {
|
||||
// Events based behaviors don't have shared data yet.
|
||||
auto sharedData =
|
||||
gd::make_unique<gd::CustomBehaviorsSharedData>(name, project, behaviorsType);
|
||||
gd::make_unique<gd::BehaviorsSharedData>(name, behaviorsType);
|
||||
sharedData->InitializeContent();
|
||||
return std::move(sharedData);
|
||||
}
|
||||
@@ -255,14 +253,7 @@ std::unique_ptr<gd::BehaviorsSharedData> Layout::CreateBehaviorsSharedData(
|
||||
project.GetCurrentPlatform(),
|
||||
behaviorsType);
|
||||
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
gd::LogWarning("Tried to create a behavior shared data with an unknown type: " +
|
||||
behaviorsType + " on object " + GetName() + "!");
|
||||
// It's probably an events-based behavior that was removed.
|
||||
// Create a custom behavior shared data to preserve the properties values.
|
||||
auto sharedData =
|
||||
gd::make_unique<gd::CustomBehaviorsSharedData>(name, project, behaviorsType);
|
||||
sharedData->InitializeContent();
|
||||
return std::move(sharedData);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gd::BehaviorsSharedData* behaviorsSharedDataBluePrint =
|
||||
|
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "MeasurementBaseUnit.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include <vector>
|
||||
|
||||
namespace gd {
|
||||
|
||||
MeasurementBaseUnit::~MeasurementBaseUnit() {}
|
||||
|
||||
const gd::MeasurementBaseUnit MeasurementBaseUnit::degreeAngle =
|
||||
MeasurementBaseUnit("degree", "deg", "");
|
||||
const gd::MeasurementBaseUnit MeasurementBaseUnit::pixel =
|
||||
MeasurementBaseUnit("pixel", "px", "distance");
|
||||
const gd::MeasurementBaseUnit MeasurementBaseUnit::meter =
|
||||
MeasurementBaseUnit("meter", "m", "distance");
|
||||
const gd::MeasurementBaseUnit MeasurementBaseUnit::second =
|
||||
MeasurementBaseUnit("second", "s", "time");
|
||||
const gd::MeasurementBaseUnit MeasurementBaseUnit::kilogram =
|
||||
MeasurementBaseUnit("kilogram", "Kg", "mass");
|
||||
|
||||
} // namespace gd
|
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_MEASUREMENTBASEUNIT
|
||||
#define GDCORE_MEASUREMENTBASEUNIT
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief An atomic unit of measurement.
|
||||
*/
|
||||
class GD_CORE_API MeasurementBaseUnit {
|
||||
public:
|
||||
MeasurementBaseUnit(gd::String name_, gd::String symbol_,
|
||||
gd::String quantity_)
|
||||
: name(name_), symbol(symbol_), quantity(quantity_) {}
|
||||
|
||||
virtual ~MeasurementBaseUnit();
|
||||
|
||||
/**
|
||||
* \brief Return the unit name.
|
||||
*/
|
||||
const gd::String &GetName() const { return name; }
|
||||
|
||||
/**
|
||||
* \brief Return the unit symbol.
|
||||
*/
|
||||
const gd::String &GetSymbol() const { return symbol; }
|
||||
|
||||
/**
|
||||
* \brief Return the physical quantity.
|
||||
*/
|
||||
const gd::String &GetQuantity() const { return quantity; }
|
||||
|
||||
static const gd::MeasurementBaseUnit degreeAngle;
|
||||
static const gd::MeasurementBaseUnit pixel;
|
||||
static const gd::MeasurementBaseUnit meter;
|
||||
static const gd::MeasurementBaseUnit second;
|
||||
static const gd::MeasurementBaseUnit kilogram;
|
||||
|
||||
private:
|
||||
gd::String name; ///< The unit name
|
||||
gd::String symbol; ///< The unit symbol
|
||||
gd::String quantity; ///< The physical quantity
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_MEASUREMENTBASEUNIT
|
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "MeasurementUnit.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
#include <vector>
|
||||
|
||||
namespace gd {
|
||||
|
||||
MeasurementUnit::~MeasurementUnit() {}
|
||||
|
||||
gd::MeasurementUnit MeasurementUnit::undefined = CreateUndefined();
|
||||
gd::MeasurementUnit MeasurementUnit::dimensionless = CreateDimensionless();
|
||||
gd::MeasurementUnit MeasurementUnit::degreeAngle = CreateDegreeAngle();
|
||||
gd::MeasurementUnit MeasurementUnit::second = CreateSecond();
|
||||
gd::MeasurementUnit MeasurementUnit::pixel = CreatePixel();
|
||||
gd::MeasurementUnit MeasurementUnit::pixelSpeed = CreatePixelSpeed();
|
||||
gd::MeasurementUnit MeasurementUnit::pixelAcceleration =
|
||||
CreatePixelAcceleration();
|
||||
gd::MeasurementUnit MeasurementUnit::newton = CreateNewton();
|
||||
gd::MeasurementUnit MeasurementUnit::angularSpeed = CreateAngularSpeed();
|
||||
|
||||
void MeasurementUnit::ApplyTranslation() {
|
||||
undefined = CreateUndefined();
|
||||
dimensionless = CreateDimensionless();
|
||||
degreeAngle = CreateDegreeAngle();
|
||||
second = CreateSecond();
|
||||
pixel = CreatePixel();
|
||||
pixelSpeed = CreatePixelSpeed();
|
||||
pixelAcceleration = CreatePixelAcceleration();
|
||||
newton = CreateNewton();
|
||||
angularSpeed = CreateAngularSpeed();
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -1,197 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_MEASUREMENTUNIT
|
||||
#define GDCORE_MEASUREMENTUNIT
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/MeasurementUnitElement.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
class MeasurementBaseUnit;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief A unit of measurement.
|
||||
*/
|
||||
class GD_CORE_API MeasurementUnit {
|
||||
public:
|
||||
MeasurementUnit(const std::vector<gd::MeasurementUnitElement> &elements_,
|
||||
gd::String name_, gd::String label_,
|
||||
gd::String elementsWithWords_, gd::String description_ = "")
|
||||
: elements(elements_), name(name_), label(label_),
|
||||
description(description_), elementsWithWords(elementsWithWords_) {}
|
||||
|
||||
MeasurementUnit(gd::String name_, gd::String label_,
|
||||
gd::String elementsWithWords_, gd::String description_ = "")
|
||||
: name(name_), label(label_), description(description_),
|
||||
elementsWithWords(elementsWithWords_) {}
|
||||
|
||||
virtual ~MeasurementUnit();
|
||||
|
||||
/**
|
||||
* \brief Return the unit name.
|
||||
*/
|
||||
const gd::String &GetName() const { return name; }
|
||||
|
||||
/**
|
||||
* \brief Return the unit label.
|
||||
*/
|
||||
const gd::String &GetLabel() const { return label; }
|
||||
|
||||
/**
|
||||
* \brief Return the unit description.
|
||||
*/
|
||||
const gd::String &GetDescription() const { return description; }
|
||||
|
||||
/**
|
||||
* \brief Return the unit description.
|
||||
*/
|
||||
const gd::String &GetElementsWithWords() const { return elementsWithWords; }
|
||||
|
||||
/**
|
||||
* \brief Return the unit elements.
|
||||
*/
|
||||
const std::vector<gd::MeasurementUnitElement> &GetElements() const {
|
||||
return elements;
|
||||
}
|
||||
|
||||
std::size_t GetElementsCount() const { return elements.size(); }
|
||||
|
||||
int GetElementPower(std::size_t elementIndex) const {
|
||||
return elements.at(elementIndex).GetPower();
|
||||
}
|
||||
|
||||
const gd::MeasurementBaseUnit &
|
||||
GetElementBaseUnit(std::size_t elementIndex) const {
|
||||
return elements.at(elementIndex).GetBaseUnit();
|
||||
}
|
||||
|
||||
bool IsUndefined() const { return this == &gd::MeasurementUnit::undefined; }
|
||||
|
||||
static void ApplyTranslation();
|
||||
|
||||
static gd::MeasurementUnit &GetUndefined() { return undefined; }
|
||||
|
||||
static gd::MeasurementUnit &GetDimensionless() { return dimensionless; }
|
||||
|
||||
static gd::MeasurementUnit &GetDegreeAngle() { return degreeAngle; }
|
||||
|
||||
static gd::MeasurementUnit &GetSecond() { return second; }
|
||||
|
||||
static gd::MeasurementUnit &GetPixel() { return pixel; }
|
||||
|
||||
static gd::MeasurementUnit &GetPixelSpeed() { return pixelSpeed; }
|
||||
|
||||
static gd::MeasurementUnit &GetPixelAcceleration() {
|
||||
return pixelAcceleration;
|
||||
}
|
||||
|
||||
static gd::MeasurementUnit &GetAngularSpeed() { return angularSpeed; }
|
||||
|
||||
static gd::MeasurementUnit &GetNewton() { return newton; }
|
||||
|
||||
private:
|
||||
static gd::MeasurementUnit undefined;
|
||||
static gd::MeasurementUnit dimensionless;
|
||||
static gd::MeasurementUnit degreeAngle;
|
||||
static gd::MeasurementUnit second;
|
||||
static gd::MeasurementUnit pixel;
|
||||
static gd::MeasurementUnit pixelSpeed;
|
||||
static gd::MeasurementUnit pixelAcceleration;
|
||||
static gd::MeasurementUnit newton;
|
||||
static gd::MeasurementUnit angularSpeed;
|
||||
|
||||
static gd::MeasurementUnit CreateUndefined() {
|
||||
return MeasurementUnit("Undefined", _("Undefined"), "");
|
||||
}
|
||||
|
||||
static gd::MeasurementUnit CreateDimensionless() {
|
||||
return MeasurementUnit("Dimensionless", _("Dimensionless"), "");
|
||||
}
|
||||
|
||||
static gd::MeasurementUnit CreateDegreeAngle() {
|
||||
std::vector<gd::MeasurementUnitElement> elements;
|
||||
elements.push_back(
|
||||
MeasurementUnitElement(gd::MeasurementBaseUnit::degreeAngle, 1));
|
||||
return MeasurementUnit(elements, "DegreeAngle", _("Angle"), _("degree"));
|
||||
}
|
||||
|
||||
static gd::MeasurementUnit CreateSecond() {
|
||||
std::vector<gd::MeasurementUnitElement> elements;
|
||||
elements.push_back(
|
||||
MeasurementUnitElement(gd::MeasurementBaseUnit::second, 1));
|
||||
return MeasurementUnit(elements, "Second", _("Duration"), _("second"));
|
||||
}
|
||||
|
||||
static gd::MeasurementUnit CreatePixel() {
|
||||
std::vector<gd::MeasurementUnitElement> elements;
|
||||
elements.push_back(
|
||||
MeasurementUnitElement(gd::MeasurementBaseUnit::pixel, 1));
|
||||
return MeasurementUnit(elements, "Pixel", _("Distance"), _("pixel"));
|
||||
}
|
||||
|
||||
static gd::MeasurementUnit CreatePixelSpeed() {
|
||||
std::vector<gd::MeasurementUnitElement> elements;
|
||||
elements.push_back(
|
||||
MeasurementUnitElement(gd::MeasurementBaseUnit::pixel, 1));
|
||||
elements.push_back(
|
||||
MeasurementUnitElement(gd::MeasurementBaseUnit::second, -1));
|
||||
return MeasurementUnit(elements, "PixelSpeed", _("Speed"),
|
||||
_("pixel per second"),
|
||||
_("How much distance is covered per second."));
|
||||
}
|
||||
|
||||
static gd::MeasurementUnit CreatePixelAcceleration() {
|
||||
std::vector<gd::MeasurementUnitElement> elements;
|
||||
elements.push_back(
|
||||
MeasurementUnitElement(gd::MeasurementBaseUnit::pixel, 1));
|
||||
elements.push_back(
|
||||
MeasurementUnitElement(gd::MeasurementBaseUnit::second, -2));
|
||||
return MeasurementUnit(elements, "PixelAcceleration", _("Acceleration"),
|
||||
_("pixel per second, per second"),
|
||||
_("How much speed is gained (or lost) per second."));
|
||||
}
|
||||
|
||||
static gd::MeasurementUnit CreateNewton() {
|
||||
std::vector<gd::MeasurementUnitElement> elements;
|
||||
elements.push_back(
|
||||
MeasurementUnitElement(gd::MeasurementBaseUnit::meter, 1));
|
||||
elements.push_back(
|
||||
MeasurementUnitElement(gd::MeasurementBaseUnit::kilogram, 1));
|
||||
elements.push_back(
|
||||
MeasurementUnitElement(gd::MeasurementBaseUnit::second, -2));
|
||||
return MeasurementUnit(
|
||||
elements, "Newton",
|
||||
_("Force (in Newton)"), _("meter kilogram per second, per second"),
|
||||
_("A unit to measure forces."));
|
||||
}
|
||||
|
||||
static gd::MeasurementUnit CreateAngularSpeed() {
|
||||
std::vector<gd::MeasurementUnitElement> elements;
|
||||
elements.push_back(
|
||||
MeasurementUnitElement(gd::MeasurementBaseUnit::degreeAngle, 1));
|
||||
elements.push_back(
|
||||
MeasurementUnitElement(gd::MeasurementBaseUnit::second, -1));
|
||||
return MeasurementUnit(elements, "AngularSpeed", _("Angular speed"),
|
||||
_("degree per second"),
|
||||
_("How much angle is covered per second."));
|
||||
}
|
||||
|
||||
gd::String name; ///< The unit name.
|
||||
gd::String label; ///< The unit label.
|
||||
gd::String description; ///< The unit description.
|
||||
gd::String elementsWithWords; ///< The unit elements put in words.
|
||||
std::vector<gd::MeasurementUnitElement> elements; ///< The unit elements.
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_MEASUREMENTUNIT
|
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "MeasurementUnitElement.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
#include <vector>
|
||||
|
||||
namespace gd {
|
||||
|
||||
MeasurementUnitElement::~MeasurementUnitElement() {}
|
||||
|
||||
} // namespace gd
|
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_MEASUREMENTUNITELEMENT
|
||||
#define GDCORE_MEASUREMENTUNITELEMENT
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/MeasurementBaseUnit.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief A couple of an atomic unit of measurement and its power.
|
||||
*/
|
||||
class GD_CORE_API MeasurementUnitElement {
|
||||
public:
|
||||
MeasurementUnitElement(const gd::MeasurementBaseUnit &baseUnit_, int power_)
|
||||
: baseUnit(baseUnit_), power(power_) {}
|
||||
|
||||
virtual ~MeasurementUnitElement();
|
||||
|
||||
/**
|
||||
* \brief Return the base unit.
|
||||
*/
|
||||
const gd::MeasurementBaseUnit &GetBaseUnit() const { return baseUnit; }
|
||||
|
||||
/**
|
||||
* \brief Return the power on the base unit.
|
||||
*/
|
||||
int GetPower() const { return power; }
|
||||
|
||||
private:
|
||||
gd::MeasurementBaseUnit baseUnit; ///< The base unit.
|
||||
int power; ///< The power on the base unit.
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_MEASUREMENTUNITELEMENT
|
@@ -114,7 +114,7 @@ gd::Behavior* Object::AddNewBehavior(const gd::Project& project,
|
||||
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
gd::LogWarning("Tried to create a behavior with an unknown type: " + type
|
||||
+ " on object " + GetName() + "!");
|
||||
// It's probably an events-based behavior that was removed.
|
||||
// It's probably an events-based object that was removed.
|
||||
// Create a custom behavior to preserve the properties values.
|
||||
return initializeAndAdd(
|
||||
gd::make_unique<CustomBehavior>(name, project, type));
|
||||
|
@@ -8,8 +8,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Project/MeasurementUnit.h"
|
||||
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
}
|
||||
@@ -30,12 +28,12 @@ class GD_CORE_API PropertyDescriptor {
|
||||
* \param propertyValue The value of the property.
|
||||
*/
|
||||
PropertyDescriptor(gd::String propertyValue)
|
||||
: currentValue(propertyValue), type("string"), label(""), hidden(false), measurementUnit(gd::MeasurementUnit::GetUndefined()) {}
|
||||
: currentValue(propertyValue), type("string"), label(""), hidden(false) {}
|
||||
|
||||
/**
|
||||
* \brief Empty constructor creating an empty property to be displayed.
|
||||
*/
|
||||
PropertyDescriptor() : hidden(false), measurementUnit(gd::MeasurementUnit::GetUndefined()) {};
|
||||
PropertyDescriptor() : hidden(false){};
|
||||
|
||||
/**
|
||||
* \brief Destructor
|
||||
@@ -105,21 +103,12 @@ class GD_CORE_API PropertyDescriptor {
|
||||
extraInformation.push_back(info);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Change the unit of measurement of the property value.
|
||||
*/
|
||||
PropertyDescriptor& SetMeasurementUnit(const gd::MeasurementUnit &measurementUnit_) {
|
||||
measurementUnit = measurementUnit_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const gd::String& GetValue() const { return currentValue; }
|
||||
const gd::String& GetType() const { return type; }
|
||||
const gd::String& GetLabel() const { return label; }
|
||||
const gd::String& GetDescription() const { return description; }
|
||||
const gd::String& GetGroup() const { return group; }
|
||||
const gd::MeasurementUnit& GetMeasurementUnit() const { return measurementUnit; }
|
||||
|
||||
const std::vector<gd::String>& GetExtraInfo() const {
|
||||
return extraInformation;
|
||||
@@ -179,7 +168,6 @@ class GD_CORE_API PropertyDescriptor {
|
||||
///< choices, if a property is a displayed as a combo
|
||||
///< box.
|
||||
bool hidden;
|
||||
gd::MeasurementUnit measurementUnit; //< The unit of measurement of the property vale.
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -208,7 +208,8 @@ SerializerElement& SerializerElement::GetChild(
|
||||
for (size_t i = 0; i < children.size(); ++i) {
|
||||
if (children[i].second == std::shared_ptr<SerializerElement>()) continue;
|
||||
|
||||
if (children[i].first == name || (isArray && children[i].first.empty()) ||
|
||||
if (children[i].first == name ||
|
||||
(isArray && children[i].first.empty()) ||
|
||||
(!deprecatedName.empty() && children[i].first == deprecatedName)) {
|
||||
if (index == currentIndex)
|
||||
return *children[i].second;
|
||||
@@ -241,7 +242,8 @@ std::size_t SerializerElement::GetChildrenCount(
|
||||
for (size_t i = 0; i < children.size(); ++i) {
|
||||
if (children[i].second == std::shared_ptr<SerializerElement>()) continue;
|
||||
|
||||
if (children[i].first == name || (isArray && children[i].first.empty()) ||
|
||||
if (children[i].first == name ||
|
||||
(isArray && children[i].first.empty()) ||
|
||||
(!deprecatedName.empty() && children[i].first == deprecatedName))
|
||||
currentIndex++;
|
||||
}
|
||||
@@ -289,31 +291,4 @@ void SerializerElement::Init(const gd::SerializerElement& other) {
|
||||
deprecatedArrayOf = other.deprecatedArrayOf;
|
||||
}
|
||||
|
||||
void SerializerElement::SetMultilineStringValue(const gd::String& value) {
|
||||
if (value.find('\n') == gd::String::npos) {
|
||||
SetStringValue(value);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<gd::String> lines = value.Split('\n');
|
||||
children.clear();
|
||||
ConsiderAsArrayOf("");
|
||||
for (const auto& line : lines) {
|
||||
AddChild("").SetStringValue(line);
|
||||
}
|
||||
}
|
||||
|
||||
gd::String SerializerElement::GetMultilineStringValue() {
|
||||
if (!ConsideredAsArray()) {
|
||||
return GetValue().GetString();
|
||||
}
|
||||
|
||||
gd::String value;
|
||||
for (const auto& child : children) {
|
||||
if (!value.empty()) value += "\n";
|
||||
value += child.second->GetStringValue();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -10,7 +10,6 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Serialization/SerializerValue.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
@@ -178,18 +177,6 @@ class GD_CORE_API SerializerElement {
|
||||
* \brief Return true if no value was set for the element.
|
||||
*/
|
||||
bool IsValueUndefined() const { return valueUndefined; }
|
||||
|
||||
/**
|
||||
* \brief Save the value either as a string or as an array of strings if it
|
||||
* has line breaks.
|
||||
*/
|
||||
void SetMultilineStringValue(const gd::String &value);
|
||||
|
||||
/**
|
||||
* \brief Read the value, either represented as a string or as an array of strings,
|
||||
* into a string.
|
||||
*/
|
||||
gd::String GetMultilineStringValue();
|
||||
///@}
|
||||
|
||||
/** \name Attributes
|
||||
@@ -453,7 +440,7 @@ class GD_CORE_API SerializerElement {
|
||||
* Initialize element using another element. Used by copy-ctor and assign-op.
|
||||
* Don't forget to update me if members were changed!
|
||||
*/
|
||||
void Init(const gd::SerializerElement &other);
|
||||
void Init(const gd::SerializerElement& other);
|
||||
|
||||
bool valueUndefined; ///< If true, the element does not have a value.
|
||||
SerializerValue elementValue;
|
||||
|
@@ -12,7 +12,6 @@
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCore/Events/Builtin/StandardEvent.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
// TODO Remove these 2 classes and write the test with events based behaviors.
|
||||
@@ -95,13 +94,6 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
// Don't show extension loading logs for tests (too verbose).
|
||||
platform.EnableExtensionLoadingLogs(false);
|
||||
|
||||
// Required for tests on event generation.
|
||||
std::shared_ptr<gd::PlatformExtension> commonInstructionsExtension =
|
||||
std::shared_ptr<gd::PlatformExtension>(new gd::PlatformExtension);
|
||||
commonInstructionsExtension->SetExtensionInformation(
|
||||
"BuiltinCommonInstructions", "instruction extension", "", "", "");
|
||||
commonInstructionsExtension->AddEvent("Standard", "Standard event", "", "", "", std::make_shared<gd::StandardEvent>());
|
||||
|
||||
std::shared_ptr<gd::PlatformExtension> baseObjectExtension =
|
||||
std::shared_ptr<gd::PlatformExtension>(new gd::PlatformExtension);
|
||||
|
||||
@@ -381,7 +373,6 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
.AddUnsupportedBaseObjectCapability("effect");
|
||||
}
|
||||
|
||||
platform.AddExtension(commonInstructionsExtension);
|
||||
platform.AddExtension(baseObjectExtension);
|
||||
platform.AddExtension(extension);
|
||||
project.AddPlatform(platform);
|
||||
|
@@ -1,739 +0,0 @@
|
||||
/*
|
||||
* 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 common features of GDevelop Core.
|
||||
*/
|
||||
#include "GDCore/IDE/PropertyFunctionGenerator.h"
|
||||
#include "DummyPlatform.h"
|
||||
#include "GDCore/Events/Builtin/StandardEvent.h"
|
||||
#include "GDCore/Extensions/Metadata/ValueTypeMetadata.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
gd::EventsBasedBehavior &
|
||||
CreateBehavior(gd::EventsFunctionsExtension &eventsExtension) {
|
||||
auto &eventsBasedBehavior =
|
||||
eventsExtension.GetEventsBasedBehaviors().InsertNew(
|
||||
"MyEventsBasedBehavior", 0);
|
||||
eventsBasedBehavior.SetFullName("My events based behavior");
|
||||
eventsBasedBehavior.SetDescription("An events based behavior for test");
|
||||
eventsBasedBehavior.SetObjectType("");
|
||||
return eventsBasedBehavior;
|
||||
};
|
||||
|
||||
gd::EventsBasedObject &
|
||||
CreateObject(gd::EventsFunctionsExtension &eventsExtension) {
|
||||
auto &eventsBasedObject = eventsExtension.GetEventsBasedObjects().InsertNew(
|
||||
"MyEventsBasedObject", 0);
|
||||
eventsBasedObject.SetFullName("My events based object");
|
||||
eventsBasedObject.SetDescription("An events based object for test");
|
||||
return eventsBasedObject;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("PropertyFunctionGenerator", "[common]") {
|
||||
SECTION("Can generate functions for a number property in a behavior") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &extension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
auto &behavior = CreateBehavior(extension);
|
||||
|
||||
auto &property =
|
||||
behavior.GetPropertyDescriptors().InsertNew("MovementAngle", 0);
|
||||
property.SetType("Number")
|
||||
.SetLabel("Movement angle")
|
||||
.SetDescription("The angle of the trajectory direction.")
|
||||
.SetGroup("Movement");
|
||||
|
||||
gd::PropertyFunctionGenerator::GenerateBehaviorGetterAndSetter(
|
||||
project, extension, behavior, property, false);
|
||||
|
||||
REQUIRE(
|
||||
behavior.GetEventsFunctions().HasEventsFunctionNamed("MovementAngle"));
|
||||
REQUIRE(behavior.GetEventsFunctions().HasEventsFunctionNamed(
|
||||
"SetMovementAngle"));
|
||||
{
|
||||
auto &getter =
|
||||
behavior.GetEventsFunctions().GetEventsFunction("MovementAngle");
|
||||
|
||||
REQUIRE(getter.GetFunctionType() ==
|
||||
gd::EventsFunction::ExpressionAndCondition);
|
||||
REQUIRE(getter.GetExpressionType().GetName() == "expression");
|
||||
REQUIRE(getter.GetFullName() == "Movement angle");
|
||||
REQUIRE(getter.GetGroup() ==
|
||||
"My events based behavior movement configuration");
|
||||
REQUIRE(getter.GetDescription() ==
|
||||
"the movement angle of the object. The "
|
||||
"angle of the trajectory direction.");
|
||||
REQUIRE(getter.GetSentence() == "the movement angle");
|
||||
// Object and behavior parameters are added automatically.
|
||||
REQUIRE(getter.GetParameters().size() == 0);
|
||||
|
||||
REQUIRE(getter.GetEvents().GetEventsCount() == 1);
|
||||
REQUIRE(getter.GetEvents().GetEvent(0).GetType() ==
|
||||
"BuiltinCommonInstructions::Standard");
|
||||
auto &getterEvent =
|
||||
dynamic_cast<gd::StandardEvent &>(getter.GetEvents().GetEvent(0));
|
||||
REQUIRE(getterEvent.GetConditions().size() == 0);
|
||||
REQUIRE(getterEvent.GetActions().size() == 1);
|
||||
auto &getterAction = getterEvent.GetActions().at(0);
|
||||
REQUIRE(getterAction.GetType() == "SetReturnNumber");
|
||||
REQUIRE(getterAction.GetParametersCount() == 1);
|
||||
REQUIRE(getterAction.GetParameter(0).GetPlainString() ==
|
||||
"Object.Behavior::PropertyMovementAngle()");
|
||||
}
|
||||
{
|
||||
auto &setter =
|
||||
behavior.GetEventsFunctions().GetEventsFunction("SetMovementAngle");
|
||||
|
||||
REQUIRE(setter.GetFunctionType() ==
|
||||
gd::EventsFunction::ActionWithOperator);
|
||||
REQUIRE(setter.GetGetterName() == "MovementAngle");
|
||||
// These fields are deducted from the getter.
|
||||
REQUIRE(setter.GetFullName() == "");
|
||||
REQUIRE(setter.GetGroup() == "");
|
||||
REQUIRE(setter.GetDescription() == "");
|
||||
REQUIRE(setter.GetSentence() == "");
|
||||
// Object and behavior parameters are added automatically.
|
||||
REQUIRE(setter.GetParameters().size() == 0);
|
||||
|
||||
REQUIRE(setter.GetEvents().GetEventsCount() == 1);
|
||||
REQUIRE(setter.GetEvents().GetEvent(0).GetType() ==
|
||||
"BuiltinCommonInstructions::Standard");
|
||||
auto &setterEvent =
|
||||
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().GetEvent(0));
|
||||
REQUIRE(setterEvent.GetConditions().size() == 0);
|
||||
REQUIRE(setterEvent.GetActions().size() == 1);
|
||||
auto &setterAction = setterEvent.GetActions().at(0);
|
||||
REQUIRE(
|
||||
setterAction.GetType() ==
|
||||
"MyEventsExtension::MyEventsBasedBehavior::SetPropertyMovementAngle");
|
||||
REQUIRE(setterAction.GetParametersCount() == 4);
|
||||
REQUIRE(setterAction.GetParameter(0).GetPlainString() == "Object");
|
||||
REQUIRE(setterAction.GetParameter(1).GetPlainString() == "Behavior");
|
||||
REQUIRE(setterAction.GetParameter(2).GetPlainString() == "=");
|
||||
REQUIRE(setterAction.GetParameter(3).GetPlainString() ==
|
||||
"GetArgumentAsNumber(\"Value\")");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Can generate functions for a choice property in a behavior") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &extension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
auto &behavior = CreateBehavior(extension);
|
||||
|
||||
auto &property =
|
||||
behavior.GetPropertyDescriptors().InsertNew("CollisionShape", 0);
|
||||
property.SetType("Choice")
|
||||
.SetLabel("Collision shape")
|
||||
.SetLabel("Dot shape")
|
||||
.SetDescription("The shape is used for collision.")
|
||||
.SetGroup("Movement");
|
||||
property.GetExtraInfo().push_back("Dot shape");
|
||||
property.GetExtraInfo().push_back("Bounding disk");
|
||||
|
||||
gd::PropertyFunctionGenerator::GenerateBehaviorGetterAndSetter(
|
||||
project, extension, behavior, property, false);
|
||||
|
||||
REQUIRE(
|
||||
behavior.GetEventsFunctions().HasEventsFunctionNamed("CollisionShape"));
|
||||
REQUIRE(behavior.GetEventsFunctions().HasEventsFunctionNamed(
|
||||
"SetCollisionShape"));
|
||||
|
||||
auto &getter =
|
||||
behavior.GetEventsFunctions().GetEventsFunction("CollisionShape");
|
||||
|
||||
REQUIRE(getter.GetFunctionType() ==
|
||||
gd::EventsFunction::ExpressionAndCondition);
|
||||
REQUIRE(getter.GetExpressionType().GetName() == "stringWithSelector");
|
||||
REQUIRE(getter.GetExpressionType().GetExtraInfo() ==
|
||||
"[\"Dot shape\",\"Bounding disk\"]");
|
||||
}
|
||||
|
||||
SECTION("Can generate functions for a boolean property in a behavior") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &extension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
auto &behavior = CreateBehavior(extension);
|
||||
|
||||
auto &property = behavior.GetPropertyDescriptors().InsertNew("Rotate", 0);
|
||||
property.SetType("Boolean")
|
||||
.SetLabel("Rotate object")
|
||||
.SetDescription(
|
||||
"The rotation follows movements done by this behavior only.")
|
||||
.SetGroup("Movement");
|
||||
|
||||
gd::PropertyFunctionGenerator::GenerateBehaviorGetterAndSetter(
|
||||
project, extension, behavior, property, false);
|
||||
|
||||
REQUIRE(behavior.GetEventsFunctions().HasEventsFunctionNamed("Rotate"));
|
||||
REQUIRE(behavior.GetEventsFunctions().HasEventsFunctionNamed("SetRotate"));
|
||||
{
|
||||
auto &getter = behavior.GetEventsFunctions().GetEventsFunction("Rotate");
|
||||
REQUIRE(getter.GetFunctionType() == gd::EventsFunction::Condition);
|
||||
REQUIRE(getter.GetExpressionType().GetName() == "boolean");
|
||||
REQUIRE(getter.GetFullName() == "Rotate object");
|
||||
REQUIRE(getter.GetGroup() ==
|
||||
"My events based behavior movement configuration");
|
||||
REQUIRE(getter.GetDescription() ==
|
||||
"Check if rotate object. The rotation follows movements done by "
|
||||
"this behavior only.");
|
||||
REQUIRE(getter.GetSentence() == "_PARAM0_ rotate object");
|
||||
// Object and behavior parameters are added automatically.
|
||||
REQUIRE(getter.GetParameters().size() == 0);
|
||||
|
||||
REQUIRE(getter.GetEvents().GetEventsCount() == 1);
|
||||
REQUIRE(getter.GetEvents().GetEvent(0).GetType() ==
|
||||
"BuiltinCommonInstructions::Standard");
|
||||
auto &getterEvent =
|
||||
dynamic_cast<gd::StandardEvent &>(getter.GetEvents().GetEvent(0));
|
||||
REQUIRE(getterEvent.GetConditions().size() == 1);
|
||||
REQUIRE(getterEvent.GetActions().size() == 1);
|
||||
|
||||
auto &getterCondition = getterEvent.GetConditions().at(0);
|
||||
REQUIRE(getterCondition.GetType() ==
|
||||
"MyEventsExtension::MyEventsBasedBehavior::PropertyRotate");
|
||||
REQUIRE(!getterCondition.IsInverted());
|
||||
REQUIRE(getterCondition.GetParametersCount() == 2);
|
||||
REQUIRE(getterCondition.GetParameter(0).GetPlainString() == "Object");
|
||||
REQUIRE(getterCondition.GetParameter(1).GetPlainString() == "Behavior");
|
||||
|
||||
auto &getterAction = getterEvent.GetActions().at(0);
|
||||
REQUIRE(getterAction.GetType() == "SetReturnBoolean");
|
||||
REQUIRE(getterAction.GetParametersCount() == 1);
|
||||
REQUIRE(getterAction.GetParameter(0).GetPlainString() == "True");
|
||||
}
|
||||
{
|
||||
auto &setter =
|
||||
behavior.GetEventsFunctions().GetEventsFunction("SetRotate");
|
||||
|
||||
REQUIRE(setter.GetFunctionType() == gd::EventsFunction::Action);
|
||||
REQUIRE(setter.GetFullName() == "Rotate object");
|
||||
REQUIRE(setter.GetGroup() ==
|
||||
"My events based behavior movement configuration");
|
||||
REQUIRE(setter.GetDescription() ==
|
||||
"Change if rotate object. The rotation follows movements done by "
|
||||
"this behavior only.");
|
||||
REQUIRE(setter.GetSentence() == "_PARAM0_ rotate object: _PARAM2_");
|
||||
// To generate the value parameter, object and behavior parameters has to
|
||||
// be declared too.
|
||||
REQUIRE(setter.GetParameters().size() == 3);
|
||||
auto &objectParameter = setter.GetParameters().at(0);
|
||||
REQUIRE(objectParameter.GetName() == "Object");
|
||||
REQUIRE(objectParameter.GetType() == "object");
|
||||
auto &behaviorParameter = setter.GetParameters().at(1);
|
||||
REQUIRE(behaviorParameter.GetName() == "Behavior");
|
||||
REQUIRE(behaviorParameter.GetType() == "behavior");
|
||||
REQUIRE(behaviorParameter.GetExtraInfo() ==
|
||||
"MyEventsExtension::MyEventsBasedBehavior");
|
||||
auto &valueParameter = setter.GetParameters().at(2);
|
||||
REQUIRE(valueParameter.GetName() == "Value");
|
||||
REQUIRE(valueParameter.GetType() == "yesorno");
|
||||
|
||||
REQUIRE(setter.GetEvents().GetEventsCount() == 2);
|
||||
REQUIRE(setter.GetEvents().GetEvent(0).GetType() ==
|
||||
"BuiltinCommonInstructions::Standard");
|
||||
REQUIRE(setter.GetEvents().GetEvent(1).GetType() ==
|
||||
"BuiltinCommonInstructions::Standard");
|
||||
|
||||
auto &setterNoEvent =
|
||||
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().GetEvent(0));
|
||||
REQUIRE(setterNoEvent.GetConditions().size() == 1);
|
||||
REQUIRE(setterNoEvent.GetActions().size() == 1);
|
||||
|
||||
auto &setterNoCondition = setterNoEvent.GetConditions().at(0);
|
||||
REQUIRE(setterNoCondition.GetType() == "GetArgumentAsBoolean");
|
||||
REQUIRE(setterNoCondition.IsInverted());
|
||||
REQUIRE(setterNoCondition.GetParametersCount() == 1);
|
||||
REQUIRE(setterNoCondition.GetParameter(0).GetPlainString() ==
|
||||
"\"Value\"");
|
||||
|
||||
auto &setterNoAction = setterNoEvent.GetActions().at(0);
|
||||
REQUIRE(setterNoAction.GetType() ==
|
||||
"MyEventsExtension::MyEventsBasedBehavior::SetPropertyRotate");
|
||||
REQUIRE(setterNoAction.GetParametersCount() == 3);
|
||||
REQUIRE(setterNoAction.GetParameter(0).GetPlainString() == "Object");
|
||||
REQUIRE(setterNoAction.GetParameter(1).GetPlainString() == "Behavior");
|
||||
REQUIRE(setterNoAction.GetParameter(2).GetPlainString() == "no");
|
||||
|
||||
auto &setterYesEvent =
|
||||
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().GetEvent(1));
|
||||
REQUIRE(setterYesEvent.GetConditions().size() == 1);
|
||||
REQUIRE(setterYesEvent.GetActions().size() == 1);
|
||||
|
||||
auto &setterYesCondition = setterYesEvent.GetConditions().at(0);
|
||||
REQUIRE(setterYesCondition.GetType() == "GetArgumentAsBoolean");
|
||||
REQUIRE(!setterYesCondition.IsInverted());
|
||||
REQUIRE(setterYesCondition.GetParametersCount() == 1);
|
||||
REQUIRE(setterYesCondition.GetParameter(0).GetPlainString() ==
|
||||
"\"Value\"");
|
||||
|
||||
auto &setterYesAction = setterYesEvent.GetActions().at(0);
|
||||
REQUIRE(setterYesAction.GetType() ==
|
||||
"MyEventsExtension::MyEventsBasedBehavior::SetPropertyRotate");
|
||||
REQUIRE(setterYesAction.GetParametersCount() == 3);
|
||||
REQUIRE(setterYesAction.GetParameter(0).GetPlainString() == "Object");
|
||||
REQUIRE(setterYesAction.GetParameter(1).GetPlainString() == "Behavior");
|
||||
REQUIRE(setterYesAction.GetParameter(2).GetPlainString() == "yes");
|
||||
}
|
||||
}
|
||||
SECTION("Can generate functions for a number property in an object") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &extension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
auto &object = CreateObject(extension);
|
||||
|
||||
auto &property =
|
||||
object.GetPropertyDescriptors().InsertNew("MovementAngle", 0);
|
||||
property.SetType("Number")
|
||||
.SetLabel("Movement angle")
|
||||
.SetDescription("The angle of the trajectory direction.")
|
||||
.SetGroup("Movement");
|
||||
|
||||
gd::PropertyFunctionGenerator::GenerateObjectGetterAndSetter(
|
||||
project, extension, object, property);
|
||||
|
||||
REQUIRE(
|
||||
object.GetEventsFunctions().HasEventsFunctionNamed("MovementAngle"));
|
||||
REQUIRE(
|
||||
object.GetEventsFunctions().HasEventsFunctionNamed("SetMovementAngle"));
|
||||
{
|
||||
auto &getter =
|
||||
object.GetEventsFunctions().GetEventsFunction("MovementAngle");
|
||||
|
||||
REQUIRE(getter.GetFunctionType() ==
|
||||
gd::EventsFunction::ExpressionAndCondition);
|
||||
REQUIRE(getter.GetExpressionType().GetName() == "expression");
|
||||
REQUIRE(getter.GetFullName() == "Movement angle");
|
||||
REQUIRE(getter.GetGroup() ==
|
||||
"My events based object movement configuration");
|
||||
REQUIRE(getter.GetDescription() ==
|
||||
"the movement angle of the object. The "
|
||||
"angle of the trajectory direction.");
|
||||
REQUIRE(getter.GetSentence() == "the movement angle");
|
||||
// Object parameter is added automatically.
|
||||
REQUIRE(getter.GetParameters().size() == 0);
|
||||
|
||||
REQUIRE(getter.GetEvents().GetEventsCount() == 1);
|
||||
REQUIRE(getter.GetEvents().GetEvent(0).GetType() ==
|
||||
"BuiltinCommonInstructions::Standard");
|
||||
auto &getterEvent =
|
||||
dynamic_cast<gd::StandardEvent &>(getter.GetEvents().GetEvent(0));
|
||||
REQUIRE(getterEvent.GetConditions().size() == 0);
|
||||
REQUIRE(getterEvent.GetActions().size() == 1);
|
||||
auto &getterAction = getterEvent.GetActions().at(0);
|
||||
REQUIRE(getterAction.GetType() == "SetReturnNumber");
|
||||
REQUIRE(getterAction.GetParametersCount() == 1);
|
||||
REQUIRE(getterAction.GetParameter(0).GetPlainString() ==
|
||||
"Object.PropertyMovementAngle()");
|
||||
}
|
||||
{
|
||||
auto &setter =
|
||||
object.GetEventsFunctions().GetEventsFunction("SetMovementAngle");
|
||||
|
||||
REQUIRE(setter.GetFunctionType() ==
|
||||
gd::EventsFunction::ActionWithOperator);
|
||||
REQUIRE(setter.GetGetterName() == "MovementAngle");
|
||||
// These fields are deducted from the getter.
|
||||
REQUIRE(setter.GetFullName() == "");
|
||||
REQUIRE(setter.GetGroup() == "");
|
||||
REQUIRE(setter.GetDescription() == "");
|
||||
REQUIRE(setter.GetSentence() == "");
|
||||
// Object parameter is added automatically.
|
||||
REQUIRE(setter.GetParameters().size() == 0);
|
||||
|
||||
REQUIRE(setter.GetEvents().GetEventsCount() == 1);
|
||||
REQUIRE(setter.GetEvents().GetEvent(0).GetType() ==
|
||||
"BuiltinCommonInstructions::Standard");
|
||||
auto &setterEvent =
|
||||
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().GetEvent(0));
|
||||
REQUIRE(setterEvent.GetConditions().size() == 0);
|
||||
REQUIRE(setterEvent.GetActions().size() == 1);
|
||||
auto &setterAction = setterEvent.GetActions().at(0);
|
||||
REQUIRE(
|
||||
setterAction.GetType() ==
|
||||
"MyEventsExtension::MyEventsBasedObject::SetPropertyMovementAngle");
|
||||
REQUIRE(setterAction.GetParametersCount() == 3);
|
||||
REQUIRE(setterAction.GetParameter(0).GetPlainString() == "Object");
|
||||
REQUIRE(setterAction.GetParameter(1).GetPlainString() == "=");
|
||||
REQUIRE(setterAction.GetParameter(2).GetPlainString() ==
|
||||
"GetArgumentAsNumber(\"Value\")");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Can generate functions for a choice property in an object") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &extension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
auto &object = CreateObject(extension);
|
||||
|
||||
auto &property =
|
||||
object.GetPropertyDescriptors().InsertNew("CollisionShape", 0);
|
||||
property.SetType("Choice")
|
||||
.SetLabel("Collision shape")
|
||||
.SetLabel("Dot shape")
|
||||
.SetDescription("The shape is used for collision.")
|
||||
.SetGroup("Movement");
|
||||
property.GetExtraInfo().push_back("Dot shape");
|
||||
property.GetExtraInfo().push_back("Bounding disk");
|
||||
|
||||
gd::PropertyFunctionGenerator::GenerateObjectGetterAndSetter(
|
||||
project, extension, object, property);
|
||||
|
||||
REQUIRE(
|
||||
object.GetEventsFunctions().HasEventsFunctionNamed("CollisionShape"));
|
||||
REQUIRE(object.GetEventsFunctions().HasEventsFunctionNamed(
|
||||
"SetCollisionShape"));
|
||||
|
||||
auto &getter =
|
||||
object.GetEventsFunctions().GetEventsFunction("CollisionShape");
|
||||
|
||||
REQUIRE(getter.GetFunctionType() ==
|
||||
gd::EventsFunction::ExpressionAndCondition);
|
||||
REQUIRE(getter.GetExpressionType().GetName() == "stringWithSelector");
|
||||
REQUIRE(getter.GetExpressionType().GetExtraInfo() ==
|
||||
"[\"Dot shape\",\"Bounding disk\"]");
|
||||
}
|
||||
|
||||
SECTION("Can generate functions for a boolean property in an object") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &extension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
auto &object = CreateObject(extension);
|
||||
|
||||
auto &property = object.GetPropertyDescriptors().InsertNew("Rotate", 0);
|
||||
property.SetType("Boolean")
|
||||
.SetLabel("Rotate object")
|
||||
.SetDescription("The rotation follows movements done by this object.")
|
||||
.SetGroup("Movement");
|
||||
|
||||
gd::PropertyFunctionGenerator::GenerateObjectGetterAndSetter(
|
||||
project, extension, object, property);
|
||||
|
||||
REQUIRE(object.GetEventsFunctions().HasEventsFunctionNamed("Rotate"));
|
||||
REQUIRE(object.GetEventsFunctions().HasEventsFunctionNamed("SetRotate"));
|
||||
{
|
||||
auto &getter = object.GetEventsFunctions().GetEventsFunction("Rotate");
|
||||
REQUIRE(getter.GetFunctionType() == gd::EventsFunction::Condition);
|
||||
REQUIRE(getter.GetExpressionType().GetName() == "boolean");
|
||||
REQUIRE(getter.GetFullName() == "Rotate object");
|
||||
REQUIRE(getter.GetGroup() ==
|
||||
"My events based object movement configuration");
|
||||
REQUIRE(getter.GetDescription() ==
|
||||
"Check if rotate object. The rotation follows movements done by "
|
||||
"this object.");
|
||||
REQUIRE(getter.GetSentence() == "_PARAM0_ rotate object");
|
||||
// The Object parameter is added automatically.
|
||||
REQUIRE(getter.GetParameters().size() == 0);
|
||||
|
||||
REQUIRE(getter.GetEvents().GetEventsCount() == 1);
|
||||
REQUIRE(getter.GetEvents().GetEvent(0).GetType() ==
|
||||
"BuiltinCommonInstructions::Standard");
|
||||
auto &getterEvent =
|
||||
dynamic_cast<gd::StandardEvent &>(getter.GetEvents().GetEvent(0));
|
||||
REQUIRE(getterEvent.GetConditions().size() == 1);
|
||||
REQUIRE(getterEvent.GetActions().size() == 1);
|
||||
|
||||
auto &getterCondition = getterEvent.GetConditions().at(0);
|
||||
REQUIRE(getterCondition.GetType() ==
|
||||
"MyEventsExtension::MyEventsBasedObject::PropertyRotate");
|
||||
REQUIRE(!getterCondition.IsInverted());
|
||||
REQUIRE(getterCondition.GetParametersCount() == 1);
|
||||
REQUIRE(getterCondition.GetParameter(0).GetPlainString() == "Object");
|
||||
|
||||
auto &getterAction = getterEvent.GetActions().at(0);
|
||||
REQUIRE(getterAction.GetType() == "SetReturnBoolean");
|
||||
REQUIRE(getterAction.GetParametersCount() == 1);
|
||||
REQUIRE(getterAction.GetParameter(0).GetPlainString() == "True");
|
||||
}
|
||||
{
|
||||
auto &setter = object.GetEventsFunctions().GetEventsFunction("SetRotate");
|
||||
|
||||
REQUIRE(setter.GetFunctionType() == gd::EventsFunction::Action);
|
||||
REQUIRE(setter.GetFullName() == "Rotate object");
|
||||
REQUIRE(setter.GetGroup() ==
|
||||
"My events based object movement configuration");
|
||||
REQUIRE(setter.GetDescription() ==
|
||||
"Change if rotate object. The rotation follows movements done by "
|
||||
"this object.");
|
||||
REQUIRE(setter.GetSentence() == "_PARAM0_ rotate object: _PARAM1_");
|
||||
// To generate the value parameter, the object parameter has to
|
||||
// be declared too.
|
||||
REQUIRE(setter.GetParameters().size() == 2);
|
||||
auto &objectParameter = setter.GetParameters().at(0);
|
||||
REQUIRE(objectParameter.GetName() == "Object");
|
||||
REQUIRE(objectParameter.GetType() == "object");
|
||||
REQUIRE(objectParameter.GetExtraInfo() ==
|
||||
"MyEventsExtension::MyEventsBasedObject");
|
||||
auto &valueParameter = setter.GetParameters().at(1);
|
||||
REQUIRE(valueParameter.GetName() == "Value");
|
||||
REQUIRE(valueParameter.GetType() == "yesorno");
|
||||
|
||||
REQUIRE(setter.GetEvents().GetEventsCount() == 2);
|
||||
REQUIRE(setter.GetEvents().GetEvent(0).GetType() ==
|
||||
"BuiltinCommonInstructions::Standard");
|
||||
REQUIRE(setter.GetEvents().GetEvent(1).GetType() ==
|
||||
"BuiltinCommonInstructions::Standard");
|
||||
|
||||
auto &setterNoEvent =
|
||||
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().GetEvent(0));
|
||||
REQUIRE(setterNoEvent.GetConditions().size() == 1);
|
||||
REQUIRE(setterNoEvent.GetActions().size() == 1);
|
||||
|
||||
auto &setterNoCondition = setterNoEvent.GetConditions().at(0);
|
||||
REQUIRE(setterNoCondition.GetType() == "GetArgumentAsBoolean");
|
||||
REQUIRE(setterNoCondition.IsInverted());
|
||||
REQUIRE(setterNoCondition.GetParametersCount() == 1);
|
||||
REQUIRE(setterNoCondition.GetParameter(0).GetPlainString() ==
|
||||
"\"Value\"");
|
||||
|
||||
auto &setterNoAction = setterNoEvent.GetActions().at(0);
|
||||
REQUIRE(setterNoAction.GetType() ==
|
||||
"MyEventsExtension::MyEventsBasedObject::SetPropertyRotate");
|
||||
REQUIRE(setterNoAction.GetParametersCount() == 2);
|
||||
REQUIRE(setterNoAction.GetParameter(0).GetPlainString() == "Object");
|
||||
REQUIRE(setterNoAction.GetParameter(1).GetPlainString() == "no");
|
||||
|
||||
auto &setterYesEvent =
|
||||
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().GetEvent(1));
|
||||
REQUIRE(setterYesEvent.GetConditions().size() == 1);
|
||||
REQUIRE(setterYesEvent.GetActions().size() == 1);
|
||||
|
||||
auto &setterYesCondition = setterYesEvent.GetConditions().at(0);
|
||||
REQUIRE(setterYesCondition.GetType() == "GetArgumentAsBoolean");
|
||||
REQUIRE(!setterYesCondition.IsInverted());
|
||||
REQUIRE(setterYesCondition.GetParametersCount() == 1);
|
||||
REQUIRE(setterYesCondition.GetParameter(0).GetPlainString() ==
|
||||
"\"Value\"");
|
||||
|
||||
auto &setterYesAction = setterYesEvent.GetActions().at(0);
|
||||
REQUIRE(setterYesAction.GetType() ==
|
||||
"MyEventsExtension::MyEventsBasedObject::SetPropertyRotate");
|
||||
REQUIRE(setterYesAction.GetParametersCount() == 2);
|
||||
REQUIRE(setterYesAction.GetParameter(0).GetPlainString() == "Object");
|
||||
REQUIRE(setterYesAction.GetParameter(1).GetPlainString() == "yes");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Can generate functions for a shared property") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &extension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
auto &behavior = CreateBehavior(extension);
|
||||
|
||||
auto &property =
|
||||
behavior.GetSharedPropertyDescriptors().InsertNew("MovementAngle", 0);
|
||||
property.SetType("Number")
|
||||
.SetLabel("Movement angle")
|
||||
.SetDescription("The angle of the trajectory direction.")
|
||||
.SetGroup("Movement");
|
||||
|
||||
gd::PropertyFunctionGenerator::GenerateBehaviorGetterAndSetter(
|
||||
project, extension, behavior, property, true);
|
||||
|
||||
REQUIRE(
|
||||
behavior.GetEventsFunctions().HasEventsFunctionNamed("MovementAngle"));
|
||||
REQUIRE(behavior.GetEventsFunctions().HasEventsFunctionNamed(
|
||||
"SetMovementAngle"));
|
||||
{
|
||||
auto &getter =
|
||||
behavior.GetEventsFunctions().GetEventsFunction("MovementAngle");
|
||||
REQUIRE(getter.GetDescription() ==
|
||||
"the movement angle. The angle of the trajectory direction. "
|
||||
"While an object is needed, this will apply to all objects using "
|
||||
"the behavior.");
|
||||
|
||||
REQUIRE(getter.GetEvents().GetEventsCount() == 1);
|
||||
REQUIRE(getter.GetEvents().GetEvent(0).GetType() ==
|
||||
"BuiltinCommonInstructions::Standard");
|
||||
auto &getterEvent =
|
||||
dynamic_cast<gd::StandardEvent &>(getter.GetEvents().GetEvent(0));
|
||||
REQUIRE(getterEvent.GetConditions().size() == 0);
|
||||
REQUIRE(getterEvent.GetActions().size() == 1);
|
||||
auto &getterAction = getterEvent.GetActions().at(0);
|
||||
REQUIRE(getterAction.GetType() == "SetReturnNumber");
|
||||
REQUIRE(getterAction.GetParametersCount() == 1);
|
||||
REQUIRE(getterAction.GetParameter(0).GetPlainString() ==
|
||||
"Object.Behavior::SharedPropertyMovementAngle()");
|
||||
}
|
||||
{
|
||||
auto &setter =
|
||||
behavior.GetEventsFunctions().GetEventsFunction("SetMovementAngle");
|
||||
|
||||
REQUIRE(setter.GetEvents().GetEventsCount() == 1);
|
||||
REQUIRE(setter.GetEvents().GetEvent(0).GetType() ==
|
||||
"BuiltinCommonInstructions::Standard");
|
||||
auto &setterEvent =
|
||||
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().GetEvent(0));
|
||||
REQUIRE(setterEvent.GetConditions().size() == 0);
|
||||
REQUIRE(setterEvent.GetActions().size() == 1);
|
||||
auto &setterAction = setterEvent.GetActions().at(0);
|
||||
REQUIRE(setterAction.GetType() ==
|
||||
"MyEventsExtension::MyEventsBasedBehavior::"
|
||||
"SetSharedPropertyMovementAngle");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Allow functions generation when there is no setter") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &extension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
auto &behavior = CreateBehavior(extension);
|
||||
|
||||
auto &property =
|
||||
behavior.GetPropertyDescriptors().InsertNew("MovementAngle", 0);
|
||||
property.SetType("Number")
|
||||
.SetLabel("Movement angle")
|
||||
.SetDescription("The angle of the trajectory direction.")
|
||||
.SetGroup("Movement");
|
||||
|
||||
REQUIRE(gd::PropertyFunctionGenerator::CanGenerateGetterAndSetter(
|
||||
behavior, property));
|
||||
}
|
||||
|
||||
SECTION("Forbid functions generation when a getter exists") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &extension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
auto &behavior = CreateBehavior(extension);
|
||||
|
||||
auto &property =
|
||||
behavior.GetPropertyDescriptors().InsertNew("MovementAngle", 0);
|
||||
property.SetType("Number")
|
||||
.SetLabel("Movement angle")
|
||||
.SetDescription("The angle of the trajectory direction.")
|
||||
.SetGroup("Movement");
|
||||
|
||||
behavior.GetEventsFunctions().InsertNewEventsFunction("MovementAngle", 0);
|
||||
|
||||
REQUIRE(!gd::PropertyFunctionGenerator::CanGenerateGetterAndSetter(
|
||||
behavior, property));
|
||||
}
|
||||
|
||||
SECTION("Forbid functions generation when a setter exists") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &extension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
auto &behavior = CreateBehavior(extension);
|
||||
|
||||
auto &property =
|
||||
behavior.GetPropertyDescriptors().InsertNew("MovementAngle", 0);
|
||||
property.SetType("Number")
|
||||
.SetLabel("Movement angle")
|
||||
.SetDescription("The angle of the trajectory direction.")
|
||||
.SetGroup("Movement");
|
||||
|
||||
behavior.GetEventsFunctions().InsertNewEventsFunction("SetMovementAngle",
|
||||
0);
|
||||
|
||||
REQUIRE(!gd::PropertyFunctionGenerator::CanGenerateGetterAndSetter(
|
||||
behavior, property));
|
||||
}
|
||||
|
||||
SECTION("Forbid functions generation when both setter and getter exist") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &extension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
auto &behavior = CreateBehavior(extension);
|
||||
|
||||
auto &property =
|
||||
behavior.GetPropertyDescriptors().InsertNew("MovementAngle", 0);
|
||||
property.SetType("Number")
|
||||
.SetLabel("Movement angle")
|
||||
.SetDescription("The angle of the trajectory direction.")
|
||||
.SetGroup("Movement");
|
||||
|
||||
behavior.GetEventsFunctions().InsertNewEventsFunction("MovementAngle", 0);
|
||||
behavior.GetEventsFunctions().InsertNewEventsFunction("SetMovementAngle",
|
||||
0);
|
||||
|
||||
REQUIRE(!gd::PropertyFunctionGenerator::CanGenerateGetterAndSetter(
|
||||
behavior, property));
|
||||
}
|
||||
|
||||
SECTION("Forbid functions generation for required behavior properties") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &extension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
auto &behavior = CreateBehavior(extension);
|
||||
|
||||
auto &property =
|
||||
behavior.GetPropertyDescriptors().InsertNew("MovementAngle", 0);
|
||||
property.SetType("Behavior")
|
||||
.SetLabel("Pathfinding behavior")
|
||||
.SetDescription("A required behavior.")
|
||||
.SetGroup("Movement")
|
||||
.GetExtraInfo()
|
||||
.push_back("PlatformBehavior::PlatformerObjectBehavior");
|
||||
|
||||
REQUIRE(!gd::PropertyFunctionGenerator::CanGenerateGetterAndSetter(
|
||||
behavior, property));
|
||||
}
|
||||
|
||||
SECTION("Can generate functions when only the property name is filled") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &extension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
auto &behavior = CreateBehavior(extension);
|
||||
|
||||
auto &property =
|
||||
behavior.GetPropertyDescriptors().InsertNew("MovementAngle", 0);
|
||||
property.SetType("Number");
|
||||
|
||||
gd::PropertyFunctionGenerator::GenerateBehaviorGetterAndSetter(
|
||||
project, extension, behavior, property, false);
|
||||
|
||||
REQUIRE(
|
||||
behavior.GetEventsFunctions().HasEventsFunctionNamed("MovementAngle"));
|
||||
REQUIRE(behavior.GetEventsFunctions().HasEventsFunctionNamed(
|
||||
"SetMovementAngle"));
|
||||
|
||||
auto &getter =
|
||||
behavior.GetEventsFunctions().GetEventsFunction("MovementAngle");
|
||||
|
||||
REQUIRE(getter.GetFunctionType() ==
|
||||
gd::EventsFunction::ExpressionAndCondition);
|
||||
REQUIRE(getter.GetExpressionType().GetName() == "expression");
|
||||
REQUIRE(getter.GetFullName() == "MovementAngle");
|
||||
REQUIRE(getter.GetGroup() == "My events based behavior configuration");
|
||||
REQUIRE(getter.GetDescription() == "the movementAngle of the object.");
|
||||
REQUIRE(getter.GetSentence() == "the movementAngle");
|
||||
}
|
||||
}
|
@@ -81,30 +81,6 @@ TEST_CASE("SerializerElement", "[common]") {
|
||||
REQUIRE(element.GetChild(2).GetDoubleValue() == 45.6);
|
||||
}
|
||||
|
||||
SECTION("Multiline strings") {
|
||||
SerializerElement element;
|
||||
|
||||
// A single line is saved as a string.
|
||||
element.SetMultilineStringValue("test");
|
||||
REQUIRE(element.GetMultilineStringValue() == "test");
|
||||
REQUIRE(element.GetStringValue() == "test");
|
||||
|
||||
// A string can be read.
|
||||
element.SetStringValue("test of\nsomething\nsaved as a string");
|
||||
REQUIRE(element.GetMultilineStringValue() == "test of\nsomething\nsaved as a string");
|
||||
|
||||
// A multi lines string is saved as an array.
|
||||
element.SetMultilineStringValue("test\nwith\nmultiple lines.");
|
||||
REQUIRE(element.ConsideredAsArray() == true);
|
||||
REQUIRE(element.GetChildrenCount() == 3);
|
||||
REQUIRE(element.GetMultilineStringValue() == "test\nwith\nmultiple lines.");
|
||||
|
||||
element.SetMultilineStringValue("test\n\nwith\n\nmultiple lines.\n");
|
||||
REQUIRE(element.ConsideredAsArray() == true);
|
||||
REQUIRE(element.GetChildrenCount() == 6);
|
||||
REQUIRE(element.GetMultilineStringValue() == "test\n\nwith\n\nmultiple lines.\n");
|
||||
}
|
||||
|
||||
SECTION("(Deprecated) attributes") {
|
||||
SerializerElement element;
|
||||
element.AddChild("child1").SetStringValue("value123");
|
||||
|
@@ -80,9 +80,6 @@ enum TestEvent {
|
||||
BehaviorPropertyAction,
|
||||
BehaviorPropertyCondition,
|
||||
BehaviorPropertyExpression,
|
||||
BehaviorSharedPropertyAction,
|
||||
BehaviorSharedPropertyCondition,
|
||||
BehaviorSharedPropertyExpression,
|
||||
BehaviorExpression,
|
||||
IllNamedBehaviorExpression,
|
||||
NoParameterBehaviorExpression,
|
||||
@@ -341,52 +338,6 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != BehaviorSharedPropertyAction) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event in the layout using "MyProperty" action
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction instruction;
|
||||
instruction.SetType(
|
||||
"MyEventsExtension::MyEventsBasedBehavior::" +
|
||||
gd::EventsBasedBehavior::GetSharedPropertyActionName("MyProperty"));
|
||||
event.GetActions().Insert(instruction);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != BehaviorSharedPropertyCondition) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event in the layout using "MyProperty" condition
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction instruction;
|
||||
instruction.SetType(
|
||||
"MyEventsExtension::MyEventsBasedBehavior::" +
|
||||
gd::EventsBasedBehavior::GetSharedPropertyConditionName("MyProperty"));
|
||||
event.GetConditions().Insert(instruction);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != BehaviorSharedPropertyExpression) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event in the layout using "MyProperty" expression
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction instruction;
|
||||
instruction.SetType("MyExtension::DoSomething");
|
||||
instruction.SetParametersCount(1);
|
||||
instruction.SetParameter(
|
||||
0, gd::Expression("ObjectWithMyBehavior.MyBehavior::" +
|
||||
gd::EventsBasedBehavior::GetSharedPropertyExpressionName(
|
||||
"MyProperty") +
|
||||
"()"));
|
||||
event.GetActions().Insert(instruction);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != BehaviorExpression) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
@@ -860,11 +811,6 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
eventsBasedBehavior.GetPropertyDescriptors()
|
||||
.InsertNew("MyProperty", 0)
|
||||
.SetType("Number");
|
||||
// The same name is used for the shared property to ensure there is no name
|
||||
// collision.
|
||||
eventsBasedBehavior.GetSharedPropertyDescriptors()
|
||||
.InsertNew("MyProperty", 0)
|
||||
.SetType("Number");
|
||||
}
|
||||
|
||||
// Add a events based object
|
||||
@@ -1486,10 +1432,6 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
eventsList->GetEvent(BehaviorPropertyAction)) ==
|
||||
"MyRenamedExtension::MyEventsBasedBehavior::"
|
||||
"SetPropertyMyProperty");
|
||||
REQUIRE(GetEventFirstActionType(
|
||||
eventsList->GetEvent(BehaviorSharedPropertyAction)) ==
|
||||
"MyRenamedExtension::MyEventsBasedBehavior::"
|
||||
"SetSharedPropertyMyProperty");
|
||||
|
||||
// Check events-based behavior methods have *not* been renamed in
|
||||
// expressions
|
||||
@@ -1804,10 +1746,6 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
eventsList->GetEvent(BehaviorPropertyAction)) ==
|
||||
"MyEventsExtension::MyRenamedEventsBasedBehavior::"
|
||||
"SetPropertyMyProperty");
|
||||
REQUIRE(GetEventFirstActionType(
|
||||
eventsList->GetEvent(BehaviorSharedPropertyAction)) ==
|
||||
"MyEventsExtension::MyRenamedEventsBasedBehavior::"
|
||||
"SetSharedPropertyMyProperty");
|
||||
|
||||
// Check events-based behavior methods have *not* been renamed in
|
||||
// expressions
|
||||
@@ -2389,7 +2327,8 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Events based behavior) property renamed (not a required behavior)") {
|
||||
SECTION(
|
||||
"(Events based behavior) property renamed (not a required behavior)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
@@ -2417,67 +2356,6 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(BehaviorPropertyExpression)) ==
|
||||
"ObjectWithMyBehavior.MyBehavior::PropertyMyRenamedProperty()");
|
||||
|
||||
// Ensure that the shared property was NOT renamed.
|
||||
REQUIRE(GetEventFirstActionType(
|
||||
eventsList->GetEvent(BehaviorSharedPropertyAction)) ==
|
||||
"MyEventsExtension::MyEventsBasedBehavior::"
|
||||
"SetSharedPropertyMyProperty");
|
||||
|
||||
REQUIRE(GetEventFirstConditionType(
|
||||
eventsList->GetEvent(BehaviorSharedPropertyCondition)) ==
|
||||
"MyEventsExtension::MyEventsBasedBehavior::"
|
||||
"SharedPropertyMyProperty");
|
||||
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(BehaviorSharedPropertyExpression)) ==
|
||||
"ObjectWithMyBehavior.MyBehavior::SharedPropertyMyProperty()");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Events based behavior) shared property renamed") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &eventsBasedBehavior =
|
||||
eventsExtension.GetEventsBasedBehaviors().Get("MyEventsBasedBehavior");
|
||||
|
||||
gd::WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
|
||||
project, eventsExtension, eventsBasedBehavior, "MyProperty",
|
||||
"MyRenamedProperty");
|
||||
|
||||
for (auto *eventsList : GetEventsLists(project)) {
|
||||
// Check if events-based behaviors shared property has been renamed in
|
||||
// instructions
|
||||
REQUIRE(GetEventFirstActionType(
|
||||
eventsList->GetEvent(BehaviorSharedPropertyAction)) ==
|
||||
"MyEventsExtension::MyEventsBasedBehavior::"
|
||||
"SetSharedPropertyMyRenamedProperty");
|
||||
|
||||
REQUIRE(GetEventFirstConditionType(
|
||||
eventsList->GetEvent(BehaviorSharedPropertyCondition)) ==
|
||||
"MyEventsExtension::MyEventsBasedBehavior::"
|
||||
"SharedPropertyMyRenamedProperty");
|
||||
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(BehaviorSharedPropertyExpression)) ==
|
||||
"ObjectWithMyBehavior.MyBehavior::SharedPropertyMyRenamedProperty()");
|
||||
|
||||
// Ensure that the property was NOT renamed.
|
||||
REQUIRE(GetEventFirstActionType(
|
||||
eventsList->GetEvent(BehaviorPropertyAction)) ==
|
||||
"MyEventsExtension::MyEventsBasedBehavior::"
|
||||
"SetPropertyMyProperty");
|
||||
|
||||
REQUIRE(GetEventFirstConditionType(
|
||||
eventsList->GetEvent(BehaviorPropertyCondition)) ==
|
||||
"MyEventsExtension::MyEventsBasedBehavior::"
|
||||
"PropertyMyProperty");
|
||||
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(BehaviorPropertyExpression)) ==
|
||||
"ObjectWithMyBehavior.MyBehavior::PropertyMyProperty()");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -62,6 +62,16 @@ describe('gdjs.AnchorRuntimeBehavior', function () {
|
||||
return object;
|
||||
}
|
||||
|
||||
function getAnchorBehavior(object) {
|
||||
const behavior = object.getBehavior(anchorBehaviorName);
|
||||
if (!(behavior instanceof gdjs.AnchorRuntimeBehavior)) {
|
||||
throw new Error(
|
||||
'Expected behavior to be an instance of gdjs.AnchorBehavior'
|
||||
);
|
||||
}
|
||||
return behavior;
|
||||
}
|
||||
|
||||
describe('(anchor horizontal edge)', function () {
|
||||
['rightEdgeAnchor', 'leftEdgeAnchor'].forEach((objectEdge) => {
|
||||
it(`anchors the ${objectEdge} edge of object to window left (fixed)`, function () {
|
||||
|
@@ -25,7 +25,6 @@ DestroyOutsideBehavior::GetProperties(
|
||||
.SetValue(gd::String::From(
|
||||
behaviorContent.GetDoubleAttribute("extraBorder", 0)))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetLabel(_("Margin before deleting the object, in pixels"));
|
||||
|
||||
return properties;
|
||||
|
@@ -15,9 +15,9 @@ namespace gdjs {
|
||||
this._textToSet = behaviorData.property1;
|
||||
|
||||
// You can also access to the shared data:
|
||||
const sharedData = instanceContainer.getInitialSharedDataForBehavior(
|
||||
behaviorData.name
|
||||
);
|
||||
const sharedData = instanceContainer
|
||||
.getScene()
|
||||
.getInitialSharedDataForBehavior(behaviorData.name);
|
||||
this._textToSet = (sharedData as any).sharedProperty1;
|
||||
|
||||
// You can also run arbitrary code at the creation of the behavior:
|
||||
|
@@ -239,14 +239,14 @@ describe('gdjs.LinksManager', function () {
|
||||
manager.removeAllLinksOf(object1A);
|
||||
manager.removeAllLinksOf(object1A);
|
||||
{
|
||||
const { pickedSomething } = pickObjectsLinkedTo(
|
||||
const { pickedSomething, objectsLists } = pickObjectsLinkedTo(
|
||||
object1A,
|
||||
Hashtable.newFrom({ obj2: [object2A, object2B, object2C] })
|
||||
);
|
||||
expect(pickedSomething).to.be(false);
|
||||
}
|
||||
{
|
||||
const { pickedSomething } = pickObjectsLinkedTo(
|
||||
const { pickedSomething, objectsLists } = pickObjectsLinkedTo(
|
||||
object2A,
|
||||
Hashtable.newFrom({ obj1: [object1A, object1B, object1C] })
|
||||
);
|
||||
|
@@ -33,24 +33,27 @@ namespace gdjs {
|
||||
const StretchedSprite = !tiled ? PIXI.Sprite : PIXI.TilingSprite;
|
||||
this._spritesContainer = new PIXI.Container();
|
||||
this._wrapperContainer = new PIXI.Container();
|
||||
this._centerSprite = new StretchedSprite(
|
||||
new PIXI.Texture(texture.baseTexture)
|
||||
);
|
||||
// @ts-ignore
|
||||
this._centerSprite = new StretchedSprite(new PIXI.Texture(texture));
|
||||
this._borderSprites = [
|
||||
// Right
|
||||
new StretchedSprite(new PIXI.Texture(texture.baseTexture)),
|
||||
// Top-Right
|
||||
// @ts-ignore
|
||||
new StretchedSprite(new PIXI.Texture(texture)),
|
||||
//Right
|
||||
new PIXI.Sprite(texture),
|
||||
// Top
|
||||
new StretchedSprite(new PIXI.Texture(texture.baseTexture)),
|
||||
// Top-Left
|
||||
//Top-Right
|
||||
// @ts-ignore
|
||||
new StretchedSprite(new PIXI.Texture(texture)),
|
||||
//Top
|
||||
new PIXI.Sprite(texture),
|
||||
// Left
|
||||
new StretchedSprite(new PIXI.Texture(texture.baseTexture)),
|
||||
// Bottom-Left
|
||||
//Top-Left
|
||||
// @ts-ignore
|
||||
new StretchedSprite(new PIXI.Texture(texture)),
|
||||
//Left
|
||||
new PIXI.Sprite(texture),
|
||||
// Bottom
|
||||
new StretchedSprite(new PIXI.Texture(texture.baseTexture)),
|
||||
//Bottom-Left
|
||||
// @ts-ignore
|
||||
new StretchedSprite(new PIXI.Texture(texture)),
|
||||
//Bottom
|
||||
new PIXI.Sprite(texture),
|
||||
];
|
||||
|
||||
@@ -74,19 +77,11 @@ namespace gdjs {
|
||||
|
||||
ensureUpToDate() {
|
||||
if (this._spritesContainer.visible && this._wasRendered) {
|
||||
// PIXI uses PIXI.SCALE_MODES.LINEAR for the cached image:
|
||||
// this._spritesContainer._cacheData.sprite._texture.baseTexture.scaleMode
|
||||
// There seems to be no way to configure this so the optimization is disabled.
|
||||
if (
|
||||
this._centerSprite.texture.baseTexture.scaleMode !==
|
||||
PIXI.SCALE_MODES.NEAREST
|
||||
) {
|
||||
// Cache the rendered sprites as a bitmap to speed up rendering when
|
||||
// lots of panel sprites are on the scene.
|
||||
// Sadly, because of this, we need a wrapper container to workaround
|
||||
// a PixiJS issue with alpha (see updateOpacity).
|
||||
this._spritesContainer.cacheAsBitmap = true;
|
||||
}
|
||||
// Cache the rendered sprites as a bitmap to speed up rendering when
|
||||
// lots of panel sprites are on the scene.
|
||||
// Sadly, because of this, we need a wrapper container to workaround
|
||||
// a PixiJS issue with alpha (see updateOpacity).
|
||||
this._spritesContainer.cacheAsBitmap = true;
|
||||
}
|
||||
this._wasRendered = true;
|
||||
}
|
||||
@@ -198,10 +193,14 @@ namespace gdjs {
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): void {
|
||||
const obj = this._object;
|
||||
// @ts-ignore
|
||||
const texture = instanceContainer
|
||||
.getGame()
|
||||
.getImageManager()
|
||||
.getPIXITexture(textureName).baseTexture;
|
||||
.getPIXITexture(textureName) as PIXI.BaseTexture<
|
||||
PIXI.Resource,
|
||||
PIXI.IAutoDetectOptions
|
||||
>;
|
||||
this._textureWidth = texture.width;
|
||||
this._textureHeight = texture.height;
|
||||
|
||||
|
@@ -27,10 +27,7 @@ class PathfindingBehaviorJsExtension : public gd::PlatformExtension {
|
||||
"Extensions/PathfindingBehavior/pathfindingruntimebehavior.js")
|
||||
.AddIncludeFile(
|
||||
"Extensions/PathfindingBehavior/"
|
||||
"pathfindingobstacleruntimebehavior.js")
|
||||
.AddIncludeFile(
|
||||
"Extensions/PathfindingBehavior/"
|
||||
"PathTools.js");
|
||||
"pathfindingobstacleruntimebehavior.js");
|
||||
|
||||
{
|
||||
std::map<gd::String, gd::InstructionMetadata>& autActions =
|
||||
|
@@ -1,163 +0,0 @@
|
||||
namespace gdjs {
|
||||
export namespace pathfinding {
|
||||
/**
|
||||
* Simplify a path according to an allowed gap.
|
||||
*
|
||||
* The simplified path vertices are the same instances as the one in
|
||||
* the source. They must be cloned to make them truly independent from each
|
||||
* other.
|
||||
*
|
||||
* @param sourceVertices The path to simplify.
|
||||
* @param maxGap The maximum distance the edge of the contour may deviate
|
||||
* from the source geometry.
|
||||
* @param simplifiedVertices The simplified path.
|
||||
* @param workingVertices It avoids allocations.
|
||||
*/
|
||||
export const simplifyPath = (
|
||||
sourceVertices: FloatPoint[],
|
||||
maxGap: float,
|
||||
simplifiedVertices: FloatPoint[] = [],
|
||||
workingVertices: FloatPoint[] = []
|
||||
): FloatPoint[] => {
|
||||
if (sourceVertices.length <= 2) {
|
||||
simplifiedVertices.length = 0;
|
||||
simplifiedVertices.push.apply(simplifiedVertices, sourceVertices);
|
||||
return simplifiedVertices;
|
||||
}
|
||||
const maxGapSq = maxGap * maxGap;
|
||||
|
||||
// We start with only one rope part.
|
||||
// Stretch a rope between the start and the end of the path.
|
||||
let previousStepVertices: FloatPoint[] = workingVertices;
|
||||
previousStepVertices.length = 0;
|
||||
previousStepVertices.push(sourceVertices[0]);
|
||||
previousStepVertices.push(sourceVertices[sourceVertices.length - 1]);
|
||||
|
||||
do {
|
||||
simplifiedVertices.length = 0;
|
||||
simplifiedVertices.push(previousStepVertices[0]);
|
||||
|
||||
// For each part of the rope...
|
||||
let sourceIndex = 0;
|
||||
for (
|
||||
let previousStepVerticesIndex = 0;
|
||||
previousStepVerticesIndex + 1 < previousStepVertices.length;
|
||||
previousStepVerticesIndex++
|
||||
) {
|
||||
const startVertex = previousStepVertices[previousStepVerticesIndex];
|
||||
const endVertex = previousStepVertices[previousStepVerticesIndex + 1];
|
||||
|
||||
const startX = startVertex[0];
|
||||
const startY = startVertex[1];
|
||||
const endX = endVertex[0];
|
||||
const endY = endVertex[1];
|
||||
|
||||
// Search the furthest vertex from the rope part.
|
||||
let maxDeviationSq = maxGapSq;
|
||||
let maxDeviationVertex: FloatPoint | null = null;
|
||||
// The first and last vertices of the rope part are not checked.
|
||||
for (
|
||||
sourceIndex++;
|
||||
sourceVertices[sourceIndex] !== endVertex;
|
||||
sourceIndex++
|
||||
) {
|
||||
const sourceVertex = sourceVertices[sourceIndex];
|
||||
|
||||
const deviationSq = gdjs.pathfinding.getPointSegmentDistanceSq(
|
||||
sourceVertex[0],
|
||||
sourceVertex[1],
|
||||
startX,
|
||||
startY,
|
||||
endX,
|
||||
endY
|
||||
);
|
||||
if (deviationSq > maxDeviationSq) {
|
||||
maxDeviationSq = deviationSq;
|
||||
maxDeviationVertex = sourceVertex;
|
||||
}
|
||||
}
|
||||
// Add the furthest vertex to the rope.
|
||||
// The current rope part is split in 2 for the next step.
|
||||
if (maxDeviationVertex) {
|
||||
simplifiedVertices.push(maxDeviationVertex);
|
||||
}
|
||||
simplifiedVertices.push(endVertex);
|
||||
}
|
||||
|
||||
const swapVertices = previousStepVertices;
|
||||
previousStepVertices = simplifiedVertices;
|
||||
simplifiedVertices = swapVertices;
|
||||
} while (
|
||||
// Stop when no new vertex were added.
|
||||
// It means that the maxGap constraint is fulfilled.
|
||||
// Otherwise, iterate over the full path once more.
|
||||
simplifiedVertices.length !== previousStepVertices.length
|
||||
);
|
||||
return simplifiedVertices;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the distance squared from the point to the line segment.
|
||||
*
|
||||
* Behavior is undefined if the the closest distance is outside the
|
||||
* line segment.
|
||||
*
|
||||
* @param px The X position of point (px, py).
|
||||
* @param py The Y position of point (px, py)
|
||||
* @param ax The X position of the line segment's vertex A.
|
||||
* @param ay The Y position of the line segment's vertex A.
|
||||
* @param bx The X position of the line segment's vertex B.
|
||||
* @param by The Y position of the line segment's vertex B.
|
||||
* @return The distance squared from the point (px, py) to line segment AB.
|
||||
*/
|
||||
export const getPointSegmentDistanceSq = (
|
||||
px: float,
|
||||
py: float,
|
||||
ax: float,
|
||||
ay: float,
|
||||
bx: float,
|
||||
by: float
|
||||
): float => {
|
||||
// This implementation is strongly inspired from CritterAI class "Geometry".
|
||||
//
|
||||
// Reference: http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/
|
||||
//
|
||||
// The goal of the algorithm is to find the point on line segment AB
|
||||
// that is closest to P and then calculate the distance between P
|
||||
// and that point.
|
||||
|
||||
const deltaABx = bx - ax;
|
||||
const deltaABy = by - ay;
|
||||
const deltaAPx = px - ax;
|
||||
const deltaAPy = py - ay;
|
||||
|
||||
const segmentABLengthSq = deltaABx * deltaABx + deltaABy * deltaABy;
|
||||
if (segmentABLengthSq === 0) {
|
||||
// AB is not a line segment. So just return
|
||||
// distanceSq from P to A
|
||||
return deltaAPx * deltaAPx + deltaAPy * deltaAPy;
|
||||
}
|
||||
|
||||
const u = (deltaAPx * deltaABx + deltaAPy * deltaABy) / segmentABLengthSq;
|
||||
if (u < 0) {
|
||||
// Closest point on line AB is outside outside segment AB and
|
||||
// closer to A. So return distanceSq from P to A.
|
||||
return deltaAPx * deltaAPx + deltaAPy * deltaAPy;
|
||||
} else if (u > 1) {
|
||||
// Closest point on line AB is outside segment AB and closer to B.
|
||||
// So return distanceSq from P to B.
|
||||
return (px - bx) * (px - bx) + (py - by) * (py - by);
|
||||
}
|
||||
|
||||
// Closest point on lineAB is inside segment AB. So find the exact
|
||||
// point on AB and calculate the distanceSq from it to P.
|
||||
|
||||
// The calculation in parenthesis is the location of the point on
|
||||
// the line segment.
|
||||
const deltaX = ax + u * deltaABx - px;
|
||||
const deltaY = ay + u * deltaABy - py;
|
||||
|
||||
return deltaX * deltaX + deltaY * deltaY;
|
||||
};
|
||||
}
|
||||
}
|
@@ -24,92 +24,39 @@ void PathfindingBehavior::InitializeContent(
|
||||
behaviorContent.SetAttribute("gridOffsetX", 0);
|
||||
behaviorContent.SetAttribute("gridOffsetY", 0);
|
||||
behaviorContent.SetAttribute("extraBorder", 0);
|
||||
behaviorContent.SetAttribute("smoothingMaxCellGap", 1);
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
std::map<gd::String, gd::PropertyDescriptor> PathfindingBehavior::GetProperties(
|
||||
const gd::SerializerElement &behaviorContent) const {
|
||||
const gd::SerializerElement& behaviorContent) const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
|
||||
properties["AllowDiagonals"]
|
||||
.SetLabel(_("Allows diagonals"))
|
||||
properties[_("Allows diagonals")]
|
||||
.SetValue(behaviorContent.GetBoolAttribute("allowDiagonals") ? "true"
|
||||
: "false")
|
||||
.SetGroup(_("Path smoothing"))
|
||||
.SetType("Boolean");
|
||||
properties["Acceleration"]
|
||||
.SetLabel(_("Acceleration"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixelAcceleration()).SetValue(
|
||||
properties[_("Acceleration")].SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("acceleration")));
|
||||
properties["MaxSpeed"]
|
||||
.SetLabel(_("Max. speed"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixelSpeed()).SetValue(
|
||||
properties[_("Max. speed")].SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("maxSpeed")));
|
||||
properties["AngularMaxSpeed"]
|
||||
.SetLabel(_("Rotation speed"))
|
||||
.SetGroup(_("Rotation"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetAngularSpeed())
|
||||
.SetValue(gd::String::From(
|
||||
behaviorContent.GetDoubleAttribute("angularMaxSpeed")));
|
||||
properties["RotateObject"]
|
||||
.SetLabel(_("Rotate object"))
|
||||
.SetGroup(_("Rotation"))
|
||||
properties[_("Rotate speed")].SetGroup(_("Rotation")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("angularMaxSpeed")));
|
||||
properties[_("Rotate object")].SetGroup(_("Rotation"))
|
||||
.SetValue(behaviorContent.GetBoolAttribute("rotateObject") ? "true"
|
||||
: "false")
|
||||
.SetType("Boolean");
|
||||
properties["AngleOffset"]
|
||||
.SetLabel(_("Angle offset"))
|
||||
.SetGroup(_("Rotation"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetDegreeAngle())
|
||||
.SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("angleOffset")));
|
||||
properties["CellWidth"]
|
||||
.SetLabel(_("Virtual cell width"))
|
||||
.SetGroup(_("Virtual Grid"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("cellWidth", 0)));
|
||||
properties["CellHeight"]
|
||||
.SetLabel(_("Virtual cell height"))
|
||||
.SetGroup(_("Virtual Grid"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetValue(gd::String::From(
|
||||
behaviorContent.GetDoubleAttribute("cellHeight", 0)));
|
||||
properties["GridOffsetX"]
|
||||
.SetLabel(_("Virtual grid X offset"))
|
||||
.SetGroup(_("Virtual Grid"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetValue(gd::String::From(
|
||||
behaviorContent.GetDoubleAttribute("gridOffsetX", 0)));
|
||||
properties["GridOffsetY"]
|
||||
.SetLabel(_("Virtual grid Y offset"))
|
||||
.SetGroup(_("Virtual Grid"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetValue(gd::String::From(
|
||||
behaviorContent.GetDoubleAttribute("gridOffsetY", 0)));
|
||||
properties["ExtraBorder"]
|
||||
.SetDescription(_("Extra border size"))
|
||||
.SetGroup(_("Collision"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("extraBorder")));
|
||||
properties["SmoothingMaxCellGap"]
|
||||
.SetLabel(_("Smoothing max cell gap"))
|
||||
.SetValue(gd::String::From(
|
||||
behaviorContent.GetDoubleAttribute("smoothingMaxCellGap")))
|
||||
.SetGroup(_("Path smoothing"))
|
||||
.SetDescription(_("It's recommended to leave a max gap of 1 cell. "
|
||||
"Setting it to 0 disable the smoothing."));
|
||||
properties[_("Angle offset")].SetGroup(_("Rotation")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("angleOffset")));
|
||||
properties[_("Virtual cell width")].SetGroup(_("Virtual Grid")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("cellWidth", 0)));
|
||||
properties[_("Virtual cell height")].SetGroup(_("Virtual Grid")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("cellHeight", 0)));
|
||||
properties[_("Virtual grid X offset")].SetGroup(_("Virtual Grid")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("gridOffsetX", 0)));
|
||||
properties[_("Virtual grid Y offset")].SetGroup(_("Virtual Grid")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("gridOffsetY", 0)));
|
||||
properties[_("Extra border size")].SetGroup(_("Collision")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("extraBorder")));
|
||||
|
||||
return properties;
|
||||
}
|
||||
@@ -117,39 +64,37 @@ std::map<gd::String, gd::PropertyDescriptor> PathfindingBehavior::GetProperties(
|
||||
bool PathfindingBehavior::UpdateProperty(gd::SerializerElement& behaviorContent,
|
||||
const gd::String& name,
|
||||
const gd::String& value) {
|
||||
if (name == "AllowDiagonals") {
|
||||
if (name == _("Allows diagonals")) {
|
||||
behaviorContent.SetAttribute("allowDiagonals", (value != "0"));
|
||||
return true;
|
||||
}
|
||||
if (name == "RotateObject") {
|
||||
if (name == _("Rotate object")) {
|
||||
behaviorContent.SetAttribute("rotateObject", (value != "0"));
|
||||
return true;
|
||||
}
|
||||
if (name == "ExtraBorder") {
|
||||
if (name == _("Extra border size")) {
|
||||
behaviorContent.SetAttribute("extraBorder", value.To<float>());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value.To<float>() < 0) return false;
|
||||
|
||||
if (name == "Acceleration")
|
||||
if (name == _("Acceleration"))
|
||||
behaviorContent.SetAttribute("acceleration", value.To<float>());
|
||||
else if (name == "MaxSpeed")
|
||||
else if (name == _("Max. speed"))
|
||||
behaviorContent.SetAttribute("maxSpeed", value.To<float>());
|
||||
else if (name == "AngularMaxSpeed")
|
||||
else if (name == _("Rotate speed"))
|
||||
behaviorContent.SetAttribute("angularMaxSpeed", value.To<float>());
|
||||
else if (name == "AngleOffset")
|
||||
else if (name == _("Angle offset"))
|
||||
behaviorContent.SetAttribute("angleOffset", value.To<float>());
|
||||
else if (name == "CellWidth")
|
||||
else if (name == _("Virtual cell width"))
|
||||
behaviorContent.SetAttribute("cellWidth", value.To<float>());
|
||||
else if (name == "CellHeight")
|
||||
else if (name == _("Virtual cell height"))
|
||||
behaviorContent.SetAttribute("cellHeight", value.To<float>());
|
||||
else if (name == "GridOffsetX")
|
||||
else if (name == _("Virtual grid X offset"))
|
||||
behaviorContent.SetAttribute("gridOffsetX", value.To<float>());
|
||||
else if (name == "GridOffsetY")
|
||||
else if (name == _("Virtual grid Y offset"))
|
||||
behaviorContent.SetAttribute("gridOffsetY", value.To<float>());
|
||||
else if (name == "SmoothingMaxCellGap")
|
||||
behaviorContent.SetAttribute("smoothingMaxCellGap", value.To<float>());
|
||||
else
|
||||
return false;
|
||||
|
||||
|
@@ -20,14 +20,12 @@ std::map<gd::String, gd::PropertyDescriptor>
|
||||
PathfindingObstacleBehavior::GetProperties(
|
||||
const gd::SerializerElement& behaviorContent) const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties["Impassable"]
|
||||
.SetLabel(_("Impassable obstacle"))
|
||||
properties[_("Impassable obstacle")]
|
||||
.SetValue(behaviorContent.GetBoolAttribute("impassable") ? "true"
|
||||
: "false")
|
||||
.SetType("Boolean");
|
||||
properties["Cost"]
|
||||
.SetLabel(_("Cost (if not impassable)"))
|
||||
.SetValue(gd::String::From(behaviorContent.GetDoubleAttribute("cost")));
|
||||
properties[_("Cost (if not impassable)")].SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("cost")));
|
||||
|
||||
return properties;
|
||||
}
|
||||
@@ -36,14 +34,14 @@ bool PathfindingObstacleBehavior::UpdateProperty(
|
||||
gd::SerializerElement& behaviorContent,
|
||||
const gd::String& name,
|
||||
const gd::String& value) {
|
||||
if (name == "Impassable") {
|
||||
if (name == _("Impassable obstacle")) {
|
||||
behaviorContent.SetAttribute("impassable", (value != "0"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value.To<float>() < 0) return false;
|
||||
|
||||
if (name == "Cost")
|
||||
if (name == _("Cost (if not impassable)"))
|
||||
behaviorContent.SetAttribute("cost", value.To<float>());
|
||||
else
|
||||
return false;
|
||||
|
@@ -10,10 +10,6 @@ namespace gdjs {
|
||||
*/
|
||||
export class PathfindingRuntimeBehavior extends gdjs.RuntimeBehavior {
|
||||
_path: Array<FloatPoint> = [];
|
||||
/** Used by the path simplification algorithm */
|
||||
static _smoothingResultVertices: Array<FloatPoint> = [];
|
||||
/** Used by the path simplification algorithm */
|
||||
static _smoothingWorkingVertices: Array<FloatPoint> = [];
|
||||
|
||||
//Behavior configuration:
|
||||
_allowDiagonals: boolean;
|
||||
@@ -27,7 +23,6 @@ namespace gdjs {
|
||||
_gridOffsetX: float;
|
||||
_gridOffsetY: float;
|
||||
_extraBorder: float;
|
||||
_smoothingMaxCellGap: float;
|
||||
|
||||
//Attributes used for traveling on the path:
|
||||
_pathFound: boolean = false;
|
||||
@@ -65,7 +60,6 @@ namespace gdjs {
|
||||
this._gridOffsetX = behaviorData.gridOffsetX || 0;
|
||||
this._gridOffsetY = behaviorData.gridOffsetY || 0;
|
||||
this._extraBorder = behaviorData.extraBorder;
|
||||
this._smoothingMaxCellGap = behaviorData.smoothingMaxCellGap || 0;
|
||||
this._manager = gdjs.PathfindingObstaclesManager.getManager(
|
||||
instanceContainer
|
||||
);
|
||||
@@ -108,12 +102,6 @@ namespace gdjs {
|
||||
if (oldBehaviorData.extraBorder !== newBehaviorData.extraBorder) {
|
||||
this.setExtraBorder(newBehaviorData.extraBorder);
|
||||
}
|
||||
if (
|
||||
oldBehaviorData.smoothingMaxCellGap !==
|
||||
newBehaviorData.smoothingMaxCellGap
|
||||
) {
|
||||
this._smoothingMaxCellGap = newBehaviorData.smoothingMaxCellGap;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -389,20 +377,6 @@ namespace gdjs {
|
||||
this._path.reverse();
|
||||
this._path[0][0] = owner.getX();
|
||||
this._path[0][1] = owner.getY();
|
||||
|
||||
if (this._allowDiagonals && this._smoothingMaxCellGap > 0) {
|
||||
gdjs.pathfinding.simplifyPath(
|
||||
this._path,
|
||||
this._smoothingMaxCellGap *
|
||||
Math.min(this._cellWidth, this._cellHeight),
|
||||
gdjs.PathfindingRuntimeBehavior._smoothingResultVertices,
|
||||
gdjs.PathfindingRuntimeBehavior._smoothingWorkingVertices
|
||||
);
|
||||
let swapArray = this._path;
|
||||
this._path = gdjs.PathfindingRuntimeBehavior._smoothingResultVertices;
|
||||
gdjs.PathfindingRuntimeBehavior._smoothingResultVertices = swapArray;
|
||||
}
|
||||
|
||||
this._enterSegment(0);
|
||||
this._pathFound = true;
|
||||
return;
|
||||
|
@@ -1,239 +0,0 @@
|
||||
// @ts-check
|
||||
describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
const epsilon = 1 / (2 << 16);
|
||||
// tests cases where every collisionMethod has the same behavior.
|
||||
let doCommonPathFindingTests = (collisionMethod) => {
|
||||
const pathFindingName = 'auto1';
|
||||
|
||||
const createScene = (framePerSecond = 60) => {
|
||||
const runtimeGame = new gdjs.RuntimeGame({
|
||||
variables: [],
|
||||
// @ts-ignore - missing properties.
|
||||
properties: { windowWidth: 800, windowHeight: 600 },
|
||||
resources: { resources: [] },
|
||||
});
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
cameras: [],
|
||||
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: true,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
});
|
||||
setFramePerSecond(runtimeScene, framePerSecond);
|
||||
return runtimeScene;
|
||||
};
|
||||
const setFramePerSecond = (runtimeScene, framePerSecond) => {
|
||||
runtimeScene._timeManager.getElapsedTime = function () {
|
||||
return 1000 / framePerSecond;
|
||||
};
|
||||
};
|
||||
|
||||
const addPlayer = (runtimeScene, allowDiagonals) => {
|
||||
const player = new gdjs.RuntimeObject(runtimeScene, {
|
||||
name: 'player',
|
||||
type: '',
|
||||
behaviors: [
|
||||
{
|
||||
type: 'PathfindingBehavior::PathfindingBehavior',
|
||||
name: 'auto1',
|
||||
// @ts-ignore - properties are not typed
|
||||
allowDiagonals: allowDiagonals,
|
||||
acceleration: 400,
|
||||
maxSpeed: 200,
|
||||
angularMaxSpeed: 180,
|
||||
rotateObject: false,
|
||||
angleOffset: 0,
|
||||
cellWidth: 20,
|
||||
cellHeight: 20,
|
||||
extraBorder: 0,
|
||||
collisionMethod: true,
|
||||
},
|
||||
],
|
||||
effects: [],
|
||||
});
|
||||
player.getWidth = function () {
|
||||
return 90;
|
||||
};
|
||||
player.getHeight = function () {
|
||||
return 90;
|
||||
};
|
||||
runtimeScene.addObject(player);
|
||||
return player;
|
||||
};
|
||||
|
||||
const addObstacle = (runtimeScene) => {
|
||||
const obstacle = new gdjs.RuntimeObject(runtimeScene, {
|
||||
name: 'obstacle',
|
||||
type: '',
|
||||
behaviors: [
|
||||
{
|
||||
type: 'PathfindingBehavior::PathfindingObstacleBehavior',
|
||||
// @ts-ignore - properties are not typed
|
||||
impassable: true,
|
||||
cost: 2,
|
||||
},
|
||||
],
|
||||
effects: [],
|
||||
});
|
||||
obstacle.getWidth = function () {
|
||||
return 100;
|
||||
};
|
||||
obstacle.getHeight = function () {
|
||||
return 100;
|
||||
};
|
||||
runtimeScene.addObject(obstacle);
|
||||
return obstacle;
|
||||
};
|
||||
|
||||
const getPathLength = (player) => {
|
||||
/** @type gdjs.PathfindingRuntimeBehavior */
|
||||
const behavior = player.getBehavior(pathFindingName);
|
||||
if (behavior.getNodeCount() < 2) {
|
||||
return 0;
|
||||
}
|
||||
let pathLength = 0;
|
||||
let previousNodeX = behavior.getNodeX(0);
|
||||
let previousNodeY = behavior.getNodeY(0);
|
||||
for (let index = 1; index < behavior.getNodeCount(); index++) {
|
||||
const nodeX = behavior.getNodeX(index);
|
||||
const nodeY = behavior.getNodeY(index);
|
||||
pathLength += Math.hypot(nodeX - previousNodeX, nodeY - previousNodeY);
|
||||
previousNodeX = nodeX;
|
||||
previousNodeY = nodeY;
|
||||
}
|
||||
return pathLength;
|
||||
};
|
||||
|
||||
describe(`(allowDiagonals: true)`, function () {
|
||||
let runtimeScene;
|
||||
let player;
|
||||
|
||||
beforeEach(function () {
|
||||
runtimeScene = createScene();
|
||||
const allowDiagonals = true;
|
||||
player = addPlayer(runtimeScene, allowDiagonals);
|
||||
});
|
||||
|
||||
[20, 30, 60, 120].forEach((framePerSecond) => {
|
||||
describe(`(${framePerSecond} fps)`, function () {
|
||||
it('can move on the path at the right speed', function () {
|
||||
setFramePerSecond(runtimeScene, framePerSecond);
|
||||
const obstacle = addObstacle(runtimeScene);
|
||||
|
||||
obstacle.setPosition(600, 300);
|
||||
// To ensure obstacles are registered.
|
||||
runtimeScene.renderAndStep(1000 / framePerSecond);
|
||||
|
||||
player.setPosition(480, 300);
|
||||
player.getBehavior(pathFindingName).moveTo(runtimeScene, 720, 300);
|
||||
expect(player.getBehavior(pathFindingName).pathFound()).to.be(true);
|
||||
expect(getPathLength(player)).to.be.above(720 - 480 + 50);
|
||||
|
||||
// Move on the path and stop before the last 1/10 of second.
|
||||
for (let i = 0; i < (framePerSecond * 17) / 10; i++) {
|
||||
runtimeScene.renderAndStep(1000 / framePerSecond);
|
||||
expect(
|
||||
player.getBehavior(pathFindingName).destinationReached()
|
||||
).to.be(false);
|
||||
}
|
||||
// The position is the same no matter the frame rate.
|
||||
expect(player.getX()).to.be(720);
|
||||
expect(player.getY()).to.be.within(
|
||||
288.5786437626905 - epsilon,
|
||||
288.5786437626905 + epsilon
|
||||
);
|
||||
|
||||
// Let 1/10 of second pass,
|
||||
// because the calculus interval is not the same for each case.
|
||||
for (let i = 0; i < framePerSecond / 10; i++) {
|
||||
runtimeScene.renderAndStep(1000 / framePerSecond);
|
||||
}
|
||||
// The destination is reached for every frame rate within 1/10 of second.
|
||||
expect(player.getX()).to.be(720);
|
||||
expect(player.getY()).to.be(300);
|
||||
expect(
|
||||
player.getBehavior(pathFindingName).destinationReached()
|
||||
).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe(`(allowDiagonals: false)`, function () {
|
||||
let runtimeScene;
|
||||
let player;
|
||||
|
||||
beforeEach(function () {
|
||||
runtimeScene = createScene();
|
||||
const allowDiagonals = false;
|
||||
player = addPlayer(runtimeScene, allowDiagonals);
|
||||
});
|
||||
|
||||
[20, 30, 60, 120].forEach((framePerSecond) => {
|
||||
describe(`(${framePerSecond} fps)`, function () {
|
||||
it('can move on the path at the right speed', function () {
|
||||
setFramePerSecond(runtimeScene, framePerSecond);
|
||||
const obstacle = addObstacle(runtimeScene);
|
||||
|
||||
obstacle.setPosition(600, 300);
|
||||
// To ensure obstacles are registered.
|
||||
runtimeScene.renderAndStep(1000 / framePerSecond);
|
||||
|
||||
player.setPosition(480, 300);
|
||||
player.getBehavior(pathFindingName).moveTo(runtimeScene, 720, 300);
|
||||
expect(player.getBehavior(pathFindingName).pathFound()).to.be(true);
|
||||
expect(getPathLength(player)).to.be.above(720 - 480 + 100);
|
||||
|
||||
// Move on the path and stop before the last 1/10 of second.
|
||||
for (let i = 0; i < (framePerSecond * 20) / 10; i++) {
|
||||
runtimeScene.renderAndStep(1000 / framePerSecond);
|
||||
expect(
|
||||
player.getBehavior(pathFindingName).destinationReached()
|
||||
).to.be(false);
|
||||
}
|
||||
expect(player.getX()).to.be(710);
|
||||
expect(player.getY()).to.be.within(300 - epsilon, 300 + epsilon);
|
||||
|
||||
// Let 1/10 of second pass,
|
||||
// because the calculus interval is not the same for each case.
|
||||
for (let i = 0; i < (framePerSecond * 1) / 10; i++) {
|
||||
runtimeScene.renderAndStep(1000 / framePerSecond);
|
||||
}
|
||||
// The destination is reached for every frame rate within 1/10 of second.
|
||||
expect(player.getX()).to.be(720);
|
||||
expect(player.getY()).to.be(300);
|
||||
expect(
|
||||
player.getBehavior(pathFindingName).destinationReached()
|
||||
).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
['Legacy'].forEach((collisionMethod) => {
|
||||
describe(`(collisionMethod: ${collisionMethod}, `, function () {
|
||||
doCommonPathFindingTests(collisionMethod);
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,115 +0,0 @@
|
||||
// @ts-check
|
||||
describe('gdjs.pathfinding', function () {
|
||||
it('can give back an empty path', function () {
|
||||
expect(gdjs.pathfinding.simplifyPath([], 1)).to.eql([]);
|
||||
});
|
||||
|
||||
it('can give back a path with only 1 vertex', function () {
|
||||
expect(gdjs.pathfinding.simplifyPath([[2, 4]], 1)).to.eql([[2, 4]]);
|
||||
});
|
||||
|
||||
it('can give back a path with only 2 vertex', function () {
|
||||
expect(
|
||||
gdjs.pathfinding.simplifyPath(
|
||||
[
|
||||
[2, 4],
|
||||
[8, 1],
|
||||
],
|
||||
1
|
||||
)
|
||||
).to.eql([
|
||||
[2, 4],
|
||||
[8, 1],
|
||||
]);
|
||||
});
|
||||
|
||||
it('can give back a path with 3 vertex', function () {
|
||||
expect(
|
||||
gdjs.pathfinding.simplifyPath(
|
||||
[
|
||||
[2, 4],
|
||||
[8, 1],
|
||||
[16, 32],
|
||||
],
|
||||
1
|
||||
)
|
||||
).to.eql([
|
||||
[2, 4],
|
||||
[8, 1],
|
||||
[16, 32],
|
||||
]);
|
||||
});
|
||||
|
||||
it('can simplify a line of vertices', function () {
|
||||
expect(
|
||||
gdjs.pathfinding.simplifyPath(
|
||||
[
|
||||
[2, 4],
|
||||
[2, 5],
|
||||
[2, 9],
|
||||
[2, 9.5],
|
||||
],
|
||||
1
|
||||
)
|
||||
).to.eql([
|
||||
[2, 4],
|
||||
[2, 9.5],
|
||||
]);
|
||||
});
|
||||
|
||||
it('can simplify a line of vertices with some tangential noise', function () {
|
||||
expect(
|
||||
gdjs.pathfinding.simplifyPath(
|
||||
[
|
||||
[2, 4],
|
||||
[2.5, 5],
|
||||
[1.1, 9],
|
||||
[2, 9.5],
|
||||
],
|
||||
1
|
||||
)
|
||||
).to.eql([
|
||||
[2, 4],
|
||||
[2, 9.5],
|
||||
]);
|
||||
});
|
||||
|
||||
it('can simplify an aliased oblique line', function () {
|
||||
expect(
|
||||
gdjs.pathfinding.simplifyPath(
|
||||
[
|
||||
[2, 4],
|
||||
[3, 4],
|
||||
[4, 3],
|
||||
[5, 3],
|
||||
[6, 3],
|
||||
[7, 2],
|
||||
[8, 2],
|
||||
],
|
||||
1
|
||||
)
|
||||
).to.eql([
|
||||
[2, 4],
|
||||
[8, 2],
|
||||
]);
|
||||
});
|
||||
|
||||
it('can preserve a bend', function () {
|
||||
expect(
|
||||
gdjs.pathfinding.simplifyPath(
|
||||
[
|
||||
[2, 4],
|
||||
[2.5, 5],
|
||||
[2, 9],
|
||||
[3, 9.9],
|
||||
[5, 9],
|
||||
],
|
||||
1
|
||||
)
|
||||
).to.eql([
|
||||
[2, 4],
|
||||
[2, 9],
|
||||
[5, 9],
|
||||
]);
|
||||
});
|
||||
});
|
@@ -1,11 +1,8 @@
|
||||
// @ts-check
|
||||
describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
const epsilon = 1 / (2 << 16);
|
||||
// tests cases where every collisionMethod has the same behavior.
|
||||
let doCommonPathFindingTests = (
|
||||
collisionMethod,
|
||||
allowDiagonals,
|
||||
smoothingMaxCellGap
|
||||
) => {
|
||||
let doCommonPathFindingTests = (collisionMethod, allowDiagonals) => {
|
||||
const pathFindingName = 'auto1';
|
||||
|
||||
const createScene = (framePerSecond = 60) => {
|
||||
@@ -70,7 +67,6 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
cellWidth: 20,
|
||||
cellHeight: 20,
|
||||
extraBorder: 0,
|
||||
smoothingMaxCellGap: smoothingMaxCellGap,
|
||||
collisionMethod: collisionMethod,
|
||||
},
|
||||
],
|
||||
@@ -110,25 +106,6 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
return obstacle;
|
||||
};
|
||||
|
||||
const getPathLength = (player) => {
|
||||
/** @type gdjs.PathfindingRuntimeBehavior */
|
||||
const behavior = player.getBehavior(pathFindingName);
|
||||
if (behavior.getNodeCount() < 2) {
|
||||
return 0;
|
||||
}
|
||||
let pathLength = 0;
|
||||
let previousNodeX = behavior.getNodeX(0);
|
||||
let previousNodeY = behavior.getNodeY(0);
|
||||
for (let index = 1; index < behavior.getNodeCount(); index++) {
|
||||
const nodeX = behavior.getNodeX(index);
|
||||
const nodeY = behavior.getNodeY(index);
|
||||
pathLength += Math.hypot(nodeX - previousNodeX, nodeY - previousNodeY);
|
||||
previousNodeX = nodeX;
|
||||
previousNodeY = nodeY;
|
||||
}
|
||||
return pathLength;
|
||||
};
|
||||
|
||||
let runtimeScene;
|
||||
let player;
|
||||
beforeEach(function () {
|
||||
@@ -140,7 +117,7 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
player.setPosition(480, 300);
|
||||
player.getBehavior(pathFindingName).moveTo(runtimeScene, 720, 300);
|
||||
expect(player.getBehavior(pathFindingName).pathFound()).to.be(true);
|
||||
expect(getPathLength(player)).to.be(720 - 480);
|
||||
expect(player.getBehavior(pathFindingName).getNodeCount()).to.be(13);
|
||||
});
|
||||
|
||||
it('can find a path without any obstacle in the way', function () {
|
||||
@@ -153,7 +130,7 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
player.setPosition(480, 300);
|
||||
player.getBehavior(pathFindingName).moveTo(runtimeScene, 720, 300);
|
||||
expect(player.getBehavior(pathFindingName).pathFound()).to.be(true);
|
||||
expect(getPathLength(player)).to.be(720 - 480);
|
||||
expect(player.getBehavior(pathFindingName).getNodeCount()).to.be(13);
|
||||
});
|
||||
|
||||
it("mustn't find a path to the obstacle inside", function () {
|
||||
@@ -178,9 +155,101 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
player.setPosition(480, 300);
|
||||
player.getBehavior(pathFindingName).moveTo(runtimeScene, 720, 300);
|
||||
expect(player.getBehavior(pathFindingName).pathFound()).to.be(true);
|
||||
expect(getPathLength(player)).to.be.above(720 - 480 + 50);
|
||||
expect(player.getBehavior(pathFindingName).getNodeCount()).to.be.above(
|
||||
13
|
||||
);
|
||||
});
|
||||
|
||||
if (allowDiagonals) {
|
||||
[20, 30, 60, 120].forEach((framePerSecond) => {
|
||||
describe(`(${framePerSecond} fps)`, function () {
|
||||
it('can move on the path at the right speed', function () {
|
||||
setFramePerSecond(runtimeScene, framePerSecond);
|
||||
const obstacle = addObstacle(runtimeScene);
|
||||
|
||||
obstacle.setPosition(600, 300);
|
||||
// To ensure obstacles are registered.
|
||||
runtimeScene.renderAndStep(1000 / framePerSecond);
|
||||
|
||||
player.setPosition(480, 300);
|
||||
player.getBehavior(pathFindingName).moveTo(runtimeScene, 720, 300);
|
||||
expect(player.getBehavior(pathFindingName).pathFound()).to.be(true);
|
||||
expect(
|
||||
player.getBehavior(pathFindingName).getNodeCount()
|
||||
).to.be.above(13);
|
||||
|
||||
// Move on the path and stop before the last 1/10 of second.
|
||||
for (let i = 0; i < (framePerSecond * 17) / 10; i++) {
|
||||
runtimeScene.renderAndStep(1000 / framePerSecond);
|
||||
expect(
|
||||
player.getBehavior(pathFindingName).destinationReached()
|
||||
).to.be(false);
|
||||
}
|
||||
// The position is the same no matter the frame rate.
|
||||
expect(player.getX()).to.be(720);
|
||||
expect(player.getY()).to.be.within(
|
||||
288.5786437626905 - epsilon,
|
||||
288.5786437626905 + epsilon
|
||||
);
|
||||
|
||||
// Let 1/10 of second pass,
|
||||
// because the calculus interval is not the same for each case.
|
||||
for (let i = 0; i < framePerSecond / 10; i++) {
|
||||
runtimeScene.renderAndStep(1000 / framePerSecond);
|
||||
}
|
||||
// The destination is reached for every frame rate within 1/10 of second.
|
||||
expect(player.getX()).to.be(720);
|
||||
expect(player.getY()).to.be(300);
|
||||
expect(
|
||||
player.getBehavior(pathFindingName).destinationReached()
|
||||
).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
[20, 30, 60, 120].forEach((framePerSecond) => {
|
||||
describe(`(${framePerSecond} fps)`, function () {
|
||||
it('can move on the path at the right speed', function () {
|
||||
setFramePerSecond(runtimeScene, framePerSecond);
|
||||
const obstacle = addObstacle(runtimeScene);
|
||||
|
||||
obstacle.setPosition(600, 300);
|
||||
// To ensure obstacles are registered.
|
||||
runtimeScene.renderAndStep(1000 / framePerSecond);
|
||||
|
||||
player.setPosition(480, 300);
|
||||
player.getBehavior(pathFindingName).moveTo(runtimeScene, 720, 300);
|
||||
expect(player.getBehavior(pathFindingName).pathFound()).to.be(true);
|
||||
expect(
|
||||
player.getBehavior(pathFindingName).getNodeCount()
|
||||
).to.be.above(13);
|
||||
|
||||
// Move on the path and stop before the last 1/10 of second.
|
||||
for (let i = 0; i < (framePerSecond * 20) / 10; i++) {
|
||||
runtimeScene.renderAndStep(1000 / framePerSecond);
|
||||
expect(
|
||||
player.getBehavior(pathFindingName).destinationReached()
|
||||
).to.be(false);
|
||||
}
|
||||
expect(player.getX()).to.be(710);
|
||||
expect(player.getY()).to.be.within(300 - epsilon, 300 + epsilon);
|
||||
|
||||
// Let 1/10 of second pass,
|
||||
// because the calculus interval is not the same for each case.
|
||||
for (let i = 0; i < (framePerSecond * 1) / 10; i++) {
|
||||
runtimeScene.renderAndStep(1000 / framePerSecond);
|
||||
}
|
||||
// The destination is reached for every frame rate within 1/10 of second.
|
||||
expect(player.getX()).to.be(720);
|
||||
expect(player.getY()).to.be(300);
|
||||
expect(
|
||||
player.getBehavior(pathFindingName).destinationReached()
|
||||
).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
it('can find a path between 2 obstacles', function () {
|
||||
const obstacleTop = addObstacle(runtimeScene);
|
||||
const obstacleBottom = addObstacle(runtimeScene);
|
||||
@@ -193,7 +262,7 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
player.setPosition(480, 300);
|
||||
player.getBehavior(pathFindingName).moveTo(runtimeScene, 720, 300);
|
||||
expect(player.getBehavior(pathFindingName).pathFound()).to.be(true);
|
||||
expect(getPathLength(player)).to.be(720 - 480);
|
||||
expect(player.getBehavior(pathFindingName).getNodeCount()).to.be(13);
|
||||
});
|
||||
|
||||
it("mustn't find a path to a closed room", function () {
|
||||
@@ -219,15 +288,7 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
describe(`(collisionMethod: ${collisionMethod}, `, function () {
|
||||
[false, true].forEach((allowDiagonals) => {
|
||||
describe(`(allowDiagonals: ${allowDiagonals})`, function () {
|
||||
[0, 1].forEach((smoothingMaxCellGap) => {
|
||||
describe(`(smoothingMaxCellGap: ${smoothingMaxCellGap})`, function () {
|
||||
doCommonPathFindingTests(
|
||||
collisionMethod,
|
||||
allowDiagonals,
|
||||
smoothingMaxCellGap
|
||||
);
|
||||
});
|
||||
});
|
||||
doCommonPathFindingTests(collisionMethod, allowDiagonals);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,8 +1,6 @@
|
||||
// @ts-check
|
||||
describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
// limit tests cases on the legacy collision methods.
|
||||
// Note that the legacy collision mode is still the only mode that exists
|
||||
// because the new one were never merged.
|
||||
let doLegacyPathFindingTests = (
|
||||
cellSize,
|
||||
objectCenteredOnCells,
|
||||
|
@@ -200,7 +200,6 @@ module.exports = {
|
||||
.toString(10)
|
||||
)
|
||||
.setType('Number')
|
||||
.setMeasurementUnit(gd.MeasurementUnit.getPixel())
|
||||
.setLabel('Shape Dimension A');
|
||||
behaviorProperties
|
||||
.getOrCreate('shapeDimensionB')
|
||||
@@ -211,7 +210,6 @@ module.exports = {
|
||||
.toString(10)
|
||||
)
|
||||
.setType('Number')
|
||||
.setMeasurementUnit(gd.MeasurementUnit.getPixel())
|
||||
.setLabel('Shape Dimension B');
|
||||
behaviorProperties
|
||||
.getOrCreate('shapeOffsetX')
|
||||
@@ -219,7 +217,6 @@ module.exports = {
|
||||
behaviorContent.getChild('shapeOffsetX').getDoubleValue().toString(10)
|
||||
)
|
||||
.setType('Number')
|
||||
.setMeasurementUnit(gd.MeasurementUnit.getPixel())
|
||||
.setLabel('Shape Offset X');
|
||||
behaviorProperties
|
||||
.getOrCreate('shapeOffsetY')
|
||||
@@ -227,7 +224,6 @@ module.exports = {
|
||||
behaviorContent.getChild('shapeOffsetY').getDoubleValue().toString(10)
|
||||
)
|
||||
.setType('Number')
|
||||
.setMeasurementUnit(gd.MeasurementUnit.getPixel())
|
||||
.setLabel('Shape Offset Y');
|
||||
behaviorProperties
|
||||
.getOrCreate('polygonOrigin')
|
||||
@@ -377,15 +373,13 @@ module.exports = {
|
||||
.setValue(
|
||||
sharedContent.getChild('gravityX').getDoubleValue().toString(10)
|
||||
)
|
||||
.setType('Number')
|
||||
.setMeasurementUnit(gd.MeasurementUnit.getNewton());
|
||||
.setType('Number');
|
||||
sharedProperties
|
||||
.getOrCreate('gravityY')
|
||||
.setValue(
|
||||
sharedContent.getChild('gravityY').getDoubleValue().toString(10)
|
||||
)
|
||||
.setType('Number')
|
||||
.setMeasurementUnit(gd.MeasurementUnit.getNewton());
|
||||
.setType('Number');
|
||||
sharedProperties
|
||||
.getOrCreate('scaleX')
|
||||
.setValue(
|
||||
|
@@ -825,12 +825,8 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
// Step the world if not done this frame yet.
|
||||
// Don't step at the first frame to allow events to handle overlapping objects.
|
||||
if (
|
||||
!this._sharedData.stepped &&
|
||||
!instanceContainer.getScene().getTimeManager().isFirstFrame()
|
||||
) {
|
||||
// Step the world if not done this frame yet
|
||||
if (!this._sharedData.stepped) {
|
||||
// Reset started and ended contacts array for all physics instances.
|
||||
this._sharedData.resetStartedAndEndedCollisions();
|
||||
this._sharedData.updateBodiesFromObjects();
|
||||
|
@@ -64,7 +64,7 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
resources: { resources: [] },
|
||||
properties: { windowWidth: 1000, windowHeight: 1000 },
|
||||
});
|
||||
const runtimeScene = new gdjs.TestRuntimeScene(runtimeGame);
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [
|
||||
{
|
||||
@@ -236,39 +236,6 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
expect(behavior.getRestitution()).to.be(0.5);
|
||||
});
|
||||
|
||||
it('should not resolve collision before the 1st frame events', () => {
|
||||
const fps = 60;
|
||||
runtimeScene._timeManager.getElapsedTime = function () {
|
||||
return (1 / fps) * 1000;
|
||||
};
|
||||
|
||||
// Create objects in contact
|
||||
const {
|
||||
object: object1,
|
||||
behavior: object1Behavior,
|
||||
} = createObjectWithPhysicsBehavior(runtimeScene, {
|
||||
bodyType: 'Dynamic',
|
||||
});
|
||||
object1.setPosition(10, 0);
|
||||
const {
|
||||
object: object2,
|
||||
behavior: object2Behavior,
|
||||
} = createObjectWithPhysicsBehavior(runtimeScene, {
|
||||
bodyType: 'Static',
|
||||
restitution: 0,
|
||||
});
|
||||
object2.setPosition(20, 0);
|
||||
|
||||
// First frame
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
|
||||
// The object has not moved.
|
||||
expect(object1.getX()).to.be(10);
|
||||
expect(object1.getY()).to.be(0);
|
||||
expect(object2.getX()).to.be(20);
|
||||
expect(object2.getY()).to.be(0);
|
||||
});
|
||||
|
||||
it('should clear contacts when deactivating the physics2 behavior', () => {
|
||||
const fps = 60;
|
||||
runtimeGame.setGameResolutionSize(1000, 1000);
|
||||
@@ -276,9 +243,6 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
return (1 / fps) * 1000;
|
||||
};
|
||||
|
||||
// The behavior doesn't call Box2D step at the 1st frame.
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
|
||||
// Create objects not in contact
|
||||
const {
|
||||
object: object1,
|
||||
@@ -307,10 +271,11 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
).to.be(true);
|
||||
|
||||
// Put objects in contact and assert collision started during the frame
|
||||
runtimeScene.renderAndStepWithEventsFunction(1000 / fps, () => {
|
||||
runtimeScene.setEventsFunction(() => {
|
||||
object1.setPosition(10, 0);
|
||||
object2.setPosition(20, 0);
|
||||
});
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
|
||||
// After post event, collision should be present
|
||||
assertCollision(object1, object2, {
|
||||
@@ -319,6 +284,9 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
stopped: false,
|
||||
});
|
||||
|
||||
// Reset scene events
|
||||
runtimeScene.setEventsFunction(() => {});
|
||||
|
||||
// Deactivate physics behavior and test that collisions are cleared.
|
||||
object1.activateBehavior('Physics2', false);
|
||||
assertCollision(object1, object2, {
|
||||
@@ -456,28 +424,33 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
movingObjectBehavior.setLinearVelocityY(40000);
|
||||
|
||||
let hasBounced = false;
|
||||
for (let stepIndex = 0; stepIndex < 10 && !hasBounced; stepIndex++) {
|
||||
runtimeScene.renderAndStepWithEventsFunction(1000 / fps, () => {
|
||||
if (movingObjectBehavior.getLinearVelocityY() > 0) {
|
||||
// If the moving object has a positive velocity, it hasn't bounced
|
||||
// on the static object
|
||||
assertCollision(movingObject, staticObject, {
|
||||
started: false,
|
||||
collision: false,
|
||||
stopped: false,
|
||||
});
|
||||
} else {
|
||||
hasBounced = true;
|
||||
expect(movingObject.getY() < staticObject.getY()).to.be(true);
|
||||
assertCollision(movingObject, staticObject, {
|
||||
started: true,
|
||||
collision: true,
|
||||
stopped: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
let stepIndex = 0;
|
||||
|
||||
runtimeScene.setEventsFunction(() => {
|
||||
if (movingObjectBehavior.getLinearVelocityY() > 0) {
|
||||
// If the moving object has a positive velocity, it hasn't bounced
|
||||
// on the static object
|
||||
assertCollision(movingObject, staticObject, {
|
||||
started: false,
|
||||
collision: false,
|
||||
stopped: false,
|
||||
});
|
||||
} else {
|
||||
hasBounced = true;
|
||||
expect(movingObject.getY() < staticObject.getY()).to.be(true);
|
||||
assertCollision(movingObject, staticObject, {
|
||||
started: true,
|
||||
collision: true,
|
||||
stopped: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
while (stepIndex < 10 && !hasBounced) {
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
stepIndex++;
|
||||
}
|
||||
|
||||
runtimeScene.setEventsFunction(() => {});
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
assertCollision(movingObject, staticObject, {
|
||||
started: false,
|
||||
@@ -513,31 +486,32 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
movingObjectBehavior.setLinearVelocityY(40000);
|
||||
|
||||
let hasBegunBouncing = false;
|
||||
for (
|
||||
let stepIndex = 0;
|
||||
stepIndex < 10 && !hasBegunBouncing;
|
||||
stepIndex++
|
||||
) {
|
||||
runtimeScene.renderAndStepWithEventsFunction(1000 / fps, () => {
|
||||
if (movingObjectBehavior.getLinearVelocityY() > 0) {
|
||||
// If the moving object has a positive velocity, it hasn't bounced
|
||||
// on the static object
|
||||
assertCollision(movingObject, staticObject, {
|
||||
started: false,
|
||||
collision: false,
|
||||
stopped: false,
|
||||
});
|
||||
} else {
|
||||
hasBegunBouncing = true;
|
||||
// At first frame, collision should have only started
|
||||
expect(movingObject.getY() < staticObject.getY()).to.be(true);
|
||||
assertCollision(movingObject, staticObject, {
|
||||
started: true,
|
||||
collision: true,
|
||||
stopped: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
let stepIndex = 0;
|
||||
|
||||
runtimeScene.setEventsFunction(() => {
|
||||
if (movingObjectBehavior.getLinearVelocityY() > 0) {
|
||||
// If the moving object has a positive velocity, it hasn't bounced
|
||||
// on the static object
|
||||
assertCollision(movingObject, staticObject, {
|
||||
started: false,
|
||||
collision: false,
|
||||
stopped: false,
|
||||
});
|
||||
} else {
|
||||
hasBegunBouncing = true;
|
||||
// At first frame, collision should have only started
|
||||
expect(movingObject.getY() < staticObject.getY()).to.be(true);
|
||||
assertCollision(movingObject, staticObject, {
|
||||
started: true,
|
||||
collision: true,
|
||||
stopped: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
while (stepIndex < 10 && !hasBegunBouncing) {
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
stepIndex++;
|
||||
}
|
||||
|
||||
if (!hasBegunBouncing) {
|
||||
@@ -548,7 +522,8 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
|
||||
// At next frame, end of collision should be detected
|
||||
let hasFinishedBouncing = false;
|
||||
runtimeScene.renderAndStepWithEventsFunction(1000 / fps, () => {
|
||||
|
||||
runtimeScene.setEventsFunction(() => {
|
||||
hasFinishedBouncing = true;
|
||||
assertCollision(movingObject, staticObject, {
|
||||
started: false,
|
||||
@@ -557,6 +532,8 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
});
|
||||
});
|
||||
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
|
||||
if (!hasFinishedBouncing) {
|
||||
throw new Error('End of contact was not detected, nothing was tested.');
|
||||
}
|
||||
@@ -569,9 +546,6 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
return (1 / fps) * 1000;
|
||||
};
|
||||
|
||||
// The behavior doesn't call Box2D step at the 1st frame.
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
|
||||
const {
|
||||
behavior: movingObjectBehavior,
|
||||
object: movingObject,
|
||||
@@ -593,7 +567,7 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
stopped: false,
|
||||
});
|
||||
|
||||
runtimeScene.renderAndStepWithEventsFunction(1000 / fps, () => {
|
||||
runtimeScene.setEventsFunction(() => {
|
||||
// Manually call onContactEnd and onContactBegin methods to simulate
|
||||
// a loss of contact followed by a contact beginning during the preEvent.
|
||||
movingObject
|
||||
@@ -610,6 +584,7 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
stopped: false,
|
||||
});
|
||||
});
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
});
|
||||
|
||||
it('should not detect a new contact if the contact ended and jittered.', () => {
|
||||
@@ -619,9 +594,6 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
return (1 / fps) * 1000;
|
||||
};
|
||||
|
||||
// The behavior doesn't call Box2D step at the 1st frame.
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
|
||||
const {
|
||||
behavior: movingObjectBehavior,
|
||||
object: movingObject,
|
||||
@@ -643,7 +615,7 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
stopped: false,
|
||||
});
|
||||
|
||||
runtimeScene.renderAndStepWithEventsFunction(1000 / fps, () => {
|
||||
runtimeScene.setEventsFunction(() => {
|
||||
// Manually call onContactEnd and onContactBegin methods to simulate
|
||||
// a loss of contact followed by a contact beginning and another loss
|
||||
// of contact during the event.
|
||||
@@ -665,6 +637,7 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
stopped: true,
|
||||
});
|
||||
});
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
});
|
||||
|
||||
it('it should end collision on resize (body updated in pre-event).', () => {
|
||||
@@ -674,9 +647,6 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
return (1 / fps) * 1000;
|
||||
};
|
||||
|
||||
// The behavior doesn't call Box2D step at the 1st frame.
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
|
||||
const {
|
||||
behavior: movingObjectBehavior,
|
||||
object: movingObject,
|
||||
@@ -698,15 +668,18 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
});
|
||||
|
||||
// Resize.
|
||||
runtimeScene.renderAndStepWithEventsFunction(1000 / fps, () => {
|
||||
runtimeScene.setEventsFunction(() => {
|
||||
movingObject.setCustomWidthAndHeight(5, 5);
|
||||
});
|
||||
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
assertCollision(movingObject, staticObject, {
|
||||
started: false,
|
||||
collision: true,
|
||||
stopped: false,
|
||||
});
|
||||
|
||||
runtimeScene.setEventsFunction(() => {});
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
assertCollision(movingObject, staticObject, {
|
||||
started: false,
|
||||
@@ -722,9 +695,6 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
return (1 / fps) * 1000;
|
||||
};
|
||||
|
||||
// The behavior doesn't call Box2D step at the 1st frame.
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
|
||||
const {
|
||||
behavior: movingObjectBehavior,
|
||||
object: movingObject,
|
||||
@@ -746,11 +716,13 @@ describe('Physics2RuntimeBehavior', () => {
|
||||
stopped: false,
|
||||
});
|
||||
|
||||
// Destroy (handled by postEvent).
|
||||
runtimeScene.renderAndStepWithEventsFunction(1000 / fps, () => {
|
||||
// Destroy (postEvent operation).
|
||||
runtimeScene.setEventsFunction(() => {
|
||||
movingObject.deleteFromScene(runtimeScene);
|
||||
});
|
||||
|
||||
runtimeScene.renderAndStep(1000 / fps);
|
||||
|
||||
// Collision should be reset on destroyed object and
|
||||
// added to contactsEndedThisFrame array of the other object.
|
||||
assertCollision(movingObject, staticObject, {
|
||||
|
@@ -36,24 +36,18 @@ std::map<gd::String, gd::PropertyDescriptor> PlatformBehavior::GetProperties(
|
||||
else if (platformType == "Jumpthru")
|
||||
platformTypeStr = _("Jumpthru platform");
|
||||
|
||||
properties["PlatformType"]
|
||||
.SetLabel(_("Type"))
|
||||
properties[_("Type")]
|
||||
.SetValue(platformTypeStr)
|
||||
.SetType("Choice")
|
||||
.AddExtraInfo(_("Platform"))
|
||||
.AddExtraInfo(_("Jumpthru platform"))
|
||||
.AddExtraInfo(_("Ladder"));
|
||||
properties["CanBeGrabbed"]
|
||||
.SetLabel(_("Ledges can be grabbed"))
|
||||
.SetGroup(_("Ledge"))
|
||||
properties[_("Ledges can be grabbed")].SetGroup(_("Ledge"))
|
||||
.SetValue(behaviorContent.GetBoolAttribute("canBeGrabbed", true)
|
||||
? "true"
|
||||
: "false")
|
||||
.SetType("Boolean");
|
||||
properties["YGrabOffset"]
|
||||
.SetLabel(_("Grab offset on Y axis"))
|
||||
.SetGroup(_("Ledge"))
|
||||
.SetValue(
|
||||
properties[_("Grab offset on Y axis")].SetGroup(_("Ledge")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("yGrabOffset")));
|
||||
|
||||
return properties;
|
||||
@@ -62,16 +56,16 @@ std::map<gd::String, gd::PropertyDescriptor> PlatformBehavior::GetProperties(
|
||||
bool PlatformBehavior::UpdateProperty(gd::SerializerElement& behaviorContent,
|
||||
const gd::String& name,
|
||||
const gd::String& value) {
|
||||
if (name == "CanBeGrabbed")
|
||||
if (name == _("Ledges can be grabbed"))
|
||||
behaviorContent.SetAttribute("canBeGrabbed", (value == "1"));
|
||||
else if (name == "PlatformType") {
|
||||
else if (name == _("Type")) {
|
||||
if (value == _("Jumpthru platform"))
|
||||
behaviorContent.SetAttribute("platformType", "Jumpthru");
|
||||
else if (value == _("Ladder"))
|
||||
behaviorContent.SetAttribute("platformType", "Ladder");
|
||||
else
|
||||
behaviorContent.SetAttribute("platformType", "NormalPlatform");
|
||||
} else if (name == "YGrabOffset")
|
||||
} else if (name == _("Grab offset on Y axis"))
|
||||
behaviorContent.SetAttribute("yGrabOffset", value.To<double>());
|
||||
else
|
||||
return false;
|
||||
|
@@ -13,7 +13,6 @@ This project is released under the MIT License.
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/MeasurementUnit.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
@@ -45,109 +44,60 @@ PlatformerObjectBehavior::GetProperties(
|
||||
const gd::SerializerElement& behaviorContent) const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
|
||||
properties["Gravity"]
|
||||
.SetLabel(_("Gravity"))
|
||||
properties[_("Gravity")].SetGroup(_("Jump")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("gravity")));
|
||||
properties[_("Jump speed")].SetGroup(_("Jump")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("jumpSpeed")));
|
||||
properties["jumpSustainTime"]
|
||||
.SetGroup(_("Jump"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixelAcceleration())
|
||||
.SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("gravity")));
|
||||
properties["JumpSpeed"]
|
||||
.SetLabel(_("Jump speed"))
|
||||
.SetGroup(_("Jump"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixelSpeed())
|
||||
.SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("jumpSpeed")));
|
||||
properties["JumpSustainTime"]
|
||||
.SetLabel(_("Jump sustain time"))
|
||||
.SetGroup(_("Jump"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetSecond())
|
||||
.SetValue(gd::String::From(
|
||||
behaviorContent.GetDoubleAttribute("jumpSustainTime", 0)))
|
||||
.SetLabel(_("Jump sustain time"))
|
||||
.SetDescription(
|
||||
_("Maximum time (in seconds) during which the jump strength is "
|
||||
"sustained if the jump key is held - allowing variable height "
|
||||
"jumps."));
|
||||
properties["MaxFallingSpeed"]
|
||||
.SetLabel(_("Max. falling speed"))
|
||||
.SetGroup(_("Jump"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixelSpeed())
|
||||
.SetValue(gd::String::From(
|
||||
behaviorContent.GetDoubleAttribute("maxFallingSpeed")));
|
||||
properties["LadderClimbingSpeed"]
|
||||
.SetLabel(_("Ladder climbing speed"))
|
||||
properties[_("Max. falling speed")].SetGroup(_("Jump")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("maxFallingSpeed")));
|
||||
properties[_("Ladder climbing speed")]
|
||||
.SetGroup(_("Ladder"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixelSpeed())
|
||||
.SetValue(gd::String::From(
|
||||
behaviorContent.GetDoubleAttribute("ladderClimbingSpeed", 150)));
|
||||
properties["Acceleration"]
|
||||
.SetLabel(_("Acceleration"))
|
||||
.SetGroup(_("Walk"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixelAcceleration())
|
||||
.SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("acceleration")));
|
||||
properties["Deceleration"]
|
||||
.SetLabel(_("Deceleration"))
|
||||
.SetGroup(_("Walk"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixelAcceleration())
|
||||
.SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("deceleration")));
|
||||
properties["MaxSpeed"]
|
||||
.SetLabel(_("Max. speed"))
|
||||
.SetGroup(_("Walk"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixelSpeed())
|
||||
.SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("maxSpeed")));
|
||||
properties["IgnoreDefaultControls"]
|
||||
.SetLabel(_("Default controls"))
|
||||
properties[_("Acceleration")].SetGroup(_("Walk")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("acceleration")));
|
||||
properties[_("Deceleration")].SetGroup(_("Walk")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("deceleration")));
|
||||
properties[_("Max. speed")].SetGroup(_("Walk")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("maxSpeed")));
|
||||
properties[_("Default controls")]
|
||||
.SetValue(behaviorContent.GetBoolAttribute("ignoreDefaultControls")
|
||||
? "false"
|
||||
: "true")
|
||||
.SetType("Boolean");
|
||||
properties["SlopeMaxAngle"]
|
||||
.SetLabel(_("Slope max. angle"))
|
||||
.SetGroup(_("Walk"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetDegreeAngle())
|
||||
.SetValue(gd::String::From(
|
||||
behaviorContent.GetDoubleAttribute("slopeMaxAngle")));
|
||||
properties["CanGrabPlatforms"]
|
||||
.SetLabel(_("Can grab platform ledges"))
|
||||
properties[_("Slope max. angle")].SetGroup(_("Walk")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("slopeMaxAngle")));
|
||||
properties[_("Can grab platform ledges")]
|
||||
.SetGroup(_("Ledge"))
|
||||
.SetValue(behaviorContent.GetBoolAttribute("canGrabPlatforms", false)
|
||||
? "true"
|
||||
: "false")
|
||||
.SetType("Boolean");
|
||||
properties["CanGrabWithoutMoving"]
|
||||
.SetLabel(_("Automatically grab platform ledges without having to move "
|
||||
"horizontally"))
|
||||
properties[_("Automatically grab platform ledges without having to move "
|
||||
"horizontally")]
|
||||
.SetGroup(_("Ledge"))
|
||||
.SetValue(behaviorContent.GetBoolAttribute("canGrabWithoutMoving", false)
|
||||
? "true"
|
||||
: "false")
|
||||
.SetType("Boolean");
|
||||
properties["YGrabOffset"]
|
||||
.SetLabel(_("Grab offset on Y axis"))
|
||||
properties[_("Grab offset on Y axis")]
|
||||
.SetGroup(_("Ledge"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("yGrabOffset")));
|
||||
properties["XGrabTolerance"]
|
||||
.SetLabel(_("Grab tolerance on X axis"))
|
||||
properties[_("Grab tolerance on X axis")]
|
||||
.SetGroup(_("Ledge"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetValue(gd::String::From(
|
||||
behaviorContent.GetDoubleAttribute("xGrabTolerance", 10)));
|
||||
properties["UseLegacyTrajectory"]
|
||||
properties["useLegacyTrajectory"]
|
||||
.SetLabel(_("Use frame rate dependent trajectories (deprecated, it's "
|
||||
"recommended to leave this unchecked)"))
|
||||
.SetGroup(_("Deprecated options (advanced)"))
|
||||
@@ -155,8 +105,7 @@ PlatformerObjectBehavior::GetProperties(
|
||||
? "true"
|
||||
: "false")
|
||||
.SetType("Boolean");
|
||||
properties["CanGoDownFromJumpthru"]
|
||||
.SetLabel(_("Can go down from jumpthru platforms"))
|
||||
properties[_("Can go down from jumpthru platforms")]
|
||||
.SetGroup(_("Walk"))
|
||||
.SetValue(behaviorContent.GetBoolAttribute("canGoDownFromJumpthru", false)
|
||||
? "true"
|
||||
@@ -169,43 +118,44 @@ bool PlatformerObjectBehavior::UpdateProperty(
|
||||
gd::SerializerElement& behaviorContent,
|
||||
const gd::String& name,
|
||||
const gd::String& value) {
|
||||
if (name == "IgnoreDefaultControls")
|
||||
if (name == _("Default controls"))
|
||||
behaviorContent.SetAttribute("ignoreDefaultControls", (value == "0"));
|
||||
else if (name == "CanGrabPlatforms")
|
||||
else if (name == _("Can grab platform ledges"))
|
||||
behaviorContent.SetAttribute("canGrabPlatforms", (value == "1"));
|
||||
else if (name == "CanGrabWithoutMoving")
|
||||
else if (name == _("Automatically grab platform ledges without having to "
|
||||
"move horizontally"))
|
||||
behaviorContent.SetAttribute("canGrabWithoutMoving", (value == "1"));
|
||||
else if (name == "UseLegacyTrajectory")
|
||||
else if (name == "useLegacyTrajectory")
|
||||
behaviorContent.SetAttribute("useLegacyTrajectory", (value == "1"));
|
||||
else if (name == "CanGoDownFromJumpthru")
|
||||
else if (name == _("Can go down from jumpthru platforms"))
|
||||
behaviorContent.SetAttribute("canGoDownFromJumpthru", (value == "1"));
|
||||
else if (name == "YGrabOffset")
|
||||
else if (name == _("Grab offset on Y axis"))
|
||||
behaviorContent.SetAttribute("yGrabOffset", value.To<double>());
|
||||
else {
|
||||
if (value.To<double>() < 0) return false;
|
||||
|
||||
if (name == "Gravity")
|
||||
if (name == _("Gravity"))
|
||||
behaviorContent.SetAttribute("gravity", value.To<double>());
|
||||
else if (name == "MaxFallingSpeed")
|
||||
else if (name == _("Max. falling speed"))
|
||||
behaviorContent.SetAttribute("maxFallingSpeed", value.To<double>());
|
||||
else if (name == "LadderClimbingSpeed")
|
||||
else if (name == _("Ladder climbing speed"))
|
||||
behaviorContent.SetAttribute("ladderClimbingSpeed", value.To<double>());
|
||||
else if (name == "Acceleration")
|
||||
else if (name == _("Acceleration"))
|
||||
behaviorContent.SetAttribute("acceleration", value.To<double>());
|
||||
else if (name == "Deceleration")
|
||||
else if (name == _("Deceleration"))
|
||||
behaviorContent.SetAttribute("deceleration", value.To<double>());
|
||||
else if (name == "MaxSpeed")
|
||||
else if (name == _("Max. speed"))
|
||||
behaviorContent.SetAttribute("maxSpeed", value.To<double>());
|
||||
else if (name == "JumpSpeed")
|
||||
else if (name == _("Jump speed"))
|
||||
behaviorContent.SetAttribute("jumpSpeed", value.To<double>());
|
||||
else if (name == "JumpSustainTime")
|
||||
else if (name == "jumpSustainTime")
|
||||
behaviorContent.SetAttribute("jumpSustainTime", value.To<double>());
|
||||
else if (name == "SlopeMaxAngle") {
|
||||
else if (name == _("Slope max. angle")) {
|
||||
double newMaxAngle = value.To<double>();
|
||||
if (newMaxAngle < 0 || newMaxAngle >= 90) return false;
|
||||
|
||||
behaviorContent.SetAttribute("slopeMaxAngle", newMaxAngle);
|
||||
} else if (name == "XGrabTolerance")
|
||||
} else if (name == _("Grab tolerance on X axis"))
|
||||
behaviorContent.SetAttribute("xGrabTolerance", value.To<double>());
|
||||
else
|
||||
return false;
|
||||
|
@@ -1143,14 +1143,6 @@ namespace gdjs {
|
||||
return this._gravity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get maximum angle of a slope for the Platformer Object to run on it as a floor.
|
||||
* @returns the slope maximum angle, in degrees.
|
||||
*/
|
||||
getSlopeMaxAngle(): float {
|
||||
return this._slopeMaxAngle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum falling speed of the Platformer Object.
|
||||
* @returns The maximum falling speed.
|
||||
|
@@ -404,9 +404,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
||||
expect(object.getY()).to.be(-30); // -30 = -10 (platform y) + -20 (object height)
|
||||
|
||||
// Make the platform under the character feet smaller.
|
||||
runtimeScene.renderAndStepWithEventsFunction(1000 / 60, () => {
|
||||
object.setCustomWidthAndHeight(object.getWidth(), 9);
|
||||
});
|
||||
object.setCustomWidthAndHeight(object.getWidth(), 9);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
expect(object.getBehavior('auto1').isFalling()).to.be(false);
|
||||
expect(object.getBehavior('auto1').isFallingWithoutJumping()).to.be(
|
||||
@@ -681,11 +679,18 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
||||
expect(object.getY()).to.be.within(140.6297999, 140.6298001);
|
||||
|
||||
// Move the platform by 6 pixels to the right.
|
||||
for (let index = 0; index < 6; index++) {
|
||||
runtimeScene.renderAndStepWithEventsFunction(1000 / 60, () => {
|
||||
platform.setX(platform.getX() + 1);
|
||||
});
|
||||
}
|
||||
platform.setX(platform.getX() + 1);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
platform.setX(platform.getX() + 1);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
platform.setX(platform.getX() + 1);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
platform.setX(platform.getX() + 1);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
platform.setX(platform.getX() + 1);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
platform.setX(platform.getX() + 1);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
// Ensure the object followed the platform on the X axis.
|
||||
// If the floating point errors caused oscillations between two Y positions,
|
||||
@@ -694,9 +699,6 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
||||
expect(object.getBehavior('auto1').isFalling()).to.be(false);
|
||||
expect(object.getBehavior('auto1').isOnFloor()).to.be(true);
|
||||
expect(object.getY()).to.be.within(140.6297999, 140.6298001);
|
||||
// TODO Remove the 1-frame delay
|
||||
expect(object.getX()).to.be(5);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
expect(object.getX()).to.be(6);
|
||||
});
|
||||
});
|
||||
|
@@ -59,18 +59,13 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
||||
|
||||
// Check that the object follow the platform, even if the
|
||||
// movement is less than one pixel.
|
||||
runtimeScene.renderAndStepWithEventsFunction(1000 / 60, () => {
|
||||
platform.setX(platform.getX() + 0.12);
|
||||
});
|
||||
runtimeScene.renderAndStepWithEventsFunction(1000 / 60, () => {
|
||||
platform.setX(platform.getX() + 0.12);
|
||||
});
|
||||
runtimeScene.renderAndStepWithEventsFunction(1000 / 60, () => {
|
||||
platform.setX(platform.getX() + 0.12);
|
||||
});
|
||||
// TODO Remove the 1-frame delay
|
||||
expect(object.getX()).to.be(0.24);
|
||||
platform.setX(platform.getX() + 0.12);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
platform.setX(platform.getX() + 0.12);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
platform.setX(platform.getX() + 0.12);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
expect(object.getX()).to.be(0.36);
|
||||
});
|
||||
|
||||
@@ -245,28 +240,22 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
||||
// Check that the object follow the platform, even if the
|
||||
// movement is less than one pixel.
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
const previousPlatformY = platform.getY();
|
||||
runtimeScene.renderAndStepWithEventsFunction(1000 / 60, () => {
|
||||
platform.setPosition(
|
||||
platform.getX() + deltaX,
|
||||
platform.getY() + deltaY
|
||||
);
|
||||
});
|
||||
platform.setPosition(
|
||||
platform.getX() + deltaX,
|
||||
platform.getY() + deltaY
|
||||
);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
expect(object.getBehavior('auto1').isOnFloor()).to.be(true);
|
||||
expect(object.getBehavior('auto1').isFalling()).to.be(false);
|
||||
expect(object.getBehavior('auto1').isMoving()).to.be(false);
|
||||
// The object follow the platform
|
||||
// The rounding error is probably due to a separate call.
|
||||
// TODO Try to make it exact or find why
|
||||
// TODO Remove the 1-frame delay
|
||||
expect(object.getY()).to.be.within(
|
||||
previousPlatformY - object.getHeight() - epsilon,
|
||||
previousPlatformY - object.getHeight() + epsilon
|
||||
platform.getY() - object.getHeight() - epsilon,
|
||||
platform.getY() - object.getHeight() + epsilon
|
||||
);
|
||||
}
|
||||
// TODO Remove the 1-frame delay
|
||||
expect(object.getX()).to.be(0 + 4 * deltaX);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
expect(object.getX()).to.be(0 + 5 * deltaX);
|
||||
});
|
||||
});
|
||||
@@ -389,26 +378,20 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
||||
// Check that the object follow the platform, even if the
|
||||
// movement is less than one pixel.
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
const previousPlatformY = platform.getY();
|
||||
runtimeScene.renderAndStepWithEventsFunction(1000 / 60, () => {
|
||||
platform.setPosition(
|
||||
platform.getX() + deltaX,
|
||||
platform.getY() + deltaY
|
||||
);
|
||||
});
|
||||
platform.setPosition(
|
||||
platform.getX() + deltaX,
|
||||
platform.getY() + deltaY
|
||||
);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
expect(object.getBehavior('auto1').isOnFloor()).to.be(true);
|
||||
expect(object.getBehavior('auto1').isFalling()).to.be(false);
|
||||
expect(object.getBehavior('auto1').isMoving()).to.be(false);
|
||||
// The object must not be inside the platform or it gets stuck
|
||||
// TODO Remove the 1-frame delay
|
||||
expect(object.getY()).to.be.within(
|
||||
previousPlatformY - object.getHeight() - epsilon,
|
||||
previousPlatformY - object.getHeight() + epsilon
|
||||
platform.getY() - object.getHeight() - epsilon,
|
||||
platform.getY() - object.getHeight() + epsilon
|
||||
);
|
||||
}
|
||||
// TODO Remove the 1-frame delay
|
||||
expect(object.getX()).to.be(0 + 4 * deltaX);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
expect(object.getX()).to.be(0 + 5 * deltaX);
|
||||
});
|
||||
});
|
||||
|
@@ -7,7 +7,7 @@
|
||||
},
|
||||
properties: { windowWidth: 800, windowHeight: 600 },
|
||||
});
|
||||
const runtimeScene = new gdjs.TestRuntimeScene(runtimeGame);
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [{ name: '', visibility: true, effects: [] }],
|
||||
variables: [],
|
||||
|
@@ -111,6 +111,7 @@ describe('gdjs.TextInputRuntimeObject (using a PixiJS RuntimeGame with DOM eleme
|
||||
const {
|
||||
runtimeScene,
|
||||
gameDomElementContainer,
|
||||
object,
|
||||
} = await setupObjectAndGetDomElementContainer();
|
||||
|
||||
expect(gameDomElementContainer.querySelector('input')).not.to.be(null);
|
||||
|
@@ -170,21 +170,19 @@ namespace gdjs {
|
||||
// Position the input on the container on top of the canvas.
|
||||
workingPoint[0] = canvasLeft;
|
||||
workingPoint[1] = canvasTop;
|
||||
runtimeGameRenderer.convertCanvasToDomElementContainerCoords(
|
||||
workingPoint,
|
||||
const topLeftPageCoordinates = runtimeGameRenderer.convertCanvasToDomElementContainerCoords(
|
||||
workingPoint
|
||||
);
|
||||
const pageLeft = workingPoint[0];
|
||||
const pageTop = workingPoint[1];
|
||||
const pageLeft = topLeftPageCoordinates[0];
|
||||
const pageTop = topLeftPageCoordinates[1];
|
||||
|
||||
workingPoint[0] = canvasRight;
|
||||
workingPoint[1] = canvasBottom;
|
||||
runtimeGameRenderer.convertCanvasToDomElementContainerCoords(
|
||||
workingPoint,
|
||||
const bottomRightPageCoordinates = runtimeGameRenderer.convertCanvasToDomElementContainerCoords(
|
||||
workingPoint
|
||||
);
|
||||
const pageRight = workingPoint[0];
|
||||
const pageBottom = workingPoint[1];
|
||||
const pageRight = bottomRightPageCoordinates[0];
|
||||
const pageBottom = bottomRightPageCoordinates[1];
|
||||
|
||||
const widthInContainer = pageRight - pageLeft;
|
||||
const heightInContainer = pageBottom - pageTop;
|
||||
|
@@ -1,4 +1,6 @@
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Text input object');
|
||||
|
||||
const supportedInputTypes = [
|
||||
'text',
|
||||
'email',
|
||||
|
@@ -29,8 +29,7 @@ TextObject::TextObject()
|
||||
underlined(false),
|
||||
colorR(0),
|
||||
colorG(0),
|
||||
colorB(0),
|
||||
textAlignment("left")
|
||||
colorB(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -40,7 +39,6 @@ void TextObject::DoUnserializeFrom(gd::Project& project,
|
||||
const gd::SerializerElement& element) {
|
||||
SetString(element.GetChild("string", 0, "String").GetValue().GetString());
|
||||
SetFontName(element.GetChild("font", 0, "Font").GetValue().GetString());
|
||||
SetTextAlignment(element.GetChild("textAlignment").GetValue().GetString());
|
||||
SetCharacterSize(element.GetChild("characterSize", 0, "CharacterSize")
|
||||
.GetValue()
|
||||
.GetInt());
|
||||
@@ -58,7 +56,6 @@ void TextObject::DoUnserializeFrom(gd::Project& project,
|
||||
void TextObject::DoSerializeTo(gd::SerializerElement& element) const {
|
||||
element.AddChild("string").SetValue(GetString());
|
||||
element.AddChild("font").SetValue(GetFontName());
|
||||
element.AddChild("textAlignment").SetValue(GetTextAlignment());
|
||||
element.AddChild("characterSize").SetValue(GetCharacterSize());
|
||||
element.AddChild("color")
|
||||
.SetAttribute("r", (int)GetColorR())
|
||||
|
@@ -53,9 +53,6 @@ class GD_EXTENSION_API TextObject : public gd::ObjectConfiguration {
|
||||
*/
|
||||
void SetFontName(const gd::String& resourceName) { fontName = resourceName; };
|
||||
|
||||
inline const gd::String& GetTextAlignment() const { return textAlignment; };
|
||||
void SetTextAlignment(const gd::String& textAlignment_) { textAlignment = textAlignment_; };
|
||||
|
||||
bool IsBold() const { return bold; };
|
||||
void SetBold(bool enable) { bold = enable; };
|
||||
bool IsItalic() const { return italic; };
|
||||
@@ -90,7 +87,6 @@ class GD_EXTENSION_API TextObject : public gd::ObjectConfiguration {
|
||||
unsigned int colorR;
|
||||
unsigned int colorG;
|
||||
unsigned int colorB;
|
||||
gd::String textAlignment;
|
||||
};
|
||||
|
||||
#endif // TEXTOBJECT_H
|
||||
|
@@ -94,25 +94,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
updatePosition(): void {
|
||||
if (this._object.isWrapping()) {
|
||||
const alignmentX =
|
||||
this._object._textAlign === 'right'
|
||||
? 1
|
||||
: this._object._textAlign === 'center'
|
||||
? 0.5
|
||||
: 0;
|
||||
|
||||
const width = this._object.getWrappingWidth();
|
||||
|
||||
// A vector from the custom size center to the renderer center.
|
||||
const centerToCenterX = (width - this._text.width) * (alignmentX - 0.5);
|
||||
|
||||
this._text.position.x = this._object.x + width / 2;
|
||||
this._text.anchor.x = 0.5 - centerToCenterX / this._text.width;
|
||||
} else {
|
||||
this._text.position.x = this._object.x + this._text.width / 2;
|
||||
this._text.anchor.x = 0.5;
|
||||
}
|
||||
this._text.position.x = this._object.x + this._text.width / 2;
|
||||
this._text.position.y = this._object.y + this._text.height / 2;
|
||||
}
|
||||
|
||||
|
@@ -26,7 +26,6 @@ namespace gdjs {
|
||||
};
|
||||
/** The text of the object */
|
||||
string: string;
|
||||
textAlignment: string;
|
||||
};
|
||||
|
||||
export type TextObjectData = ObjectData & TextObjectDataType;
|
||||
@@ -83,7 +82,6 @@ namespace gdjs {
|
||||
textObjectData.color.b,
|
||||
];
|
||||
this._str = textObjectData.string;
|
||||
this._textAlign = textObjectData.textAlignment;
|
||||
this._renderer = new gdjs.TextRuntimeObjectRenderer(
|
||||
this,
|
||||
instanceContainer
|
||||
@@ -129,9 +127,6 @@ namespace gdjs {
|
||||
if (oldObjectData.underlined !== newObjectData.underlined) {
|
||||
return false;
|
||||
}
|
||||
if (oldObjectData.textAlignment !== newObjectData.textAlignment) {
|
||||
this.setTextAlignment(newObjectData.textAlignment);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -293,7 +288,7 @@ namespace gdjs {
|
||||
* Get width of the text.
|
||||
*/
|
||||
getWidth(): float {
|
||||
return this._wrapping ? this._wrappingWidth : this._renderer.getWidth();
|
||||
return this._renderer.getWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -124,7 +124,7 @@ describe('gdjs.TileMapCollisionMaskRuntimeObject', function () {
|
||||
index < 200 && tileMap._collisionTileMap.getDimensionX() === 0;
|
||||
index++
|
||||
) {
|
||||
await delay(100);
|
||||
await delay(25);
|
||||
}
|
||||
if (tileMap._collisionTileMap.getDimensionX() === 0) {
|
||||
throw new Error('Timeout reading the tile map JSON file.');
|
||||
|
@@ -1,5 +1,7 @@
|
||||
/// <reference path="helper/TileMapHelper.d.ts" />
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Tilemap object');
|
||||
|
||||
/**
|
||||
* An object that handle hitboxes for a tile map.
|
||||
* @extends gdjs.RuntimeObject
|
||||
@@ -180,7 +182,7 @@ namespace gdjs {
|
||||
updateHitBoxes(): void {
|
||||
this.updateTransformation();
|
||||
// Update the RuntimeObject hitboxes attribute.
|
||||
for (const _ of this._collisionTileMap.getAllHitboxes(
|
||||
for (const hitboxes of this._collisionTileMap.getAllHitboxes(
|
||||
this._collisionMaskTag
|
||||
)) {
|
||||
// RuntimeObject.hitBoxes contains the same polygons instances as the
|
||||
|
@@ -1,6 +1,8 @@
|
||||
/// <reference path="helper/TileMapHelper.d.ts" />
|
||||
/// <reference path="pixi-tilemap/dist/pixi-tilemap.d.ts" />
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Tilemap object');
|
||||
|
||||
/**
|
||||
* The PIXI.js renderer for the Tile map runtime object.
|
||||
*
|
||||
|
@@ -2,6 +2,7 @@
|
||||
namespace gdjs {
|
||||
import PIXI = GlobalPIXIModule.PIXI;
|
||||
|
||||
const logger = new gdjs.Logger('Tilemap object');
|
||||
/**
|
||||
* Displays a Tilemap object (mapeditor.org supported).
|
||||
*/
|
||||
|
@@ -66,13 +66,13 @@ namespace gdjs {
|
||||
return this._tiledSprite.height;
|
||||
}
|
||||
|
||||
setWidth(width: float): void {
|
||||
setWidth(width): void {
|
||||
this._tiledSprite.width = width;
|
||||
this._tiledSprite.pivot.x = width / 2;
|
||||
this.updatePosition();
|
||||
}
|
||||
|
||||
setHeight(height: float): void {
|
||||
setHeight(height): void {
|
||||
this._tiledSprite.height = height;
|
||||
this._tiledSprite.pivot.y = height / 2;
|
||||
this.updatePosition();
|
||||
@@ -94,7 +94,7 @@ namespace gdjs {
|
||||
-this._object._yOffset % this._tiledSprite.texture.height;
|
||||
}
|
||||
|
||||
setColor(rgbColor: string): void {
|
||||
setColor(rgbColor): void {
|
||||
const colors = rgbColor.split(';');
|
||||
if (colors.length < 3) {
|
||||
return;
|
||||
|
@@ -14,7 +14,6 @@ This project is released under the MIT License.
|
||||
#include <set>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Project/MeasurementUnit.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
@@ -46,55 +45,26 @@ TopDownMovementBehavior::GetProperties(
|
||||
const gd::SerializerElement& behaviorContent) const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
|
||||
properties["AllowDiagonals"]
|
||||
.SetLabel(_("Allows diagonals"))
|
||||
.SetGroup(_("Movement"))
|
||||
properties[_("Allows diagonals")].SetGroup(_("Movement"))
|
||||
.SetValue(behaviorContent.GetBoolAttribute("allowDiagonals") ? "true"
|
||||
: "false")
|
||||
.SetType("Boolean");
|
||||
properties["Acceleration"]
|
||||
.SetLabel(_("Acceleration"))
|
||||
.SetGroup(_("Movement"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixelAcceleration())
|
||||
.SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("acceleration")));
|
||||
properties["Deceleration"]
|
||||
.SetLabel(_("Deceleration"))
|
||||
.SetGroup(_("Movement"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixelAcceleration())
|
||||
.SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("deceleration")));
|
||||
properties["MaxSpeed"]
|
||||
.SetLabel(_("Max. speed"))
|
||||
.SetGroup(_("Movement"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixelSpeed())
|
||||
.SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("maxSpeed")));
|
||||
properties["AngularMaxSpeed"]
|
||||
.SetLabel(_("Rotation speed"))
|
||||
.SetGroup(_("Rotation"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetAngularSpeed())
|
||||
.SetValue(gd::String::From(
|
||||
behaviorContent.GetDoubleAttribute("angularMaxSpeed")));
|
||||
properties["RotateObject"]
|
||||
.SetLabel(_("Rotate object"))
|
||||
properties[_("Acceleration")].SetGroup(_("Movement")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("acceleration")));
|
||||
properties[_("Deceleration")].SetGroup(_("Movement")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("deceleration")));
|
||||
properties[_("Max. speed")].SetGroup(_("Movement")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("maxSpeed")));
|
||||
properties[_("Rotate speed")].SetGroup(_("Rotation")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("angularMaxSpeed")));
|
||||
properties[_("Rotate object")]
|
||||
.SetGroup(_("Rotation"))
|
||||
.SetValue(behaviorContent.GetBoolAttribute("rotateObject") ? "true"
|
||||
: "false")
|
||||
.SetType("Boolean");
|
||||
properties["AngleOffset"]
|
||||
.SetLabel(_("Angle offset"))
|
||||
.SetGroup(_("Rotation"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetDegreeAngle())
|
||||
.SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("angleOffset")));
|
||||
properties["IgnoreDefaultControls"]
|
||||
.SetLabel(_("Default controls"))
|
||||
properties[_("Angle offset")].SetGroup(_("Rotation")).SetValue(
|
||||
gd::String::From(behaviorContent.GetDoubleAttribute("angleOffset")));
|
||||
properties[_("Default controls")]
|
||||
.SetValue(behaviorContent.GetBoolAttribute("ignoreDefaultControls")
|
||||
? "false"
|
||||
: "true")
|
||||
@@ -110,8 +80,7 @@ TopDownMovementBehavior::GetProperties(
|
||||
viewpointStr = _("True Isometry (30°)");
|
||||
else if (viewpoint == "CustomIsometry")
|
||||
viewpointStr = _("Custom Isometry");
|
||||
properties["Viewpoint"]
|
||||
.SetLabel(_("Viewpoint"))
|
||||
properties[_("Viewpoint")]
|
||||
.SetGroup(_("Viewpoint"))
|
||||
.SetValue(viewpointStr)
|
||||
.SetType("Choice")
|
||||
@@ -119,20 +88,14 @@ TopDownMovementBehavior::GetProperties(
|
||||
.AddExtraInfo(_("Isometry 2:1 (26.565°)"))
|
||||
.AddExtraInfo(_("True Isometry (30°)"))
|
||||
.AddExtraInfo(_("Custom Isometry"));
|
||||
properties["CustomIsometryAngle"]
|
||||
.SetLabel(_("Custom isometry angle"))
|
||||
properties[_("Custom isometry angle")]
|
||||
.SetGroup(_("Viewpoint"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetDegreeAngle())
|
||||
.SetValue(gd::String::From(
|
||||
behaviorContent.GetDoubleAttribute("customIsometryAngle")))
|
||||
.SetDescription(_("If you choose \"Custom Isometry\", this allows to "
|
||||
"specify the angle of your isometry projection."));
|
||||
properties["MovementAngleOffset"]
|
||||
.SetLabel(_("Movement angle offset"))
|
||||
properties[_("Movement angle offset")]
|
||||
.SetGroup(_("Viewpoint"))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetDegreeAngle())
|
||||
.SetValue(gd::String::From(
|
||||
behaviorContent.GetDoubleAttribute("movementAngleOffset")))
|
||||
.SetDescription(_(
|
||||
@@ -146,19 +109,19 @@ bool TopDownMovementBehavior::UpdateProperty(
|
||||
gd::SerializerElement& behaviorContent,
|
||||
const gd::String& name,
|
||||
const gd::String& value) {
|
||||
if (name == "IgnoreDefaultControls") {
|
||||
if (name == _("Default controls")) {
|
||||
behaviorContent.SetAttribute("ignoreDefaultControls", (value == "0"));
|
||||
return true;
|
||||
}
|
||||
if (name == "AllowDiagonals") {
|
||||
if (name == _("Allows diagonals")) {
|
||||
behaviorContent.SetAttribute("allowDiagonals", (value != "0"));
|
||||
return true;
|
||||
}
|
||||
if (name == "RotateObject") {
|
||||
if (name == _("Rotate object")) {
|
||||
behaviorContent.SetAttribute("rotateObject", (value != "0"));
|
||||
return true;
|
||||
}
|
||||
if (name == "Viewpoint") {
|
||||
if (name == _("Viewpoint")) {
|
||||
// Fix the offset angle when switching between top-down and isometry
|
||||
const gd::String& oldValue =
|
||||
behaviorContent.GetStringAttribute("viewpoint", "TopDown", "");
|
||||
@@ -184,23 +147,23 @@ bool TopDownMovementBehavior::UpdateProperty(
|
||||
behaviorContent.SetAttribute("viewpoint", "TopDown");
|
||||
return true;
|
||||
}
|
||||
if (name == "MovementAngleOffset") {
|
||||
if (name == _("Movement angle offset")) {
|
||||
behaviorContent.SetAttribute("movementAngleOffset", value.To<float>());
|
||||
}
|
||||
|
||||
if (value.To<float>() < 0) return false;
|
||||
|
||||
if (name == "Acceleration")
|
||||
if (name == _("Acceleration"))
|
||||
behaviorContent.SetAttribute("acceleration", value.To<float>());
|
||||
else if (name == "Deceleration")
|
||||
else if (name == _("Deceleration"))
|
||||
behaviorContent.SetAttribute("deceleration", value.To<float>());
|
||||
else if (name == "MaxSpeed")
|
||||
else if (name == _("Max. speed"))
|
||||
behaviorContent.SetAttribute("maxSpeed", value.To<float>());
|
||||
else if (name == "RotationSpeed")
|
||||
else if (name == _("Rotate speed"))
|
||||
behaviorContent.SetAttribute("angularMaxSpeed", value.To<float>());
|
||||
else if (name == "AngleOffset")
|
||||
else if (name == _("Angle offset"))
|
||||
behaviorContent.SetAttribute("angleOffset", value.To<float>());
|
||||
else if (name == "CustomIsometryAngle") {
|
||||
else if (name == _("Custom isometry angle")) {
|
||||
if (value.To<float>() < 1 || value.To<float>() > 44) return false;
|
||||
behaviorContent.SetAttribute("customIsometryAngle", value.To<float>());
|
||||
} else
|
||||
|
@@ -24,6 +24,8 @@ namespace gdjs {
|
||||
private _angle: float = 0;
|
||||
|
||||
//Attributes used when moving
|
||||
private _x: float = 0;
|
||||
private _y: float = 0;
|
||||
private _xVelocity: float = 0;
|
||||
private _yVelocity: float = 0;
|
||||
private _angularSpeed: float = 0;
|
||||
|
@@ -42,7 +42,7 @@ JsCodeEvent::GetAllExpressionsWithMetadata() const {
|
||||
}
|
||||
|
||||
void JsCodeEvent::SerializeTo(gd::SerializerElement& element) const {
|
||||
element.AddChild("inlineCode").SetMultilineStringValue(inlineCode);
|
||||
element.AddChild("inlineCode").SetValue(inlineCode);
|
||||
element.AddChild("parameterObjects")
|
||||
.SetValue(parameterObjects.GetPlainString());
|
||||
element.AddChild("useStrict").SetValue(useStrict);
|
||||
@@ -51,7 +51,7 @@ void JsCodeEvent::SerializeTo(gd::SerializerElement& element) const {
|
||||
|
||||
void JsCodeEvent::UnserializeFrom(gd::Project& project,
|
||||
const gd::SerializerElement& element) {
|
||||
inlineCode = element.GetChild("inlineCode").GetMultilineStringValue();
|
||||
inlineCode = element.GetChild("inlineCode").GetValue().GetString();
|
||||
parameterObjects = gd::Expression(
|
||||
element.GetChild("parameterObjects").GetValue().GetString());
|
||||
|
||||
|
@@ -22,130 +22,95 @@ gd::String BehaviorCodeGenerator::GenerateRuntimeBehaviorCompleteCode(
|
||||
auto& eventsFunctionsVector =
|
||||
eventsBasedBehavior.GetEventsFunctions().GetInternalVector();
|
||||
|
||||
auto generateInitializePropertiesCode = [&]() {
|
||||
gd::String runtimeBehaviorDataInitializationCode;
|
||||
for (auto& property :
|
||||
eventsBasedBehavior.GetPropertyDescriptors().GetInternalVector()) {
|
||||
runtimeBehaviorDataInitializationCode +=
|
||||
property->IsHidden()
|
||||
? GenerateInitializePropertyFromDefaultValueCode(*property)
|
||||
: GenerateInitializePropertyFromDataCode(*property);
|
||||
}
|
||||
|
||||
return runtimeBehaviorDataInitializationCode;
|
||||
};
|
||||
|
||||
auto generatePropertiesCode = [&]() {
|
||||
gd::String runtimeBehaviorPropertyMethodsCode;
|
||||
for (auto& property :
|
||||
eventsBasedBehavior.GetPropertyDescriptors().GetInternalVector()) {
|
||||
runtimeBehaviorPropertyMethodsCode +=
|
||||
GenerateRuntimeBehaviorPropertyTemplateCode(
|
||||
eventsBasedBehavior, *property);
|
||||
}
|
||||
|
||||
return runtimeBehaviorPropertyMethodsCode;
|
||||
};
|
||||
|
||||
auto generateInitializeSharedPropertiesCode = [&]() {
|
||||
gd::String runtimeBehaviorSharedDataInitializationCode;
|
||||
for (auto& property :
|
||||
eventsBasedBehavior.GetSharedPropertyDescriptors().GetInternalVector()) {
|
||||
runtimeBehaviorSharedDataInitializationCode +=
|
||||
property->IsHidden()
|
||||
? GenerateInitializeSharedPropertyFromDefaultValueCode(*property)
|
||||
: GenerateInitializeSharedPropertyFromDataCode(*property);
|
||||
}
|
||||
|
||||
return runtimeBehaviorSharedDataInitializationCode;
|
||||
};
|
||||
|
||||
auto generateSharedPropertiesCode = [&]() {
|
||||
gd::String runtimeBehaviorSharedPropertyMethodsCode;
|
||||
for (auto& property :
|
||||
eventsBasedBehavior.GetSharedPropertyDescriptors().GetInternalVector()) {
|
||||
runtimeBehaviorSharedPropertyMethodsCode +=
|
||||
GenerateRuntimeBehaviorSharedPropertyTemplateCode(
|
||||
eventsBasedBehavior, *property);
|
||||
}
|
||||
|
||||
return runtimeBehaviorSharedPropertyMethodsCode;
|
||||
};
|
||||
|
||||
// TODO: Update code generation to be able to generate methods (which would allow
|
||||
// for a cleaner output, not having to add methods to the prototype).
|
||||
auto generateMethodsCode = [&]() {
|
||||
gd::String runtimeBehaviorMethodsCode;
|
||||
for (auto& eventsFunction : eventsFunctionsVector) {
|
||||
const gd::String& functionName =
|
||||
behaviorMethodMangledNames.find(eventsFunction->GetName()) !=
|
||||
behaviorMethodMangledNames.end()
|
||||
? behaviorMethodMangledNames.find(eventsFunction->GetName())
|
||||
->second
|
||||
: "UNKNOWN_FUNCTION_fix_behaviorMethodMangledNames_please";
|
||||
gd::String methodCodeNamespace =
|
||||
codeNamespace + "." + eventsBasedBehavior.GetName() +
|
||||
".prototype." + functionName + "Context";
|
||||
gd::String methodFullyQualifiedName = codeNamespace + "." +
|
||||
eventsBasedBehavior.GetName() +
|
||||
".prototype." + functionName;
|
||||
runtimeBehaviorMethodsCode +=
|
||||
EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
project,
|
||||
eventsBasedBehavior,
|
||||
*eventsFunction,
|
||||
methodCodeNamespace,
|
||||
methodFullyQualifiedName,
|
||||
"that._onceTriggers",
|
||||
functionName == doStepPreEventsFunctionName
|
||||
? GenerateDoStepPreEventsPreludeCode()
|
||||
: "",
|
||||
includeFiles,
|
||||
compilationForRuntime);
|
||||
|
||||
// Compatibility with GD <= 5.0 beta 75
|
||||
if (functionName == "onOwnerRemovedFromScene") {
|
||||
runtimeBehaviorMethodsCode +=
|
||||
GenerateBehaviorOnDestroyToDeprecatedOnOwnerRemovedFromScene(
|
||||
eventsBasedBehavior, codeNamespace);
|
||||
}
|
||||
// end of compatibility code
|
||||
}
|
||||
|
||||
bool hasDoStepPreEventsFunction =
|
||||
eventsBasedBehavior.GetEventsFunctions().HasEventsFunctionNamed(
|
||||
doStepPreEventsFunctionName);
|
||||
if (!hasDoStepPreEventsFunction) {
|
||||
runtimeBehaviorMethodsCode +=
|
||||
GenerateDefaultDoStepPreEventsFunctionCode(eventsBasedBehavior,
|
||||
codeNamespace);
|
||||
}
|
||||
|
||||
return runtimeBehaviorMethodsCode;
|
||||
};
|
||||
|
||||
auto generateUpdateFromBehaviorDataCode = [&]() {
|
||||
gd::String updateFromBehaviorCode;
|
||||
for (auto& property :
|
||||
eventsBasedBehavior.GetPropertyDescriptors().GetInternalVector()) {
|
||||
updateFromBehaviorCode +=
|
||||
GenerateUpdatePropertyFromBehaviorDataCode(
|
||||
eventsBasedBehavior, *property);
|
||||
}
|
||||
|
||||
return updateFromBehaviorCode;
|
||||
};
|
||||
|
||||
return GenerateRuntimeBehaviorTemplateCode(
|
||||
extensionName,
|
||||
eventsBasedBehavior,
|
||||
codeNamespace,
|
||||
generateInitializePropertiesCode,
|
||||
generatePropertiesCode,
|
||||
generateInitializeSharedPropertiesCode,
|
||||
generateSharedPropertiesCode,
|
||||
generateMethodsCode,
|
||||
generateUpdateFromBehaviorDataCode);
|
||||
[&]() {
|
||||
gd::String runtimeBehaviorDataInitializationCode;
|
||||
for (auto& property :
|
||||
eventsBasedBehavior.GetPropertyDescriptors().GetInternalVector()) {
|
||||
runtimeBehaviorDataInitializationCode +=
|
||||
property->IsHidden()
|
||||
? GenerateInitializePropertyFromDefaultValueCode(*property)
|
||||
: GenerateInitializePropertyFromDataCode(*property);
|
||||
}
|
||||
|
||||
return runtimeBehaviorDataInitializationCode;
|
||||
},
|
||||
[&]() {
|
||||
gd::String runtimeBehaviorPropertyMethodsCode;
|
||||
for (auto& property :
|
||||
eventsBasedBehavior.GetPropertyDescriptors().GetInternalVector()) {
|
||||
runtimeBehaviorPropertyMethodsCode +=
|
||||
GenerateRuntimeBehaviorPropertyTemplateCode(
|
||||
eventsBasedBehavior, *property);
|
||||
}
|
||||
|
||||
return runtimeBehaviorPropertyMethodsCode;
|
||||
},
|
||||
// TODO: Update code generation to be able to generate methods (which would allow
|
||||
// for a cleaner output, not having to add methods to the prototype).
|
||||
[&]() {
|
||||
gd::String runtimeBehaviorMethodsCode;
|
||||
for (auto& eventsFunction : eventsFunctionsVector) {
|
||||
const gd::String& functionName =
|
||||
behaviorMethodMangledNames.find(eventsFunction->GetName()) !=
|
||||
behaviorMethodMangledNames.end()
|
||||
? behaviorMethodMangledNames.find(eventsFunction->GetName())
|
||||
->second
|
||||
: "UNKNOWN_FUNCTION_fix_behaviorMethodMangledNames_please";
|
||||
gd::String methodCodeNamespace =
|
||||
codeNamespace + "." + eventsBasedBehavior.GetName() +
|
||||
".prototype." + functionName + "Context";
|
||||
gd::String methodFullyQualifiedName = codeNamespace + "." +
|
||||
eventsBasedBehavior.GetName() +
|
||||
".prototype." + functionName;
|
||||
runtimeBehaviorMethodsCode +=
|
||||
EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
project,
|
||||
eventsBasedBehavior,
|
||||
*eventsFunction,
|
||||
methodCodeNamespace,
|
||||
methodFullyQualifiedName,
|
||||
"that._onceTriggers",
|
||||
functionName == doStepPreEventsFunctionName
|
||||
? GenerateDoStepPreEventsPreludeCode()
|
||||
: "",
|
||||
includeFiles,
|
||||
compilationForRuntime);
|
||||
|
||||
// Compatibility with GD <= 5.0 beta 75
|
||||
if (functionName == "onOwnerRemovedFromScene") {
|
||||
runtimeBehaviorMethodsCode +=
|
||||
GenerateBehaviorOnDestroyToDeprecatedOnOwnerRemovedFromScene(
|
||||
eventsBasedBehavior, codeNamespace);
|
||||
}
|
||||
// end of compatibility code
|
||||
}
|
||||
|
||||
bool hasDoStepPreEventsFunction =
|
||||
eventsBasedBehavior.GetEventsFunctions().HasEventsFunctionNamed(
|
||||
doStepPreEventsFunctionName);
|
||||
if (!hasDoStepPreEventsFunction) {
|
||||
runtimeBehaviorMethodsCode +=
|
||||
GenerateDefaultDoStepPreEventsFunctionCode(eventsBasedBehavior,
|
||||
codeNamespace);
|
||||
}
|
||||
|
||||
return runtimeBehaviorMethodsCode;
|
||||
},
|
||||
[&]() {
|
||||
gd::String updateFromBehaviorCode;
|
||||
for (auto& property :
|
||||
eventsBasedBehavior.GetPropertyDescriptors().GetInternalVector()) {
|
||||
updateFromBehaviorCode +=
|
||||
GenerateUpdatePropertyFromBehaviorDataCode(
|
||||
eventsBasedBehavior, *property);
|
||||
}
|
||||
|
||||
return updateFromBehaviorCode;
|
||||
});
|
||||
}
|
||||
|
||||
gd::String BehaviorCodeGenerator::GenerateRuntimeBehaviorTemplateCode(
|
||||
@@ -154,8 +119,6 @@ gd::String BehaviorCodeGenerator::GenerateRuntimeBehaviorTemplateCode(
|
||||
const gd::String& codeNamespace,
|
||||
std::function<gd::String()> generateInitializePropertiesCode,
|
||||
std::function<gd::String()> generatePropertiesCode,
|
||||
std::function<gd::String()> generateInitializeSharedPropertiesCode,
|
||||
std::function<gd::String()> generateSharedPropertiesCode,
|
||||
std::function<gd::String()> generateMethodsCode,
|
||||
std::function<gd::String()> generateUpdateFromBehaviorDataCode) {
|
||||
return gd::String(R"jscode_template(
|
||||
@@ -165,16 +128,12 @@ CODE_NAMESPACE = CODE_NAMESPACE || {};
|
||||
* Behavior generated from BEHAVIOR_FULL_NAME
|
||||
*/
|
||||
CODE_NAMESPACE.RUNTIME_BEHAVIOR_CLASSNAME = class RUNTIME_BEHAVIOR_CLASSNAME extends gdjs.RuntimeBehavior {
|
||||
constructor(instanceContainer, behaviorData, owner) {
|
||||
super(instanceContainer, behaviorData, owner);
|
||||
this._runtimeScene = instanceContainer;
|
||||
constructor(runtimeScene, behaviorData, owner) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
this._runtimeScene = runtimeScene;
|
||||
|
||||
this._onceTriggers = new gdjs.OnceTriggers();
|
||||
this._behaviorData = {};
|
||||
this._sharedData = CODE_NAMESPACE.RUNTIME_BEHAVIOR_CLASSNAME.getSharedData(
|
||||
instanceContainer,
|
||||
behaviorData.name
|
||||
);
|
||||
INITIALIZE_PROPERTIES_CODE
|
||||
}
|
||||
|
||||
@@ -189,30 +148,6 @@ CODE_NAMESPACE.RUNTIME_BEHAVIOR_CLASSNAME = class RUNTIME_BEHAVIOR_CLASSNAME ext
|
||||
PROPERTIES_CODE
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared data generated from BEHAVIOR_FULL_NAME
|
||||
*/
|
||||
CODE_NAMESPACE.RUNTIME_BEHAVIOR_CLASSNAME.SharedData = class RUNTIME_BEHAVIOR_CLASSNAMESharedData {
|
||||
constructor(sharedData) {
|
||||
INITIALIZE_SHARED_PROPERTIES_CODE
|
||||
}
|
||||
|
||||
// Shared properties:
|
||||
SHARED_PROPERTIES_CODE
|
||||
}
|
||||
|
||||
CODE_NAMESPACE.RUNTIME_BEHAVIOR_CLASSNAME.getSharedData = function(instanceContainer, behaviorName) {
|
||||
if (!instanceContainer._EXTENSION_NAME_RUNTIME_BEHAVIOR_CLASSNAMESharedData) {
|
||||
const initialData = instanceContainer.getInitialSharedDataForBehavior(
|
||||
behaviorName
|
||||
);
|
||||
instanceContainer._EXTENSION_NAME_RUNTIME_BEHAVIOR_CLASSNAMESharedData = new CODE_NAMESPACE.RUNTIME_BEHAVIOR_CLASSNAME.SharedData(
|
||||
initialData
|
||||
);
|
||||
}
|
||||
return instanceContainer._EXTENSION_NAME_RUNTIME_BEHAVIOR_CLASSNAMESharedData;
|
||||
}
|
||||
|
||||
// Methods:
|
||||
METHODS_CODE
|
||||
|
||||
@@ -224,13 +159,9 @@ gdjs.registerBehavior("EXTENSION_NAME::BEHAVIOR_NAME", CODE_NAMESPACE.RUNTIME_BE
|
||||
.FindAndReplace("RUNTIME_BEHAVIOR_CLASSNAME",
|
||||
eventsBasedBehavior.GetName())
|
||||
.FindAndReplace("CODE_NAMESPACE", codeNamespace)
|
||||
.FindAndReplace("INITIALIZE_SHARED_PROPERTIES_CODE",
|
||||
generateInitializeSharedPropertiesCode())
|
||||
.FindAndReplace("INITIALIZE_PROPERTIES_CODE",
|
||||
generateInitializePropertiesCode())
|
||||
.FindAndReplace("UPDATE_FROM_BEHAVIOR_DATA_CODE", generateUpdateFromBehaviorDataCode())
|
||||
// It must be done before PROPERTIES_CODE.
|
||||
.FindAndReplace("SHARED_PROPERTIES_CODE", generateSharedPropertiesCode())
|
||||
.FindAndReplace("PROPERTIES_CODE", generatePropertiesCode())
|
||||
.FindAndReplace("METHODS_CODE", generateMethodsCode());
|
||||
;
|
||||
@@ -243,15 +174,6 @@ gd::String BehaviorCodeGenerator::GenerateInitializePropertyFromDataCode(
|
||||
.FindAndReplace("PROPERTY_NAME", property.GetName())
|
||||
.FindAndReplace("DEFAULT_VALUE", GeneratePropertyValueCode(property));
|
||||
}
|
||||
|
||||
gd::String BehaviorCodeGenerator::GenerateInitializeSharedPropertyFromDataCode(
|
||||
const gd::NamedPropertyDescriptor& property) {
|
||||
return gd::String(R"jscode_template(
|
||||
this.PROPERTY_NAME = sharedData.PROPERTY_NAME !== undefined ? sharedData.PROPERTY_NAME : DEFAULT_VALUE;)jscode_template")
|
||||
.FindAndReplace("PROPERTY_NAME", property.GetName())
|
||||
.FindAndReplace("DEFAULT_VALUE", GeneratePropertyValueCode(property));
|
||||
}
|
||||
|
||||
gd::String
|
||||
BehaviorCodeGenerator::GenerateInitializePropertyFromDefaultValueCode(
|
||||
const gd::NamedPropertyDescriptor& property) {
|
||||
@@ -261,15 +183,6 @@ BehaviorCodeGenerator::GenerateInitializePropertyFromDefaultValueCode(
|
||||
.FindAndReplace("DEFAULT_VALUE", GeneratePropertyValueCode(property));
|
||||
}
|
||||
|
||||
gd::String
|
||||
BehaviorCodeGenerator::GenerateInitializeSharedPropertyFromDefaultValueCode(
|
||||
const gd::NamedPropertyDescriptor& property) {
|
||||
return gd::String(R"jscode_template(
|
||||
this.PROPERTY_NAME = DEFAULT_VALUE;)jscode_template")
|
||||
.FindAndReplace("PROPERTY_NAME", property.GetName())
|
||||
.FindAndReplace("DEFAULT_VALUE", GeneratePropertyValueCode(property));
|
||||
}
|
||||
|
||||
gd::String BehaviorCodeGenerator::GenerateRuntimeBehaviorPropertyTemplateCode(
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::NamedPropertyDescriptor& property) {
|
||||
@@ -290,26 +203,6 @@ gd::String BehaviorCodeGenerator::GenerateRuntimeBehaviorPropertyTemplateCode(
|
||||
eventsBasedBehavior.GetName());
|
||||
}
|
||||
|
||||
gd::String BehaviorCodeGenerator::GenerateRuntimeBehaviorSharedPropertyTemplateCode(
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::NamedPropertyDescriptor& property) {
|
||||
return gd::String(R"jscode_template(
|
||||
GETTER_NAME() {
|
||||
return this.PROPERTY_NAME !== undefined ? this.PROPERTY_NAME : DEFAULT_VALUE;
|
||||
}
|
||||
SETTER_NAME(newValue) {
|
||||
this.PROPERTY_NAME = newValue;
|
||||
})jscode_template")
|
||||
.FindAndReplace("PROPERTY_NAME", property.GetName())
|
||||
.FindAndReplace("GETTER_NAME",
|
||||
GetBehaviorSharedPropertyGetterInternalName(property.GetName()))
|
||||
.FindAndReplace("SETTER_NAME",
|
||||
GetBehaviorSharedPropertySetterInternalName(property.GetName()))
|
||||
.FindAndReplace("DEFAULT_VALUE", GeneratePropertyValueCode(property))
|
||||
.FindAndReplace("RUNTIME_BEHAVIOR_CLASSNAME",
|
||||
eventsBasedBehavior.GetName());
|
||||
}
|
||||
|
||||
gd::String BehaviorCodeGenerator::GenerateUpdatePropertyFromBehaviorDataCode(
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::NamedPropertyDescriptor& property) {
|
||||
@@ -370,23 +263,4 @@ gd::String BehaviorCodeGenerator::GenerateDoStepPreEventsPreludeCode() {
|
||||
return "this._onceTriggers.startNewFrame();";
|
||||
}
|
||||
|
||||
gd::String BehaviorCodeGenerator::GetBehaviorSharedPropertyGetterName(
|
||||
const gd::String& propertyName) {
|
||||
return "_sharedData." + GetBehaviorSharedPropertyGetterInternalName(propertyName);
|
||||
}
|
||||
|
||||
gd::String BehaviorCodeGenerator::GetBehaviorSharedPropertySetterName(
|
||||
const gd::String& propertyName) {
|
||||
return "_sharedData." + GetBehaviorSharedPropertySetterInternalName(propertyName);
|
||||
}
|
||||
|
||||
gd::String BehaviorCodeGenerator::GetBehaviorSharedPropertyGetterInternalName(
|
||||
const gd::String& propertyName) {
|
||||
return "_get" + propertyName;
|
||||
}
|
||||
|
||||
gd::String BehaviorCodeGenerator::GetBehaviorSharedPropertySetterInternalName(
|
||||
const gd::String& propertyName) {
|
||||
return "_set" + propertyName;
|
||||
}
|
||||
} // namespace gdjs
|
||||
|
@@ -57,79 +57,32 @@ class BehaviorCodeGenerator {
|
||||
return "_set" + propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Generate the name of the method to get the value of the shared property
|
||||
* of a behavior.
|
||||
*/
|
||||
static gd::String GetBehaviorSharedPropertyGetterName(
|
||||
const gd::String& propertyName);
|
||||
|
||||
/**
|
||||
* \brief Generate the name of the method to set the value of the shared property
|
||||
* of a behavior.
|
||||
*/
|
||||
static gd::String GetBehaviorSharedPropertySetterName(
|
||||
const gd::String& propertyName);
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief Generate the name of the method to get the value of the shared property
|
||||
* of a behavior form within the shared data class.
|
||||
*/
|
||||
static gd::String GetBehaviorSharedPropertyGetterInternalName(
|
||||
const gd::String& propertyName);
|
||||
|
||||
/**
|
||||
* \brief Generate the name of the method to set the value of the shared property
|
||||
* of a behavior form within the shared data class.
|
||||
*/
|
||||
static gd::String GetBehaviorSharedPropertySetterInternalName(
|
||||
const gd::String& propertyName);
|
||||
|
||||
gd::String GenerateRuntimeBehaviorTemplateCode(
|
||||
const gd::String& extensionName,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::String& codeNamespace,
|
||||
std::function<gd::String()> generateInitializePropertiesCode,
|
||||
std::function<gd::String()> generatePropertiesCode,
|
||||
std::function<gd::String()> generateInitializeSharedPropertiesCode,
|
||||
std::function<gd::String()> generateSharedPropertiesCode,
|
||||
std::function<gd::String()> generateMethodsCode,
|
||||
std::function<gd::String()> generatePropertiesCode,
|
||||
std::function<gd::String()> generateUpdateFromBehaviorDataCode);
|
||||
|
||||
gd::String GenerateRuntimeBehaviorPropertyTemplateCode(
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::NamedPropertyDescriptor& property);
|
||||
|
||||
gd::String GenerateInitializePropertyFromDataCode(
|
||||
const gd::NamedPropertyDescriptor& property);
|
||||
|
||||
gd::String GenerateInitializePropertyFromDefaultValueCode(
|
||||
const gd::NamedPropertyDescriptor& property);
|
||||
|
||||
gd::String GenerateRuntimeBehaviorSharedPropertyTemplateCode(
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::NamedPropertyDescriptor& property);
|
||||
|
||||
gd::String GenerateInitializeSharedPropertyFromDataCode(
|
||||
const gd::NamedPropertyDescriptor& property);
|
||||
|
||||
gd::String GenerateInitializeSharedPropertyFromDefaultValueCode(
|
||||
const gd::NamedPropertyDescriptor& property);
|
||||
|
||||
gd::String GeneratePropertyValueCode(const gd::PropertyDescriptor& property);
|
||||
gd::String GenerateUpdatePropertyFromBehaviorDataCode(
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::NamedPropertyDescriptor& property);
|
||||
|
||||
gd::String GenerateBehaviorOnDestroyToDeprecatedOnOwnerRemovedFromScene(
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::String& codeNamespace);
|
||||
|
||||
gd::String GenerateDefaultDoStepPreEventsFunctionCode(
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::String& codeNamespace);
|
||||
|
||||
gd::String GenerateDoStepPreEventsPreludeCode();
|
||||
|
||||
gd::Project& project;
|
||||
|
@@ -121,62 +121,6 @@ AdvancedExtension::AdvancedExtension() {
|
||||
"eventsFunctionContext.getArgument(" +
|
||||
parameterNameCode + ") : \"\")";
|
||||
});
|
||||
|
||||
GetAllConditions()["CompareArgumentAsNumber"]
|
||||
.GetCodeExtraInformation()
|
||||
.SetCustomCodeGenerator([](gd::Instruction &instruction,
|
||||
gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
gd::String parameterNameCode =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "string",
|
||||
instruction.GetParameter(0).GetPlainString());
|
||||
|
||||
gd::String operatorCode = codeGenerator.GenerateRelationalOperatorCodes(
|
||||
instruction.GetParameter(1).GetPlainString());
|
||||
|
||||
gd::String operandCode =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "number",
|
||||
instruction.GetParameter(2).GetPlainString());
|
||||
|
||||
gd::String resultingBoolean =
|
||||
codeGenerator.GenerateBooleanFullName("conditionTrue", context) +
|
||||
".val";
|
||||
|
||||
return resultingBoolean + " = ((typeof eventsFunctionContext !== 'undefined' ? "
|
||||
"Number(eventsFunctionContext.getArgument(" +
|
||||
parameterNameCode + ")) || 0 : 0) " + operatorCode + " " +
|
||||
operandCode + ");\n";
|
||||
});
|
||||
|
||||
GetAllConditions()["CompareArgumentAsString"]
|
||||
.GetCodeExtraInformation()
|
||||
.SetCustomCodeGenerator([](gd::Instruction &instruction,
|
||||
gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
gd::String parameterNameCode =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "string",
|
||||
instruction.GetParameter(0).GetPlainString());
|
||||
|
||||
gd::String operatorCode = codeGenerator.GenerateRelationalOperatorCodes(
|
||||
instruction.GetParameter(1).GetPlainString());
|
||||
|
||||
gd::String operandCode =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "string",
|
||||
instruction.GetParameter(2).GetPlainString());
|
||||
|
||||
gd::String resultingBoolean =
|
||||
codeGenerator.GenerateBooleanFullName("conditionTrue", context) +
|
||||
".val";
|
||||
|
||||
return resultingBoolean + " = ((typeof eventsFunctionContext !== 'undefined' ? "
|
||||
"\"\" + eventsFunctionContext.getArgument(" +
|
||||
parameterNameCode + ") : \"\") " + operatorCode + " " +
|
||||
operandCode + ");\n";
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace gdjs
|
||||
} // namespace gdjs
|
||||
|
@@ -55,24 +55,40 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
codeGenerator,
|
||||
context,
|
||||
"number",
|
||||
instruction.GetParameter(0).GetPlainString());
|
||||
|
||||
gd::String operatorCode = codeGenerator.GenerateRelationalOperatorCodes(
|
||||
instruction.GetParameter(1).GetPlainString());
|
||||
instruction.GetParameters()[0].GetPlainString());
|
||||
|
||||
gd::String value2Code =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"number",
|
||||
instruction.GetParameter(2).GetPlainString());
|
||||
instruction.GetParameters()[2].GetPlainString());
|
||||
|
||||
gd::String resultingBoolean =
|
||||
codeGenerator.GenerateBooleanFullName("conditionTrue", context) +
|
||||
".val";
|
||||
|
||||
return resultingBoolean + " = (" + value1Code + " " + operatorCode +
|
||||
" " + value2Code + ");\n";
|
||||
if (instruction.GetParameters()[1].GetPlainString() == "=" ||
|
||||
instruction.GetParameters()[1].GetPlainString().empty())
|
||||
return resultingBoolean + " = (" + value1Code + " == " + value2Code +
|
||||
");\n";
|
||||
else if (instruction.GetParameters()[1].GetPlainString() == ">")
|
||||
return resultingBoolean + " = (" + value1Code + " > " + value2Code +
|
||||
");\n";
|
||||
else if (instruction.GetParameters()[1].GetPlainString() == "<")
|
||||
return resultingBoolean + " = (" + value1Code + " < " + value2Code +
|
||||
");\n";
|
||||
else if (instruction.GetParameters()[1].GetPlainString() == "<=")
|
||||
return resultingBoolean + " = (" + value1Code + " <= " + value2Code +
|
||||
");\n";
|
||||
else if (instruction.GetParameters()[1].GetPlainString() == ">=")
|
||||
return resultingBoolean + " = (" + value1Code + " >= " + value2Code +
|
||||
");\n";
|
||||
else if (instruction.GetParameters()[1].GetPlainString() == "!=")
|
||||
return resultingBoolean + " = (" + value1Code + " != " + value2Code +
|
||||
");\n";
|
||||
|
||||
return gd::String("");
|
||||
});
|
||||
GetAllConditions()["BuiltinCommonInstructions::CompareNumbers"]
|
||||
.codeExtraInformation = GetAllConditions()["Egal"].codeExtraInformation;
|
||||
@@ -86,24 +102,27 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
codeGenerator,
|
||||
context,
|
||||
"string",
|
||||
instruction.GetParameter(0).GetPlainString());
|
||||
|
||||
gd::String operatorCode = codeGenerator.GenerateRelationalOperatorCodes(
|
||||
instruction.GetParameter(1).GetPlainString());
|
||||
instruction.GetParameters()[0].GetPlainString());
|
||||
|
||||
gd::String value2Code =
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"string",
|
||||
instruction.GetParameter(2).GetPlainString());
|
||||
instruction.GetParameters()[2].GetPlainString());
|
||||
|
||||
gd::String resultingBoolean =
|
||||
codeGenerator.GenerateBooleanFullName("conditionTrue", context) +
|
||||
".val";
|
||||
|
||||
return resultingBoolean + " = (" + value1Code + " " + operatorCode +
|
||||
" " + value2Code + ");\n";
|
||||
if (instruction.GetParameters()[1].GetPlainString() == "=")
|
||||
return resultingBoolean + " = (" + value1Code + " == " + value2Code +
|
||||
");\n";
|
||||
else if (instruction.GetParameters()[1].GetPlainString() == "!=")
|
||||
return resultingBoolean + " = (" + value1Code + " != " + value2Code +
|
||||
");\n";
|
||||
|
||||
return gd::String("");
|
||||
});
|
||||
GetAllConditions()["BuiltinCommonInstructions::CompareStrings"]
|
||||
.codeExtraInformation =
|
||||
|
@@ -71,7 +71,6 @@ MathematicalToolsExtension::MathematicalToolsExtension() {
|
||||
GetAllExpressions()["XFromAngleAndDistance"].SetFunctionName("gdjs.evtTools.common.getXFromAngleAndDistance");
|
||||
GetAllExpressions()["YFromAngleAndDistance"].SetFunctionName("gdjs.evtTools.common.getYFromAngleAndDistance");
|
||||
GetAllExpressions()["Pi"].SetFunctionName("gdjs.evtTools.common.pi");
|
||||
GetAllExpressions()["lerpAngle"].SetFunctionName("gdjs.evtTools.common.lerpAngle");
|
||||
|
||||
StripUnimplementedInstructionsAndExpressions();
|
||||
}
|
||||
|
@@ -46,7 +46,6 @@ SpriteExtension::SpriteExtension() {
|
||||
spriteConditions["Direction"].SetFunctionName("getDirectionOrAngle");
|
||||
spriteConditions["Sprite"].SetFunctionName("getAnimationFrame");
|
||||
spriteConditions["AnimationEnded"].SetFunctionName("hasAnimationEnded");
|
||||
spriteConditions["AnimationEnded2"].SetFunctionName("hasAnimationEnded2");
|
||||
spriteActions["PauseAnimation"].SetFunctionName("pauseAnimation");
|
||||
spriteActions["PlayAnimation"].SetFunctionName("playAnimation");
|
||||
spriteConditions["AnimStopped"].SetFunctionName("animationPaused");
|
||||
|
@@ -265,6 +265,7 @@ namespace gdjs {
|
||||
cy *= absScaleY;
|
||||
|
||||
// Rotation
|
||||
const oldX = x;
|
||||
const angleInRadians = (this.angle / 180) * Math.PI;
|
||||
const cosValue = Math.cos(angleInRadians);
|
||||
const sinValue = Math.sin(angleInRadians);
|
||||
|
@@ -5,6 +5,9 @@
|
||||
*/
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('CustomRuntimeObject');
|
||||
const setupWarningLogger = new gdjs.Logger(
|
||||
'CustomRuntimeObject (setup warnings)'
|
||||
);
|
||||
|
||||
/**
|
||||
* The instance container of a custom object, containing instances of objects rendered on screen.
|
||||
@@ -197,8 +200,12 @@ namespace gdjs {
|
||||
*/
|
||||
_updateObjectsPreRender() {
|
||||
const allInstancesList = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
|
||||
const object = allInstancesList[i];
|
||||
for (
|
||||
let i = 0, len = this.getAdhocListOfAllInstances().length;
|
||||
i < len;
|
||||
++i
|
||||
) {
|
||||
const object = this.getAdhocListOfAllInstances()[i];
|
||||
const rendererObject = object.getRendererObject();
|
||||
if (rendererObject) {
|
||||
rendererObject.visible = !object.isHidden();
|
||||
@@ -215,7 +222,7 @@ namespace gdjs {
|
||||
// to see what is rendered).
|
||||
if (this._debugDrawEnabled) {
|
||||
this._debuggerRenderer.renderDebugDraw(
|
||||
allInstancesList,
|
||||
this.getAdhocListOfAllInstances(),
|
||||
this._debugDrawShowHiddenInstances,
|
||||
this._debugDrawShowPointsNames,
|
||||
this._debugDrawShowCustomPoints
|
||||
|
@@ -5,13 +5,14 @@
|
||||
*/
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('RuntimeInstanceContainer');
|
||||
const setupWarningLogger = new gdjs.Logger(
|
||||
'RuntimeInstanceContainer (setup warnings)'
|
||||
);
|
||||
|
||||
/**
|
||||
* A container of object instances rendered on screen.
|
||||
*/
|
||||
export abstract class RuntimeInstanceContainer {
|
||||
_initialBehaviorSharedData: Hashtable<BehaviorSharedData | null>;
|
||||
|
||||
/** Contains the instances living on the container */
|
||||
_instances: Hashtable<RuntimeObject[]>;
|
||||
|
||||
@@ -42,7 +43,6 @@ namespace gdjs {
|
||||
_debugDrawShowCustomPoints: boolean = false;
|
||||
|
||||
constructor() {
|
||||
this._initialBehaviorSharedData = new Hashtable();
|
||||
this._instances = new Hashtable();
|
||||
this._instancesCache = new Hashtable();
|
||||
this._objects = new Hashtable();
|
||||
@@ -266,32 +266,6 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data representing the initial shared data of the scene for the specified behavior.
|
||||
* @param name The name of the behavior
|
||||
* @returns The shared data for the behavior, if any.
|
||||
*/
|
||||
getInitialSharedDataForBehavior(name: string): BehaviorSharedData | null {
|
||||
const behaviorSharedData = this._initialBehaviorSharedData.get(name);
|
||||
if (behaviorSharedData) {
|
||||
return behaviorSharedData;
|
||||
}
|
||||
logger.error("Can't find shared data for behavior with name: " + name);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the data representing the initial shared data of the scene for the specified behavior.
|
||||
* @param name The name of the behavior
|
||||
* @param sharedData The shared data for the behavior, or null to remove it.
|
||||
*/
|
||||
setInitialSharedDataForBehavior(
|
||||
name: string,
|
||||
sharedData: BehaviorSharedData | null
|
||||
): void {
|
||||
this._initialBehaviorSharedData.put(name, sharedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default Z order for each layer, which is the highest Z order found on each layer.
|
||||
* Useful as it ensures that instances created from events are, by default, shown in front
|
||||
|
@@ -408,30 +408,6 @@ namespace gdjs {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback called when the game is paused.
|
||||
*/
|
||||
sendGamePaused(): void {
|
||||
this._sendMessage(
|
||||
circularSafeStringify({
|
||||
command: 'game.paused',
|
||||
payload: null,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback called when the game is resumed.
|
||||
*/
|
||||
sendGameResumed(): void {
|
||||
this._sendMessage(
|
||||
circularSafeStringify({
|
||||
command: 'game.resumed',
|
||||
payload: null,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send profiling results.
|
||||
* @param framesAverageMeasures The measures made for each frames.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user