Compare commits

...

73 Commits

Author SHA1 Message Date
AlexandreSi
1952705a0a Update fling game tutorial 2022-12-12 11:55:21 +01:00
AlexandreSi
193f90f467 Try catch local file reading 2022-12-12 11:53:28 +01:00
AlexandreSi
c3df2603bb Fix typo 2022-12-12 11:41:56 +01:00
Clément Pasteau
d53eed8db8 Rename variables 2022-12-08 17:24:02 +01:00
Clément Pasteau
873c9f7700 Add in app tutorials to extra resources 2022-12-08 17:15:29 +01:00
Clément Pasteau
0d426615cf Add current version of in-app-tutorials and logic to load them on desktop release 2022-12-08 16:57:09 +01:00
Clément Pasteau
a22a96152b Add D8H to core contributors for changelog extract 2022-12-08 16:51:17 +01:00
Clément Pasteau
ea0d201868 Remove outdated examples from electron app 2022-12-08 16:09:49 +01:00
Florian Rival
c596335b7b Add some space to drag the titlebar even if a lot of tabs are opened
Don't show in changelog
2022-12-08 11:21:00 +01:00
github-actions[bot]
a9b42de64b Update translations [skip ci] (#4639)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2022-12-08 10:40:17 +01:00
AlexandreS
64ea3461d0 Make autocomplete dropdowns more visible (#4634)
Do not show in changelog
2022-12-08 09:34:25 +01:00
Florian Rival
cef473ca0e Update GitHub screenshot [skip ci]
Don't show in changelog
2022-12-07 18:12:14 +01:00
github-actions[bot]
9378b325d0 Update translations [skip ci] (#4635)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2022-12-07 17:56:45 +01:00
Clément Pasteau
238043655c Send gdevelopVersion for in-app-tutorials (#4636)
Do not show in changelog
2022-12-07 17:39:52 +01:00
Florian Rival
731a64aa0f Redesign the top tabs and toolbars in the app, so the app looks modern and takes less space on the top of the screens (#4630)
* On desktop, the titlebar is now gone and replaced by the tabs and a button to open the main menu of the app.
* On the web-app, if installed (available on Chrome and Edge), the titlebar can also be retracted. Whatever your system or device, the menu can be accessed from the top left.
* The top toolbars have been entirely redesigned to be integrated below the tabs - which is more intuitive for new users. All the icons have been reworked to be cleaner, take less space, and be more modern.
* The debugger toolbar was also improved to display just Play/Pause according to the game state.
* Finally, the project manager was slightly redesigned to use new icons.
2022-12-07 17:22:38 +01:00
github-actions[bot]
e1e7344ca5 Update translations [skip ci] (#4617)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2022-12-07 17:04:51 +01:00
Clément Pasteau
a5d5f0b7a5 Fix allowing to type "/" inside the path for project folder (#4633)
Do not show in changelog
2022-12-07 16:49:02 +01:00
Clément Pasteau
3dcbe46fc7 Improve warning when a project autosave is detected on Desktop (#4632)
* Autosave will not be displayed if the files are the same
* Prevent showing a warning when a project with an autosave is opened after being zipped
* Improve overall wording and dialogs
2022-12-07 16:46:38 +01:00
Florian Rival
4d3d96a889 Fix SemiControlledAutoComplete not using the value entered when pressing Enter in a InlineParameterEditor
Don't show in changelog
2022-12-07 12:03:10 +01:00
Clément Pasteau
23631cc2ce Allow entering a donation link on the user profile (#4628)
* Accepts any type of donation page, Ko-fi, Patreon, Paypal, Github...
* Once entered, it will appear on your Liluo.io Game and Profile pages
2022-12-06 17:21:34 +01:00
AlexandreS
3937b59d73 Use same border radius between command palette and autocomplete picker (#4629)
Do not show in changelog
2022-12-06 11:44:54 +01:00
Florian Rival
3b594ded7d Add Enter as a key to validate changes to a parameter in an event sheet (#4621)
* Shift+Enter can be used to enter new lines in expressions when editing a parameter inline
2022-12-06 10:37:55 +01:00
AlexandreS
e8a7cad17c Restore possibility to search texts with parenthesis in events parameters (#4625) 2022-12-06 10:30:18 +01:00
Clément Pasteau
2557cf556c Allow leaderboard color customisation (#4612)
* Silver and Gold subscribers can now customize their leaderboard with 4 different colors
2022-12-05 18:05:37 +01:00
AlexandreS
7c51f0af81 Add link to asset store license + Add message when no projects in the list (#4624)
Do not show in changelog
2022-12-05 16:56:41 +01:00
D8H
dc146a7411 Add a command to generate an action and an expression for a custom object property (#4620)
* Don't show in changelog
2022-12-04 20:27:17 +01:00
D8H
7620bac88a Enable serialization of JS code events and extension descriptions as arrays of strings (#4613)
* Only show in developer changelog
2022-12-04 13:38:08 +01:00
AlexandreS
c51e4be22d Display password prompt when requesting checkout session for asset pack (#4616)
Do not show in changelog
2022-12-02 18:17:38 +01:00
github-actions[bot]
98499dfc53 Update translations [skip ci] (#4610)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2022-12-02 12:17:48 +01:00
AlexandreS
36de82c93f Few fixes (#4611)
Do not show in changelog
2022-12-02 11:55:43 +01:00
Daniel R
7e97edcad0 Add a new tab "Folders" in Preferences to allow to choose the default folder where local projects are created (#4582) 2022-12-02 11:50:58 +01:00
D8H
5abb0fd9e3 Fix boolean property condition sentences (#4605) 2022-12-02 11:45:13 +01:00
D8H
d80c21244f Boolean property generated actions no longer miss the "Value" parameter (#4594) 2022-12-02 11:44:17 +01:00
D8H
70f4d545b4 Display some behavior properties in one row (#4606) 2022-12-02 11:37:32 +01:00
github-actions[bot]
85355c3f17 Update translations [skip ci] (#4609)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2022-12-01 17:27:19 +01:00
github-actions[bot]
044cc5354f Update translations [skip ci] (#4607)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2022-12-01 17:11:46 +01:00
AlexandreS
5ff02b11fc Fix a few MUI component imports (#4608)
Do not show in changelog
2022-12-01 17:05:23 +01:00
github-actions[bot]
9bf24f9baf Update translations [skip ci] (#4604)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2022-12-01 16:30:12 +01:00
AlexandreS
958482ee44 Suggest a new and more complete 3-chapter in-app tutorial (#4476) 2022-12-01 16:18:42 +01:00
AlexandreS
7a1fb5b033 Improve loading of Home Build section to reduce layout shifts (#4603) 2022-12-01 11:28:49 +01:00
D8H
33b2fb0168 Show unit of measurements on properties of built-in extensions (#4576) 2022-11-30 21:18:54 +01:00
Clément Pasteau
5cad2be194 Improve Toggle styling (#4602) 2022-11-30 15:23:43 +01:00
Clément Pasteau
2b38aa5445 Simplify assets loading to prevent unnecessary calls (#4601)
Do not show in changelog
2022-11-30 14:26:38 +01:00
D8H
32279f02e9 Fix function name collision between event-based objects from the same extension (#4598) 2022-11-30 14:10:52 +01:00
Clément Pasteau
7452358656 Trigger Rename & Focus for Object, Group, Layout, Events (#4591) 2022-11-30 10:52:15 +01:00
D8H
d2ec483d71 Changing custom object opacity now works (#4597) 2022-11-29 10:43:17 +01:00
github-actions[bot]
4cb62d15bf Update translations [skip ci] (#4589)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2022-11-28 15:53:08 +01:00
AlexandreS
96bdbfc70b Correctly deactivate cloud projects on desktop app in prod (#4592)
Do not show in changelog
2022-11-28 15:47:55 +01:00
Clément Pasteau
a64815f500 Fix missing text formatting (#4587)
Do not show in changelog
2022-11-28 15:47:39 +01:00
Clément Pasteau
5ab8a3cd73 Improve initial dialog logic to avoid opening tab on subsequent profile openings. (#4590)
Do not show in changelog
2022-11-28 15:45:12 +01:00
D8H
7d0ecf113a Add a command to generate an action and an expression for a property (#4565) 2022-11-28 14:30:03 +01:00
D8H
de30049182 Show parameters description in expression documentations (#4585) 2022-11-28 13:19:42 +01:00
Clément Pasteau
c2a1fb63e1 Fix opening initial dialog again after closing it (#4588) 2022-11-28 12:34:22 +01:00
github-actions[bot]
8562019953 Update translations [skip ci] (#4572)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2022-11-28 10:34:59 +01:00
Florian Rival
f8232953b5 Add support for cloud projects to the desktop app (#4240)
* Also add support for the asset store in the objects editors - like on the web-app.
2022-11-27 18:09:27 +01:00
AlexandreS
d52ac6fc3e Send subscription dialog opening reason (#4586)
Do not show in changelog
2022-11-25 18:12:03 +01:00
Clément Pasteau
be4aab6d5c Allow opening up the feedback tab from URL query params (#4574)
Do not show in changelog
2022-11-25 17:18:32 +01:00
Clément Pasteau
4ed8ff15dd Improve Asset pack install dialog (#4583)
Do not show in changelog
2022-11-25 11:33:00 +01:00
Clément Pasteau
2dd1105a10 Improve Game Feedback management (#4579)
* Display the average game ratings at the top
* Add an option to mark all as read
* improve readability by adding a number for each rating
2022-11-25 10:12:11 +01:00
Clément Pasteau
0fce6aaaaa Fix missing scroll on points and collision mask editors (#4578) 2022-11-24 15:51:22 +01:00
Florian Rival
29797b7a2f Add analytics data when opening an asset pack or an asset (#4573)
Don't show in changelog
2022-11-24 09:41:24 +01:00
Clément Pasteau
7df7f9f458 Remove help button on additional info dialog (#4570)
Do not show in changelog
2022-11-23 15:20:52 +01:00
github-actions[bot]
fc61fa2c54 Update translations [skip ci] (#4571)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2022-11-23 15:20:36 +01:00
D8H
fccd3b8f2e Fix the drag and drop of the extension editor. (#4568)
* Items were not drop at the right position when they were moved down.
2022-11-23 15:08:33 +01:00
github-actions[bot]
5ca91cfac4 Update translations [skip ci] (#4569)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2022-11-23 15:08:17 +01:00
Clément Pasteau
628d18ac5a Improve login and signup flow (#4566)
* Small design improvements to the Log in & Sign up flows
* A dialog is now shown for every user on signup to gather a bit of information about who they are.
  * This information stays of course private and is helpful to gather information about GDevelop's usage
2022-11-23 14:58:17 +01:00
github-actions[bot]
61d5c08549 Update translations [skip ci] (#4555)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2022-11-23 14:54:05 +01:00
Clément Pasteau
34497c2783 Fix cleaning the resource URL when added from the resource store (#4567)
Do not show in changelog
2022-11-22 19:11:18 +01:00
Clément Pasteau
4627facfd5 Improve Searchbar's design and usability (#4553) 2022-11-21 16:16:07 +01:00
D8H
aee15424f2 Save the scroll position of the asset store (#4528) 2022-11-18 17:06:10 +01:00
D8H
6c44f6e937 Physics2 behavior no longer step before the first frame (#4559)
* It allows events to access to the initial object positions.
2022-11-18 17:05:28 +01:00
Clément Pasteau
a115df260f Revert time before showing warning in object edition (#4558)
Do not show in changelog
2022-11-18 10:24:56 +01:00
Clément Pasteau
6e7bc9c809 Improve the snackbar messages when saving a cloud project (#4554) 2022-11-16 16:42:23 +01:00
1423 changed files with 24208 additions and 90082 deletions

View File

@@ -55,6 +55,10 @@ 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 =

View File

@@ -123,6 +123,11 @@ 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
*/

View File

@@ -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

View File

@@ -46,4 +46,25 @@ 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

View File

@@ -192,6 +192,12 @@ 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
*/
///@{
@@ -212,6 +218,12 @@ 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

View File

@@ -24,14 +24,12 @@
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,
@@ -41,7 +39,6 @@ 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,
@@ -53,7 +50,6 @@ gd::InstructionMetadata& PlatformExtension::AddCondition(
smallicon)
.SetHelpPath(GetHelpPath());
return conditionsInfos[nameWithNamespace];
#endif
}
gd::InstructionMetadata& PlatformExtension::AddAction(
@@ -64,7 +60,6 @@ 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,
@@ -76,7 +71,6 @@ gd::InstructionMetadata& PlatformExtension::AddAction(
smallicon)
.SetHelpPath(GetHelpPath());
return actionsInfos[nameWithNamespace];
#endif
}
gd::ExpressionMetadata& PlatformExtension::AddExpression(
@@ -85,7 +79,6 @@ 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(),
@@ -96,7 +89,6 @@ gd::ExpressionMetadata& PlatformExtension::AddExpression(
smallicon)
.SetHelpPath(GetHelpPath());
return expressionsInfos[nameWithNamespace];
#endif
}
gd::ExpressionMetadata& PlatformExtension::AddStrExpression(
@@ -105,7 +97,6 @@ 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(),
@@ -116,7 +107,6 @@ gd::ExpressionMetadata& PlatformExtension::AddStrExpression(
smallicon)
.SetHelpPath(GetHelpPath());
return strExpressionsInfos[nameWithNamespace];
#endif
}
gd::MultipleInstructionMetadata PlatformExtension::AddExpressionAndCondition(
@@ -220,12 +210,10 @@ 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,
@@ -317,7 +305,6 @@ 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_,
@@ -326,7 +313,6 @@ gd::EventMetadata& PlatformExtension::AddEvent(
smallicon_,
instance_);
return eventsInfos[nameWithNamespace];
#endif
}
PlatformExtension& PlatformExtension::SetExtensionInformation(
@@ -406,8 +392,6 @@ 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;
@@ -586,7 +570,6 @@ gd::BaseEventSPtr PlatformExtension::CreateEvent(
return std::shared_ptr<gd::BaseEvent>();
}
#endif
CreateFunPtr PlatformExtension::GetObjectCreationFunctionPtr(
const gd::String& objectType) const {
@@ -665,7 +648,6 @@ 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();
@@ -810,7 +792,40 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
++it;
}
}
#endif
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;
}
PlatformExtension::PlatformExtension()
: deprecated(false), category(_("General")) {}

View File

@@ -620,7 +620,26 @@ class GD_CORE_API PlatformExtension {
*/
static gd::String GetNamespaceSeparator() { return "::"; }
private:
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:
/**
* Set the namespace (the string all actions/conditions/expressions start
* with).

View File

@@ -773,15 +773,18 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
const gd::String& ignored_characters =
EventsRefactorer::searchIgnoredCharacters;
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(), ' ');
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(), ' ');
}
for (std::size_t i = 0; i < events.size(); ++i) {
bool eventAddedInResults = false;

View File

@@ -0,0 +1,301 @@
/*
* 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

View File

@@ -0,0 +1,65 @@
/*
* 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

View File

@@ -35,40 +35,6 @@
#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
@@ -252,7 +218,7 @@ WholeProjectRefactorer::GetAllObjectTypesUsingEventsBasedBehavior(
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::EventsBasedBehavior& eventsBasedBehavior) {
std::set<gd::String> allTypes;
const gd::String behaviorType = GetBehaviorFullType(
const gd::String behaviorType = gd::PlatformExtension::GetBehaviorFullType(
eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName());
auto addTypesOfObjectsIn =
@@ -295,7 +261,7 @@ void WholeProjectRefactorer::EnsureBehaviorEventsFunctionsProperParameters(
.SetType("behavior")
.SetName("Behavior")
.SetDescription("Behavior")
.SetExtraInfo(GetBehaviorFullType(eventsFunctionsExtension.GetName(),
.SetExtraInfo(gd::PlatformExtension::GetBehaviorFullType(eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName()));
}
}
@@ -315,7 +281,7 @@ void WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
.SetType("object")
.SetName(parentObjectParameterName)
.SetDescription("Object")
.SetExtraInfo(GetObjectFullType(eventsFunctionsExtension.GetName(),
.SetExtraInfo(gd::PlatformExtension::GetObjectFullType(eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName()));
}
}
@@ -330,8 +296,8 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
DoRenameEventsFunction(
project,
eventsFunction,
GetEventsFunctionFullType(oldName, eventsFunction.GetName()),
GetEventsFunctionFullType(newName, eventsFunction.GetName()));
gd::PlatformExtension::GetEventsFunctionFullType(oldName, eventsFunction.GetName()),
gd::PlatformExtension::GetEventsFunctionFullType(newName, eventsFunction.GetName()));
};
auto renameBehaviorEventsFunction =
@@ -344,10 +310,10 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(oldName,
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(oldName,
eventsBasedBehavior.GetName(),
eventsFunction.GetName()),
GetBehaviorEventsFunctionFullType(newName,
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(newName,
eventsBasedBehavior.GetName(),
eventsFunction.GetName()));
ExposeProjectEvents(project, renamer);
@@ -360,12 +326,12 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
const gd::NamedPropertyDescriptor& property) {
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
oldName,
eventsBasedBehavior.GetName(),
gd::EventsBasedBehavior::GetPropertyActionName(
property.GetName())),
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
newName,
eventsBasedBehavior.GetName(),
gd::EventsBasedBehavior::GetPropertyActionName(
@@ -375,12 +341,12 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
gd::InstructionsTypeRenamer conditionRenamer =
gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
oldName,
eventsBasedBehavior.GetName(),
gd::EventsBasedBehavior::GetPropertyConditionName(
property.GetName())),
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
newName,
eventsBasedBehavior.GetName(),
gd::EventsBasedBehavior::GetPropertyConditionName(
@@ -397,12 +363,12 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
const gd::NamedPropertyDescriptor& property) {
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
oldName,
eventsBasedBehavior.GetName(),
gd::EventsBasedBehavior::GetSharedPropertyActionName(
property.GetName())),
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
newName,
eventsBasedBehavior.GetName(),
gd::EventsBasedBehavior::GetSharedPropertyActionName(
@@ -412,12 +378,12 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
gd::InstructionsTypeRenamer conditionRenamer =
gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
oldName,
eventsBasedBehavior.GetName(),
gd::EventsBasedBehavior::GetSharedPropertyConditionName(
property.GetName())),
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
newName,
eventsBasedBehavior.GetName(),
gd::EventsBasedBehavior::GetSharedPropertyConditionName(
@@ -438,10 +404,10 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(oldName,
gd::PlatformExtension::GetObjectEventsFunctionFullType(oldName,
eventsBasedObject.GetName(),
eventsFunction.GetName()),
GetObjectEventsFunctionFullType(newName,
gd::PlatformExtension::GetObjectEventsFunctionFullType(newName,
eventsBasedObject.GetName(),
eventsFunction.GetName()));
ExposeProjectEvents(project, renamer);
@@ -454,12 +420,12 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
const gd::NamedPropertyDescriptor& property) {
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
oldName,
eventsBasedObject.GetName(),
gd::EventsBasedObject::GetPropertyActionName(
property.GetName())),
GetObjectEventsFunctionFullType(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
newName,
eventsBasedObject.GetName(),
gd::EventsBasedObject::GetPropertyActionName(
@@ -469,12 +435,12 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
gd::InstructionsTypeRenamer conditionRenamer =
gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
oldName,
eventsBasedObject.GetName(),
gd::EventsBasedObject::GetPropertyConditionName(
property.GetName())),
GetObjectEventsFunctionFullType(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
newName,
eventsBasedObject.GetName(),
gd::EventsBasedObject::GetPropertyConditionName(
@@ -566,8 +532,8 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
eventsFunctionsExtension.GetEventsBasedBehaviors().GetInternalVector()) {
DoRenameBehavior(
project,
GetBehaviorFullType(oldName, eventsBasedBehavior->GetName()),
GetBehaviorFullType(newName, eventsBasedBehavior->GetName()));
gd::PlatformExtension::GetBehaviorFullType(oldName, eventsBasedBehavior->GetName()),
gd::PlatformExtension::GetBehaviorFullType(newName, eventsBasedBehavior->GetName()));
}
// Finally, rename custom objects type
@@ -575,8 +541,8 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) {
DoRenameObject(
project,
GetObjectFullType(oldName, eventsBasedObject->GetName()),
GetObjectFullType(newName, eventsBasedObject->GetName()));
gd::PlatformExtension::GetObjectFullType(oldName, eventsBasedObject->GetName()),
gd::PlatformExtension::GetObjectFullType(newName, eventsBasedObject->GetName()));
}
}
@@ -593,9 +559,9 @@ void WholeProjectRefactorer::RenameEventsFunction(
DoRenameEventsFunction(
project,
eventsFunction,
GetEventsFunctionFullType(eventsFunctionsExtension.GetName(),
gd::PlatformExtension::GetEventsFunctionFullType(eventsFunctionsExtension.GetName(),
oldFunctionName),
GetEventsFunctionFullType(eventsFunctionsExtension.GetName(),
gd::PlatformExtension::GetEventsFunctionFullType(eventsFunctionsExtension.GetName(),
newFunctionName));
if (eventsFunction.GetFunctionType() == gd::EventsFunction::ExpressionAndCondition) {
@@ -628,7 +594,7 @@ void WholeProjectRefactorer::RenameBehaviorEventsFunction(
gd::ExpressionsRenamer renamer =
gd::ExpressionsRenamer(project.GetCurrentPlatform());
renamer.SetReplacedBehaviorExpression(
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
gd::PlatformExtension::GetBehaviorFullType(eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName()),
oldFunctionName,
newFunctionName);
@@ -637,10 +603,10 @@ void WholeProjectRefactorer::RenameBehaviorEventsFunction(
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(eventsFunctionsExtension.GetName(),
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
oldFunctionName),
GetBehaviorEventsFunctionFullType(eventsFunctionsExtension.GetName(),
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
newFunctionName));
ExposeProjectEvents(project, renamer);
@@ -672,7 +638,7 @@ void WholeProjectRefactorer::RenameObjectEventsFunction(
gd::ExpressionsRenamer renamer =
gd::ExpressionsRenamer(project.GetCurrentPlatform());
renamer.SetReplacedObjectExpression(
GetObjectFullType(eventsFunctionsExtension.GetName(),
gd::PlatformExtension::GetObjectFullType(eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName()),
oldFunctionName,
newFunctionName);
@@ -681,10 +647,10 @@ void WholeProjectRefactorer::RenameObjectEventsFunction(
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
gd::PlatformExtension::GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName(),
oldFunctionName),
GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
gd::PlatformExtension::GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName(),
newFunctionName));
ExposeProjectEvents(project, renamer);
@@ -711,7 +677,7 @@ void WholeProjectRefactorer::MoveEventsFunctionParameter(
const gd::EventsFunction& eventsFunction =
eventsFunctionsExtension.GetEventsFunction(functionName);
const gd::String& eventsFunctionType = GetEventsFunctionFullType(
const gd::String& eventsFunctionType = gd::PlatformExtension::GetEventsFunctionFullType(
eventsFunctionsExtension.GetName(), functionName);
if (eventsFunction.IsExpression()) {
@@ -746,7 +712,7 @@ void WholeProjectRefactorer::MoveBehaviorEventsFunctionParameter(
eventsFunctions.GetEventsFunction(functionName);
const gd::String& eventsFunctionType =
GetBehaviorEventsFunctionFullType(eventsFunctionsExtension.GetName(),
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
functionName);
@@ -754,7 +720,7 @@ void WholeProjectRefactorer::MoveBehaviorEventsFunctionParameter(
gd::ExpressionsParameterMover mover =
gd::ExpressionsParameterMover(project.GetCurrentPlatform());
mover.SetBehaviorExpressionMovedParameter(
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
gd::PlatformExtension::GetBehaviorFullType(eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName()),
functionName,
oldIndex,
@@ -786,7 +752,7 @@ void WholeProjectRefactorer::MoveObjectEventsFunctionParameter(
eventsFunctions.GetEventsFunction(functionName);
const gd::String& eventsFunctionType =
GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
gd::PlatformExtension::GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName(),
functionName);
@@ -794,7 +760,7 @@ void WholeProjectRefactorer::MoveObjectEventsFunctionParameter(
gd::ExpressionsParameterMover mover =
gd::ExpressionsParameterMover(project.GetCurrentPlatform());
mover.SetObjectExpressionMovedParameter(
GetObjectFullType(eventsFunctionsExtension.GetName(),
gd::PlatformExtension::GetObjectFullType(eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName()),
functionName,
oldIndex,
@@ -846,7 +812,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
gd::ExpressionsRenamer expressionRenamer =
gd::ExpressionsRenamer(project.GetCurrentPlatform());
expressionRenamer.SetReplacedBehaviorExpression(
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
gd::PlatformExtension::GetBehaviorFullType(eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName()),
EventsBasedBehavior::GetPropertyExpressionName(oldPropertyName),
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
@@ -854,11 +820,11 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetPropertyActionName(oldPropertyName)),
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetPropertyActionName(newPropertyName)));
@@ -866,11 +832,11 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetPropertyConditionName(oldPropertyName)),
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetPropertyConditionName(newPropertyName)));
@@ -912,7 +878,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
gd::ExpressionsRenamer expressionRenamer =
gd::ExpressionsRenamer(project.GetCurrentPlatform());
expressionRenamer.SetReplacedBehaviorExpression(
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
gd::PlatformExtension::GetBehaviorFullType(eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName()),
EventsBasedBehavior::GetSharedPropertyExpressionName(oldPropertyName),
EventsBasedBehavior::GetSharedPropertyExpressionName(newPropertyName));
@@ -920,11 +886,11 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetSharedPropertyActionName(oldPropertyName)),
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetSharedPropertyActionName(newPropertyName)));
@@ -932,11 +898,11 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetSharedPropertyConditionName(oldPropertyName)),
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetSharedPropertyConditionName(newPropertyName)));
@@ -962,7 +928,7 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
gd::ExpressionsRenamer expressionRenamer =
gd::ExpressionsRenamer(project.GetCurrentPlatform());
expressionRenamer.SetReplacedObjectExpression(
GetObjectFullType(eventsFunctionsExtension.GetName(),
gd::PlatformExtension::GetObjectFullType(eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName()),
EventsBasedObject::GetPropertyExpressionName(oldPropertyName),
EventsBasedObject::GetPropertyExpressionName(newPropertyName));
@@ -970,11 +936,11 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName(),
EventsBasedObject::GetPropertyActionName(oldPropertyName)),
GetObjectEventsFunctionFullType(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName(),
EventsBasedObject::GetPropertyActionName(newPropertyName)));
@@ -982,11 +948,11 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName(),
EventsBasedObject::GetPropertyConditionName(oldPropertyName)),
GetObjectEventsFunctionFullType(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
eventsBasedObject.GetName(),
EventsBasedObject::GetPropertyConditionName(newPropertyName)));
@@ -1223,11 +1189,11 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
oldBehaviorName,
eventsFunction.GetName()),
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
newBehaviorName,
eventsFunction.GetName()));
@@ -1243,11 +1209,11 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
property) {
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
oldBehaviorName,
EventsBasedBehavior::GetPropertyActionName(property.GetName())),
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
newBehaviorName,
EventsBasedBehavior::GetPropertyActionName(property.GetName())));
@@ -1255,11 +1221,11 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
oldBehaviorName,
EventsBasedBehavior::GetPropertyConditionName(property.GetName())),
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
newBehaviorName,
EventsBasedBehavior::GetPropertyConditionName(property.GetName())));
@@ -1277,11 +1243,11 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
property) {
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
oldBehaviorName,
EventsBasedBehavior::GetSharedPropertyActionName(property.GetName())),
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
newBehaviorName,
EventsBasedBehavior::GetSharedPropertyActionName(property.GetName())));
@@ -1289,11 +1255,11 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
project,
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
oldBehaviorName,
EventsBasedBehavior::GetSharedPropertyConditionName(property.GetName())),
GetBehaviorEventsFunctionFullType(
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
newBehaviorName,
EventsBasedBehavior::GetSharedPropertyConditionName(property.GetName())));
@@ -1332,8 +1298,8 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
DoRenameBehavior(
project,
GetBehaviorFullType(eventsFunctionsExtension.GetName(), oldBehaviorName),
GetBehaviorFullType(eventsFunctionsExtension.GetName(), newBehaviorName));
gd::PlatformExtension::GetBehaviorFullType(eventsFunctionsExtension.GetName(), oldBehaviorName),
gd::PlatformExtension::GetBehaviorFullType(eventsFunctionsExtension.GetName(), newBehaviorName));
}
void WholeProjectRefactorer::RenameEventsBasedObject(
@@ -1362,11 +1328,11 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
oldObjectName,
eventsFunction.GetName()),
GetObjectEventsFunctionFullType(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
newObjectName,
eventsFunction.GetName()));
@@ -1382,11 +1348,11 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
property) {
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
oldObjectName,
EventsBasedObject::GetPropertyActionName(property.GetName())),
GetObjectEventsFunctionFullType(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
newObjectName,
EventsBasedObject::GetPropertyActionName(property.GetName())));
@@ -1394,11 +1360,11 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
project,
GetObjectEventsFunctionFullType(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
oldObjectName,
EventsBasedObject::GetPropertyConditionName(property.GetName())),
GetObjectEventsFunctionFullType(
gd::PlatformExtension::GetObjectEventsFunctionFullType(
eventsFunctionsExtension.GetName(),
newObjectName,
EventsBasedObject::GetPropertyConditionName(property.GetName())));
@@ -1435,8 +1401,8 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
DoRenameObject(
project,
GetObjectFullType(eventsFunctionsExtension.GetName(), oldObjectName),
GetObjectFullType(eventsFunctionsExtension.GetName(), newObjectName));
gd::PlatformExtension::GetObjectFullType(eventsFunctionsExtension.GetName(), oldObjectName),
gd::PlatformExtension::GetObjectFullType(eventsFunctionsExtension.GetName(), newObjectName));
}
void WholeProjectRefactorer::DoRenameEventsFunction(

View File

@@ -145,6 +145,11 @@ 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,

View File

@@ -0,0 +1,27 @@
/*
* 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

View File

@@ -0,0 +1,57 @@
/*
* 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

View File

@@ -0,0 +1,38 @@
/*
* 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

View File

@@ -0,0 +1,197 @@
/*
* 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

View File

@@ -0,0 +1,15 @@
/*
* 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

View File

@@ -0,0 +1,46 @@
/*
* 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

View File

@@ -8,6 +8,8 @@
#include <vector>
#include "GDCore/String.h"
#include "GDCore/Project/MeasurementUnit.h"
namespace gd {
class SerializerElement;
}
@@ -28,12 +30,12 @@ class GD_CORE_API PropertyDescriptor {
* \param propertyValue The value of the property.
*/
PropertyDescriptor(gd::String propertyValue)
: currentValue(propertyValue), type("string"), label(""), hidden(false) {}
: currentValue(propertyValue), type("string"), label(""), hidden(false), measurementUnit(gd::MeasurementUnit::GetUndefined()) {}
/**
* \brief Empty constructor creating an empty property to be displayed.
*/
PropertyDescriptor() : hidden(false){};
PropertyDescriptor() : hidden(false), measurementUnit(gd::MeasurementUnit::GetUndefined()) {};
/**
* \brief Destructor
@@ -103,12 +105,21 @@ 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;
@@ -168,6 +179,7 @@ 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

View File

@@ -289,9 +289,8 @@ void SerializerElement::Init(const gd::SerializerElement& other) {
deprecatedArrayOf = other.deprecatedArrayOf;
}
// TODO Remove shouldAlwayUseSetString in a release that follows the 150.
void SerializerElement::SetMultilineStringValue(const gd::String& value, bool shouldAlwayUseSetString) {
if (shouldAlwayUseSetString || value.find('\n') == gd::String::npos) {
void SerializerElement::SetMultilineStringValue(const gd::String& value) {
if (value.find('\n') == gd::String::npos) {
SetStringValue(value);
return;
}

View File

@@ -183,7 +183,7 @@ class GD_CORE_API SerializerElement {
* \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, bool shouldAlwayUseSetString = true);
void SetMultilineStringValue(const gd::String &value);
/**
* \brief Read the value, either represented as a string or as an array of strings,

View File

@@ -12,6 +12,7 @@
#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.
@@ -94,6 +95,13 @@ 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);
@@ -373,6 +381,7 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
.AddUnsupportedBaseObjectCapability("effect");
}
platform.AddExtension(commonInstructionsExtension);
platform.AddExtension(baseObjectExtension);
platform.AddExtension(extension);
project.AddPlatform(platform);

View File

@@ -0,0 +1,739 @@
/*
* 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");
}
}

View File

@@ -85,7 +85,7 @@ TEST_CASE("SerializerElement", "[common]") {
SerializerElement element;
// A single line is saved as a string.
element.SetMultilineStringValue("test", false);
element.SetMultilineStringValue("test");
REQUIRE(element.GetMultilineStringValue() == "test");
REQUIRE(element.GetStringValue() == "test");
@@ -94,12 +94,12 @@ TEST_CASE("SerializerElement", "[common]") {
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.", false);
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", false);
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");

View File

@@ -25,6 +25,7 @@ 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;

View File

@@ -29,37 +29,82 @@ void PathfindingBehavior::InitializeContent(
#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[_("Allows diagonals")]
properties["AllowDiagonals"]
.SetLabel(_("Allows diagonals"))
.SetValue(behaviorContent.GetBoolAttribute("allowDiagonals") ? "true"
: "false")
.SetGroup(_("Path smoothing"))
.SetType("Boolean");
properties[_("Acceleration")].SetValue(
properties["Acceleration"]
.SetLabel(_("Acceleration"))
.SetType("Number")
.SetMeasurementUnit(gd::MeasurementUnit::GetPixelAcceleration()).SetValue(
gd::String::From(behaviorContent.GetDoubleAttribute("acceleration")));
properties[_("Max. speed")].SetValue(
properties["MaxSpeed"]
.SetLabel(_("Max. speed"))
.SetType("Number")
.SetMeasurementUnit(gd::MeasurementUnit::GetPixelSpeed()).SetValue(
gd::String::From(behaviorContent.GetDoubleAttribute("maxSpeed")));
properties[_("Rotate speed")].SetGroup(_("Rotation")).SetValue(
gd::String::From(behaviorContent.GetDoubleAttribute("angularMaxSpeed")));
properties[_("Rotate object")].SetGroup(_("Rotation"))
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"))
.SetValue(behaviorContent.GetBoolAttribute("rotateObject") ? "true"
: "false")
.SetType("Boolean");
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")));
properties[_("Smoothing max cell gap")]
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"))
@@ -72,38 +117,38 @@ std::map<gd::String, gd::PropertyDescriptor> PathfindingBehavior::GetProperties(
bool PathfindingBehavior::UpdateProperty(gd::SerializerElement& behaviorContent,
const gd::String& name,
const gd::String& value) {
if (name == _("Allows diagonals")) {
if (name == "AllowDiagonals") {
behaviorContent.SetAttribute("allowDiagonals", (value != "0"));
return true;
}
if (name == _("Rotate object")) {
if (name == "RotateObject") {
behaviorContent.SetAttribute("rotateObject", (value != "0"));
return true;
}
if (name == _("Extra border size")) {
if (name == "ExtraBorder") {
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 == _("Max. speed"))
else if (name == "MaxSpeed")
behaviorContent.SetAttribute("maxSpeed", value.To<float>());
else if (name == _("Rotate speed"))
else if (name == "AngularMaxSpeed")
behaviorContent.SetAttribute("angularMaxSpeed", value.To<float>());
else if (name == _("Angle offset"))
else if (name == "AngleOffset")
behaviorContent.SetAttribute("angleOffset", value.To<float>());
else if (name == _("Virtual cell width"))
else if (name == "CellWidth")
behaviorContent.SetAttribute("cellWidth", value.To<float>());
else if (name == _("Virtual cell height"))
else if (name == "CellHeight")
behaviorContent.SetAttribute("cellHeight", value.To<float>());
else if (name == _("Virtual grid X offset"))
else if (name == "GridOffsetX")
behaviorContent.SetAttribute("gridOffsetX", value.To<float>());
else if (name == _("Virtual grid Y offset"))
else if (name == "GridOffsetY")
behaviorContent.SetAttribute("gridOffsetY", value.To<float>());
else if (name == _("Smoothing max cell gap"))
else if (name == "SmoothingMaxCellGap")
behaviorContent.SetAttribute("smoothingMaxCellGap", value.To<float>());
else
return false;

View File

@@ -20,12 +20,14 @@ std::map<gd::String, gd::PropertyDescriptor>
PathfindingObstacleBehavior::GetProperties(
const gd::SerializerElement& behaviorContent) const {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[_("Impassable obstacle")]
properties["Impassable"]
.SetLabel(_("Impassable obstacle"))
.SetValue(behaviorContent.GetBoolAttribute("impassable") ? "true"
: "false")
.SetType("Boolean");
properties[_("Cost (if not impassable)")].SetValue(
gd::String::From(behaviorContent.GetDoubleAttribute("cost")));
properties["Cost"]
.SetLabel(_("Cost (if not impassable)"))
.SetValue(gd::String::From(behaviorContent.GetDoubleAttribute("cost")));
return properties;
}
@@ -34,14 +36,14 @@ bool PathfindingObstacleBehavior::UpdateProperty(
gd::SerializerElement& behaviorContent,
const gd::String& name,
const gd::String& value) {
if (name == _("Impassable obstacle")) {
if (name == "Impassable") {
behaviorContent.SetAttribute("impassable", (value != "0"));
return true;
}
if (value.To<float>() < 0) return false;
if (name == _("Cost (if not impassable)"))
if (name == "Cost")
behaviorContent.SetAttribute("cost", value.To<float>());
else
return false;

View File

@@ -200,6 +200,7 @@ module.exports = {
.toString(10)
)
.setType('Number')
.setMeasurementUnit(gd.MeasurementUnit.getPixel())
.setLabel('Shape Dimension A');
behaviorProperties
.getOrCreate('shapeDimensionB')
@@ -210,6 +211,7 @@ module.exports = {
.toString(10)
)
.setType('Number')
.setMeasurementUnit(gd.MeasurementUnit.getPixel())
.setLabel('Shape Dimension B');
behaviorProperties
.getOrCreate('shapeOffsetX')
@@ -217,6 +219,7 @@ module.exports = {
behaviorContent.getChild('shapeOffsetX').getDoubleValue().toString(10)
)
.setType('Number')
.setMeasurementUnit(gd.MeasurementUnit.getPixel())
.setLabel('Shape Offset X');
behaviorProperties
.getOrCreate('shapeOffsetY')
@@ -224,6 +227,7 @@ module.exports = {
behaviorContent.getChild('shapeOffsetY').getDoubleValue().toString(10)
)
.setType('Number')
.setMeasurementUnit(gd.MeasurementUnit.getPixel())
.setLabel('Shape Offset Y');
behaviorProperties
.getOrCreate('polygonOrigin')
@@ -373,13 +377,15 @@ module.exports = {
.setValue(
sharedContent.getChild('gravityX').getDoubleValue().toString(10)
)
.setType('Number');
.setType('Number')
.setMeasurementUnit(gd.MeasurementUnit.getNewton());
sharedProperties
.getOrCreate('gravityY')
.setValue(
sharedContent.getChild('gravityY').getDoubleValue().toString(10)
)
.setType('Number');
.setType('Number')
.setMeasurementUnit(gd.MeasurementUnit.getNewton());
sharedProperties
.getOrCreate('scaleX')
.setValue(

View File

@@ -825,8 +825,12 @@ namespace gdjs {
}
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
// Step the world if not done this frame yet
if (!this._sharedData.stepped) {
// 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()
) {
// Reset started and ended contacts array for all physics instances.
this._sharedData.resetStartedAndEndedCollisions();
this._sharedData.updateBodiesFromObjects();

View File

@@ -64,7 +64,7 @@ describe('Physics2RuntimeBehavior', () => {
resources: { resources: [] },
properties: { windowWidth: 1000, windowHeight: 1000 },
});
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
const runtimeScene = new gdjs.TestRuntimeScene(runtimeGame);
runtimeScene.loadFromScene({
layers: [
{
@@ -236,6 +236,39 @@ 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);
@@ -243,6 +276,9 @@ 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,
@@ -271,11 +307,10 @@ describe('Physics2RuntimeBehavior', () => {
).to.be(true);
// Put objects in contact and assert collision started during the frame
runtimeScene.setEventsFunction(() => {
runtimeScene.renderAndStepWithEventsFunction(1000 / fps, () => {
object1.setPosition(10, 0);
object2.setPosition(20, 0);
});
runtimeScene.renderAndStep(1000 / fps);
// After post event, collision should be present
assertCollision(object1, object2, {
@@ -284,9 +319,6 @@ 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, {
@@ -424,33 +456,28 @@ describe('Physics2RuntimeBehavior', () => {
movingObjectBehavior.setLinearVelocityY(40000);
let hasBounced = 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 {
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++;
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,
});
}
});
}
runtimeScene.setEventsFunction(() => {});
runtimeScene.renderAndStep(1000 / fps);
assertCollision(movingObject, staticObject, {
started: false,
@@ -486,32 +513,31 @@ describe('Physics2RuntimeBehavior', () => {
movingObjectBehavior.setLinearVelocityY(40000);
let hasBegunBouncing = 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++;
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,
});
}
});
}
if (!hasBegunBouncing) {
@@ -522,8 +548,7 @@ describe('Physics2RuntimeBehavior', () => {
// At next frame, end of collision should be detected
let hasFinishedBouncing = false;
runtimeScene.setEventsFunction(() => {
runtimeScene.renderAndStepWithEventsFunction(1000 / fps, () => {
hasFinishedBouncing = true;
assertCollision(movingObject, staticObject, {
started: false,
@@ -532,8 +557,6 @@ describe('Physics2RuntimeBehavior', () => {
});
});
runtimeScene.renderAndStep(1000 / fps);
if (!hasFinishedBouncing) {
throw new Error('End of contact was not detected, nothing was tested.');
}
@@ -546,6 +569,9 @@ 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,
@@ -567,7 +593,7 @@ describe('Physics2RuntimeBehavior', () => {
stopped: false,
});
runtimeScene.setEventsFunction(() => {
runtimeScene.renderAndStepWithEventsFunction(1000 / fps, () => {
// Manually call onContactEnd and onContactBegin methods to simulate
// a loss of contact followed by a contact beginning during the preEvent.
movingObject
@@ -584,7 +610,6 @@ describe('Physics2RuntimeBehavior', () => {
stopped: false,
});
});
runtimeScene.renderAndStep(1000 / fps);
});
it('should not detect a new contact if the contact ended and jittered.', () => {
@@ -594,6 +619,9 @@ 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,
@@ -615,7 +643,7 @@ describe('Physics2RuntimeBehavior', () => {
stopped: false,
});
runtimeScene.setEventsFunction(() => {
runtimeScene.renderAndStepWithEventsFunction(1000 / fps, () => {
// 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.
@@ -637,7 +665,6 @@ describe('Physics2RuntimeBehavior', () => {
stopped: true,
});
});
runtimeScene.renderAndStep(1000 / fps);
});
it('it should end collision on resize (body updated in pre-event).', () => {
@@ -647,6 +674,9 @@ 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,
@@ -668,18 +698,15 @@ describe('Physics2RuntimeBehavior', () => {
});
// Resize.
runtimeScene.setEventsFunction(() => {
runtimeScene.renderAndStepWithEventsFunction(1000 / fps, () => {
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,
@@ -695,6 +722,9 @@ 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,
@@ -716,13 +746,11 @@ describe('Physics2RuntimeBehavior', () => {
stopped: false,
});
// Destroy (postEvent operation).
runtimeScene.setEventsFunction(() => {
// Destroy (handled by postEvent).
runtimeScene.renderAndStepWithEventsFunction(1000 / fps, () => {
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, {

View File

@@ -36,18 +36,24 @@ std::map<gd::String, gd::PropertyDescriptor> PlatformBehavior::GetProperties(
else if (platformType == "Jumpthru")
platformTypeStr = _("Jumpthru platform");
properties[_("Type")]
properties["PlatformType"]
.SetLabel(_("Type"))
.SetValue(platformTypeStr)
.SetType("Choice")
.AddExtraInfo(_("Platform"))
.AddExtraInfo(_("Jumpthru platform"))
.AddExtraInfo(_("Ladder"));
properties[_("Ledges can be grabbed")].SetGroup(_("Ledge"))
properties["CanBeGrabbed"]
.SetLabel(_("Ledges can be grabbed"))
.SetGroup(_("Ledge"))
.SetValue(behaviorContent.GetBoolAttribute("canBeGrabbed", true)
? "true"
: "false")
.SetType("Boolean");
properties[_("Grab offset on Y axis")].SetGroup(_("Ledge")).SetValue(
properties["YGrabOffset"]
.SetLabel(_("Grab offset on Y axis"))
.SetGroup(_("Ledge"))
.SetValue(
gd::String::From(behaviorContent.GetDoubleAttribute("yGrabOffset")));
return properties;
@@ -56,16 +62,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 == _("Ledges can be grabbed"))
if (name == "CanBeGrabbed")
behaviorContent.SetAttribute("canBeGrabbed", (value == "1"));
else if (name == _("Type")) {
else if (name == "PlatformType") {
if (value == _("Jumpthru platform"))
behaviorContent.SetAttribute("platformType", "Jumpthru");
else if (value == _("Ladder"))
behaviorContent.SetAttribute("platformType", "Ladder");
else
behaviorContent.SetAttribute("platformType", "NormalPlatform");
} else if (name == _("Grab offset on Y axis"))
} else if (name == "YGrabOffset")
behaviorContent.SetAttribute("yGrabOffset", value.To<double>());
else
return false;

View File

@@ -13,6 +13,7 @@ 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"
@@ -44,60 +45,109 @@ PlatformerObjectBehavior::GetProperties(
const gd::SerializerElement& behaviorContent) const {
std::map<gd::String, gd::PropertyDescriptor> properties;
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"]
properties["Gravity"]
.SetLabel(_("Gravity"))
.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[_("Max. falling speed")].SetGroup(_("Jump")).SetValue(
gd::String::From(behaviorContent.GetDoubleAttribute("maxFallingSpeed")));
properties[_("Ladder climbing speed")]
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"))
.SetGroup(_("Ladder"))
.SetType("Number")
.SetMeasurementUnit(gd::MeasurementUnit::GetPixelSpeed())
.SetValue(gd::String::From(
behaviorContent.GetDoubleAttribute("ladderClimbingSpeed", 150)));
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")]
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"))
.SetValue(behaviorContent.GetBoolAttribute("ignoreDefaultControls")
? "false"
: "true")
.SetType("Boolean");
properties[_("Slope max. angle")].SetGroup(_("Walk")).SetValue(
gd::String::From(behaviorContent.GetDoubleAttribute("slopeMaxAngle")));
properties[_("Can grab platform ledges")]
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"))
.SetGroup(_("Ledge"))
.SetValue(behaviorContent.GetBoolAttribute("canGrabPlatforms", false)
? "true"
: "false")
.SetType("Boolean");
properties[_("Automatically grab platform ledges without having to move "
"horizontally")]
properties["CanGrabWithoutMoving"]
.SetLabel(_("Automatically grab platform ledges without having to move "
"horizontally"))
.SetGroup(_("Ledge"))
.SetValue(behaviorContent.GetBoolAttribute("canGrabWithoutMoving", false)
? "true"
: "false")
.SetType("Boolean");
properties[_("Grab offset on Y axis")]
properties["YGrabOffset"]
.SetLabel(_("Grab offset on Y axis"))
.SetGroup(_("Ledge"))
.SetType("Number")
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
.SetValue(
gd::String::From(behaviorContent.GetDoubleAttribute("yGrabOffset")));
properties[_("Grab tolerance on X axis")]
properties["XGrabTolerance"]
.SetLabel(_("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)"))
@@ -105,7 +155,8 @@ PlatformerObjectBehavior::GetProperties(
? "true"
: "false")
.SetType("Boolean");
properties[_("Can go down from jumpthru platforms")]
properties["CanGoDownFromJumpthru"]
.SetLabel(_("Can go down from jumpthru platforms"))
.SetGroup(_("Walk"))
.SetValue(behaviorContent.GetBoolAttribute("canGoDownFromJumpthru", false)
? "true"
@@ -118,44 +169,43 @@ bool PlatformerObjectBehavior::UpdateProperty(
gd::SerializerElement& behaviorContent,
const gd::String& name,
const gd::String& value) {
if (name == _("Default controls"))
if (name == "IgnoreDefaultControls")
behaviorContent.SetAttribute("ignoreDefaultControls", (value == "0"));
else if (name == _("Can grab platform ledges"))
else if (name == "CanGrabPlatforms")
behaviorContent.SetAttribute("canGrabPlatforms", (value == "1"));
else if (name == _("Automatically grab platform ledges without having to "
"move horizontally"))
else if (name == "CanGrabWithoutMoving")
behaviorContent.SetAttribute("canGrabWithoutMoving", (value == "1"));
else if (name == "useLegacyTrajectory")
else if (name == "UseLegacyTrajectory")
behaviorContent.SetAttribute("useLegacyTrajectory", (value == "1"));
else if (name == _("Can go down from jumpthru platforms"))
else if (name == "CanGoDownFromJumpthru")
behaviorContent.SetAttribute("canGoDownFromJumpthru", (value == "1"));
else if (name == _("Grab offset on Y axis"))
else if (name == "YGrabOffset")
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 == _("Max. falling speed"))
else if (name == "MaxFallingSpeed")
behaviorContent.SetAttribute("maxFallingSpeed", value.To<double>());
else if (name == _("Ladder climbing speed"))
else if (name == "LadderClimbingSpeed")
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 == _("Max. speed"))
else if (name == "MaxSpeed")
behaviorContent.SetAttribute("maxSpeed", value.To<double>());
else if (name == _("Jump speed"))
else if (name == "JumpSpeed")
behaviorContent.SetAttribute("jumpSpeed", value.To<double>());
else if (name == "jumpSustainTime")
else if (name == "JumpSustainTime")
behaviorContent.SetAttribute("jumpSustainTime", value.To<double>());
else if (name == _("Slope max. angle")) {
else if (name == "SlopeMaxAngle") {
double newMaxAngle = value.To<double>();
if (newMaxAngle < 0 || newMaxAngle >= 90) return false;
behaviorContent.SetAttribute("slopeMaxAngle", newMaxAngle);
} else if (name == _("Grab tolerance on X axis"))
} else if (name == "XGrabTolerance")
behaviorContent.SetAttribute("xGrabTolerance", value.To<double>());
else
return false;

View File

@@ -14,6 +14,7 @@ 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"
@@ -45,26 +46,55 @@ TopDownMovementBehavior::GetProperties(
const gd::SerializerElement& behaviorContent) const {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[_("Allows diagonals")].SetGroup(_("Movement"))
properties["AllowDiagonals"]
.SetLabel(_("Allows diagonals"))
.SetGroup(_("Movement"))
.SetValue(behaviorContent.GetBoolAttribute("allowDiagonals") ? "true"
: "false")
.SetType("Boolean");
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")]
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"))
.SetGroup(_("Rotation"))
.SetValue(behaviorContent.GetBoolAttribute("rotateObject") ? "true"
: "false")
.SetType("Boolean");
properties[_("Angle offset")].SetGroup(_("Rotation")).SetValue(
gd::String::From(behaviorContent.GetDoubleAttribute("angleOffset")));
properties[_("Default controls")]
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"))
.SetValue(behaviorContent.GetBoolAttribute("ignoreDefaultControls")
? "false"
: "true")
@@ -80,7 +110,8 @@ TopDownMovementBehavior::GetProperties(
viewpointStr = _("True Isometry (30°)");
else if (viewpoint == "CustomIsometry")
viewpointStr = _("Custom Isometry");
properties[_("Viewpoint")]
properties["Viewpoint"]
.SetLabel(_("Viewpoint"))
.SetGroup(_("Viewpoint"))
.SetValue(viewpointStr)
.SetType("Choice")
@@ -88,14 +119,20 @@ TopDownMovementBehavior::GetProperties(
.AddExtraInfo(_("Isometry 2:1 (26.565°)"))
.AddExtraInfo(_("True Isometry (30°)"))
.AddExtraInfo(_("Custom Isometry"));
properties[_("Custom isometry angle")]
properties["CustomIsometryAngle"]
.SetLabel(_("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[_("Movement angle offset")]
properties["MovementAngleOffset"]
.SetLabel(_("Movement angle offset"))
.SetGroup(_("Viewpoint"))
.SetType("Number")
.SetMeasurementUnit(gd::MeasurementUnit::GetDegreeAngle())
.SetValue(gd::String::From(
behaviorContent.GetDoubleAttribute("movementAngleOffset")))
.SetDescription(_(
@@ -109,19 +146,19 @@ bool TopDownMovementBehavior::UpdateProperty(
gd::SerializerElement& behaviorContent,
const gd::String& name,
const gd::String& value) {
if (name == _("Default controls")) {
if (name == "IgnoreDefaultControls") {
behaviorContent.SetAttribute("ignoreDefaultControls", (value == "0"));
return true;
}
if (name == _("Allows diagonals")) {
if (name == "AllowDiagonals") {
behaviorContent.SetAttribute("allowDiagonals", (value != "0"));
return true;
}
if (name == _("Rotate object")) {
if (name == "RotateObject") {
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", "");
@@ -147,23 +184,23 @@ bool TopDownMovementBehavior::UpdateProperty(
behaviorContent.SetAttribute("viewpoint", "TopDown");
return true;
}
if (name == _("Movement angle offset")) {
if (name == "MovementAngleOffset") {
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 == _("Max. speed"))
else if (name == "MaxSpeed")
behaviorContent.SetAttribute("maxSpeed", value.To<float>());
else if (name == _("Rotate speed"))
else if (name == "RotationSpeed")
behaviorContent.SetAttribute("angularMaxSpeed", value.To<float>());
else if (name == _("Angle offset"))
else if (name == "AngleOffset")
behaviorContent.SetAttribute("angleOffset", value.To<float>());
else if (name == _("Custom isometry angle")) {
else if (name == "CustomIsometryAngle") {
if (value.To<float>() < 1 || value.To<float>() > 44) return false;
behaviorContent.SetAttribute("customIsometryAngle", value.To<float>());
} else

View File

@@ -408,6 +408,30 @@ 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.

View File

@@ -493,7 +493,13 @@ namespace gdjs {
* @param enable true to pause the game, false to unpause
*/
pause(enable: boolean) {
if (this._paused === enable) return;
this._paused = enable;
if (this._debuggerClient) {
if (this._paused) this._debuggerClient.sendGamePaused();
else this._debuggerClient.sendGameResumed();
}
}
/**

View File

@@ -818,6 +818,8 @@ interface PropertyDescriptor {
[Ref] PropertyDescriptor SetExtraInfo([Const, Ref] VectorString info);
[Ref] VectorString GetExtraInfo();
[Ref] PropertyDescriptor SetHidden(boolean enable);
[Const, Ref] MeasurementUnit GetMeasurementUnit();
[Ref] PropertyDescriptor SetMeasurementUnit([Const, Ref] MeasurementUnit measurementUnit);
boolean IsHidden();
void SerializeTo([Ref] SerializerElement element);
@@ -826,6 +828,39 @@ interface PropertyDescriptor {
void UnserializeValuesFrom([Const, Ref] SerializerElement element);
};
interface MeasurementUnit {
void MeasurementUnit(DOMString name, DOMString label, DOMString description);
[Const, Ref] DOMString GetName();
[Const, Ref] DOMString GetLabel();
[Const, Ref] DOMString GetDescription();
[Const, Ref] DOMString GetElementsWithWords();
long GetElementsCount();
long GetElementPower(long elementIndex);
[Const, Ref] MeasurementBaseUnit GetElementBaseUnit(long elementIndex);
boolean IsUndefined();
void STATIC_ApplyTranslation();
[Ref] MeasurementUnit STATIC_GetDimensionless();
[Ref] MeasurementUnit STATIC_GetDegreeAngle();
[Ref] MeasurementUnit STATIC_GetSecond();
[Ref] MeasurementUnit STATIC_GetPixel();
[Ref] MeasurementUnit STATIC_GetPixelSpeed();
[Ref] MeasurementUnit STATIC_GetPixelAcceleration();
[Ref] MeasurementUnit STATIC_GetNewton();
};
interface MeasurementBaseUnit {
void MeasurementBaseUnit(DOMString name, DOMString symbol, DOMString quantity);
[Const, Ref] DOMString GetName();
[Const, Ref] DOMString GetSymbol();
[Const, Ref] DOMString GetQuantity();
};
interface NamedPropertyDescriptor {
void NamedPropertyDescriptor();
@@ -1367,6 +1402,7 @@ interface ValueTypeMetadata {
boolean STATIC_IsTypeBehavior([Const] DOMString parameterType);
boolean STATIC_IsTypeExpression([Const] DOMString type, [Const] DOMString parameterType);
[Const, Ref] DOMString STATIC_GetPrimitiveValueType([Const] DOMString parameterType);
[Const, Ref] DOMString STATIC_ConvertPropertyTypeToValueType([Const] DOMString propertyType);
void SerializeTo([Ref] SerializerElement element);
void UnserializeFrom([Const, Ref] SerializerElement element);
@@ -2158,6 +2194,12 @@ interface WholeProjectRefactorer {
boolean STATIC_FixInvalidRequiredBehaviorProperties([Ref] Project project);
};
interface PropertyFunctionGenerator {
void STATIC_GenerateBehaviorGetterAndSetter([Ref] Project project, [Ref] EventsFunctionsExtension extension, [Ref] EventsBasedBehavior eventsBasedBehavior, [Const, Ref] NamedPropertyDescriptor property, boolean isSharedProperties);
void STATIC_GenerateObjectGetterAndSetter([Ref] Project project, [Ref] EventsFunctionsExtension extension, [Ref] EventsBasedObject eventsBasedObject, [Const, Ref] NamedPropertyDescriptor property);
boolean STATIC_CanGenerateGetterAndSetter([Const, Ref] AbstractEventsBasedEntity eventsBasedBehavior, [Const, Ref] NamedPropertyDescriptor property);
};
interface UsedExtensionsFinder {
[Value] SetString STATIC_ScanProject([Ref] Project project);
};
@@ -2350,6 +2392,14 @@ interface EventsFunctionsContainer {
unsigned long GetEventsFunctionPosition([Const, Ref] EventsFunction eventsFunction);
};
interface AbstractEventsBasedEntity {
[Ref] EventsFunctionsContainer GetEventsFunctions();
[Ref] NamedPropertyDescriptorsList GetPropertyDescriptors();
void SerializeTo([Ref] SerializerElement element);
void UnserializeFrom([Ref] Project project, [Const, Ref] SerializerElement element);
};
interface EventsBasedBehavior {
void EventsBasedBehavior();
@@ -2364,18 +2414,16 @@ interface EventsBasedBehavior {
[Ref] EventsBasedBehavior SetPrivate(boolean isPrivate);
boolean IsPrivate();
[Ref] EventsFunctionsContainer GetEventsFunctions();
[Ref] NamedPropertyDescriptorsList GetPropertyDescriptors();
[Ref] NamedPropertyDescriptorsList GetSharedPropertyDescriptors();
void SerializeTo([Ref] SerializerElement element);
void UnserializeFrom([Ref] Project project, [Const, Ref] SerializerElement element);
[Const, Value] DOMString STATIC_GetPropertyActionName([Const] DOMString propertyName);
[Const, Value] DOMString STATIC_GetPropertyConditionName([Const] DOMString propertyName);
[Const, Value] DOMString STATIC_GetPropertyExpressionName([Const] DOMString propertyName);
[Const, Value] DOMString STATIC_GetSharedPropertyActionName([Const] DOMString propertyName);
[Const, Value] DOMString STATIC_GetSharedPropertyConditionName([Const] DOMString propertyName);
[Const, Value] DOMString STATIC_GetSharedPropertyExpressionName([Const] DOMString propertyName);
};
EventsBasedBehavior implements AbstractEventsBasedEntity;
interface EventsBasedBehaviorsList {
[Ref] EventsBasedBehavior InsertNew([Const] DOMString name, unsigned long pos);
@@ -2404,17 +2452,26 @@ interface EventsBasedObject {
[Ref] EventsBasedObject SetDefaultName([Const] DOMString defaultName);
[Const, Ref] DOMString GetDefaultName();
[Ref] EventsFunctionsContainer GetEventsFunctions();
[Ref] NamedPropertyDescriptorsList GetPropertyDescriptors();
void SerializeTo([Ref] SerializerElement element);
void UnserializeFrom([Ref] Project project, [Const, Ref] SerializerElement element);
[Const, Value] DOMString STATIC_GetPropertyActionName([Const] DOMString propertyName);
[Const, Value] DOMString STATIC_GetPropertyConditionName([Const] DOMString propertyName);
[Const, Value] DOMString STATIC_GetPropertyExpressionName([Const] DOMString propertyName);
// Inherited from gd::ObjectsContainer
[Ref] gdObject InsertNewObject([Ref] Project project, [Const] DOMString type, [Const] DOMString name, unsigned long pos);
[Ref] gdObject InsertObject([Const, Ref] gdObject obj, unsigned long pos);
boolean HasObjectNamed([Const] DOMString name);
[Ref] gdObject GetObject([Const] DOMString name);
[Ref] gdObject GetObjectAt(unsigned long pos);
unsigned long GetObjectPosition([Const] DOMString name);
void RemoveObject([Const] DOMString name);
void SwapObjects(unsigned long first, unsigned long second);
void MoveObject(unsigned long oldIndex, unsigned long newIndex);
void MoveObjectToAnotherContainer([Const] DOMString name, [Ref] ObjectsContainer newObjectsContainer, unsigned long newPosition);
unsigned long GetObjectsCount();
[Ref] ObjectGroupsContainer GetObjectGroups();
};
EventsBasedObject implements ObjectsContainer;
EventsBasedObject implements AbstractEventsBasedEntity;
interface EventsBasedObjectsList {
[Ref] EventsBasedObject InsertNew([Const] DOMString name, unsigned long pos);

View File

@@ -48,6 +48,7 @@
#include <GDCore/IDE/Project/ResourcesInUseHelper.h>
#include <GDCore/IDE/Project/ResourcesMergingHelper.h>
#include <GDCore/IDE/Project/ResourcesRenamer.h>
#include <GDCore/IDE/PropertyFunctionGenerator.h>
#include <GDCore/IDE/WholeProjectRefactorer.h>
#include <GDCore/IDE/UnfilledRequiredBehaviorPropertyProblem.h>
#include <GDCore/Project/Behavior.h>
@@ -61,6 +62,9 @@
#include <GDCore/Project/InitialInstance.h>
#include <GDCore/Project/InitialInstancesContainer.h>
#include <GDCore/Project/Layout.h>
#include <GDCore/Project/MeasurementBaseUnit.h>
#include <GDCore/Project/MeasurementUnitElement.h>
#include <GDCore/Project/MeasurementUnitElement.h>
#include <GDCore/Project/NamedPropertyDescriptor.h>
#include <GDCore/Project/Object.h>
#include <GDCore/Project/ObjectConfiguration.h>
@@ -516,6 +520,7 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_IsTypeExpression IsTypeExpression
#define STATIC_GetExpressionValueType GetExpressionValueType
#define STATIC_GetPrimitiveValueType GetPrimitiveValueType
#define STATIC_ConvertPropertyTypeToValueType ConvertPropertyTypeToValueType
#define STATIC_Get Get
#define STATIC_GetAllUseless GetAllUseless
#define STATIC_RemoveAllUseless RemoveAllUseless
@@ -595,6 +600,9 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
GetBehaviorsWithType
#define STATIC_FixInvalidRequiredBehaviorProperties \
FixInvalidRequiredBehaviorProperties
#define STATIC_GenerateBehaviorGetterAndSetter GenerateBehaviorGetterAndSetter
#define STATIC_GenerateObjectGetterAndSetter GenerateObjectGetterAndSetter
#define STATIC_CanGenerateGetterAndSetter CanGenerateGetterAndSetter
#define STATIC_CreateRectangle CreateRectangle
#define STATIC_SanityCheckBehaviorProperty SanityCheckBehaviorProperty
#define STATIC_SanityCheckObjectProperty SanityCheckObjectProperty
@@ -642,6 +650,8 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_GetPropertyActionName GetPropertyActionName
#define STATIC_GetPropertyConditionName GetPropertyConditionName
#define STATIC_GetPropertyExpressionName GetPropertyExpressionName
#define STATIC_GetSharedPropertyActionName GetSharedPropertyActionName
#define STATIC_GetSharedPropertyConditionName GetSharedPropertyConditionName
#define STATIC_GetSharedPropertyExpressionName GetSharedPropertyExpressionName
#define STATIC_CopyAllResourcesTo CopyAllResourcesTo
@@ -655,6 +665,15 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_ScanProject ScanProject
#define STATIC_ApplyTranslation ApplyTranslation
#define STATIC_GetDimensionless GetDimensionless
#define STATIC_GetDegreeAngle GetDegreeAngle
#define STATIC_GetSecond GetSecond
#define STATIC_GetPixel GetPixel
#define STATIC_GetPixelSpeed GetPixelSpeed
#define STATIC_GetPixelAcceleration GetPixelAcceleration
#define STATIC_GetNewton GetNewton
// We postfix some methods with "At" as Javascript does not support overloading
#define GetLayoutAt GetLayout
#define GetExternalEventsAt GetExternalEvents

View File

@@ -0,0 +1,9 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdAbstractEventsBasedEntity {
getEventsFunctions(): gdEventsFunctionsContainer;
getPropertyDescriptors(): gdNamedPropertyDescriptorsList;
serializeTo(element: gdSerializerElement): void;
unserializeFrom(project: gdProject, element: gdSerializerElement): void;
delete(): void;
ptr: number;
};

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdEventsBasedBehavior {
declare class gdEventsBasedBehavior extends gdAbstractEventsBasedEntity {
constructor(): void;
setDescription(description: string): gdEventsBasedBehavior;
getDescription(): string;
@@ -11,14 +11,12 @@ declare class gdEventsBasedBehavior {
getObjectType(): string;
setPrivate(isPrivate: boolean): gdEventsBasedBehavior;
isPrivate(): boolean;
getEventsFunctions(): gdEventsFunctionsContainer;
getPropertyDescriptors(): gdNamedPropertyDescriptorsList;
getSharedPropertyDescriptors(): gdNamedPropertyDescriptorsList;
serializeTo(element: gdSerializerElement): void;
unserializeFrom(project: gdProject, element: gdSerializerElement): void;
static getPropertyActionName(propertyName: string): string;
static getPropertyConditionName(propertyName: string): string;
static getPropertyExpressionName(propertyName: string): string;
static getSharedPropertyActionName(propertyName: string): string;
static getSharedPropertyConditionName(propertyName: string): string;
static getSharedPropertyExpressionName(propertyName: string): string;
delete(): void;
ptr: number;

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdEventsBasedObject extends gdObjectsContainer {
declare class gdEventsBasedObject extends gdAbstractEventsBasedEntity {
constructor(): void;
setDescription(description: string): gdEventsBasedObject;
getDescription(): string;
@@ -9,13 +9,21 @@ declare class gdEventsBasedObject extends gdObjectsContainer {
getFullName(): string;
setDefaultName(defaultName: string): gdEventsBasedObject;
getDefaultName(): string;
getEventsFunctions(): gdEventsFunctionsContainer;
getPropertyDescriptors(): gdNamedPropertyDescriptorsList;
serializeTo(element: gdSerializerElement): void;
unserializeFrom(project: gdProject, element: gdSerializerElement): void;
static getPropertyActionName(propertyName: string): string;
static getPropertyConditionName(propertyName: string): string;
static getPropertyExpressionName(propertyName: string): string;
insertNewObject(project: gdProject, type: string, name: string, pos: number): gdObject;
insertObject(obj: gdObject, pos: number): gdObject;
hasObjectNamed(name: string): boolean;
getObject(name: string): gdObject;
getObjectAt(pos: number): gdObject;
getObjectPosition(name: string): number;
removeObject(name: string): void;
swapObjects(first: number, second: number): void;
moveObject(oldIndex: number, newIndex: number): void;
moveObjectToAnotherContainer(name: string, newObjectsContainer: gdObjectsContainer, newPosition: number): void;
getObjectsCount(): number;
getObjectGroups(): gdObjectGroupsContainer;
delete(): void;
ptr: number;
};

View File

@@ -0,0 +1,9 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdMeasurementBaseUnit {
constructor(name: string, symbol: string, quantity: string): void;
getName(): string;
getSymbol(): string;
getQuantity(): string;
delete(): void;
ptr: number;
};

View File

@@ -0,0 +1,22 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdMeasurementUnit {
constructor(name: string, label: string, description: string): void;
getName(): string;
getLabel(): string;
getDescription(): string;
getElementsWithWords(): string;
getElementsCount(): number;
getElementPower(elementIndex: number): number;
getElementBaseUnit(elementIndex: number): gdMeasurementBaseUnit;
isUndefined(): boolean;
static applyTranslation(): void;
static getDimensionless(): gdMeasurementUnit;
static getDegreeAngle(): gdMeasurementUnit;
static getSecond(): gdMeasurementUnit;
static getPixel(): gdMeasurementUnit;
static getPixelSpeed(): gdMeasurementUnit;
static getPixelAcceleration(): gdMeasurementUnit;
static getNewton(): gdMeasurementUnit;
delete(): void;
ptr: number;
};

View File

@@ -15,6 +15,8 @@ declare class gdPropertyDescriptor {
setExtraInfo(info: gdVectorString): gdPropertyDescriptor;
getExtraInfo(): gdVectorString;
setHidden(enable: boolean): gdPropertyDescriptor;
getMeasurementUnit(): gdMeasurementUnit;
setMeasurementUnit(measurementUnit: gdMeasurementUnit): gdPropertyDescriptor;
isHidden(): boolean;
serializeTo(element: gdSerializerElement): void;
unserializeFrom(element: gdSerializerElement): void;

View File

@@ -0,0 +1,8 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdPropertyFunctionGenerator {
static generateBehaviorGetterAndSetter(project: gdProject, extension: gdEventsFunctionsExtension, eventsBasedBehavior: gdEventsBasedBehavior, property: gdNamedPropertyDescriptor, isSharedProperties: boolean): void;
static generateObjectGetterAndSetter(project: gdProject, extension: gdEventsFunctionsExtension, eventsBasedObject: gdEventsBasedObject, property: gdNamedPropertyDescriptor): void;
static canGenerateGetterAndSetter(eventsBasedBehavior: gdAbstractEventsBasedEntity, property: gdNamedPropertyDescriptor): boolean;
delete(): void;
ptr: number;
};

View File

@@ -18,6 +18,7 @@ declare class gdValueTypeMetadata {
static isTypeBehavior(parameterType: string): boolean;
static isTypeExpression(type: string, parameterType: string): boolean;
static getPrimitiveValueType(parameterType: string): string;
static convertPropertyTypeToValueType(propertyType: string): string;
serializeTo(element: gdSerializerElement): void;
unserializeFrom(element: gdSerializerElement): void;
delete(): void;

View File

@@ -84,6 +84,8 @@ declare class libGDevelop {
EffectsContainer: Class<gdEffectsContainer>;
Layer: Class<gdLayer>;
PropertyDescriptor: Class<gdPropertyDescriptor>;
MeasurementUnit: Class<gdMeasurementUnit>;
MeasurementBaseUnit: Class<gdMeasurementBaseUnit>;
NamedPropertyDescriptor: Class<gdNamedPropertyDescriptor>;
MapStringPropertyDescriptor: Class<gdMapStringPropertyDescriptor>;
MapStringSerializerValue: Class<gdMapStringSerializerValue>;
@@ -146,6 +148,7 @@ declare class libGDevelop {
UnfilledRequiredBehaviorPropertyProblem: Class<gdUnfilledRequiredBehaviorPropertyProblem>;
VectorUnfilledRequiredBehaviorPropertyProblem: Class<gdVectorUnfilledRequiredBehaviorPropertyProblem>;
WholeProjectRefactorer: Class<gdWholeProjectRefactorer>;
PropertyFunctionGenerator: Class<gdPropertyFunctionGenerator>;
UsedExtensionsFinder: Class<gdUsedExtensionsFinder>;
ExtensionAndBehaviorMetadata: Class<gdExtensionAndBehaviorMetadata>;
ExtensionAndObjectMetadata: Class<gdExtensionAndObjectMetadata>;
@@ -169,6 +172,7 @@ declare class libGDevelop {
EventsFunction_FunctionType: Class<EventsFunction_FunctionType>;
EventsFunction: Class<gdEventsFunction>;
EventsFunctionsContainer: Class<gdEventsFunctionsContainer>;
AbstractEventsBasedEntity: Class<gdAbstractEventsBasedEntity>;
EventsBasedBehavior: Class<gdEventsBasedBehavior>;
EventsBasedBehaviorsList: Class<gdEventsBasedBehaviorsList>;
EventsBasedObject: Class<gdEventsBasedObject>;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@@ -36,7 +36,6 @@
"pixi.js-legacy": "^6.1.2",
"posthog-js": "^1.34.0",
"prop-types": "^15.5.10",
"randomcolor": "^0.5.3",
"raven-js": "^3.19.1",
"react": "16.14.0",
"react-color": "2.13.8",
@@ -33462,11 +33461,6 @@
"safe-buffer": "^5.1.0"
}
},
"node_modules/randomcolor": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/randomcolor/-/randomcolor-0.5.4.tgz",
"integrity": "sha512-nYd4nmTuuwMFzHL6W+UWR5fNERGZeVauho8mrJDUSXdNDbao4rbrUwhuLgKC/j8VCS5+34Ria8CsTDuBjrIrQA=="
},
"node_modules/randomfill": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
@@ -67942,11 +67936,6 @@
"safe-buffer": "^5.1.0"
}
},
"randomcolor": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/randomcolor/-/randomcolor-0.5.4.tgz",
"integrity": "sha512-nYd4nmTuuwMFzHL6W+UWR5fNERGZeVauho8mrJDUSXdNDbao4rbrUwhuLgKC/j8VCS5+34Ria8CsTDuBjrIrQA=="
},
"randomfill": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",

View File

@@ -59,7 +59,6 @@
"pixi.js-legacy": "^6.1.2",
"posthog-js": "^1.34.0",
"prop-types": "^15.5.10",
"randomcolor": "^0.5.3",
"raven-js": "^3.19.1",
"react": "16.14.0",
"react-color": "2.13.8",

View File

@@ -25,6 +25,7 @@
],
"start_url": "./index.html",
"display": "standalone",
"display_override": ["window-controls-overlay"],
"theme_color": "#252525",
"background_color": "#f0f0f0"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 542 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -1 +0,0 @@
A fun demo, using the Physics Engine to build an advanced simulation of a bike, with a person pedaling on it. Try to cross the finish line without falling and as fast as possible!

View File

@@ -1 +0,0 @@
A demo showing how to enhance the "game feel" of your project: VFX, shot trail, ambient sounds and SFX, screenshake, wobble...

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 789 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Some files were not shown because too many files have changed in this diff Show More