mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-08-24 22:31:30 -04:00
2e9f9dae6d
Don't show in changelog
913 lines
32 KiB
JavaScript
913 lines
32 KiB
JavaScript
//@ts-check
|
||
/// <reference path="../JsExtensionTypes.d.ts" />
|
||
/**
|
||
* This is a declaration of an extension for GDevelop 5.
|
||
*
|
||
* ℹ️ Changes in this file are watched and automatically imported if the editor
|
||
* is running. You can also manually run `node import-GDJS-Runtime.js` (in newIDE/app/scripts).
|
||
*
|
||
* The file must be named "JsExtension.js", otherwise GDevelop won't load it.
|
||
* ⚠️ If you make a change and the extension is not loaded, open the developer console
|
||
* and search for any errors.
|
||
*
|
||
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
|
||
*/
|
||
|
||
/** @type {ExtensionModule} */
|
||
module.exports = {
|
||
createExtension: function (_, gd) {
|
||
const extension = new gd.PlatformExtension();
|
||
extension
|
||
.setExtensionInformation(
|
||
'NavMeshPathfinding',
|
||
_('Navmesh pathfinding'),
|
||
'Pathfinding allows to compute an efficient path for objects, including crowds, following walkable floors and avoiding obstacles on the way.',
|
||
'',
|
||
'Open source (MIT License)'
|
||
)
|
||
.setShortDescription(
|
||
'Navmesh based pathfinding: compute path avoiding obstacles and handle crowds.'
|
||
)
|
||
.setDimension('2D/3D')
|
||
.setCategory('Movement')
|
||
.setTags('pathfinding, obstacle, collision')
|
||
.setExtensionHelpPath('/behaviors/nav-mesh-pathfinding');
|
||
extension
|
||
.addInstructionOrExpressionGroupMetadata(_('Navmesh pathfinding'))
|
||
.setIcon('JsPlatform/Extensions/nav-mesh-character.svg');
|
||
{
|
||
const behavior = new gd.BehaviorJsImplementation();
|
||
behavior.updateProperty = function (
|
||
behaviorContent,
|
||
propertyName,
|
||
newValue
|
||
) {
|
||
if (propertyName === 'acceleration') {
|
||
const newValueAsNumber = parseFloat(newValue);
|
||
if (newValueAsNumber !== newValueAsNumber) return false;
|
||
behaviorContent
|
||
.getOrCreateChild('acceleration')
|
||
.setDoubleValue(newValueAsNumber);
|
||
return true;
|
||
}
|
||
|
||
if (propertyName === 'maxSpeed') {
|
||
const newValueAsNumber = parseFloat(newValue);
|
||
if (newValueAsNumber !== newValueAsNumber) return false;
|
||
behaviorContent
|
||
.getOrCreateChild('maxSpeed')
|
||
.setDoubleValue(newValueAsNumber);
|
||
return true;
|
||
}
|
||
|
||
if (propertyName === 'angularMaxSpeed') {
|
||
const newValueAsNumber = parseFloat(newValue);
|
||
if (newValueAsNumber !== newValueAsNumber) return false;
|
||
behaviorContent
|
||
.getOrCreateChild('angularMaxSpeed')
|
||
.setDoubleValue(newValueAsNumber);
|
||
return true;
|
||
}
|
||
|
||
if (propertyName === 'rotateObject') {
|
||
behaviorContent
|
||
.getOrCreateChild('rotateObject')
|
||
.setBoolValue(newValue === '1');
|
||
return true;
|
||
}
|
||
|
||
if (propertyName === 'angleOffset') {
|
||
const newValueAsNumber = parseFloat(newValue);
|
||
if (newValueAsNumber !== newValueAsNumber) return false;
|
||
behaviorContent
|
||
.getOrCreateChild('angleOffset')
|
||
.setDoubleValue(newValueAsNumber);
|
||
return true;
|
||
}
|
||
|
||
if (propertyName === 'radius') {
|
||
const newValueAsNumber = parseFloat(newValue);
|
||
if (newValueAsNumber !== newValueAsNumber) return false;
|
||
behaviorContent
|
||
.getOrCreateChild('radius')
|
||
.setDoubleValue(newValueAsNumber);
|
||
return true;
|
||
}
|
||
|
||
if (propertyName === 'avoidanceSightRange') {
|
||
const newValueAsNumber = parseFloat(newValue);
|
||
if (newValueAsNumber !== newValueAsNumber) return false;
|
||
behaviorContent
|
||
.getOrCreateChild('avoidanceSightRange')
|
||
.setDoubleValue(newValueAsNumber);
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
};
|
||
behavior.getProperties = function (behaviorContent) {
|
||
const behaviorProperties = new gd.MapStringPropertyDescriptor();
|
||
|
||
behaviorProperties
|
||
.getOrCreate('acceleration')
|
||
.setValue(behaviorContent.getChild('acceleration').getStringValue())
|
||
.setLabel(_('Acceleration'))
|
||
.setType('Number')
|
||
.setMeasurementUnit(gd.MeasurementUnit.getPixelAcceleration());
|
||
|
||
behaviorProperties
|
||
.getOrCreate('maxSpeed')
|
||
.setValue(behaviorContent.getChild('maxSpeed').getStringValue())
|
||
.setLabel(_('Max. speed'))
|
||
.setType('Number')
|
||
.setMeasurementUnit(gd.MeasurementUnit.getPixelSpeed());
|
||
|
||
behaviorProperties
|
||
.getOrCreate('angularMaxSpeed')
|
||
.setValue(
|
||
behaviorContent.getChild('angularMaxSpeed').getStringValue()
|
||
)
|
||
.setLabel(_('Rotation speed'))
|
||
.setGroup(_('Rotation'))
|
||
.setType('Number')
|
||
.setMeasurementUnit(gd.MeasurementUnit.getAngularSpeed());
|
||
|
||
behaviorProperties
|
||
.getOrCreate('rotateObject')
|
||
.setValue(
|
||
behaviorContent.getChild('rotateObject').getBoolValue()
|
||
? 'true'
|
||
: 'false'
|
||
)
|
||
.setLabel(_('Rotate object'))
|
||
.setGroup(_('Rotation'))
|
||
.setType('Boolean');
|
||
|
||
behaviorProperties
|
||
.getOrCreate('angleOffset')
|
||
.setValue(behaviorContent.getChild('angleOffset').getStringValue())
|
||
.setLabel(_('Angle offset'))
|
||
.setGroup(_('Rotation'))
|
||
.setType('Number')
|
||
.setMeasurementUnit(gd.MeasurementUnit.getDegreeAngle());
|
||
|
||
behaviorProperties
|
||
.getOrCreate('radius')
|
||
.setValue(behaviorContent.getChild('radius').getStringValue())
|
||
.setLabel(_('Radius'))
|
||
.setDescription(
|
||
_(
|
||
'Use the circle inside the object width and height when left to 0.'
|
||
)
|
||
)
|
||
.setGroup(_('Collision'))
|
||
.setType('Number')
|
||
.setMeasurementUnit(gd.MeasurementUnit.getPixel());
|
||
|
||
behaviorProperties
|
||
.getOrCreate('avoidanceSightRange')
|
||
.setValue(
|
||
behaviorContent.getChild('avoidanceSightRange').getStringValue()
|
||
)
|
||
.setLabel(_('Avoidance sight range'))
|
||
.setGroup(_('Collision'))
|
||
.setType('Number')
|
||
.setMeasurementUnit(gd.MeasurementUnit.getPixel());
|
||
|
||
return behaviorProperties;
|
||
};
|
||
|
||
behavior.initializeContent = function (behaviorContent) {
|
||
behaviorContent.addChild('acceleration').setDoubleValue(400);
|
||
behaviorContent.addChild('maxSpeed').setDoubleValue(200);
|
||
behaviorContent.addChild('angularMaxSpeed').setDoubleValue(180);
|
||
behaviorContent.addChild('rotateObject').setBoolValue(true);
|
||
behaviorContent.addChild('angleOffset').setDoubleValue(0);
|
||
behaviorContent.addChild('radius').setDoubleValue(0);
|
||
behaviorContent.addChild('avoidanceSightRange').setDoubleValue(120);
|
||
};
|
||
|
||
const sharedData = new gd.BehaviorSharedDataJsImplementation();
|
||
sharedData.updateProperty = function (
|
||
sharedContent,
|
||
propertyName,
|
||
newValue
|
||
) {
|
||
if (propertyName === 'cellSize') {
|
||
const newValueAsNumber = parseFloat(newValue);
|
||
if (newValueAsNumber !== newValueAsNumber) return false;
|
||
sharedContent
|
||
.getOrCreateChild('cellSize')
|
||
.setDoubleValue(newValueAsNumber);
|
||
return true;
|
||
}
|
||
if (propertyName === 'cellDepth') {
|
||
const newValueAsNumber = parseFloat(newValue);
|
||
if (newValueAsNumber !== newValueAsNumber) return false;
|
||
sharedContent
|
||
.getOrCreateChild('cellDepth')
|
||
.setDoubleValue(newValueAsNumber);
|
||
return true;
|
||
}
|
||
if (propertyName === 'slopeMaxAngle') {
|
||
const newValueAsNumber = parseFloat(newValue);
|
||
if (newValueAsNumber !== newValueAsNumber) return false;
|
||
sharedContent
|
||
.getOrCreateChild('slopeMaxAngle')
|
||
.setDoubleValue(newValueAsNumber);
|
||
return true;
|
||
}
|
||
if (propertyName === 'stairHeightMax') {
|
||
const newValueAsNumber = parseFloat(newValue);
|
||
if (newValueAsNumber !== newValueAsNumber) return false;
|
||
sharedContent
|
||
.getOrCreateChild('stairHeightMax')
|
||
.setDoubleValue(newValueAsNumber);
|
||
return true;
|
||
}
|
||
if (propertyName === 'walkableRadius') {
|
||
const newValueAsNumber = parseFloat(newValue);
|
||
if (newValueAsNumber !== newValueAsNumber) return false;
|
||
sharedContent
|
||
.getOrCreateChild('walkableRadius')
|
||
.setDoubleValue(newValueAsNumber);
|
||
return true;
|
||
}
|
||
if (propertyName === 'walkableDepth') {
|
||
const newValueAsNumber = parseFloat(newValue);
|
||
if (newValueAsNumber !== newValueAsNumber) return false;
|
||
sharedContent
|
||
.getOrCreateChild('walkableDepth')
|
||
.setDoubleValue(newValueAsNumber);
|
||
return true;
|
||
}
|
||
if (propertyName === 'speedScaleY') {
|
||
const newValueAsNumber = parseFloat(newValue);
|
||
if (newValueAsNumber !== newValueAsNumber) return false;
|
||
sharedContent
|
||
.getOrCreateChild('speedScaleY')
|
||
.setDoubleValue(newValueAsNumber);
|
||
return true;
|
||
}
|
||
return false;
|
||
};
|
||
sharedData.getProperties = function (sharedContent) {
|
||
const sharedProperties = new gd.MapStringPropertyDescriptor();
|
||
|
||
sharedProperties
|
||
.getOrCreate('cellSize')
|
||
.setLabel(_('Cell size'))
|
||
.setType('Number')
|
||
.setMeasurementUnit(gd.MeasurementUnit.getPixel())
|
||
.setValue(
|
||
sharedContent.getChild('cellSize').getDoubleValue().toString(10)
|
||
)
|
||
.setAdvanced(true)
|
||
.setQuickCustomizationVisibility(gd.QuickCustomization.Hidden);
|
||
|
||
sharedProperties
|
||
.getOrCreate('cellDepth')
|
||
.setLabel(_('Cell depth'))
|
||
.setGroup(_('3D only'))
|
||
.setType('Number')
|
||
.setMeasurementUnit(gd.MeasurementUnit.getPixel())
|
||
.setValue(
|
||
sharedContent.getChild('cellDepth').getDoubleValue().toString(10)
|
||
)
|
||
.setAdvanced(true)
|
||
.setQuickCustomizationVisibility(gd.QuickCustomization.Hidden);
|
||
|
||
sharedProperties
|
||
.getOrCreate('slopeMaxAngle')
|
||
.setLabel(_('Slope max. angle'))
|
||
.setGroup(_('3D only'))
|
||
.setType('Number')
|
||
.setMeasurementUnit(gd.MeasurementUnit.getDegreeAngle())
|
||
.setValue(
|
||
sharedContent
|
||
.getChild('slopeMaxAngle')
|
||
.getDoubleValue()
|
||
.toString(10)
|
||
)
|
||
.setAdvanced(true)
|
||
.setQuickCustomizationVisibility(gd.QuickCustomization.Hidden);
|
||
|
||
sharedProperties
|
||
.getOrCreate('stairHeightMax')
|
||
.setLabel(_('Max. stair height'))
|
||
.setGroup(_('3D only'))
|
||
.setType('Number')
|
||
.setMeasurementUnit(gd.MeasurementUnit.getPixel())
|
||
.setValue(
|
||
sharedContent
|
||
.getChild('stairHeightMax')
|
||
.getDoubleValue()
|
||
.toString(10)
|
||
)
|
||
.setAdvanced(true)
|
||
.setQuickCustomizationVisibility(gd.QuickCustomization.Hidden);
|
||
|
||
sharedProperties
|
||
.getOrCreate('walkableRadius')
|
||
.setLabel(_('Walkable radius'))
|
||
.setDescription(
|
||
_(
|
||
'The biggest character radius is automatically used when left negative.'
|
||
)
|
||
)
|
||
.setType('Number')
|
||
.setMeasurementUnit(gd.MeasurementUnit.getPixel())
|
||
.setValue(
|
||
sharedContent
|
||
.getChild('walkableRadius')
|
||
.getDoubleValue()
|
||
.toString(10)
|
||
)
|
||
.setAdvanced(true)
|
||
.setQuickCustomizationVisibility(gd.QuickCustomization.Hidden);
|
||
|
||
sharedProperties
|
||
.getOrCreate('walkableDepth')
|
||
.setLabel(_('Walkable depth'))
|
||
.setDescription(
|
||
_(
|
||
'Minimum floor to ceiling height that will still allow the floor area to be considered walkable.'
|
||
)
|
||
)
|
||
.setGroup(_('3D only'))
|
||
.setType('Number')
|
||
.setMeasurementUnit(gd.MeasurementUnit.getPixel())
|
||
.setValue(
|
||
sharedContent
|
||
.getChild('walkableDepth')
|
||
.getDoubleValue()
|
||
.toString(10)
|
||
)
|
||
.setAdvanced(true)
|
||
.setQuickCustomizationVisibility(gd.QuickCustomization.Hidden);
|
||
|
||
sharedProperties
|
||
.getOrCreate('speedScaleY')
|
||
.setLabel(_('Y speed scale'))
|
||
.setDescription(
|
||
_(
|
||
'Allow a depth effect for 2D games. Usually set to 0.5 for isometry.'
|
||
)
|
||
)
|
||
.setGroup(_('2D only'))
|
||
.setType('Number')
|
||
.setValue(
|
||
sharedContent.getChild('speedScaleY').getDoubleValue().toString(10)
|
||
)
|
||
.setAdvanced(true)
|
||
.setQuickCustomizationVisibility(gd.QuickCustomization.Hidden);
|
||
|
||
return sharedProperties;
|
||
};
|
||
sharedData.initializeContent = function (sharedContent) {
|
||
sharedContent.addChild('cellSize').setDoubleValue(10);
|
||
sharedContent.addChild('cellDepth').setDoubleValue(10);
|
||
sharedContent.addChild('slopeMaxAngle').setDoubleValue(50);
|
||
sharedContent.addChild('stairHeightMax').setDoubleValue(20);
|
||
sharedContent.addChild('walkableRadius').setDoubleValue(-1);
|
||
sharedContent.addChild('walkableDepth').setDoubleValue(150);
|
||
sharedContent.addChild('speedScaleY').setDoubleValue(1);
|
||
};
|
||
|
||
const aut = extension
|
||
.addBehavior(
|
||
'NavMeshCharacterBehavior',
|
||
_('Pathfinding character (navmesh based)'),
|
||
'NavMeshCharacter',
|
||
_(
|
||
'Move objects to a target by following walkable floors and avoiding obstacles. Uses a flexible 2D/3D "navmesh"-based pathfinding.'
|
||
),
|
||
'',
|
||
'JsPlatform/Extensions/nav-mesh-character.svg',
|
||
'NavMeshCharacterBehavior',
|
||
//@ts-ignore The class hierarchy is incorrect leading to a type error, but this is valid.
|
||
behavior,
|
||
sharedData
|
||
)
|
||
.markAsIrrelevantForChildObjects()
|
||
.addIncludeFile(
|
||
'Extensions/NavMeshPathfinding/NavMeshCharacterRuntimeBehavior.js'
|
||
)
|
||
.addIncludeFile(
|
||
'Extensions/NavMeshPathfinding/NavMeshObstacleRuntimeBehavior.js'
|
||
)
|
||
.addIncludeFile(
|
||
'Extensions/NavMeshPathfinding/recast-navigation.wasm.js'
|
||
)
|
||
.addRequiredFile(
|
||
'Extensions/NavMeshPathfinding/recast-navigation.wasm.wasm'
|
||
)
|
||
.addIncludeFile(
|
||
'Extensions/NavMeshPathfinding/recast-navigation-generators.js'
|
||
);
|
||
|
||
aut
|
||
.addAction(
|
||
'MoveTo',
|
||
_('Move to a position'),
|
||
_('Move the object to a position'),
|
||
_('Move _PARAM0_ to _PARAM2_ ; _PARAM3_ ; _PARAM4_'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg',
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.addParameter('expression', _('Destination X position'))
|
||
.addParameter('expression', _('Destination Y position'))
|
||
.addParameter('expression', _('Destination Z position'))
|
||
.setFunctionName('moveTo');
|
||
|
||
aut
|
||
.addCondition(
|
||
'PathFound',
|
||
_('Path found'),
|
||
_('Check if a path has been found.'),
|
||
_('A path has been found for _PARAM0_'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg',
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.setFunctionName('pathFound');
|
||
|
||
aut
|
||
.addCondition(
|
||
'DestinationReached',
|
||
_('Destination reached'),
|
||
_('Check if the destination was reached.'),
|
||
_('_PARAM0_ reached its destination'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg',
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.setFunctionName('destinationReached');
|
||
|
||
aut
|
||
.addExpressionAndConditionAndAction(
|
||
'number',
|
||
'Acceleration',
|
||
_('Acceleration'),
|
||
_('the acceleration when moving the object'),
|
||
_('the acceleration on the path'),
|
||
_('Pathfinding configuration'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||
.setFunctionName('setAcceleration')
|
||
.setGetter('getAcceleration');
|
||
|
||
aut
|
||
.addExpressionAndConditionAndAction(
|
||
'number',
|
||
'MaxSpeed',
|
||
_('Maximum speed'),
|
||
_('the maximum speed when moving the object'),
|
||
_('the max. speed on the path'),
|
||
_('Pathfinding configuration'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.useStandardParameters(
|
||
'number',
|
||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||
_('Max speed (in pixels per second)')
|
||
)
|
||
)
|
||
.setFunctionName('setMaxSpeed')
|
||
.setGetter('getMaxSpeed');
|
||
|
||
aut
|
||
.addExpressionAndConditionAndAction(
|
||
'number',
|
||
'Speed',
|
||
_('Speed'),
|
||
_('Change the speed of the object on the path'),
|
||
_('the speed on the path'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.useStandardParameters(
|
||
'number',
|
||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||
_('Speed (in pixels per second)')
|
||
)
|
||
)
|
||
.setFunctionName('setSpeed')
|
||
.setGetter('getSpeed');
|
||
|
||
aut
|
||
.addScopedCondition(
|
||
'MovementAngleIsAround',
|
||
_('Angle of movement on its path'),
|
||
_('Compare the angle of movement of an object on its path.'),
|
||
_('Angle of movement of _PARAM0_ is _PARAM2_ ± _PARAM3_°'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg',
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.addParameter('expression', _('Angle, in degrees'))
|
||
.addParameter('expression', _('Tolerance, in degrees'));
|
||
|
||
aut
|
||
.addExpressionAndConditionAndAction(
|
||
'number',
|
||
'AngularMaxSpeed',
|
||
_('Angular maximum speed'),
|
||
_('the maximum angular speed when moving the object'),
|
||
_('the max. angular speed on the path'),
|
||
_('Pathfinding configuration'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.useStandardParameters(
|
||
'number',
|
||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||
_('Max angular speed (in degrees per second)')
|
||
)
|
||
)
|
||
.setFunctionName('setAngularMaxSpeed')
|
||
.setGetter('getAngularMaxSpeed');
|
||
|
||
aut
|
||
.addExpressionAndConditionAndAction(
|
||
'number',
|
||
'AngleOffset',
|
||
_('Rotation offset'),
|
||
_('the rotation offset applied when moving the object'),
|
||
_('the rotation offset on the path'),
|
||
_('Pathfinding configuration'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.useStandardParameters(
|
||
'number',
|
||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||
_('Angle (in degrees)')
|
||
)
|
||
)
|
||
.setFunctionName('setAngleOffset')
|
||
.setGetter('getAngleOffset');
|
||
|
||
aut
|
||
.addScopedAction(
|
||
'RotateObject',
|
||
_('Rotate the object'),
|
||
_('Enable or disable rotation of the object on the path'),
|
||
_('Enable rotation of _PARAM0_ on the path: _PARAM2_'),
|
||
_('Pathfinding configuration'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg',
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.addParameter('yesorno', _('Rotate object?'))
|
||
.setFunctionName('setRotateObject');
|
||
|
||
aut
|
||
.addScopedCondition(
|
||
'ObjectRotated',
|
||
_('Object rotated'),
|
||
_('Check if the object is rotated when traveling on its path.'),
|
||
_('_PARAM0_ is rotated when traveling on its path'),
|
||
_('Pathfinding configuration'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg',
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.setFunctionName('isObjectRotated');
|
||
|
||
aut
|
||
.addExpression(
|
||
'GetNodeX',
|
||
_('Get a waypoint X position'),
|
||
_('Get a waypoint X position'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.addParameter('expression', _('Node index (start at 0!)'))
|
||
.setFunctionName('getNodeX');
|
||
|
||
aut
|
||
.addExpression(
|
||
'GetNodeY',
|
||
_('Get a waypoint Y position'),
|
||
_('Get a waypoint Y position'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.addParameter('expression', _('Node index (start at 0!)'))
|
||
.setFunctionName('getNodeY');
|
||
|
||
aut
|
||
.addExpression(
|
||
'GetNodeZ',
|
||
_('Get a waypoint Z position'),
|
||
_('Get a waypoint Z position'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.addParameter('expression', _('Node index (start at 0!)'))
|
||
.setFunctionName('getNodeZ');
|
||
|
||
aut
|
||
.addExpression(
|
||
'NextNodeIndex',
|
||
_('Index of the next waypoint'),
|
||
_('Get the index of the next waypoint to reach'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.setFunctionName('getNextNodeIndex');
|
||
|
||
aut
|
||
.addExpression(
|
||
'NodeCount',
|
||
_('Waypoint count'),
|
||
_('Get the number of waypoints on the path'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.setFunctionName('getNodeCount');
|
||
|
||
aut
|
||
.addExpression(
|
||
'NextNodeX',
|
||
_('Get next waypoint X position'),
|
||
_('Get next waypoint X position'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.setFunctionName('getNextNodeX');
|
||
|
||
aut
|
||
.addExpression(
|
||
'NextNodeY',
|
||
_('Get next waypoint Y position'),
|
||
_('Get next waypoint Y position'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.setFunctionName('getNextNodeY');
|
||
|
||
aut
|
||
.addExpression(
|
||
'NextNodeZ',
|
||
_('Get next waypoint Z position'),
|
||
_('Get next waypoint Z position'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.setFunctionName('getNextNodeZ');
|
||
|
||
aut
|
||
.addExpression(
|
||
'PreviousNodeX',
|
||
_('Previous waypoint X position'),
|
||
_('Previous waypoint X position'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.setFunctionName('getPreviousNodeX');
|
||
|
||
aut
|
||
.addExpression(
|
||
'PreviousNodeY',
|
||
_('Previous waypoint Y position'),
|
||
_('Previous waypoint Y position'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.setFunctionName('getPreviousNodeY');
|
||
|
||
aut
|
||
.addExpression(
|
||
'PreviousNodeZ',
|
||
_('Previous waypoint Z position'),
|
||
_('Previous waypoint Z position'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.setFunctionName('getPreviousNodeZ');
|
||
|
||
aut
|
||
.addExpression(
|
||
'DestinationX',
|
||
_('Destination X position'),
|
||
_('Destination X position of the path'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.setFunctionName('getDestinationX');
|
||
|
||
aut
|
||
.addExpression(
|
||
'DestinationY',
|
||
_('Destination Y position'),
|
||
_('Destination Y position of the path'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.setFunctionName('getDestinationY');
|
||
|
||
aut
|
||
.addExpression(
|
||
'DestinationZ',
|
||
_('Destination Z position'),
|
||
_('Destination Z position of the path'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.setFunctionName('getDestinationZ');
|
||
|
||
aut
|
||
.addExpression(
|
||
'MovementAngle',
|
||
_('Angle of movement on its path'),
|
||
_('Angle of movement on its path'),
|
||
_('Movement on the path'),
|
||
'JsPlatform/Extensions/nav-mesh-character.svg'
|
||
)
|
||
.addParameter('object', _('Object'))
|
||
.addParameter('behavior', _('Behavior'), 'NavMeshCharacterBehavior')
|
||
.setFunctionName('getMovementAngle');
|
||
}
|
||
{
|
||
const behavior = new gd.BehaviorJsImplementation();
|
||
behavior.updateProperty = function (
|
||
behaviorContent,
|
||
propertyName,
|
||
newValue
|
||
) {
|
||
if (propertyName === 'shape') {
|
||
const normalizedValue = newValue.toLowerCase();
|
||
let shapeValue = '';
|
||
if (normalizedValue === 'box') shapeValue = 'Box';
|
||
else if (normalizedValue === 'mesh') shapeValue = 'Mesh';
|
||
else return false;
|
||
|
||
behaviorContent.getOrCreateChild('shape').setStringValue(shapeValue);
|
||
return true;
|
||
}
|
||
|
||
if (propertyName === 'meshShapeResourceName') {
|
||
behaviorContent
|
||
.getOrCreateChild('meshShapeResourceName')
|
||
.setStringValue(newValue);
|
||
return true;
|
||
}
|
||
return false;
|
||
};
|
||
behavior.getProperties = function (behaviorContent) {
|
||
const behaviorProperties = new gd.MapStringPropertyDescriptor();
|
||
|
||
behaviorProperties
|
||
.getOrCreate('shape')
|
||
.setValue(behaviorContent.getChild('shape').getStringValue())
|
||
.setType('Choice')
|
||
.setLabel('Shape')
|
||
.setQuickCustomizationVisibility(gd.QuickCustomization.Hidden)
|
||
.addChoice('Box', _('Box'))
|
||
.addChoice('Mesh', _('Mesh'));
|
||
behaviorProperties
|
||
.getOrCreate('meshShapeResourceName')
|
||
.setValue(
|
||
behaviorContent.getChild('meshShapeResourceName').getStringValue()
|
||
)
|
||
.setType('resource')
|
||
.addExtraInfo('model3D')
|
||
.setLabel(_('Simplified 3D model'))
|
||
.setDescription(_("Leave empty to use object's one"));
|
||
|
||
return behaviorProperties;
|
||
};
|
||
|
||
behavior.initializeContent = function (behaviorContent) {
|
||
behaviorContent.addChild('shape').setStringValue('Box');
|
||
behaviorContent.addChild('meshShapeResourceName').setStringValue('');
|
||
};
|
||
|
||
const sharedData = new gd.BehaviorSharedDataJsImplementation();
|
||
sharedData.updateProperty = function (
|
||
sharedContent,
|
||
propertyName,
|
||
newValue
|
||
) {
|
||
return false;
|
||
};
|
||
sharedData.getProperties = function (sharedContent) {
|
||
const sharedProperties = new gd.MapStringPropertyDescriptor();
|
||
return sharedProperties;
|
||
};
|
||
sharedData.initializeContent = function (sharedContent) {};
|
||
|
||
extension
|
||
.addBehavior(
|
||
'NavMeshObstacleBehavior',
|
||
_('Floor/obstacle for pathfinding (navmesh based)'),
|
||
'NavMeshObstacle',
|
||
_(
|
||
'Flag objects as being walkable floors and/or obstacles for navmesh pathfinding.'
|
||
),
|
||
'',
|
||
'JsPlatform/Extensions/nav-mesh-obstacle.svg',
|
||
'NavMeshObstacle',
|
||
//@ts-ignore The class hierarchy is incorrect leading to a type error, but this is valid.
|
||
behavior,
|
||
sharedData
|
||
)
|
||
.markAsIrrelevantForChildObjects()
|
||
.addIncludeFile(
|
||
'Extensions/NavMeshPathfinding/NavMeshObstacleRuntimeBehavior.js'
|
||
)
|
||
.addIncludeFile(
|
||
'Extensions/NavMeshPathfinding/recast-navigation.wasm.js'
|
||
)
|
||
.addRequiredFile(
|
||
'Extensions/NavMeshPathfinding/recast-navigation.wasm.wasm'
|
||
)
|
||
.addIncludeFile(
|
||
'Extensions/NavMeshPathfinding/recast-navigation-generators.js'
|
||
);
|
||
}
|
||
|
||
extension
|
||
.addAction(
|
||
'EnableDebugDraw',
|
||
_('Draw pathfinding walkable area'),
|
||
_('This activates the display of the walkable area (in blue).'),
|
||
_('Enable debugging view of navmesh pathfinding: _PARAM1_'),
|
||
'',
|
||
'res/actions/planicon24.png',
|
||
'res/actions/planicon.png'
|
||
)
|
||
.addCodeOnlyParameter('currentScene', '')
|
||
.addParameter('yesorno', _('Enable debug draw'), '', false)
|
||
.setDefaultValue('yes')
|
||
.getCodeExtraInformation()
|
||
.addIncludeFile(
|
||
'Extensions/NavMeshPathfinding/NavMeshObstacleRuntimeBehavior.js'
|
||
)
|
||
.addIncludeFile('Extensions/NavMeshPathfinding/recast-navigation.wasm.js')
|
||
.addIncludeFile(
|
||
'Extensions/NavMeshPathfinding/recast-navigation-generators.js'
|
||
)
|
||
.addIncludeFile(
|
||
'Extensions/NavMeshPathfinding/NavMeshDebugPixiRenderer.js'
|
||
)
|
||
.setFunctionName('gdjs.NavMeshObstaclesManager.enableDebugDraw');
|
||
|
||
return extension;
|
||
},
|
||
|
||
runExtensionSanityTests: function (gd, extension) {
|
||
return [];
|
||
},
|
||
};
|