mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
97 Commits
mention-bu
...
fix/disabl
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8b2c32bd6a | ||
![]() |
15f3a45d6a | ||
![]() |
f0a4f352cc | ||
![]() |
d16b3e8154 | ||
![]() |
614fb97288 | ||
![]() |
8a40d3645a | ||
![]() |
2b7dadf2a8 | ||
![]() |
c338e16e4f | ||
![]() |
aded08471d | ||
![]() |
cccb59b1c5 | ||
![]() |
3592fb7e62 | ||
![]() |
307c92991c | ||
![]() |
4b3f077669 | ||
![]() |
352bae518e | ||
![]() |
c958f4d522 | ||
![]() |
35bbb37ad2 | ||
![]() |
1d48acc841 | ||
![]() |
87702edccc | ||
![]() |
1f0ba7c19a | ||
![]() |
b4d08a99ad | ||
![]() |
8acaa06e42 | ||
![]() |
27ee85b5d4 | ||
![]() |
bbe2d1854e | ||
![]() |
d338690ff5 | ||
![]() |
571a6d8c1a | ||
![]() |
ddb5157c0a | ||
![]() |
64f01354bc | ||
![]() |
37fd99e542 | ||
![]() |
23be4a5849 | ||
![]() |
64c0ee8f98 | ||
![]() |
e5ecce3abf | ||
![]() |
5c71a4da56 | ||
![]() |
dff99b79cb | ||
![]() |
5fe46ea8ea | ||
![]() |
4a590adac4 | ||
![]() |
279d41cdb7 | ||
![]() |
5cf65a9f62 | ||
![]() |
08b05c13b6 | ||
![]() |
eb55c85f4e | ||
![]() |
8a243440db | ||
![]() |
b3e4e6b89c | ||
![]() |
a1a25f6df4 | ||
![]() |
6114a6cec1 | ||
![]() |
5058964937 | ||
![]() |
4488675540 | ||
![]() |
6a2d2c9e67 | ||
![]() |
b43c42d763 | ||
![]() |
69112183d4 | ||
![]() |
a4c2778b8d | ||
![]() |
f26e56c3bf | ||
![]() |
f5f9944fc4 | ||
![]() |
9467caf1e9 | ||
![]() |
00376f39d5 | ||
![]() |
40b6a34dc5 | ||
![]() |
17d2b8c2c2 | ||
![]() |
935af42d23 | ||
![]() |
d4a8d468cb | ||
![]() |
b16099aee0 | ||
![]() |
c17b918a43 | ||
![]() |
d58e8c7ef9 | ||
![]() |
ddd6b6e3a8 | ||
![]() |
e629c132ea | ||
![]() |
b80e03f153 | ||
![]() |
11e36ff3f1 | ||
![]() |
22de356413 | ||
![]() |
caefa04fbe | ||
![]() |
cf2e7d67d7 | ||
![]() |
685e444b2d | ||
![]() |
a9c1045afd | ||
![]() |
24e0d37583 | ||
![]() |
d44997d372 | ||
![]() |
062aa888f8 | ||
![]() |
de4c2ae4ad | ||
![]() |
29ad7308c3 | ||
![]() |
19b21c280e | ||
![]() |
fbfe8b246a | ||
![]() |
73f66eb51f | ||
![]() |
d62ba2b9a0 | ||
![]() |
323a2b6c2f | ||
![]() |
8e4cccd562 | ||
![]() |
795795ba40 | ||
![]() |
4af86b36e5 | ||
![]() |
b00632a625 | ||
![]() |
6f23f76441 | ||
![]() |
a6cd4b3c5d | ||
![]() |
81d63c41b6 | ||
![]() |
a924840228 | ||
![]() |
b013297c8e | ||
![]() |
ca77a31037 | ||
![]() |
5adb2240d5 | ||
![]() |
9d42be3362 | ||
![]() |
21201dec29 | ||
![]() |
08229cbe1d | ||
![]() |
96e9dd7c4b | ||
![]() |
7dbc687200 | ||
![]() |
7e1f2c6c97 | ||
![]() |
37cba12e4a |
@@ -18,13 +18,13 @@ jobs:
|
|||||||
# Build the **entire** app for macOS (including the GDevelop.js library).
|
# Build the **entire** app for macOS (including the GDevelop.js library).
|
||||||
build-macos:
|
build-macos:
|
||||||
macos:
|
macos:
|
||||||
xcode: 14.2.0
|
xcode: 16.4.0
|
||||||
resource_class: macos.m1.large.gen1
|
resource_class: m4pro.medium
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
# Install Rosetta for AWS CLI and disable TSO to speed up S3 uploads (https://support.circleci.com/hc/en-us/articles/19334402064027-Troubleshooting-slow-uploads-to-S3-for-jobs-using-an-m1-macOS-resource-class)
|
# Install Rosetta for AWS CLI and disable TSO to speed up S3 uploads (https://support.circleci.com/hc/en-us/articles/19334402064027-Troubleshooting-slow-uploads-to-S3-for-jobs-using-an-m1-macOS-resource-class)
|
||||||
- macos/install-rosetta
|
- macos/install-rosetta
|
||||||
- run: sudo sysctl net.inet.tcp.tso=0
|
# - run: sudo sysctl net.inet.tcp.tso=0
|
||||||
|
|
||||||
# Install a recent version of npm to workaround a notarization issue because of a symlink made by npm: https://github.com/electron-userland/electron-builder/issues/7755
|
# Install a recent version of npm to workaround a notarization issue because of a symlink made by npm: https://github.com/electron-userland/electron-builder/issues/7755
|
||||||
# Node.js v20.14.0 comes with npm v10.7.0.
|
# Node.js v20.14.0 comes with npm v10.7.0.
|
||||||
@@ -88,13 +88,35 @@ jobs:
|
|||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: newIDE/electron-app/dist
|
path: newIDE/electron-app/dist
|
||||||
|
|
||||||
|
|
||||||
# Upload artifacts (AWS)
|
# Upload artifacts (AWS)
|
||||||
- run:
|
- run:
|
||||||
name: Deploy to S3 (specific commit)
|
name: Deploy to S3 (specific commit)
|
||||||
command: export PATH=~/.local/bin:$PATH && aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/commit/$(git rev-parse HEAD)/
|
command: |
|
||||||
|
export PATH=~/.local/bin:$PATH
|
||||||
|
for i in 1 2 3 4 5 6 7; do
|
||||||
|
aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/commit/$(git rev-parse HEAD)/ && break
|
||||||
|
echo "Retry $i failed... retrying in 10 seconds"
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
if [ $i -eq 7 ]; then
|
||||||
|
echo "All retries for deployment failed!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
- run:
|
- run:
|
||||||
name: Deploy to S3 (latest)
|
name: Deploy to S3 (latest)
|
||||||
command: export PATH=~/.local/bin:$PATH && aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/latest/
|
command: |
|
||||||
|
export PATH=~/.local/bin:$PATH
|
||||||
|
for i in 1 2 3 4 5 6 7; do
|
||||||
|
aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/latest/ && break
|
||||||
|
echo "Retry $i failed... retrying in 10 seconds"
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
if [ $i -eq 7 ]; then
|
||||||
|
echo "All retries for deployment failed!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Build the app for Linux (using a pre-built GDevelop.js library).
|
# Build the app for Linux (using a pre-built GDevelop.js library).
|
||||||
build-linux:
|
build-linux:
|
||||||
@@ -368,7 +390,7 @@ jobs:
|
|||||||
npm -v
|
npm -v
|
||||||
|
|
||||||
Remove-Item package-lock.json
|
Remove-Item package-lock.json
|
||||||
|
|
||||||
$Env:REQUIRES_EXACT_LIBGD_JS_VERSION = "true"
|
$Env:REQUIRES_EXACT_LIBGD_JS_VERSION = "true"
|
||||||
|
|
||||||
npm install
|
npm install
|
||||||
@@ -425,10 +447,10 @@ jobs:
|
|||||||
|
|
||||||
$Env:GD_SIGNTOOL_THUMBPRINT = ''
|
$Env:GD_SIGNTOOL_THUMBPRINT = ''
|
||||||
|
|
||||||
$Env:GD_SIGNTOOL_SUBJECT_NAME = ''
|
$Env:GD_SIGNTOOL_SUBJECT_NAME = ''
|
||||||
|
|
||||||
$Env:CSC_LINK = ''
|
$Env:CSC_LINK = ''
|
||||||
|
|
||||||
$Env:CSC_KEY_PASSWORD = ''
|
$Env:CSC_KEY_PASSWORD = ''
|
||||||
|
|
||||||
node scripts/build.js --skip-app-build --win appx --publish=never
|
node scripts/build.js --skip-app-build --win appx --publish=never
|
||||||
@@ -445,16 +467,16 @@ jobs:
|
|||||||
name: Install AWS CLI
|
name: Install AWS CLI
|
||||||
command: |
|
command: |
|
||||||
# Install the CLI for the current user
|
# Install the CLI for the current user
|
||||||
|
|
||||||
pip install --quiet --upgrade --user awscli
|
pip install --quiet --upgrade --user awscli
|
||||||
|
|
||||||
# Add the user-Scripts dir to PATH for this step and the next.
|
# Add the user-Scripts dir to PATH for this step and the next.
|
||||||
|
|
||||||
$binDir = (python -m site --user-base) + "\Scripts"
|
$binDir = (python -m site --user-base) + "\Scripts"
|
||||||
$Env:Path += ";$binDir"
|
$Env:Path += ";$binDir"
|
||||||
|
|
||||||
# Sanity check:
|
# Sanity check:
|
||||||
aws --version
|
aws --version
|
||||||
|
|
||||||
# Upload artifacts (S3)
|
# Upload artifacts (S3)
|
||||||
- run:
|
- run:
|
||||||
|
3
.vscode/tasks.json
vendored
3
.vscode/tasks.json
vendored
@@ -38,8 +38,7 @@
|
|||||||
"presentation": {
|
"presentation": {
|
||||||
"reveal": "silent"
|
"reveal": "silent"
|
||||||
},
|
},
|
||||||
"isBackground": true,
|
"isBackground": true
|
||||||
"runOptions": { "instanceLimit": 1, "runOn": "folderOpen" }
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "npm",
|
"type": "npm",
|
||||||
|
@@ -61,10 +61,12 @@ void GroupEvent::UnserializeFrom(gd::Project& project,
|
|||||||
project, events, element.GetChild("events"));
|
project, events, element.GetChild("events"));
|
||||||
|
|
||||||
parameters.clear();
|
parameters.clear();
|
||||||
gd::SerializerElement& parametersElement = element.GetChild("parameters");
|
if (element.HasChild("parameters")) {
|
||||||
parametersElement.ConsiderAsArrayOf("parameters");
|
gd::SerializerElement& parametersElement = element.GetChild("parameters");
|
||||||
for (std::size_t i = 0; i < parametersElement.GetChildrenCount(); ++i)
|
parametersElement.ConsiderAsArrayOf("parameters");
|
||||||
parameters.push_back(parametersElement.GetChild(i).GetValue().GetString());
|
for (std::size_t i = 0; i < parametersElement.GetChildrenCount(); ++i)
|
||||||
|
parameters.push_back(parametersElement.GetChild(i).GetValue().GetString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupEvent::SetBackgroundColor(unsigned int colorR_,
|
void GroupEvent::SetBackgroundColor(unsigned int colorR_,
|
||||||
|
@@ -163,6 +163,21 @@ void LinkEvent::UnserializeFrom(gd::Project& project,
|
|||||||
// end of compatibility code
|
// end of compatibility code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<gd::String> LinkEvent::GetAllSearchableStrings() const {
|
||||||
|
vector<gd::String> allSearchableStrings;
|
||||||
|
|
||||||
|
allSearchableStrings.push_back(target);
|
||||||
|
|
||||||
|
return allSearchableStrings;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LinkEvent::ReplaceAllSearchableStrings(
|
||||||
|
std::vector<gd::String> newSearchableString) {
|
||||||
|
if (newSearchableString[0] == target) return false;
|
||||||
|
SetTarget(newSearchableString[0]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool LinkEvent::AcceptVisitor(gd::EventVisitor &eventVisitor) {
|
bool LinkEvent::AcceptVisitor(gd::EventVisitor &eventVisitor) {
|
||||||
return BaseEvent::AcceptVisitor(eventVisitor) ||
|
return BaseEvent::AcceptVisitor(eventVisitor) ||
|
||||||
eventVisitor.VisitLinkEvent(*this);
|
eventVisitor.VisitLinkEvent(*this);
|
||||||
|
@@ -109,6 +109,10 @@ class GD_CORE_API LinkEvent : public gd::BaseEvent {
|
|||||||
|
|
||||||
virtual bool IsExecutable() const override { return true; };
|
virtual bool IsExecutable() const override { return true; };
|
||||||
|
|
||||||
|
virtual std::vector<gd::String> GetAllSearchableStrings() const override;
|
||||||
|
virtual bool ReplaceAllSearchableStrings(
|
||||||
|
std::vector<gd::String> newSearchableString) override;
|
||||||
|
|
||||||
virtual void SerializeTo(SerializerElement& element) const override;
|
virtual void SerializeTo(SerializerElement& element) const override;
|
||||||
virtual void UnserializeFrom(gd::Project& project,
|
virtual void UnserializeFrom(gd::Project& project,
|
||||||
const SerializerElement& element) override;
|
const SerializerElement& element) override;
|
||||||
|
@@ -286,6 +286,20 @@ class GD_CORE_API BaseEvent {
|
|||||||
* \brief True if the event should be folded in the events editor.
|
* \brief True if the event should be folded in the events editor.
|
||||||
*/
|
*/
|
||||||
bool IsFolded() const { return folded; }
|
bool IsFolded() const { return folded; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the AI generated event ID.
|
||||||
|
*/
|
||||||
|
void SetAiGeneratedEventId(const gd::String& aiGeneratedEventId_) {
|
||||||
|
aiGeneratedEventId = aiGeneratedEventId_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the AI generated event ID.
|
||||||
|
*/
|
||||||
|
const gd::String& GetAiGeneratedEventId() const {
|
||||||
|
return aiGeneratedEventId;
|
||||||
|
}
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
std::weak_ptr<gd::BaseEvent>
|
std::weak_ptr<gd::BaseEvent>
|
||||||
@@ -304,6 +318,7 @@ class GD_CORE_API BaseEvent {
|
|||||||
bool disabled; ///< True if the event is disabled and must not be executed
|
bool disabled; ///< True if the event is disabled and must not be executed
|
||||||
gd::String type; ///< Type of the event. Must be assigned at the creation.
|
gd::String type; ///< Type of the event. Must be assigned at the creation.
|
||||||
///< Used for saving the event for instance.
|
///< Used for saving the event for instance.
|
||||||
|
gd::String aiGeneratedEventId; ///< When generated by an AI/external tool.
|
||||||
|
|
||||||
static gd::EventsList badSubEvents;
|
static gd::EventsList badSubEvents;
|
||||||
static gd::VariablesContainer badLocalVariables;
|
static gd::VariablesContainer badLocalVariables;
|
||||||
|
@@ -221,6 +221,8 @@ void EventsListSerialization::UnserializeEventsFrom(
|
|||||||
|
|
||||||
event->SetDisabled(eventElem.GetBoolAttribute("disabled", false));
|
event->SetDisabled(eventElem.GetBoolAttribute("disabled", false));
|
||||||
event->SetFolded(eventElem.GetBoolAttribute("folded", false));
|
event->SetFolded(eventElem.GetBoolAttribute("folded", false));
|
||||||
|
event->SetAiGeneratedEventId(
|
||||||
|
eventElem.GetStringAttribute("aiGeneratedEventId", ""));
|
||||||
|
|
||||||
list.InsertEvent(event, list.GetEventsCount());
|
list.InsertEvent(event, list.GetEventsCount());
|
||||||
}
|
}
|
||||||
@@ -236,6 +238,8 @@ void EventsListSerialization::SerializeEventsTo(const EventsList& list,
|
|||||||
if (event.IsDisabled())
|
if (event.IsDisabled())
|
||||||
eventElem.SetAttribute("disabled", event.IsDisabled());
|
eventElem.SetAttribute("disabled", event.IsDisabled());
|
||||||
if (event.IsFolded()) eventElem.SetAttribute("folded", event.IsFolded());
|
if (event.IsFolded()) eventElem.SetAttribute("folded", event.IsFolded());
|
||||||
|
if (!event.GetAiGeneratedEventId().empty())
|
||||||
|
eventElem.SetAttribute("aiGeneratedEventId", event.GetAiGeneratedEventId());
|
||||||
eventElem.AddChild("type").SetValue(event.GetType());
|
eventElem.AddChild("type").SetValue(event.GetType());
|
||||||
|
|
||||||
event.SerializeTo(eventElem);
|
event.SerializeTo(eventElem);
|
||||||
|
@@ -37,8 +37,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
|||||||
.SetIcon("res/actions/position24_black.png");
|
.SetIcon("res/actions/position24_black.png");
|
||||||
extension.AddInstructionOrExpressionGroupMetadata(_("Angle"))
|
extension.AddInstructionOrExpressionGroupMetadata(_("Angle"))
|
||||||
.SetIcon("res/actions/direction24_black.png");
|
.SetIcon("res/actions/direction24_black.png");
|
||||||
extension.AddInstructionOrExpressionGroupMetadata(_("Size"))
|
extension.AddInstructionOrExpressionGroupMetadata(_("Size")).SetIcon(
|
||||||
.SetIcon("res/actions/scale24_black.png");
|
"res/actions/scale24_black.png");
|
||||||
|
|
||||||
gd::ObjectMetadata& obj = extension.AddObject<gd::ObjectConfiguration>(
|
gd::ObjectMetadata& obj = extension.AddObject<gd::ObjectConfiguration>(
|
||||||
"", _("Base object"), _("Base object"), "res/objeticon24.png");
|
"", _("Base object"), _("Base object"), "res/objeticon24.png");
|
||||||
@@ -235,7 +235,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
|||||||
|
|
||||||
obj.AddAction("SetAngle",
|
obj.AddAction("SetAngle",
|
||||||
_("Angle"),
|
_("Angle"),
|
||||||
_("Change the angle of rotation of an object (in degrees)."),
|
_("Change the angle of rotation of an object (in degrees). For "
|
||||||
|
"3D objects, this is the rotation around the Z axis."),
|
||||||
_("the angle"),
|
_("the angle"),
|
||||||
_("Angle"),
|
_("Angle"),
|
||||||
"res/actions/direction24_black.png",
|
"res/actions/direction24_black.png",
|
||||||
@@ -250,7 +251,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
|||||||
obj.AddAction("Rotate",
|
obj.AddAction("Rotate",
|
||||||
_("Rotate"),
|
_("Rotate"),
|
||||||
_("Rotate an object, clockwise if the speed is positive, "
|
_("Rotate an object, clockwise if the speed is positive, "
|
||||||
"counterclockwise otherwise."),
|
"counterclockwise otherwise. For 3D objects, this is the "
|
||||||
|
"rotation around the Z axis."),
|
||||||
_("Rotate _PARAM0_ at speed _PARAM1_ deg/second"),
|
_("Rotate _PARAM0_ at speed _PARAM1_ deg/second"),
|
||||||
_("Angle"),
|
_("Angle"),
|
||||||
"res/actions/rotate24_black.png",
|
"res/actions/rotate24_black.png",
|
||||||
@@ -634,7 +636,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
|||||||
|
|
||||||
obj.AddCondition("Angle",
|
obj.AddCondition("Angle",
|
||||||
_("Angle"),
|
_("Angle"),
|
||||||
_("Compare the angle of the specified object."),
|
_("Compare the angle, in degrees, of the specified object. "
|
||||||
|
"For 3D objects, this is the angle around the Z axis."),
|
||||||
_("the angle (in degrees)"),
|
_("the angle (in degrees)"),
|
||||||
_("Angle"),
|
_("Angle"),
|
||||||
"res/conditions/direction24_black.png",
|
"res/conditions/direction24_black.png",
|
||||||
@@ -835,14 +838,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
|||||||
.MarkAsAdvanced()
|
.MarkAsAdvanced()
|
||||||
.SetRelevantForLayoutEventsOnly();
|
.SetRelevantForLayoutEventsOnly();
|
||||||
|
|
||||||
obj.AddAction(
|
obj.AddAction("PushBooleanToObjectVariable",
|
||||||
"PushBooleanToObjectVariable",
|
_("Add value to object array variable"),
|
||||||
_("Add value to object array variable"),
|
_("Adds a boolean to the end of an object array variable."),
|
||||||
_("Adds a boolean to the end of an object array variable."),
|
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||||
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
_("Variables ❯ Arrays and structures"),
|
||||||
_("Variables ❯ Arrays and structures"),
|
"res/actions/var24.png",
|
||||||
"res/actions/var24.png",
|
"res/actions/var.png")
|
||||||
"res/actions/var.png")
|
|
||||||
.AddParameter("object", _("Object"))
|
.AddParameter("object", _("Object"))
|
||||||
.AddParameter("objectvar", _("Array variable"))
|
.AddParameter("objectvar", _("Array variable"))
|
||||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||||
@@ -1268,7 +1270,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
|||||||
|
|
||||||
obj.AddExpression("Angle",
|
obj.AddExpression("Angle",
|
||||||
_("Angle"),
|
_("Angle"),
|
||||||
_("Current angle, in degrees, of the object"),
|
_("Current angle, in degrees, of the object. For 3D "
|
||||||
|
"objects, this is the angle around the Z axis."),
|
||||||
_("Angle"),
|
_("Angle"),
|
||||||
"res/actions/direction_black.png")
|
"res/actions/direction_black.png")
|
||||||
.AddParameter("object", _("Object"));
|
.AddParameter("object", _("Object"));
|
||||||
@@ -1571,7 +1574,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
|||||||
extension
|
extension
|
||||||
.AddAction("Create",
|
.AddAction("Create",
|
||||||
_("Create an object"),
|
_("Create an object"),
|
||||||
_("Create an object at specified position"),
|
_("Create an instance of the object at the specified position."
|
||||||
|
"The created object instance will be available for the next "
|
||||||
|
"actions and sub-events."),
|
||||||
_("Create object _PARAM1_ at position _PARAM2_;_PARAM3_ "
|
_("Create object _PARAM1_ at position _PARAM2_;_PARAM3_ "
|
||||||
"(layer: _PARAM4_)"),
|
"(layer: _PARAM4_)"),
|
||||||
"",
|
"",
|
||||||
|
@@ -72,7 +72,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
|||||||
|
|
||||||
extension
|
extension
|
||||||
.AddExpression("normalize",
|
.AddExpression("normalize",
|
||||||
_("Normalize a value between `min` and `max` to a value between 0 and 1."),
|
_("Normalize a value between `min` and `max` to a value "
|
||||||
|
"between 0 and 1."),
|
||||||
_("Remap a value between 0 and 1."),
|
_("Remap a value between 0 and 1."),
|
||||||
"",
|
"",
|
||||||
"res/mathfunction.png")
|
"res/mathfunction.png")
|
||||||
@@ -124,7 +125,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
|||||||
extension
|
extension
|
||||||
.AddExpression("mod",
|
.AddExpression("mod",
|
||||||
_("Modulo"),
|
_("Modulo"),
|
||||||
_("x mod y"),
|
_("Compute \"x mod y\". GDevelop does NOT support the \% "
|
||||||
|
"operator. Use this mod(x, y) function instead."),
|
||||||
"",
|
"",
|
||||||
"res/mathfunction.png")
|
"res/mathfunction.png")
|
||||||
.AddParameter("expression", _("x (as in x mod y)"))
|
.AddParameter("expression", _("x (as in x mod y)"))
|
||||||
@@ -184,11 +186,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
|||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
.AddExpression("asinh",
|
.AddExpression(
|
||||||
_("Arcsine"),
|
"asinh", _("Arcsine"), _("Arcsine"), "", "res/mathfunction.png")
|
||||||
_("Arcsine"),
|
|
||||||
"",
|
|
||||||
"res/mathfunction.png")
|
|
||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
@@ -218,11 +217,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
|||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
.AddExpression("cbrt",
|
.AddExpression(
|
||||||
_("Cube root"),
|
"cbrt", _("Cube root"), _("Cube root"), "", "res/mathfunction.png")
|
||||||
_("Cube root"),
|
|
||||||
"",
|
|
||||||
"res/mathfunction.png")
|
|
||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
@@ -260,12 +256,13 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
|||||||
.AddParameter("expression", _("Expression"), "", true);
|
.AddParameter("expression", _("Expression"), "", true);
|
||||||
|
|
||||||
extension
|
extension
|
||||||
.AddExpression("cos",
|
.AddExpression(
|
||||||
_("Cosine"),
|
"cos",
|
||||||
_("Cosine of an angle (in radian). "
|
_("Cosine"),
|
||||||
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
|
_("Cosine of an angle (in radian). "
|
||||||
"",
|
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
|
||||||
"res/mathfunction.png")
|
"",
|
||||||
|
"res/mathfunction.png")
|
||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
@@ -293,29 +290,20 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
|||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
.AddExpression("int",
|
.AddExpression(
|
||||||
_("Round"),
|
"int", _("Round"), _("Round a number"), "", "res/mathfunction.png")
|
||||||
_("Round a number"),
|
|
||||||
"",
|
|
||||||
"res/mathfunction.png")
|
|
||||||
.SetHidden()
|
.SetHidden()
|
||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
.AddExpression("rint",
|
.AddExpression(
|
||||||
_("Round"),
|
"rint", _("Round"), _("Round a number"), "", "res/mathfunction.png")
|
||||||
_("Round a number"),
|
|
||||||
"",
|
|
||||||
"res/mathfunction.png")
|
|
||||||
.SetHidden()
|
.SetHidden()
|
||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
.AddExpression("round",
|
.AddExpression(
|
||||||
_("Round"),
|
"round", _("Round"), _("Round a number"), "", "res/mathfunction.png")
|
||||||
_("Round a number"),
|
|
||||||
"",
|
|
||||||
"res/mathfunction.png")
|
|
||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
@@ -324,8 +312,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
|||||||
_("Round a number to the Nth decimal place"),
|
_("Round a number to the Nth decimal place"),
|
||||||
"",
|
"",
|
||||||
"res/mathfunction.png")
|
"res/mathfunction.png")
|
||||||
.AddParameter("expression", _("Expression"))
|
.AddParameter("expression", _("Number to Round"))
|
||||||
.AddParameter("expression", _("Expression"), "", true);
|
.AddParameter("expression", _("Decimal Places"), "", true);
|
||||||
|
|
||||||
extension
|
extension
|
||||||
.AddExpression("exp",
|
.AddExpression("exp",
|
||||||
@@ -336,19 +324,13 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
|||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
.AddExpression("log",
|
.AddExpression(
|
||||||
_("Logarithm"),
|
"log", _("Logarithm"), _("Logarithm"), "", "res/mathfunction.png")
|
||||||
_("Logarithm"),
|
|
||||||
"",
|
|
||||||
"res/mathfunction.png")
|
|
||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
.AddExpression("ln",
|
.AddExpression(
|
||||||
_("Logarithm"),
|
"ln", _("Logarithm"), _("Logarithm"), "", "res/mathfunction.png")
|
||||||
_("Logarithm"),
|
|
||||||
"",
|
|
||||||
"res/mathfunction.png")
|
|
||||||
.SetHidden()
|
.SetHidden()
|
||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
@@ -387,11 +369,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
|||||||
.AddParameter("expression", _("The exponent (n in x^n)"));
|
.AddParameter("expression", _("The exponent (n in x^n)"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
.AddExpression("sec",
|
.AddExpression(
|
||||||
_("Secant"),
|
"sec", _("Secant"), _("Secant"), "", "res/mathfunction.png")
|
||||||
_("Secant"),
|
|
||||||
"",
|
|
||||||
"res/mathfunction.png")
|
|
||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
@@ -403,12 +382,13 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
|||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
.AddExpression("sin",
|
.AddExpression(
|
||||||
_("Sine"),
|
"sin",
|
||||||
_("Sine of an angle (in radian). "
|
_("Sine"),
|
||||||
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
|
_("Sine of an angle (in radian). "
|
||||||
"",
|
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
|
||||||
"res/mathfunction.png")
|
"",
|
||||||
|
"res/mathfunction.png")
|
||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
@@ -428,12 +408,13 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
|||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
.AddExpression("tan",
|
.AddExpression(
|
||||||
_("Tangent"),
|
"tan",
|
||||||
_("Tangent of an angle (in radian). "
|
_("Tangent"),
|
||||||
"If you want to use degrees, use`ToRad`: `tan(ToRad(45))`."),
|
_("Tangent of an angle (in radian). "
|
||||||
"",
|
"If you want to use degrees, use`ToRad`: `tan(ToRad(45))`."),
|
||||||
"res/mathfunction.png")
|
"",
|
||||||
|
"res/mathfunction.png")
|
||||||
.AddParameter("expression", _("Expression"));
|
.AddParameter("expression", _("Expression"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
@@ -463,26 +444,28 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
|||||||
.AddParameter("expression", _("x (in a+(b-a)*x)"));
|
.AddParameter("expression", _("x (in a+(b-a)*x)"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
.AddExpression("XFromAngleAndDistance",
|
.AddExpression(
|
||||||
_("X position from angle and distance"),
|
"XFromAngleAndDistance",
|
||||||
_("Compute the X position when given an angle and distance "
|
_("X position from angle and distance"),
|
||||||
"relative to the origin (0;0). This is also known as "
|
_("Compute the X position when given an angle and distance "
|
||||||
"getting the cartesian coordinates of a 2D vector, using "
|
"relative to the origin (0;0). This is also known as "
|
||||||
"its polar coordinates."),
|
"getting the cartesian coordinates of a 2D vector, using "
|
||||||
"",
|
"its polar coordinates."),
|
||||||
"res/mathfunction.png")
|
"",
|
||||||
|
"res/mathfunction.png")
|
||||||
.AddParameter("expression", _("Angle, in degrees"))
|
.AddParameter("expression", _("Angle, in degrees"))
|
||||||
.AddParameter("expression", _("Distance"));
|
.AddParameter("expression", _("Distance"));
|
||||||
|
|
||||||
extension
|
extension
|
||||||
.AddExpression("YFromAngleAndDistance",
|
.AddExpression(
|
||||||
_("Y position from angle and distance"),
|
"YFromAngleAndDistance",
|
||||||
_("Compute the Y position when given an angle and distance "
|
_("Y position from angle and distance"),
|
||||||
"relative to the origin (0;0). This is also known as "
|
_("Compute the Y position when given an angle and distance "
|
||||||
"getting the cartesian coordinates of a 2D vector, using "
|
"relative to the origin (0;0). This is also known as "
|
||||||
"its polar coordinates."),
|
"getting the cartesian coordinates of a 2D vector, using "
|
||||||
"",
|
"its polar coordinates."),
|
||||||
"res/mathfunction.png")
|
"",
|
||||||
|
"res/mathfunction.png")
|
||||||
.AddParameter("expression", _("Angle, in degrees"))
|
.AddParameter("expression", _("Angle, in degrees"))
|
||||||
.AddParameter("expression", _("Distance"));
|
.AddParameter("expression", _("Distance"));
|
||||||
|
|
||||||
@@ -497,7 +480,8 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
|||||||
extension
|
extension
|
||||||
.AddExpression("lerpAngle",
|
.AddExpression("lerpAngle",
|
||||||
_("Lerp (Linear interpolation) between two angles"),
|
_("Lerp (Linear interpolation) between two angles"),
|
||||||
_("Linearly interpolates between two angles (in degrees) by taking the shortest direction around the circle."),
|
_("Linearly interpolates between two angles (in degrees) "
|
||||||
|
"by taking the shortest direction around the circle."),
|
||||||
"",
|
"",
|
||||||
"res/mathfunction.png")
|
"res/mathfunction.png")
|
||||||
.AddParameter("expression", _("Starting angle, in degrees"))
|
.AddParameter("expression", _("Starting angle, in degrees"))
|
||||||
|
@@ -779,6 +779,26 @@ gd::String PlatformExtension::GetBehaviorFullType(
|
|||||||
return extensionName + separator + behaviorName;
|
return extensionName + separator + behaviorName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gd::String PlatformExtension::GetExtensionFromFullBehaviorType(
|
||||||
|
const gd::String& type) {
|
||||||
|
const auto separatorIndex =
|
||||||
|
type.find(PlatformExtension::GetNamespaceSeparator());
|
||||||
|
if (separatorIndex == std::string::npos) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return type.substr(0, separatorIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
gd::String PlatformExtension::GetBehaviorNameFromFullBehaviorType(
|
||||||
|
const gd::String& type) {
|
||||||
|
const auto separatorIndex =
|
||||||
|
type.find(PlatformExtension::GetNamespaceSeparator());
|
||||||
|
if (separatorIndex == std::string::npos) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return type.substr(separatorIndex + 2);
|
||||||
|
}
|
||||||
|
|
||||||
gd::String PlatformExtension::GetObjectEventsFunctionFullType(
|
gd::String PlatformExtension::GetObjectEventsFunctionFullType(
|
||||||
const gd::String& extensionName,
|
const gd::String& extensionName,
|
||||||
const gd::String& objectName,
|
const gd::String& objectName,
|
||||||
|
@@ -651,6 +651,10 @@ class GD_CORE_API PlatformExtension {
|
|||||||
static gd::String GetBehaviorFullType(const gd::String& extensionName,
|
static gd::String GetBehaviorFullType(const gd::String& extensionName,
|
||||||
const gd::String& behaviorName);
|
const gd::String& behaviorName);
|
||||||
|
|
||||||
|
static gd::String GetExtensionFromFullBehaviorType(const gd::String& type);
|
||||||
|
|
||||||
|
static gd::String GetBehaviorNameFromFullBehaviorType(const gd::String& type);
|
||||||
|
|
||||||
static gd::String GetObjectEventsFunctionFullType(
|
static gd::String GetObjectEventsFunctionFullType(
|
||||||
const gd::String& extensionName,
|
const gd::String& extensionName,
|
||||||
const gd::String& objectName,
|
const gd::String& objectName,
|
||||||
|
@@ -1781,6 +1781,14 @@ void WholeProjectRefactorer::DoRenameBehavior(
|
|||||||
projectBrowser.ExposeFunctions(project, behaviorParameterRenamer);
|
projectBrowser.ExposeFunctions(project, behaviorParameterRenamer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WholeProjectRefactorer::UpdateBehaviorsSharedData(gd::Project &project) {
|
||||||
|
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
|
||||||
|
gd::Layout &layout = project.GetLayout(i);
|
||||||
|
|
||||||
|
layout.UpdateBehaviorsSharedData(project);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WholeProjectRefactorer::DoRenameObject(
|
void WholeProjectRefactorer::DoRenameObject(
|
||||||
gd::Project &project, const gd::String &oldObjectType,
|
gd::Project &project, const gd::String &oldObjectType,
|
||||||
const gd::String &newObjectType, const gd::ProjectBrowser &projectBrowser) {
|
const gd::String &newObjectType, const gd::ProjectBrowser &projectBrowser) {
|
||||||
|
@@ -704,6 +704,16 @@ class GD_CORE_API WholeProjectRefactorer {
|
|||||||
static size_t GetLayoutAndExternalLayoutLayerInstancesCount(
|
static size_t GetLayoutAndExternalLayoutLayerInstancesCount(
|
||||||
gd::Project &project, gd::Layout &layout, const gd::String &layerName);
|
gd::Project &project, gd::Layout &layout, const gd::String &layerName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This ensures that the scenes had an instance of shared data for
|
||||||
|
* every behavior of every object that can be used on the scene
|
||||||
|
* (i.e. the objects of the scene and the global objects)
|
||||||
|
*
|
||||||
|
* Must be called when a behavior have been added/deleted
|
||||||
|
* from a global object or an object has been made global.
|
||||||
|
*/
|
||||||
|
static void UpdateBehaviorsSharedData(gd::Project &project);
|
||||||
|
|
||||||
virtual ~WholeProjectRefactorer(){};
|
virtual ~WholeProjectRefactorer(){};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -250,25 +250,28 @@ void CustomObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker& wor
|
|||||||
}
|
}
|
||||||
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
|
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
|
||||||
|
|
||||||
if (isMarkedAsOverridingEventsBasedObjectChildrenConfiguration) {
|
if (IsForcedToOverrideEventsBasedObjectChildrenConfiguration()) {
|
||||||
|
for (auto &childObject : eventsBasedObject.GetObjects().GetObjects()) {
|
||||||
|
auto &configuration = GetChildObjectConfiguration(childObject->GetName());
|
||||||
|
configuration.ExposeResources(worker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (eventsBasedObject.GetVariants().HasVariantNamed(variantName)) {
|
||||||
|
for (auto &childObject : eventsBasedObject.GetVariants()
|
||||||
|
.GetVariant(variantName)
|
||||||
|
.GetObjects()
|
||||||
|
.GetObjects()) {
|
||||||
|
childObject->GetConfiguration().ExposeResources(worker);
|
||||||
|
}
|
||||||
|
} else if (isMarkedAsOverridingEventsBasedObjectChildrenConfiguration) {
|
||||||
for (auto &childObject : eventsBasedObject.GetObjects().GetObjects()) {
|
for (auto &childObject : eventsBasedObject.GetObjects().GetObjects()) {
|
||||||
auto &configuration = GetChildObjectConfiguration(childObject->GetName());
|
auto &configuration = GetChildObjectConfiguration(childObject->GetName());
|
||||||
configuration.ExposeResources(worker);
|
configuration.ExposeResources(worker);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (variantName.empty() ||
|
for (auto &childObject :
|
||||||
!eventsBasedObject.GetVariants().HasVariantNamed(variantName)) {
|
eventsBasedObject.GetDefaultVariant().GetObjects().GetObjects()) {
|
||||||
for (auto &childObject :
|
childObject->GetConfiguration().ExposeResources(worker);
|
||||||
eventsBasedObject.GetDefaultVariant().GetObjects().GetObjects()) {
|
|
||||||
childObject->GetConfiguration().ExposeResources(worker);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (auto &childObject : eventsBasedObject.GetVariants()
|
|
||||||
.GetVariant(variantName)
|
|
||||||
.GetObjects()
|
|
||||||
.GetObjects()) {
|
|
||||||
childObject->GetConfiguration().ExposeResources(worker);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -78,6 +78,15 @@ public:
|
|||||||
variantName = variantName_;
|
variantName = variantName_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legacy events-based objects don't have any instance in their default
|
||||||
|
* variant since there wasn't a graphical editor at the time. In this case,
|
||||||
|
* the editor doesn't allow to choose a variant, but a variant may have stayed
|
||||||
|
* after a user rolled back the extension. This variant must be ignored.
|
||||||
|
*
|
||||||
|
* @return true when its events-based object doesn't have any initial
|
||||||
|
* instance.
|
||||||
|
*/
|
||||||
bool IsForcedToOverrideEventsBasedObjectChildrenConfiguration() const;
|
bool IsForcedToOverrideEventsBasedObjectChildrenConfiguration() const;
|
||||||
|
|
||||||
bool IsMarkedAsOverridingEventsBasedObjectChildrenConfiguration() const {
|
bool IsMarkedAsOverridingEventsBasedObjectChildrenConfiguration() const {
|
||||||
|
@@ -8,6 +8,8 @@
|
|||||||
#include "GDCore/Serialization/SerializerElement.h"
|
#include "GDCore/Serialization/SerializerElement.h"
|
||||||
|
|
||||||
namespace gd {
|
namespace gd {
|
||||||
|
|
||||||
|
gd::String Effect::badStringParameterValue;
|
||||||
|
|
||||||
void Effect::SerializeTo(SerializerElement& element) const {
|
void Effect::SerializeTo(SerializerElement& element) const {
|
||||||
element.SetAttribute("name", GetName());
|
element.SetAttribute("name", GetName());
|
||||||
|
@@ -3,8 +3,7 @@
|
|||||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||||
* reserved. This project is released under the MIT License.
|
* reserved. This project is released under the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef GDCORE_EFFECT_H
|
#pragma once
|
||||||
#define GDCORE_EFFECT_H
|
|
||||||
#include <map>
|
#include <map>
|
||||||
namespace gd {
|
namespace gd {
|
||||||
class SerializerElement;
|
class SerializerElement;
|
||||||
@@ -35,28 +34,43 @@ class GD_CORE_API Effect {
|
|||||||
void SetFolded(bool fold = true) { folded = fold; }
|
void SetFolded(bool fold = true) { folded = fold; }
|
||||||
bool IsFolded() const { return folded; }
|
bool IsFolded() const { return folded; }
|
||||||
|
|
||||||
void SetDoubleParameter(const gd::String& name, double value) {
|
void SetDoubleParameter(const gd::String &name, double value) {
|
||||||
doubleParameters[name] = value;
|
doubleParameters[name] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
double GetDoubleParameter(const gd::String& name) {
|
double GetDoubleParameter(const gd::String &name) const {
|
||||||
return doubleParameters[name];
|
auto itr = doubleParameters.find(name);
|
||||||
|
return itr == doubleParameters.end() ? 0 : itr->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetStringParameter(const gd::String& name, const gd::String& value) {
|
bool HasDoubleParameter(const gd::String &name) const {
|
||||||
|
return doubleParameters.find(name) != doubleParameters.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetStringParameter(const gd::String &name, const gd::String &value) {
|
||||||
stringParameters[name] = value;
|
stringParameters[name] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gd::String& GetStringParameter(const gd::String& name) {
|
const gd::String &GetStringParameter(const gd::String &name) const {
|
||||||
return stringParameters[name];
|
auto itr = stringParameters.find(name);
|
||||||
|
return itr == stringParameters.end() ? badStringParameterValue : itr->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetBooleanParameter(const gd::String& name, bool value) {
|
bool HasStringParameter(const gd::String &name) const {
|
||||||
|
return stringParameters.find(name) != stringParameters.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBooleanParameter(const gd::String &name, bool value) {
|
||||||
booleanParameters[name] = value;
|
booleanParameters[name] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetBooleanParameter(const gd::String& name) {
|
bool GetBooleanParameter(const gd::String &name) const {
|
||||||
return booleanParameters[name];
|
auto itr = booleanParameters.find(name);
|
||||||
|
return itr == booleanParameters.end() ? false : itr->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasBooleanParameter(const gd::String &name) const {
|
||||||
|
return booleanParameters.find(name) != booleanParameters.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<gd::String, double>& GetAllDoubleParameters() const {
|
const std::map<gd::String, double>& GetAllDoubleParameters() const {
|
||||||
@@ -94,7 +108,9 @@ class GD_CORE_API Effect {
|
|||||||
std::map<gd::String, double> doubleParameters; ///< Values of parameters being doubles, keyed by names.
|
std::map<gd::String, double> doubleParameters; ///< Values of parameters being doubles, keyed by names.
|
||||||
std::map<gd::String, gd::String> stringParameters; ///< Values of parameters being strings, keyed by names.
|
std::map<gd::String, gd::String> stringParameters; ///< Values of parameters being strings, keyed by names.
|
||||||
std::map<gd::String, bool> booleanParameters; ///< Values of parameters being booleans, keyed by names.
|
std::map<gd::String, bool> booleanParameters; ///< Values of parameters being booleans, keyed by names.
|
||||||
|
|
||||||
|
static gd::String badStringParameterValue; ///< Empty string returned by
|
||||||
|
///< GeStringParameter
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gd
|
} // namespace gd
|
||||||
#endif
|
|
||||||
|
@@ -83,6 +83,9 @@ void EventsFunctionsExtension::SerializeTo(SerializerElement& element, bool isEx
|
|||||||
element.SetAttribute("iconUrl", iconUrl);
|
element.SetAttribute("iconUrl", iconUrl);
|
||||||
element.SetAttribute("helpPath", helpPath);
|
element.SetAttribute("helpPath", helpPath);
|
||||||
element.SetAttribute("gdevelopVersion", gdevelopVersion);
|
element.SetAttribute("gdevelopVersion", gdevelopVersion);
|
||||||
|
if (changelog.GetChangesCount() > 0) {
|
||||||
|
changelog.SerializeTo(element.AddChild("changelog"));
|
||||||
|
}
|
||||||
auto& dependenciesElement = element.AddChild("dependencies");
|
auto& dependenciesElement = element.AddChild("dependencies");
|
||||||
dependenciesElement.ConsiderAsArray();
|
dependenciesElement.ConsiderAsArray();
|
||||||
for (auto& dependency : dependencies)
|
for (auto& dependency : dependencies)
|
||||||
@@ -139,6 +142,9 @@ void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
|
|||||||
iconUrl = element.GetStringAttribute("iconUrl");
|
iconUrl = element.GetStringAttribute("iconUrl");
|
||||||
helpPath = element.GetStringAttribute("helpPath");
|
helpPath = element.GetStringAttribute("helpPath");
|
||||||
gdevelopVersion = element.GetStringAttribute("gdevelopVersion");
|
gdevelopVersion = element.GetStringAttribute("gdevelopVersion");
|
||||||
|
if (element.HasChild("changelog")) {
|
||||||
|
changelog.UnserializeFrom(element.GetChild("changelog"));
|
||||||
|
}
|
||||||
|
|
||||||
if (element.HasChild("origin")) {
|
if (element.HasChild("origin")) {
|
||||||
gd::String originName =
|
gd::String originName =
|
||||||
|
@@ -12,9 +12,11 @@
|
|||||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||||
#include "GDCore/Project/EventsBasedObject.h"
|
#include "GDCore/Project/EventsBasedObject.h"
|
||||||
#include "GDCore/Project/EventsFunctionsContainer.h"
|
#include "GDCore/Project/EventsFunctionsContainer.h"
|
||||||
|
#include "GDCore/Project/EventsFunctionsExtensionChangelog.h"
|
||||||
#include "GDCore/Project/VariablesContainer.h"
|
#include "GDCore/Project/VariablesContainer.h"
|
||||||
#include "GDCore/String.h"
|
#include "GDCore/String.h"
|
||||||
#include "GDCore/Tools/SerializableWithNameList.h"
|
#include "GDCore/Tools/SerializableWithNameList.h"
|
||||||
|
|
||||||
namespace gd {
|
namespace gd {
|
||||||
class SerializerElement;
|
class SerializerElement;
|
||||||
class Project;
|
class Project;
|
||||||
@@ -406,6 +408,7 @@ class GD_CORE_API EventsFunctionsExtension {
|
|||||||
gd::String helpPath; ///< The relative path to the help for this extension in
|
gd::String helpPath; ///< The relative path to the help for this extension in
|
||||||
///< the documentation (or an absolute URL).
|
///< the documentation (or an absolute URL).
|
||||||
gd::String gdevelopVersion;
|
gd::String gdevelopVersion;
|
||||||
|
gd::EventsFunctionsExtensionChangelog changelog;
|
||||||
gd::SerializableWithNameList<EventsBasedBehavior> eventsBasedBehaviors;
|
gd::SerializableWithNameList<EventsBasedBehavior> eventsBasedBehaviors;
|
||||||
gd::SerializableWithNameList<EventsBasedObject> eventsBasedObjects;
|
gd::SerializableWithNameList<EventsBasedObject> eventsBasedObjects;
|
||||||
std::vector<gd::DependencyMetadata> dependencies;
|
std::vector<gd::DependencyMetadata> dependencies;
|
||||||
|
105
Core/GDCore/Project/EventsFunctionsExtensionChangelog.h
Normal file
105
Core/GDCore/Project/EventsFunctionsExtensionChangelog.h
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* GDevelop Core
|
||||||
|
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||||
|
* reserved. This project is released under the MIT License.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "GDCore/Serialization/SerializerElement.h"
|
||||||
|
#include "GDCore/String.h"
|
||||||
|
|
||||||
|
namespace gd {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The change of a specific extension version (only the breaking
|
||||||
|
* changes).
|
||||||
|
*/
|
||||||
|
class GD_CORE_API EventsFunctionsExtensionVersionChange {
|
||||||
|
public:
|
||||||
|
EventsFunctionsExtensionVersionChange(){};
|
||||||
|
virtual ~EventsFunctionsExtensionVersionChange(){};
|
||||||
|
|
||||||
|
const gd::String &GetVersion() const { return version; };
|
||||||
|
gd::EventsFunctionsExtensionVersionChange &
|
||||||
|
SetVersion(const gd::String &version_) {
|
||||||
|
version = version_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gd::String &GetBreakingChangesDescription() const { return version; };
|
||||||
|
gd::EventsFunctionsExtensionVersionChange &
|
||||||
|
GetBreakingChangesDescription(const gd::String &breakingChangesDescription_) {
|
||||||
|
breakingChangesDescription = breakingChangesDescription_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Serialize the EventsFunctionsExtensionVersionChange to the specified
|
||||||
|
* element
|
||||||
|
*/
|
||||||
|
void SerializeTo(gd::SerializerElement &element) const {
|
||||||
|
element.SetAttribute("version", version);
|
||||||
|
element.AddChild("breaking")
|
||||||
|
.SetMultilineStringValue(breakingChangesDescription);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Load the EventsFunctionsExtensionVersionChange from the specified
|
||||||
|
* element.
|
||||||
|
*/
|
||||||
|
void UnserializeFrom(const gd::SerializerElement &element) {
|
||||||
|
version = element.GetStringAttribute("version");
|
||||||
|
breakingChangesDescription =
|
||||||
|
element.GetChild("breaking").GetMultilineStringValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
gd::String version;
|
||||||
|
gd::String breakingChangesDescription;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The changelog of an extension (only the breaking changes).
|
||||||
|
*/
|
||||||
|
class GD_CORE_API EventsFunctionsExtensionChangelog {
|
||||||
|
public:
|
||||||
|
EventsFunctionsExtensionChangelog(){};
|
||||||
|
virtual ~EventsFunctionsExtensionChangelog(){};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Return the number of variants.
|
||||||
|
*/
|
||||||
|
std::size_t GetChangesCount() const { return versionChanges.size(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Serialize the EventsFunctionsExtensionChangelog to the specified
|
||||||
|
* element
|
||||||
|
*/
|
||||||
|
void SerializeTo(gd::SerializerElement &element) const {
|
||||||
|
element.ConsiderAsArray();
|
||||||
|
for (const auto &versionChange : versionChanges) {
|
||||||
|
versionChange.SerializeTo(element.AddChild(""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Load the EventsFunctionsExtensionChangelog from the specified
|
||||||
|
* element.
|
||||||
|
*/
|
||||||
|
void UnserializeFrom(const gd::SerializerElement &element) {
|
||||||
|
versionChanges.clear();
|
||||||
|
element.ConsiderAsArray();
|
||||||
|
for (std::size_t i = 0; i < element.GetChildrenCount(); ++i) {
|
||||||
|
gd::EventsFunctionsExtensionVersionChange versionChange;
|
||||||
|
versionChange.UnserializeFrom(element.GetChild(i));
|
||||||
|
versionChanges.push_back(versionChange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<gd::EventsFunctionsExtensionVersionChange> versionChanges;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace gd
|
@@ -365,6 +365,8 @@ class GD_CORE_API InitialInstance {
|
|||||||
* the same initial instance between serialization.
|
* the same initial instance between serialization.
|
||||||
*/
|
*/
|
||||||
InitialInstance& ResetPersistentUuid();
|
InitialInstance& ResetPersistentUuid();
|
||||||
|
|
||||||
|
const gd::String& GetPersistentUuid() const { return persistentUuid; }
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -36,7 +36,7 @@ namespace gd {
|
|||||||
|
|
||||||
gd::BehaviorsSharedData Layout::badBehaviorSharedData("", "");
|
gd::BehaviorsSharedData Layout::badBehaviorSharedData("", "");
|
||||||
|
|
||||||
Layout::Layout(const Layout &other)
|
Layout::Layout(const Layout& other)
|
||||||
: objectsContainer(gd::ObjectsContainer::SourceType::Scene) {
|
: objectsContainer(gd::ObjectsContainer::SourceType::Scene) {
|
||||||
Init(other);
|
Init(other);
|
||||||
}
|
}
|
||||||
@@ -54,6 +54,8 @@ Layout::Layout()
|
|||||||
backgroundColorG(209),
|
backgroundColorG(209),
|
||||||
backgroundColorB(209),
|
backgroundColorB(209),
|
||||||
stopSoundsOnStartup(true),
|
stopSoundsOnStartup(true),
|
||||||
|
resourcesPreloading("inherit"),
|
||||||
|
resourcesUnloading("inherit"),
|
||||||
standardSortMethod(true),
|
standardSortMethod(true),
|
||||||
disableInputWhenNotFocused(true),
|
disableInputWhenNotFocused(true),
|
||||||
variables(gd::VariablesContainer::SourceType::Scene),
|
variables(gd::VariablesContainer::SourceType::Scene),
|
||||||
@@ -244,6 +246,10 @@ void Layout::SerializeTo(SerializerElement& element) const {
|
|||||||
element.SetAttribute("title", GetWindowDefaultTitle());
|
element.SetAttribute("title", GetWindowDefaultTitle());
|
||||||
element.SetAttribute("standardSortMethod", standardSortMethod);
|
element.SetAttribute("standardSortMethod", standardSortMethod);
|
||||||
element.SetAttribute("stopSoundsOnStartup", stopSoundsOnStartup);
|
element.SetAttribute("stopSoundsOnStartup", stopSoundsOnStartup);
|
||||||
|
if (resourcesPreloading != "inherit")
|
||||||
|
element.SetAttribute("resourcesPreloading", resourcesPreloading);
|
||||||
|
if (resourcesUnloading != "inherit")
|
||||||
|
element.SetAttribute("resourcesUnloading", resourcesUnloading);
|
||||||
element.SetAttribute("disableInputWhenNotFocused",
|
element.SetAttribute("disableInputWhenNotFocused",
|
||||||
disableInputWhenNotFocused);
|
disableInputWhenNotFocused);
|
||||||
|
|
||||||
@@ -304,6 +310,10 @@ void Layout::UnserializeFrom(gd::Project& project,
|
|||||||
element.GetStringAttribute("title", "(No title)", "titre"));
|
element.GetStringAttribute("title", "(No title)", "titre"));
|
||||||
standardSortMethod = element.GetBoolAttribute("standardSortMethod");
|
standardSortMethod = element.GetBoolAttribute("standardSortMethod");
|
||||||
stopSoundsOnStartup = element.GetBoolAttribute("stopSoundsOnStartup");
|
stopSoundsOnStartup = element.GetBoolAttribute("stopSoundsOnStartup");
|
||||||
|
resourcesPreloading =
|
||||||
|
element.GetStringAttribute("resourcesPreloading", "inherit");
|
||||||
|
resourcesUnloading =
|
||||||
|
element.GetStringAttribute("resourcesUnloading", "inherit");
|
||||||
disableInputWhenNotFocused =
|
disableInputWhenNotFocused =
|
||||||
element.GetBoolAttribute("disableInputWhenNotFocused");
|
element.GetBoolAttribute("disableInputWhenNotFocused");
|
||||||
|
|
||||||
@@ -391,6 +401,8 @@ void Layout::Init(const Layout& other) {
|
|||||||
standardSortMethod = other.standardSortMethod;
|
standardSortMethod = other.standardSortMethod;
|
||||||
title = other.title;
|
title = other.title;
|
||||||
stopSoundsOnStartup = other.stopSoundsOnStartup;
|
stopSoundsOnStartup = other.stopSoundsOnStartup;
|
||||||
|
resourcesPreloading = other.resourcesPreloading;
|
||||||
|
resourcesUnloading = other.resourcesUnloading;
|
||||||
disableInputWhenNotFocused = other.disableInputWhenNotFocused;
|
disableInputWhenNotFocused = other.disableInputWhenNotFocused;
|
||||||
initialInstances = other.initialInstances;
|
initialInstances = other.initialInstances;
|
||||||
layers = other.layers;
|
layers = other.layers;
|
||||||
|
@@ -349,6 +349,36 @@ class GD_CORE_API Layout {
|
|||||||
* launched
|
* launched
|
||||||
*/
|
*/
|
||||||
bool StopSoundsOnStartup() const { return stopSoundsOnStartup; }
|
bool StopSoundsOnStartup() const { return stopSoundsOnStartup; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set when the scene must preload its resources: `at-startup`, `never` or
|
||||||
|
* `inherit` (default).
|
||||||
|
*/
|
||||||
|
void SetResourcesPreloading(gd::String resourcesPreloading_) {
|
||||||
|
resourcesPreloading = resourcesPreloading_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get when the scene must preload its resources: `at-startup`, `never` or
|
||||||
|
* `inherit` (default).
|
||||||
|
*/
|
||||||
|
const gd::String& GetResourcesPreloading() const {
|
||||||
|
return resourcesPreloading;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set when the scene must unload its resources: `at-scene-exit`, `never` or
|
||||||
|
* `inherit` (default).
|
||||||
|
*/
|
||||||
|
void SetResourcesUnloading(gd::String resourcesUnloading_) {
|
||||||
|
resourcesUnloading = resourcesUnloading_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get when the scene must unload its resources: `at-scene-exit`, `never` or
|
||||||
|
* `inherit` (default).
|
||||||
|
*/
|
||||||
|
const gd::String& GetResourcesUnloading() const { return resourcesUnloading; }
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
/** \name Saving and loading
|
/** \name Saving and loading
|
||||||
@@ -381,6 +411,10 @@ class GD_CORE_API Layout {
|
|||||||
behaviorsSharedData; ///< Initial shared datas of behaviors
|
behaviorsSharedData; ///< Initial shared datas of behaviors
|
||||||
bool stopSoundsOnStartup = true; ///< True to make the scene stop all sounds at
|
bool stopSoundsOnStartup = true; ///< True to make the scene stop all sounds at
|
||||||
///< startup.
|
///< startup.
|
||||||
|
gd::String
|
||||||
|
resourcesPreloading; ///< `at-startup`, `never` or `inherit` (default).
|
||||||
|
gd::String
|
||||||
|
resourcesUnloading; ///< `at-scene-exit`, `never` or `inherit` (default).
|
||||||
bool standardSortMethod = true; ///< True to sort objects using standard sort.
|
bool standardSortMethod = true; ///< True to sort objects using standard sort.
|
||||||
bool disableInputWhenNotFocused = true; /// If set to true, the input must be
|
bool disableInputWhenNotFocused = true; /// If set to true, the input must be
|
||||||
/// disabled when the window do not have the
|
/// disabled when the window do not have the
|
||||||
|
@@ -81,6 +81,11 @@ class GD_CORE_API ObjectsContainersList {
|
|||||||
/**
|
/**
|
||||||
* \brief Return the container of the variables for the specified object or
|
* \brief Return the container of the variables for the specified object or
|
||||||
* group of objects.
|
* group of objects.
|
||||||
|
*
|
||||||
|
* \warning In most cases, prefer to use other methods to access variables or use
|
||||||
|
* ObjectVariableHelper::MergeVariableContainers if you know you're dealing with a group.
|
||||||
|
* This is because the variables container of an object group does not exist and the one from
|
||||||
|
* first object of the group will be returned.
|
||||||
*/
|
*/
|
||||||
const gd::VariablesContainer* GetObjectOrGroupVariablesContainer(
|
const gd::VariablesContainer* GetObjectOrGroupVariablesContainer(
|
||||||
const gd::String& objectOrGroupName) const;
|
const gd::String& objectOrGroupName) const;
|
||||||
|
@@ -74,7 +74,9 @@ Project::Project()
|
|||||||
gdMinorVersion(gd::VersionWrapper::Minor()),
|
gdMinorVersion(gd::VersionWrapper::Minor()),
|
||||||
gdBuildVersion(gd::VersionWrapper::Build()),
|
gdBuildVersion(gd::VersionWrapper::Build()),
|
||||||
variables(gd::VariablesContainer::SourceType::Global),
|
variables(gd::VariablesContainer::SourceType::Global),
|
||||||
objectsContainer(gd::ObjectsContainer::SourceType::Global) {}
|
objectsContainer(gd::ObjectsContainer::SourceType::Global),
|
||||||
|
sceneResourcesPreloading("at-startup"),
|
||||||
|
sceneResourcesUnloading("never") {}
|
||||||
|
|
||||||
Project::~Project() {}
|
Project::~Project() {}
|
||||||
|
|
||||||
@@ -1166,6 +1168,13 @@ void Project::SerializeTo(SerializerElement& element) const {
|
|||||||
else
|
else
|
||||||
std::cout << "ERROR: The project current platform is NULL.";
|
std::cout << "ERROR: The project current platform is NULL.";
|
||||||
|
|
||||||
|
if (sceneResourcesPreloading != "at-startup") {
|
||||||
|
propElement.SetAttribute("sceneResourcesPreloading", sceneResourcesPreloading);
|
||||||
|
}
|
||||||
|
if (sceneResourcesUnloading != "never") {
|
||||||
|
propElement.SetAttribute("sceneResourcesUnloading", sceneResourcesUnloading);
|
||||||
|
}
|
||||||
|
|
||||||
resourcesManager.SerializeTo(element.AddChild("resources"));
|
resourcesManager.SerializeTo(element.AddChild("resources"));
|
||||||
objectsContainer.SerializeObjectsTo(element.AddChild("objects"));
|
objectsContainer.SerializeObjectsTo(element.AddChild("objects"));
|
||||||
objectsContainer.SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
|
objectsContainer.SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
|
||||||
@@ -1307,6 +1316,9 @@ void Project::Init(const gd::Project& game) {
|
|||||||
variables = game.GetVariables();
|
variables = game.GetVariables();
|
||||||
|
|
||||||
projectFile = game.GetProjectFile();
|
projectFile = game.GetProjectFile();
|
||||||
|
|
||||||
|
sceneResourcesPreloading = game.sceneResourcesPreloading;
|
||||||
|
sceneResourcesUnloading = game.sceneResourcesUnloading;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace gd
|
} // namespace gd
|
||||||
|
@@ -964,6 +964,37 @@ class GD_CORE_API Project {
|
|||||||
*/
|
*/
|
||||||
ResourcesManager& GetResourcesManager() { return resourcesManager; }
|
ResourcesManager& GetResourcesManager() { return resourcesManager; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set when the scenes must preload their resources: `at-startup`, `never`
|
||||||
|
* (default).
|
||||||
|
*/
|
||||||
|
void SetSceneResourcesPreloading(gd::String sceneResourcesPreloading_) {
|
||||||
|
sceneResourcesPreloading = sceneResourcesPreloading_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get when the scenes must preload their resources: `at-startup`, `never`
|
||||||
|
* (default).
|
||||||
|
*/
|
||||||
|
const gd::String& GetSceneResourcesPreloading() const {
|
||||||
|
return sceneResourcesPreloading;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set when the scenes must unload their resources: `at-scene-exit`, `never`
|
||||||
|
* (default).
|
||||||
|
*/
|
||||||
|
void SetSceneResourcesUnloading(gd::String sceneResourcesUnloading_) {
|
||||||
|
sceneResourcesUnloading = sceneResourcesUnloading_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get when the scenes must unload their resources: `at-scene-exit`, `never`
|
||||||
|
* (default).
|
||||||
|
*/
|
||||||
|
const gd::String& GetSceneResourcesUnloading() const {
|
||||||
|
return sceneResourcesUnloading;
|
||||||
|
}
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
/** \name Variable management
|
/** \name Variable management
|
||||||
@@ -1121,6 +1152,10 @@ class GD_CORE_API Project {
|
|||||||
ExtensionProperties
|
ExtensionProperties
|
||||||
extensionProperties; ///< The properties of the extensions.
|
extensionProperties; ///< The properties of the extensions.
|
||||||
gd::WholeProjectDiagnosticReport wholeProjectDiagnosticReport;
|
gd::WholeProjectDiagnosticReport wholeProjectDiagnosticReport;
|
||||||
|
gd::String sceneResourcesPreloading; ///< `at-startup` or `never`
|
||||||
|
///< (default: `at-startup`).
|
||||||
|
gd::String sceneResourcesUnloading; ///< `at-scene-exit` or `never`
|
||||||
|
///< (default: `never`).
|
||||||
mutable unsigned int gdMajorVersion =
|
mutable unsigned int gdMajorVersion =
|
||||||
0; ///< The GD major version used the last
|
0; ///< The GD major version used the last
|
||||||
///< time the project was saved.
|
///< time the project was saved.
|
||||||
|
@@ -21,14 +21,19 @@ void PropertyDescriptor::SerializeTo(SerializerElement& element) const {
|
|||||||
element.AddChild("unit").SetStringValue(measurementUnit.GetName());
|
element.AddChild("unit").SetStringValue(measurementUnit.GetName());
|
||||||
}
|
}
|
||||||
element.AddChild("label").SetStringValue(label);
|
element.AddChild("label").SetStringValue(label);
|
||||||
element.AddChild("description").SetStringValue(description);
|
if (!description.empty())
|
||||||
element.AddChild("group").SetStringValue(group);
|
element.AddChild("description").SetStringValue(description);
|
||||||
SerializerElement& extraInformationElement =
|
if (!group.empty()) element.AddChild("group").SetStringValue(group);
|
||||||
element.AddChild("extraInformation");
|
|
||||||
extraInformationElement.ConsiderAsArray();
|
if (!extraInformation.empty()) {
|
||||||
for (const gd::String& information : extraInformation) {
|
SerializerElement& extraInformationElement =
|
||||||
extraInformationElement.AddChild("").SetStringValue(information);
|
element.AddChild("extraInformation");
|
||||||
|
extraInformationElement.ConsiderAsArray();
|
||||||
|
for (const gd::String& information : extraInformation) {
|
||||||
|
extraInformationElement.AddChild("").SetStringValue(information);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
element.AddChild("hidden").SetBoolValue(hidden);
|
element.AddChild("hidden").SetBoolValue(hidden);
|
||||||
}
|
}
|
||||||
@@ -59,16 +64,21 @@ void PropertyDescriptor::UnserializeFrom(const SerializerElement& element) {
|
|||||||
: gd::MeasurementUnit::GetUndefined();
|
: gd::MeasurementUnit::GetUndefined();
|
||||||
}
|
}
|
||||||
label = element.GetChild("label").GetStringValue();
|
label = element.GetChild("label").GetStringValue();
|
||||||
description = element.GetChild("description").GetStringValue();
|
description = element.HasChild("description")
|
||||||
group = element.GetChild("group").GetStringValue();
|
? element.GetChild("description").GetStringValue()
|
||||||
|
: "";
|
||||||
|
group = element.HasChild("group") ? element.GetChild("group").GetStringValue()
|
||||||
|
: "";
|
||||||
|
|
||||||
extraInformation.clear();
|
extraInformation.clear();
|
||||||
const SerializerElement& extraInformationElement =
|
if (element.HasChild("extraInformation")) {
|
||||||
element.GetChild("extraInformation");
|
const SerializerElement& extraInformationElement =
|
||||||
extraInformationElement.ConsiderAsArray();
|
element.GetChild("extraInformation");
|
||||||
for (std::size_t i = 0; i < extraInformationElement.GetChildrenCount(); ++i)
|
extraInformationElement.ConsiderAsArray();
|
||||||
extraInformation.push_back(
|
for (std::size_t i = 0; i < extraInformationElement.GetChildrenCount(); ++i)
|
||||||
extraInformationElement.GetChild(i).GetStringValue());
|
extraInformation.push_back(
|
||||||
|
extraInformationElement.GetChild(i).GetStringValue());
|
||||||
|
}
|
||||||
|
|
||||||
hidden = element.HasChild("hidden")
|
hidden = element.HasChild("hidden")
|
||||||
? element.GetChild("hidden").GetBoolValue()
|
? element.GetChild("hidden").GetBoolValue()
|
||||||
|
@@ -7,9 +7,9 @@
|
|||||||
#define GDCORE_PROPERTYDESCRIPTOR
|
#define GDCORE_PROPERTYDESCRIPTOR
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "GDCore/String.h"
|
|
||||||
#include "GDCore/Project/MeasurementUnit.h"
|
#include "GDCore/Project/MeasurementUnit.h"
|
||||||
#include "GDCore/Project/QuickCustomization.h"
|
#include "GDCore/Project/QuickCustomization.h"
|
||||||
|
#include "GDCore/String.h"
|
||||||
|
|
||||||
namespace gd {
|
namespace gd {
|
||||||
class SerializerElement;
|
class SerializerElement;
|
||||||
@@ -17,6 +17,19 @@ class SerializerElement;
|
|||||||
|
|
||||||
namespace gd {
|
namespace gd {
|
||||||
|
|
||||||
|
class GD_CORE_API PropertyDescriptorChoice {
|
||||||
|
public:
|
||||||
|
PropertyDescriptorChoice(const gd::String& value, const gd::String& label)
|
||||||
|
: value(value), label(label) {}
|
||||||
|
|
||||||
|
const gd::String& GetValue() const { return value; }
|
||||||
|
const gd::String& GetLabel() const { return label; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
gd::String value;
|
||||||
|
gd::String label;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Used to describe a property shown in a property grid.
|
* \brief Used to describe a property shown in a property grid.
|
||||||
* \see gd::Object
|
* \see gd::Object
|
||||||
@@ -31,8 +44,12 @@ class GD_CORE_API PropertyDescriptor {
|
|||||||
* \param propertyValue The value of the property.
|
* \param propertyValue The value of the property.
|
||||||
*/
|
*/
|
||||||
PropertyDescriptor(gd::String propertyValue)
|
PropertyDescriptor(gd::String propertyValue)
|
||||||
: currentValue(propertyValue), type("string"), label(""), hidden(false),
|
: currentValue(propertyValue),
|
||||||
deprecated(false), advanced(false),
|
type("string"),
|
||||||
|
label(""),
|
||||||
|
hidden(false),
|
||||||
|
deprecated(false),
|
||||||
|
advanced(false),
|
||||||
hasImpactOnOtherProperties(false),
|
hasImpactOnOtherProperties(false),
|
||||||
measurementUnit(gd::MeasurementUnit::GetUndefined()),
|
measurementUnit(gd::MeasurementUnit::GetUndefined()),
|
||||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {}
|
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {}
|
||||||
@@ -41,10 +58,13 @@ class GD_CORE_API PropertyDescriptor {
|
|||||||
* \brief Empty constructor creating an empty property to be displayed.
|
* \brief Empty constructor creating an empty property to be displayed.
|
||||||
*/
|
*/
|
||||||
PropertyDescriptor()
|
PropertyDescriptor()
|
||||||
: hidden(false), deprecated(false), advanced(false),
|
: hidden(false),
|
||||||
|
deprecated(false),
|
||||||
|
advanced(false),
|
||||||
hasImpactOnOtherProperties(false),
|
hasImpactOnOtherProperties(false),
|
||||||
measurementUnit(gd::MeasurementUnit::GetUndefined()),
|
measurementUnit(gd::MeasurementUnit::GetUndefined()),
|
||||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default){};
|
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Destructor
|
* \brief Destructor
|
||||||
@@ -88,13 +108,20 @@ class GD_CORE_API PropertyDescriptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Change the group where this property is displayed to the user, if any.
|
* \brief Change the group where this property is displayed to the user, if
|
||||||
|
* any.
|
||||||
*/
|
*/
|
||||||
PropertyDescriptor& SetGroup(gd::String group_) {
|
PropertyDescriptor& SetGroup(gd::String group_) {
|
||||||
group = group_;
|
group = group_;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PropertyDescriptor& AddChoice(const gd::String& value,
|
||||||
|
const gd::String& label) {
|
||||||
|
choices.push_back(PropertyDescriptorChoice(value, label));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Set and replace the additional information for the property.
|
* \brief Set and replace the additional information for the property.
|
||||||
*/
|
*/
|
||||||
@@ -118,7 +145,8 @@ class GD_CORE_API PropertyDescriptor {
|
|||||||
/**
|
/**
|
||||||
* \brief Change the unit of measurement of the property value.
|
* \brief Change the unit of measurement of the property value.
|
||||||
*/
|
*/
|
||||||
PropertyDescriptor& SetMeasurementUnit(const gd::MeasurementUnit &measurementUnit_) {
|
PropertyDescriptor& SetMeasurementUnit(
|
||||||
|
const gd::MeasurementUnit& measurementUnit_) {
|
||||||
measurementUnit = measurementUnit_;
|
measurementUnit = measurementUnit_;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -128,14 +156,18 @@ class GD_CORE_API PropertyDescriptor {
|
|||||||
const gd::String& GetLabel() const { return label; }
|
const gd::String& GetLabel() const { return label; }
|
||||||
const gd::String& GetDescription() const { return description; }
|
const gd::String& GetDescription() const { return description; }
|
||||||
const gd::String& GetGroup() const { return group; }
|
const gd::String& GetGroup() const { return group; }
|
||||||
const gd::MeasurementUnit& GetMeasurementUnit() const { return measurementUnit; }
|
const gd::MeasurementUnit& GetMeasurementUnit() const {
|
||||||
|
return measurementUnit;
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<gd::String>& GetExtraInfo() const {
|
const std::vector<gd::String>& GetExtraInfo() const {
|
||||||
return extraInformation;
|
return extraInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<gd::String>& GetExtraInfo() {
|
std::vector<gd::String>& GetExtraInfo() { return extraInformation; }
|
||||||
return extraInformation;
|
|
||||||
|
const std::vector<PropertyDescriptorChoice>& GetChoices() const {
|
||||||
|
return choices;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -178,23 +210,26 @@ class GD_CORE_API PropertyDescriptor {
|
|||||||
bool IsAdvanced() const { return advanced; }
|
bool IsAdvanced() const { return advanced; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Check if the property has impact on other properties - which means a change
|
* \brief Check if the property has impact on other properties - which means a
|
||||||
* must re-render other properties.
|
* change must re-render other properties.
|
||||||
*/
|
*/
|
||||||
bool HasImpactOnOtherProperties() const { return hasImpactOnOtherProperties; }
|
bool HasImpactOnOtherProperties() const { return hasImpactOnOtherProperties; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Set if the property has impact on other properties - which means a change
|
* \brief Set if the property has impact on other properties - which means a
|
||||||
* must re-render other properties.
|
* change must re-render other properties.
|
||||||
*/
|
*/
|
||||||
PropertyDescriptor& SetHasImpactOnOtherProperties(bool enable) {
|
PropertyDescriptor& SetHasImpactOnOtherProperties(bool enable) {
|
||||||
hasImpactOnOtherProperties = enable;
|
hasImpactOnOtherProperties = enable;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
QuickCustomization::Visibility GetQuickCustomizationVisibility() const { return quickCustomizationVisibility; }
|
QuickCustomization::Visibility GetQuickCustomizationVisibility() const {
|
||||||
|
return quickCustomizationVisibility;
|
||||||
|
}
|
||||||
|
|
||||||
PropertyDescriptor& SetQuickCustomizationVisibility(QuickCustomization::Visibility visibility) {
|
PropertyDescriptor& SetQuickCustomizationVisibility(
|
||||||
|
QuickCustomization::Visibility visibility) {
|
||||||
quickCustomizationVisibility = visibility;
|
quickCustomizationVisibility = visibility;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -231,15 +266,17 @@ class GD_CORE_API PropertyDescriptor {
|
|||||||
gd::String label; //< The user-friendly property name
|
gd::String label; //< The user-friendly property name
|
||||||
gd::String description; //< The user-friendly property description
|
gd::String description; //< The user-friendly property description
|
||||||
gd::String group; //< The user-friendly property group
|
gd::String group; //< The user-friendly property group
|
||||||
|
std::vector<PropertyDescriptorChoice>
|
||||||
|
choices; //< The optional choices for the property.
|
||||||
std::vector<gd::String>
|
std::vector<gd::String>
|
||||||
extraInformation; ///< Can be used to store for example the available
|
extraInformation; ///< Can be used to store an additional information
|
||||||
///< choices, if a property is a displayed as a combo
|
///< like an object type.
|
||||||
///< box.
|
|
||||||
bool hidden;
|
bool hidden;
|
||||||
bool deprecated;
|
bool deprecated;
|
||||||
bool advanced;
|
bool advanced;
|
||||||
bool hasImpactOnOtherProperties;
|
bool hasImpactOnOtherProperties;
|
||||||
gd::MeasurementUnit measurementUnit; //< The unit of measurement of the property vale.
|
gd::MeasurementUnit
|
||||||
|
measurementUnit; //< The unit of measurement of the property vale.
|
||||||
QuickCustomization::Visibility quickCustomizationVisibility;
|
QuickCustomization::Visibility quickCustomizationVisibility;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -5,8 +5,6 @@ namespace gdjs {
|
|||||||
type Object3DNetworkSyncDataType = {
|
type Object3DNetworkSyncDataType = {
|
||||||
// z is position on the Z axis, different from zo, which is Z order
|
// z is position on the Z axis, different from zo, which is Z order
|
||||||
z: number;
|
z: number;
|
||||||
w: number;
|
|
||||||
h: number;
|
|
||||||
d: number;
|
d: number;
|
||||||
rx: number;
|
rx: number;
|
||||||
ry: number;
|
ry: number;
|
||||||
@@ -116,8 +114,6 @@ namespace gdjs {
|
|||||||
return {
|
return {
|
||||||
...super.getNetworkSyncData(),
|
...super.getNetworkSyncData(),
|
||||||
z: this.getZ(),
|
z: this.getZ(),
|
||||||
w: this.getWidth(),
|
|
||||||
h: this.getHeight(),
|
|
||||||
d: this.getDepth(),
|
d: this.getDepth(),
|
||||||
rx: this.getRotationX(),
|
rx: this.getRotationX(),
|
||||||
ry: this.getRotationY(),
|
ry: this.getRotationY(),
|
||||||
@@ -130,8 +126,6 @@ namespace gdjs {
|
|||||||
updateFromNetworkSyncData(networkSyncData: Object3DNetworkSyncData) {
|
updateFromNetworkSyncData(networkSyncData: Object3DNetworkSyncData) {
|
||||||
super.updateFromNetworkSyncData(networkSyncData);
|
super.updateFromNetworkSyncData(networkSyncData);
|
||||||
if (networkSyncData.z !== undefined) this.setZ(networkSyncData.z);
|
if (networkSyncData.z !== undefined) this.setZ(networkSyncData.z);
|
||||||
if (networkSyncData.w !== undefined) this.setWidth(networkSyncData.w);
|
|
||||||
if (networkSyncData.h !== undefined) this.setHeight(networkSyncData.h);
|
|
||||||
if (networkSyncData.d !== undefined) this.setDepth(networkSyncData.d);
|
if (networkSyncData.d !== undefined) this.setDepth(networkSyncData.d);
|
||||||
if (networkSyncData.rx !== undefined)
|
if (networkSyncData.rx !== undefined)
|
||||||
this.setRotationX(networkSyncData.rx);
|
this.setRotationX(networkSyncData.rx);
|
||||||
|
@@ -25,6 +25,8 @@ namespace gdjs {
|
|||||||
topFaceVisible: boolean;
|
topFaceVisible: boolean;
|
||||||
bottomFaceVisible: boolean;
|
bottomFaceVisible: boolean;
|
||||||
tint: string | undefined;
|
tint: string | undefined;
|
||||||
|
isCastingShadow: boolean;
|
||||||
|
isReceivingShadow: boolean;
|
||||||
materialType: 'Basic' | 'StandardWithoutMetalness';
|
materialType: 'Basic' | 'StandardWithoutMetalness';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -71,8 +73,10 @@ namespace gdjs {
|
|||||||
string,
|
string,
|
||||||
];
|
];
|
||||||
_materialType: gdjs.Cube3DRuntimeObject.MaterialType =
|
_materialType: gdjs.Cube3DRuntimeObject.MaterialType =
|
||||||
gdjs.Cube3DRuntimeObject.MaterialType.Basic;
|
gdjs.Cube3DRuntimeObject.MaterialType.StandardWithoutMetalness;
|
||||||
_tint: string;
|
_tint: string;
|
||||||
|
_isCastingShadow: boolean = true;
|
||||||
|
_isReceivingShadow: boolean = true;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||||
@@ -121,6 +125,8 @@ namespace gdjs {
|
|||||||
];
|
];
|
||||||
|
|
||||||
this._tint = objectData.content.tint || '255;255;255';
|
this._tint = objectData.content.tint || '255;255;255';
|
||||||
|
this._isCastingShadow = objectData.content.isCastingShadow || false;
|
||||||
|
this._isReceivingShadow = objectData.content.isReceivingShadow || false;
|
||||||
|
|
||||||
this._materialType = this._convertMaterialType(
|
this._materialType = this._convertMaterialType(
|
||||||
objectData.content.materialType
|
objectData.content.materialType
|
||||||
@@ -430,6 +436,18 @@ namespace gdjs {
|
|||||||
) {
|
) {
|
||||||
this.setMaterialType(newObjectData.content.materialType);
|
this.setMaterialType(newObjectData.content.materialType);
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
oldObjectData.content.isCastingShadow !==
|
||||||
|
newObjectData.content.isCastingShadow
|
||||||
|
) {
|
||||||
|
this.updateShadowCasting(newObjectData.content.isCastingShadow);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
oldObjectData.content.isReceivingShadow !==
|
||||||
|
newObjectData.content.isReceivingShadow
|
||||||
|
) {
|
||||||
|
this.updateShadowReceiving(newObjectData.content.isReceivingShadow);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -531,6 +549,14 @@ namespace gdjs {
|
|||||||
this._materialType = newMaterialType;
|
this._materialType = newMaterialType;
|
||||||
this._renderer._updateMaterials();
|
this._renderer._updateMaterials();
|
||||||
}
|
}
|
||||||
|
updateShadowCasting(value: boolean) {
|
||||||
|
this._isCastingShadow = value;
|
||||||
|
this._renderer.updateShadowCasting();
|
||||||
|
}
|
||||||
|
updateShadowReceiving(value: boolean) {
|
||||||
|
this._isReceivingShadow = value;
|
||||||
|
this._renderer.updateShadowReceiving();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace Cube3DRuntimeObject {
|
export namespace Cube3DRuntimeObject {
|
||||||
|
@@ -81,13 +81,14 @@ namespace gdjs {
|
|||||||
.map((_, index) =>
|
.map((_, index) =>
|
||||||
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[index])
|
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[index])
|
||||||
);
|
);
|
||||||
|
|
||||||
const boxMesh = new THREE.Mesh(geometry, materials);
|
const boxMesh = new THREE.Mesh(geometry, materials);
|
||||||
|
|
||||||
super(runtimeObject, instanceContainer, boxMesh);
|
super(runtimeObject, instanceContainer, boxMesh);
|
||||||
this._boxMesh = boxMesh;
|
this._boxMesh = boxMesh;
|
||||||
this._cube3DRuntimeObject = runtimeObject;
|
this._cube3DRuntimeObject = runtimeObject;
|
||||||
|
|
||||||
|
boxMesh.receiveShadow = this._cube3DRuntimeObject._isReceivingShadow;
|
||||||
|
boxMesh.castShadow = this._cube3DRuntimeObject._isCastingShadow;
|
||||||
this.updateSize();
|
this.updateSize();
|
||||||
this.updatePosition();
|
this.updatePosition();
|
||||||
this.updateRotation();
|
this.updateRotation();
|
||||||
@@ -114,6 +115,13 @@ namespace gdjs {
|
|||||||
new THREE.BufferAttribute(new Float32Array(tints), 3)
|
new THREE.BufferAttribute(new Float32Array(tints), 3)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
updateShadowCasting() {
|
||||||
|
this._boxMesh.castShadow = this._cube3DRuntimeObject._isCastingShadow;
|
||||||
|
}
|
||||||
|
updateShadowReceiving() {
|
||||||
|
this._boxMesh.receiveShadow =
|
||||||
|
this._cube3DRuntimeObject._isReceivingShadow;
|
||||||
|
}
|
||||||
|
|
||||||
updateFace(faceIndex: integer) {
|
updateFace(faceIndex: integer) {
|
||||||
const materialIndex = faceIndexToMaterialIndex[faceIndex];
|
const materialIndex = faceIndexToMaterialIndex[faceIndex];
|
||||||
|
@@ -1,4 +1,12 @@
|
|||||||
namespace gdjs {
|
namespace gdjs {
|
||||||
|
type CustomObject3DNetworkSyncDataType = CustomObjectNetworkSyncDataType & {
|
||||||
|
z: float;
|
||||||
|
d: float;
|
||||||
|
rx: float;
|
||||||
|
ry: float;
|
||||||
|
ifz: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for 3D custom objects.
|
* Base class for 3D custom objects.
|
||||||
*/
|
*/
|
||||||
@@ -34,7 +42,6 @@ namespace gdjs {
|
|||||||
objectData: gdjs.Object3DData & gdjs.CustomObjectConfiguration
|
objectData: gdjs.Object3DData & gdjs.CustomObjectConfiguration
|
||||||
) {
|
) {
|
||||||
super(parent, objectData);
|
super(parent, objectData);
|
||||||
this._renderer.reinitialize(this, parent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override _createRender() {
|
protected override _createRender() {
|
||||||
@@ -78,6 +85,30 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getNetworkSyncData(): CustomObject3DNetworkSyncDataType {
|
||||||
|
return {
|
||||||
|
...super.getNetworkSyncData(),
|
||||||
|
z: this.getZ(),
|
||||||
|
d: this.getDepth(),
|
||||||
|
rx: this.getRotationX(),
|
||||||
|
ry: this.getRotationY(),
|
||||||
|
ifz: this.isFlippedZ(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFromNetworkSyncData(
|
||||||
|
networkSyncData: CustomObject3DNetworkSyncDataType
|
||||||
|
): void {
|
||||||
|
super.updateFromNetworkSyncData(networkSyncData);
|
||||||
|
if (networkSyncData.z !== undefined) this.setZ(networkSyncData.z);
|
||||||
|
if (networkSyncData.d !== undefined) this.setDepth(networkSyncData.d);
|
||||||
|
if (networkSyncData.rx !== undefined)
|
||||||
|
this.setRotationX(networkSyncData.rx);
|
||||||
|
if (networkSyncData.ry !== undefined)
|
||||||
|
this.setRotationY(networkSyncData.ry);
|
||||||
|
if (networkSyncData.ifz !== undefined) this.flipZ(networkSyncData.ifz);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the object position on the Z axis.
|
* Set the object position on the Z axis.
|
||||||
*/
|
*/
|
||||||
|
@@ -44,10 +44,7 @@ namespace gdjs {
|
|||||||
) {
|
) {
|
||||||
this._object = object;
|
this._object = object;
|
||||||
this._isContainerDirty = true;
|
this._isContainerDirty = true;
|
||||||
const layer = parent.getLayer('');
|
this._threeGroup.clear();
|
||||||
if (layer) {
|
|
||||||
layer.getRenderer().add3DRendererObject(this._threeGroup);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateThreeGroup() {
|
_updateThreeGroup() {
|
||||||
|
@@ -6,6 +6,7 @@ namespace gdjs {
|
|||||||
r: number;
|
r: number;
|
||||||
t: string;
|
t: string;
|
||||||
}
|
}
|
||||||
|
const shadowHelper = false;
|
||||||
gdjs.PixiFiltersTools.registerFilterCreator(
|
gdjs.PixiFiltersTools.registerFilterCreator(
|
||||||
'Scene3D::DirectionalLight',
|
'Scene3D::DirectionalLight',
|
||||||
new (class implements gdjs.PixiFiltersTools.FilterCreator {
|
new (class implements gdjs.PixiFiltersTools.FilterCreator {
|
||||||
@@ -17,19 +18,63 @@ namespace gdjs {
|
|||||||
return new gdjs.PixiFiltersTools.EmptyFilter();
|
return new gdjs.PixiFiltersTools.EmptyFilter();
|
||||||
}
|
}
|
||||||
return new (class implements gdjs.PixiFiltersTools.Filter {
|
return new (class implements gdjs.PixiFiltersTools.Filter {
|
||||||
light: THREE.DirectionalLight;
|
private _top: string = 'Z+';
|
||||||
rotationObject: THREE.Group;
|
private _elevation: float = 45;
|
||||||
_isEnabled: boolean = false;
|
private _rotation: float = 0;
|
||||||
top: string = 'Y-';
|
private _shadowMapSize: float = 1024;
|
||||||
elevation: float = 45;
|
private _minimumShadowBias: float = 0;
|
||||||
rotation: float = 0;
|
private _distanceFromCamera: float = 1500;
|
||||||
|
private _frustumSize: float = 4000;
|
||||||
|
|
||||||
|
private _isEnabled: boolean = false;
|
||||||
|
private _light: THREE.DirectionalLight;
|
||||||
|
private _shadowMapDirty = true;
|
||||||
|
private _shadowCameraDirty = true;
|
||||||
|
private _shadowCameraHelper: THREE.CameraHelper | null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.light = new THREE.DirectionalLight();
|
this._light = new THREE.DirectionalLight();
|
||||||
this.light.position.set(1, 0, 0);
|
|
||||||
this.rotationObject = new THREE.Group();
|
if (shadowHelper) {
|
||||||
this.rotationObject.add(this.light);
|
this._shadowCameraHelper = new THREE.CameraHelper(
|
||||||
this.updateRotation();
|
this._light.shadow.camera
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this._shadowCameraHelper = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._light.shadow.camera.updateProjectionMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _updateShadowCamera(): void {
|
||||||
|
if (!this._shadowCameraDirty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._shadowCameraDirty = false;
|
||||||
|
|
||||||
|
this._light.shadow.camera.near = 1;
|
||||||
|
this._light.shadow.camera.far = this._distanceFromCamera + 10000;
|
||||||
|
this._light.shadow.camera.right = this._frustumSize / 2;
|
||||||
|
this._light.shadow.camera.left = -this._frustumSize / 2;
|
||||||
|
this._light.shadow.camera.top = this._frustumSize / 2;
|
||||||
|
this._light.shadow.camera.bottom = -this._frustumSize / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _updateShadowMapSize(): void {
|
||||||
|
if (!this._shadowMapDirty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._shadowMapDirty = false;
|
||||||
|
|
||||||
|
this._light.shadow.mapSize.set(
|
||||||
|
this._shadowMapSize,
|
||||||
|
this._shadowMapSize
|
||||||
|
);
|
||||||
|
|
||||||
|
// Force the recreation of the shadow map texture:
|
||||||
|
this._light.shadow.map?.dispose();
|
||||||
|
this._light.shadow.map = null;
|
||||||
|
this._light.shadow.needsUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
isEnabled(target: EffectsTarget): boolean {
|
isEnabled(target: EffectsTarget): boolean {
|
||||||
@@ -53,7 +98,12 @@ namespace gdjs {
|
|||||||
if (!scene) {
|
if (!scene) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
scene.add(this.rotationObject);
|
scene.add(this._light);
|
||||||
|
scene.add(this._light.target);
|
||||||
|
if (this._shadowCameraHelper) {
|
||||||
|
scene.add(this._shadowCameraHelper);
|
||||||
|
}
|
||||||
|
|
||||||
this._isEnabled = true;
|
this._isEnabled = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -65,82 +115,164 @@ namespace gdjs {
|
|||||||
if (!scene) {
|
if (!scene) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
scene.remove(this.rotationObject);
|
scene.remove(this._light);
|
||||||
|
scene.remove(this._light.target);
|
||||||
|
if (this._shadowCameraHelper) {
|
||||||
|
scene.remove(this._shadowCameraHelper);
|
||||||
|
}
|
||||||
this._isEnabled = false;
|
this._isEnabled = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
updatePreRender(target: gdjs.EffectsTarget): any {}
|
updatePreRender(target: gdjs.EffectsTarget): any {
|
||||||
|
// Apply any update to the camera or shadow map size.
|
||||||
|
this._updateShadowCamera();
|
||||||
|
this._updateShadowMapSize();
|
||||||
|
|
||||||
|
// Avoid shadow acne due to depth buffer precision.
|
||||||
|
const biasMultiplier =
|
||||||
|
this._shadowMapSize < 1024
|
||||||
|
? 2
|
||||||
|
: this._shadowMapSize < 2048
|
||||||
|
? 1.25
|
||||||
|
: 1;
|
||||||
|
this._light.shadow.bias = -this._minimumShadowBias * biasMultiplier;
|
||||||
|
|
||||||
|
// Apply update to the light position and its target.
|
||||||
|
// By doing this, the shadows are "following" the GDevelop camera.
|
||||||
|
if (!target.getRuntimeLayer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const layer = target.getRuntimeLayer();
|
||||||
|
const x = layer.getCameraX();
|
||||||
|
const y = layer.getCameraY();
|
||||||
|
const z = layer.getCameraZ(layer.getInitialCamera3DFieldOfView());
|
||||||
|
|
||||||
|
const roundedX = Math.floor(x / 100) * 100;
|
||||||
|
const roundedY = Math.floor(y / 100) * 100;
|
||||||
|
const roundedZ = Math.floor(z / 100) * 100;
|
||||||
|
if (this._top === 'Y-') {
|
||||||
|
const posLightX =
|
||||||
|
roundedX +
|
||||||
|
this._distanceFromCamera *
|
||||||
|
Math.cos(gdjs.toRad(-this._rotation + 90)) *
|
||||||
|
Math.cos(gdjs.toRad(this._elevation));
|
||||||
|
const posLightY =
|
||||||
|
roundedY -
|
||||||
|
this._distanceFromCamera *
|
||||||
|
Math.sin(gdjs.toRad(this._elevation));
|
||||||
|
const posLightZ =
|
||||||
|
roundedZ +
|
||||||
|
this._distanceFromCamera *
|
||||||
|
Math.sin(gdjs.toRad(-this._rotation + 90)) *
|
||||||
|
Math.cos(gdjs.toRad(this._elevation));
|
||||||
|
this._light.position.set(posLightX, posLightY, posLightZ);
|
||||||
|
this._light.target.position.set(roundedX, roundedY, roundedZ);
|
||||||
|
} else {
|
||||||
|
const posLightX =
|
||||||
|
roundedX +
|
||||||
|
this._distanceFromCamera *
|
||||||
|
Math.cos(gdjs.toRad(this._rotation)) *
|
||||||
|
Math.cos(gdjs.toRad(this._elevation));
|
||||||
|
const posLightY =
|
||||||
|
roundedY +
|
||||||
|
this._distanceFromCamera *
|
||||||
|
Math.sin(gdjs.toRad(this._rotation)) *
|
||||||
|
Math.cos(gdjs.toRad(this._elevation));
|
||||||
|
const posLightZ =
|
||||||
|
roundedZ +
|
||||||
|
this._distanceFromCamera *
|
||||||
|
Math.sin(gdjs.toRad(this._elevation));
|
||||||
|
|
||||||
|
this._light.position.set(posLightX, posLightY, posLightZ);
|
||||||
|
this._light.target.position.set(roundedX, roundedY, roundedZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
updateDoubleParameter(parameterName: string, value: number): void {
|
updateDoubleParameter(parameterName: string, value: number): void {
|
||||||
if (parameterName === 'intensity') {
|
if (parameterName === 'intensity') {
|
||||||
this.light.intensity = value;
|
this._light.intensity = value;
|
||||||
} else if (parameterName === 'elevation') {
|
} else if (parameterName === 'elevation') {
|
||||||
this.elevation = value;
|
this._elevation = value;
|
||||||
this.updateRotation();
|
|
||||||
} else if (parameterName === 'rotation') {
|
} else if (parameterName === 'rotation') {
|
||||||
this.rotation = value;
|
this._rotation = value;
|
||||||
this.updateRotation();
|
} else if (parameterName === 'distanceFromCamera') {
|
||||||
|
this._distanceFromCamera = value;
|
||||||
|
} else if (parameterName === 'frustumSize') {
|
||||||
|
this._frustumSize = value;
|
||||||
|
} else if (parameterName === 'minimumShadowBias') {
|
||||||
|
this._minimumShadowBias = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getDoubleParameter(parameterName: string): number {
|
getDoubleParameter(parameterName: string): number {
|
||||||
if (parameterName === 'intensity') {
|
if (parameterName === 'intensity') {
|
||||||
return this.light.intensity;
|
return this._light.intensity;
|
||||||
} else if (parameterName === 'elevation') {
|
} else if (parameterName === 'elevation') {
|
||||||
return this.elevation;
|
return this._elevation;
|
||||||
} else if (parameterName === 'rotation') {
|
} else if (parameterName === 'rotation') {
|
||||||
return this.rotation;
|
return this._rotation;
|
||||||
|
} else if (parameterName === 'distanceFromCamera') {
|
||||||
|
return this._distanceFromCamera;
|
||||||
|
} else if (parameterName === 'frustumSize') {
|
||||||
|
return this._frustumSize;
|
||||||
|
} else if (parameterName === 'minimumShadowBias') {
|
||||||
|
return this._minimumShadowBias;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
updateStringParameter(parameterName: string, value: string): void {
|
updateStringParameter(parameterName: string, value: string): void {
|
||||||
if (parameterName === 'color') {
|
if (parameterName === 'color') {
|
||||||
this.light.color = new THREE.Color(
|
this._light.color = new THREE.Color(
|
||||||
gdjs.rgbOrHexStringToNumber(value)
|
gdjs.rgbOrHexStringToNumber(value)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (parameterName === 'top') {
|
if (parameterName === 'top') {
|
||||||
this.top = value;
|
this._top = value;
|
||||||
this.updateRotation();
|
}
|
||||||
|
if (parameterName === 'shadowQuality') {
|
||||||
|
if (value === 'low' && this._shadowMapSize !== 512) {
|
||||||
|
this._shadowMapSize = 512;
|
||||||
|
this._shadowMapDirty = true;
|
||||||
|
}
|
||||||
|
if (value === 'medium' && this._shadowMapSize !== 1024) {
|
||||||
|
this._shadowMapSize = 1024;
|
||||||
|
this._shadowMapDirty = true;
|
||||||
|
}
|
||||||
|
if (value === 'high' && this._shadowMapSize !== 2048) {
|
||||||
|
this._shadowMapSize = 2048;
|
||||||
|
this._shadowMapDirty = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateColorParameter(parameterName: string, value: number): void {
|
updateColorParameter(parameterName: string, value: number): void {
|
||||||
if (parameterName === 'color') {
|
if (parameterName === 'color') {
|
||||||
this.light.color.setHex(value);
|
this._light.color.setHex(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getColorParameter(parameterName: string): number {
|
getColorParameter(parameterName: string): number {
|
||||||
if (parameterName === 'color') {
|
if (parameterName === 'color') {
|
||||||
return this.light.color.getHex();
|
return this._light.color.getHex();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
updateBooleanParameter(parameterName: string, value: boolean): void {
|
||||||
updateRotation() {
|
if (parameterName === 'isCastingShadow') {
|
||||||
if (this.top === 'Z+') {
|
this._light.castShadow = value;
|
||||||
// 0° is a light from the right of the screen.
|
|
||||||
this.rotationObject.rotation.z = gdjs.toRad(this.rotation);
|
|
||||||
this.rotationObject.rotation.y = -gdjs.toRad(this.elevation);
|
|
||||||
} else {
|
|
||||||
// 0° becomes a light from Z+.
|
|
||||||
this.rotationObject.rotation.y = gdjs.toRad(this.rotation - 90);
|
|
||||||
this.rotationObject.rotation.z = -gdjs.toRad(this.elevation);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getNetworkSyncData(): DirectionalLightFilterNetworkSyncData {
|
getNetworkSyncData(): DirectionalLightFilterNetworkSyncData {
|
||||||
return {
|
return {
|
||||||
i: this.light.intensity,
|
i: this._light.intensity,
|
||||||
c: this.light.color.getHex(),
|
c: this._light.color.getHex(),
|
||||||
e: this.elevation,
|
e: this._elevation,
|
||||||
r: this.rotation,
|
r: this._rotation,
|
||||||
t: this.top,
|
t: this._top,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
updateFromNetworkSyncData(syncData: any): void {
|
updateFromNetworkSyncData(syncData: any): void {
|
||||||
this.light.intensity = syncData.i;
|
this._light.intensity = syncData.i;
|
||||||
this.light.color.setHex(syncData.c);
|
this._light.color.setHex(syncData.c);
|
||||||
this.elevation = syncData.e;
|
this._elevation = syncData.e;
|
||||||
this.rotation = syncData.r;
|
this._rotation = syncData.r;
|
||||||
this.top = syncData.t;
|
this._top = syncData.t;
|
||||||
this.updateRotation();
|
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
@@ -18,18 +18,15 @@ namespace gdjs {
|
|||||||
return new gdjs.PixiFiltersTools.EmptyFilter();
|
return new gdjs.PixiFiltersTools.EmptyFilter();
|
||||||
}
|
}
|
||||||
return new (class implements gdjs.PixiFiltersTools.Filter {
|
return new (class implements gdjs.PixiFiltersTools.Filter {
|
||||||
light: THREE.HemisphereLight;
|
_top: string = 'Z+';
|
||||||
rotationObject: THREE.Group;
|
_elevation: float = 90;
|
||||||
|
_rotation: float = 0;
|
||||||
|
|
||||||
_isEnabled: boolean = false;
|
_isEnabled: boolean = false;
|
||||||
top: string = 'Y-';
|
_light: THREE.HemisphereLight;
|
||||||
elevation: float = 45;
|
|
||||||
rotation: float = 0;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.light = new THREE.HemisphereLight();
|
this._light = new THREE.HemisphereLight();
|
||||||
this.light.position.set(1, 0, 0);
|
|
||||||
this.rotationObject = new THREE.Group();
|
|
||||||
this.rotationObject.add(this.light);
|
|
||||||
this.updateRotation();
|
this.updateRotation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +51,7 @@ namespace gdjs {
|
|||||||
if (!scene) {
|
if (!scene) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
scene.add(this.rotationObject);
|
scene.add(this._light);
|
||||||
this._isEnabled = true;
|
this._isEnabled = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -66,96 +63,106 @@ namespace gdjs {
|
|||||||
if (!scene) {
|
if (!scene) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
scene.remove(this.rotationObject);
|
scene.remove(this._light);
|
||||||
this._isEnabled = false;
|
this._isEnabled = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
updatePreRender(target: gdjs.EffectsTarget): any {}
|
updatePreRender(target: gdjs.EffectsTarget): any {}
|
||||||
updateDoubleParameter(parameterName: string, value: number): void {
|
updateDoubleParameter(parameterName: string, value: number): void {
|
||||||
if (parameterName === 'intensity') {
|
if (parameterName === 'intensity') {
|
||||||
this.light.intensity = value;
|
this._light.intensity = value;
|
||||||
} else if (parameterName === 'elevation') {
|
} else if (parameterName === 'elevation') {
|
||||||
this.elevation = value;
|
this._elevation = value;
|
||||||
this.updateRotation();
|
this.updateRotation();
|
||||||
} else if (parameterName === 'rotation') {
|
} else if (parameterName === 'rotation') {
|
||||||
this.rotation = value;
|
this._rotation = value;
|
||||||
this.updateRotation();
|
this.updateRotation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getDoubleParameter(parameterName: string): number {
|
getDoubleParameter(parameterName: string): number {
|
||||||
if (parameterName === 'intensity') {
|
if (parameterName === 'intensity') {
|
||||||
return this.light.intensity;
|
return this._light.intensity;
|
||||||
} else if (parameterName === 'elevation') {
|
} else if (parameterName === 'elevation') {
|
||||||
return this.elevation;
|
return this._elevation;
|
||||||
} else if (parameterName === 'rotation') {
|
} else if (parameterName === 'rotation') {
|
||||||
return this.rotation;
|
return this._rotation;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
updateStringParameter(parameterName: string, value: string): void {
|
updateStringParameter(parameterName: string, value: string): void {
|
||||||
if (parameterName === 'skyColor') {
|
if (parameterName === 'skyColor') {
|
||||||
this.light.color = new THREE.Color(
|
this._light.color = new THREE.Color(
|
||||||
gdjs.rgbOrHexStringToNumber(value)
|
gdjs.rgbOrHexStringToNumber(value)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (parameterName === 'groundColor') {
|
if (parameterName === 'groundColor') {
|
||||||
this.light.groundColor = new THREE.Color(
|
this._light.groundColor = new THREE.Color(
|
||||||
gdjs.rgbOrHexStringToNumber(value)
|
gdjs.rgbOrHexStringToNumber(value)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (parameterName === 'top') {
|
if (parameterName === 'top') {
|
||||||
this.top = value;
|
this._top = value;
|
||||||
this.updateRotation();
|
this.updateRotation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateColorParameter(parameterName: string, value: number): void {
|
updateColorParameter(parameterName: string, value: number): void {
|
||||||
if (parameterName === 'skyColor') {
|
if (parameterName === 'skyColor') {
|
||||||
this.light.color.setHex(value);
|
this._light.color.setHex(value);
|
||||||
}
|
}
|
||||||
if (parameterName === 'groundColor') {
|
if (parameterName === 'groundColor') {
|
||||||
this.light.groundColor.setHex(value);
|
this._light.groundColor.setHex(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getColorParameter(parameterName: string): number {
|
getColorParameter(parameterName: string): number {
|
||||||
if (parameterName === 'skyColor') {
|
if (parameterName === 'skyColor') {
|
||||||
return this.light.color.getHex();
|
return this._light.color.getHex();
|
||||||
}
|
}
|
||||||
if (parameterName === 'groundColor') {
|
if (parameterName === 'groundColor') {
|
||||||
return this.light.groundColor.getHex();
|
return this._light.groundColor.getHex();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||||
updateRotation() {
|
updateRotation() {
|
||||||
if (this.top === 'Z+') {
|
if (this._top === 'Y-') {
|
||||||
// 0° is a light from the right of the screen.
|
// `rotation` at 0° becomes a light from Z+.
|
||||||
this.rotationObject.rotation.z = gdjs.toRad(this.rotation);
|
this._light.position.set(
|
||||||
this.rotationObject.rotation.y = -gdjs.toRad(this.elevation);
|
Math.cos(gdjs.toRad(-this._rotation + 90)) *
|
||||||
|
Math.cos(gdjs.toRad(this._elevation)),
|
||||||
|
-Math.sin(gdjs.toRad(this._elevation)),
|
||||||
|
Math.sin(gdjs.toRad(-this._rotation + 90)) *
|
||||||
|
Math.cos(gdjs.toRad(this._elevation))
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// 0° becomes a light from Z+.
|
// `rotation` at 0° is a light from the right of the screen.
|
||||||
this.rotationObject.rotation.y = gdjs.toRad(this.rotation - 90);
|
this._light.position.set(
|
||||||
this.rotationObject.rotation.z = -gdjs.toRad(this.elevation);
|
Math.cos(gdjs.toRad(this._rotation)) *
|
||||||
|
Math.cos(gdjs.toRad(this._elevation)),
|
||||||
|
Math.sin(gdjs.toRad(this._rotation)) *
|
||||||
|
Math.cos(gdjs.toRad(this._elevation)),
|
||||||
|
Math.sin(gdjs.toRad(this._elevation))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getNetworkSyncData(): HemisphereLightFilterNetworkSyncData {
|
getNetworkSyncData(): HemisphereLightFilterNetworkSyncData {
|
||||||
return {
|
return {
|
||||||
i: this.light.intensity,
|
i: this._light.intensity,
|
||||||
sc: this.light.color.getHex(),
|
sc: this._light.color.getHex(),
|
||||||
gc: this.light.groundColor.getHex(),
|
gc: this._light.groundColor.getHex(),
|
||||||
e: this.elevation,
|
e: this._elevation,
|
||||||
r: this.rotation,
|
r: this._rotation,
|
||||||
t: this.top,
|
t: this._top,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
updateFromNetworkSyncData(
|
updateFromNetworkSyncData(
|
||||||
syncData: HemisphereLightFilterNetworkSyncData
|
syncData: HemisphereLightFilterNetworkSyncData
|
||||||
): void {
|
): void {
|
||||||
this.light.intensity = syncData.i;
|
this._light.intensity = syncData.i;
|
||||||
this.light.color.setHex(syncData.sc);
|
this._light.color.setHex(syncData.sc);
|
||||||
this.light.groundColor.setHex(syncData.gc);
|
this._light.groundColor.setHex(syncData.gc);
|
||||||
this.elevation = syncData.e;
|
this._elevation = syncData.e;
|
||||||
this.rotation = syncData.r;
|
this._rotation = syncData.r;
|
||||||
this.top = syncData.t;
|
this._top = syncData.t;
|
||||||
this.updateRotation();
|
this.updateRotation();
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
@@ -859,7 +859,9 @@ module.exports = {
|
|||||||
propertyName === 'rightFaceResourceRepeat' ||
|
propertyName === 'rightFaceResourceRepeat' ||
|
||||||
propertyName === 'topFaceResourceRepeat' ||
|
propertyName === 'topFaceResourceRepeat' ||
|
||||||
propertyName === 'bottomFaceResourceRepeat' ||
|
propertyName === 'bottomFaceResourceRepeat' ||
|
||||||
propertyName === 'enableTextureTransparency'
|
propertyName === 'enableTextureTransparency' ||
|
||||||
|
propertyName === 'isCastingShadow' ||
|
||||||
|
propertyName === 'isReceivingShadow'
|
||||||
) {
|
) {
|
||||||
objectContent[propertyName] = newValue === '1';
|
objectContent[propertyName] = newValue === '1';
|
||||||
return true;
|
return true;
|
||||||
@@ -887,8 +889,8 @@ module.exports = {
|
|||||||
.getOrCreate('facesOrientation')
|
.getOrCreate('facesOrientation')
|
||||||
.setValue(objectContent.facesOrientation || 'Y')
|
.setValue(objectContent.facesOrientation || 'Y')
|
||||||
.setType('choice')
|
.setType('choice')
|
||||||
.addExtraInfo('Y')
|
.addChoice('Y', 'Y')
|
||||||
.addExtraInfo('Z')
|
.addChoice('Z', 'Z')
|
||||||
.setLabel(_('Faces orientation'))
|
.setLabel(_('Faces orientation'))
|
||||||
.setDescription(
|
.setDescription(
|
||||||
_(
|
_(
|
||||||
@@ -948,8 +950,8 @@ module.exports = {
|
|||||||
.getOrCreate('backFaceUpThroughWhichAxisRotation')
|
.getOrCreate('backFaceUpThroughWhichAxisRotation')
|
||||||
.setValue(objectContent.backFaceUpThroughWhichAxisRotation || 'X')
|
.setValue(objectContent.backFaceUpThroughWhichAxisRotation || 'X')
|
||||||
.setType('choice')
|
.setType('choice')
|
||||||
.addExtraInfo('X')
|
.addChoice('X', 'X')
|
||||||
.addExtraInfo('Y')
|
.addChoice('Y', 'Y')
|
||||||
.setLabel(_('Back face orientation'))
|
.setLabel(_('Back face orientation'))
|
||||||
.setDescription(
|
.setDescription(
|
||||||
_(
|
_(
|
||||||
@@ -1083,11 +1085,29 @@ module.exports = {
|
|||||||
|
|
||||||
objectProperties
|
objectProperties
|
||||||
.getOrCreate('materialType')
|
.getOrCreate('materialType')
|
||||||
.setValue(objectContent.materialType || 'Basic')
|
.setValue(objectContent.materialType || 'StandardWithoutMetalness')
|
||||||
.setType('choice')
|
.setType('choice')
|
||||||
.addExtraInfo('Basic')
|
.addChoice('Basic', _('Basic (no lighting, no shadows)'))
|
||||||
.addExtraInfo('StandardWithoutMetalness')
|
.addChoice(
|
||||||
.setLabel(_('Material type'));
|
'StandardWithoutMetalness',
|
||||||
|
_('Standard (without metalness)')
|
||||||
|
)
|
||||||
|
.setLabel(_('Material type'))
|
||||||
|
.setGroup(_('Lighting'));
|
||||||
|
|
||||||
|
objectProperties
|
||||||
|
.getOrCreate('isCastingShadow')
|
||||||
|
.setValue(objectContent.isCastingShadow ? 'true' : 'false')
|
||||||
|
.setType('boolean')
|
||||||
|
.setLabel(_('Shadow casting'))
|
||||||
|
.setGroup(_('Lighting'));
|
||||||
|
|
||||||
|
objectProperties
|
||||||
|
.getOrCreate('isReceivingShadow')
|
||||||
|
.setValue(objectContent.isReceivingShadow ? 'true' : 'false')
|
||||||
|
.setType('boolean')
|
||||||
|
.setLabel(_('Shadow receiving'))
|
||||||
|
.setGroup(_('Lighting'));
|
||||||
|
|
||||||
return objectProperties;
|
return objectProperties;
|
||||||
};
|
};
|
||||||
@@ -1116,8 +1136,10 @@ module.exports = {
|
|||||||
rightFaceResourceRepeat: false,
|
rightFaceResourceRepeat: false,
|
||||||
topFaceResourceRepeat: false,
|
topFaceResourceRepeat: false,
|
||||||
bottomFaceResourceRepeat: false,
|
bottomFaceResourceRepeat: false,
|
||||||
materialType: 'Basic',
|
materialType: 'StandardWithoutMetalness',
|
||||||
tint: '255;255;255',
|
tint: '255;255;255',
|
||||||
|
isCastingShadow: true,
|
||||||
|
isReceivingShadow: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
Cube3DObject.updateInitialInstanceProperty = function (
|
Cube3DObject.updateInitialInstanceProperty = function (
|
||||||
@@ -1894,11 +1916,11 @@ module.exports = {
|
|||||||
.setType('number');
|
.setType('number');
|
||||||
properties
|
properties
|
||||||
.getOrCreate('top')
|
.getOrCreate('top')
|
||||||
.setValue('Y-')
|
.setValue('Z+')
|
||||||
.setLabel(_('3D world top'))
|
.setLabel(_('3D world top'))
|
||||||
.setType('choice')
|
.setType('choice')
|
||||||
.addExtraInfo('Y-')
|
|
||||||
.addExtraInfo('Z+')
|
.addExtraInfo('Z+')
|
||||||
|
.addExtraInfo('Y-')
|
||||||
.setGroup(_('Orientation'));
|
.setGroup(_('Orientation'));
|
||||||
properties
|
properties
|
||||||
.getOrCreate('elevation')
|
.getOrCreate('elevation')
|
||||||
@@ -1913,6 +1935,47 @@ module.exports = {
|
|||||||
.setLabel(_('Rotation (in degrees)'))
|
.setLabel(_('Rotation (in degrees)'))
|
||||||
.setType('number')
|
.setType('number')
|
||||||
.setGroup(_('Orientation'));
|
.setGroup(_('Orientation'));
|
||||||
|
properties
|
||||||
|
.getOrCreate('isCastingShadow')
|
||||||
|
.setValue('false')
|
||||||
|
.setLabel(_('Shadow casting'))
|
||||||
|
.setType('boolean')
|
||||||
|
.setGroup(_('Shadows'));
|
||||||
|
properties
|
||||||
|
.getOrCreate('shadowQuality')
|
||||||
|
.setValue('medium')
|
||||||
|
.addChoice('low', _('Low quality'))
|
||||||
|
.addChoice('medium', _('Medium quality'))
|
||||||
|
.addChoice('high', _('High quality'))
|
||||||
|
.setLabel(_('Shadow quality'))
|
||||||
|
.setType('choice')
|
||||||
|
.setGroup(_('Shadows'));
|
||||||
|
properties
|
||||||
|
.getOrCreate('minimumShadowBias')
|
||||||
|
.setValue('0')
|
||||||
|
.setLabel(_('Shadow bias'))
|
||||||
|
.setDescription(
|
||||||
|
_(
|
||||||
|
'Use this to avoid "shadow acne" due to depth buffer precision. Choose a value small enough like 0.001 to avoid creating distance between shadows and objects but not too small to avoid shadow glitches on low/medium quality. This value is used for high quality, and multiplied by 1.25 for medium quality and 2 for low quality.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.setType('number')
|
||||||
|
.setGroup(_('Shadows'))
|
||||||
|
.setAdvanced(true);
|
||||||
|
properties
|
||||||
|
.getOrCreate('frustumSize')
|
||||||
|
.setValue('4000')
|
||||||
|
.setLabel(_('Shadow frustum size'))
|
||||||
|
.setType('number')
|
||||||
|
.setGroup(_('Shadows'))
|
||||||
|
.setAdvanced(true);
|
||||||
|
properties
|
||||||
|
.getOrCreate('distanceFromCamera')
|
||||||
|
.setValue('1500')
|
||||||
|
.setLabel(_("Distance from layer's camera"))
|
||||||
|
.setType('number')
|
||||||
|
.setGroup(_('Shadows'))
|
||||||
|
.setAdvanced(true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const effect = extension
|
const effect = extension
|
||||||
@@ -1944,11 +2007,11 @@ module.exports = {
|
|||||||
.setType('number');
|
.setType('number');
|
||||||
properties
|
properties
|
||||||
.getOrCreate('top')
|
.getOrCreate('top')
|
||||||
.setValue('Y-')
|
.setValue('Z+')
|
||||||
.setLabel(_('3D world top'))
|
.setLabel(_('3D world top'))
|
||||||
.setType('choice')
|
.setType('choice')
|
||||||
.addExtraInfo('Y-')
|
|
||||||
.addExtraInfo('Z+')
|
.addExtraInfo('Z+')
|
||||||
|
.addExtraInfo('Y-')
|
||||||
.setGroup(_('Orientation'));
|
.setGroup(_('Orientation'));
|
||||||
properties
|
properties
|
||||||
.getOrCreate('elevation')
|
.getOrCreate('elevation')
|
||||||
@@ -3210,6 +3273,8 @@ module.exports = {
|
|||||||
|
|
||||||
this._threeObject = new THREE.Group();
|
this._threeObject = new THREE.Group();
|
||||||
this._threeObject.rotation.order = 'ZYX';
|
this._threeObject.rotation.order = 'ZYX';
|
||||||
|
this._threeObject.castShadow = true;
|
||||||
|
this._threeObject.receiveShadow = true;
|
||||||
this._threeGroup.add(this._threeObject);
|
this._threeGroup.add(this._threeObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@ Model3DObjectConfiguration::Model3DObjectConfiguration()
|
|||||||
: width(100), height(100), depth(100), rotationX(0), rotationY(0),
|
: width(100), height(100), depth(100), rotationX(0), rotationY(0),
|
||||||
rotationZ(0), modelResourceName(""), materialType("StandardWithoutMetalness"),
|
rotationZ(0), modelResourceName(""), materialType("StandardWithoutMetalness"),
|
||||||
originLocation("ModelOrigin"), centerLocation("ModelOrigin"),
|
originLocation("ModelOrigin"), centerLocation("ModelOrigin"),
|
||||||
keepAspectRatio(true), crossfadeDuration(0.1f) {}
|
keepAspectRatio(true), crossfadeDuration(0.1f), isCastingShadow(true), isReceivingShadow(true) {}
|
||||||
|
|
||||||
bool Model3DObjectConfiguration::UpdateProperty(const gd::String &propertyName,
|
bool Model3DObjectConfiguration::UpdateProperty(const gd::String &propertyName,
|
||||||
const gd::String &newValue) {
|
const gd::String &newValue) {
|
||||||
@@ -75,6 +75,16 @@ bool Model3DObjectConfiguration::UpdateProperty(const gd::String &propertyName,
|
|||||||
crossfadeDuration = newValue.To<double>();
|
crossfadeDuration = newValue.To<double>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if(propertyName == "isCastingShadow")
|
||||||
|
{
|
||||||
|
isCastingShadow = newValue == "1";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(propertyName == "isReceivingShadow")
|
||||||
|
{
|
||||||
|
isReceivingShadow = newValue == "1";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -143,19 +153,20 @@ Model3DObjectConfiguration::GetProperties() const {
|
|||||||
objectProperties["materialType"]
|
objectProperties["materialType"]
|
||||||
.SetValue(materialType.empty() ? "Basic" : materialType)
|
.SetValue(materialType.empty() ? "Basic" : materialType)
|
||||||
.SetType("choice")
|
.SetType("choice")
|
||||||
.AddExtraInfo("Basic")
|
.AddChoice("Basic", _("Basic (no lighting, no shadows)"))
|
||||||
.AddExtraInfo("StandardWithoutMetalness")
|
.AddChoice("StandardWithoutMetalness", _("Standard (without metalness)"))
|
||||||
.AddExtraInfo("KeepOriginal")
|
.AddChoice("KeepOriginal", _("Keep original"))
|
||||||
.SetLabel(_("Material"));
|
.SetLabel(_("Material"))
|
||||||
|
.SetGroup(_("Lighting"));
|
||||||
|
|
||||||
objectProperties["originLocation"]
|
objectProperties["originLocation"]
|
||||||
.SetValue(originLocation.empty() ? "TopLeft" : originLocation)
|
.SetValue(originLocation.empty() ? "TopLeft" : originLocation)
|
||||||
.SetType("choice")
|
.SetType("choice")
|
||||||
.AddExtraInfo("ModelOrigin")
|
.AddChoice("ModelOrigin", _("Model origin"))
|
||||||
.AddExtraInfo("TopLeft")
|
.AddChoice("TopLeft", _("Top left"))
|
||||||
.AddExtraInfo("ObjectCenter")
|
.AddChoice("ObjectCenter", _("Object center"))
|
||||||
.AddExtraInfo("BottomCenterZ")
|
.AddChoice("BottomCenterZ", _("Bottom center (Z)"))
|
||||||
.AddExtraInfo("BottomCenterY")
|
.AddChoice("BottomCenterY", _("Bottom center (Y)"))
|
||||||
.SetLabel(_("Origin point"))
|
.SetLabel(_("Origin point"))
|
||||||
.SetGroup(_("Points"))
|
.SetGroup(_("Points"))
|
||||||
.SetAdvanced(true);
|
.SetAdvanced(true);
|
||||||
@@ -163,10 +174,10 @@ Model3DObjectConfiguration::GetProperties() const {
|
|||||||
objectProperties["centerLocation"]
|
objectProperties["centerLocation"]
|
||||||
.SetValue(centerLocation.empty() ? "ObjectCenter" : centerLocation)
|
.SetValue(centerLocation.empty() ? "ObjectCenter" : centerLocation)
|
||||||
.SetType("choice")
|
.SetType("choice")
|
||||||
.AddExtraInfo("ModelOrigin")
|
.AddChoice("ModelOrigin", _("Model origin"))
|
||||||
.AddExtraInfo("ObjectCenter")
|
.AddChoice("ObjectCenter", _("Object center"))
|
||||||
.AddExtraInfo("BottomCenterZ")
|
.AddChoice("BottomCenterZ", _("Bottom center (Z)"))
|
||||||
.AddExtraInfo("BottomCenterY")
|
.AddChoice("BottomCenterY", _("Bottom center (Y)"))
|
||||||
.SetLabel(_("Center point"))
|
.SetLabel(_("Center point"))
|
||||||
.SetGroup(_("Points"))
|
.SetGroup(_("Points"))
|
||||||
.SetAdvanced(true);
|
.SetAdvanced(true);
|
||||||
@@ -178,6 +189,20 @@ Model3DObjectConfiguration::GetProperties() const {
|
|||||||
.SetGroup(_("Animations"))
|
.SetGroup(_("Animations"))
|
||||||
.SetMeasurementUnit(gd::MeasurementUnit::GetSecond());
|
.SetMeasurementUnit(gd::MeasurementUnit::GetSecond());
|
||||||
|
|
||||||
|
objectProperties["isCastingShadow"]
|
||||||
|
.SetValue(isCastingShadow ? "true" : "false")
|
||||||
|
.SetType("boolean")
|
||||||
|
.SetLabel(_("Shadow casting"))
|
||||||
|
.SetGroup(_("Lighting"));
|
||||||
|
|
||||||
|
objectProperties["isReceivingShadow"]
|
||||||
|
.SetValue(isReceivingShadow ? "true" : "false")
|
||||||
|
.SetType("boolean")
|
||||||
|
.SetLabel(_("Shadow receiving"))
|
||||||
|
.SetGroup(_("Lighting"));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return objectProperties;
|
return objectProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,6 +235,8 @@ void Model3DObjectConfiguration::DoUnserializeFrom(
|
|||||||
centerLocation = content.GetStringAttribute("centerLocation");
|
centerLocation = content.GetStringAttribute("centerLocation");
|
||||||
keepAspectRatio = content.GetBoolAttribute("keepAspectRatio");
|
keepAspectRatio = content.GetBoolAttribute("keepAspectRatio");
|
||||||
crossfadeDuration = content.GetDoubleAttribute("crossfadeDuration");
|
crossfadeDuration = content.GetDoubleAttribute("crossfadeDuration");
|
||||||
|
isCastingShadow = content.GetBoolAttribute("isCastingShadow");
|
||||||
|
isReceivingShadow = content.GetBoolAttribute("isReceivingShadow");
|
||||||
|
|
||||||
RemoveAllAnimations();
|
RemoveAllAnimations();
|
||||||
auto &animationsElement = content.GetChild("animations");
|
auto &animationsElement = content.GetChild("animations");
|
||||||
@@ -239,6 +266,8 @@ void Model3DObjectConfiguration::DoSerializeTo(
|
|||||||
content.SetAttribute("centerLocation", centerLocation);
|
content.SetAttribute("centerLocation", centerLocation);
|
||||||
content.SetAttribute("keepAspectRatio", keepAspectRatio);
|
content.SetAttribute("keepAspectRatio", keepAspectRatio);
|
||||||
content.SetAttribute("crossfadeDuration", crossfadeDuration);
|
content.SetAttribute("crossfadeDuration", crossfadeDuration);
|
||||||
|
content.SetAttribute("isCastingShadow", isCastingShadow);
|
||||||
|
content.SetAttribute("isReceivingShadow", isReceivingShadow);
|
||||||
|
|
||||||
auto &animationsElement = content.AddChild("animations");
|
auto &animationsElement = content.AddChild("animations");
|
||||||
animationsElement.ConsiderAsArrayOf("animation");
|
animationsElement.ConsiderAsArrayOf("animation");
|
||||||
|
@@ -160,6 +160,8 @@ public:
|
|||||||
const gd::String& GetCenterLocation() const { return centerLocation; };
|
const gd::String& GetCenterLocation() const { return centerLocation; };
|
||||||
|
|
||||||
bool shouldKeepAspectRatio() const { return keepAspectRatio; };
|
bool shouldKeepAspectRatio() const { return keepAspectRatio; };
|
||||||
|
bool shouldCastShadow() const { return isCastingShadow; };
|
||||||
|
bool shouldReceiveShadow() const { return isReceivingShadow; };
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -182,6 +184,8 @@ private:
|
|||||||
gd::String centerLocation;
|
gd::String centerLocation;
|
||||||
|
|
||||||
bool keepAspectRatio;
|
bool keepAspectRatio;
|
||||||
|
bool isCastingShadow;
|
||||||
|
bool isReceivingShadow;
|
||||||
|
|
||||||
std::vector<Model3DAnimation> animations;
|
std::vector<Model3DAnimation> animations;
|
||||||
static Model3DAnimation badAnimation; //< Bad animation when an out of bound
|
static Model3DAnimation badAnimation; //< Bad animation when an out of bound
|
||||||
|
@@ -38,6 +38,8 @@ namespace gdjs {
|
|||||||
| 'BottomCenterY';
|
| 'BottomCenterY';
|
||||||
animations: Model3DAnimation[];
|
animations: Model3DAnimation[];
|
||||||
crossfadeDuration: float;
|
crossfadeDuration: float;
|
||||||
|
isCastingShadow: boolean;
|
||||||
|
isReceivingShadow: boolean;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,6 +103,8 @@ namespace gdjs {
|
|||||||
_animationSpeedScale: float = 1;
|
_animationSpeedScale: float = 1;
|
||||||
_animationPaused: boolean = false;
|
_animationPaused: boolean = false;
|
||||||
_crossfadeDuration: float = 0;
|
_crossfadeDuration: float = 0;
|
||||||
|
_isCastingShadow: boolean = true;
|
||||||
|
_isReceivingShadow: boolean = true;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||||
@@ -123,6 +127,8 @@ namespace gdjs {
|
|||||||
objectData.content.materialType
|
objectData.content.materialType
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.setIsCastingShadow(objectData.content.isCastingShadow);
|
||||||
|
this.setIsReceivingShadow(objectData.content.isReceivingShadow);
|
||||||
this.onModelChanged(objectData);
|
this.onModelChanged(objectData);
|
||||||
|
|
||||||
this._crossfadeDuration = objectData.content.crossfadeDuration || 0;
|
this._crossfadeDuration = objectData.content.crossfadeDuration || 0;
|
||||||
@@ -195,6 +201,18 @@ namespace gdjs {
|
|||||||
newObjectData.content.centerLocation
|
newObjectData.content.centerLocation
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
oldObjectData.content.isCastingShadow !==
|
||||||
|
newObjectData.content.isCastingShadow
|
||||||
|
) {
|
||||||
|
this.setIsCastingShadow(newObjectData.content.isCastingShadow);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
oldObjectData.content.isReceivingShadow !==
|
||||||
|
newObjectData.content.isReceivingShadow
|
||||||
|
) {
|
||||||
|
this.setIsReceivingShadow(newObjectData.content.isReceivingShadow);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,6 +376,16 @@ namespace gdjs {
|
|||||||
return this._renderer.hasAnimationEnded();
|
return this._renderer.hasAnimationEnded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setIsCastingShadow(value: boolean): void {
|
||||||
|
this._isCastingShadow = value;
|
||||||
|
this._renderer._updateShadow();
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsReceivingShadow(value: boolean): void {
|
||||||
|
this._isReceivingShadow = value;
|
||||||
|
this._renderer._updateShadow();
|
||||||
|
}
|
||||||
|
|
||||||
setCrossfadeDuration(duration: number): void {
|
setCrossfadeDuration(duration: number): void {
|
||||||
if (this._crossfadeDuration === duration) return;
|
if (this._crossfadeDuration === duration) return;
|
||||||
this._crossfadeDuration = duration;
|
this._crossfadeDuration = duration;
|
||||||
|
@@ -286,6 +286,7 @@ namespace gdjs {
|
|||||||
this.get3DRendererObject().remove(this._threeObject);
|
this.get3DRendererObject().remove(this._threeObject);
|
||||||
this.get3DRendererObject().add(threeObject);
|
this.get3DRendererObject().add(threeObject);
|
||||||
this._threeObject = threeObject;
|
this._threeObject = threeObject;
|
||||||
|
this._updateShadow();
|
||||||
|
|
||||||
// Start the current animation on the new 3D object.
|
// Start the current animation on the new 3D object.
|
||||||
this._animationMixer = new THREE.AnimationMixer(root);
|
this._animationMixer = new THREE.AnimationMixer(root);
|
||||||
@@ -323,6 +324,13 @@ namespace gdjs {
|
|||||||
return this._originalModel.animations[animationIndex].name;
|
return this._originalModel.animations[animationIndex].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_updateShadow() {
|
||||||
|
this._threeObject.traverse((child) => {
|
||||||
|
child.castShadow = this._model3DRuntimeObject._isCastingShadow;
|
||||||
|
child.receiveShadow = this._model3DRuntimeObject._isReceivingShadow;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if animation has ended.
|
* Return true if animation has ended.
|
||||||
* The animation had ended if:
|
* The animation had ended if:
|
||||||
|
@@ -14,6 +14,7 @@ describe('gdjs.AnchorRuntimeBehavior', () => {
|
|||||||
effects: [],
|
effects: [],
|
||||||
content: {},
|
content: {},
|
||||||
childrenContent: {},
|
childrenContent: {},
|
||||||
|
isInnerAreaFollowingParentSize: false,
|
||||||
});
|
});
|
||||||
runtimeScene.addObject(customObject);
|
runtimeScene.addObject(customObject);
|
||||||
customObject.setPosition(500, 250);
|
customObject.setPosition(500, 250);
|
||||||
|
@@ -75,9 +75,9 @@ module.exports = {
|
|||||||
.getOrCreate('align')
|
.getOrCreate('align')
|
||||||
.setValue(objectContent.align)
|
.setValue(objectContent.align)
|
||||||
.setType('choice')
|
.setType('choice')
|
||||||
.addExtraInfo('left')
|
.addChoice('left', _('Left'))
|
||||||
.addExtraInfo('center')
|
.addChoice('center', _('Center'))
|
||||||
.addExtraInfo('right')
|
.addChoice('right', _('Right'))
|
||||||
.setLabel(_('Base alignment'))
|
.setLabel(_('Base alignment'))
|
||||||
.setGroup(_('Appearance'));
|
.setGroup(_('Appearance'));
|
||||||
|
|
||||||
@@ -88,9 +88,9 @@ module.exports = {
|
|||||||
.getOrCreate('verticalTextAlignment')
|
.getOrCreate('verticalTextAlignment')
|
||||||
.setValue(objectContent.verticalTextAlignment)
|
.setValue(objectContent.verticalTextAlignment)
|
||||||
.setType('choice')
|
.setType('choice')
|
||||||
.addExtraInfo('top')
|
.addChoice('top', _('Top'))
|
||||||
.addExtraInfo('center')
|
.addChoice('center', _('Center'))
|
||||||
.addExtraInfo('bottom')
|
.addChoice('bottom', _('Bottom'))
|
||||||
.setLabel(_('Vertical alignment'))
|
.setLabel(_('Vertical alignment'))
|
||||||
.setGroup(_('Appearance'));
|
.setGroup(_('Appearance'));
|
||||||
|
|
||||||
|
@@ -61,9 +61,9 @@ module.exports = {
|
|||||||
.getOrCreate('align')
|
.getOrCreate('align')
|
||||||
.setValue(objectContent.align)
|
.setValue(objectContent.align)
|
||||||
.setType('choice')
|
.setType('choice')
|
||||||
.addExtraInfo('left')
|
.addChoice('left', _('Left'))
|
||||||
.addExtraInfo('center')
|
.addChoice('center', _('Center'))
|
||||||
.addExtraInfo('right')
|
.addChoice('right', _('Right'))
|
||||||
.setLabel(_('Alignment'))
|
.setLabel(_('Alignment'))
|
||||||
.setGroup(_('Appearance'));
|
.setGroup(_('Appearance'));
|
||||||
|
|
||||||
@@ -74,9 +74,9 @@ module.exports = {
|
|||||||
.getOrCreate('verticalTextAlignment')
|
.getOrCreate('verticalTextAlignment')
|
||||||
.setValue(objectContent.verticalTextAlignment)
|
.setValue(objectContent.verticalTextAlignment)
|
||||||
.setType('choice')
|
.setType('choice')
|
||||||
.addExtraInfo('top')
|
.addChoice('top', _('Top'))
|
||||||
.addExtraInfo('center')
|
.addChoice('center', _('Center'))
|
||||||
.addExtraInfo('bottom')
|
.addChoice('bottom', _('Bottom'))
|
||||||
.setLabel(_('Vertical alignment'))
|
.setLabel(_('Vertical alignment'))
|
||||||
.setGroup(_('Appearance'));
|
.setGroup(_('Appearance'));
|
||||||
|
|
||||||
|
@@ -12,7 +12,7 @@ This project is released under the MIT License.
|
|||||||
#include "GDCore/Tools/Localization.h"
|
#include "GDCore/Tools/Localization.h"
|
||||||
|
|
||||||
void DestroyOutsideBehavior::InitializeContent(gd::SerializerElement& content) {
|
void DestroyOutsideBehavior::InitializeContent(gd::SerializerElement& content) {
|
||||||
content.SetAttribute("extraBorder", 0);
|
content.SetAttribute("extraBorder", 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(GD_IDE_ONLY)
|
#if defined(GD_IDE_ONLY)
|
||||||
|
@@ -35,25 +35,32 @@ void DeclareDraggableBehaviorExtension(gd::PlatformExtension& extension) {
|
|||||||
std::make_shared<DraggableBehavior>(),
|
std::make_shared<DraggableBehavior>(),
|
||||||
std::shared_ptr<gd::BehaviorsSharedData>());
|
std::shared_ptr<gd::BehaviorsSharedData>());
|
||||||
|
|
||||||
aut.AddCondition("Dragged",
|
aut.AddCondition(
|
||||||
_("Being dragged"),
|
"Dragged",
|
||||||
_("Check if the object is being dragged."),
|
_("Being dragged"),
|
||||||
_("_PARAM0_ is being dragged"),
|
_("Check if the object is being dragged. This means the mouse button "
|
||||||
_("Draggable"),
|
"or touch is pressed on it. When the mouse button or touch is "
|
||||||
"CppPlatform/Extensions/draggableicon24.png",
|
"released, the object is no longer being considered dragged (use "
|
||||||
"CppPlatform/Extensions/draggableicon16.png")
|
"the condition \"Was just dropped\" to check when the dragging is "
|
||||||
|
"ending)."),
|
||||||
|
_("_PARAM0_ is being dragged"),
|
||||||
|
_("Draggable"),
|
||||||
|
"CppPlatform/Extensions/draggableicon24.png",
|
||||||
|
"CppPlatform/Extensions/draggableicon16.png")
|
||||||
|
|
||||||
.AddParameter("object", _("Object"))
|
.AddParameter("object", _("Object"))
|
||||||
.AddParameter("behavior", _("Behavior"), "Draggable")
|
.AddParameter("behavior", _("Behavior"), "Draggable")
|
||||||
.SetFunctionName("IsDragged");
|
.SetFunctionName("IsDragged");
|
||||||
|
|
||||||
aut.AddCondition("Dropped",
|
aut.AddCondition(
|
||||||
_("Was just dropped"),
|
"Dropped",
|
||||||
_("Check if the object was just dropped after being dragged."),
|
_("Was just dropped"),
|
||||||
_("_PARAM0_ was just dropped"),
|
_("Check if the object was just dropped after being dragged (the "
|
||||||
_("Draggable"),
|
"mouse button or touch was just released this frame)."),
|
||||||
"CppPlatform/Extensions/draggableicon24.png",
|
_("_PARAM0_ was just dropped"),
|
||||||
"CppPlatform/Extensions/draggableicon16.png")
|
_("Draggable"),
|
||||||
|
"CppPlatform/Extensions/draggableicon24.png",
|
||||||
|
"CppPlatform/Extensions/draggableicon16.png")
|
||||||
|
|
||||||
.AddParameter("object", _("Object"))
|
.AddParameter("object", _("Object"))
|
||||||
.AddParameter("behavior", _("Behavior"), "Draggable")
|
.AddParameter("behavior", _("Behavior"), "Draggable")
|
||||||
|
@@ -293,6 +293,8 @@ namespace gdjs {
|
|||||||
x: objectNetworkSyncData.x,
|
x: objectNetworkSyncData.x,
|
||||||
y: objectNetworkSyncData.y,
|
y: objectNetworkSyncData.y,
|
||||||
z: objectNetworkSyncData.z,
|
z: objectNetworkSyncData.z,
|
||||||
|
w: objectNetworkSyncData.w,
|
||||||
|
h: objectNetworkSyncData.h,
|
||||||
zo: objectNetworkSyncData.zo,
|
zo: objectNetworkSyncData.zo,
|
||||||
a: objectNetworkSyncData.a,
|
a: objectNetworkSyncData.a,
|
||||||
hid: objectNetworkSyncData.hid,
|
hid: objectNetworkSyncData.hid,
|
||||||
@@ -369,6 +371,9 @@ namespace gdjs {
|
|||||||
this._lastSentBasicObjectSyncData = {
|
this._lastSentBasicObjectSyncData = {
|
||||||
x: objectNetworkSyncData.x,
|
x: objectNetworkSyncData.x,
|
||||||
y: objectNetworkSyncData.y,
|
y: objectNetworkSyncData.y,
|
||||||
|
z: objectNetworkSyncData.z,
|
||||||
|
w: objectNetworkSyncData.w,
|
||||||
|
h: objectNetworkSyncData.h,
|
||||||
zo: objectNetworkSyncData.zo,
|
zo: objectNetworkSyncData.zo,
|
||||||
a: objectNetworkSyncData.a,
|
a: objectNetworkSyncData.a,
|
||||||
hid: objectNetworkSyncData.hid,
|
hid: objectNetworkSyncData.hid,
|
||||||
|
@@ -116,48 +116,7 @@ namespace gdjs {
|
|||||||
|
|
||||||
_updateLocalPositions() {
|
_updateLocalPositions() {
|
||||||
const obj = this._object;
|
const obj = this._object;
|
||||||
this._centerSprite.position.x = obj._lBorder;
|
|
||||||
this._centerSprite.position.y = obj._tBorder;
|
|
||||||
|
|
||||||
//Right
|
|
||||||
this._borderSprites[0].position.x = obj._width - obj._rBorder;
|
|
||||||
this._borderSprites[0].position.y = obj._tBorder;
|
|
||||||
|
|
||||||
//Top-right
|
|
||||||
this._borderSprites[1].position.x =
|
|
||||||
obj._width - this._borderSprites[1].width;
|
|
||||||
this._borderSprites[1].position.y = 0;
|
|
||||||
|
|
||||||
//Top
|
|
||||||
this._borderSprites[2].position.x = obj._lBorder;
|
|
||||||
this._borderSprites[2].position.y = 0;
|
|
||||||
|
|
||||||
//Top-Left
|
|
||||||
this._borderSprites[3].position.x = 0;
|
|
||||||
this._borderSprites[3].position.y = 0;
|
|
||||||
|
|
||||||
//Left
|
|
||||||
this._borderSprites[4].position.x = 0;
|
|
||||||
this._borderSprites[4].position.y = obj._tBorder;
|
|
||||||
|
|
||||||
//Bottom-Left
|
|
||||||
this._borderSprites[5].position.x = 0;
|
|
||||||
this._borderSprites[5].position.y =
|
|
||||||
obj._height - this._borderSprites[5].height;
|
|
||||||
|
|
||||||
//Bottom
|
|
||||||
this._borderSprites[6].position.x = obj._lBorder;
|
|
||||||
this._borderSprites[6].position.y = obj._height - obj._bBorder;
|
|
||||||
|
|
||||||
//Bottom-Right
|
|
||||||
this._borderSprites[7].position.x =
|
|
||||||
obj._width - this._borderSprites[7].width;
|
|
||||||
this._borderSprites[7].position.y =
|
|
||||||
obj._height - this._borderSprites[7].height;
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateSpritesAndTexturesSize() {
|
|
||||||
const obj = this._object;
|
|
||||||
this._centerSprite.width = Math.max(
|
this._centerSprite.width = Math.max(
|
||||||
obj._width - obj._rBorder - obj._lBorder,
|
obj._width - obj._rBorder - obj._lBorder,
|
||||||
0
|
0
|
||||||
@@ -167,35 +126,107 @@ namespace gdjs {
|
|||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let leftMargin = obj._lBorder;
|
||||||
|
let rightMargin = obj._rBorder;
|
||||||
|
if (this._centerSprite.width === 0 && obj._lBorder + obj._rBorder > 0) {
|
||||||
|
leftMargin =
|
||||||
|
(obj._width * obj._lBorder) / (obj._lBorder + obj._rBorder);
|
||||||
|
rightMargin = obj._width - leftMargin;
|
||||||
|
}
|
||||||
|
let topMargin = obj._tBorder;
|
||||||
|
let bottomMargin = obj._bBorder;
|
||||||
|
if (this._centerSprite.height === 0 && obj._tBorder + obj._bBorder > 0) {
|
||||||
|
topMargin =
|
||||||
|
(obj._height * obj._tBorder) / (obj._tBorder + obj._bBorder);
|
||||||
|
bottomMargin = obj._height - topMargin;
|
||||||
|
}
|
||||||
|
|
||||||
//Right
|
//Right
|
||||||
this._borderSprites[0].width = obj._rBorder;
|
this._borderSprites[0].width = rightMargin;
|
||||||
this._borderSprites[0].height = Math.max(
|
this._borderSprites[0].height = Math.max(
|
||||||
obj._height - obj._tBorder - obj._bBorder,
|
obj._height - topMargin - bottomMargin,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
//Top
|
//Top
|
||||||
this._borderSprites[2].height = obj._tBorder;
|
this._borderSprites[2].height = topMargin;
|
||||||
this._borderSprites[2].width = Math.max(
|
this._borderSprites[2].width = Math.max(
|
||||||
obj._width - obj._rBorder - obj._lBorder,
|
obj._width - rightMargin - leftMargin,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
//Left
|
//Left
|
||||||
this._borderSprites[4].width = obj._lBorder;
|
this._borderSprites[4].width = leftMargin;
|
||||||
this._borderSprites[4].height = Math.max(
|
this._borderSprites[4].height = Math.max(
|
||||||
obj._height - obj._tBorder - obj._bBorder,
|
obj._height - topMargin - bottomMargin,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
//Bottom
|
//Bottom
|
||||||
this._borderSprites[6].height = obj._bBorder;
|
this._borderSprites[6].height = bottomMargin;
|
||||||
this._borderSprites[6].width = Math.max(
|
this._borderSprites[6].width = Math.max(
|
||||||
obj._width - obj._rBorder - obj._lBorder,
|
obj._width - rightMargin - leftMargin,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//Top-right
|
||||||
|
this._borderSprites[1].width = rightMargin;
|
||||||
|
this._borderSprites[1].height = topMargin;
|
||||||
|
|
||||||
|
//Top-Left
|
||||||
|
this._borderSprites[3].width = leftMargin;
|
||||||
|
this._borderSprites[3].height = topMargin;
|
||||||
|
|
||||||
|
//Bottom-Left
|
||||||
|
this._borderSprites[5].width = leftMargin;
|
||||||
|
this._borderSprites[5].height = bottomMargin;
|
||||||
|
|
||||||
|
//Bottom-Right
|
||||||
|
this._borderSprites[7].width = rightMargin;
|
||||||
|
this._borderSprites[7].height = bottomMargin;
|
||||||
|
|
||||||
this._wasRendered = true;
|
this._wasRendered = true;
|
||||||
this._spritesContainer.cacheAsBitmap = false;
|
this._spritesContainer.cacheAsBitmap = false;
|
||||||
|
|
||||||
|
const leftBorder = leftMargin;
|
||||||
|
const topBorder = topMargin;
|
||||||
|
const rightBorder = obj._width - rightMargin;
|
||||||
|
const bottomBorder = obj._height - bottomMargin;
|
||||||
|
|
||||||
|
this._centerSprite.position.x = leftBorder;
|
||||||
|
this._centerSprite.position.y = topBorder;
|
||||||
|
|
||||||
|
//Right
|
||||||
|
this._borderSprites[0].position.x = rightBorder;
|
||||||
|
this._borderSprites[0].position.y = topBorder;
|
||||||
|
|
||||||
|
//Top-right
|
||||||
|
this._borderSprites[1].position.x = rightBorder;
|
||||||
|
this._borderSprites[1].position.y = 0;
|
||||||
|
|
||||||
|
//Top
|
||||||
|
this._borderSprites[2].position.x = leftBorder;
|
||||||
|
this._borderSprites[2].position.y = 0;
|
||||||
|
|
||||||
|
//Top-Left
|
||||||
|
this._borderSprites[3].position.x = 0;
|
||||||
|
this._borderSprites[3].position.y = 0;
|
||||||
|
|
||||||
|
//Left
|
||||||
|
this._borderSprites[4].position.x = 0;
|
||||||
|
this._borderSprites[4].position.y = topBorder;
|
||||||
|
|
||||||
|
//Bottom-Left
|
||||||
|
this._borderSprites[5].position.x = 0;
|
||||||
|
this._borderSprites[5].position.y = bottomBorder;
|
||||||
|
|
||||||
|
//Bottom
|
||||||
|
this._borderSprites[6].position.x = leftBorder;
|
||||||
|
this._borderSprites[6].position.y = bottomBorder;
|
||||||
|
|
||||||
|
//Bottom-Right
|
||||||
|
this._borderSprites[7].position.x = rightBorder;
|
||||||
|
this._borderSprites[7].position.y = bottomBorder;
|
||||||
}
|
}
|
||||||
|
|
||||||
setTexture(
|
setTexture(
|
||||||
@@ -340,7 +371,6 @@ namespace gdjs {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
this._updateSpritesAndTexturesSize();
|
|
||||||
this._updateLocalPositions();
|
this._updateLocalPositions();
|
||||||
this.updatePosition();
|
this.updatePosition();
|
||||||
this._wrapperContainer.pivot.x = this._object._width / 2;
|
this._wrapperContainer.pivot.x = this._object._width / 2;
|
||||||
@@ -349,14 +379,12 @@ namespace gdjs {
|
|||||||
|
|
||||||
updateWidth(): void {
|
updateWidth(): void {
|
||||||
this._wrapperContainer.pivot.x = this._object._width / 2;
|
this._wrapperContainer.pivot.x = this._object._width / 2;
|
||||||
this._updateSpritesAndTexturesSize();
|
|
||||||
this._updateLocalPositions();
|
this._updateLocalPositions();
|
||||||
this.updatePosition();
|
this.updatePosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHeight(): void {
|
updateHeight(): void {
|
||||||
this._wrapperContainer.pivot.y = this._object._height / 2;
|
this._wrapperContainer.pivot.y = this._object._height / 2;
|
||||||
this._updateSpritesAndTexturesSize();
|
|
||||||
this._updateLocalPositions();
|
this._updateLocalPositions();
|
||||||
this.updatePosition();
|
this.updatePosition();
|
||||||
}
|
}
|
||||||
|
@@ -25,8 +25,6 @@ namespace gdjs {
|
|||||||
export type PanelSpriteObjectData = ObjectData & PanelSpriteObjectDataType;
|
export type PanelSpriteObjectData = ObjectData & PanelSpriteObjectDataType;
|
||||||
|
|
||||||
export type PanelSpriteNetworkSyncDataType = {
|
export type PanelSpriteNetworkSyncDataType = {
|
||||||
wid: number;
|
|
||||||
hei: number;
|
|
||||||
op: number;
|
op: number;
|
||||||
color: string;
|
color: string;
|
||||||
};
|
};
|
||||||
@@ -124,8 +122,6 @@ namespace gdjs {
|
|||||||
getNetworkSyncData(): PanelSpriteNetworkSyncData {
|
getNetworkSyncData(): PanelSpriteNetworkSyncData {
|
||||||
return {
|
return {
|
||||||
...super.getNetworkSyncData(),
|
...super.getNetworkSyncData(),
|
||||||
wid: this.getWidth(),
|
|
||||||
hei: this.getHeight(),
|
|
||||||
op: this.getOpacity(),
|
op: this.getOpacity(),
|
||||||
color: this.getColor(),
|
color: this.getColor(),
|
||||||
};
|
};
|
||||||
@@ -138,12 +134,6 @@ namespace gdjs {
|
|||||||
|
|
||||||
// Texture is not synchronized, see if this is asked or not.
|
// Texture is not synchronized, see if this is asked or not.
|
||||||
|
|
||||||
if (networkSyncData.wid !== undefined) {
|
|
||||||
this.setWidth(networkSyncData.wid);
|
|
||||||
}
|
|
||||||
if (networkSyncData.hei !== undefined) {
|
|
||||||
this.setHeight(networkSyncData.hei);
|
|
||||||
}
|
|
||||||
if (networkSyncData.op !== undefined) {
|
if (networkSyncData.op !== undefined) {
|
||||||
this.setOpacity(networkSyncData.op);
|
this.setOpacity(networkSyncData.op);
|
||||||
}
|
}
|
||||||
|
@@ -194,9 +194,9 @@ ParticleEmitterObject::GetProperties() const {
|
|||||||
: GetRendererType() == Line ? "Line"
|
: GetRendererType() == Line ? "Line"
|
||||||
: "Image")
|
: "Image")
|
||||||
.SetType("choice")
|
.SetType("choice")
|
||||||
.AddExtraInfo("Circle")
|
.AddChoice("Circle", _("Circle"))
|
||||||
.AddExtraInfo("Line")
|
.AddChoice("Line", _("Line"))
|
||||||
.AddExtraInfo("Image")
|
.AddChoice("Image", _("Image"))
|
||||||
.SetLabel(_("Particle type"))
|
.SetLabel(_("Particle type"))
|
||||||
.SetHasImpactOnOtherProperties(true);
|
.SetHasImpactOnOtherProperties(true);
|
||||||
|
|
||||||
|
@@ -818,7 +818,7 @@ module.exports = {
|
|||||||
)
|
)
|
||||||
.addParameter('object', _('Object'), '', false)
|
.addParameter('object', _('Object'), '', false)
|
||||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||||
.addParameter('yesorno', _('Treat as bullet?'), '', false)
|
.addParameter('yesorno', _('Treat as bullet'), '', false)
|
||||||
.setDefaultValue('false')
|
.setDefaultValue('false')
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
.setFunctionName('setBullet');
|
.setFunctionName('setBullet');
|
||||||
@@ -852,7 +852,7 @@ module.exports = {
|
|||||||
)
|
)
|
||||||
.addParameter('object', _('Object'), '', false)
|
.addParameter('object', _('Object'), '', false)
|
||||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||||
.addParameter('yesorno', _('Fixed rotation?'), '', false)
|
.addParameter('yesorno', _('Fixed rotation'), '', false)
|
||||||
.setDefaultValue('false')
|
.setDefaultValue('false')
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
.setFunctionName('setFixedRotation');
|
.setFunctionName('setFixedRotation');
|
||||||
@@ -886,7 +886,7 @@ module.exports = {
|
|||||||
)
|
)
|
||||||
.addParameter('object', _('Object'), '', false)
|
.addParameter('object', _('Object'), '', false)
|
||||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||||
.addParameter('yesorno', _('Can sleep?'), '', false)
|
.addParameter('yesorno', _('Can sleep'), '', false)
|
||||||
.setDefaultValue('true')
|
.setDefaultValue('true')
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
.setFunctionName('setSleepingAllowed');
|
.setFunctionName('setSleepingAllowed');
|
||||||
@@ -1296,7 +1296,7 @@ module.exports = {
|
|||||||
.addParameter('object', _('Object'), '', false)
|
.addParameter('object', _('Object'), '', false)
|
||||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||||
.addParameter('expression', _('Layer (1 - 16)'))
|
.addParameter('expression', _('Layer (1 - 16)'))
|
||||||
.addParameter('yesorno', _('Enable?'), '', false)
|
.addParameter('yesorno', _('Enable'), '', false)
|
||||||
.setDefaultValue('true')
|
.setDefaultValue('true')
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
.setFunctionName('enableLayer');
|
.setFunctionName('enableLayer');
|
||||||
@@ -1332,7 +1332,7 @@ module.exports = {
|
|||||||
.addParameter('object', _('Object'), '', false)
|
.addParameter('object', _('Object'), '', false)
|
||||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||||
.addParameter('expression', _('Mask (1 - 16)'))
|
.addParameter('expression', _('Mask (1 - 16)'))
|
||||||
.addParameter('yesorno', _('Enable?'), '', false)
|
.addParameter('yesorno', _('Enable'), '', false)
|
||||||
.setDefaultValue('true')
|
.setDefaultValue('true')
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
.setFunctionName('enableMask');
|
.setFunctionName('enableMask');
|
||||||
@@ -2409,7 +2409,7 @@ module.exports = {
|
|||||||
.addParameter('object', _('Object'), '', false)
|
.addParameter('object', _('Object'), '', false)
|
||||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||||
.addParameter('expression', _('Joint ID'))
|
.addParameter('expression', _('Joint ID'))
|
||||||
.addParameter('yesorno', _('Enable?'))
|
.addParameter('yesorno', _('Enable'))
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
.setFunctionName('enableRevoluteJointLimits');
|
.setFunctionName('enableRevoluteJointLimits');
|
||||||
|
|
||||||
@@ -2488,7 +2488,7 @@ module.exports = {
|
|||||||
.addParameter('object', _('Object'), '', false)
|
.addParameter('object', _('Object'), '', false)
|
||||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||||
.addParameter('expression', _('Joint ID'))
|
.addParameter('expression', _('Joint ID'))
|
||||||
.addParameter('yesorno', _('Enable?'))
|
.addParameter('yesorno', _('Enable'))
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
.setFunctionName('enableRevoluteJointMotor');
|
.setFunctionName('enableRevoluteJointMotor');
|
||||||
|
|
||||||
@@ -2727,7 +2727,7 @@ module.exports = {
|
|||||||
.addParameter('object', _('Object'), '', false)
|
.addParameter('object', _('Object'), '', false)
|
||||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||||
.addParameter('expression', _('Joint ID'))
|
.addParameter('expression', _('Joint ID'))
|
||||||
.addParameter('yesorno', _('Enable?'))
|
.addParameter('yesorno', _('Enable'))
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
.setFunctionName('enablePrismaticJointLimits');
|
.setFunctionName('enablePrismaticJointLimits');
|
||||||
|
|
||||||
@@ -2806,7 +2806,7 @@ module.exports = {
|
|||||||
.addParameter('object', _('Object'), '', false)
|
.addParameter('object', _('Object'), '', false)
|
||||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||||
.addParameter('expression', _('Joint ID'))
|
.addParameter('expression', _('Joint ID'))
|
||||||
.addParameter('yesorno', _('Enable?'))
|
.addParameter('yesorno', _('Enable'))
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
.setFunctionName('enablePrismaticJointMotor');
|
.setFunctionName('enablePrismaticJointMotor');
|
||||||
|
|
||||||
@@ -3486,7 +3486,7 @@ module.exports = {
|
|||||||
.addParameter('object', _('Object'), '', false)
|
.addParameter('object', _('Object'), '', false)
|
||||||
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
.addParameter('behavior', _('Behavior'), 'Physics2Behavior')
|
||||||
.addParameter('expression', _('Joint ID'))
|
.addParameter('expression', _('Joint ID'))
|
||||||
.addParameter('yesorno', _('Enable?'))
|
.addParameter('yesorno', _('Enable'))
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
.setFunctionName('enableWheelJointMotor');
|
.setFunctionName('enableWheelJointMotor');
|
||||||
|
|
||||||
|
@@ -274,7 +274,7 @@ module.exports = {
|
|||||||
.setLabel('Fixed Rotation')
|
.setLabel('Fixed Rotation')
|
||||||
.setDescription(
|
.setDescription(
|
||||||
_(
|
_(
|
||||||
"If enabled, the object won't rotate and will stay at the same angle. Useful for characters for example."
|
"If enabled, the object won't rotate and will stay at the same angle."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.setGroup(_('Movement'));
|
.setGroup(_('Movement'));
|
||||||
@@ -845,7 +845,7 @@ module.exports = {
|
|||||||
)
|
)
|
||||||
.addParameter('object', _('Object'), '', false)
|
.addParameter('object', _('Object'), '', false)
|
||||||
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||||
.addParameter('yesorno', _('Treat as bullet?'), '', false)
|
.addParameter('yesorno', _('Treat as bullet'), '', false)
|
||||||
.setDefaultValue('false')
|
.setDefaultValue('false')
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
.setFunctionName('setBullet');
|
.setFunctionName('setBullet');
|
||||||
@@ -870,7 +870,7 @@ module.exports = {
|
|||||||
'SetFixedRotation',
|
'SetFixedRotation',
|
||||||
_('Fixed rotation'),
|
_('Fixed rotation'),
|
||||||
_(
|
_(
|
||||||
"Enable or disable an object fixed rotation. If enabled the object won't be able to rotate."
|
"Enable or disable an object fixed rotation. If enabled the object won't be able to rotate. This action has no effect on characters."
|
||||||
),
|
),
|
||||||
_('Set _PARAM0_ fixed rotation: _PARAM2_'),
|
_('Set _PARAM0_ fixed rotation: _PARAM2_'),
|
||||||
_('Dynamics'),
|
_('Dynamics'),
|
||||||
@@ -879,7 +879,7 @@ module.exports = {
|
|||||||
)
|
)
|
||||||
.addParameter('object', _('Object'), '', false)
|
.addParameter('object', _('Object'), '', false)
|
||||||
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||||
.addParameter('yesorno', _('Fixed rotation?'), '', false)
|
.addParameter('yesorno', _('Fixed rotation'), '', false)
|
||||||
.setDefaultValue('false')
|
.setDefaultValue('false')
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
.setFunctionName('setFixedRotation');
|
.setFunctionName('setFixedRotation');
|
||||||
@@ -927,6 +927,54 @@ module.exports = {
|
|||||||
.setFunctionName('setDensity')
|
.setFunctionName('setDensity')
|
||||||
.setGetter('getDensity');
|
.setGetter('getDensity');
|
||||||
|
|
||||||
|
aut
|
||||||
|
.addExpressionAndConditionAndAction(
|
||||||
|
'number',
|
||||||
|
'ShapeOffsetX',
|
||||||
|
_('Shape offset X'),
|
||||||
|
_('the object shape offset on X.'),
|
||||||
|
_('the shape offset on X'),
|
||||||
|
_('Body settings'),
|
||||||
|
'JsPlatform/Extensions/physics3d.svg'
|
||||||
|
)
|
||||||
|
.addParameter('object', _('Object'), '', false)
|
||||||
|
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||||
|
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||||
|
.setFunctionName('setShapeOffsetX')
|
||||||
|
.setGetter('getShapeOffsetX');
|
||||||
|
|
||||||
|
aut
|
||||||
|
.addExpressionAndConditionAndAction(
|
||||||
|
'number',
|
||||||
|
'ShapeOffsetY',
|
||||||
|
_('Shape offset Y'),
|
||||||
|
_('the object shape offset on Y.'),
|
||||||
|
_('the shape offset on Y'),
|
||||||
|
_('Body settings'),
|
||||||
|
'JsPlatform/Extensions/physics3d.svg'
|
||||||
|
)
|
||||||
|
.addParameter('object', _('Object'), '', false)
|
||||||
|
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||||
|
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||||
|
.setFunctionName('setShapeOffsetY')
|
||||||
|
.setGetter('getShapeOffsetY');
|
||||||
|
|
||||||
|
aut
|
||||||
|
.addExpressionAndConditionAndAction(
|
||||||
|
'number',
|
||||||
|
'ShapeOffsetZ',
|
||||||
|
_('Shape offset Z'),
|
||||||
|
_('the object shape offset on Z.'),
|
||||||
|
_('the shape offset on Z'),
|
||||||
|
_('Body settings'),
|
||||||
|
'JsPlatform/Extensions/physics3d.svg'
|
||||||
|
)
|
||||||
|
.addParameter('object', _('Object'), '', false)
|
||||||
|
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||||
|
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||||
|
.setFunctionName('setShapeOffsetZ')
|
||||||
|
.setGetter('getShapeOffsetZ');
|
||||||
|
|
||||||
aut
|
aut
|
||||||
.addExpressionAndConditionAndAction(
|
.addExpressionAndConditionAndAction(
|
||||||
'number',
|
'number',
|
||||||
@@ -1054,7 +1102,7 @@ module.exports = {
|
|||||||
.addParameter('object', _('Object'), '', false)
|
.addParameter('object', _('Object'), '', false)
|
||||||
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||||
.addParameter('expression', _('Layer (1 - 8)'))
|
.addParameter('expression', _('Layer (1 - 8)'))
|
||||||
.addParameter('yesorno', _('Enable?'), '', false)
|
.addParameter('yesorno', _('Enable'), '', false)
|
||||||
.setDefaultValue('true')
|
.setDefaultValue('true')
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
.setFunctionName('enableLayer');
|
.setFunctionName('enableLayer');
|
||||||
@@ -1090,7 +1138,7 @@ module.exports = {
|
|||||||
.addParameter('object', _('Object'), '', false)
|
.addParameter('object', _('Object'), '', false)
|
||||||
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||||
.addParameter('expression', _('Mask (1 - 8)'))
|
.addParameter('expression', _('Mask (1 - 8)'))
|
||||||
.addParameter('yesorno', _('Enable?'), '', false)
|
.addParameter('yesorno', _('Enable'), '', false)
|
||||||
.setDefaultValue('true')
|
.setDefaultValue('true')
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
.setFunctionName('enableMask');
|
.setFunctionName('enableMask');
|
||||||
@@ -1270,7 +1318,7 @@ module.exports = {
|
|||||||
.addParameter('expression', _('Application point on Z axis'))
|
.addParameter('expression', _('Application point on Z axis'))
|
||||||
.setParameterLongDescription(
|
.setParameterLongDescription(
|
||||||
_(
|
_(
|
||||||
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
|
'Use `MassCenterX`, `MassCenterY` and `MassCenterZ` expressions to avoid any rotation.'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
@@ -1544,6 +1592,19 @@ module.exports = {
|
|||||||
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||||
.getCodeExtraInformation()
|
.getCodeExtraInformation()
|
||||||
.setFunctionName('getMassCenterY');
|
.setFunctionName('getMassCenterY');
|
||||||
|
|
||||||
|
aut
|
||||||
|
.addExpression(
|
||||||
|
'MassCenterZ',
|
||||||
|
_('Mass center Z'),
|
||||||
|
_('Mass center Z'),
|
||||||
|
'',
|
||||||
|
'JsPlatform/Extensions/physics3d.svg'
|
||||||
|
)
|
||||||
|
.addParameter('object', _('Object'), '', false)
|
||||||
|
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
|
||||||
|
.getCodeExtraInformation()
|
||||||
|
.setFunctionName('getMassCenterZ');
|
||||||
}
|
}
|
||||||
// Collision
|
// Collision
|
||||||
extension
|
extension
|
||||||
|
@@ -630,10 +630,7 @@ namespace gdjs {
|
|||||||
|
|
||||||
override onDeActivate() {
|
override onDeActivate() {
|
||||||
this._sharedData.removeFromBehaviorsList(this);
|
this._sharedData.removeFromBehaviorsList(this);
|
||||||
this.bodyUpdater.destroyBody();
|
this._destroyBody();
|
||||||
this._contactsEndedThisFrame.length = 0;
|
|
||||||
this._contactsStartedThisFrame.length = 0;
|
|
||||||
this._currentContacts.length = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override onActivate() {
|
override onActivate() {
|
||||||
@@ -650,6 +647,24 @@ namespace gdjs {
|
|||||||
this.onDeActivate();
|
this.onDeActivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_destroyBody() {
|
||||||
|
this.bodyUpdater.destroyBody();
|
||||||
|
this._contactsEndedThisFrame.length = 0;
|
||||||
|
this._contactsStartedThisFrame.length = 0;
|
||||||
|
this._currentContacts.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
resetToDefaultBodyUpdater() {
|
||||||
|
this.bodyUpdater = new gdjs.Physics3DRuntimeBehavior.DefaultBodyUpdater(
|
||||||
|
this
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
resetToDefaultCollisionChecker() {
|
||||||
|
this.collisionChecker =
|
||||||
|
new gdjs.Physics3DRuntimeBehavior.DefaultCollisionChecker(this);
|
||||||
|
}
|
||||||
|
|
||||||
createShape(): Jolt.Shape {
|
createShape(): Jolt.Shape {
|
||||||
if (
|
if (
|
||||||
this.massCenterOffsetX === 0 &&
|
this.massCenterOffsetX === 0 &&
|
||||||
@@ -927,9 +942,7 @@ namespace gdjs {
|
|||||||
const angularVelocityY = angularVelocity.GetY();
|
const angularVelocityY = angularVelocity.GetY();
|
||||||
const angularVelocityZ = angularVelocity.GetZ();
|
const angularVelocityZ = angularVelocity.GetZ();
|
||||||
|
|
||||||
let bodyID = this._body.GetID();
|
this.bodyUpdater.destroyBody();
|
||||||
bodyInterface.RemoveBody(bodyID);
|
|
||||||
bodyInterface.DestroyBody(bodyID);
|
|
||||||
this._contactsEndedThisFrame.length = 0;
|
this._contactsEndedThisFrame.length = 0;
|
||||||
this._contactsStartedThisFrame.length = 0;
|
this._contactsStartedThisFrame.length = 0;
|
||||||
this._currentContacts.length = 0;
|
this._currentContacts.length = 0;
|
||||||
@@ -938,7 +951,7 @@ namespace gdjs {
|
|||||||
if (!this._body) {
|
if (!this._body) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bodyID = this._body.GetID();
|
const bodyID = this._body.GetID();
|
||||||
bodyInterface.SetLinearVelocity(
|
bodyInterface.SetLinearVelocity(
|
||||||
bodyID,
|
bodyID,
|
||||||
this.getVec3(linearVelocityX, linearVelocityY, linearVelocityZ)
|
this.getVec3(linearVelocityX, linearVelocityY, linearVelocityZ)
|
||||||
@@ -1178,6 +1191,33 @@ namespace gdjs {
|
|||||||
this._needToRecreateBody = true;
|
this._needToRecreateBody = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getShapeOffsetX(): float {
|
||||||
|
return this.shapeOffsetX;
|
||||||
|
}
|
||||||
|
|
||||||
|
setShapeOffsetX(shapeOffsetX: float): void {
|
||||||
|
this.shapeOffsetX = shapeOffsetX;
|
||||||
|
this._needToRecreateShape = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getShapeOffsetY(): float {
|
||||||
|
return this.shapeOffsetY;
|
||||||
|
}
|
||||||
|
|
||||||
|
setShapeOffsetY(shapeOffsetY: float): void {
|
||||||
|
this.shapeOffsetY = shapeOffsetY;
|
||||||
|
this._needToRecreateShape = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getShapeOffsetZ(): float {
|
||||||
|
return this.shapeOffsetZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
setShapeOffsetZ(shapeOffsetZ: float): void {
|
||||||
|
this.shapeOffsetZ = shapeOffsetZ;
|
||||||
|
this._needToRecreateShape = true;
|
||||||
|
}
|
||||||
|
|
||||||
getFriction(): float {
|
getFriction(): float {
|
||||||
return this.friction;
|
return this.friction;
|
||||||
}
|
}
|
||||||
@@ -1542,9 +1582,9 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
const body = this._body!;
|
const body = this._body!;
|
||||||
|
|
||||||
const deltaX = towardX - body.GetPosition().GetX();
|
const deltaX = towardX - this.owner3D.getX();
|
||||||
const deltaY = towardY - body.GetPosition().GetY();
|
const deltaY = towardY - this.owner3D.getY();
|
||||||
const deltaZ = towardZ - body.GetPosition().GetZ();
|
const deltaZ = towardZ - this.owner3D.getZ();
|
||||||
const distanceSq = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
|
const distanceSq = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
|
||||||
if (distanceSq === 0) {
|
if (distanceSq === 0) {
|
||||||
return;
|
return;
|
||||||
@@ -1602,19 +1642,16 @@ namespace gdjs {
|
|||||||
length: float,
|
length: float,
|
||||||
towardX: float,
|
towardX: float,
|
||||||
towardY: float,
|
towardY: float,
|
||||||
towardZ: float,
|
towardZ: float
|
||||||
originX: float,
|
|
||||||
originY: float,
|
|
||||||
originZ: float
|
|
||||||
): void {
|
): void {
|
||||||
if (this._body === null) {
|
if (this._body === null) {
|
||||||
if (!this._createBody()) return;
|
if (!this._createBody()) return;
|
||||||
}
|
}
|
||||||
const body = this._body!;
|
const body = this._body!;
|
||||||
|
|
||||||
const deltaX = towardX - originX;
|
const deltaX = towardX - this.owner3D.getX();
|
||||||
const deltaY = towardY - originY;
|
const deltaY = towardY - this.owner3D.getY();
|
||||||
const deltaZ = towardZ - originZ;
|
const deltaZ = towardZ - this.owner3D.getZ();
|
||||||
const distanceSq = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
|
const distanceSq = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
|
||||||
if (distanceSq === 0) {
|
if (distanceSq === 0) {
|
||||||
return;
|
return;
|
||||||
@@ -1623,12 +1660,7 @@ namespace gdjs {
|
|||||||
|
|
||||||
this._sharedData.bodyInterface.AddImpulse(
|
this._sharedData.bodyInterface.AddImpulse(
|
||||||
body.GetID(),
|
body.GetID(),
|
||||||
this.getVec3(deltaX * ratio, deltaY * ratio, deltaZ * ratio),
|
this.getVec3(deltaX * ratio, deltaY * ratio, deltaZ * ratio)
|
||||||
this.getRVec3(
|
|
||||||
originX * this._sharedData.worldInvScale,
|
|
||||||
originY * this._sharedData.worldInvScale,
|
|
||||||
originZ * this._sharedData.worldInvScale
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -29,6 +29,7 @@ namespace gdjs {
|
|||||||
owner3D: gdjs.RuntimeObject3D;
|
owner3D: gdjs.RuntimeObject3D;
|
||||||
private _physics3DBehaviorName: string;
|
private _physics3DBehaviorName: string;
|
||||||
private _physics3D: Physics3D | null = null;
|
private _physics3D: Physics3D | null = null;
|
||||||
|
private _isHookedToPhysicsStep = false;
|
||||||
_vehicleController: Jolt.WheeledVehicleController | null = null;
|
_vehicleController: Jolt.WheeledVehicleController | null = null;
|
||||||
_stepListener: Jolt.VehicleConstraintStepListener | null = null;
|
_stepListener: Jolt.VehicleConstraintStepListener | null = null;
|
||||||
_vehicleCollisionTester: Jolt.VehicleCollisionTesterCastCylinder | null =
|
_vehicleCollisionTester: Jolt.VehicleCollisionTesterCastCylinder | null =
|
||||||
@@ -153,13 +154,19 @@ namespace gdjs {
|
|||||||
const behavior = this.owner.getBehavior(
|
const behavior = this.owner.getBehavior(
|
||||||
this._physics3DBehaviorName
|
this._physics3DBehaviorName
|
||||||
) as gdjs.Physics3DRuntimeBehavior;
|
) as gdjs.Physics3DRuntimeBehavior;
|
||||||
|
if (!behavior.activated()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const sharedData = behavior._sharedData;
|
const sharedData = behavior._sharedData;
|
||||||
|
|
||||||
this._physics3D = {
|
this._physics3D = {
|
||||||
behavior,
|
behavior,
|
||||||
};
|
};
|
||||||
sharedData.registerHook(this);
|
if (!this._isHookedToPhysicsStep) {
|
||||||
|
sharedData.registerHook(this);
|
||||||
|
this._isHookedToPhysicsStep = true;
|
||||||
|
}
|
||||||
|
|
||||||
behavior.bodyUpdater =
|
behavior.bodyUpdater =
|
||||||
new gdjs.PhysicsCar3DRuntimeBehavior.VehicleBodyUpdater(
|
new gdjs.PhysicsCar3DRuntimeBehavior.VehicleBodyUpdater(
|
||||||
@@ -330,25 +337,33 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override onDeActivate() {
|
override onDeActivate() {
|
||||||
if (this._stepListener) {
|
if (!this._physics3D) {
|
||||||
this._sharedData.physicsSystem.RemoveStepListener(this._stepListener);
|
return;
|
||||||
}
|
}
|
||||||
|
this._destroyBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
override onActivate() {
|
override onActivate() {
|
||||||
if (this._stepListener) {
|
const behavior = this.owner.getBehavior(
|
||||||
this._sharedData.physicsSystem.AddStepListener(this._stepListener);
|
this._physics3DBehaviorName
|
||||||
|
) as gdjs.Physics3DRuntimeBehavior;
|
||||||
|
if (!behavior) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
behavior._destroyBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
override onDestroy() {
|
override onDestroy() {
|
||||||
|
this._destroyedDuringFrameLogic = true;
|
||||||
|
this._destroyBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
_destroyBody() {
|
||||||
if (!this._vehicleController) {
|
if (!this._vehicleController) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._destroyedDuringFrameLogic = true;
|
|
||||||
this.onDeActivate();
|
|
||||||
if (this._stepListener) {
|
if (this._stepListener) {
|
||||||
// stepListener is removed by onDeActivate
|
this._sharedData.physicsSystem.RemoveStepListener(this._stepListener);
|
||||||
Jolt.destroy(this._stepListener);
|
Jolt.destroy(this._stepListener);
|
||||||
this._stepListener = null;
|
this._stepListener = null;
|
||||||
}
|
}
|
||||||
@@ -360,6 +375,8 @@ namespace gdjs {
|
|||||||
// It is destroyed with the constraint.
|
// It is destroyed with the constraint.
|
||||||
this._vehicleCollisionTester = null;
|
this._vehicleCollisionTester = null;
|
||||||
if (this._physics3D) {
|
if (this._physics3D) {
|
||||||
|
const { behavior } = this._physics3D;
|
||||||
|
behavior.resetToDefaultBodyUpdater();
|
||||||
this._physics3D = null;
|
this._physics3D = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -733,7 +750,7 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setWheelOffsetZ(wheelOffsetZ: float): void {
|
setWheelOffsetZ(wheelOffsetZ: float): void {
|
||||||
this._wheelOffsetY = wheelOffsetZ;
|
this._wheelOffsetZ = wheelOffsetZ;
|
||||||
this._updateWheels();
|
this._updateWheels();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -783,11 +800,11 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hasFrontWheelDrive(): boolean {
|
hasFrontWheelDrive(): boolean {
|
||||||
return this._hasBackWheelDrive;
|
return this._hasFrontWheelDrive;
|
||||||
}
|
}
|
||||||
|
|
||||||
setFrontWheelDrive(hasFrontWheelDrive: boolean): void {
|
setFrontWheelDrive(hasFrontWheelDrive: boolean): void {
|
||||||
this._hasBackWheelDrive = hasFrontWheelDrive;
|
this._hasFrontWheelDrive = hasFrontWheelDrive;
|
||||||
this.invalidateShape();
|
this.invalidateShape();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1110,7 +1127,7 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
destroyBody() {
|
destroyBody() {
|
||||||
this.carBehavior.onDestroy();
|
this.carBehavior._destroyBody();
|
||||||
this.physicsBodyUpdater.destroyBody();
|
this.physicsBodyUpdater.destroyBody();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -41,6 +41,7 @@ namespace gdjs {
|
|||||||
owner3D: gdjs.RuntimeObject3D;
|
owner3D: gdjs.RuntimeObject3D;
|
||||||
private _physics3DBehaviorName: string;
|
private _physics3DBehaviorName: string;
|
||||||
private _physics3D: Physics3D | null = null;
|
private _physics3D: Physics3D | null = null;
|
||||||
|
private _isHookedToPhysicsStep = false;
|
||||||
character: Jolt.CharacterVirtual | null = null;
|
character: Jolt.CharacterVirtual | null = null;
|
||||||
/**
|
/**
|
||||||
* sharedData is a reference to the shared data of the scene, that registers
|
* sharedData is a reference to the shared data of the scene, that registers
|
||||||
@@ -169,10 +170,15 @@ namespace gdjs {
|
|||||||
if (this._physics3D) {
|
if (this._physics3D) {
|
||||||
return this._physics3D;
|
return this._physics3D;
|
||||||
}
|
}
|
||||||
|
if (!this.activated()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const behavior = this.owner.getBehavior(
|
const behavior = this.owner.getBehavior(
|
||||||
this._physics3DBehaviorName
|
this._physics3DBehaviorName
|
||||||
) as gdjs.Physics3DRuntimeBehavior;
|
) as gdjs.Physics3DRuntimeBehavior;
|
||||||
|
if (!behavior.activated()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const sharedData = behavior._sharedData;
|
const sharedData = behavior._sharedData;
|
||||||
const jolt = sharedData.jolt;
|
const jolt = sharedData.jolt;
|
||||||
const extendedUpdateSettings = new Jolt.ExtendedUpdateSettings();
|
const extendedUpdateSettings = new Jolt.ExtendedUpdateSettings();
|
||||||
@@ -196,7 +202,10 @@ namespace gdjs {
|
|||||||
shapeFilter,
|
shapeFilter,
|
||||||
};
|
};
|
||||||
this.setStairHeightMax(this._stairHeightMax);
|
this.setStairHeightMax(this._stairHeightMax);
|
||||||
sharedData.registerHook(this);
|
if (!this._isHookedToPhysicsStep) {
|
||||||
|
sharedData.registerHook(this);
|
||||||
|
this._isHookedToPhysicsStep = true;
|
||||||
|
}
|
||||||
|
|
||||||
behavior.bodyUpdater =
|
behavior.bodyUpdater =
|
||||||
new gdjs.PhysicsCharacter3DRuntimeBehavior.CharacterBodyUpdater(this);
|
new gdjs.PhysicsCharacter3DRuntimeBehavior.CharacterBodyUpdater(this);
|
||||||
@@ -390,36 +399,48 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override onDeActivate() {
|
override onDeActivate() {
|
||||||
this.collisionChecker.clearContacts();
|
if (!this._physics3D) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._destroyBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
override onActivate() {}
|
override onActivate() {
|
||||||
|
const behavior = this.owner.getBehavior(
|
||||||
|
this._physics3DBehaviorName
|
||||||
|
) as gdjs.Physics3DRuntimeBehavior;
|
||||||
|
if (!behavior) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
behavior._destroyBody();
|
||||||
|
}
|
||||||
|
|
||||||
override onDestroy() {
|
override onDestroy() {
|
||||||
this._destroyedDuringFrameLogic = true;
|
this._destroyedDuringFrameLogic = true;
|
||||||
this.onDeActivate();
|
this.onDeActivate();
|
||||||
this._destroyCharacter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the character and its body from the physics engine.
|
* Remove the character and its body from the physics engine.
|
||||||
* This method is called when:
|
* This method is called when:
|
||||||
* - The Physics3D behavior is deactivated
|
* - The Physics3D behavior is deactivated
|
||||||
|
* - This behavior is deactivated
|
||||||
* - The object is destroyed
|
* - The object is destroyed
|
||||||
*
|
|
||||||
* Only deactivating the character behavior won't destroy the character.
|
|
||||||
* Indeed, deactivated characters don't move as characters but still have collisions.
|
|
||||||
*/
|
*/
|
||||||
_destroyCharacter() {
|
_destroyBody() {
|
||||||
if (this.character) {
|
if (this.character) {
|
||||||
if (this._canBePushed) {
|
if (this._canBePushed) {
|
||||||
this.charactersManager.removeCharacter(this.character);
|
this.charactersManager.removeCharacter(this.character);
|
||||||
Jolt.destroy(this.character.GetListener());
|
Jolt.destroy(this.character.GetListener());
|
||||||
}
|
}
|
||||||
|
this.collisionChecker.clearContacts();
|
||||||
// The body is destroyed with the character.
|
// The body is destroyed with the character.
|
||||||
Jolt.destroy(this.character);
|
Jolt.destroy(this.character);
|
||||||
this.character = null;
|
this.character = null;
|
||||||
if (this._physics3D) {
|
if (this._physics3D) {
|
||||||
|
const { behavior } = this._physics3D;
|
||||||
|
behavior.resetToDefaultBodyUpdater();
|
||||||
|
behavior.resetToDefaultCollisionChecker();
|
||||||
this._physics3D.behavior._body = null;
|
this._physics3D.behavior._body = null;
|
||||||
const {
|
const {
|
||||||
extendedUpdateSettings,
|
extendedUpdateSettings,
|
||||||
@@ -1780,7 +1801,7 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
destroyBody() {
|
destroyBody() {
|
||||||
this.characterBehavior._destroyCharacter();
|
this.characterBehavior._destroyBody();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -36,6 +36,7 @@ void PlatformerObjectBehavior::InitializeContent(
|
|||||||
behaviorContent.SetAttribute("yGrabOffset", 0);
|
behaviorContent.SetAttribute("yGrabOffset", 0);
|
||||||
behaviorContent.SetAttribute("xGrabTolerance", 10);
|
behaviorContent.SetAttribute("xGrabTolerance", 10);
|
||||||
behaviorContent.SetAttribute("useLegacyTrajectory", false);
|
behaviorContent.SetAttribute("useLegacyTrajectory", false);
|
||||||
|
behaviorContent.SetAttribute("useRepeatedJump", false);
|
||||||
behaviorContent.SetAttribute("canGoDownFromJumpthru", true);
|
behaviorContent.SetAttribute("canGoDownFromJumpthru", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,11 +109,11 @@ PlatformerObjectBehavior::GetProperties(
|
|||||||
.SetValue(
|
.SetValue(
|
||||||
gd::String::From(behaviorContent.GetDoubleAttribute("maxSpeed")));
|
gd::String::From(behaviorContent.GetDoubleAttribute("maxSpeed")));
|
||||||
properties["IgnoreDefaultControls"]
|
properties["IgnoreDefaultControls"]
|
||||||
.SetLabel(_("Default controls"))
|
.SetLabel(_("Disable default keyboard controls"))
|
||||||
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden)
|
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden)
|
||||||
.SetValue(behaviorContent.GetBoolAttribute("ignoreDefaultControls")
|
.SetValue(behaviorContent.GetBoolAttribute("ignoreDefaultControls")
|
||||||
? "false"
|
? "true"
|
||||||
: "true")
|
: "false")
|
||||||
.SetType("Boolean");
|
.SetType("Boolean");
|
||||||
properties["SlopeMaxAngle"]
|
properties["SlopeMaxAngle"]
|
||||||
.SetLabel(_("Slope max. angle"))
|
.SetLabel(_("Slope max. angle"))
|
||||||
@@ -156,14 +157,23 @@ PlatformerObjectBehavior::GetProperties(
|
|||||||
.SetValue(gd::String::From(
|
.SetValue(gd::String::From(
|
||||||
behaviorContent.GetDoubleAttribute("xGrabTolerance", 10)));
|
behaviorContent.GetDoubleAttribute("xGrabTolerance", 10)));
|
||||||
properties["UseLegacyTrajectory"]
|
properties["UseLegacyTrajectory"]
|
||||||
.SetLabel(_("Use frame rate dependent trajectories (deprecated, it's "
|
.SetLabel(_("Use frame rate dependent trajectories "
|
||||||
"recommended to leave this unchecked)"))
|
"(deprecated — best left unchecked)"))
|
||||||
.SetGroup(_("Deprecated options"))
|
.SetGroup(_("Deprecated options"))
|
||||||
.SetDeprecated()
|
.SetDeprecated()
|
||||||
.SetValue(behaviorContent.GetBoolAttribute("useLegacyTrajectory", true)
|
.SetValue(behaviorContent.GetBoolAttribute("useLegacyTrajectory", true)
|
||||||
? "true"
|
? "true"
|
||||||
: "false")
|
: "false")
|
||||||
.SetType("Boolean");
|
.SetType("Boolean");
|
||||||
|
properties["UseRepeatedJump"]
|
||||||
|
.SetLabel(_("Allows repeated jumps while holding the jump key "
|
||||||
|
"(deprecated — best left unchecked)"))
|
||||||
|
.SetGroup(_("Deprecated options"))
|
||||||
|
.SetDeprecated()
|
||||||
|
.SetValue(behaviorContent.GetBoolAttribute("useRepeatedJump", true)
|
||||||
|
? "true"
|
||||||
|
: "false")
|
||||||
|
.SetType("Boolean");
|
||||||
properties["CanGoDownFromJumpthru"]
|
properties["CanGoDownFromJumpthru"]
|
||||||
.SetLabel(_("Can go down from jumpthru platforms"))
|
.SetLabel(_("Can go down from jumpthru platforms"))
|
||||||
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden)
|
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden)
|
||||||
@@ -180,13 +190,15 @@ bool PlatformerObjectBehavior::UpdateProperty(
|
|||||||
const gd::String& name,
|
const gd::String& name,
|
||||||
const gd::String& value) {
|
const gd::String& value) {
|
||||||
if (name == "IgnoreDefaultControls")
|
if (name == "IgnoreDefaultControls")
|
||||||
behaviorContent.SetAttribute("ignoreDefaultControls", (value == "0"));
|
behaviorContent.SetAttribute("ignoreDefaultControls", (value == "1"));
|
||||||
else if (name == "CanGrabPlatforms")
|
else if (name == "CanGrabPlatforms")
|
||||||
behaviorContent.SetAttribute("canGrabPlatforms", (value == "1"));
|
behaviorContent.SetAttribute("canGrabPlatforms", (value == "1"));
|
||||||
else if (name == "CanGrabWithoutMoving")
|
else if (name == "CanGrabWithoutMoving")
|
||||||
behaviorContent.SetAttribute("canGrabWithoutMoving", (value == "1"));
|
behaviorContent.SetAttribute("canGrabWithoutMoving", (value == "1"));
|
||||||
else if (name == "UseLegacyTrajectory")
|
else if (name == "UseLegacyTrajectory")
|
||||||
behaviorContent.SetAttribute("useLegacyTrajectory", (value == "1"));
|
behaviorContent.SetAttribute("useLegacyTrajectory", (value == "1"));
|
||||||
|
else if (name == "UseRepeatedJump")
|
||||||
|
behaviorContent.SetAttribute("useRepeatedJump", (value == "1"));
|
||||||
else if (name == "CanGoDownFromJumpthru")
|
else if (name == "CanGoDownFromJumpthru")
|
||||||
behaviorContent.SetAttribute("canGoDownFromJumpthru", (value == "1"));
|
behaviorContent.SetAttribute("canGoDownFromJumpthru", (value == "1"));
|
||||||
else if (name == "YGrabOffset")
|
else if (name == "YGrabOffset")
|
||||||
|
@@ -23,7 +23,6 @@ namespace gdjs {
|
|||||||
interface JumpingStateNetworkSyncData {
|
interface JumpingStateNetworkSyncData {
|
||||||
cjs: number;
|
cjs: number;
|
||||||
tscjs: number;
|
tscjs: number;
|
||||||
jkhsjs: boolean;
|
|
||||||
jfd: boolean;
|
jfd: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,6 +56,7 @@ namespace gdjs {
|
|||||||
juk: boolean;
|
juk: boolean;
|
||||||
rpk: boolean;
|
rpk: boolean;
|
||||||
rlk: boolean;
|
rlk: boolean;
|
||||||
|
jkhsjs: boolean;
|
||||||
sn: string;
|
sn: string;
|
||||||
ssd: StateNetworkSyncData;
|
ssd: StateNetworkSyncData;
|
||||||
}
|
}
|
||||||
@@ -119,6 +119,7 @@ namespace gdjs {
|
|||||||
private _xGrabTolerance: any;
|
private _xGrabTolerance: any;
|
||||||
|
|
||||||
_useLegacyTrajectory: boolean;
|
_useLegacyTrajectory: boolean;
|
||||||
|
_useRepeatedJump: boolean;
|
||||||
|
|
||||||
_canGoDownFromJumpthru: boolean = false;
|
_canGoDownFromJumpthru: boolean = false;
|
||||||
|
|
||||||
@@ -139,6 +140,7 @@ namespace gdjs {
|
|||||||
_upKey: boolean = false;
|
_upKey: boolean = false;
|
||||||
_downKey: boolean = false;
|
_downKey: boolean = false;
|
||||||
_jumpKey: boolean = false;
|
_jumpKey: boolean = false;
|
||||||
|
_jumpKeyHeldSinceJumpStart: boolean = false;
|
||||||
_releasePlatformKey: boolean = false;
|
_releasePlatformKey: boolean = false;
|
||||||
_releaseLadderKey: boolean = false;
|
_releaseLadderKey: boolean = false;
|
||||||
|
|
||||||
@@ -204,6 +206,10 @@ namespace gdjs {
|
|||||||
behaviorData.useLegacyTrajectory === undefined
|
behaviorData.useLegacyTrajectory === undefined
|
||||||
? true
|
? true
|
||||||
: behaviorData.useLegacyTrajectory;
|
: behaviorData.useLegacyTrajectory;
|
||||||
|
this._useRepeatedJump =
|
||||||
|
behaviorData.useRepeatedJump === undefined
|
||||||
|
? true
|
||||||
|
: behaviorData.useRepeatedJump;
|
||||||
this._canGoDownFromJumpthru = behaviorData.canGoDownFromJumpthru;
|
this._canGoDownFromJumpthru = behaviorData.canGoDownFromJumpthru;
|
||||||
this._slopeMaxAngle = 0;
|
this._slopeMaxAngle = 0;
|
||||||
this.setSlopeMaxAngle(behaviorData.slopeMaxAngle);
|
this.setSlopeMaxAngle(behaviorData.slopeMaxAngle);
|
||||||
@@ -249,6 +255,7 @@ namespace gdjs {
|
|||||||
juk: this._wasJumpKeyPressed,
|
juk: this._wasJumpKeyPressed,
|
||||||
rpk: this._wasReleasePlatformKeyPressed,
|
rpk: this._wasReleasePlatformKeyPressed,
|
||||||
rlk: this._wasReleaseLadderKeyPressed,
|
rlk: this._wasReleaseLadderKeyPressed,
|
||||||
|
jkhsjs: this._jumpKeyHeldSinceJumpStart,
|
||||||
sn: this._state.toString(),
|
sn: this._state.toString(),
|
||||||
ssd: this._state.getNetworkSyncData(),
|
ssd: this._state.getNetworkSyncData(),
|
||||||
},
|
},
|
||||||
@@ -306,6 +313,9 @@ namespace gdjs {
|
|||||||
if (behaviorSpecificProps.rlk !== this._releaseLadderKey) {
|
if (behaviorSpecificProps.rlk !== this._releaseLadderKey) {
|
||||||
this._releaseLadderKey = behaviorSpecificProps.rlk;
|
this._releaseLadderKey = behaviorSpecificProps.rlk;
|
||||||
}
|
}
|
||||||
|
if (behaviorSpecificProps.jkhsjs !== this._jumpKeyHeldSinceJumpStart) {
|
||||||
|
this._jumpKeyHeldSinceJumpStart = behaviorSpecificProps.jkhsjs;
|
||||||
|
}
|
||||||
|
|
||||||
if (behaviorSpecificProps.sn !== this._state.toString()) {
|
if (behaviorSpecificProps.sn !== this._state.toString()) {
|
||||||
switch (behaviorSpecificProps.sn) {
|
switch (behaviorSpecificProps.sn) {
|
||||||
@@ -427,6 +437,11 @@ namespace gdjs {
|
|||||||
(inputManager.isKeyPressed(LSHIFTKEY) ||
|
(inputManager.isKeyPressed(LSHIFTKEY) ||
|
||||||
inputManager.isKeyPressed(RSHIFTKEY) ||
|
inputManager.isKeyPressed(RSHIFTKEY) ||
|
||||||
inputManager.isKeyPressed(SPACEKEY)));
|
inputManager.isKeyPressed(SPACEKEY)));
|
||||||
|
// Check if the jump key is continuously held since
|
||||||
|
// the beginning of the jump.
|
||||||
|
if (!this._jumpKey) {
|
||||||
|
this._jumpKeyHeldSinceJumpStart = false;
|
||||||
|
}
|
||||||
|
|
||||||
this._ladderKey ||
|
this._ladderKey ||
|
||||||
(this._ladderKey =
|
(this._ladderKey =
|
||||||
@@ -471,7 +486,16 @@ namespace gdjs {
|
|||||||
this._state.beforeMovingX();
|
this._state.beforeMovingX();
|
||||||
|
|
||||||
//Ensure the object is not stuck
|
//Ensure the object is not stuck
|
||||||
if (this._separateFromPlatforms(this._potentialCollidingObjects, true)) {
|
const hasPopOutOfPlatform = this._separateFromPlatforms(
|
||||||
|
this._potentialCollidingObjects,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
if (hasPopOutOfPlatform && !this._jumpKey) {
|
||||||
|
// TODO This is probably unnecessary because `_canJump` is already set
|
||||||
|
// to true when entering the `OnFloor` state.
|
||||||
|
// This is wrongly allowing double jumps when characters are flipped
|
||||||
|
// with an offset center.
|
||||||
|
|
||||||
//After being unstuck, the object must be able to jump again.
|
//After being unstuck, the object must be able to jump again.
|
||||||
this._canJump = true;
|
this._canJump = true;
|
||||||
}
|
}
|
||||||
@@ -750,7 +774,11 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_checkTransitionJumping() {
|
_checkTransitionJumping() {
|
||||||
if (this._canJump && this._jumpKey) {
|
if (
|
||||||
|
this._canJump &&
|
||||||
|
this._jumpKey &&
|
||||||
|
(!this._jumpKeyHeldSinceJumpStart || this._useRepeatedJump)
|
||||||
|
) {
|
||||||
this._setJumping();
|
this._setJumping();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2270,7 +2298,6 @@ namespace gdjs {
|
|||||||
private _behavior: PlatformerObjectRuntimeBehavior;
|
private _behavior: PlatformerObjectRuntimeBehavior;
|
||||||
private _currentJumpSpeed: number = 0;
|
private _currentJumpSpeed: number = 0;
|
||||||
private _timeSinceCurrentJumpStart: number = 0;
|
private _timeSinceCurrentJumpStart: number = 0;
|
||||||
private _jumpKeyHeldSinceJumpStart: boolean = false;
|
|
||||||
private _jumpingFirstDelta: boolean = false;
|
private _jumpingFirstDelta: boolean = false;
|
||||||
|
|
||||||
constructor(behavior: PlatformerObjectRuntimeBehavior) {
|
constructor(behavior: PlatformerObjectRuntimeBehavior) {
|
||||||
@@ -2288,7 +2315,7 @@ namespace gdjs {
|
|||||||
enter(from: State) {
|
enter(from: State) {
|
||||||
const behavior = this._behavior;
|
const behavior = this._behavior;
|
||||||
this._timeSinceCurrentJumpStart = 0;
|
this._timeSinceCurrentJumpStart = 0;
|
||||||
this._jumpKeyHeldSinceJumpStart = true;
|
behavior._jumpKeyHeldSinceJumpStart = true;
|
||||||
|
|
||||||
if (from !== behavior._jumping && from !== behavior._falling) {
|
if (from !== behavior._jumping && from !== behavior._falling) {
|
||||||
this._jumpingFirstDelta = true;
|
this._jumpingFirstDelta = true;
|
||||||
@@ -2329,17 +2356,12 @@ namespace gdjs {
|
|||||||
beforeMovingY(timeDelta: float, oldX: float) {
|
beforeMovingY(timeDelta: float, oldX: float) {
|
||||||
const behavior = this._behavior;
|
const behavior = this._behavior;
|
||||||
|
|
||||||
// Check if the jump key is continuously held since
|
|
||||||
// the beginning of the jump.
|
|
||||||
if (!behavior._jumpKey) {
|
|
||||||
this._jumpKeyHeldSinceJumpStart = false;
|
|
||||||
}
|
|
||||||
this._timeSinceCurrentJumpStart += timeDelta;
|
this._timeSinceCurrentJumpStart += timeDelta;
|
||||||
|
|
||||||
const previousJumpSpeed = this._currentJumpSpeed;
|
const previousJumpSpeed = this._currentJumpSpeed;
|
||||||
// Decrease jump speed after the (optional) jump sustain time is over.
|
// Decrease jump speed after the (optional) jump sustain time is over.
|
||||||
const sustainJumpSpeed =
|
const sustainJumpSpeed =
|
||||||
this._jumpKeyHeldSinceJumpStart &&
|
behavior._jumpKeyHeldSinceJumpStart &&
|
||||||
this._timeSinceCurrentJumpStart < behavior._jumpSustainTime;
|
this._timeSinceCurrentJumpStart < behavior._jumpSustainTime;
|
||||||
if (!sustainJumpSpeed) {
|
if (!sustainJumpSpeed) {
|
||||||
this._currentJumpSpeed -= behavior._gravity * timeDelta;
|
this._currentJumpSpeed -= behavior._gravity * timeDelta;
|
||||||
@@ -2374,7 +2396,6 @@ namespace gdjs {
|
|||||||
return {
|
return {
|
||||||
cjs: this._currentJumpSpeed,
|
cjs: this._currentJumpSpeed,
|
||||||
tscjs: this._timeSinceCurrentJumpStart,
|
tscjs: this._timeSinceCurrentJumpStart,
|
||||||
jkhsjs: this._jumpKeyHeldSinceJumpStart,
|
|
||||||
jfd: this._jumpingFirstDelta,
|
jfd: this._jumpingFirstDelta,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -2382,7 +2403,6 @@ namespace gdjs {
|
|||||||
updateFromNetworkSyncData(data: JumpingStateNetworkSyncData) {
|
updateFromNetworkSyncData(data: JumpingStateNetworkSyncData) {
|
||||||
this._currentJumpSpeed = data.cjs;
|
this._currentJumpSpeed = data.cjs;
|
||||||
this._timeSinceCurrentJumpStart = data.tscjs;
|
this._timeSinceCurrentJumpStart = data.tscjs;
|
||||||
this._jumpKeyHeldSinceJumpStart = data.jkhsjs;
|
|
||||||
this._jumpingFirstDelta = data.jfd;
|
this._jumpingFirstDelta = data.jfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,6 +27,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: slopeMaxAngle,
|
slopeMaxAngle: slopeMaxAngle,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -331,6 +332,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
ignoreDefaultControls: true,
|
ignoreDefaultControls: true,
|
||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -491,6 +493,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -624,6 +627,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 0,
|
slopeMaxAngle: 0,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -728,6 +732,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
|
@@ -26,6 +26,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
ignoreDefaultControls: true,
|
ignoreDefaultControls: true,
|
||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -172,6 +173,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -287,6 +289,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: true,
|
useLegacyTrajectory: true,
|
||||||
|
useRepeatedJump: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -383,6 +386,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: true,
|
useLegacyTrajectory: true,
|
||||||
|
useRepeatedJump: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -481,6 +485,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: true,
|
useLegacyTrajectory: true,
|
||||||
|
useRepeatedJump: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -555,6 +560,8 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
let runtimeScene;
|
let runtimeScene;
|
||||||
let object;
|
let object;
|
||||||
let platform;
|
let platform;
|
||||||
|
/** @type {gdjs.PlatformerObjectRuntimeBehavior} */
|
||||||
|
let characterBehavior;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
runtimeScene = makePlatformerTestRuntimeScene();
|
runtimeScene = makePlatformerTestRuntimeScene();
|
||||||
@@ -578,6 +585,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -585,6 +593,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
object.setCustomWidthAndHeight(10, 20);
|
object.setCustomWidthAndHeight(10, 20);
|
||||||
runtimeScene.addObject(object);
|
runtimeScene.addObject(object);
|
||||||
object.setPosition(0, -32);
|
object.setPosition(0, -32);
|
||||||
|
characterBehavior = object.getBehavior('auto1');
|
||||||
|
|
||||||
// Put a platform.
|
// Put a platform.
|
||||||
platform = addPlatformObject(runtimeScene);
|
platform = addPlatformObject(runtimeScene);
|
||||||
@@ -644,6 +653,48 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
expect(object.getY()).to.be(-30);
|
expect(object.getY()).to.be(-30);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can only jump once while the jump key is held', function () {
|
||||||
|
// Ensure the object falls on the platform
|
||||||
|
for (let i = 0; i < 10; ++i) {
|
||||||
|
runtimeScene.renderAndStep(1000 / 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check the object is on the platform
|
||||||
|
expect(object.getY()).to.be(-30); // -30 = -10 (platform y) + -20 (object height)
|
||||||
|
expect(characterBehavior.isFalling()).to.be(false);
|
||||||
|
expect(characterBehavior.isFallingWithoutJumping()).to.be(false);
|
||||||
|
expect(characterBehavior.isMoving()).to.be(false);
|
||||||
|
|
||||||
|
// The character jumps a first time.
|
||||||
|
for (let i = 0; i < 80; ++i) {
|
||||||
|
characterBehavior.simulateJumpKey();
|
||||||
|
runtimeScene.renderAndStep(1000 / 60);
|
||||||
|
characterBehavior.isJumping(true);
|
||||||
|
}
|
||||||
|
// The character lands back on the floor
|
||||||
|
// while the player holds the jump key.
|
||||||
|
for (let i = 0; i < 4; ++i) {
|
||||||
|
characterBehavior.simulateJumpKey();
|
||||||
|
runtimeScene.renderAndStep(1000 / 60);
|
||||||
|
}
|
||||||
|
characterBehavior.isOnFloor(true);
|
||||||
|
expect(object.getY()).to.be(-30);
|
||||||
|
|
||||||
|
// The character doesn't jump a 2nd time.
|
||||||
|
characterBehavior.simulateJumpKey();
|
||||||
|
runtimeScene.renderAndStep(1000 / 60);
|
||||||
|
characterBehavior.isOnFloor(true);
|
||||||
|
|
||||||
|
// The player release the jump key.
|
||||||
|
runtimeScene.renderAndStep(1000 / 60);
|
||||||
|
characterBehavior.isOnFloor(true);
|
||||||
|
|
||||||
|
// The character can now jump again.
|
||||||
|
characterBehavior.simulateJumpKey();
|
||||||
|
runtimeScene.renderAndStep(1000 / 60);
|
||||||
|
characterBehavior.isJumping(true);
|
||||||
|
});
|
||||||
|
|
||||||
it('can jump, and only sustain the jump while key held', function () {
|
it('can jump, and only sustain the jump while key held', function () {
|
||||||
// Ensure the object falls on the platform
|
// Ensure the object falls on the platform
|
||||||
for (let i = 0; i < 10; ++i) {
|
for (let i = 0; i < 10; ++i) {
|
||||||
@@ -1126,6 +1177,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
canGoDownFromJumpthru: true,
|
canGoDownFromJumpthru: true,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -1467,6 +1519,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
ignoreDefaultControls: true,
|
ignoreDefaultControls: true,
|
||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -1497,6 +1550,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
ignoreDefaultControls: true,
|
ignoreDefaultControls: true,
|
||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'PlatformBehavior::PlatformBehavior',
|
type: 'PlatformBehavior::PlatformBehavior',
|
||||||
@@ -1637,6 +1691,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -1758,6 +1813,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -1843,6 +1899,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -1921,6 +1978,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
|
@@ -26,6 +26,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
canGrabWithoutMoving: canGrabWithoutMoving,
|
canGrabWithoutMoving: canGrabWithoutMoving,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -233,6 +234,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
canGrabWithoutMoving: true,
|
canGrabWithoutMoving: true,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -398,6 +400,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
|
@@ -32,6 +32,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
ignoreDefaultControls: true,
|
ignoreDefaultControls: true,
|
||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -308,6 +309,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
ignoreDefaultControls: true,
|
ignoreDefaultControls: true,
|
||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
|
@@ -27,6 +27,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -438,6 +439,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
@@ -546,6 +548,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
|||||||
slopeMaxAngle: slopeMaxAngle,
|
slopeMaxAngle: slopeMaxAngle,
|
||||||
jumpSustainTime: 0.2,
|
jumpSustainTime: 0.2,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
|
@@ -36,6 +36,7 @@ describe(`gdjs.PlatformerObjectRuntimeBehavior.findHighestFloorAndMoveOnTop`, fu
|
|||||||
ignoreDefaultControls: true,
|
ignoreDefaultControls: true,
|
||||||
slopeMaxAngle: 60,
|
slopeMaxAngle: 60,
|
||||||
useLegacyTrajectory: false,
|
useLegacyTrajectory: false,
|
||||||
|
useRepeatedJump: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects: [],
|
effects: [],
|
||||||
|
@@ -311,7 +311,7 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
|
|||||||
"such as \"Path line\" (in the Advanced category) can be "
|
"such as \"Path line\" (in the Advanced category) can be "
|
||||||
"used to draw. Be sure to use \"End fill path\" action when "
|
"used to draw. Be sure to use \"End fill path\" action when "
|
||||||
"you're done drawing the shape."),
|
"you're done drawing the shape."),
|
||||||
_("Begins drawing filling of an advanced path "
|
_("Begin drawing filling of an advanced path "
|
||||||
"with _PARAM0_ (start: _PARAM1_;_PARAM2_)"),
|
"with _PARAM0_ (start: _PARAM1_;_PARAM2_)"),
|
||||||
_("Advanced"),
|
_("Advanced"),
|
||||||
"res/actions/beginFillPath24.png",
|
"res/actions/beginFillPath24.png",
|
||||||
|
@@ -246,10 +246,10 @@ std::map<gd::String, gd::PropertyDescriptor> ShapePainterObject::GetProperties()
|
|||||||
objectProperties["antialiasing"]
|
objectProperties["antialiasing"]
|
||||||
.SetValue(GetAntialiasing())
|
.SetValue(GetAntialiasing())
|
||||||
.SetType("choice")
|
.SetType("choice")
|
||||||
.AddExtraInfo("none")
|
.AddChoice("none", _("None"))
|
||||||
.AddExtraInfo("low")
|
.AddChoice("low", _("Low quality"))
|
||||||
.AddExtraInfo("medium")
|
.AddChoice("medium", _("Medium quality"))
|
||||||
.AddExtraInfo("high")
|
.AddChoice("high", _("High quality"))
|
||||||
.SetGroup(_("Drawing"))
|
.SetGroup(_("Drawing"))
|
||||||
.SetLabel(_("Antialiasing"))
|
.SetLabel(_("Antialiasing"))
|
||||||
.SetDescription(_("Antialiasing mode"));
|
.SetDescription(_("Antialiasing mode"));
|
||||||
|
@@ -195,11 +195,35 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* To be called when the game is disposed.
|
* To be called when the game is disposed.
|
||||||
* Clear the Spine Atlases loaded in this manager.
|
* Clear the Spine atlases loaded in this manager.
|
||||||
*/
|
*/
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
this._loadedSpineAtlases.clear();
|
this._loadedSpineAtlases.clear();
|
||||||
this._loadingSpineAtlases.clear();
|
this._loadingSpineAtlases.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unload the specified list of resources:
|
||||||
|
* this clears the Spine atlases loaded in this manager.
|
||||||
|
*
|
||||||
|
* Usually called when scene resoures are unloaded.
|
||||||
|
*
|
||||||
|
* @param resourcesList The list of specific resources
|
||||||
|
*/
|
||||||
|
unloadResourcesList(resourcesList: ResourceData[]): void {
|
||||||
|
resourcesList.forEach((resourceData) => {
|
||||||
|
const loadedSpineAtlas = this._loadedSpineAtlases.get(resourceData);
|
||||||
|
if (loadedSpineAtlas) {
|
||||||
|
loadedSpineAtlas.dispose();
|
||||||
|
this._loadedSpineAtlases.delete(resourceData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadingSpineAtlas = this._loadingSpineAtlases.get(resourceData);
|
||||||
|
if (loadingSpineAtlas) {
|
||||||
|
loadingSpineAtlas.then((atl) => atl.dispose());
|
||||||
|
this._loadingSpineAtlases.delete(resourceData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -126,5 +126,22 @@ namespace gdjs {
|
|||||||
dispose(): void {
|
dispose(): void {
|
||||||
this._loadedSpines.clear();
|
this._loadedSpines.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unload the specified list of resources:
|
||||||
|
* this clears the Spine skeleton data loaded in this manager.
|
||||||
|
*
|
||||||
|
* Usually called when scene resoures are unloaded.
|
||||||
|
*
|
||||||
|
* @param resourcesList The list of specific resources
|
||||||
|
*/
|
||||||
|
unloadResourcesList(resourcesList: ResourceData[]): void {
|
||||||
|
resourcesList.forEach((resourceData) => {
|
||||||
|
const loadedSpine = this._loadedSpines.get(resourceData);
|
||||||
|
if (loadedSpine) {
|
||||||
|
this._loadedSpines.delete(resourceData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,8 +14,6 @@ namespace gdjs {
|
|||||||
|
|
||||||
export type SpineNetworkSyncDataType = {
|
export type SpineNetworkSyncDataType = {
|
||||||
opa: float;
|
opa: float;
|
||||||
wid: float;
|
|
||||||
hei: float;
|
|
||||||
scaX: float;
|
scaX: float;
|
||||||
scaY: float;
|
scaY: float;
|
||||||
flipX: boolean;
|
flipX: boolean;
|
||||||
@@ -117,8 +115,6 @@ namespace gdjs {
|
|||||||
return {
|
return {
|
||||||
...super.getNetworkSyncData(),
|
...super.getNetworkSyncData(),
|
||||||
opa: this._opacity,
|
opa: this._opacity,
|
||||||
wid: this.getWidth(),
|
|
||||||
hei: this.getHeight(),
|
|
||||||
scaX: this.getScaleX(),
|
scaX: this.getScaleX(),
|
||||||
scaY: this.getScaleY(),
|
scaY: this.getScaleY(),
|
||||||
flipX: this.isFlippedX(),
|
flipX: this.isFlippedX(),
|
||||||
@@ -137,12 +133,6 @@ namespace gdjs {
|
|||||||
if (syncData.opa !== undefined && syncData.opa !== this._opacity) {
|
if (syncData.opa !== undefined && syncData.opa !== this._opacity) {
|
||||||
this.setOpacity(syncData.opa);
|
this.setOpacity(syncData.opa);
|
||||||
}
|
}
|
||||||
if (syncData.wid !== undefined && syncData.wid !== this.getWidth()) {
|
|
||||||
this.setWidth(syncData.wid);
|
|
||||||
}
|
|
||||||
if (syncData.hei !== undefined && syncData.hei !== this.getHeight()) {
|
|
||||||
this.setHeight(syncData.hei);
|
|
||||||
}
|
|
||||||
if (syncData.scaX !== undefined && syncData.scaX !== this.getScaleX()) {
|
if (syncData.scaX !== undefined && syncData.scaX !== this.getScaleX()) {
|
||||||
this.setScaleX(syncData.scaX);
|
this.setScaleX(syncData.scaX);
|
||||||
}
|
}
|
||||||
|
@@ -131,14 +131,14 @@ module.exports = {
|
|||||||
.getOrCreate('inputType')
|
.getOrCreate('inputType')
|
||||||
.setValue(objectContent.inputType || '')
|
.setValue(objectContent.inputType || '')
|
||||||
.setType('choice')
|
.setType('choice')
|
||||||
.addExtraInfo('text')
|
.addChoice('text', _('Text'))
|
||||||
.addExtraInfo('text area')
|
.addChoice('text area', _('Text area'))
|
||||||
.addExtraInfo('email')
|
.addChoice('email', _('Email'))
|
||||||
.addExtraInfo('password')
|
.addChoice('password', _('Password'))
|
||||||
.addExtraInfo('number')
|
.addChoice('number', _('Number'))
|
||||||
.addExtraInfo('telephone number')
|
.addChoice('telephone number', _('Telephone number'))
|
||||||
.addExtraInfo('url')
|
.addChoice('url', _('URL'))
|
||||||
.addExtraInfo('search')
|
.addChoice('search', _('Search'))
|
||||||
.setLabel(_('Input type'))
|
.setLabel(_('Input type'))
|
||||||
.setDescription(
|
.setDescription(
|
||||||
_(
|
_(
|
||||||
@@ -250,9 +250,9 @@ module.exports = {
|
|||||||
.getOrCreate('textAlign')
|
.getOrCreate('textAlign')
|
||||||
.setValue(objectContent.textAlign || 'left')
|
.setValue(objectContent.textAlign || 'left')
|
||||||
.setType('choice')
|
.setType('choice')
|
||||||
.addExtraInfo('left')
|
.addChoice('left', _('Left'))
|
||||||
.addExtraInfo('center')
|
.addChoice('center', _('Center'))
|
||||||
.addExtraInfo('right')
|
.addChoice('right', _('Right'))
|
||||||
.setLabel(_('Text alignment'))
|
.setLabel(_('Text alignment'))
|
||||||
.setGroup(_('Field appearance'));
|
.setGroup(_('Field appearance'));
|
||||||
|
|
||||||
|
@@ -64,8 +64,6 @@ namespace gdjs {
|
|||||||
|
|
||||||
export type TextInputNetworkSyncDataType = {
|
export type TextInputNetworkSyncDataType = {
|
||||||
opa: float;
|
opa: float;
|
||||||
wid: float;
|
|
||||||
hei: float;
|
|
||||||
txt: string;
|
txt: string;
|
||||||
frn: string;
|
frn: string;
|
||||||
fs: number;
|
fs: number;
|
||||||
@@ -260,8 +258,6 @@ namespace gdjs {
|
|||||||
return {
|
return {
|
||||||
...super.getNetworkSyncData(),
|
...super.getNetworkSyncData(),
|
||||||
opa: this.getOpacity(),
|
opa: this.getOpacity(),
|
||||||
wid: this.getWidth(),
|
|
||||||
hei: this.getHeight(),
|
|
||||||
txt: this.getText(),
|
txt: this.getText(),
|
||||||
frn: this.getFontResourceName(),
|
frn: this.getFontResourceName(),
|
||||||
fs: this.getFontSize(),
|
fs: this.getFontSize(),
|
||||||
@@ -282,8 +278,6 @@ namespace gdjs {
|
|||||||
super.updateFromNetworkSyncData(syncData);
|
super.updateFromNetworkSyncData(syncData);
|
||||||
|
|
||||||
if (syncData.opa !== undefined) this.setOpacity(syncData.opa);
|
if (syncData.opa !== undefined) this.setOpacity(syncData.opa);
|
||||||
if (syncData.wid !== undefined) this.setWidth(syncData.wid);
|
|
||||||
if (syncData.hei !== undefined) this.setHeight(syncData.hei);
|
|
||||||
if (syncData.txt !== undefined) this.setText(syncData.txt);
|
if (syncData.txt !== undefined) this.setText(syncData.txt);
|
||||||
if (syncData.frn !== undefined) this.setFontResourceName(syncData.frn);
|
if (syncData.frn !== undefined) this.setFontResourceName(syncData.frn);
|
||||||
if (syncData.fs !== undefined) this.setFontSize(syncData.fs);
|
if (syncData.fs !== undefined) this.setFontSize(syncData.fs);
|
||||||
|
@@ -160,9 +160,9 @@ std::map<gd::String, gd::PropertyDescriptor> TextObject::GetProperties() const {
|
|||||||
objectProperties["textAlignment"]
|
objectProperties["textAlignment"]
|
||||||
.SetValue(textAlignment)
|
.SetValue(textAlignment)
|
||||||
.SetType("choice")
|
.SetType("choice")
|
||||||
.AddExtraInfo("left")
|
.AddChoice("left", _("Left"))
|
||||||
.AddExtraInfo("center")
|
.AddChoice("center", _("Center"))
|
||||||
.AddExtraInfo("right")
|
.AddChoice("right", _("Right"))
|
||||||
.SetLabel(_("Alignment"))
|
.SetLabel(_("Alignment"))
|
||||||
.SetDescription(_("Alignment of the text when multiple lines are displayed"))
|
.SetDescription(_("Alignment of the text when multiple lines are displayed"))
|
||||||
.SetGroup(_("Font"))
|
.SetGroup(_("Font"))
|
||||||
@@ -171,9 +171,9 @@ std::map<gd::String, gd::PropertyDescriptor> TextObject::GetProperties() const {
|
|||||||
objectProperties["verticalTextAlignment"]
|
objectProperties["verticalTextAlignment"]
|
||||||
.SetValue(verticalTextAlignment)
|
.SetValue(verticalTextAlignment)
|
||||||
.SetType("choice")
|
.SetType("choice")
|
||||||
.AddExtraInfo("top")
|
.AddChoice("top", _("Top"))
|
||||||
.AddExtraInfo("center")
|
.AddChoice("center", _("Center"))
|
||||||
.AddExtraInfo("bottom")
|
.AddChoice("bottom", _("Bottom"))
|
||||||
.SetLabel(_("Vertical alignment"))
|
.SetLabel(_("Vertical alignment"))
|
||||||
.SetGroup(_("Font"))
|
.SetGroup(_("Font"))
|
||||||
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden);
|
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden);
|
||||||
|
@@ -102,9 +102,9 @@ const defineTileMap = function (extension, _, gd) {
|
|||||||
'displayMode',
|
'displayMode',
|
||||||
new gd.PropertyDescriptor(objectContent.displayMode)
|
new gd.PropertyDescriptor(objectContent.displayMode)
|
||||||
.setType('choice')
|
.setType('choice')
|
||||||
.addExtraInfo('visible')
|
.addChoice('visible', _('Visible layers'))
|
||||||
.addExtraInfo('all')
|
.addChoice('all', _('All layers'))
|
||||||
.addExtraInfo('index')
|
.addChoice('index', _('Only the layer with the specified index'))
|
||||||
.setLabel(_('Display mode'))
|
.setLabel(_('Display mode'))
|
||||||
.setGroup(_('Appearance'))
|
.setGroup(_('Appearance'))
|
||||||
);
|
);
|
||||||
|
@@ -17,8 +17,6 @@ namespace gdjs {
|
|||||||
export type SimpleTileMapNetworkSyncDataType = {
|
export type SimpleTileMapNetworkSyncDataType = {
|
||||||
op: number;
|
op: number;
|
||||||
ai: string;
|
ai: string;
|
||||||
wid: number;
|
|
||||||
hei: number;
|
|
||||||
// TODO: Support tilemap synchronization. Find an efficient way to send tiles changes.
|
// TODO: Support tilemap synchronization. Find an efficient way to send tiles changes.
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -170,8 +168,6 @@ namespace gdjs {
|
|||||||
...super.getNetworkSyncData(),
|
...super.getNetworkSyncData(),
|
||||||
op: this._opacity,
|
op: this._opacity,
|
||||||
ai: this._atlasImage,
|
ai: this._atlasImage,
|
||||||
wid: this.getWidth(),
|
|
||||||
hei: this.getHeight(),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,18 +182,6 @@ namespace gdjs {
|
|||||||
) {
|
) {
|
||||||
this.setOpacity(networkSyncData.op);
|
this.setOpacity(networkSyncData.op);
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
networkSyncData.wid !== undefined &&
|
|
||||||
networkSyncData.wid !== this.getWidth()
|
|
||||||
) {
|
|
||||||
this.setWidth(networkSyncData.wid);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
networkSyncData.hei !== undefined &&
|
|
||||||
networkSyncData.hei !== this.getHeight()
|
|
||||||
) {
|
|
||||||
this.setHeight(networkSyncData.hei);
|
|
||||||
}
|
|
||||||
if (networkSyncData.ai !== undefined) {
|
if (networkSyncData.ai !== undefined) {
|
||||||
// TODO: support changing the atlas texture
|
// TODO: support changing the atlas texture
|
||||||
}
|
}
|
||||||
|
@@ -26,8 +26,6 @@ namespace gdjs {
|
|||||||
os: float;
|
os: float;
|
||||||
fo: float;
|
fo: float;
|
||||||
oo: float;
|
oo: float;
|
||||||
wid: float;
|
|
||||||
hei: float;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TilemapCollisionMaskNetworkSyncData = ObjectNetworkSyncData &
|
export type TilemapCollisionMaskNetworkSyncData = ObjectNetworkSyncData &
|
||||||
@@ -202,8 +200,6 @@ namespace gdjs {
|
|||||||
os: this.getOutlineSize(),
|
os: this.getOutlineSize(),
|
||||||
fo: this.getFillOpacity(),
|
fo: this.getFillOpacity(),
|
||||||
oo: this.getOutlineOpacity(),
|
oo: this.getOutlineOpacity(),
|
||||||
wid: this.getWidth(),
|
|
||||||
hei: this.getHeight(),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,12 +232,6 @@ namespace gdjs {
|
|||||||
if (networkSyncData.oo !== undefined) {
|
if (networkSyncData.oo !== undefined) {
|
||||||
this.setOutlineOpacity(networkSyncData.oo);
|
this.setOutlineOpacity(networkSyncData.oo);
|
||||||
}
|
}
|
||||||
if (networkSyncData.wid !== undefined) {
|
|
||||||
this.setWidth(networkSyncData.wid);
|
|
||||||
}
|
|
||||||
if (networkSyncData.hei !== undefined) {
|
|
||||||
this.setHeight(networkSyncData.hei);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extraInitializationFromInitialInstance(initialInstanceData): void {
|
extraInitializationFromInitialInstance(initialInstanceData): void {
|
||||||
|
@@ -25,8 +25,6 @@ namespace gdjs {
|
|||||||
lai: number;
|
lai: number;
|
||||||
lei: number;
|
lei: number;
|
||||||
asps: number;
|
asps: number;
|
||||||
wid: number;
|
|
||||||
hei: number;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TilemapNetworkSyncData = ObjectNetworkSyncData &
|
export type TilemapNetworkSyncData = ObjectNetworkSyncData &
|
||||||
@@ -158,8 +156,6 @@ namespace gdjs {
|
|||||||
lai: this._layerIndex,
|
lai: this._layerIndex,
|
||||||
lei: this._levelIndex,
|
lei: this._levelIndex,
|
||||||
asps: this._animationSpeedScale,
|
asps: this._animationSpeedScale,
|
||||||
wid: this.getWidth(),
|
|
||||||
hei: this.getHeight(),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,12 +186,6 @@ namespace gdjs {
|
|||||||
if (networkSyncData.asps !== undefined) {
|
if (networkSyncData.asps !== undefined) {
|
||||||
this.setAnimationSpeedScale(networkSyncData.asps);
|
this.setAnimationSpeedScale(networkSyncData.asps);
|
||||||
}
|
}
|
||||||
if (networkSyncData.wid !== undefined) {
|
|
||||||
this.setWidth(networkSyncData.wid);
|
|
||||||
}
|
|
||||||
if (networkSyncData.hei !== undefined) {
|
|
||||||
this.setHeight(networkSyncData.hei);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extraInitializationFromInitialInstance(initialInstanceData): void {
|
extraInitializationFromInitialInstance(initialInstanceData): void {
|
||||||
|
@@ -15,8 +15,6 @@ namespace gdjs {
|
|||||||
export type TiledSpriteObjectData = ObjectData & TiledSpriteObjectDataType;
|
export type TiledSpriteObjectData = ObjectData & TiledSpriteObjectDataType;
|
||||||
|
|
||||||
export type TiledSpriteNetworkSyncDataType = {
|
export type TiledSpriteNetworkSyncDataType = {
|
||||||
wid: number;
|
|
||||||
hei: number;
|
|
||||||
xo: number;
|
xo: number;
|
||||||
yo: number;
|
yo: number;
|
||||||
op: number;
|
op: number;
|
||||||
@@ -83,8 +81,6 @@ namespace gdjs {
|
|||||||
getNetworkSyncData(): TiledSpriteNetworkSyncData {
|
getNetworkSyncData(): TiledSpriteNetworkSyncData {
|
||||||
return {
|
return {
|
||||||
...super.getNetworkSyncData(),
|
...super.getNetworkSyncData(),
|
||||||
wid: this.getWidth(),
|
|
||||||
hei: this.getHeight(),
|
|
||||||
xo: this.getXOffset(),
|
xo: this.getXOffset(),
|
||||||
yo: this.getYOffset(),
|
yo: this.getYOffset(),
|
||||||
op: this.getOpacity(),
|
op: this.getOpacity(),
|
||||||
@@ -99,12 +95,6 @@ namespace gdjs {
|
|||||||
|
|
||||||
// Texture is not synchronized, see if this is asked or not.
|
// Texture is not synchronized, see if this is asked or not.
|
||||||
|
|
||||||
if (networkSyncData.wid !== undefined) {
|
|
||||||
this.setWidth(networkSyncData.wid);
|
|
||||||
}
|
|
||||||
if (networkSyncData.hei !== undefined) {
|
|
||||||
this.setHeight(networkSyncData.hei);
|
|
||||||
}
|
|
||||||
if (networkSyncData.xo !== undefined) {
|
if (networkSyncData.xo !== undefined) {
|
||||||
this.setXOffset(networkSyncData.xo);
|
this.setXOffset(networkSyncData.xo);
|
||||||
}
|
}
|
||||||
|
@@ -34,6 +34,7 @@ void TopDownMovementBehavior::InitializeContent(
|
|||||||
behaviorContent.SetAttribute("viewpoint", "TopDown");
|
behaviorContent.SetAttribute("viewpoint", "TopDown");
|
||||||
behaviorContent.SetAttribute("customIsometryAngle", 30);
|
behaviorContent.SetAttribute("customIsometryAngle", 30);
|
||||||
behaviorContent.SetAttribute("movementAngleOffset", 0);
|
behaviorContent.SetAttribute("movementAngleOffset", 0);
|
||||||
|
behaviorContent.SetAttribute("useLegacyTurnBack", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<gd::String, gd::PropertyDescriptor>
|
std::map<gd::String, gd::PropertyDescriptor>
|
||||||
@@ -89,10 +90,20 @@ TopDownMovementBehavior::GetProperties(
|
|||||||
.SetValue(
|
.SetValue(
|
||||||
gd::String::From(behaviorContent.GetDoubleAttribute("angleOffset")));
|
gd::String::From(behaviorContent.GetDoubleAttribute("angleOffset")));
|
||||||
properties["IgnoreDefaultControls"]
|
properties["IgnoreDefaultControls"]
|
||||||
.SetLabel(_("Default controls"))
|
.SetLabel(_("Disable default keyboard controls"))
|
||||||
|
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden)
|
||||||
.SetValue(behaviorContent.GetBoolAttribute("ignoreDefaultControls")
|
.SetValue(behaviorContent.GetBoolAttribute("ignoreDefaultControls")
|
||||||
? "false"
|
? "true"
|
||||||
: "true")
|
: "false")
|
||||||
|
.SetType("Boolean");
|
||||||
|
properties["UseLegacyTurnBack"]
|
||||||
|
.SetLabel(_("Only use acceleration to turn back "
|
||||||
|
"(deprecated — best left unchecked)"))
|
||||||
|
.SetGroup(_("Deprecated options"))
|
||||||
|
.SetDeprecated()
|
||||||
|
.SetValue(behaviorContent.GetBoolAttribute("useLegacyTurnBack", true)
|
||||||
|
? "true"
|
||||||
|
: "false")
|
||||||
.SetType("Boolean");
|
.SetType("Boolean");
|
||||||
|
|
||||||
gd::String viewpoint = behaviorContent.GetStringAttribute("viewpoint");
|
gd::String viewpoint = behaviorContent.GetStringAttribute("viewpoint");
|
||||||
@@ -145,7 +156,7 @@ bool TopDownMovementBehavior::UpdateProperty(
|
|||||||
const gd::String& name,
|
const gd::String& name,
|
||||||
const gd::String& value) {
|
const gd::String& value) {
|
||||||
if (name == "IgnoreDefaultControls") {
|
if (name == "IgnoreDefaultControls") {
|
||||||
behaviorContent.SetAttribute("ignoreDefaultControls", (value == "0"));
|
behaviorContent.SetAttribute("ignoreDefaultControls", (value == "1"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (name == "AllowDiagonals") {
|
if (name == "AllowDiagonals") {
|
||||||
@@ -156,6 +167,9 @@ bool TopDownMovementBehavior::UpdateProperty(
|
|||||||
behaviorContent.SetAttribute("rotateObject", (value != "0"));
|
behaviorContent.SetAttribute("rotateObject", (value != "0"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (name == "UseLegacyTurnBack") {
|
||||||
|
behaviorContent.SetAttribute("useLegacyTurnBack", (value == "1"));
|
||||||
|
}
|
||||||
if (name == "Viewpoint") {
|
if (name == "Viewpoint") {
|
||||||
// Fix the offset angle when switching between top-down and isometry
|
// Fix the offset angle when switching between top-down and isometry
|
||||||
const gd::String& oldValue =
|
const gd::String& oldValue =
|
||||||
|
@@ -37,6 +37,7 @@ namespace gdjs {
|
|||||||
private _angleOffset: float;
|
private _angleOffset: float;
|
||||||
private _ignoreDefaultControls: boolean;
|
private _ignoreDefaultControls: boolean;
|
||||||
private _movementAngleOffset: float;
|
private _movementAngleOffset: float;
|
||||||
|
private _useLegacyTurnBack: boolean;
|
||||||
|
|
||||||
/** The latest angle of movement, in degrees. */
|
/** The latest angle of movement, in degrees. */
|
||||||
private _angle: float = 0;
|
private _angle: float = 0;
|
||||||
@@ -102,6 +103,10 @@ namespace gdjs {
|
|||||||
behaviorData.customIsometryAngle
|
behaviorData.customIsometryAngle
|
||||||
);
|
);
|
||||||
this._movementAngleOffset = behaviorData.movementAngleOffset || 0;
|
this._movementAngleOffset = behaviorData.movementAngleOffset || 0;
|
||||||
|
this._useLegacyTurnBack =
|
||||||
|
behaviorData.useLegacyTurnBack === undefined
|
||||||
|
? true
|
||||||
|
: behaviorData.useLegacyTurnBack;
|
||||||
}
|
}
|
||||||
|
|
||||||
getNetworkSyncData(): TopDownMovementNetworkSyncData {
|
getNetworkSyncData(): TopDownMovementNetworkSyncData {
|
||||||
@@ -303,9 +308,7 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSpeed(): float {
|
getSpeed(): float {
|
||||||
return Math.sqrt(
|
return Math.hypot(this._xVelocity, this._yVelocity);
|
||||||
this._xVelocity * this._xVelocity + this._yVelocity * this._yVelocity
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getXVelocity(): float {
|
getXVelocity(): float {
|
||||||
@@ -468,74 +471,71 @@ namespace gdjs {
|
|||||||
// variables without assigning them a value.
|
// variables without assigning them a value.
|
||||||
let directionInRad = 0;
|
let directionInRad = 0;
|
||||||
let directionInDeg = 0;
|
let directionInDeg = 0;
|
||||||
let cos = 1;
|
|
||||||
let sin = 0;
|
|
||||||
|
|
||||||
|
let isMoving = false;
|
||||||
|
let targetedSpeed = 0;
|
||||||
// Update the speed of the object:
|
// Update the speed of the object:
|
||||||
if (direction !== -1) {
|
if (direction !== -1) {
|
||||||
|
isMoving = true;
|
||||||
directionInRad =
|
directionInRad =
|
||||||
((direction + this._movementAngleOffset / 45) * Math.PI) / 4.0;
|
((direction + this._movementAngleOffset / 45) * Math.PI) / 4.0;
|
||||||
directionInDeg = direction * 45 + this._movementAngleOffset;
|
directionInDeg = direction * 45 + this._movementAngleOffset;
|
||||||
// This makes the trigo resilient to rounding errors on directionInRad.
|
targetedSpeed = this._maxSpeed;
|
||||||
cos = Math.cos(directionInRad);
|
|
||||||
sin = Math.sin(directionInRad);
|
|
||||||
if (cos === -1 || cos === 1) {
|
|
||||||
sin = 0;
|
|
||||||
}
|
|
||||||
if (sin === -1 || sin === 1) {
|
|
||||||
cos = 0;
|
|
||||||
}
|
|
||||||
this._xVelocity += this._acceleration * timeDelta * cos;
|
|
||||||
this._yVelocity += this._acceleration * timeDelta * sin;
|
|
||||||
} else if (this._stickForce !== 0) {
|
} else if (this._stickForce !== 0) {
|
||||||
|
isMoving = true;
|
||||||
if (!this._allowDiagonals) {
|
if (!this._allowDiagonals) {
|
||||||
this._stickAngle = 90 * Math.floor((this._stickAngle + 45) / 90);
|
this._stickAngle = 90 * Math.floor((this._stickAngle + 45) / 90);
|
||||||
}
|
}
|
||||||
directionInDeg = this._stickAngle + this._movementAngleOffset;
|
directionInDeg = this._stickAngle + this._movementAngleOffset;
|
||||||
directionInRad = (directionInDeg * Math.PI) / 180;
|
directionInRad = (directionInDeg * Math.PI) / 180;
|
||||||
const norm = this._acceleration * timeDelta * this._stickForce;
|
targetedSpeed = this._maxSpeed * this._stickForce;
|
||||||
// This makes the trigo resilient to rounding errors on directionInRad.
|
|
||||||
cos = Math.cos(directionInRad);
|
|
||||||
sin = Math.sin(directionInRad);
|
|
||||||
if (cos === -1 || cos === 1) {
|
|
||||||
sin = 0;
|
|
||||||
}
|
|
||||||
if (sin === -1 || sin === 1) {
|
|
||||||
cos = 0;
|
|
||||||
}
|
|
||||||
this._xVelocity += norm * cos;
|
|
||||||
this._yVelocity += norm * sin;
|
|
||||||
|
|
||||||
this._wasStickUsed = true;
|
this._wasStickUsed = true;
|
||||||
this._stickForce = 0;
|
|
||||||
} else if (this._yVelocity !== 0 || this._xVelocity !== 0) {
|
} else if (this._yVelocity !== 0 || this._xVelocity !== 0) {
|
||||||
|
isMoving = true;
|
||||||
directionInRad = Math.atan2(this._yVelocity, this._xVelocity);
|
directionInRad = Math.atan2(this._yVelocity, this._xVelocity);
|
||||||
directionInDeg = (directionInRad * 180.0) / Math.PI;
|
directionInDeg = (directionInRad * 180.0) / Math.PI;
|
||||||
const xVelocityWasPositive = this._xVelocity >= 0;
|
}
|
||||||
const yVelocityWasPositive = this._yVelocity >= 0;
|
if (isMoving) {
|
||||||
// This makes the trigo resilient to rounding errors on directionInRad.
|
// This makes the trigo resilient to rounding errors on directionInRad.
|
||||||
cos = Math.cos(directionInRad);
|
let cos = Math.cos(directionInRad);
|
||||||
sin = Math.sin(directionInRad);
|
let sin = Math.sin(directionInRad);
|
||||||
if (cos === -1 || cos === 1) {
|
if (cos === -1 || cos === 1) {
|
||||||
sin = 0;
|
sin = 0;
|
||||||
}
|
}
|
||||||
if (sin === -1 || sin === 1) {
|
if (sin === -1 || sin === 1) {
|
||||||
cos = 0;
|
cos = 0;
|
||||||
}
|
}
|
||||||
this._xVelocity -= this._deceleration * timeDelta * cos;
|
|
||||||
this._yVelocity -= this._deceleration * timeDelta * sin;
|
const getAcceleratedSpeed = this._useLegacyTurnBack
|
||||||
if (this._xVelocity > 0 !== xVelocityWasPositive) {
|
? TopDownMovementRuntimeBehavior.getLegacyAcceleratedSpeed
|
||||||
this._xVelocity = 0;
|
: TopDownMovementRuntimeBehavior.getAcceleratedSpeed;
|
||||||
}
|
|
||||||
if (this._yVelocity > 0 !== yVelocityWasPositive) {
|
let currentSpeed = Math.hypot(this._xVelocity, this._yVelocity);
|
||||||
this._yVelocity = 0;
|
const dotProduct = this._xVelocity * cos + this._yVelocity * sin;
|
||||||
|
if (dotProduct < 0) {
|
||||||
|
// The object is turning back.
|
||||||
|
// Keep the negative velocity projected on the new direction.
|
||||||
|
currentSpeed = dotProduct;
|
||||||
}
|
}
|
||||||
|
const speed = getAcceleratedSpeed(
|
||||||
|
currentSpeed,
|
||||||
|
targetedSpeed,
|
||||||
|
this._maxSpeed,
|
||||||
|
this._acceleration,
|
||||||
|
this._deceleration,
|
||||||
|
timeDelta
|
||||||
|
);
|
||||||
|
this._xVelocity = speed * cos;
|
||||||
|
this._yVelocity = speed * sin;
|
||||||
}
|
}
|
||||||
|
|
||||||
const squaredSpeed =
|
const squaredSpeed =
|
||||||
this._xVelocity * this._xVelocity + this._yVelocity * this._yVelocity;
|
this._xVelocity * this._xVelocity + this._yVelocity * this._yVelocity;
|
||||||
if (squaredSpeed > this._maxSpeed * this._maxSpeed) {
|
if (squaredSpeed > this._maxSpeed * this._maxSpeed) {
|
||||||
this._xVelocity = this._maxSpeed * cos;
|
const ratio = this._maxSpeed / Math.sqrt(squaredSpeed);
|
||||||
this._yVelocity = this._maxSpeed * sin;
|
this._xVelocity *= ratio;
|
||||||
|
this._yVelocity *= ratio;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No acceleration for angular speed for now.
|
// No acceleration for angular speed for now.
|
||||||
@@ -589,9 +589,125 @@ namespace gdjs {
|
|||||||
this._rightKey = false;
|
this._rightKey = false;
|
||||||
this._upKey = false;
|
this._upKey = false;
|
||||||
this._downKey = false;
|
this._downKey = false;
|
||||||
|
this._stickForce = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static getAcceleratedSpeed(
|
||||||
|
currentSpeed: float,
|
||||||
|
targetedSpeed: float,
|
||||||
|
speedMax: float,
|
||||||
|
acceleration: float,
|
||||||
|
deceleration: float,
|
||||||
|
timeDelta: float
|
||||||
|
): float {
|
||||||
|
let newSpeed = currentSpeed;
|
||||||
|
const turningBackAcceleration = Math.max(acceleration, deceleration);
|
||||||
|
if (targetedSpeed < 0) {
|
||||||
|
if (currentSpeed <= targetedSpeed) {
|
||||||
|
// Reduce the speed to match the stick force.
|
||||||
|
newSpeed = Math.min(
|
||||||
|
targetedSpeed,
|
||||||
|
currentSpeed + turningBackAcceleration * timeDelta
|
||||||
|
);
|
||||||
|
} else if (currentSpeed <= 0) {
|
||||||
|
// Accelerate
|
||||||
|
newSpeed -= Math.max(-speedMax, acceleration * timeDelta);
|
||||||
|
} else {
|
||||||
|
// Turn back at least as fast as it would stop.
|
||||||
|
newSpeed = Math.max(
|
||||||
|
targetedSpeed,
|
||||||
|
currentSpeed - turningBackAcceleration * timeDelta
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (targetedSpeed > 0) {
|
||||||
|
if (currentSpeed >= targetedSpeed) {
|
||||||
|
// Reduce the speed to match the stick force.
|
||||||
|
newSpeed = Math.max(
|
||||||
|
targetedSpeed,
|
||||||
|
currentSpeed - turningBackAcceleration * timeDelta
|
||||||
|
);
|
||||||
|
} else if (currentSpeed >= 0) {
|
||||||
|
// Accelerate
|
||||||
|
newSpeed = Math.min(
|
||||||
|
speedMax,
|
||||||
|
currentSpeed + acceleration * timeDelta
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Turn back at least as fast as it would stop.
|
||||||
|
newSpeed = Math.min(
|
||||||
|
targetedSpeed,
|
||||||
|
currentSpeed + turningBackAcceleration * timeDelta
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Decelerate and stop.
|
||||||
|
if (currentSpeed < 0) {
|
||||||
|
newSpeed = Math.min(currentSpeed + deceleration * timeDelta, 0);
|
||||||
|
}
|
||||||
|
if (currentSpeed > 0) {
|
||||||
|
newSpeed = Math.max(currentSpeed - deceleration * timeDelta, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getLegacyAcceleratedSpeed(
|
||||||
|
currentSpeed: float,
|
||||||
|
targetedSpeed: float,
|
||||||
|
speedMax: float,
|
||||||
|
acceleration: float,
|
||||||
|
deceleration: float,
|
||||||
|
timeDelta: float
|
||||||
|
): float {
|
||||||
|
let newSpeed = currentSpeed;
|
||||||
|
if (targetedSpeed < 0) {
|
||||||
|
if (currentSpeed <= targetedSpeed) {
|
||||||
|
// Reduce the speed to match the stick force.
|
||||||
|
newSpeed = Math.min(
|
||||||
|
targetedSpeed,
|
||||||
|
currentSpeed + deceleration * timeDelta
|
||||||
|
);
|
||||||
|
} else if (currentSpeed <= 0) {
|
||||||
|
// Accelerate
|
||||||
|
newSpeed -= Math.max(-speedMax, acceleration * timeDelta);
|
||||||
|
} else {
|
||||||
|
newSpeed = Math.max(
|
||||||
|
targetedSpeed,
|
||||||
|
currentSpeed - deceleration * timeDelta
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (targetedSpeed > 0) {
|
||||||
|
if (currentSpeed >= targetedSpeed) {
|
||||||
|
// Reduce the speed to match the stick force.
|
||||||
|
newSpeed = Math.max(
|
||||||
|
targetedSpeed,
|
||||||
|
currentSpeed - deceleration * timeDelta
|
||||||
|
);
|
||||||
|
} else if (currentSpeed >= 0) {
|
||||||
|
// Accelerate
|
||||||
|
newSpeed = Math.min(
|
||||||
|
speedMax,
|
||||||
|
currentSpeed + acceleration * timeDelta
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
newSpeed = Math.min(
|
||||||
|
targetedSpeed,
|
||||||
|
currentSpeed + deceleration * timeDelta
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Decelerate and stop.
|
||||||
|
if (currentSpeed < 0) {
|
||||||
|
newSpeed = Math.min(currentSpeed + deceleration * timeDelta, 0);
|
||||||
|
}
|
||||||
|
if (currentSpeed > 0) {
|
||||||
|
newSpeed = Math.max(currentSpeed - deceleration * timeDelta, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
simulateControl(input: string) {
|
simulateControl(input: string) {
|
||||||
if (input === 'Left') {
|
if (input === 'Left') {
|
||||||
this._leftKey = true;
|
this._leftKey = true;
|
||||||
|
@@ -60,7 +60,7 @@ module.exports = {
|
|||||||
'Tween',
|
'Tween',
|
||||||
_('Tweening'),
|
_('Tweening'),
|
||||||
_(
|
_(
|
||||||
'Animate object properties over time. This allows smooth transitions, animations or movement of objects to specified positions.'
|
'Smoothly animate object properties over time — such as position, rotation scale, opacity, and more — as well as variables. Ideal for creating fluid transitions and UI animations. While you can use tweens to move objects, other behaviors (like platform, physics, ellipse movement...) or forces are often better suited for dynamic movement. Tween is best used for animating UI elements, static objects that need to move from one point to another, or other values like variables.'
|
||||||
),
|
),
|
||||||
'Matthias Meike, Florian Rival',
|
'Matthias Meike, Florian Rival',
|
||||||
'Open source (MIT License)'
|
'Open source (MIT License)'
|
||||||
|
@@ -18,8 +18,6 @@ namespace gdjs {
|
|||||||
|
|
||||||
export type VideoNetworkSyncDataType = {
|
export type VideoNetworkSyncDataType = {
|
||||||
op: float;
|
op: float;
|
||||||
wid: float;
|
|
||||||
hei: float;
|
|
||||||
// We don't sync volume, as it's probably a user setting?
|
// We don't sync volume, as it's probably a user setting?
|
||||||
pla: boolean;
|
pla: boolean;
|
||||||
loop: boolean;
|
loop: boolean;
|
||||||
@@ -105,8 +103,6 @@ namespace gdjs {
|
|||||||
return {
|
return {
|
||||||
...super.getNetworkSyncData(),
|
...super.getNetworkSyncData(),
|
||||||
op: this._opacity,
|
op: this._opacity,
|
||||||
wid: this.getWidth(),
|
|
||||||
hei: this.getHeight(),
|
|
||||||
pla: this.isPlayed(),
|
pla: this.isPlayed(),
|
||||||
loop: this.isLooped(),
|
loop: this.isLooped(),
|
||||||
ct: this.getCurrentTime(),
|
ct: this.getCurrentTime(),
|
||||||
@@ -120,12 +116,6 @@ namespace gdjs {
|
|||||||
if (this._opacity !== undefined && this._opacity && syncData.op) {
|
if (this._opacity !== undefined && this._opacity && syncData.op) {
|
||||||
this.setOpacity(syncData.op);
|
this.setOpacity(syncData.op);
|
||||||
}
|
}
|
||||||
if (this.getWidth() !== undefined && this.getWidth() !== syncData.wid) {
|
|
||||||
this.setWidth(syncData.wid);
|
|
||||||
}
|
|
||||||
if (this.getHeight() !== undefined && this.getHeight() !== syncData.hei) {
|
|
||||||
this.setHeight(syncData.hei);
|
|
||||||
}
|
|
||||||
if (syncData.pla !== undefined && this.isPlayed() !== syncData.pla) {
|
if (syncData.pla !== undefined && this.isPlayed() !== syncData.pla) {
|
||||||
syncData.pla ? this.play() : this.pause();
|
syncData.pla ? this.play() : this.pause();
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,12 @@ namespace gdjs {
|
|||||||
animatable?: SpriteAnimationData[];
|
animatable?: SpriteAnimationData[];
|
||||||
variant: string;
|
variant: string;
|
||||||
childrenContent: { [objectName: string]: ObjectConfiguration & any };
|
childrenContent: { [objectName: string]: ObjectConfiguration & any };
|
||||||
|
isInnerAreaFollowingParentSize: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CustomObjectNetworkSyncDataType = ObjectNetworkSyncData & {
|
||||||
|
ifx: boolean;
|
||||||
|
ify: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,9 +117,19 @@ namespace gdjs {
|
|||||||
name: '',
|
name: '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// Legacy events-based objects don't have any instance in their default
|
||||||
|
// variant since there wasn't a graphical editor at the time.
|
||||||
|
// In this case, the editor doesn't allow to choose a variant, but a
|
||||||
|
// variant may have stayed after a user rolled back the extension.
|
||||||
|
// This variant must be ignored to match what the editor shows.
|
||||||
|
const isForcedToOverrideEventsBasedObjectChildrenConfiguration =
|
||||||
|
eventsBasedObjectData.defaultVariant.instances.length == 0;
|
||||||
let usedVariantData: EventsBasedObjectVariantData =
|
let usedVariantData: EventsBasedObjectVariantData =
|
||||||
eventsBasedObjectData.defaultVariant;
|
eventsBasedObjectData.defaultVariant;
|
||||||
if (customObjectData.variant) {
|
if (
|
||||||
|
customObjectData.variant &&
|
||||||
|
!isForcedToOverrideEventsBasedObjectChildrenConfiguration
|
||||||
|
) {
|
||||||
for (
|
for (
|
||||||
let variantIndex = 0;
|
let variantIndex = 0;
|
||||||
variantIndex < eventsBasedObjectData.variants.length;
|
variantIndex < eventsBasedObjectData.variants.length;
|
||||||
@@ -154,10 +170,12 @@ namespace gdjs {
|
|||||||
override reinitialize(objectData: ObjectData & CustomObjectConfiguration) {
|
override reinitialize(objectData: ObjectData & CustomObjectConfiguration) {
|
||||||
super.reinitialize(objectData);
|
super.reinitialize(objectData);
|
||||||
|
|
||||||
this._initializeFromObjectData(objectData);
|
|
||||||
this._reinitializeRenderer();
|
this._reinitializeRenderer();
|
||||||
|
this._initializeFromObjectData(objectData);
|
||||||
|
|
||||||
// The generated code calls the onCreated super implementation at the end.
|
// When changing the variant, the instance is like a new instance.
|
||||||
|
// We call again `onCreated` at the end, like done by the constructor
|
||||||
|
// the first time it's created.
|
||||||
this.onCreated();
|
this.onCreated();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,9 +190,57 @@ namespace gdjs {
|
|||||||
newObjectData.animatable || []
|
newObjectData.animatable || []
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (oldObjectData.variant !== newObjectData.variant) {
|
||||||
|
const width = this.getWidth();
|
||||||
|
const height = this.getHeight();
|
||||||
|
const hasInnerAreaChanged =
|
||||||
|
oldObjectData.isInnerAreaFollowingParentSize &&
|
||||||
|
this._instanceContainer._initialInnerArea &&
|
||||||
|
this._innerArea &&
|
||||||
|
(this._instanceContainer._initialInnerArea.min[0] !==
|
||||||
|
this._innerArea.min[0] ||
|
||||||
|
this._instanceContainer._initialInnerArea.min[1] !==
|
||||||
|
this._innerArea.min[1] ||
|
||||||
|
this._instanceContainer._initialInnerArea.max[0] !==
|
||||||
|
this._innerArea.max[0] ||
|
||||||
|
this._instanceContainer._initialInnerArea.max[1] !==
|
||||||
|
this._innerArea.max[1]);
|
||||||
|
|
||||||
|
this._reinitializeRenderer();
|
||||||
|
this._initializeFromObjectData(newObjectData);
|
||||||
|
|
||||||
|
// The generated code calls the onCreated super implementation at the end.
|
||||||
|
this.onCreated();
|
||||||
|
|
||||||
|
// Keep the custom size
|
||||||
|
if (hasInnerAreaChanged) {
|
||||||
|
this.setWidth(width);
|
||||||
|
this.setHeight(height);
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getNetworkSyncData(): CustomObjectNetworkSyncDataType {
|
||||||
|
return {
|
||||||
|
...super.getNetworkSyncData(),
|
||||||
|
ifx: this.isFlippedX(),
|
||||||
|
ify: this.isFlippedY(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFromNetworkSyncData(
|
||||||
|
networkSyncData: CustomObjectNetworkSyncDataType
|
||||||
|
) {
|
||||||
|
super.updateFromNetworkSyncData(networkSyncData);
|
||||||
|
if (networkSyncData.ifx !== undefined) {
|
||||||
|
this.flipX(networkSyncData.ifx);
|
||||||
|
}
|
||||||
|
if (networkSyncData.ify !== undefined) {
|
||||||
|
this.flipY(networkSyncData.ify);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override extraInitializationFromInitialInstance(
|
override extraInitializationFromInitialInstance(
|
||||||
initialInstanceData: InstanceData
|
initialInstanceData: InstanceData
|
||||||
) {
|
) {
|
||||||
@@ -212,7 +278,12 @@ namespace gdjs {
|
|||||||
// Let behaviors do something before the object is destroyed.
|
// Let behaviors do something before the object is destroyed.
|
||||||
super.onDeletedFromScene();
|
super.onDeletedFromScene();
|
||||||
// Destroy the children.
|
// Destroy the children.
|
||||||
this._instanceContainer.onDestroyFromScene(this._runtimeScene);
|
this._instanceContainer.onDeletedFromScene(this._runtimeScene);
|
||||||
|
}
|
||||||
|
|
||||||
|
override onDestroyed(): void {
|
||||||
|
this._instanceContainer._destroy();
|
||||||
|
super.onDestroyed();
|
||||||
}
|
}
|
||||||
|
|
||||||
override update(parent: gdjs.RuntimeInstanceContainer): void {
|
override update(parent: gdjs.RuntimeInstanceContainer): void {
|
||||||
@@ -235,6 +306,8 @@ namespace gdjs {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called when the preview is being hot-reloaded.
|
* This method is called when the preview is being hot-reloaded.
|
||||||
|
*
|
||||||
|
* Custom objects implement this method with code generated from events.
|
||||||
*/
|
*/
|
||||||
onHotReloading(parent: gdjs.RuntimeInstanceContainer) {}
|
onHotReloading(parent: gdjs.RuntimeInstanceContainer) {}
|
||||||
|
|
||||||
@@ -243,6 +316,8 @@ namespace gdjs {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called each tick after events are done.
|
* This method is called each tick after events are done.
|
||||||
|
*
|
||||||
|
* Custom objects implement this method with code generated from events.
|
||||||
* @param parent The instanceContainer owning the object
|
* @param parent The instanceContainer owning the object
|
||||||
*/
|
*/
|
||||||
doStepPostEvents(parent: gdjs.RuntimeInstanceContainer) {}
|
doStepPostEvents(parent: gdjs.RuntimeInstanceContainer) {}
|
||||||
@@ -250,6 +325,8 @@ namespace gdjs {
|
|||||||
/**
|
/**
|
||||||
* This method is called when the object is being removed from its parent
|
* This method is called when the object is being removed from its parent
|
||||||
* container and is about to be destroyed/reused later.
|
* container and is about to be destroyed/reused later.
|
||||||
|
*
|
||||||
|
* Custom objects implement this method with code generated from events.
|
||||||
*/
|
*/
|
||||||
onDestroy(parent: gdjs.RuntimeInstanceContainer) {}
|
onDestroy(parent: gdjs.RuntimeInstanceContainer) {}
|
||||||
|
|
||||||
|
@@ -8,7 +8,6 @@ namespace gdjs {
|
|||||||
objectData: ObjectData & CustomObjectConfiguration
|
objectData: ObjectData & CustomObjectConfiguration
|
||||||
) {
|
) {
|
||||||
super(parent, objectData);
|
super(parent, objectData);
|
||||||
this.getRenderer().reinitialize(this, parent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override _createRender(): gdjs.CustomRuntimeObject2DRenderer {
|
protected override _createRender(): gdjs.CustomRuntimeObject2DRenderer {
|
||||||
|
@@ -24,7 +24,7 @@ namespace gdjs {
|
|||||||
*
|
*
|
||||||
* @see gdjs.CustomRuntimeObject._innerArea
|
* @see gdjs.CustomRuntimeObject._innerArea
|
||||||
**/
|
**/
|
||||||
private _initialInnerArea: {
|
_initialInnerArea: {
|
||||||
min: [float, float, float];
|
min: [float, float, float];
|
||||||
max: [float, float, float];
|
max: [float, float, float];
|
||||||
} | null = null;
|
} | null = null;
|
||||||
@@ -47,6 +47,9 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addLayer(layerData: LayerData) {
|
addLayer(layerData: LayerData) {
|
||||||
|
if (this._layers.containsKey(layerData.name)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const layer = new gdjs.RuntimeCustomObjectLayer(layerData, this);
|
const layer = new gdjs.RuntimeCustomObjectLayer(layerData, this);
|
||||||
this._layers.put(layerData.name, layer);
|
this._layers.put(layerData.name, layer);
|
||||||
this._orderedLayers.push(layer);
|
this._orderedLayers.push(layer);
|
||||||
@@ -68,9 +71,13 @@ namespace gdjs {
|
|||||||
eventsBasedObjectVariantData: EventsBasedObjectVariantData
|
eventsBasedObjectVariantData: EventsBasedObjectVariantData
|
||||||
) {
|
) {
|
||||||
if (this._isLoaded) {
|
if (this._isLoaded) {
|
||||||
this.onDestroyFromScene(this._parent);
|
this.onDeletedFromScene(this._parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isForcedToOverrideEventsBasedObjectChildrenConfiguration =
|
||||||
|
!eventsBasedObjectVariantData.name &&
|
||||||
|
eventsBasedObjectVariantData.instances.length == 0;
|
||||||
|
|
||||||
this._setOriginalInnerArea(eventsBasedObjectVariantData);
|
this._setOriginalInnerArea(eventsBasedObjectVariantData);
|
||||||
|
|
||||||
// Registering objects
|
// Registering objects
|
||||||
@@ -83,7 +90,8 @@ namespace gdjs {
|
|||||||
// The children configuration override only applies to the default variant.
|
// The children configuration override only applies to the default variant.
|
||||||
if (
|
if (
|
||||||
customObjectData.childrenContent &&
|
customObjectData.childrenContent &&
|
||||||
!eventsBasedObjectVariantData.name
|
(!eventsBasedObjectVariantData.name ||
|
||||||
|
isForcedToOverrideEventsBasedObjectChildrenConfiguration)
|
||||||
) {
|
) {
|
||||||
this.registerObject({
|
this.registerObject({
|
||||||
...childObjectData,
|
...childObjectData,
|
||||||
@@ -178,26 +186,25 @@ namespace gdjs {
|
|||||||
*
|
*
|
||||||
* @param instanceContainer The container owning the object.
|
* @param instanceContainer The container owning the object.
|
||||||
*/
|
*/
|
||||||
onDestroyFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
onDeletedFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||||
if (!this._isLoaded) {
|
if (!this._isLoaded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify the objects they are being destroyed
|
// Notify the objects they are being destroyed
|
||||||
const allInstancesList = this.getAdhocListOfAllInstances();
|
const allInstancesList = this.getAdhocListOfAllInstances();
|
||||||
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
|
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
|
||||||
const object = allInstancesList[i];
|
const object = allInstancesList[i];
|
||||||
object.onDeletedFromScene();
|
object.onDeletedFromScene();
|
||||||
// The object can free all its resource directly...
|
|
||||||
object.onDestroyed();
|
|
||||||
}
|
}
|
||||||
// ...as its container cache `_instancesRemoved` is also destroy.
|
|
||||||
this._destroy();
|
|
||||||
|
|
||||||
this._isLoaded = false;
|
this._isLoaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_destroy() {
|
override _destroy() {
|
||||||
|
const allInstancesList = this.getAdhocListOfAllInstances();
|
||||||
|
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
|
||||||
|
const object = allInstancesList[i];
|
||||||
|
object.onDestroyed();
|
||||||
|
}
|
||||||
// It should not be necessary to reset these variables, but this help
|
// It should not be necessary to reset these variables, but this help
|
||||||
// ensuring that all memory related to the container is released immediately.
|
// ensuring that all memory related to the container is released immediately.
|
||||||
super._destroy();
|
super._destroy();
|
||||||
@@ -375,11 +382,9 @@ namespace gdjs {
|
|||||||
): FloatPoint {
|
): FloatPoint {
|
||||||
const position = result || [0, 0];
|
const position = result || [0, 0];
|
||||||
this._customObject.applyObjectTransformation(sceneX, sceneY, position);
|
this._customObject.applyObjectTransformation(sceneX, sceneY, position);
|
||||||
return this._parent.convertInverseCoords(
|
return this._parent
|
||||||
position[0],
|
.getLayer(this._customObject.getLayer())
|
||||||
position[1],
|
.convertInverseCoords(position[0], position[1], 0, position);
|
||||||
position
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -162,5 +162,29 @@ namespace gdjs {
|
|||||||
this._invalidModel.scene.clear();
|
this._invalidModel.scene.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unload the specified list of resources:
|
||||||
|
* this clears the models, resources loaded and destroy 3D models loaders in this manager.
|
||||||
|
*
|
||||||
|
* Usually called when scene resoures are unloaded.
|
||||||
|
*
|
||||||
|
* @param resourcesList The list of specific resources
|
||||||
|
*/
|
||||||
|
unloadResourcesList(resourcesList: ResourceData[]): void {
|
||||||
|
resourcesList.forEach((resourceData) => {
|
||||||
|
const loadedThreeModel = this._loadedThreeModels.get(resourceData);
|
||||||
|
if (loadedThreeModel) {
|
||||||
|
loadedThreeModel.scene.clear();
|
||||||
|
this._loadedThreeModels.delete(resourceData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadedArrayBuffer =
|
||||||
|
this._downloadedArrayBuffers.get(resourceData);
|
||||||
|
if (downloadedArrayBuffer) {
|
||||||
|
this._downloadedArrayBuffers.delete(resourceData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
namespace gdjs {
|
namespace gdjs {
|
||||||
const logger = new gdjs.Logger('ResourceLoader');
|
const logger = new gdjs.Logger('ResourceLoader');
|
||||||
|
const debugLogger = new gdjs.Logger('ResourceLoader - debug').enable(false);
|
||||||
|
|
||||||
const addSearchParameterToUrl = (
|
const addSearchParameterToUrl = (
|
||||||
url: string,
|
url: string,
|
||||||
@@ -96,17 +97,15 @@ namespace gdjs {
|
|||||||
*/
|
*/
|
||||||
private _globalResources: Array<string>;
|
private _globalResources: Array<string>;
|
||||||
/**
|
/**
|
||||||
* Resources by scene names.
|
* Resources and the loading state of each scene, indexed by scene name.
|
||||||
*/
|
*/
|
||||||
private _sceneResources: Map<string, Array<string>>;
|
private _sceneLoadingStates: Map<
|
||||||
/**
|
string,
|
||||||
* Keep track of which scene whose resources has already be pre-loaded.
|
{
|
||||||
*/
|
resourceNames: Array<string>;
|
||||||
private _sceneNamesToLoad: Set<string>;
|
status: 'not-loaded' | 'loaded' | 'ready';
|
||||||
/**
|
}
|
||||||
* Keep track of which scene whose resources has already be loaded.
|
> = new Map();
|
||||||
*/
|
|
||||||
private _sceneNamesToMakeReady: Set<string>;
|
|
||||||
/**
|
/**
|
||||||
* A queue of scenes whose resources are still to be pre-loaded.
|
* A queue of scenes whose resources are still to be pre-loaded.
|
||||||
*/
|
*/
|
||||||
@@ -127,11 +126,12 @@ namespace gdjs {
|
|||||||
private _spineManager: SpineManager | null = null;
|
private _spineManager: SpineManager | null = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only used by events.
|
* The name of the scene for which resources are currently being loaded.
|
||||||
*/
|
*/
|
||||||
private currentLoadingSceneName: string = '';
|
private currentLoadingSceneName: string = '';
|
||||||
/**
|
/**
|
||||||
* Only used by events.
|
* The progress, between 0 and 1, of the loading of the resource, for the
|
||||||
|
* scene that is being loaded (see `currentLoadingSceneName`).
|
||||||
*/
|
*/
|
||||||
private currentSceneLoadingProgress: float = 0;
|
private currentSceneLoadingProgress: float = 0;
|
||||||
/**
|
/**
|
||||||
@@ -144,8 +144,8 @@ namespace gdjs {
|
|||||||
/**
|
/**
|
||||||
* @param runtimeGame The game.
|
* @param runtimeGame The game.
|
||||||
* @param resourceDataArray The resources data of the game.
|
* @param resourceDataArray The resources data of the game.
|
||||||
* @param globalResources The resources needed for any layer.
|
* @param globalResources The resources needed for any scene.
|
||||||
* @param layoutDataArray The resources used by each layer.
|
* @param layoutDataArray The resources used by each scene.
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
runtimeGame: RuntimeGame,
|
runtimeGame: RuntimeGame,
|
||||||
@@ -158,9 +158,6 @@ namespace gdjs {
|
|||||||
this._globalResources = globalResources;
|
this._globalResources = globalResources;
|
||||||
|
|
||||||
// These 3 attributes are filled by `setResources`.
|
// These 3 attributes are filled by `setResources`.
|
||||||
this._sceneResources = new Map<string, Array<string>>();
|
|
||||||
this._sceneNamesToLoad = new Set<string>();
|
|
||||||
this._sceneNamesToMakeReady = new Set<string>();
|
|
||||||
this.setResources(resourceDataArray, globalResources, layoutDataArray);
|
this.setResources(resourceDataArray, globalResources, layoutDataArray);
|
||||||
|
|
||||||
this._imageManager = new gdjs.ImageManager(this);
|
this._imageManager = new gdjs.ImageManager(this);
|
||||||
@@ -224,23 +221,31 @@ namespace gdjs {
|
|||||||
): void {
|
): void {
|
||||||
this._globalResources = globalResources;
|
this._globalResources = globalResources;
|
||||||
|
|
||||||
this._sceneResources.clear();
|
this._sceneLoadingStates.clear();
|
||||||
this._sceneNamesToLoad.clear();
|
|
||||||
this._sceneNamesToMakeReady.clear();
|
|
||||||
for (const layoutData of layoutDataArray) {
|
for (const layoutData of layoutDataArray) {
|
||||||
this._sceneResources.set(
|
this._sceneLoadingStates.set(layoutData.name, {
|
||||||
layoutData.name,
|
resourceNames: layoutData.usedResources.map(
|
||||||
layoutData.usedResources.map((resource) => resource.name)
|
(resource) => resource.name
|
||||||
);
|
),
|
||||||
this._sceneNamesToLoad.add(layoutData.name);
|
status: 'not-loaded',
|
||||||
this._sceneNamesToMakeReady.add(layoutData.name);
|
});
|
||||||
}
|
}
|
||||||
// TODO Clearing the queue doesn't abort the running task, but it should
|
// TODO Clearing the queue doesn't abort the running task, but it should
|
||||||
// not matter as resource loading is really fast in preview mode.
|
// not matter as resource loading is really fast in preview mode.
|
||||||
this._sceneToLoadQueue.length = 0;
|
this._sceneToLoadQueue.length = 0;
|
||||||
for (let index = layoutDataArray.length - 1; index >= 0; index--) {
|
for (let index = layoutDataArray.length - 1; index >= 0; index--) {
|
||||||
const layoutData = layoutDataArray[index];
|
const layoutData = layoutDataArray[index];
|
||||||
this._sceneToLoadQueue.push(new SceneLoadingTask(layoutData.name));
|
|
||||||
|
const resourcesPreloading = layoutData.resourcesPreloading || 'inherit';
|
||||||
|
const resolvedResourcesPreloading =
|
||||||
|
resourcesPreloading === 'inherit'
|
||||||
|
? this._runtimeGame.getSceneResourcesPreloading()
|
||||||
|
: resourcesPreloading;
|
||||||
|
|
||||||
|
if (resolvedResourcesPreloading === 'at-startup') {
|
||||||
|
this._sceneToLoadQueue.push(new SceneLoadingTask(layoutData.name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._resources.clear();
|
this._resources.clear();
|
||||||
@@ -271,8 +276,10 @@ namespace gdjs {
|
|||||||
onProgress(loadedCount, this._resources.size);
|
onProgress(loadedCount, this._resources.size);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this._sceneNamesToLoad.clear();
|
|
||||||
this._sceneNamesToMakeReady.clear();
|
for (const sceneLoadingState of this._sceneLoadingStates.values()) {
|
||||||
|
sceneLoadingState.status = 'ready';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -282,17 +289,21 @@ namespace gdjs {
|
|||||||
firstSceneName: string,
|
firstSceneName: string,
|
||||||
onProgress: (count: number, total: number) => void
|
onProgress: (count: number, total: number) => void
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const sceneResources = this._sceneResources.get(firstSceneName);
|
const firstSceneState = this._sceneLoadingStates.get(firstSceneName);
|
||||||
if (!sceneResources) {
|
if (!firstSceneState) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
'Can\'t load resource for unknown scene: "' + firstSceneName + '".'
|
'Can\'t load resource for unknown scene: "' + firstSceneName + '".'
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let loadedCount = 0;
|
let loadedCount = 0;
|
||||||
const resources = [...this._globalResources, ...sceneResources.values()];
|
const resourceNames = [
|
||||||
|
...this._globalResources,
|
||||||
|
...firstSceneState.resourceNames,
|
||||||
|
];
|
||||||
await processAndRetryIfNeededWithPromisePool(
|
await processAndRetryIfNeededWithPromisePool(
|
||||||
resources,
|
resourceNames,
|
||||||
maxForegroundConcurrency,
|
maxForegroundConcurrency,
|
||||||
maxAttempt,
|
maxAttempt,
|
||||||
async (resourceName) => {
|
async (resourceName) => {
|
||||||
@@ -304,11 +315,11 @@ namespace gdjs {
|
|||||||
await this._loadResource(resource);
|
await this._loadResource(resource);
|
||||||
await this._processResource(resource);
|
await this._processResource(resource);
|
||||||
loadedCount++;
|
loadedCount++;
|
||||||
onProgress(loadedCount, resources.length);
|
onProgress(loadedCount, resourceNames.length);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this._setSceneAssetsLoaded(firstSceneName);
|
|
||||||
this._setSceneAssetsReady(firstSceneName);
|
firstSceneState.status = 'ready';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -318,17 +329,32 @@ namespace gdjs {
|
|||||||
* scenes.
|
* scenes.
|
||||||
*/
|
*/
|
||||||
async loadAllSceneInBackground(): Promise<void> {
|
async loadAllSceneInBackground(): Promise<void> {
|
||||||
|
if (this.currentLoadingSceneName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
debugLogger.log('Loading all scene resources, in background.');
|
||||||
while (this._sceneToLoadQueue.length > 0) {
|
while (this._sceneToLoadQueue.length > 0) {
|
||||||
|
debugLogger.log(
|
||||||
|
`Still resources of ${this._sceneToLoadQueue.length} scene(s) to load: ${this._sceneToLoadQueue.map((task) => task.sceneName).join(', ')}`
|
||||||
|
);
|
||||||
const task = this._sceneToLoadQueue[this._sceneToLoadQueue.length - 1];
|
const task = this._sceneToLoadQueue[this._sceneToLoadQueue.length - 1];
|
||||||
if (task === undefined) {
|
if (task === undefined) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
this.currentLoadingSceneName = task.sceneName;
|
this.currentLoadingSceneName = task.sceneName;
|
||||||
if (!this.areSceneAssetsLoaded(task.sceneName)) {
|
if (!this.areSceneAssetsLoaded(task.sceneName)) {
|
||||||
|
debugLogger.log(
|
||||||
|
`Loading (but not processing) resources for scene ${task.sceneName}.`
|
||||||
|
);
|
||||||
await this._doLoadSceneResources(
|
await this._doLoadSceneResources(
|
||||||
task.sceneName,
|
task.sceneName,
|
||||||
async (count, total) => task.onProgress(count, total)
|
async (count, total) => task.onProgress(count, total)
|
||||||
);
|
);
|
||||||
|
debugLogger.log(
|
||||||
|
`Done loading (but not processing) resources for scene ${task.sceneName}.`
|
||||||
|
);
|
||||||
|
|
||||||
// A scene may have been moved last while awaiting resources to be
|
// A scene may have been moved last while awaiting resources to be
|
||||||
// downloaded (see _prioritizeScene).
|
// downloaded (see _prioritizeScene).
|
||||||
this._sceneToLoadQueue.splice(
|
this._sceneToLoadQueue.splice(
|
||||||
@@ -340,6 +366,7 @@ namespace gdjs {
|
|||||||
this._sceneToLoadQueue.pop();
|
this._sceneToLoadQueue.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
debugLogger.log(`Scene resources loading finished.`);
|
||||||
this.currentLoadingSceneName = '';
|
this.currentLoadingSceneName = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,16 +374,17 @@ namespace gdjs {
|
|||||||
sceneName: string,
|
sceneName: string,
|
||||||
onProgress?: (count: number, total: number) => Promise<void>
|
onProgress?: (count: number, total: number) => Promise<void>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const sceneResources = this._sceneResources.get(sceneName);
|
const sceneState = this._sceneLoadingStates.get(sceneName);
|
||||||
if (!sceneResources) {
|
if (!sceneState) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
'Can\'t load resource for unknown scene: "' + sceneName + '".'
|
'Can\'t load resource for unknown scene: "' + sceneName + '".'
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let loadedCount = 0;
|
let loadedCount = 0;
|
||||||
await processAndRetryIfNeededWithPromisePool(
|
await processAndRetryIfNeededWithPromisePool(
|
||||||
[...sceneResources.values()],
|
sceneState.resourceNames,
|
||||||
this._isLoadingInForeground
|
this._isLoadingInForeground
|
||||||
? maxForegroundConcurrency
|
? maxForegroundConcurrency
|
||||||
: maxBackgroundConcurrency,
|
: maxBackgroundConcurrency,
|
||||||
@@ -369,11 +397,13 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
await this._loadResource(resource);
|
await this._loadResource(resource);
|
||||||
loadedCount++;
|
loadedCount++;
|
||||||
this.currentSceneLoadingProgress = loadedCount / this._resources.size;
|
this.currentSceneLoadingProgress =
|
||||||
onProgress && (await onProgress(loadedCount, this._resources.size));
|
loadedCount / sceneState.resourceNames.length;
|
||||||
|
onProgress &&
|
||||||
|
(await onProgress(loadedCount, sceneState.resourceNames.length));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this._setSceneAssetsLoaded(sceneName);
|
sceneState.status = 'loaded';
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _loadResource(resource: ResourceData): Promise<void> {
|
private async _loadResource(resource: ResourceData): Promise<void> {
|
||||||
@@ -405,8 +435,8 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
await this.loadSceneResources(sceneName, onProgress);
|
await this.loadSceneResources(sceneName, onProgress);
|
||||||
|
|
||||||
const sceneResources = this._sceneResources.get(sceneName);
|
const sceneState = this._sceneLoadingStates.get(sceneName);
|
||||||
if (!sceneResources) {
|
if (!sceneState) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
'Can\'t load resource for unknown scene: "' + sceneName + '".'
|
'Can\'t load resource for unknown scene: "' + sceneName + '".'
|
||||||
);
|
);
|
||||||
@@ -414,7 +444,7 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let parsedCount = 0;
|
let parsedCount = 0;
|
||||||
for (const resourceName of sceneResources) {
|
for (const resourceName of sceneState.resourceNames) {
|
||||||
const resource = this._resources.get(resourceName);
|
const resource = this._resources.get(resourceName);
|
||||||
if (!resource) {
|
if (!resource) {
|
||||||
logger.warn('Unable to find resource "' + resourceName + '".');
|
logger.warn('Unable to find resource "' + resourceName + '".');
|
||||||
@@ -422,9 +452,10 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
await this._processResource(resource);
|
await this._processResource(resource);
|
||||||
parsedCount++;
|
parsedCount++;
|
||||||
onProgress && (await onProgress(parsedCount, sceneResources.length));
|
onProgress &&
|
||||||
|
(await onProgress(parsedCount, sceneState.resourceNames.length));
|
||||||
}
|
}
|
||||||
this._setSceneAssetsReady(sceneName);
|
sceneState.status = 'ready';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -438,15 +469,25 @@ namespace gdjs {
|
|||||||
sceneName: string,
|
sceneName: string,
|
||||||
onProgress?: (count: number, total: number) => void
|
onProgress?: (count: number, total: number) => void
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
debugLogger.log(
|
||||||
|
`Prioritization of loading of resources for scene ${sceneName} was requested.`
|
||||||
|
);
|
||||||
|
|
||||||
this._isLoadingInForeground = true;
|
this._isLoadingInForeground = true;
|
||||||
const task = this._prioritizeScene(sceneName);
|
const task = this._prioritizeScene(sceneName);
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
if (!task) {
|
if (!task) {
|
||||||
this._isLoadingInForeground = false;
|
this._isLoadingInForeground = false;
|
||||||
|
debugLogger.log(
|
||||||
|
`Loading of resources for scene ${sceneName} was immediately resolved.`
|
||||||
|
);
|
||||||
resolve();
|
resolve();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
task.registerCallback(() => {
|
task.registerCallback(() => {
|
||||||
|
debugLogger.log(
|
||||||
|
`Loading of resources for scene ${sceneName} just finished.`
|
||||||
|
);
|
||||||
this._isLoadingInForeground = false;
|
this._isLoadingInForeground = false;
|
||||||
resolve();
|
resolve();
|
||||||
}, onProgress);
|
}, onProgress);
|
||||||
@@ -463,6 +504,51 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To be called when a scene is unloaded.
|
||||||
|
*/
|
||||||
|
unloadSceneResources({
|
||||||
|
unloadedSceneName,
|
||||||
|
newSceneName,
|
||||||
|
}: {
|
||||||
|
unloadedSceneName: string;
|
||||||
|
newSceneName: string | null;
|
||||||
|
}): void {
|
||||||
|
if (!unloadedSceneName) return;
|
||||||
|
debugLogger.log(
|
||||||
|
`Unloading of resources for scene ${unloadedSceneName} was requested.`
|
||||||
|
);
|
||||||
|
|
||||||
|
const sceneUniqueResourcesByKindMap =
|
||||||
|
this._getResourcesByKindOnlyUsedInUnloadedScene({
|
||||||
|
unloadedSceneName,
|
||||||
|
newSceneName,
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const [kindResourceManager, resourceManager] of this
|
||||||
|
._resourceManagersMap) {
|
||||||
|
const resources =
|
||||||
|
sceneUniqueResourcesByKindMap.get(kindResourceManager);
|
||||||
|
if (resources) {
|
||||||
|
debugLogger.log(
|
||||||
|
`Unloading of resources of kind ${kindResourceManager} for scene ${unloadedSceneName}: `,
|
||||||
|
resources.map((resource) => resource.name).join(', ')
|
||||||
|
);
|
||||||
|
resourceManager.unloadResourcesList(resources);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debugLogger.log(
|
||||||
|
`Unloading of resources for scene ${unloadedSceneName} finished.`
|
||||||
|
);
|
||||||
|
|
||||||
|
const sceneState = this._sceneLoadingStates.get(unloadedSceneName);
|
||||||
|
if (sceneState) {
|
||||||
|
sceneState.status = 'not-loaded';
|
||||||
|
}
|
||||||
|
// TODO: mark the scene as unloaded so it's not automatically loaded again eagerly.
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Put a given scene at the end of the queue.
|
* Put a given scene at the end of the queue.
|
||||||
*
|
*
|
||||||
@@ -470,16 +556,41 @@ namespace gdjs {
|
|||||||
* this scene will be the next to be loaded.
|
* this scene will be the next to be loaded.
|
||||||
*/
|
*/
|
||||||
private _prioritizeScene(sceneName: string): SceneLoadingTask | null {
|
private _prioritizeScene(sceneName: string): SceneLoadingTask | null {
|
||||||
|
const sceneState = this._sceneLoadingStates.get(sceneName);
|
||||||
|
if (!sceneState) return null;
|
||||||
|
if (sceneState.status === 'loaded' || sceneState.status === 'ready') {
|
||||||
|
debugLogger.log(
|
||||||
|
`Scene ${sceneName} is already loaded. Skipping prioritization.`
|
||||||
|
);
|
||||||
|
|
||||||
|
// The scene is already loaded, nothing to do.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The scene is not loaded: either prioritize it or add it to the loading queue.
|
||||||
const taskIndex = this._sceneToLoadQueue.findIndex(
|
const taskIndex = this._sceneToLoadQueue.findIndex(
|
||||||
(task) => task.sceneName === sceneName
|
(task) => task.sceneName === sceneName
|
||||||
);
|
);
|
||||||
if (taskIndex < 0) {
|
let task: SceneLoadingTask;
|
||||||
// The scene is already loaded.
|
if (taskIndex !== -1) {
|
||||||
return null;
|
// There is already a task for this scene in the queue.
|
||||||
|
// Move it so that it's loaded first.
|
||||||
|
task = this._sceneToLoadQueue[taskIndex];
|
||||||
|
this._sceneToLoadQueue.splice(taskIndex, 1);
|
||||||
|
this._sceneToLoadQueue.push(task);
|
||||||
|
} else {
|
||||||
|
// There is no task for this scene in the queue.
|
||||||
|
// It might be because the scene was unloaded or never loaded.
|
||||||
|
// In this case, we need to add a new task to the queue.
|
||||||
|
task = new SceneLoadingTask(sceneName);
|
||||||
|
this._sceneToLoadQueue.push(task);
|
||||||
}
|
}
|
||||||
const task = this._sceneToLoadQueue[taskIndex];
|
|
||||||
this._sceneToLoadQueue.splice(taskIndex, 1);
|
// Re-start the loading process in the background. While at the beginning of the game
|
||||||
this._sceneToLoadQueue.push(task);
|
// it's not needed because already launched, a scene might be unloaded. This means
|
||||||
|
// that we then need to relaunch the loading process.
|
||||||
|
this.loadAllSceneInBackground();
|
||||||
|
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,7 +622,10 @@ namespace gdjs {
|
|||||||
* (but maybe not parsed).
|
* (but maybe not parsed).
|
||||||
*/
|
*/
|
||||||
areSceneAssetsLoaded(sceneName: string): boolean {
|
areSceneAssetsLoaded(sceneName: string): boolean {
|
||||||
return !this._sceneNamesToLoad.has(sceneName);
|
const sceneState = this._sceneLoadingStates.get(sceneName);
|
||||||
|
if (!sceneState) return false;
|
||||||
|
|
||||||
|
return sceneState.status === 'loaded' || sceneState.status === 'ready';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -519,15 +633,10 @@ namespace gdjs {
|
|||||||
* parsed.
|
* parsed.
|
||||||
*/
|
*/
|
||||||
areSceneAssetsReady(sceneName: string): boolean {
|
areSceneAssetsReady(sceneName: string): boolean {
|
||||||
return !this._sceneNamesToMakeReady.has(sceneName);
|
const sceneState = this._sceneLoadingStates.get(sceneName);
|
||||||
}
|
if (!sceneState) return false;
|
||||||
|
|
||||||
private _setSceneAssetsLoaded(sceneName: string): void {
|
return sceneState.status === 'ready';
|
||||||
this._sceneNamesToLoad.delete(sceneName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _setSceneAssetsReady(sceneName: string): void {
|
|
||||||
this._sceneNamesToMakeReady.delete(sceneName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getResource(resourceName: string): ResourceData | null {
|
getResource(resourceName: string): ResourceData | null {
|
||||||
@@ -636,6 +745,70 @@ namespace gdjs {
|
|||||||
getSpineAtlasManager(): gdjs.SpineAtlasManager | null {
|
getSpineAtlasManager(): gdjs.SpineAtlasManager | null {
|
||||||
return this._spineAtlasManager;
|
return this._spineAtlasManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
injectMockResourceManagerForTesting(
|
||||||
|
resourceKind: ResourceKind,
|
||||||
|
resourceManager: ResourceManager
|
||||||
|
) {
|
||||||
|
this._resourceManagersMap.set(resourceKind, resourceManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the map of resources that are only used in the scene that is being unloaded,
|
||||||
|
* and that are not used in any other loaded scene (or the scene that is coming next).
|
||||||
|
*/
|
||||||
|
private _getResourcesByKindOnlyUsedInUnloadedScene({
|
||||||
|
unloadedSceneName,
|
||||||
|
newSceneName,
|
||||||
|
}: {
|
||||||
|
unloadedSceneName: string;
|
||||||
|
newSceneName: string | null;
|
||||||
|
}): Map<ResourceKind, ResourceData[]> {
|
||||||
|
const unloadedSceneState =
|
||||||
|
this._sceneLoadingStates.get(unloadedSceneName);
|
||||||
|
if (!unloadedSceneState) {
|
||||||
|
return new Map<ResourceKind, ResourceData[]>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the set of all resources to unload. These are the resources
|
||||||
|
// used in the scene that is being unloaded minus all the resources used
|
||||||
|
// by the other scenes that are loaded (and the possible scene that is coming next).
|
||||||
|
const resourceNamesToUnload = new Set<string>(
|
||||||
|
unloadedSceneState.resourceNames
|
||||||
|
);
|
||||||
|
for (const [
|
||||||
|
sceneName,
|
||||||
|
sceneState,
|
||||||
|
] of this._sceneLoadingStates.entries()) {
|
||||||
|
if (sceneName === unloadedSceneName) continue;
|
||||||
|
|
||||||
|
if (
|
||||||
|
sceneName === newSceneName ||
|
||||||
|
sceneState.status === 'loaded' ||
|
||||||
|
sceneState.status === 'ready'
|
||||||
|
) {
|
||||||
|
sceneState.resourceNames.forEach((resourceName) => {
|
||||||
|
resourceNamesToUnload.delete(resourceName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = new Map<ResourceKind, ResourceData[]>();
|
||||||
|
resourceNamesToUnload.forEach((resourceName) => {
|
||||||
|
const resourceData = this._resources.get(resourceName);
|
||||||
|
if (!resourceData) return;
|
||||||
|
|
||||||
|
const kind = resourceData.kind;
|
||||||
|
const resources = result.get(kind);
|
||||||
|
if (resources) {
|
||||||
|
resources.push(resourceData);
|
||||||
|
} else {
|
||||||
|
result.set(kind, [resourceData]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type PromiseError<T> = { item: T; error: Error };
|
type PromiseError<T> = { item: T; error: Error };
|
||||||
|
@@ -35,5 +35,15 @@ namespace gdjs {
|
|||||||
* Using the manager after calling this method is undefined behavior.
|
* Using the manager after calling this method is undefined behavior.
|
||||||
*/
|
*/
|
||||||
dispose(): void;
|
dispose(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should clear all specified resources data and anything stored by this manager
|
||||||
|
* for these resources.
|
||||||
|
*
|
||||||
|
* Usually called when scene resoures are unloaded.
|
||||||
|
*
|
||||||
|
* @param resourcesList The list of specific resources that need to be clear
|
||||||
|
*/
|
||||||
|
unloadResourcesList(resourcesList: ResourceData[]): void;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -811,6 +811,8 @@ namespace gdjs {
|
|||||||
this._objectsCtor = new Hashtable();
|
this._objectsCtor = new Hashtable();
|
||||||
this._allInstancesList = [];
|
this._allInstancesList = [];
|
||||||
this._instancesRemoved = [];
|
this._instancesRemoved = [];
|
||||||
|
this._layersCameraCoordinates = {};
|
||||||
|
this._initialBehaviorSharedData = new Hashtable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -116,6 +116,9 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRuntimeLayer(): gdjs.RuntimeLayer {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
getRenderer(): gdjs.LayerRenderer {
|
getRenderer(): gdjs.LayerRenderer {
|
||||||
return this._renderer;
|
return this._renderer;
|
||||||
}
|
}
|
||||||
|
@@ -222,7 +222,9 @@ namespace gdjs {
|
|||||||
kind: 'fatal',
|
kind: 'fatal',
|
||||||
message:
|
message:
|
||||||
'Unexpected error happened while hot-reloading: ' +
|
'Unexpected error happened while hot-reloading: ' +
|
||||||
error.message,
|
error.message +
|
||||||
|
'\n' +
|
||||||
|
error.stack,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -472,13 +474,24 @@ namespace gdjs {
|
|||||||
newExternalLayoutData.associatedLayout
|
newExternalLayoutData.associatedLayout
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const oldObjectDataList =
|
||||||
|
HotReloader.resolveCustomObjectConfigurations(
|
||||||
|
oldProjectData,
|
||||||
|
oldLayoutData ? oldLayoutData.objects : []
|
||||||
|
);
|
||||||
|
const newObjectDataList =
|
||||||
|
HotReloader.resolveCustomObjectConfigurations(
|
||||||
|
newProjectData,
|
||||||
|
newLayoutData ? newLayoutData.objects : []
|
||||||
|
);
|
||||||
|
|
||||||
sceneStack._stack.forEach((runtimeScene) => {
|
sceneStack._stack.forEach((runtimeScene) => {
|
||||||
this._hotReloadRuntimeSceneInstances(
|
this._hotReloadRuntimeSceneInstances(
|
||||||
oldProjectData,
|
oldProjectData,
|
||||||
newProjectData,
|
newProjectData,
|
||||||
changedRuntimeBehaviors,
|
changedRuntimeBehaviors,
|
||||||
oldLayoutData ? oldLayoutData.objects : [],
|
oldObjectDataList,
|
||||||
newLayoutData ? newLayoutData.objects : [],
|
newObjectDataList,
|
||||||
oldExternalLayoutData.instances,
|
oldExternalLayoutData.instances,
|
||||||
newExternalLayoutData.instances,
|
newExternalLayoutData.instances,
|
||||||
runtimeScene
|
runtimeScene
|
||||||
@@ -725,7 +738,6 @@ namespace gdjs {
|
|||||||
// scene (see `_hotReloadRuntimeInstanceContainer` call from
|
// scene (see `_hotReloadRuntimeInstanceContainer` call from
|
||||||
// `_hotReloadRuntimeSceneInstances`).
|
// `_hotReloadRuntimeSceneInstances`).
|
||||||
objects: mergedChildObjectDataList,
|
objects: mergedChildObjectDataList,
|
||||||
childrenContent: mergedChildObjectDataList,
|
|
||||||
};
|
};
|
||||||
return mergedObjectConfiguration;
|
return mergedObjectConfiguration;
|
||||||
});
|
});
|
||||||
|
@@ -380,11 +380,8 @@ namespace gdjs {
|
|||||||
.isMouseInsideCanvas();
|
.isMouseInsideCanvas();
|
||||||
};
|
};
|
||||||
|
|
||||||
const _cursorIsOnObject = function (
|
const _cursorIsOnObject = function (obj: gdjs.RuntimeObject) {
|
||||||
obj: gdjs.RuntimeObject,
|
return obj.cursorOnObject();
|
||||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
|
||||||
) {
|
|
||||||
return obj.cursorOnObject(instanceContainer);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const cursorOnObject = function (
|
export const cursorOnObject = function (
|
||||||
@@ -397,7 +394,7 @@ namespace gdjs {
|
|||||||
_cursorIsOnObject,
|
_cursorIsOnObject,
|
||||||
objectsLists,
|
objectsLists,
|
||||||
inverted,
|
inverted,
|
||||||
instanceContainer
|
null
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -362,8 +362,7 @@ namespace gdjs {
|
|||||||
if (objectsLists.items.hasOwnProperty(name)) {
|
if (objectsLists.items.hasOwnProperty(name)) {
|
||||||
const allObjects = objectsContext.getObjects(name);
|
const allObjects = objectsContext.getObjects(name);
|
||||||
const objectsList = objectsLists.items[name];
|
const objectsList = objectsLists.items[name];
|
||||||
objectsList.length = 0;
|
gdjs.copyArray(allObjects, objectsList);
|
||||||
objectsList.push.apply(objectsList, allObjects);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@@ -205,6 +205,28 @@ namespace gdjs {
|
|||||||
this._loadedFontFamily.clear();
|
this._loadedFontFamily.clear();
|
||||||
this._loadedFontFamilySet.clear();
|
this._loadedFontFamilySet.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unload the specified list of resources:
|
||||||
|
* this clears the caches of loaded font families.
|
||||||
|
*
|
||||||
|
* Usually called when scene resoures are unloaded.
|
||||||
|
*
|
||||||
|
* @param resourcesList The list of specific resources
|
||||||
|
*/
|
||||||
|
unloadResourcesList(resourcesList: ResourceData[]): void {
|
||||||
|
resourcesList.forEach((resourceData) => {
|
||||||
|
const resource = this._loadedFontFamily.get(resourceData);
|
||||||
|
if (resource) {
|
||||||
|
this._loadedFontFamily.delete(resourceData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fontName = this._getFontFamilyFromFilename(resourceData);
|
||||||
|
if (fontName) {
|
||||||
|
this._loadedFontFamilySet.delete(fontName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Register the class to let the engine use it.
|
//Register the class to let the engine use it.
|
||||||
|
@@ -397,60 +397,68 @@ namespace gdjs {
|
|||||||
document.addEventListener(
|
document.addEventListener(
|
||||||
'pause',
|
'pause',
|
||||||
function () {
|
function () {
|
||||||
const soundList = that._freeSounds.concat(that._freeMusics);
|
that.pauseAllActiveSounds();
|
||||||
for (let key in that._sounds) {
|
|
||||||
if (that._sounds.hasOwnProperty(key)) {
|
|
||||||
soundList.push(that._sounds[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let key in that._musics) {
|
|
||||||
if (that._musics.hasOwnProperty(key)) {
|
|
||||||
soundList.push(that._musics[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let i = 0; i < soundList.length; i++) {
|
|
||||||
const sound = soundList[i];
|
|
||||||
if (!sound.paused() && !sound.stopped()) {
|
|
||||||
sound.pause();
|
|
||||||
that._pausedSounds.push(sound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
that._paused = true;
|
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
document.addEventListener(
|
document.addEventListener(
|
||||||
'resume',
|
'resume',
|
||||||
function () {
|
function () {
|
||||||
try {
|
that.resumeAllActiveSounds();
|
||||||
for (let i = 0; i < that._pausedSounds.length; i++) {
|
|
||||||
const sound = that._pausedSounds[i];
|
|
||||||
if (!sound.stopped()) {
|
|
||||||
sound.play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (
|
|
||||||
error.message &&
|
|
||||||
typeof error.message === 'string' &&
|
|
||||||
error.message.startsWith('Maximum call stack size exceeded')
|
|
||||||
) {
|
|
||||||
console.warn(
|
|
||||||
'An error occurred when resuming paused sounds while the game was in background:',
|
|
||||||
error
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
that._pausedSounds.length = 0;
|
|
||||||
that._paused = false;
|
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pauseAllActiveSounds(): void {
|
||||||
|
const soundList = this._freeSounds.concat(this._freeMusics);
|
||||||
|
for (let key in this._sounds) {
|
||||||
|
if (this._sounds.hasOwnProperty(key)) {
|
||||||
|
soundList.push(this._sounds[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let key in this._musics) {
|
||||||
|
if (this._musics.hasOwnProperty(key)) {
|
||||||
|
soundList.push(this._musics[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = 0; i < soundList.length; i++) {
|
||||||
|
const sound = soundList[i];
|
||||||
|
if (!sound.paused() && !sound.stopped()) {
|
||||||
|
sound.pause();
|
||||||
|
this._pausedSounds.push(sound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._paused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
resumeAllActiveSounds(): void {
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < this._pausedSounds.length; i++) {
|
||||||
|
const sound = this._pausedSounds[i];
|
||||||
|
if (!sound.stopped()) {
|
||||||
|
sound.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (
|
||||||
|
error.message &&
|
||||||
|
typeof error.message === 'string' &&
|
||||||
|
error.message.startsWith('Maximum call stack size exceeded')
|
||||||
|
) {
|
||||||
|
console.warn(
|
||||||
|
'An error occurred when resuming paused sounds while the game was in background:',
|
||||||
|
error
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._pausedSounds.length = 0;
|
||||||
|
this._paused = false;
|
||||||
|
}
|
||||||
|
|
||||||
getResourceKinds(): ResourceKind[] {
|
getResourceKinds(): ResourceKind[] {
|
||||||
return resourceKinds;
|
return resourceKinds;
|
||||||
}
|
}
|
||||||
@@ -931,6 +939,28 @@ namespace gdjs {
|
|||||||
dispose(): void {
|
dispose(): void {
|
||||||
this.unloadAll();
|
this.unloadAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unload the specified list of resources:
|
||||||
|
* this unloads all audio from the specified resources from memory.
|
||||||
|
*
|
||||||
|
* Usually called when scene resoures are unloaded.
|
||||||
|
*
|
||||||
|
* @param resourcesList The list of specific resources
|
||||||
|
*/
|
||||||
|
unloadResourcesList(resourcesList: ResourceData[]): void {
|
||||||
|
resourcesList.forEach((resourceData) => {
|
||||||
|
const musicRes = this._loadedMusics.get(resourceData);
|
||||||
|
if (musicRes) {
|
||||||
|
this.unloadAudio(resourceData.name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const soundRes = this._loadedSounds.get(resourceData);
|
||||||
|
if (soundRes) {
|
||||||
|
this.unloadAudio(resourceData.name, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the class to let the engine use it.
|
// Register the class to let the engine use it.
|
||||||
|
@@ -208,5 +208,26 @@ namespace gdjs {
|
|||||||
this._loadedJsons.clear();
|
this._loadedJsons.clear();
|
||||||
this._callbacks.clear();
|
this._callbacks.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unload the specified list of resources:
|
||||||
|
* this clears the JSONs loaded in this manager.
|
||||||
|
*
|
||||||
|
* Usually called when scene resoures are unloaded.
|
||||||
|
* @param resourcesList The list of specific resources
|
||||||
|
*/
|
||||||
|
unloadResourcesList(resourcesList: ResourceData[]): void {
|
||||||
|
resourcesList.forEach((resourceData) => {
|
||||||
|
const loadedJson = this._loadedJsons.get(resourceData);
|
||||||
|
if (loadedJson) {
|
||||||
|
this._loadedJsons.delete(resourceData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const callback = this._callbacks.get(resourceData);
|
||||||
|
if (callback) {
|
||||||
|
this._callbacks.delete(resourceData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -66,6 +66,7 @@ namespace gdjs {
|
|||||||
*/
|
*/
|
||||||
export class Logger {
|
export class Logger {
|
||||||
private readonly group: string;
|
private readonly group: string;
|
||||||
|
private enabled: boolean = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new logger with the given group name.
|
* Create a new logger with the given group name.
|
||||||
@@ -76,21 +77,30 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log(...messages: any[]): void {
|
log(...messages: any[]): void {
|
||||||
|
if (!this.enabled) return;
|
||||||
loggerOutput.log(this.group, objectsToString(messages), 'info');
|
loggerOutput.log(this.group, objectsToString(messages), 'info');
|
||||||
}
|
}
|
||||||
|
|
||||||
info(...messages: any[]): void {
|
info(...messages: any[]): void {
|
||||||
|
if (!this.enabled) return;
|
||||||
loggerOutput.log(this.group, objectsToString(messages), 'info');
|
loggerOutput.log(this.group, objectsToString(messages), 'info');
|
||||||
}
|
}
|
||||||
|
|
||||||
warn(...messages: any[]): void {
|
warn(...messages: any[]): void {
|
||||||
|
if (!this.enabled) return;
|
||||||
loggerOutput.log(this.group, objectsToString(messages), 'warning');
|
loggerOutput.log(this.group, objectsToString(messages), 'warning');
|
||||||
}
|
}
|
||||||
|
|
||||||
error(...messages: any[]): void {
|
error(...messages: any[]): void {
|
||||||
|
if (!this.enabled) return;
|
||||||
loggerOutput.log(this.group, objectsToString(messages), 'error');
|
loggerOutput.log(this.group, objectsToString(messages), 'error');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enable(enabled: boolean): gdjs.Logger {
|
||||||
|
this.enabled = enabled;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Give access to the console output used by default by the logger.
|
* Give access to the console output used by default by the logger.
|
||||||
* This can be useful to restore the default log method if you overrode it
|
* This can be useful to restore the default log method if you overrode it
|
||||||
|
@@ -50,12 +50,7 @@ namespace gdjs {
|
|||||||
) {
|
) {
|
||||||
this._object = object;
|
this._object = object;
|
||||||
this._isContainerDirty = true;
|
this._isContainerDirty = true;
|
||||||
const layer = parent.getLayer('');
|
this._pixiContainer.removeChildren();
|
||||||
if (layer) {
|
|
||||||
layer
|
|
||||||
.getRenderer()
|
|
||||||
.addRendererObject(this._pixiContainer, object.getZOrder());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getRendererObject() {
|
getRendererObject() {
|
||||||
|
@@ -307,6 +307,34 @@ namespace gdjs {
|
|||||||
this._pixiBitmapFontsToUninstall.length = 0;
|
this._pixiBitmapFontsToUninstall.length = 0;
|
||||||
this._loadedFontsData.clear();
|
this._loadedFontsData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unload the specified list of resources:
|
||||||
|
* this uninstalls fonts from memory and clear cache of loaded fonts.
|
||||||
|
*
|
||||||
|
* Usually called when scene resoures are unloaded.
|
||||||
|
*
|
||||||
|
* @param resourcesList The list of specific resources
|
||||||
|
*/
|
||||||
|
|
||||||
|
unloadResourcesList(resourcesList: ResourceData[]): void {
|
||||||
|
resourcesList.forEach((resourceData) => {
|
||||||
|
const loadedFont = this._loadedFontsData.get(resourceData);
|
||||||
|
if (loadedFont) {
|
||||||
|
this._loadedFontsData.delete(resourceData);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const bitmapFontInstallKey in this._pixiBitmapFontsInUse) {
|
||||||
|
if (bitmapFontInstallKey.endsWith(resourceData.file))
|
||||||
|
PIXI.BitmapFont.uninstall(bitmapFontInstallKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const bitmapFontInstallKey of this._pixiBitmapFontsToUninstall) {
|
||||||
|
if (bitmapFontInstallKey.endsWith(resourceData.file))
|
||||||
|
PIXI.BitmapFont.uninstall(bitmapFontInstallKey);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the class to let the engine use it.
|
// Register the class to let the engine use it.
|
||||||
|
@@ -17,6 +17,7 @@ namespace gdjs {
|
|||||||
getName: () => string;
|
getName: () => string;
|
||||||
getRendererObject: () => RendererObjectInterface | null | undefined;
|
getRendererObject: () => RendererObjectInterface | null | undefined;
|
||||||
get3DRendererObject: () => THREE.Object3D | null | undefined;
|
get3DRendererObject: () => THREE.Object3D | null | undefined;
|
||||||
|
getRuntimeLayer?: () => gdjs.RuntimeLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -519,6 +519,37 @@ namespace gdjs {
|
|||||||
}
|
}
|
||||||
this._scaledTextures.clear();
|
this._scaledTextures.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unload the specified list of resources:
|
||||||
|
* this clears the cache of loaded textures associated to these resources.
|
||||||
|
*
|
||||||
|
* Usually called when scene resoures are unloaded.
|
||||||
|
*
|
||||||
|
* @param resourcesList The list of specific resources
|
||||||
|
*/
|
||||||
|
unloadResourcesList(resourcesList: ResourceData[]): void {
|
||||||
|
resourcesList.forEach((resourceData) => {
|
||||||
|
const resourceName = resourceData.name;
|
||||||
|
const resource = this._loadedTextures.get(resourceData);
|
||||||
|
if (resource) {
|
||||||
|
resource.destroy(true);
|
||||||
|
this._loadedTextures.delete(resourceData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const threeTexture = this._loadedThreeTextures.get(resourceName);
|
||||||
|
if (threeTexture) {
|
||||||
|
threeTexture.dispose();
|
||||||
|
this._loadedThreeTextures.remove(resourceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
const threeMaterials = this._loadedThreeMaterials.get(resourceName);
|
||||||
|
if (threeMaterials) {
|
||||||
|
threeMaterials.dispose();
|
||||||
|
this._loadedThreeMaterials.remove(resourceName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Register the class to let the engine use it.
|
//Register the class to let the engine use it.
|
||||||
|
@@ -97,6 +97,8 @@ namespace gdjs {
|
|||||||
!gdjs.evtTools.common.isMobile()),
|
!gdjs.evtTools.common.isMobile()),
|
||||||
preserveDrawingBuffer: true, // Keep to true to allow screenshots.
|
preserveDrawingBuffer: true, // Keep to true to allow screenshots.
|
||||||
});
|
});
|
||||||
|
this._threeRenderer.shadowMap.enabled = true;
|
||||||
|
this._threeRenderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
||||||
this._threeRenderer.useLegacyLights = true;
|
this._threeRenderer.useLegacyLights = true;
|
||||||
this._threeRenderer.autoClear = false;
|
this._threeRenderer.autoClear = false;
|
||||||
this._threeRenderer.setSize(
|
this._threeRenderer.setSize(
|
||||||
|
@@ -184,6 +184,9 @@ namespace gdjs {
|
|||||||
*/
|
*/
|
||||||
_embeddedResourcesMappings: Map<string, Record<string, string>>;
|
_embeddedResourcesMappings: Map<string, Record<string, string>>;
|
||||||
|
|
||||||
|
_sceneResourcesPreloading: 'at-startup' | 'never';
|
||||||
|
_sceneResourcesUnloading: 'at-scene-exit' | 'never';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional client to connect to a debugger server.
|
* Optional client to connect to a debugger server.
|
||||||
*/
|
*/
|
||||||
@@ -223,6 +226,11 @@ namespace gdjs {
|
|||||||
this._data = data;
|
this._data = data;
|
||||||
this._updateSceneAndExtensionsData();
|
this._updateSceneAndExtensionsData();
|
||||||
|
|
||||||
|
this._sceneResourcesPreloading =
|
||||||
|
this._data.properties.sceneResourcesPreloading || 'at-startup';
|
||||||
|
this._sceneResourcesUnloading =
|
||||||
|
this._data.properties.sceneResourcesUnloading || 'never';
|
||||||
|
|
||||||
this._resourcesLoader = new gdjs.ResourceLoader(
|
this._resourcesLoader = new gdjs.ResourceLoader(
|
||||||
this,
|
this,
|
||||||
data.resources.resources,
|
data.resources.resources,
|
||||||
@@ -245,6 +253,7 @@ namespace gdjs {
|
|||||||
this._antialiasingMode = this._data.properties.antialiasingMode;
|
this._antialiasingMode = this._data.properties.antialiasingMode;
|
||||||
this._isAntialisingEnabledOnMobile =
|
this._isAntialisingEnabledOnMobile =
|
||||||
this._data.properties.antialisingEnabledOnMobile;
|
this._data.properties.antialisingEnabledOnMobile;
|
||||||
|
|
||||||
this._renderer = new gdjs.RuntimeGameRenderer(
|
this._renderer = new gdjs.RuntimeGameRenderer(
|
||||||
this,
|
this,
|
||||||
this._options.forceFullscreen || false
|
this._options.forceFullscreen || false
|
||||||
@@ -363,6 +372,14 @@ namespace gdjs {
|
|||||||
return this._variablesByExtensionName.get(extensionName) || null;
|
return this._variablesByExtensionName.get(extensionName) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the gdjs.ResourceLoader of the RuntimeGame.
|
||||||
|
* @return The resource loader.
|
||||||
|
*/
|
||||||
|
getResourceLoader(): gdjs.ResourceLoader {
|
||||||
|
return this._resourcesLoader;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the gdjs.SoundManager of the RuntimeGame.
|
* Get the gdjs.SoundManager of the RuntimeGame.
|
||||||
* @return The sound manager.
|
* @return The sound manager.
|
||||||
@@ -764,6 +781,22 @@ namespace gdjs {
|
|||||||
return this._resourcesLoader.areSceneAssetsReady(sceneName);
|
return this._resourcesLoader.areSceneAssetsReady(sceneName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the scene resources preloading mode.
|
||||||
|
* It can be overriden by each scene.
|
||||||
|
*/
|
||||||
|
getSceneResourcesPreloading(): 'at-startup' | 'never' {
|
||||||
|
return this._sceneResourcesPreloading;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the scene resources unloading mode.
|
||||||
|
* It can be overriden by each scene.
|
||||||
|
*/
|
||||||
|
getSceneResourcesUnloading(): 'at-scene-exit' | 'never' {
|
||||||
|
return this._sceneResourcesUnloading;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load all assets needed to display the 1st scene, displaying progress in
|
* Load all assets needed to display the 1st scene, displaying progress in
|
||||||
* renderer.
|
* renderer.
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user