mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
9 Commits
d474c2a47e
...
fix-create
Author | SHA1 | Date | |
---|---|---|---|
![]() |
66b0cb6349 | ||
![]() |
e533637c1e | ||
![]() |
4546ad1a8a | ||
![]() |
873502eaf6 | ||
![]() |
733935ecd1 | ||
![]() |
336a40fe1c | ||
![]() |
5dee9da344 | ||
![]() |
6522ac74c3 | ||
![]() |
ad3fda1a3f |
@@ -299,6 +299,22 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
|
||||
AddIncludeFiles(instrInfos.GetIncludeFiles());
|
||||
maxConditionsListsSize =
|
||||
std::max(maxConditionsListsSize, condition.GetSubInstructions().size());
|
||||
|
||||
// Flag the ObjectsLists as modified.
|
||||
gd::ParameterMetadataTools::IterateOverParameters(
|
||||
condition.GetParameters(), instrInfos.parameters,
|
||||
[this, &context,
|
||||
&conditionCode](const gd::ParameterMetadata ¶meterMetadata,
|
||||
const gd::Expression ¶meterValue,
|
||||
const gd::String &lastObjectName) {
|
||||
if (parameterMetadata.GetType() == "objectList" ||
|
||||
parameterMetadata.GetType() == "objectListOrEmptyIfJustDeclared" ||
|
||||
parameterMetadata.GetType() == "objectListOrEmptyWithoutPicking") {
|
||||
conditionCode +=
|
||||
GetObjectMapName(parameterValue.GetPlainString(), context) +
|
||||
".isPicked = true;\n";
|
||||
}
|
||||
});
|
||||
|
||||
if (instrInfos.HasCustomCodeGenerator()) {
|
||||
context.EnterCustomCondition();
|
||||
|
@@ -585,6 +585,12 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
return "fakeObjectListOf_" + objectName;
|
||||
}
|
||||
|
||||
// TODO Documentation
|
||||
virtual gd::String GetObjectMapName(const gd::String &objectName,
|
||||
gd::EventsCodeGenerationContext &context) {
|
||||
return "fakeObjectListOf_" + objectName;
|
||||
}
|
||||
|
||||
virtual gd::String GeneratePropertyGetter(
|
||||
const gd::PropertiesContainer& propertiesContainer,
|
||||
const gd::NamedPropertyDescriptor& property,
|
||||
|
@@ -1375,7 +1375,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/actions/create24.png",
|
||||
"res/actions/create24.png")
|
||||
.AddCodeOnlyParameter("objectsContext", "")
|
||||
.AddParameter("objectListOrEmptyIfJustDeclared", _("Object to create"))
|
||||
.AddParameter("objectList", _("Object to create"))
|
||||
.AddParameter("expression", _("X position"))
|
||||
.AddParameter("expression", _("Y position"))
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
@@ -1393,7 +1393,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/actions/create24.png",
|
||||
"res/actions/create24.png")
|
||||
.AddCodeOnlyParameter("objectsContext", "")
|
||||
.AddParameter("objectListOrEmptyIfJustDeclared",
|
||||
.AddParameter("objectList",
|
||||
_("Group of potential objects"))
|
||||
.SetParameterLongDescription(
|
||||
_("Group containing objects that can be created by the action."))
|
||||
|
@@ -1,9 +1,9 @@
|
||||
namespace gdjs {
|
||||
export namespace physics2 {
|
||||
export const objectsCollide = function (
|
||||
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists1: ObjectsLists,
|
||||
behaviorName: string,
|
||||
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists2: ObjectsLists,
|
||||
inverted: boolean
|
||||
) {
|
||||
return gdjs.evtTools.object.twoListsTest(
|
||||
@@ -16,9 +16,9 @@ namespace gdjs {
|
||||
};
|
||||
|
||||
export const haveObjectsStartedColliding = function (
|
||||
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists1: ObjectsLists,
|
||||
behaviorName: string,
|
||||
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists2: ObjectsLists,
|
||||
inverted: boolean
|
||||
) {
|
||||
return gdjs.evtTools.object.twoListsTest(
|
||||
@@ -31,9 +31,9 @@ namespace gdjs {
|
||||
};
|
||||
|
||||
export const haveObjectsStoppedColliding = function (
|
||||
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists1: ObjectsLists,
|
||||
behaviorName: string,
|
||||
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists2: ObjectsLists,
|
||||
inverted: boolean
|
||||
) {
|
||||
return gdjs.evtTools.object.twoListsTest(
|
||||
@@ -45,7 +45,11 @@ namespace gdjs {
|
||||
);
|
||||
};
|
||||
|
||||
export const setTimeScale = function (objectsLists, behavior, timeScale) {
|
||||
export const setTimeScale = function (
|
||||
objectsLists: ObjectsLists,
|
||||
behavior: gdjs.Physics2RuntimeBehavior,
|
||||
timeScale: float
|
||||
) {
|
||||
const lists = gdjs.staticArray(gdjs.physics2.setTimeScale);
|
||||
objectsLists.values(lists);
|
||||
for (let i = 0, len = lists.length; i < len; i++) {
|
||||
|
@@ -2,9 +2,9 @@ namespace gdjs {
|
||||
export namespace evtTools {
|
||||
export namespace platform {
|
||||
export const isOnPlatform = function (
|
||||
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists1: ObjectsLists,
|
||||
behaviorName: string,
|
||||
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists2: ObjectsLists,
|
||||
inverted: boolean
|
||||
) {
|
||||
return gdjs.evtTools.object.twoListsTest(
|
||||
|
@@ -568,22 +568,21 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
// to create the new object as the object names used in the function
|
||||
// are not the same as the objects available in the scene.
|
||||
" createObject: function(objectName) {\n"
|
||||
" const objectsList = "
|
||||
" const objectsLists = "
|
||||
"eventsFunctionContext._objectsMap[objectName];\n" +
|
||||
// TODO: we could speed this up by storing a map of object names, but
|
||||
// the cost of creating/storing it for each events function might not
|
||||
// be worth it.
|
||||
" if (objectsList) {\n" +
|
||||
" if (objectsLists) {\n" +
|
||||
" const object = parentEventsFunctionContext ?\n" +
|
||||
" "
|
||||
"parentEventsFunctionContext.createObject(objectsList.firstKey()) "
|
||||
"parentEventsFunctionContext.createObject(objectsLists.firstKey()) "
|
||||
":\n" +
|
||||
" runtimeScene.createObject(objectsList.firstKey());\n" +
|
||||
" runtimeScene.createObject(objectsLists.firstKey());\n" +
|
||||
// Add the new instance to object lists
|
||||
" if (object) {\n" +
|
||||
" objectsList.get(objectsList.firstKey()).push(object);\n" +
|
||||
" "
|
||||
"eventsFunctionContext._objectArraysMap[objectName].push(object);\n" +
|
||||
" if (object) {\n"
|
||||
" gdjs.evtTools.objectsLists.addObject(objectsLists, "
|
||||
"objectsLists.firstKey(), object);\n" +
|
||||
" }\n" + " return object;" + " }\n" +
|
||||
// Unknown object, don't create anything:
|
||||
" return null;\n" +
|
||||
@@ -767,6 +766,9 @@ gd::String EventsCodeGenerator::GenerateObjectCondition(
|
||||
}
|
||||
if (conditionInverted) predicate = GenerateNegatedPredicate(predicate);
|
||||
|
||||
// Flag the picking list as modified.
|
||||
conditionCode += GetObjectMapName(objectName, context) + ".isPicked = true;\n";
|
||||
|
||||
// Generate whole condition code
|
||||
conditionCode +=
|
||||
"for (var i = 0, k = 0, l = " + GetObjectListName(objectName, context) +
|
||||
@@ -823,6 +825,9 @@ gd::String EventsCodeGenerator::GenerateBehaviorCondition(
|
||||
<< "\" requested for object \'" << objectName
|
||||
<< "\" (condition: " << instrInfos.GetFullName() << ")." << endl;
|
||||
} else {
|
||||
// Flag the picking list as modified.
|
||||
conditionCode += GetObjectMapName(objectName, context) + ".isPicked = true;\n";
|
||||
|
||||
conditionCode +=
|
||||
"for (var i = 0, k = 0, l = " + GetObjectListName(objectName, context) +
|
||||
".length;i<l;++i) {\n";
|
||||
@@ -1021,7 +1026,8 @@ gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
|
||||
gd::String copiedListName = "asyncObjectsList.getObjects(" +
|
||||
ConvertToStringExplicit(object) + ")";
|
||||
return "gdjs.copyArray(" + copiedListName + ", " + objectListName +
|
||||
");\n";
|
||||
");\n" +
|
||||
GenerateObject(object, "objectList", context) + ".isPicked = false;\n";
|
||||
}
|
||||
|
||||
//*Optimization*: Avoid expensive copy of the object list if we're using
|
||||
@@ -1032,7 +1038,8 @@ gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
|
||||
gd::String copiedListName =
|
||||
GetObjectListName(object, *context.GetParentContext());
|
||||
return "gdjs.copyArray(" + copiedListName + ", " + objectListName +
|
||||
");\n";
|
||||
");\n" +
|
||||
GenerateObject(object, "objectList", context) + ".isPicked = false;\n";
|
||||
};
|
||||
|
||||
gd::String declarationsCode;
|
||||
@@ -1041,7 +1048,8 @@ gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
|
||||
if (!context.ObjectAlreadyDeclaredByParents(object)) {
|
||||
objectListDeclaration += "gdjs.copyArray(" +
|
||||
GenerateAllInstancesGetterCode(object, context) +
|
||||
", " + GetObjectListName(object, context) + ");";
|
||||
", " + GetObjectListName(object, context) + ");\n" +
|
||||
GenerateObject(object, "objectList", context) + ".isPicked = false;\n";
|
||||
} else
|
||||
objectListDeclaration = declareObjectListFromParent(object, context);
|
||||
|
||||
@@ -1051,7 +1059,8 @@ gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
|
||||
gd::String objectListDeclaration = "";
|
||||
if (!context.ObjectAlreadyDeclaredByParents(object)) {
|
||||
objectListDeclaration =
|
||||
GetObjectListName(object, context) + ".length = 0;\n";
|
||||
GetObjectListName(object, context) + ".length = 0;\n" +
|
||||
GenerateObject(object, "objectList", context) + ".isPicked = false;\n";
|
||||
} else
|
||||
objectListDeclaration = declareObjectListFromParent(object, context);
|
||||
|
||||
@@ -1061,10 +1070,12 @@ gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
|
||||
gd::String objectListDeclaration = "";
|
||||
if (!context.ObjectAlreadyDeclaredByParents(object)) {
|
||||
objectListDeclaration =
|
||||
GetObjectListName(object, context) + ".length = 0;\n";
|
||||
GetObjectListName(object, context) + ".length = 0;\n" +
|
||||
GenerateObject(object, "objectList", context) + ".isPicked = false;\n";
|
||||
} else
|
||||
objectListDeclaration =
|
||||
GetObjectListName(object, context) + ".length = 0;\n";
|
||||
GetObjectListName(object, context) + ".length = 0;\n" +
|
||||
GenerateObject(object, "objectList", context) + ".isPicked = false;\n";
|
||||
|
||||
declarationsCode += objectListDeclaration + "\n";
|
||||
}
|
||||
@@ -1183,6 +1194,28 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
return argOutput;
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GetObjectMapName(
|
||||
const gd::String& objectName,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
|
||||
// TODO Why can't it just use objectName directly?
|
||||
std::vector<gd::String> realObjects =
|
||||
GetObjectsContainersList().ExpandObjectName(objectName,
|
||||
context.GetCurrentObject());
|
||||
|
||||
// The map name must be unique for each set of objects lists.
|
||||
// We generate it from the objects lists names.
|
||||
gd::String objectsMapName = GetCodeNamespaceAccessor() + "mapOf";
|
||||
|
||||
// Map each declared object to its list.
|
||||
for (auto &objectName : realObjects) {
|
||||
objectsMapName += ManObjListName(GetObjectListName(objectName, context));
|
||||
}
|
||||
// TODO Handle objectListOrEmptyWithoutPicking?
|
||||
|
||||
return objectsMapName;
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateObject(
|
||||
const gd::String& objectName,
|
||||
const gd::String& type,
|
||||
|
@@ -335,6 +335,9 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
const gd::String& type,
|
||||
gd::EventsCodeGenerationContext& context) override;
|
||||
|
||||
virtual gd::String GetObjectMapName(const gd::String &objectName,
|
||||
gd::EventsCodeGenerationContext &context) override;
|
||||
|
||||
virtual gd::String GenerateNegatedPredicate(const gd::String& predicate) const override {
|
||||
return "!(" + predicate + ")";
|
||||
};
|
||||
|
@@ -614,6 +614,7 @@ void ExporterHelper::AddLibsInclude(bool pixiRenderers,
|
||||
// First, do not forget common includes (they must be included before events
|
||||
// generated code files).
|
||||
InsertUnique(includesFiles, "libs/jshashtable.js");
|
||||
InsertUnique(includesFiles, "ObjectsLists.js");
|
||||
InsertUnique(includesFiles, "logger.js");
|
||||
InsertUnique(includesFiles, "gd.js");
|
||||
InsertUnique(includesFiles, "libs/rbush.js");
|
||||
|
58
GDJS/Runtime/ObjectsLists.ts
Normal file
58
GDJS/Runtime/ObjectsLists.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* GDevelop JS Platform
|
||||
* Copyright 2013-2023 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
|
||||
* This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Picked objects lists.
|
||||
*/
|
||||
class ObjectsLists extends Hashtable<Array<gdjs.RuntimeObject>> {
|
||||
/** Is true as soon as an instruction has pick some or every instances */
|
||||
isPicked: boolean = false;
|
||||
}
|
||||
|
||||
namespace gdjs {
|
||||
export namespace evtTools {
|
||||
export namespace objectsLists {
|
||||
/**
|
||||
* Construct a ObjectsLists from a JS object.
|
||||
*
|
||||
* @param items The content of the Hashtable.
|
||||
* @returns The new picked objects lists.
|
||||
*/
|
||||
export const newFrom = (
|
||||
items: {
|
||||
[key: string]: Array<gdjs.RuntimeObject>;
|
||||
},
|
||||
isPicked: boolean
|
||||
): ObjectsLists => {
|
||||
const hashtable = new ObjectsLists();
|
||||
hashtable.items = items;
|
||||
hashtable.isPicked = isPicked;
|
||||
return hashtable;
|
||||
};
|
||||
|
||||
export const addObject = (
|
||||
objectsLists: ObjectsLists,
|
||||
objectName: string,
|
||||
object: gdjs.RuntimeObject
|
||||
) => {
|
||||
if (!objectsLists.isPicked) {
|
||||
// A picking starts from empty lists.
|
||||
clearObjectsLists(objectsLists);
|
||||
objectsLists.isPicked = true;
|
||||
}
|
||||
objectsLists.get(objectName).push(object);
|
||||
};
|
||||
|
||||
const clearObjectsLists = (objectsLists: ObjectsLists) => {
|
||||
for (const k in objectsLists.items) {
|
||||
if (objectsLists.items.hasOwnProperty(k)) {
|
||||
objectsLists.items[k].length = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -388,7 +388,7 @@ namespace gdjs {
|
||||
};
|
||||
|
||||
export const cursorOnObject = function (
|
||||
objectsLists: Hashtable<gdjs.RuntimeObject[]>,
|
||||
objectsLists: ObjectsLists,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
accurate: boolean,
|
||||
inverted: boolean
|
||||
|
@@ -496,14 +496,14 @@ namespace gdjs {
|
||||
const obj = objectsContext.createObject(objectName);
|
||||
const layer = objectsContext.getLayer(layerName);
|
||||
if (obj !== null) {
|
||||
//Do some extra setup
|
||||
// Do some extra setup
|
||||
obj.setPosition(x, y);
|
||||
obj.setLayer(layerName);
|
||||
obj.setZOrder(layer.getDefaultZOrder());
|
||||
|
||||
//Let the new object be picked by next actions/conditions.
|
||||
// Let the new object be picked by next actions/conditions.
|
||||
if (objectsLists.containsKey(objectName)) {
|
||||
objectsLists.get(objectName).push(obj);
|
||||
gdjs.evtTools.objectsLists.addObject(objectsLists, objectName, obj);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
|
3
GDJS/Runtime/types/global-types.d.ts
vendored
3
GDJS/Runtime/types/global-types.d.ts
vendored
@@ -13,9 +13,6 @@ declare type float = number;
|
||||
/** A point in cartesian space. */
|
||||
declare type FloatPoint = [number, number];
|
||||
|
||||
/** A Hastable with the picked objects lists. */
|
||||
declare type ObjectsLists = Hashtable<gdjs.RuntimeObject[]>;
|
||||
|
||||
/**
|
||||
* Represents the context of the events function (or the behavior method),
|
||||
* if any. If the JavaScript code is running in a scene, this will be undefined (so you can't use this in a scene).
|
||||
|
@@ -36,6 +36,7 @@ module.exports = function (config) {
|
||||
|
||||
//GDJS game engine files: (Order is important)
|
||||
'./newIDE/app/resources/GDJS/Runtime/libs/jshashtable.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/ObjectsLists.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/logger.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/gd.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/AsyncTasksManager.js',
|
||||
|
@@ -13,28 +13,37 @@ describe('gdjs.evtTools.object', function () {
|
||||
|
||||
expect(
|
||||
gdjs.evtTools.object.getPickedInstancesCount(
|
||||
Hashtable.newFrom({
|
||||
MyObjectA: [objectA1, objectA2],
|
||||
MyObjectB: [objectB1],
|
||||
})
|
||||
gdjs.evtTools.objectsLists.newFrom(
|
||||
{
|
||||
MyObjectA: [objectA1, objectA2],
|
||||
MyObjectB: [objectB1],
|
||||
},
|
||||
true
|
||||
)
|
||||
)
|
||||
).to.be(3);
|
||||
expect(
|
||||
gdjs.evtTools.object.getPickedInstancesCount(
|
||||
Hashtable.newFrom({
|
||||
MyObjectA: [],
|
||||
MyObjectB: [],
|
||||
})
|
||||
gdjs.evtTools.objectsLists.newFrom(
|
||||
{
|
||||
MyObjectA: [],
|
||||
MyObjectB: [],
|
||||
},
|
||||
true
|
||||
)
|
||||
)
|
||||
).to.be(0);
|
||||
|
||||
// Also test the deprecated name for this function:
|
||||
expect(
|
||||
gdjs.evtTools.object.pickedObjectsCount(
|
||||
Hashtable.newFrom({
|
||||
MyObjectA: [objectA1, objectA2],
|
||||
MyObjectB: [objectB1],
|
||||
})
|
||||
gdjs.evtTools.objectsLists.newFrom(
|
||||
{
|
||||
MyObjectA: [objectA1, objectA2],
|
||||
MyObjectB: [objectB1],
|
||||
},
|
||||
true
|
||||
)
|
||||
)
|
||||
).to.be(3);
|
||||
});
|
||||
@@ -52,43 +61,58 @@ describe('gdjs.evtTools.object', function () {
|
||||
expect(
|
||||
gdjs.evtTools.object.getSceneInstancesCount(
|
||||
runtimeScene,
|
||||
Hashtable.newFrom({
|
||||
MyObjectA: [objectA1],
|
||||
MyObjectB: [objectB1],
|
||||
})
|
||||
gdjs.evtTools.objectsLists.newFrom(
|
||||
{
|
||||
MyObjectA: [objectA1],
|
||||
MyObjectB: [objectB1],
|
||||
},
|
||||
true
|
||||
)
|
||||
)
|
||||
).to.be(2 + 1);
|
||||
expect(
|
||||
gdjs.evtTools.object.getSceneInstancesCount(
|
||||
runtimeScene,
|
||||
Hashtable.newFrom({
|
||||
MyObjectA: [objectA1],
|
||||
MyObjectB: [],
|
||||
})
|
||||
gdjs.evtTools.objectsLists.newFrom(
|
||||
{
|
||||
MyObjectA: [objectA1],
|
||||
MyObjectB: [],
|
||||
},
|
||||
true
|
||||
)
|
||||
)
|
||||
).to.be(2 + 1);
|
||||
expect(
|
||||
gdjs.evtTools.object.getSceneInstancesCount(
|
||||
runtimeScene,
|
||||
Hashtable.newFrom({
|
||||
MyObjectA: [objectA1],
|
||||
})
|
||||
gdjs.evtTools.objectsLists.newFrom(
|
||||
{
|
||||
MyObjectA: [objectA1],
|
||||
},
|
||||
true
|
||||
)
|
||||
)
|
||||
).to.be(2);
|
||||
expect(
|
||||
gdjs.evtTools.object.getSceneInstancesCount(
|
||||
runtimeScene,
|
||||
Hashtable.newFrom({
|
||||
MyObjectA: [],
|
||||
})
|
||||
gdjs.evtTools.objectsLists.newFrom(
|
||||
{
|
||||
MyObjectA: [],
|
||||
},
|
||||
false
|
||||
)
|
||||
)
|
||||
).to.be(2);
|
||||
expect(
|
||||
gdjs.evtTools.object.getSceneInstancesCount(
|
||||
runtimeScene,
|
||||
Hashtable.newFrom({
|
||||
MyObjectC: [],
|
||||
})
|
||||
gdjs.evtTools.objectsLists.newFrom(
|
||||
{
|
||||
MyObjectC: [],
|
||||
},
|
||||
false
|
||||
)
|
||||
)
|
||||
).to.be(0);
|
||||
});
|
||||
@@ -106,9 +130,12 @@ describe('gdjs.evtTools.object', function () {
|
||||
runtimeScene.createObject('MyObjectA');
|
||||
|
||||
// 1 of 2 instances are picked.
|
||||
const pickedObjectList = Hashtable.newFrom({
|
||||
MyObjectA: [objectA1],
|
||||
});
|
||||
const pickedObjectList = gdjs.evtTools.objectsLists.newFrom(
|
||||
{
|
||||
MyObjectA: [objectA1],
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
const newObjectA = gdjs.evtTools.object.createObjectOnScene(
|
||||
runtimeScene,
|
||||
@@ -134,9 +161,12 @@ describe('gdjs.evtTools.object', function () {
|
||||
runtimeScene.createObject('MyObjectA');
|
||||
|
||||
// 0 of 2 instances are picked.
|
||||
const pickedObjectList = Hashtable.newFrom({
|
||||
MyObjectA: [],
|
||||
});
|
||||
const pickedObjectList = gdjs.evtTools.objectsLists.newFrom(
|
||||
{
|
||||
MyObjectA: [],
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
const newObjectA = gdjs.evtTools.object.createObjectOnScene(
|
||||
runtimeScene,
|
||||
@@ -152,7 +182,7 @@ describe('gdjs.evtTools.object', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('can create an instance and keep all instances picked', function () {
|
||||
it('can create an instance and only pick this one when all instances were picked', function () {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
const runtimeScene = new gdjs.TestRuntimeScene(runtimeGame);
|
||||
|
||||
@@ -161,9 +191,12 @@ describe('gdjs.evtTools.object', function () {
|
||||
const objectA2 = runtimeScene.createObject('MyObjectA');
|
||||
|
||||
// All instances are picked.
|
||||
const pickedObjectList = Hashtable.newFrom({
|
||||
MyObjectA: [objectA1, objectA2],
|
||||
});
|
||||
const pickedObjectList = gdjs.evtTools.objectsLists.newFrom(
|
||||
{
|
||||
MyObjectA: [objectA1, objectA2],
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
const newObjectA = gdjs.evtTools.object.createObjectOnScene(
|
||||
runtimeScene,
|
||||
@@ -173,9 +206,9 @@ describe('gdjs.evtTools.object', function () {
|
||||
''
|
||||
);
|
||||
|
||||
// All instances are still picked.
|
||||
// Only the created instance is picked.
|
||||
expect(getInstancesIds(pickedObjectList.get('MyObjectA'))).to.eql(
|
||||
getInstancesIds([objectA1, objectA2, newObjectA])
|
||||
getInstancesIds([newObjectA])
|
||||
);
|
||||
});
|
||||
|
||||
@@ -191,10 +224,13 @@ describe('gdjs.evtTools.object', function () {
|
||||
runtimeScene.createObject('MyObjectB');
|
||||
|
||||
// 2 of 3 instances are picked.
|
||||
const pickedObjectList = Hashtable.newFrom({
|
||||
MyObjectA: [objectA1],
|
||||
MyObjectB: [objectB1],
|
||||
});
|
||||
const pickedObjectList = gdjs.evtTools.objectsLists.newFrom(
|
||||
{
|
||||
MyObjectA: [objectA1],
|
||||
MyObjectB: [objectB1],
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
const newObjectA = gdjs.evtTools.object.createObjectOnScene(
|
||||
runtimeScene,
|
||||
@@ -213,7 +249,7 @@ describe('gdjs.evtTools.object', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('can create an instance and keep all instances picked for a group', function () {
|
||||
it('can create an instance and only pick this one when all instances were picked for a group', function () {
|
||||
const runtimeGame = gdjs.getPixiRuntimeGame();
|
||||
const runtimeScene = new gdjs.TestRuntimeScene(runtimeGame);
|
||||
|
||||
@@ -224,10 +260,14 @@ describe('gdjs.evtTools.object', function () {
|
||||
const objectB1 = runtimeScene.createObject('MyObjectB');
|
||||
|
||||
// All instances are picked.
|
||||
const pickedObjectList = Hashtable.newFrom({
|
||||
MyObjectA: [objectA1, objectA2],
|
||||
MyObjectB: [objectB1],
|
||||
});
|
||||
/** @type {ObjectsLists} */
|
||||
const pickedObjectList = gdjs.evtTools.objectsLists.newFrom(
|
||||
{
|
||||
MyObjectA: [objectA1, objectA2],
|
||||
MyObjectB: [objectB1],
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
const newObjectA = gdjs.evtTools.object.createObjectOnScene(
|
||||
runtimeScene,
|
||||
@@ -237,12 +277,12 @@ describe('gdjs.evtTools.object', function () {
|
||||
''
|
||||
);
|
||||
|
||||
// All instances are still picked.
|
||||
// Only the created instance is picked.
|
||||
expect(getInstancesIds(pickedObjectList.get('MyObjectA'))).to.eql(
|
||||
getInstancesIds([objectA1, objectA2, newObjectA])
|
||||
getInstancesIds([newObjectA])
|
||||
);
|
||||
expect(getInstancesIds(pickedObjectList.get('MyObjectB'))).to.eql(
|
||||
getInstancesIds([objectB1])
|
||||
getInstancesIds([])
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@@ -522,17 +522,59 @@ const copyArray = function (src, dst) {
|
||||
dst.length = len;
|
||||
};
|
||||
|
||||
const createObjectOnScene = (objectsContext, objectsLists, x, y, layer) => {
|
||||
const objectName = objectsLists.firstKey();
|
||||
/**
|
||||
* @param {any} objectsContext
|
||||
* @param {string} objectName
|
||||
* @param {Hashtable<RuntimeObject[]>} objectsLists
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {string} layer
|
||||
*/
|
||||
const doCreateObjectOnScene = function (
|
||||
objectsContext,
|
||||
objectName,
|
||||
objectsLists,
|
||||
x,
|
||||
y,
|
||||
layerName
|
||||
) {
|
||||
// objectsContext will either be the gdjs.RuntimeScene or, in an events function, the
|
||||
// eventsFunctionContext. We can't directly use runtimeScene because the object name could
|
||||
// be different than the real object name (this is the case in a function. The eventsFunctionContext
|
||||
// will take care of this in createObject).
|
||||
const obj = objectsContext.createObject(objectName);
|
||||
if (obj !== null) {
|
||||
// Ignore position and layer set up of the object as we're in a minimal mock of GDJS.
|
||||
|
||||
// Let the new object be picked by next actions/conditions.
|
||||
//Let the new object be picked by next actions/conditions.
|
||||
if (objectsLists.containsKey(objectName)) {
|
||||
// TODO Encapsulate this in ObjectsLists
|
||||
if (
|
||||
getPickedInstancesCount(objectsLists) + 1 ===
|
||||
getVisibleInstancesCount(objectsContext, objectsLists)
|
||||
) {
|
||||
clearObjectLists(objectsLists);
|
||||
}
|
||||
objectsLists.get(objectName).push(obj);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {any} objectsContext
|
||||
* @param {Hashtable<RuntimeObject[]>} objectsLists
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {string} layerName
|
||||
*/
|
||||
const createObjectOnScene = (objectsContext, objectsLists, x, y, layerName) => {
|
||||
return doCreateObjectOnScene(
|
||||
objectsContext,
|
||||
objectsLists.firstKey(),
|
||||
objectsLists,
|
||||
x,
|
||||
y,
|
||||
layerName
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -565,6 +607,37 @@ const getPickedInstancesCount = (objectsLists) => {
|
||||
return count;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {any} objectsContext
|
||||
* @param {Hashtable<RuntimeObject[]>} objectsLists
|
||||
*/
|
||||
const getVisibleInstancesCount = (objectsContext, objectsLists) => {
|
||||
let count = 0;
|
||||
|
||||
const objectNames = [];
|
||||
objectsLists.keys(objectNames);
|
||||
|
||||
const uniqueObjectNames = new Set(objectNames);
|
||||
for (const objectName of uniqueObjectNames) {
|
||||
const visibleObjects = objectsContext.getObjects(objectName);
|
||||
if (visibleObjects) {
|
||||
count += visibleObjects.length;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Hashtable<RuntimeObject[]>} objectsLists
|
||||
*/
|
||||
const clearObjectLists = (objectsLists) => {
|
||||
const lists = [];
|
||||
objectsLists.values(lists);
|
||||
for (let i = 0, len = lists.length; i < len; ++i) {
|
||||
lists[i].length = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/** A minimal implementation of gdjs.RuntimeScene for testing. */
|
||||
class RuntimeScene {
|
||||
constructor(sceneData) {
|
||||
@@ -706,6 +779,27 @@ class LongLivedObjectsList {
|
||||
}
|
||||
}
|
||||
|
||||
const clearObjectsLists = (objectsLists) => {
|
||||
for (const k in objectsLists.items) {
|
||||
if (objectsLists.items.hasOwnProperty(k)) {
|
||||
objectsLists.items[k].length = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const addObject = (
|
||||
objectsLists,
|
||||
objectName,
|
||||
object
|
||||
) => {
|
||||
if (!objectsLists.isPicked) {
|
||||
// A picking starts from empty lists.
|
||||
clearObjectsLists(objectsLists);
|
||||
objectsLists.isPicked = true;
|
||||
}
|
||||
objectsLists.get(objectName).push(object);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a minimal mock of GDJS with a RuntimeScene (`gdjs.RuntimeScene`),
|
||||
* supporting setting a variable, using "Trigger Once" conditions
|
||||
@@ -729,6 +823,8 @@ function makeMinimalGDJSMock(options) {
|
||||
createObjectOnScene,
|
||||
getSceneInstancesCount,
|
||||
getPickedInstancesCount,
|
||||
getVisibleInstancesCount,
|
||||
clearObjectLists,
|
||||
},
|
||||
runtimeScene: {
|
||||
wait: () => new FakeAsyncTask(),
|
||||
@@ -737,6 +833,9 @@ function makeMinimalGDJSMock(options) {
|
||||
common: {
|
||||
resolveAsyncEventsFunction: ({ task }) => task.resolve(),
|
||||
},
|
||||
objectsLists: {
|
||||
addObject,
|
||||
}
|
||||
},
|
||||
registerBehavior: (behaviorTypeName, Ctor) => {
|
||||
behaviorCtors[behaviorTypeName] = Ctor;
|
||||
|
@@ -36,7 +36,7 @@ describe('libGD.js - GDJS Code Generation integration tests', () => {
|
||||
});
|
||||
};
|
||||
|
||||
it('can create an instance and keep all instances picked', function () {
|
||||
it('can create an instance and only pick this one when all instances were picked', function () {
|
||||
const runCompiledEvents = generateFunctionWithCreateAction(gd);
|
||||
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
|
||||
|
||||
@@ -51,8 +51,8 @@ describe('libGD.js - GDJS Code Generation integration tests', () => {
|
||||
|
||||
runCompiledEvents(gdjs, runtimeScene, [myObjectLists]);
|
||||
|
||||
// All instances are still picked.
|
||||
expect(myObjectLists.get('MyObject').length).toBe(3);
|
||||
// Only the created instance is picked.
|
||||
expect(myObjectLists.get('MyObject').length).toBe(1);
|
||||
});
|
||||
|
||||
it('can create and pick an instance when some instances were not picked', function () {
|
||||
@@ -101,7 +101,7 @@ describe('libGD.js - GDJS Code Generation integration tests', () => {
|
||||
expect(myObjectLists.get('MyObject').length).toBe(1);
|
||||
});
|
||||
|
||||
it('can create an instance and keep all instances picked of a group', function () {
|
||||
it('can create an instance and only pick this one when all instances were picked for a group', function () {
|
||||
const runCompiledEvents = generateFunctionWithCreateAction(gd);
|
||||
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
|
||||
|
||||
@@ -118,9 +118,9 @@ describe('libGD.js - GDJS Code Generation integration tests', () => {
|
||||
|
||||
runCompiledEvents(gdjs, runtimeScene, [myObjectLists]);
|
||||
|
||||
// All instances are still picked.
|
||||
expect(myObjectLists.get('MyObjectA').length).toBe(3);
|
||||
expect(myObjectLists.get('MyObjectB').length).toBe(1);
|
||||
// Only the created instance is picked.
|
||||
expect(myObjectLists.get('MyObjectA').length).toBe(1);
|
||||
expect(myObjectLists.get('MyObjectB').length).toBe(0);
|
||||
});
|
||||
|
||||
it('can create and pick an instance when some instances of a group were not picked', function () {
|
||||
|
@@ -538,7 +538,8 @@ describe('libGD.js - GDJS Code Generation integration tests', function () {
|
||||
const runCompiledEvents = generateCompiledEventsForEventsFunction(
|
||||
gd,
|
||||
project,
|
||||
eventsFunction
|
||||
eventsFunction,
|
||||
false
|
||||
);
|
||||
|
||||
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
|
||||
|
Reference in New Issue
Block a user