mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
13 Commits
ai-ux-impr
...
condition-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
689676e058 | ||
![]() |
1ed6b4889a | ||
![]() |
ccec9e9b8b | ||
![]() |
2a036368f5 | ||
![]() |
3bc8b1839f | ||
![]() |
d8f2ced5f5 | ||
![]() |
5373406177 | ||
![]() |
3d1142f7c7 | ||
![]() |
2d7e6248f7 | ||
![]() |
85dd04e430 | ||
![]() |
c25252ce33 | ||
![]() |
685b2105e1 | ||
![]() |
cd0bfa9281 |
@@ -66,6 +66,19 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("SetReturnObject",
|
||||
_("Set returned objects"),
|
||||
_("Set currently picked instances as the ones returned for the object. These instances will be picked for actions, conditions and sub-events that follow this function call."),
|
||||
_("Set currently picked instances of _PARAM0_ to be returned"),
|
||||
_("Functions"),
|
||||
"res/function24.png",
|
||||
"res/function16.png")
|
||||
.SetHelpPath("/events/functions/return")
|
||||
.AddParameter("object", "Picked instances object")
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("CopyArgumentToVariable",
|
||||
_("Copy function parameter to variable"),
|
||||
|
@@ -99,6 +99,28 @@ AdvancedExtension::AdvancedExtension() {
|
||||
"}\n";
|
||||
});
|
||||
|
||||
GetAllActions()["SetReturnObject"]
|
||||
.GetCodeExtraInformation()
|
||||
.SetCustomCodeGenerator([](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
gd::String objectsPickingCode;
|
||||
|
||||
for (const auto& objectName : codeGenerator.GetObjectsContainersList().ExpandObjectName(
|
||||
instruction.GetParameter(0).GetPlainString(), context.GetCurrentObject())) {
|
||||
const gd::String& objectNameString = codeGenerator.ConvertToStringExplicit(objectName);
|
||||
const gd::String& objectList = codeGenerator.GetObjectListName(objectName, context);
|
||||
objectsPickingCode += "gdjs.evtTools.object.pickObjects("
|
||||
"eventsFunctionContext.getObjectsLists(" +
|
||||
objectNameString + "), " + objectList + ");\n";
|
||||
}
|
||||
|
||||
return "if (typeof eventsFunctionContext !== 'undefined') {\n"
|
||||
" eventsFunctionContext.returnValue = true;\n"
|
||||
+ objectsPickingCode +
|
||||
"}\n";
|
||||
});
|
||||
|
||||
GetAllConditions()["GetArgumentAsBoolean"]
|
||||
.SetCustomCodeGenerator([](gd::Instruction& instruction,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
|
@@ -218,6 +218,37 @@ namespace gdjs {
|
||||
arr.length = finalSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pick the objects from a given `Array`.
|
||||
* @param objectsLists the picking list to filter
|
||||
* @param objects the objects to pick
|
||||
*/
|
||||
export const pickObjects = (
|
||||
objectsLists: ObjectsLists,
|
||||
objects: gdjs.RuntimeObject[]
|
||||
) => {
|
||||
// Clear the `pick` flag on every objects.
|
||||
for (const objectsName in objectsLists.items) {
|
||||
if (objectsLists.items.hasOwnProperty(objectsName)) {
|
||||
for (const object of objectsLists.items[objectsName]) {
|
||||
object.pick = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Mark objects that need to be picked.
|
||||
for (const object of objects) {
|
||||
object.pick = true;
|
||||
}
|
||||
// Trim not picked objects from lists.
|
||||
for (const objectsName in objectsLists.items) {
|
||||
if (objectsLists.items.hasOwnProperty(objectsName)) {
|
||||
gdjs.evtTools.object.filterPickedObjectsList(
|
||||
objectsLists.items[objectsName]
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const hitBoxesCollisionTest = function (
|
||||
objectsLists1: ObjectsLists,
|
||||
objectsLists2: ObjectsLists,
|
||||
|
@@ -86,6 +86,28 @@ describe('gdjs.evtTools.object.pickObjectsIf', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('gdjs.evtTools.object.pickObjects', function() {
|
||||
it('should properly pick objects', function(){
|
||||
const runtimeScene = new gdjs.RuntimeScene(null);
|
||||
const objectA1 = new gdjs.RuntimeObject(runtimeScene, {name: "ObjectA", type: "", behaviors: [], effects: []});
|
||||
const objectA2 = new gdjs.RuntimeObject(runtimeScene, {name: "ObjectA", type: "", behaviors: [], effects: []});
|
||||
const objectA3 = new gdjs.RuntimeObject(runtimeScene, {name: "ObjectA", type: "", behaviors: [], effects: []});
|
||||
const objectB1 = new gdjs.RuntimeObject(runtimeScene, {name: "ObjectB", type: "", behaviors: [], effects: []});
|
||||
const objectB2 = new gdjs.RuntimeObject(runtimeScene, {name: "ObjectB", type: "", behaviors: [], effects: []});
|
||||
|
||||
const pickedObjectMap = Hashtable.newFrom({
|
||||
ObjectA: [objectA1, objectA2, objectA3],
|
||||
ObjectB: [objectB1, objectB2]
|
||||
});
|
||||
|
||||
gdjs.evtTools.object.pickObjects(pickedObjectMap, [objectA3, objectB2, objectA1]);
|
||||
expect(pickedObjectMap.get("ObjectA")).to.have.length(2);
|
||||
expect(pickedObjectMap.get("ObjectB")).to.have.length(1);
|
||||
expect(pickedObjectMap.get("ObjectA")).to.eql([objectA1, objectA3]);
|
||||
expect(pickedObjectMap.get("ObjectB")).to.eql([objectB2]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('gdjs.evtTools.object.pickRandomObject', function() {
|
||||
it('should pick only one object', function(){
|
||||
var runtimeScene = new gdjs.RuntimeScene(null);
|
||||
|
@@ -290,6 +290,22 @@ class VariablesContainer {
|
||||
has(variableName) {
|
||||
return this._variables.containsKey(variableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {Variable} newVariable
|
||||
*/
|
||||
add(name, newVariable) {
|
||||
const oldVariable = this._variables.get(name);
|
||||
|
||||
this._variables.put(name, newVariable);
|
||||
if (oldVariable) {
|
||||
const variableIndex = this._variablesArray.indexOf(oldVariable);
|
||||
if (variableIndex !== -1) {
|
||||
this._variablesArray[variableIndex] = newVariable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RuntimeObject {
|
||||
@@ -565,6 +581,54 @@ const getPickedInstancesCount = (objectsLists) => {
|
||||
return count;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {RuntimeObject[]} arr
|
||||
*/
|
||||
const filterPickedObjectsList = function (
|
||||
arr
|
||||
) {
|
||||
let finalSize = 0;
|
||||
for (let k = 0, lenk = arr.length; k < lenk; ++k) {
|
||||
const obj = arr[k];
|
||||
if (obj.pick) {
|
||||
arr[finalSize] = obj;
|
||||
finalSize++;
|
||||
}
|
||||
}
|
||||
arr.length = finalSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Hashtable<RuntimeObject[]>} objectsLists
|
||||
* @param {RuntimeObject[]} objects
|
||||
*/
|
||||
const pickObjects = (
|
||||
objectsLists,
|
||||
objects
|
||||
) => {
|
||||
// Clear the `pick` flag on every objects.
|
||||
for (const objectsName in objectsLists.items) {
|
||||
if (objectsLists.items.hasOwnProperty(objectsName)) {
|
||||
for (const object of objectsLists.items[objectsName]) {
|
||||
object.pick = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Mark objects that need to be picked.
|
||||
for (const object of objects) {
|
||||
object.pick = true;
|
||||
}
|
||||
// Trim not picked objects from lists.
|
||||
for (const objectsName in objectsLists.items) {
|
||||
if (objectsLists.items.hasOwnProperty(objectsName)) {
|
||||
filterPickedObjectsList(
|
||||
objectsLists.items[objectsName]
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** A minimal implementation of gdjs.RuntimeScene for testing. */
|
||||
class RuntimeScene {
|
||||
constructor(sceneData) {
|
||||
@@ -729,6 +793,7 @@ function makeMinimalGDJSMock(options) {
|
||||
createObjectOnScene,
|
||||
getSceneInstancesCount,
|
||||
getPickedInstancesCount,
|
||||
pickObjects,
|
||||
},
|
||||
runtimeScene: {
|
||||
wait: () => new FakeAsyncTask(),
|
||||
|
@@ -219,4 +219,121 @@ describe('libGD.js - GDJS Code Generation integration tests', function () {
|
||||
.getAsNumber()
|
||||
).toBe(123);
|
||||
});
|
||||
|
||||
it('can generate function returning objects', function () {
|
||||
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
|
||||
|
||||
const myObjectA1 = runtimeScene.createObject('MyObjectA');
|
||||
const myObjectA2 = runtimeScene.createObject('MyObjectA');
|
||||
const myObjectB1 = runtimeScene.createObject('MyObjectB');
|
||||
const myObjectB2 = runtimeScene.createObject('MyObjectB');
|
||||
const myObjectB3 = runtimeScene.createObject('MyObjectB');
|
||||
|
||||
const variableA1 = new gdjs.Variable();
|
||||
variableA1.setNumber(1);
|
||||
myObjectA1.getVariables().add('Pick', variableA1);
|
||||
const variableB3 = new gdjs.Variable();
|
||||
variableB3.setNumber(1);
|
||||
myObjectB3.getVariables().add('Pick', variableB3);
|
||||
|
||||
// Run the function passing some objects as parameters.
|
||||
const objectsLists = gdjs.Hashtable.newFrom({
|
||||
MyObjectA: [myObjectA1],
|
||||
MyObjectB: [myObjectB2, myObjectB3],
|
||||
MyObjectC: [],
|
||||
});
|
||||
|
||||
const serializerElement = gd.Serializer.fromJSObject([
|
||||
{
|
||||
type: 'BuiltinCommonInstructions::Standard',
|
||||
conditions: [
|
||||
{
|
||||
type: { value: 'VarObjet' },
|
||||
parameters: ["Object","Pick","!=","0"],
|
||||
},
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
type: { value: 'SetReturnObject' },
|
||||
parameters: ['Object'],
|
||||
},
|
||||
],
|
||||
events: [],
|
||||
},
|
||||
]);
|
||||
const runCompiledEvents = generateCompiledEventsFromSerializedEvents(
|
||||
gd,
|
||||
serializerElement,
|
||||
{ parameterTypes: { Object: 'object' }, logCode: false }
|
||||
);
|
||||
runCompiledEvents(gdjs, runtimeScene, [objectsLists]);
|
||||
|
||||
expect(objectsLists.get('MyObjectA')).toEqual([myObjectA1]);
|
||||
expect(objectsLists.get('MyObjectB')).toEqual([myObjectB3]);
|
||||
expect(objectsLists.get('MyObjectC')).toEqual([]);
|
||||
});
|
||||
|
||||
it('can generate function creating 2 instances and returning only one', function () {
|
||||
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
|
||||
|
||||
const myObjectA1 = runtimeScene.createObject('MyObjectA');
|
||||
const myObjectA2 = runtimeScene.createObject('MyObjectA');
|
||||
const myObjectB1 = runtimeScene.createObject('MyObjectB');
|
||||
|
||||
// According to the parameter type objectListOrEmptyIfJustDeclared,
|
||||
// no instances is passed to the function because the ObjectsLists has not
|
||||
// been filtered before.
|
||||
const objectsLists = gdjs.Hashtable.newFrom({
|
||||
MyObjectA: [],
|
||||
MyObjectB: [],
|
||||
MyObjectC: [],
|
||||
});
|
||||
|
||||
const serializerElement = gd.Serializer.fromJSObject([
|
||||
{
|
||||
type: 'BuiltinCommonInstructions::Standard',
|
||||
conditions: [
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
type: { value: 'Create' },
|
||||
parameters: ['', 'Object', '0','0',''],
|
||||
},
|
||||
{
|
||||
type: {'value':'ModVarObjet'},
|
||||
parameters: ['Object','Pick','=','1']
|
||||
},
|
||||
{
|
||||
type: { value: 'Create' },
|
||||
parameters: ['', 'Object', '0','0',''],
|
||||
},
|
||||
],
|
||||
events: [],
|
||||
},
|
||||
{
|
||||
type: 'BuiltinCommonInstructions::Standard',
|
||||
conditions: [
|
||||
{
|
||||
type: { value: 'VarObjet' },
|
||||
parameters: ['Object','Pick','!=','0'],
|
||||
},
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
type: { value: 'SetReturnObject' },
|
||||
parameters: ['Object'],
|
||||
},
|
||||
],
|
||||
events: [],
|
||||
},
|
||||
]);
|
||||
const runCompiledEvents = generateCompiledEventsFromSerializedEvents(
|
||||
gd,
|
||||
serializerElement,
|
||||
{ parameterTypes: { Object: 'objectListOrEmptyIfJustDeclared' }, logCode: false }
|
||||
);
|
||||
runCompiledEvents(gdjs, runtimeScene, [objectsLists]);
|
||||
|
||||
expect(objectsLists.get('MyObjectA').length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user