From a83b0a4205aa9316d8a7050611dfa1c971bd0908 Mon Sep 17 00:00:00 2001 From: Jesse Howard Date: Thu, 13 Aug 2026 16:52:33 -0400 Subject: [PATCH] Building splash and title screens --- WorldOfSolariaV1.json | 13165 +++++++++++++++++++++++++++++++ WorldOfSolariaV1.json.autosave | 1 + assets/tempLogo.png | Bin 0 -> 60192 bytes assets/tempTitle.png | Bin 0 -> 132357 bytes 4 files changed, 13166 insertions(+) create mode 100644 WorldOfSolariaV1.json create mode 100644 WorldOfSolariaV1.json.autosave create mode 100644 assets/tempLogo.png create mode 100644 assets/tempTitle.png diff --git a/WorldOfSolariaV1.json b/WorldOfSolariaV1.json new file mode 100644 index 0000000..a0c4dad --- /dev/null +++ b/WorldOfSolariaV1.json @@ -0,0 +1,13165 @@ +{ + "firstLayout": "", + "gdVersion": { + "build": 279, + "major": 5, + "minor": 6, + "revision": 0 + }, + "initialGDVersion": "5.6.279", + "properties": { + "adaptGameResolutionAtRuntime": true, + "antialiasingMode": "MSAA", + "antialisingEnabledOnMobile": false, + "folderProject": false, + "orientation": "landscape", + "packageName": "com.example.gamename", + "pixelsRounding": true, + "projectUuid": "459bb859-e4c7-45fe-a4a8-13e8403e786f", + "scaleMode": "nearest", + "sizeOnStartupMode": "adaptWidth", + "templateSlug": "", + "version": "1.0.0", + "name": "WorldOfSolariaV1", + "description": "", + "author": "", + "windowWidth": 768, + "windowHeight": 432, + "latestCompilationDirectory": "", + "maxFPS": 60, + "minFPS": 20, + "verticalSync": false, + "platformSpecificAssets": { + "android-icon-144": "", + "android-icon-192": "", + "android-icon-36": "", + "android-icon-48": "", + "android-icon-72": "", + "android-icon-96": "", + "android-windowSplashScreenAnimatedIcon": "", + "desktop-icon-512": "", + "ios-icon-100": "", + "ios-icon-1024": "", + "ios-icon-114": "", + "ios-icon-120": "", + "ios-icon-144": "", + "ios-icon-152": "", + "ios-icon-167": "", + "ios-icon-180": "", + "ios-icon-20": "", + "ios-icon-29": "", + "ios-icon-40": "", + "ios-icon-50": "", + "ios-icon-57": "", + "ios-icon-58": "", + "ios-icon-60": "", + "ios-icon-72": "", + "ios-icon-76": "", + "ios-icon-80": "", + "ios-icon-87": "" + }, + "loadingScreen": { + "backgroundColor": 0, + "backgroundFadeInDuration": 0.2, + "backgroundImageResourceName": "", + "gdevelopLogoStyle": "light", + "logoAndProgressFadeInDuration": 0.2, + "logoAndProgressLogoFadeInDelay": 0, + "minDuration": 1.5, + "progressBarColor": 16777215, + "progressBarHeight": 20, + "progressBarMaxWidth": 200, + "progressBarMinWidth": 40, + "progressBarWidthPercent": 30, + "showGDevelopSplash": true, + "showProgressBar": true + }, + "watermark": { + "placement": "bottom-left", + "showWatermark": true + }, + "authorIds": [], + "authorUsernames": [], + "categories": [], + "playableDevices": [], + "extensionProperties": [], + "platforms": [ + { + "name": "GDevelop JS platform" + } + ], + "currentPlatform": "GDevelop JS platform" + }, + "resources": { + "resources": [ + { + "file": "assets/NewSprite.png", + "kind": "image", + "metadata": "{\"extension\":\".png\"}", + "name": "NewSprite", + "smoothed": false, + "userAdded": false + }, + { + "file": "assets/tempLogo.png", + "kind": "image", + "metadata": "{\"extension\":\".png\"}", + "name": "tempLogo", + "smoothed": false, + "userAdded": false + }, + { + "file": "assets/tempLogo.png", + "kind": "image", + "metadata": "", + "name": "assets/tempLogo.png", + "smoothed": false, + "userAdded": false + }, + { + "file": "assets/tempLogo3.png", + "kind": "image", + "metadata": "", + "name": "assets/tempLogo3.png", + "smoothed": false, + "userAdded": false + }, + { + "file": "assets/NewSprite2.png", + "kind": "image", + "metadata": "{\"extension\":\".png\"}", + "name": "NewSprite2", + "smoothed": false, + "userAdded": false + }, + { + "file": "assets/tempTitle.png", + "kind": "image", + "metadata": "", + "name": "assets/tempTitle.png", + "smoothed": false, + "userAdded": false + } + ] + }, + "objects": [ + { + "assetStoreId": "", + "name": "shp_fade", + "persistentUuid": "7c029e6d-47df-4889-bb1b-6130d9888e56", + "type": "PrimitiveDrawing::Drawer", + "variables": [], + "effects": [], + "behaviors": [ + { + "name": "FlashTransitionPainter", + "type": "FlashTransitionPainter::FlashTransitionPainter", + "Progress": 0, + "Duration": 0, + "Type": "", + "Direction": "", + "MaxOpacity": 255 + } + ], + "fillOpacity": 255, + "outlineSize": 1, + "outlineOpacity": 255, + "absoluteCoordinates": false, + "clearBetweenFrames": true, + "antialiasing": "none", + "fillColor": { + "r": 255, + "g": 255, + "b": 255 + }, + "outlineColor": { + "r": 0, + "g": 0, + "b": 0 + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Fade", + "children": [ + { + "objectName": "shp_fade" + } + ] + } + ] + }, + "objectsGroups": [], + "variables": [ + { + "name": "host", + "type": "string", + "value": "" + } + ], + "layouts": [ + { + "b": 255, + "disableInputWhenNotFocused": true, + "mangledName": "Splash", + "name": "Splash", + "r": 247, + "standardSortMethod": true, + "stopSoundsOnStartup": true, + "title": "", + "v": 249, + "uiSettings": { + "grid": true, + "gridType": "rectangular", + "gridWidth": 16, + "gridHeight": 16, + "gridDepth": 32, + "gridOffsetX": 0, + "gridOffsetY": 0, + "gridOffsetZ": 0, + "gridColor": 10401023, + "gridAlpha": 0.8, + "snap": true, + "zoomFactor": 1.1726229638177634, + "windowMask": false, + "selectedLayer": "", + "gameEditorMode": "instances-editor" + }, + "objectsGroups": [], + "variables": [], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 1, + "height": 224, + "keepRatio": true, + "layer": "", + "name": "spr_studioLogo", + "persistentUuid": "a65e3907-a834-4122-b84c-e184ed30d7a5", + "width": 480, + "x": 144, + "y": 96, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + }, + { + "angle": 0, + "customSize": false, + "height": 0, + "keepRatio": true, + "layer": "", + "name": "shp_fade", + "persistentUuid": "43c12b31-9f4a-4fd7-970e-a848140da139", + "width": 0, + "x": 640, + "y": 0, + "zOrder": 2, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "objects": [ + { + "adaptCollisionMaskAutomatically": true, + "assetStoreId": "", + "name": "spr_studioLogo", + "persistentUuid": "d8d7a523-1dfa-4cd4-9080-3d6c7deb792f", + "type": "Sprite", + "updateIfNotVisible": false, + "variables": [], + "effects": [], + "behaviors": [], + "animations": [ + { + "name": "tempLogo", + "useMultipleDirections": false, + "directions": [ + { + "looping": false, + "metadata": "{\"pskl\":{}}", + "timeBetweenFrames": 0.08, + "sprites": [ + { + "hasCustomCollisionMask": true, + "image": "tempLogo", + "points": [], + "originPoint": { + "name": "origine", + "x": 0, + "y": 0 + }, + "centerPoint": { + "automatic": true, + "name": "centre", + "x": 0, + "y": 0 + }, + "customCollisionMask": [ + [ + { + "x": 0, + "y": 0 + }, + { + "x": 640, + "y": 0 + }, + { + "x": 640, + "y": 304 + }, + { + "x": 0, + "y": 304 + } + ] + ] + } + ] + } + ] + } + ] + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Sprites", + "children": [ + { + "objectName": "spr_studioLogo" + } + ] + } + ] + }, + "events": [ + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Scene Start", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "SceneJustBegins" + }, + "parameters": [ + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "CenterWindow" + }, + "parameters": [ + "" + ] + }, + { + "type": { + "value": "SetWindowSize" + }, + "parameters": [ + "", + "768", + "432", + "" + ] + }, + { + "type": { + "value": "FlashTransitionPainter::FlashTransitionPainter::PaintEffect" + }, + "parameters": [ + "shp_fade", + "FlashTransitionPainter", + "\"0;0;0\"", + "1", + "\"Flash\"", + "\"Backward\"", + "255", + "" + ] + }, + { + "type": { + "value": "Wait" + }, + "parameters": [ + "3" + ] + }, + { + "type": { + "value": "FlashTransitionPainter::FlashTransitionPainter::PaintEffect" + }, + "parameters": [ + "shp_fade", + "FlashTransitionPainter", + "\"0;0;0\"", + "1", + "\"Flash\"", + "\"Forward\"", + "255", + "" + ] + }, + { + "type": { + "value": "Wait" + }, + "parameters": [ + "1" + ] + }, + { + "type": { + "value": "Scene" + }, + "parameters": [ + "", + "\"Title\"", + "" + ] + } + ] + } + ], + "parameters": [] + }, + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Host Device", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "SystemInfo::HasTouchScreen" + }, + "parameters": [ + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetStringVariable" + }, + "parameters": [ + "host", + "=", + "\"touchscreen\"" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "SystemInfo::IsNativeDesktopApp" + }, + "parameters": [ + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetStringVariable" + }, + "parameters": [ + "host", + "=", + "\"desktop\"" + ] + } + ] + } + ], + "parameters": [] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [] + } + ], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [ + { + "effectType": "Scene3D::HemisphereLight", + "name": "3D Ambient Hemisphere Light", + "doubleParameters": { + "elevation": 40, + "intensity": 0.33, + "rotation": 300 + }, + "stringParameters": { + "groundColor": "127;127;127", + "skyColor": "255;255;255", + "top": "Z+" + }, + "booleanParameters": {} + }, + { + "effectType": "Scene3D::DirectionalLight", + "name": "3D Sun Light", + "doubleParameters": { + "distanceFromCamera": 1500, + "elevation": 40, + "frustumSize": 4000, + "intensity": 0.75, + "minimumShadowBias": 0, + "rotation": 300 + }, + "stringParameters": { + "color": "255;255;255", + "shadowQuality": "medium", + "top": "Z+" + }, + "booleanParameters": { + "isCastingShadow": true + } + } + ] + } + ], + "behaviorsSharedData": [ + { + "name": "Animation", + "type": "AnimatableCapability::AnimatableBehavior" + }, + { + "name": "Effect", + "type": "EffectCapability::EffectBehavior" + }, + { + "name": "FlashTransitionPainter", + "type": "FlashTransitionPainter::FlashTransitionPainter" + }, + { + "name": "Flippable", + "type": "FlippableCapability::FlippableBehavior" + }, + { + "name": "Opacity", + "type": "OpacityCapability::OpacityBehavior" + }, + { + "name": "Resizable", + "type": "ResizableCapability::ResizableBehavior" + }, + { + "name": "Scale", + "type": "ScalableCapability::ScalableBehavior" + } + ] + }, + { + "b": 255, + "disableInputWhenNotFocused": true, + "mangledName": "Title", + "name": "Title", + "r": 247, + "standardSortMethod": true, + "stopSoundsOnStartup": true, + "title": "", + "v": 249, + "uiSettings": { + "grid": true, + "gridType": "rectangular", + "gridWidth": 16, + "gridHeight": 16, + "gridDepth": 32, + "gridOffsetX": 0, + "gridOffsetY": 0, + "gridOffsetZ": 0, + "gridColor": 10401023, + "gridAlpha": 0.8, + "snap": true, + "zoomFactor": 0.9114583333333334, + "windowMask": false, + "selectedLayer": "", + "gameEditorMode": "instances-editor" + }, + "objectsGroups": [], + "variables": [], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 1, + "height": 432, + "keepRatio": true, + "layer": "", + "name": "spr_tempTitle", + "persistentUuid": "7c69ad43-c862-4f49-b2a0-f7aa2a009e17", + "width": 768, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + }, + { + "angle": 0, + "customSize": false, + "height": 0, + "keepRatio": true, + "layer": "", + "name": "shp_fade", + "persistentUuid": "b2376dc0-a75e-41fc-b571-46598d263229", + "width": 0, + "x": 768, + "y": 0, + "zOrder": 2, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "objects": [ + { + "adaptCollisionMaskAutomatically": true, + "assetStoreId": "", + "name": "spr_tempTitle", + "persistentUuid": "d772eb58-a6cd-4786-9454-1d305a42c932", + "type": "Sprite", + "updateIfNotVisible": false, + "variables": [], + "effects": [], + "behaviors": [], + "animations": [ + { + "name": "", + "useMultipleDirections": false, + "directions": [ + { + "looping": false, + "timeBetweenFrames": 0.08, + "sprites": [ + { + "hasCustomCollisionMask": true, + "image": "assets/tempTitle.png", + "points": [], + "originPoint": { + "name": "origine", + "x": 0, + "y": 0 + }, + "centerPoint": { + "automatic": true, + "name": "centre", + "x": 0, + "y": 0 + }, + "customCollisionMask": [ + [ + { + "x": 0, + "y": 0 + }, + { + "x": 640, + "y": 0 + }, + { + "x": 640, + "y": 480 + }, + { + "x": 0, + "y": 480 + } + ] + ] + } + ] + } + ] + } + ] + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "spr_tempTitle" + } + ] + }, + "events": [ + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Scene Start", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "SceneJustBegins" + }, + "parameters": [ + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "CenterWindow" + }, + "parameters": [ + "" + ] + }, + { + "type": { + "value": "SetWindowSize" + }, + "parameters": [ + "", + "768", + "432", + "" + ] + }, + { + "type": { + "value": "FlashTransitionPainter::FlashTransitionPainter::PaintEffect" + }, + "parameters": [ + "shp_fade", + "FlashTransitionPainter", + "\"0;0;0\"", + "1", + "\"Flash\"", + "\"Backward\"", + "255", + "" + ] + } + ] + } + ], + "parameters": [] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [] + } + ], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [ + { + "effectType": "Scene3D::HemisphereLight", + "name": "3D Ambient Hemisphere Light", + "doubleParameters": { + "elevation": 40, + "intensity": 0.33, + "rotation": 300 + }, + "stringParameters": { + "groundColor": "127;127;127", + "skyColor": "255;255;255", + "top": "Z+" + }, + "booleanParameters": {} + }, + { + "effectType": "Scene3D::DirectionalLight", + "name": "3D Sun Light", + "doubleParameters": { + "distanceFromCamera": 1500, + "elevation": 40, + "frustumSize": 4000, + "intensity": 0.75, + "minimumShadowBias": 0, + "rotation": 300 + }, + "stringParameters": { + "color": "255;255;255", + "shadowQuality": "medium", + "top": "Z+" + }, + "booleanParameters": { + "isCastingShadow": true + } + } + ] + } + ], + "behaviorsSharedData": [ + { + "name": "Animation", + "type": "AnimatableCapability::AnimatableBehavior" + }, + { + "name": "Effect", + "type": "EffectCapability::EffectBehavior" + }, + { + "name": "FlashTransitionPainter", + "type": "FlashTransitionPainter::FlashTransitionPainter" + }, + { + "name": "Flippable", + "type": "FlippableCapability::FlippableBehavior" + }, + { + "name": "Opacity", + "type": "OpacityCapability::OpacityBehavior" + }, + { + "name": "Resizable", + "type": "ResizableCapability::ResizableBehavior" + }, + { + "name": "Scale", + "type": "ScalableCapability::ScalableBehavior" + } + ] + } + ], + "externalEvents": [ + { + "associatedLayout": "Splash", + "name": "Functions", + "events": [ + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Scene Start", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "SceneJustBegins" + }, + "parameters": [ + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "CenterWindow" + }, + "parameters": [ + "" + ] + }, + { + "type": { + "value": "SetWindowSize" + }, + "parameters": [ + "", + "768", + "432", + "" + ] + }, + { + "type": { + "value": "FlashTransitionPainter::FlashTransitionPainter::PaintEffect" + }, + "parameters": [ + "shp_fade", + "FlashTransitionPainter", + "\"0;0;0\"", + "1", + "\"Flash\"", + "\"Backward\"", + "255", + "" + ] + }, + { + "type": { + "value": "Wait" + }, + "parameters": [ + "3" + ] + }, + { + "type": { + "value": "FlashTransitionPainter::FlashTransitionPainter::PaintEffect" + }, + "parameters": [ + "shp_fade", + "FlashTransitionPainter", + "\"0;0;0\"", + "1", + "\"Flash\"", + "\"Forward\"", + "255", + "" + ] + }, + { + "type": { + "value": "Wait" + }, + "parameters": [ + "1" + ] + }, + { + "type": { + "value": "Scene" + }, + "parameters": [ + "", + "\"Title\"", + "" + ] + } + ] + } + ], + "parameters": [] + } + ] + } + ], + "eventsFunctionsExtensions": [ + { + "author": "Bouh", + "category": "Input", + "dimension": "", + "extensionNamespace": "", + "fullName": "Gamepads (controllers)", + "gdevelopVersion": ">=5.5.222", + "helpPath": "/all-features/gamepad", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLWdhbWVwYWQtdmFyaWFudC1vdXRsaW5lIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTYsOUg4VjExSDEwVjEzSDhWMTVINlYxM0g0VjExSDZWOU0xOC41LDlBMS41LDEuNSAwIDAsMSAyMCwxMC41QTEuNSwxLjUgMCAwLDEgMTguNSwxMkExLjUsMS41IDAgMCwxIDE3LDEwLjVBMS41LDEuNSAwIDAsMSAxOC41LDlNMTUuNSwxMkExLjUsMS41IDAgMCwxIDE3LDEzLjVBMS41LDEuNSAwIDAsMSAxNS41LDE1QTEuNSwxLjUgMCAwLDEgMTQsMTMuNUExLjUsMS41IDAgMCwxIDE1LjUsMTJNMTcsNUE3LDcgMCAwLDEgMjQsMTJBNyw3IDAgMCwxIDE3LDE5QzE1LjA0LDE5IDEzLjI3LDE4LjIgMTIsMTYuOUMxMC43MywxOC4yIDguOTYsMTkgNywxOUE3LDcgMCAwLDEgMCwxMkE3LDcgMCAwLDEgNyw1SDE3TTcsN0E1LDUgMCAwLDAgMiwxMkE1LDUgMCAwLDAgNywxN0M4LjY0LDE3IDEwLjA5LDE2LjIxIDExLDE1SDEzQzEzLjkxLDE2LjIxIDE1LjM2LDE3IDE3LDE3QTUsNSAwIDAsMCAyMiwxMkE1LDUgMCAwLDAgMTcsN0g3WiIgLz48L3N2Zz4=", + "name": "Gamepads", + "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/gamepad-variant-outline.svg", + "shortDescription": "Gamepad/controller support: buttons, sticks, triggers, vibration. Mapper behaviors for 2D/3D.", + "version": "0.9.2", + "description": [ + "Add support for gamepads (or other physical controllers).", + "", + "It gives access to:", + "- button presses,", + "- axis positions and force,", + "- trigger pressure,", + "- configurable deadzone,", + "- vibration,", + "- automatic \"gamepad mapper\" behaviors for 2D and 3D movement behaviors (platformer characters, top-down movement, 3D character etc...). Add one of these to the object with the movement behavior (i.e: the player most of the time) and the behavior will then be controlled automatically by the gamepad (it works by reading the gamepad state and simulating controls). No need for additional events to make it work once the behaviors are set up.", + "", + "The Bomberman-like example handles 4 players with gamepads ([open the project online](https://editor.gdevelop.io/?project=example://goose-bomberman))." + ], + "origin": { + "identifier": "Gamepads", + "name": "gdevelop-extension-store" + }, + "tags": [ + "controllers", + "gamepads", + "joysticks", + "axis", + "xbox", + "ps4", + "platformer", + "platform", + "top-down" + ], + "authorIds": [ + "2OwwM8ToR9dx9RJ2sAKTcrLmCB92", + "taRwmWxwAFYFL9yyBwB3cwBw0BO2", + "mnImQKdn8nQxwzkS5D6a1JB27V23", + "IWykYNRvhCZBN3vEgKEbBPOR3Oc2" + ], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [ + { + "name": "Buttons", + "type": "structure", + "children": [ + { + "name": "A or Cross", + "type": "string", + "value": "A" + }, + { + "name": "B or Circle", + "type": "string", + "value": "B" + }, + { + "name": "LB or L1", + "type": "string", + "value": "LB" + }, + { + "name": "LT or L2", + "type": "string", + "value": "LT" + }, + { + "name": "RB or R1", + "type": "string", + "value": "RB" + }, + { + "name": "RT or R2", + "type": "string", + "value": "RT" + }, + { + "name": "X or Square", + "type": "string", + "value": "X" + }, + { + "name": "Y or Triangle", + "type": "string", + "value": "Y" + } + ] + } + ], + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onFirstSceneLoaded", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs._extensionController) {\r", + " return;\r", + "}\r", + "\r", + "/**\r", + " * Associate controller button ids to button names\r", + " */\r", + "const controllerButtonNames = {\r", + " \"XBOX\": {\r", + " 0: \"A\",\r", + " 1: \"B\",\r", + " 2: \"X\",\r", + " 3: \"Y\",\r", + " 4: \"LB\",\r", + " 5: \"RB\",\r", + " 6: \"LT\",\r", + " 7: \"RT\",\r", + " 8: \"BACK\",\r", + " 9: \"START\",\r", + " 10: \"CLICK_STICK_LEFT\",\r", + " 11: \"CLICK_STICK_RIGHT\",\r", + " 12: \"UP\",\r", + " 13: \"DOWN\",\r", + " 14: \"LEFT\",\r", + " 15: \"RIGHT\",\r", + " 16: \"NONE\",\r", + " 17: \"NONE\"\r", + " },\r", + " \"PS4\": {\r", + " 0: \"CROSS\",\r", + " 1: \"CIRCLE\",\r", + " 2: \"SQUARE\",\r", + " 3: \"TRIANGLE\",\r", + " 4: \"L1\",\r", + " 5: \"R1\",\r", + " 6: \"L2\",\r", + " 7: \"R2\",\r", + " 8: \"SHARE\",\r", + " 9: \"OPTIONS\",\r", + " 10: \"CLICK_STICK_LEFT\",\r", + " 11: \"CLICK_STICK_RIGHT\",\r", + " 12: \"UP\",\r", + " 13: \"DOWN\",\r", + " 14: \"LEFT\",\r", + " 15: \"RIGHT\",\r", + " 16: \"PS_BUTTON\",\r", + " 17: \"CLICK_TOUCHPAD\"\r", + " }\r", + "};\r", + "\r", + "/**\r", + " * @param {number} playerId\r", + " */\r", + "function getGamepad(playerId) {\r", + " /** @type {Gamepad[]} */\r", + " const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];\r", + " return gamepads[playerId];\r", + "}\r", + "\r", + "/** @type {{[playerId: number]: Player}} */\r", + "const players = {};\r", + "\r", + "/**\r", + " * @param {number} playerId\r", + " */\r", + "function getPlayer(playerId) {\r", + " let player = players[playerId];\r", + " if (!player) {\r", + " player = new Player(playerId);\r", + " players[playerId] = player;\r", + " }\r", + " return player;\r", + "}\r", + "\r", + "class Player {\r", + " /** @type {number} */\r", + " playerId;\r", + " mapping = 'DEFAULT';\r", + " lastButtonUsed = -1;\r", + " deadzone = 0.2;\r", + " /** @type {{[buttonId: number]: ButtonState}} */\r", + " buttonStates = {};\r", + " rumble = { elapsedTime: 0, duration: 0, weakMagnitude: 0, strongMagnitude: 0 };\r", + "\r", + " /**\r", + " * @param {number} playerId\r", + " */\r", + " constructor(playerId) {\r", + " this.playerId = playerId;\r", + " }\r", + "\r", + " /**\r", + " * @param {number} buttonId\r", + " */\r", + " getButtonState(buttonId) {\r", + " let buttonState = this.buttonStates[buttonId];\r", + " if (!buttonState) {\r", + " buttonState = new ButtonState();\r", + " this.buttonStates[buttonId] = buttonState;\r", + " }\r", + " return buttonState;\r", + " }\r", + "\r", + " /**\r", + " * @param {number} buttonId\r", + " */\r", + " isButtonPressed(buttonId) {\r", + " return this.getButtonState(buttonId).isPressed;\r", + " }\r", + "\r", + " /**\r", + " * @param {number} buttonId\r", + " */\r", + " isButtonJustPressed(buttonId) {\r", + " return this.getButtonState(buttonId).isJustPressed();\r", + " }\r", + "\r", + " /**\r", + " * @param {number} buttonId\r", + " */\r", + " isButtonReleased(buttonId) {\r", + " return this.getButtonState(buttonId).isReleased();\r", + " }\r", + "\r", + " isAnyButtonReleased() {\r", + " for (const buttonId in this.buttonStates) {\r", + " const buttonState = this.buttonStates[buttonId];\r", + " if (buttonState.isReleased()) {\r", + " return true;\r", + " }\r", + " }\r", + " return false;\r", + " }\r", + "\r", + " isAnyButtonPressed() {\r", + " for (const buttonId in this.buttonStates) {\r", + " const buttonState = this.buttonStates[buttonId];\r", + " if (buttonState.isPressed) {\r", + " return true;\r", + " }\r", + " }\r", + " return false;\r", + " }\r", + "}\r", + "\r", + "class ButtonState {\r", + " wasPressed = false;\r", + " isPressed = false;\r", + "\r", + " isReleased() {\r", + " return this.wasPressed && !this.isPressed;\r", + " }\r", + "\r", + " isJustPressed() {\r", + " return !this.wasPressed && this.isPressed;\r", + " }\r", + "}\r", + "\r", + "// Async tasks are run before everything.\r", + "// This is a hack to make sure that button states are updated\r", + "// before mapping behavior events.\r", + "const frameBeginningTask = new class extends gdjs.AsyncTask {\r", + " update() {\r", + " /** @type {Gamepad[]} */\r", + " const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];\r", + " for (let playerId = 0; playerId < gamepads.length; playerId++) {\r", + " const gamepad = gamepads[playerId];\r", + " if (gamepad == null) {\r", + " // The gamepad is not connected.\r", + " continue;\r", + " }\r", + " const player = getPlayer(playerId);\r", + "\r", + " for (let buttonId = 0; buttonId < Object.keys(gamepad.buttons).length; buttonId++) {\r", + " const buttonState = player.getButtonState(buttonId);\r", + " buttonState.wasPressed = buttonState.isPressed;\r", + " buttonState.isPressed = gamepad.buttons[buttonId].pressed;\r", + " if (buttonState.isJustPressed()) {\r", + " player.lastButtonUsed = buttonId;\r", + " }\r", + " }\r", + " }\r", + " return false;\r", + " }\r", + "}();\r", + "\r", + "/**\r", + " * @param {gdjs.RuntimeScene} runtimeScene\r", + " */\r", + "function addFrameBeginningTaskIfNeeded(runtimeScene) {\r", + " const taskManager = runtimeScene.getAsyncTasksManager();\r", + " for (const taskWithCallback of taskManager.tasksWithCallback) {\r", + " if (taskWithCallback.asyncTask === frameBeginningTask) {\r", + " return;\r", + " }\r", + " }\r", + " // Async tasks are run before everything.\r", + " // This is a hack to make sure that button states are updated\r", + " // before mapping behavior events.\r", + " taskManager.addTask(frameBeginningTask);\r", + "}\r", + "\r", + "/**\r", + " * @param {gdjs.RuntimeScene} runtimeScene\r", + " */\r", + "function onScenePostEvents(runtimeScene) {\r", + " addFrameBeginningTaskIfNeeded(runtimeScene);\r", + " /** @type {Gamepad[]} */\r", + " const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];\r", + " for (let playerId = 0; playerId < gamepads.length; playerId++) {\r", + " let gamepad = gamepads[playerId];\r", + " if (gamepad == null) {\r", + " // The gamepad is not connected.\r", + " continue;\r", + " }\r", + " const player = getPlayer(playerId);\r", + " const rumble = player.rumble;\r", + " rumble.elapsedTime += runtimeScene.getElapsedTime(runtimeScene) / 1000;\r", + " if (rumble.duration - rumble.elapsedTime <= 0 &&\r", + " (rumble.weakMagnitude || rumble.strongMagnitude)\r", + " ) {\r", + " rumble.weakMagnitude = 0;\r", + " rumble.strongMagnitude = 0;\r", + " }\r", + " }\r", + "}\r", + "\r", + "/**\r", + " * @param {string} type\r", + " * @param {number} buttonId\r", + " */\r", + "function getInputString(type, buttonId) {\r", + " if (!controllerButtonNames[type]) {\r", + " return \"UNKNOWN_BUTTON\";\r", + " }\r", + " return controllerButtonNames[type][buttonId];\r", + "}\r", + "\r", + "function getButtonId(buttonName) {\r", + " switch (buttonName) {\r", + " case 'A':\r", + " case 'CROSS':\r", + " return 0;\r", + " case 'B':\r", + " case 'CIRCLE':\r", + " return 1;\r", + " case 'X':\r", + " case 'SQUARE':\r", + " return 2;\r", + " case 'Y':\r", + " case 'TRIANGLE':\r", + " return 3;\r", + " case 'LB':\r", + " case 'L1':\r", + " return 4;\r", + " case 'RB':\r", + " case 'R1':\r", + " return 5;\r", + " case 'LT':\r", + " case 'L2':\r", + " return 6;\r", + " case 'RT':\r", + " case 'R2':\r", + " return 7;\r", + " case 'UP':\r", + " return 12;\r", + " case 'DOWN':\r", + " return 13;\r", + " case 'LEFT':\r", + " return 14;\r", + " case 'RIGHT':\r", + " return 15;\r", + " case 'BACK':\r", + " case 'SHARE':\r", + " return 8;\r", + " case 'START':\r", + " case 'OPTIONS':\r", + " return 9;\r", + " case 'CLICK_STICK_LEFT':\r", + " return 10;\r", + " case 'CLICK_STICK_RIGHT':\r", + " return 11;\r", + " //PS4\r", + " case 'PS_BUTTON':\r", + " return 16;\r", + " case 'CLICK_TOUCHPAD':\r", + " return 17;\r", + " default:\r", + " console.error('The gamepad button: ' + buttonName + ' is not valid.');\r", + " return null;\r", + " }\r", + "}\r", + "\r", + "/**\r", + " * @param {number} playerId\r", + " * @param {string} directionName\r", + " * @param {number} axisValueX\r", + " * @param {number} axisValueY\r", + " */\r", + "function isAxisPushed(playerId, directionName, axisValueX, axisValueY) {\r", + " switch (directionName) {\r", + " case 'LEFT':\r", + " return getNormalizedAxisValue(axisValueX, playerId) < 0;\r", + " case 'RIGHT':\r", + " return getNormalizedAxisValue(axisValueX, playerId) > 0;\r", + " case 'UP':\r", + " return getNormalizedAxisValue(axisValueY, playerId) < 0;\r", + " case 'DOWN':\r", + " return getNormalizedAxisValue(axisValueY, playerId) > 0;\r", + " case 'ANY':\r", + " return getNormalizedAxisValue(axisValueX, playerId) < 0\r", + " || getNormalizedAxisValue(axisValueX, playerId) > 0\r", + " || getNormalizedAxisValue(axisValueY, playerId) < 0\r", + " || getNormalizedAxisValue(axisValueY, playerId) > 0\r", + " default:\r", + " console.error('The value stick direction is not valid.');\r", + " return false;\r", + " }\r", + "}\r", + "\r", + "/**\r", + " * @param {number} deltaX\r", + " * @param {number} deltaY\r", + " */\r", + "function axisToAngle(deltaX, deltaY) {\r", + " const rad = Math.atan2(deltaY, deltaX);\r", + " const deg = rad * (180 / Math.PI);\r", + " return deg;\r", + "}\r", + "\r", + "/**\r", + " * @param {{id: string}} gamepad\r", + " */\r", + "function isXbox(gamepad) {\r", + " return (gamepad ? (\r", + " gamepad.id.toUpperCase().indexOf(\"XBOX\") !== -1\r", + " // \"XINPUT\" cannot be used to check if it is a xbox controller is just a generic\r", + " // name reported in Firefox corresponding to the driver being used by the controller\r", + " // https://gamefaqs.gamespot.com/boards/916373-pc/73341312?page=1\r", + " ) : false);\r", + "}\r", + "\r", + "/**\r", + " * Returns the new value taking into account the dead zone for the player_ID given\r", + " * @param {number} value\r", + " * @param {number} playerID\r", + " */\r", + "function getNormalizedAxisValue(value, playerID) {\r", + " // gdjs._extensionController = gdjs._extensionController || { deadzone: 0.2 };\r", + "\r", + " // Anything smaller than this is assumed to be 0,0\r", + " const deadzone = getPlayer(playerID).deadzone;\r", + "\r", + " if (Math.abs(value) < deadzone) {\r", + " return 0;\r", + " } else {\r", + " // We're outside the dead zone, but we'd like to smooth\r", + " // this value out so it still runs nicely between 0..1.\r", + " // That is, we don't want it to jump suddenly from 0 to\r", + " // deadzone.\r", + "\r", + " // Remap value from\r", + " // deadzone..1 to 0..(1-deadzone)\r", + " // or from\r", + " // -1..-deadzone to -(1-deadzone)..0\r", + " value = value - Math.sign(value) * deadzone;\r", + "\r", + " // Remap value from\r", + " // 0..(1-deadzone) to 0..1\r", + " // or from\r", + " // -(1-deadzone)..0 to -1..0\r", + " return value / (1 - deadzone);\r", + " }\r", + "}\r", + "\r", + "gdjs._extensionController = {\r", + " getPlayer,\r", + " controllerButtonNames,\r", + " getInputString,\r", + " getButtonId,\r", + " axisToAngle,\r", + " isXbox,\r", + " getNormalizedAxisValue,\r", + " isAxisPushed,\r", + " getGamepad,\r", + " onScenePostEvents,\r", + " frameBeginningTask,\r", + " addFrameBeginningTaskIfNeeded,\r", + "}" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onSceneLoaded", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": "gdjs._extensionController.addFrameBeginningTaskIfNeeded(runtimeScene);", + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onScenePostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "gdjs._extensionController.onScenePostEvents(runtimeScene);", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "fullName": "Accelerated speed", + "functionType": "Expression", + "name": "AcceleratedSpeed", + "private": true, + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "AcceleratedSpeed", + "=", + "CurrentSpeed" + ] + } + ], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TargetedSpeed", + "<", + "0" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Reduce the speed to match the stick force." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "CurrentSpeed", + "<", + "TargetedSpeed" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "AcceleratedSpeed", + "=", + "min(TargetedSpeed, CurrentSpeed + Acceleration * TimeDelta())" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "CurrentSpeed", + ">", + "TargetedSpeed" + ] + }, + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "CurrentSpeed", + "<", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "AcceleratedSpeed", + "-", + "Acceleration * TimeDelta()" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Turn back at least as fast as it would stop." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "CurrentSpeed", + ">=", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "AcceleratedSpeed", + "=", + "max(TargetedSpeed, CurrentSpeed - max(Acceleration , Deceleration) * TimeDelta())" + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TargetedSpeed", + ">", + "0" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Reduce the speed to match the stick force." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "CurrentSpeed", + ">", + "TargetedSpeed" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "AcceleratedSpeed", + "=", + "max(TargetedSpeed, CurrentSpeed - Acceleration * TimeDelta())" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "CurrentSpeed", + "<", + "TargetedSpeed" + ] + }, + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "CurrentSpeed", + ">", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "AcceleratedSpeed", + "+", + "Acceleration * TimeDelta()" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Turn back at least as fast as it would stop." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "CurrentSpeed", + "<=", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "AcceleratedSpeed", + "=", + "min(TargetedSpeed, CurrentSpeed + max(Acceleration , Deceleration) * TimeDelta())" + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TargetedSpeed", + "=", + "0" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "CurrentSpeed", + "<", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "AcceleratedSpeed", + "=", + "min(0, CurrentSpeed + Acceleration * TimeDelta())" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "CurrentSpeed", + ">", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "AcceleratedSpeed", + "=", + "max(0, CurrentSpeed - Acceleration * TimeDelta())" + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "clamp(AcceleratedSpeed, -SpeedMax, SpeedMax)" + ] + } + ] + } + ], + "variables": [ + { + "name": "AcceleratedSpeed", + "type": "number", + "value": 0 + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Current speed", + "name": "CurrentSpeed", + "type": "expression" + }, + { + "description": "Targeted speed", + "name": "TargetedSpeed", + "type": "expression" + }, + { + "description": "Max speed", + "name": "SpeedMax", + "type": "expression" + }, + { + "description": "Acceleration", + "name": "Acceleration", + "type": "expression" + }, + { + "description": "Deceleration", + "name": "Deceleration", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Get the value of the pressure on a gamepad trigger.", + "fullName": "Pressure on a gamepad trigger", + "functionType": "Expression", + "name": "TriggerPressure", + "sentence": "Player _PARAM1_ push axis _PARAM2_ to _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "const trigger = eventsFunctionContext.getArgument(\"Trigger\").toUpperCase();\r", + "\r", + "if (trigger != \"LT\" && trigger != \"RT\" && trigger != \"L2\" && trigger != \"R2\") {\r", + " console.error('Parameter trigger is not valid in expression: \"Pressure on a gamepad trigger\"');\r", + " return;\r", + "}\r", + "/** @type {Gamepad} */\r", + "const gamepad = gdjs._extensionController.getGamepad(playerId);\r", + "if (!gamepad) {\r", + " // The gamepad is not connected.\r", + " return;\r", + "}\r", + "switch (trigger) {\r", + " case 'LT':\r", + " case 'L2':\r", + " eventsFunctionContext.returnValue = gamepad.buttons[6].value;\r", + " break;\r", + "\r", + " case 'RT':\r", + " case 'R2':\r", + " eventsFunctionContext.returnValue = gamepad.buttons[7].value;\r", + " break;\r", + "\r", + " default:\r", + " eventsFunctionContext.returnValue = -1;\r", + " break;\r", + "}" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + }, + { + "description": "Trigger button", + "name": "Trigger", + "supplementaryInformation": "[\"LT\",\"RT\",\"L2\",\"R2\"]", + "type": "stringWithSelector" + } + ], + "objectGroups": [] + }, + { + "description": "the force of gamepad stick (from 0 to 1).", + "fullName": "Stick force", + "functionType": "ExpressionAndCondition", + "name": "StickForce", + "sentence": "the gamepad _PARAM1_ _PARAM2_ stick force", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { getNormalizedAxisValue } = gdjs._extensionController;\r", + "\r", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "const stick = eventsFunctionContext.getArgument(\"Stick\").toUpperCase();\r", + "\r", + "if (stick !== \"LEFT\" && stick !== \"RIGHT\") {\r", + " console.error('Parameter stick is not valid in expression: \"Value of a stick force\"');\r", + " return;\r", + "}\r", + "/** @type {Gamepad} */\r", + "const gamepad = gdjs._extensionController.getGamepad(playerId);\r", + "if (!gamepad) {\r", + " // The gamepad is not connected.\r", + " return;\r", + "}\r", + "const axisValueX = stick === 'RIGHT' ? gamepad.axes[2] : gamepad.axes[0];\r", + "const axisValueY = stick === 'RIGHT' ? gamepad.axes[3] : gamepad.axes[1];\r", + "\r", + "eventsFunctionContext.returnValue = gdjs.evtTools.common.clamp(\r", + " Math.abs(getNormalizedAxisValue(axisValueX, playerId)) +\r", + " Math.abs(getNormalizedAxisValue(axisValueY, playerId)), 0, 1);\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + }, + { + "description": "Stick: \"Left\" or \"Right\"", + "name": "Stick", + "supplementaryInformation": "[\"Left\",\"Right\"]", + "type": "stringWithSelector" + } + ], + "objectGroups": [] + }, + { + "description": "Get the rotation value of a gamepad stick.\nIf the deadzone value is high, the angle value is rounded to main axes, left, left, up, down.\nAn zero deadzone value give a total freedom on the angle value.", + "fullName": "Value of a stick rotation (deprecated)", + "functionType": "Expression", + "name": "StickRotationValue", + "private": true, + "sentence": "Player _PARAM1_ push axis _PARAM2_ to _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "Gamepads::StickAngle(PlayerId, Stick)" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + }, + { + "description": "Stick: \"Left\" or \"Right\"", + "name": "Stick", + "supplementaryInformation": "[\"Left\",\"Right\"]", + "type": "stringWithSelector" + } + ], + "objectGroups": [] + }, + { + "description": "Return the angle of a gamepad stick.\nIf the deadzone value is high, the angle value is rounded to main axes, left, left, up, down.\nAn zero deadzone value give a total freedom on the angle value.", + "fullName": "Stick angle", + "functionType": "Expression", + "name": "StickAngle", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { getNormalizedAxisValue } = gdjs._extensionController;\r", + "\r", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "const stick = eventsFunctionContext.getArgument(\"Stick\").toUpperCase();\r", + "\r", + "if (stick !== \"LEFT\" && stick !== \"RIGHT\") {\r", + " console.error('Parameter stick is not valid in expression: \"Value of a stick rotation\"');\r", + " return;\r", + "}\r", + "/** @type {Gamepad} */\r", + "const gamepad = gdjs._extensionController.getGamepad(playerId);\r", + "if (!gamepad) {\r", + " // The gamepad is not connected.\r", + " return;\r", + "}\r", + "const axisValueX = stick === 'RIGHT' ? gamepad.axes[2] : gamepad.axes[0];\r", + "const axisValueY = stick === 'RIGHT' ? gamepad.axes[3] : gamepad.axes[1];\r", + "\r", + "eventsFunctionContext.returnValue = gdjs._extensionController.axisToAngle(\r", + " getNormalizedAxisValue(axisValueX, playerId),\r", + " getNormalizedAxisValue(axisValueY, playerId));" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + }, + { + "description": "Stick: \"Left\" or \"Right\"", + "name": "Stick", + "supplementaryInformation": "[\"Left\",\"Right\"]", + "type": "stringWithSelector" + } + ], + "objectGroups": [] + }, + { + "description": "Get the value of axis of a gamepad stick.", + "fullName": "Value of a gamepad axis (deprecated)", + "functionType": "Expression", + "name": "AxisValue", + "private": true, + "sentence": "Player _PARAM1_ push axis _PARAM2_ to _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "const stick = eventsFunctionContext.getArgument(\"stick\").toUpperCase();\r", + "const direction = eventsFunctionContext.getArgument(\"direction\").toUpperCase();\r", + "\r", + "if (stick != \"LEFT\" && stick != \"RIGHT\") {\r", + " console.error('Parameter stick is not valid in expression: \"Value of a gamepad axis\"');\r", + " return;\r", + "}\r", + "if (direction != \"UP\" && direction != \"DOWN\" && direction != \"LEFT\" && direction != \"RIGHT\" && direction != \"HORIZONTAL\" && direction != \"VERTICAL\") {\r", + " console.error('Parameter direction is not valid in expression: \"Value of a gamepad axis\"');\r", + " return;\r", + "}\r", + "/** @type {Gamepad} */\r", + "const gamepad = gdjs._extensionController.getGamepad(playerId);\r", + "if (!gamepad) {\r", + " // The gamepad is not connected.\r", + " return;\r", + "}\r", + "let parameterError = false;\r", + "switch (stick) {\r", + " case 'LEFT':\r", + " switch (direction) {\r", + " case 'LEFT':\r", + " if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[0], playerId) < 0) {\r", + " eventsFunctionContext.returnValue = -gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[0], playerId);\r", + " }\r", + " break;\r", + "\r", + " case 'RIGHT':\r", + " if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[0], playerId) > 0) {\r", + " eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[0], playerId);\r", + " }\r", + " break;\r", + "\r", + " case 'UP':\r", + " if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[1], playerId) < 0) {\r", + " eventsFunctionContext.returnValue = -gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[1], playerId);\r", + " }\r", + " break;\r", + "\r", + " case 'DOWN':\r", + " if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[1], playerId) > 0) {\r", + " eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[1], playerId);\r", + " }\r", + " break;\r", + "\r", + " case \"HORIZONTAL\":\r", + " eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[0], playerId);\r", + " break;\r", + "\r", + " case \"VERTICAL\":\r", + " eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[1], playerId);\r", + " break;\r", + "\r", + " default:\r", + " break;\r", + " }\r", + " break;\r", + "\r", + " case 'RIGHT':\r", + " switch (direction) {\r", + " case 'LEFT':\r", + " if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[2], playerId) < 0) {\r", + " eventsFunctionContext.returnValue = -gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[2], playerId);\r", + " }\r", + " break;\r", + "\r", + " case 'RIGHT':\r", + " if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[2], playerId) > 0) {\r", + " eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[2], playerId);\r", + " }\r", + " break;\r", + "\r", + " case 'UP':\r", + " if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[3], playerId) < 0) {\r", + " eventsFunctionContext.returnValue = -gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[3], playerId);\r", + " }\r", + " break;\r", + "\r", + " case 'DOWN':\r", + " if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[3], playerId) > 0) {\r", + " eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[3], playerId);\r", + " }\r", + " break;\r", + "\r", + " case \"HORIZONTAL\":\r", + " eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[2], playerId);\r", + " break;\r", + "\r", + " case \"VERTICAL\":\r", + " eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[3], playerId);\r", + " break;\r", + "\r", + " default:\r", + " break;\r", + " }\r", + " break;\r", + "\r", + " default:\r", + " break;\r", + "}\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + }, + { + "description": "Stick: \"Left\" or \"Right\"", + "name": "stick", + "supplementaryInformation": "[\"Left\",\"Right\"]", + "type": "stringWithSelector" + }, + { + "description": "Direction", + "name": "direction", + "supplementaryInformation": "[\"Up\",\"Down\",\"Left\",\"Right\",\"Horizontal\",\"Vertical\"]", + "type": "stringWithSelector" + } + ], + "objectGroups": [] + }, + { + "description": "Return the gamepad stick force on X axis (from -1 at the left to 1 at the right).", + "fullName": "Stick X force", + "functionType": "Expression", + "name": "StickForceX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const playerId = eventsFunctionContext.getArgument(\"Gamepad\") - 1;\r", + "const stick = eventsFunctionContext.getArgument(\"Stick\").toLowerCase();\r", + "\r", + "if (stick != \"left\" && stick != \"right\") {\r", + " console.error('Parameter stick is not valid in expression: \"Value of a gamepad axis\"');\r", + " return;\r", + "}\r", + "/** @type {Gamepad} */\r", + "const gamepad = gdjs._extensionController.getGamepad(playerId);\r", + "if (!gamepad) {\r", + " // The gamepad is not connected.\r", + " return;\r", + "}\r", + "const axisIndex = stick === 'right' ? 2 : 0;\r", + "eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[axisIndex], playerId);\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "Gamepad", + "type": "expression" + }, + { + "description": "Stick: \"Left\" or \"Right\"", + "name": "Stick", + "supplementaryInformation": "[\"Left\",\"Right\"]", + "type": "stringWithSelector" + } + ], + "objectGroups": [] + }, + { + "description": "Return the gamepad stick force on Y axis (from -1 at the top to 1 at the bottom).", + "fullName": "Stick Y force", + "functionType": "Expression", + "name": "StickForceY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const playerId = eventsFunctionContext.getArgument(\"Gamepad\") - 1;\r", + "const stick = eventsFunctionContext.getArgument(\"Stick\").toLowerCase();\r", + "\r", + "if (stick != \"left\" && stick != \"right\") {\r", + " console.error('Parameter stick is not valid in expression: \"Value of a gamepad axis\"');\r", + " return;\r", + "}\r", + "/** @type {Gamepad} */\r", + "const gamepad = gdjs._extensionController.getGamepad(playerId);\r", + "if (!gamepad) {\r", + " // The gamepad is not connected.\r", + " return;\r", + "}\r", + "const axisIndex = stick === 'right' ? 3 : 1;\r", + "eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[axisIndex], playerId);\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "Gamepad", + "type": "expression" + }, + { + "description": "Stick: \"Left\" or \"Right\"", + "name": "Stick", + "supplementaryInformation": "[\"Left\",\"Right\"]", + "type": "stringWithSelector" + } + ], + "objectGroups": [] + }, + { + "description": "Test if a button is released on a gamepad. Buttons can be:\n* Xbox: \"A\", \"B\", \"X\", \"Y\", \"LB\", \"RB\", \"LT\", \"RT\", \"BACK\", \"START\",\n* PS4: \"CROSS\", \"SQUARE\", \"CIRCLE\", \"TRIANGLE\", \"L1\", \"L2\", \"R1\", \"R2\", \"SHARE\", \"OPTIONS\", \"PS_BUTTON\", \"CLICK_TOUCHPAD\",\n* Other: \"UP\", \"DOWN\", \"LEFT\", \"RIGHT\", \"CLICK_STICK_LEFT\", \"CLICK_STICK_RIGHT\".", + "fullName": "Gamepad button released", + "functionType": "Condition", + "name": "C_Button_released", + "sentence": "Button _PARAM2_ of gamepad _PARAM1_ is released", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "const button = eventsFunctionContext.getArgument(\"Button\").toUpperCase();\r", + "\r", + "let buttonId = gdjs._extensionController.getButtonId(button);\r", + "if (buttonId === null) {\r", + " return;\r", + "}\r", + "const player = gdjs._extensionController.getPlayer(playerId)\r", + "eventsFunctionContext.returnValue = player.isButtonReleased(buttonId);" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + }, + { + "description": "Name of the button", + "name": "Button", + "supplementaryInformation": "[\"A\",\"Cross\",\"B\",\"Circle\",\"X\",\"Square\",\"Y\",\"Triangle\",\"LB\",\"L1\",\"RB\",\"R1\",\"LT\",\"L2\",\"RT\",\"R2\",\"Up\",\"Down\",\"Left\",\"Right\",\"Back\",\"Share\",\"Start\",\"Options\",\"Click_Stick_Left\",\"Click_Stick_Right\",\"PS_Button\",\"Click_Touchpad\"]", + "type": "stringWithSelector" + } + ], + "objectGroups": [] + }, + { + "description": "Check if a button was just pressed on a gamepad. Buttons can be:\n* Xbox: \"A\", \"B\", \"X\", \"Y\", \"LB\", \"RB\", \"LT\", \"RT\", \"BACK\", \"START\",\n* PS4: \"CROSS\", \"SQUARE\", \"CIRCLE\", \"TRIANGLE\", \"L1\", \"L2\", \"R1\", \"R2\", \"SHARE\", \"OPTIONS\", \"PS_BUTTON\", \"CLICK_TOUCHPAD\",\n* Other: \"UP\", \"DOWN\", \"LEFT\", \"RIGHT\", \"CLICK_STICK_LEFT\", \"CLICK_STICK_RIGHT\".", + "fullName": "Gamepad button just pressed", + "functionType": "Condition", + "name": "IsButtonJustPressed", + "sentence": "Button _PARAM2_ of gamepad _PARAM1_ was just pressed", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "const button = eventsFunctionContext.getArgument(\"Button\").toUpperCase();\r", + "\r", + "let buttonId = gdjs._extensionController.getButtonId(button);\r", + "if (buttonId === null) {\r", + " return;\r", + "}\r", + "const player = gdjs._extensionController.getPlayer(playerId)\r", + "eventsFunctionContext.returnValue = player.isButtonJustPressed(buttonId);" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + }, + { + "description": "Name of the button", + "name": "Button", + "supplementaryInformation": "[\"A\",\"Cross\",\"B\",\"Circle\",\"X\",\"Square\",\"Y\",\"Triangle\",\"LB\",\"L1\",\"RB\",\"R1\",\"LT\",\"L2\",\"RT\",\"R2\",\"Up\",\"Down\",\"Left\",\"Right\",\"Back\",\"Share\",\"Start\",\"Options\",\"Click_Stick_Left\",\"Click_Stick_Right\",\"PS_Button\",\"Click_Touchpad\"]", + "type": "stringWithSelector" + } + ], + "objectGroups": [] + }, + { + "description": "Return the index of the last pressed button of a gamepad.", + "fullName": "Last pressed button (id)", + "functionType": "Expression", + "name": "LastButtonID", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "eventsFunctionContext.returnValue = gdjs._extensionController.getPlayer(playerId).lastButtonUsed;" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if any button is pressed on a gamepad.", + "fullName": "Any gamepad button pressed", + "functionType": "Condition", + "name": "C_Any_Button_pressed", + "sentence": "Any button of gamepad _PARAM1_ is pressed", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "const player = gdjs._extensionController.getPlayer(playerId)\r", + "eventsFunctionContext.returnValue = player.isAnyButtonPressed();\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Return the last button pressed. \nButtons for Xbox and PS4 can be:\n* Xbox: \"A\", \"B\", \"X\", \"Y\", \"LB\", \"RB\", \"LT\", \"RT\", \"BACK\", \"START\",\n* PS4: \"CROSS\", \"SQUARE\", \"CIRCLE\", \"TRIANGLE\", \"L1\", \"L2\", \"R1\", \"R2\", \"SHARE\", \"OPTIONS\", \"PS_BUTTON\", \"CLICK_TOUCHPAD\",\n* Both: \"UP\", \"DOWN\", \"LEFT\", \"RIGHT\", \"CLICK_STICK_LEFT\", \"CLICK_STICK_RIGHT\".", + "fullName": "Last pressed button (string)", + "functionType": "StringExpression", + "name": "LastButtonString", + "sentence": "Button _PARAM2_ of gamepad _PARAM1_ is pressed", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "const controllerType = eventsFunctionContext.getArgument(\"controller_type\").toUpperCase();\r", + "/** @type {Gamepad} */\r", + "const gamepad = gdjs._extensionController.getGamepad(playerId);\r", + "if (!gamepad) {\r", + " // The gamepad is not connected.\r", + " return;\r", + "}\r", + "const lastButtonUsedID = gdjs._extensionController.getPlayer(playerId).lastButtonUsed;\r", + "eventsFunctionContext.returnValue = gdjs._extensionController.getInputString(controllerType, lastButtonUsedID);\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "expressionType": { + "type": "string" + }, + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + }, + { + "description": "Controller type", + "name": "controller_type", + "supplementaryInformation": "[\"Xbox\",\"PS4\"]", + "type": "stringWithSelector" + } + ], + "objectGroups": [] + }, + { + "description": "Return the number of gamepads.", + "fullName": "Gamepad count", + "functionType": "Expression", + "name": "GamepadCount", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];\r", + "let lastGamepadIndex = -1;\r", + "for (let playerId = 0; playerId < gamepads.length; playerId++) {\r", + " // Gamepads can be disconnected and become null\r", + " if (gamepads[playerId]) {\r", + " lastGamepadIndex = playerId\r", + " }\r", + "}\r", + "eventsFunctionContext.returnValue = lastGamepadIndex + 1;" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [], + "objectGroups": [] + }, + { + "description": "Check if a button is pressed on a gamepad. \nButtons can be:\n* Xbox: \"A\", \"B\", \"X\", \"Y\", \"LB\", \"RB\", \"LT\", \"RT\", \"BACK\", \"START\",\n* PS4: \"CROSS\", \"SQUARE\", \"CIRCLE\", \"TRIANGLE\", \"L1\", \"L2\", \"R1\", \"R2\", \"SHARE\", \"OPTIONS\", \"PS_BUTTON\", \"CLICK_TOUCHPAD\",\n* Other: \"UP\", \"DOWN\", \"LEFT\", \"RIGHT\", \"CLICK_STICK_LEFT\", \"CLICK_STICK_RIGHT\".", + "fullName": "Gamepad button pressed", + "functionType": "Condition", + "name": "C_Button_pressed", + "sentence": "Button _PARAM2_ of gamepad _PARAM1_ is pressed", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "const button = eventsFunctionContext.getArgument(\"button\").toUpperCase();\r", + "\r", + "const buttonId = gdjs._extensionController.getButtonId(button);\r", + "if (buttonId === null) {\r", + " return;\r", + "}\r", + "const player = gdjs._extensionController.getPlayer(playerId)\r", + "eventsFunctionContext.returnValue = player.isButtonPressed(buttonId);\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + }, + { + "description": "Name of the button", + "name": "button", + "supplementaryInformation": "[\"A\",\"Cross\",\"B\",\"Circle\",\"X\",\"Square\",\"Y\",\"Triangle\",\"LB\",\"L1\",\"RB\",\"R1\",\"LT\",\"L2\",\"RT\",\"R2\",\"Up\",\"Down\",\"Left\",\"Right\",\"Back\",\"Share\",\"Start\",\"Options\",\"Click_Stick_Left\",\"Click_Stick_Right\",\"PS_Button\",\"Click_Touchpad\"]", + "type": "stringWithSelector" + } + ], + "objectGroups": [] + }, + { + "description": "Return the value of the deadzone applied to a gamepad sticks, between 0 and 1.", + "fullName": "Gamepad deadzone for sticks", + "functionType": "Expression", + "name": "Deadzone", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "eventsFunctionContext.returnValue = gdjs._extensionController.getPlayer(playerId).deadzone;" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Set the deadzone for sticks of the gamepad. The deadzone is an area for which movement on sticks won't be taken into account (instead, the stick will be considered as not moved). Deadzone is between 0 and 1, and is by default 0.2.", + "fullName": "Set gamepad deadzone for sticks", + "functionType": "Action", + "name": "A_Set_deadzone", + "sentence": "Set deadzone for sticks on gamepad: _PARAM1_ to _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "const newDeadzone = eventsFunctionContext.getArgument(\"deadzone\");\r", + "\r", + "// https://github.com/4ian/GDevelop-extensions/pull/33#issuecomment-618224857\r", + "gdjs._extensionController.getPlayer(playerId).deadzone = gdjs.evtTools.common.clamp(newDeadzone, 0, 1);\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + }, + { + "description": "Deadzone for sticks, 0.2 by default (0 to 1)", + "name": "deadzone", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if a stick of a gamepad is pushed in a given direction.", + "fullName": "Gamepad stick pushed (axis)", + "functionType": "Condition", + "name": "C_Axis_pushed", + "sentence": "_PARAM2_ stick of gamepad _PARAM1_ is pushed in direction _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "const stick = eventsFunctionContext.getArgument(\"stick\").toUpperCase();\r", + "const direction = eventsFunctionContext.getArgument(\"direction\").toUpperCase();\r", + "\r", + "if (stick != \"LEFT\" && stick != \"RIGHT\") {\r", + " console.error('Parameter stick in condition: \"Gamepad stick pushed (axis)\", is not valid, must be LEFT or RIGHT');\r", + " return;\r", + "}\r", + "if (direction != \"UP\" && direction != \"DOWN\" && direction != \"LEFT\" && direction != \"RIGHT\" && direction != \"ANY\") {\r", + " console.error('Parameter direction in condition: \"Gamepad stick pushed (axis)\", is not valid, must be UP, DOWN, LEFT or RIGHT');\r", + " return;\r", + "}\r", + "/** @type {Gamepad} */\r", + "const gamepad = gdjs._extensionController.getGamepad(playerId);\r", + "if (!gamepad) {\r", + " // The gamepad is not connected.\r", + " return;\r", + "}\r", + "const axisValueX = stick === 'RIGHT' ? gamepad.axes[2] : gamepad.axes[0];\r", + "const axisValueY = stick === 'RIGHT' ? gamepad.axes[3] : gamepad.axes[1];\r", + "eventsFunctionContext.returnValue = gdjs._extensionController.isAxisPushed(playerId, direction, axisValueX, axisValueY);\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + }, + { + "description": "Stick: \"Left\" or \"Right\"", + "name": "stick", + "supplementaryInformation": "[\"Left\",\"Right\"]", + "type": "stringWithSelector" + }, + { + "description": "Direction", + "name": "direction", + "supplementaryInformation": "[\"Up\",\"Down\",\"Left\",\"Right\",\"Any\"]", + "type": "stringWithSelector" + } + ], + "objectGroups": [] + }, + { + "description": "Return the number of connected gamepads.", + "fullName": "Connected gamepads count", + "functionType": "Expression", + "name": "ConnectedGamepadsCount", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];\r", + "let connectedGamepadCount = 0;\r", + "for (let playerId = 0; playerId < gamepads.length; playerId++) {\r", + " // Gamepads can be disconnected and become null\r", + " if (gamepads[playerId]) {\r", + " connectedGamepadCount++;\r", + " }\r", + "}\r", + "eventsFunctionContext.returnValue = connectedGamepadCount;\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [], + "objectGroups": [] + }, + { + "description": "Return a string containing informations about the specified gamepad.", + "fullName": "Gamepad type", + "functionType": "StringExpression", + "name": "GamepadType", + "sentence": "Player _PARAM1_ use _PARAM2_ controller", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;", + "/** @type {Gamepad} */", + "const gamepad = gdjs._extensionController.getGamepad(playerId);", + "if (!gamepad) {", + " // The gamepad is not connected.", + " return;", + "}", + "eventsFunctionContext.returnValue = (gamepad && gamepad.id) ? gamepad.id : \"No information for player \" + (playerId + 1)", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "expressionType": { + "type": "string" + }, + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if the specified gamepad has the specified information in its description. Useful to know if the gamepad is a Xbox or PS4 controller.", + "fullName": "Gamepad type", + "functionType": "Condition", + "name": "C_Controller_type", + "sentence": "Gamepad _PARAM1_ is a _PARAM2_ controller", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;", + "const controllerType = eventsFunctionContext.getArgument(\"controller_type\").toUpperCase();", + "/** @type {Gamepad} */", + "const gamepad = gdjs._extensionController.getGamepad(playerId);", + "if (!gamepad) {", + " // The gamepad is not connected.", + " return;", + "}", + "if (controllerType == \"XBOX\") {", + " eventsFunctionContext.returnValue = gdjs._extensionController.isXbox(gamepad);", + "} else {", + " eventsFunctionContext.returnValue = gamepad ? gamepad.id.toUpperCase().indexOf(controllerType) !== -1 : false;", + "}" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + }, + { + "description": "Type: \"Xbox\", \"PS4\", \"Steam\" or \"PS3\" (among other)", + "name": "controller_type", + "type": "string" + } + ], + "objectGroups": [] + }, + { + "description": "Check if a gamepad is connected.", + "fullName": "Gamepad connected", + "functionType": "Condition", + "name": "C_Controller_X_is_connected", + "sentence": "Gamepad _PARAM1_ is plugged and connected", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;", + "/** @type {Gamepad[]} */", + "const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];", + "// If gamepad was disconnected it will be null (so this will return false)", + "// If gamepad was never connected it will be undefined (so this will return false)", + "eventsFunctionContext.returnValue = !!gamepads[playerId];" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Generate a vibration on the specified controller. Might only work if the game is running in a recent web browser.", + "fullName": "Gamepad vibration", + "functionType": "Action", + "name": "A_Vibrate_controller", + "sentence": "Make gamepad _PARAM1_ vibrate for _PARAM2_ seconds", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;", + "const duration = eventsFunctionContext.getArgument(\"Duration\") || 1;", + "/** @type {Gamepad} */", + "const gamepad = gdjs._extensionController.getGamepad(playerId);", + "if (!gamepad) {", + " // The gamepad is not connected.", + " return;", + "}", + "//Vibration work only on game in browser.", + "if (gamepad.vibrationActuator) {", + " gamepad.vibrationActuator.playEffect(\"dual-rumble\", {", + " startDelay: 0,", + " duration: duration * 1000,", + " weakMagnitude: 1.0,", + " strongMagnitude: 1.0", + " });", + "}" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + }, + { + "description": "Time of the vibration, in seconds (optional, default value is 1)", + "name": "Duration", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Generate an advanced vibration on the specified controller. Incompatible with Firefox.", + "fullName": "Advanced gamepad vibration", + "functionType": "Action", + "name": "A_Advanced_Vibration_Controller", + "sentence": "Make gamepad _PARAM1_ vibrate for _PARAM2_ seconds with the vibration magnitude of _PARAM3_ and _PARAM4_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { clamp } = gdjs.evtTools.common;", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;", + "const duration = eventsFunctionContext.getArgument(\"Duration\") || 1;", + "const strongRumbleMagnitude = clamp(eventsFunctionContext.getArgument(\"StrongMagnitude\"), 0, 1);", + "const weakRumbleMagnitude = clamp(eventsFunctionContext.getArgument(\"WeakMagnitude\"), 0, 1);", + "/** @type {Gamepad} */", + "const gamepad = gdjs._extensionController.getGamepad(playerId);", + "if (!gamepad) {", + " // The gamepad is not connected.", + " return;", + "}", + "//Vibration work only on game in browser.", + "if (gamepad.vibrationActuator) {", + " gamepad.vibrationActuator.playEffect(\"dual-rumble\", {", + " startDelay: 0,", + " duration: duration * 1000,", + " weakMagnitude: weakRumbleMagnitude,", + " strongMagnitude: strongRumbleMagnitude", + " });", + "}", + "const player = gdjs._extensionController.getPlayer(playerId)", + "player.rumble.duration = duration;", + "player.rumble.elapsedTime = 0;", + "player.rumble.weakMagnitude = weakRumbleMagnitude;", + "player.rumble.strongMagnitude = strongRumbleMagnitude;" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + }, + { + "description": "Time of the vibration, in seconds (optional, default value is 1)", + "name": "Duration", + "type": "expression" + }, + { + "description": "Strong rumble magnitude (from 0 to 1)", + "name": "StrongMagnitude", + "type": "expression" + }, + { + "description": "Weak rumble magnitude (from 0 to 1)", + "name": "WeakMagnitude", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Change a vibration on the specified controller. Incompatible with Firefox.", + "fullName": "Change gamepad active vibration", + "functionType": "Action", + "name": "A_Change_Vibration_Magnitude", + "sentence": "Change the vibration magnitude of _PARAM2_ & _PARAM3_ on gamepad _PARAM1_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { clamp } = gdjs.evtTools.common;", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;", + "const player = gdjs._extensionController.getPlayer(playerId);", + "const elapsedTime = player.rumble.elapsedTime || 0;", + "const originalDuration = player.rumble.duration || 1;", + "const strongRumbleMagnitude = clamp(eventsFunctionContext.getArgument(\"StrongMagnitude\"), 0, 1);", + "const weakRumbleMagnitude = clamp(eventsFunctionContext.getArgument(\"WeakMagnitude\"), 0, 1);", + "/** @type {Gamepad} */", + "const gamepad = gdjs._extensionController.getGamepad(playerId);", + "if (!gamepad) {", + " // The gamepad is not connected.", + " return;", + "}", + "if (originalDuration - elapsedTime <= 0) return;", + "//Vibration work only on game in browser.", + "if (gamepad.vibrationActuator) {", + " gamepad.vibrationActuator.playEffect(\"dual-rumble\", {", + " startDelay: 0,", + " duration: 1000 * (originalDuration - elapsedTime),", + " weakMagnitude: weakRumbleMagnitude,", + " strongMagnitude: strongRumbleMagnitude", + " });", + "}", + "", + "player.rumble.weakMagnitude = weakRumbleMagnitude;", + "player.rumble.strongMagnitude = strongRumbleMagnitude;" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + }, + { + "description": "Strong rumble magnitude (from 0 to 1)", + "name": "StrongMagnitude", + "type": "expression" + }, + { + "description": "Weak rumble magnitude (from 0 to 1)", + "name": "WeakMagnitude", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if any button is released on a gamepad.", + "fullName": "Any gamepad button released", + "functionType": "Condition", + "name": "C_any_button_released", + "sentence": "Any button of gamepad _PARAM1_ is released", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "\r", + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "const player = gdjs._extensionController.getPlayer(playerId)\r", + "eventsFunctionContext.returnValue = player.isAnyButtonReleased();" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Return the strength of the weak vibration motor on the gamepad of a player.", + "fullName": "Weak rumble magnitude", + "functionType": "Expression", + "name": "WeakVibrationMagnitude", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "eventsFunctionContext.returnValue = gdjs._extensionController.getPlayer(playerId).rumble.weakMagnitude;" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Return the strength of the strong vibration motor on the gamepad of a player.", + "fullName": "Strong rumble magnitude", + "functionType": "Expression", + "name": "StrongVibrationMagnitude", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r", + "eventsFunctionContext.returnValue = gdjs._extensionController.getPlayer(playerId).rumble.strongMagnitude;" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "The gamepad identifier: 1, 2, 3 or 4", + "name": "PlayerId", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onFirstSceneLoaded" + }, + { + "functionName": "onSceneLoaded" + }, + { + "functionName": "onScenePostEvents" + }, + { + "functionName": "AcceleratedSpeed" + }, + { + "functionName": "TriggerPressure" + }, + { + "functionName": "StickForce" + }, + { + "functionName": "StickRotationValue" + }, + { + "functionName": "StickAngle" + }, + { + "functionName": "AxisValue" + }, + { + "functionName": "StickForceX" + }, + { + "functionName": "StickForceY" + }, + { + "functionName": "C_Button_released" + }, + { + "functionName": "IsButtonJustPressed" + }, + { + "functionName": "LastButtonID" + }, + { + "functionName": "C_Any_Button_pressed" + }, + { + "functionName": "LastButtonString" + }, + { + "functionName": "GamepadCount" + }, + { + "functionName": "C_Button_pressed" + }, + { + "functionName": "Deadzone" + }, + { + "functionName": "A_Set_deadzone" + }, + { + "functionName": "C_Axis_pushed" + }, + { + "functionName": "ConnectedGamepadsCount" + }, + { + "functionName": "GamepadType" + }, + { + "functionName": "C_Controller_type" + }, + { + "functionName": "C_Controller_X_is_connected" + }, + { + "functionName": "A_Vibrate_controller" + }, + { + "functionName": "A_Advanced_Vibration_Controller" + }, + { + "functionName": "A_Change_Vibration_Magnitude" + }, + { + "functionName": "C_any_button_released" + }, + { + "functionName": "WeakVibrationMagnitude" + }, + { + "functionName": "StrongVibrationMagnitude" + } + ] + }, + "eventsBasedBehaviors": [ + { + "description": "Control a platformer character with a gamepad.", + "fullName": "Platformer gamepad mapper", + "helpPath": "", + "iconUrl": "", + "name": "PlatformerGamepadMapper", + "objectType": "", + "previewIconUrl": "", + "quickCustomizationVisibility": "hidden", + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "doStepPreEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Controller_X_is_connected" + }, + "parameters": [ + "", + "GamepadIdentifier", + "" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BooleanVariable" + }, + "parameters": [ + "UseArrows", + "True", + "" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Left\"", + "\"Left\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "PlatformBehavior::SimulateLeftKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Right\"", + "\"Left\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "PlatformBehavior::SimulateRightKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Up\"", + "\"Left\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "PlatformBehavior::SimulateUpKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + }, + { + "type": { + "value": "PlatformBehavior::SimulateLadderKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Down\"", + "\"Left\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "PlatformBehavior::SimulateDownKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BooleanVariable" + }, + "parameters": [ + "UseLeftStick", + "True", + "" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Left\"", + "\"Left\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "PlatformBehavior::SimulateLeftKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Left\"", + "\"Right\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "PlatformBehavior::SimulateRightKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Left\"", + "\"Up\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "PlatformBehavior::SimulateUpKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + }, + { + "type": { + "value": "PlatformBehavior::SimulateLadderKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Left\"", + "\"Down\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "PlatformBehavior::SimulateDownKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BooleanVariable" + }, + "parameters": [ + "UseRightStick", + "True", + "" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Right\"", + "\"Left\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "PlatformBehavior::SimulateLeftKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Right\"", + "\"Right\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "PlatformBehavior::SimulateRightKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Right\"", + "\"Up\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "PlatformBehavior::SimulateUpKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + }, + { + "type": { + "value": "PlatformBehavior::SimulateLadderKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Right\"", + "\"Down\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "PlatformBehavior::SimulateDownKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "Buttons[JumpButton]", + "\"Left\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "PlatformBehavior::SimulateJumpKey" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + } + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::PlatformerGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "doStepPreEvents" + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Behavior", + "label": "Platformer character behavior", + "extraInformation": [ + "PlatformBehavior::PlatformerObjectBehavior" + ], + "choices": [], + "name": "PlatformerCharacter" + }, + { + "value": "1", + "type": "Number", + "label": "Gamepad identifier (1, 2, 3 or 4)", + "name": "GamepadIdentifier" + }, + { + "value": "true", + "type": "Boolean", + "label": "Use directional pad", + "group": "Controls", + "name": "UseArrows" + }, + { + "value": "true", + "type": "Boolean", + "label": "Use left stick", + "group": "Controls", + "name": "UseLeftStick" + }, + { + "value": "", + "type": "Boolean", + "label": "Use right stick", + "group": "Controls", + "name": "UseRightStick" + }, + { + "value": "A or Cross", + "type": "Choice", + "label": "Jump button", + "group": "Controls", + "choices": [ + { + "label": "A or Cross", + "value": "A or Cross" + }, + { + "label": "B or Circle", + "value": "B or Circle" + }, + { + "label": "X or Square", + "value": "X or Square" + }, + { + "label": "Y or Triangle", + "value": "Y or Triangle" + }, + { + "label": "LB or L1", + "value": "LB or L1" + }, + { + "label": "RB or R1", + "value": "RB or R1" + }, + { + "label": "LT or L2", + "value": "LT or L2" + }, + { + "label": "RT or R2", + "value": "RT or R2" + } + ], + "name": "JumpButton" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "propertyName": "PlatformerCharacter" + }, + { + "propertyName": "GamepadIdentifier" + }, + { + "folderName": "Controls", + "children": [ + { + "propertyName": "UseArrows" + }, + { + "propertyName": "UseLeftStick" + }, + { + "propertyName": "UseRightStick" + }, + { + "propertyName": "JumpButton" + } + ] + } + ] + } + }, + { + "description": "Control a 3D physics character with a gamepad.", + "fullName": "3D platformer gamepad mapper", + "helpPath": "", + "iconUrl": "", + "name": "Platformer3DGamepadMapper", + "objectType": "", + "previewIconUrl": "", + "quickCustomizationVisibility": "hidden", + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "doStepPreEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Controller_X_is_connected" + }, + "parameters": [ + "", + "GamepadIdentifier", + "" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::StickForce" + }, + "parameters": [ + "", + ">", + "0", + "GamepadIdentifier", + "JoystickIdentifier", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "Physics3D::PhysicsCharacter3D::SetForwardAngle" + }, + "parameters": [ + "Object", + "PhysicsCharacter3D", + "=", + "Gamepads::StickAngle(GamepadIdentifier, JoystickIdentifier) + CameraAngle(Object.Layer())" + ] + }, + { + "type": { + "value": "Physics3D::PhysicsCharacter3D::SimulateStick" + }, + "parameters": [ + "Object", + "PhysicsCharacter3D", + "-90", + "Gamepads::StickForce(GamepadIdentifier, JoystickIdentifier)" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "Buttons[JumpButton]", + "\"Left\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "Physics3D::PhysicsCharacter3D::SimulateJumpKey" + }, + "parameters": [ + "Object", + "PhysicsCharacter3D" + ] + } + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::Platformer3DGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "doStepPreEvents" + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Behavior", + "label": "3D physics character", + "extraInformation": [ + "Physics3D::PhysicsCharacter3D" + ], + "choices": [], + "name": "PhysicsCharacter3D" + }, + { + "value": "1", + "type": "Number", + "label": "Gamepad identifier (1, 2, 3 or 4)", + "name": "GamepadIdentifier" + }, + { + "value": "Left", + "type": "Choice", + "label": "Walk joystick", + "group": "Controls", + "choices": [ + { + "label": "Left", + "value": "Left" + }, + { + "label": "Right", + "value": "Right" + } + ], + "name": "JoystickIdentifier" + }, + { + "value": "A or Cross", + "type": "Choice", + "label": "Jump button", + "group": "Controls", + "choices": [ + { + "label": "A or Cross", + "value": "A or Cross" + }, + { + "label": "B or Circle", + "value": "B or Circle" + }, + { + "label": "X or Square", + "value": "X or Square" + }, + { + "label": "Y or Triangle", + "value": "Y or Triangle" + }, + { + "label": "LB or L1", + "value": "LB or L1" + }, + { + "label": "RB or R1", + "value": "RB or R1" + }, + { + "label": "LT or L2", + "value": "LT or L2" + }, + { + "label": "RT or R2", + "value": "RT or R2" + } + ], + "name": "JumpButton" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "propertyName": "PhysicsCharacter3D" + }, + { + "propertyName": "GamepadIdentifier" + }, + { + "folderName": "Controls", + "children": [ + { + "propertyName": "JoystickIdentifier" + }, + { + "propertyName": "JumpButton" + } + ] + } + ] + } + }, + { + "description": "Control a 3D physics character with a gamepad.", + "fullName": "3D shooter gamepad mapper", + "helpPath": "", + "iconUrl": "", + "name": "Shooter3DGamepadMapper", + "objectType": "", + "previewIconUrl": "", + "quickCustomizationVisibility": "hidden", + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "doStepPreEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Controller_X_is_connected" + }, + "parameters": [ + "", + "GamepadIdentifier", + "" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::StickForce" + }, + "parameters": [ + "", + ">", + "0", + "GamepadIdentifier", + "WalkStick", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "Physics3D::PhysicsCharacter3D::SimulateStick" + }, + "parameters": [ + "Object", + "PhysicsCharacter3D", + "Gamepads::StickAngle(GamepadIdentifier, WalkStick)", + "Gamepads::StickForce(GamepadIdentifier, WalkStick)" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "Buttons[JumpButton]", + "\"Left\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "Physics3D::PhysicsCharacter3D::SimulateJumpKey" + }, + "parameters": [ + "Object", + "PhysicsCharacter3D" + ] + } + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::Shooter3DGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "doStepPreEvents" + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Behavior", + "label": "3D physics character", + "extraInformation": [ + "Physics3D::PhysicsCharacter3D" + ], + "choices": [], + "name": "PhysicsCharacter3D" + }, + { + "value": "1", + "type": "Number", + "label": "Gamepad identifier (1, 2, 3 or 4)", + "name": "GamepadIdentifier" + }, + { + "value": "Left", + "type": "Choice", + "label": "Walk joystick", + "group": "Controls", + "choices": [ + { + "label": "Left", + "value": "Left" + }, + { + "label": "Right", + "value": "Right" + } + ], + "name": "WalkStick" + }, + { + "value": "Right", + "type": "Choice", + "label": "Camera joystick", + "group": "Controls", + "choices": [ + { + "label": "Left", + "value": "Left" + }, + { + "label": "Right", + "value": "Right" + } + ], + "name": "CameraStick" + }, + { + "value": "A or Cross", + "type": "Choice", + "label": "Jump button", + "group": "Controls", + "choices": [ + { + "label": "A or Cross", + "value": "A or Cross" + }, + { + "label": "B or Circle", + "value": "B or Circle" + }, + { + "label": "X or Square", + "value": "X or Square" + }, + { + "label": "Y or Triangle", + "value": "Y or Triangle" + }, + { + "label": "LB or L1", + "value": "LB or L1" + }, + { + "label": "RB or R1", + "value": "RB or R1" + }, + { + "label": "LT or L2", + "value": "LT or L2" + }, + { + "label": "RT or R2", + "value": "RT or R2" + } + ], + "name": "JumpButton" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "propertyName": "PhysicsCharacter3D" + }, + { + "propertyName": "GamepadIdentifier" + }, + { + "folderName": "Controls", + "children": [ + { + "propertyName": "WalkStick" + }, + { + "propertyName": "CameraStick" + }, + { + "propertyName": "JumpButton" + } + ] + } + ] + } + }, + { + "description": "Control camera rotations with a gamepad.", + "fullName": "First person camera gamepad mapper", + "helpPath": "", + "iconUrl": "", + "name": "FirstPersonGamepadMapper", + "objectType": "", + "previewIconUrl": "", + "quickCustomizationVisibility": "hidden", + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "doStepPreEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "TODO It's probably a bad idea to rotate the object around Y." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "CurrentRotationSpeedZ", + "=", + "Gamepads::AcceleratedSpeed(CurrentRotationSpeedZ, Gamepads::StickForceX(GamepadIdentifier, CameraStick) * HorizontalRotationSpeedMax, HorizontalRotationSpeedMax, HorizontalRotationAcceleration, HorizontalRotationDeceleration)" + ] + }, + { + "type": { + "value": "SetAngle" + }, + "parameters": [ + "Object", + "+", + "CurrentRotationSpeedZ * TimeDelta()" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "CurrentRotationSpeedY", + "=", + "Gamepads::AcceleratedSpeed(CurrentRotationSpeedY, Gamepads::StickForceY(GamepadIdentifier, CameraStick) * VerticalRotationSpeedMax, VerticalRotationSpeedMax, VerticalRotationAcceleration, VerticalRotationDeceleration)" + ] + }, + { + "type": { + "value": "Scene3D::Base3DBehavior::SetRotationY" + }, + "parameters": [ + "Object", + "Object3D", + "+", + "CurrentRotationSpeedY * TimeDelta()" + ] + }, + { + "type": { + "value": "Scene3D::Base3DBehavior::SetRotationY" + }, + "parameters": [ + "Object", + "Object3D", + "=", + "clamp(Object.Object3D::RotationY(), VerticalAngleMin, VerticalAngleMax)" + ] + }, + { + "type": { + "value": "Gamepads::FirstPersonGamepadMapper::LookFromObjectEyes" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Move the camera to look though _PARAM1_ eyes. The object must look to the right when all its angles are 0 and the top of its head be toward Z+.", + "fullName": "Look through object eyes", + "functionType": "Action", + "group": "Layers and cameras", + "name": "LookFromObjectEyes", + "private": true, + "sentence": "Move the camera to look though _PARAM0_ eyes", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "CenterCameraOnObject" + }, + "parameters": [ + "", + "Object", + "", + "Object.Layer()", + "" + ] + }, + { + "type": { + "value": "Scene3D::SetCameraZ" + }, + "parameters": [ + "", + "=", + "Object.Object3D::Z() + Object.Object3D::Depth() + OffsetZ", + "", + "" + ] + }, + { + "type": { + "value": "Scene3D::SetCameraRotationX" + }, + "parameters": [ + "", + "=", + "- Object.Object3D::RotationY() + 90", + "GetArgumentAsString(\"Layer\")", + "" + ] + }, + { + "type": { + "value": "Scene3D::SetCameraRotationY" + }, + "parameters": [ + "", + "=", + "Object.Object3D::RotationX()", + "GetArgumentAsString(\"Layer\")", + "" + ] + }, + { + "type": { + "value": "SetCameraAngle" + }, + "parameters": [ + "", + "=", + "Object.Angle() + 90", + "Object.Layer()", + "" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "the maximum horizontal rotation speed of the object.", + "fullName": "Maximum horizontal rotation speed", + "functionType": "ExpressionAndCondition", + "group": "First person camera gamepad mapper horizontal rotation configuration", + "name": "HorizontalRotationSpeedMax", + "sentence": "the maximum horizontal rotation speed", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "HorizontalRotationSpeedMax" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "ActionWithOperator", + "getterName": "HorizontalRotationSpeedMax", + "group": "First person camera gamepad mapper horizontal rotation configuration", + "name": "SetHorizontalRotationSpeedMax", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "HorizontalRotationSpeedMax", + "=", + "Value" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "the horizontal rotation acceleration of the object.", + "fullName": "Horizontal rotation acceleration", + "functionType": "ExpressionAndCondition", + "group": "First person camera gamepad mapper horizontal rotation configuration", + "name": "HorizontalRotationAcceleration", + "sentence": "the horizontal rotation acceleration", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "HorizontalRotationAcceleration" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "ActionWithOperator", + "getterName": "HorizontalRotationAcceleration", + "group": "First person camera gamepad mapper horizontal rotation configuration", + "name": "SetHorizontalRotationAcceleration", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "HorizontalRotationAcceleration", + "=", + "Value" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "the horizontal rotation deceleration of the object.", + "fullName": "Horizontal rotation deceleration", + "functionType": "ExpressionAndCondition", + "group": "First person camera gamepad mapper horizontal rotation configuration", + "name": "HorizontalRotationDeceleration", + "sentence": "the horizontal rotation deceleration", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "HorizontalRotationDeceleration" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "ActionWithOperator", + "getterName": "HorizontalRotationDeceleration", + "group": "First person camera gamepad mapper horizontal rotation configuration", + "name": "SetHorizontalRotationDeceleration", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "HorizontalRotationDeceleration", + "=", + "Value" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "the maximum vertical rotation speed of the object.", + "fullName": "Maximum vertical rotation speed", + "functionType": "ExpressionAndCondition", + "group": "First person camera gamepad mapper vertical rotation configuration", + "name": "VerticalRotationSpeedMax", + "sentence": "the maximum vertical rotation speed", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "VerticalRotationSpeedMax" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "ActionWithOperator", + "getterName": "VerticalRotationSpeedMax", + "group": "First person camera gamepad mapper vertical rotation configuration", + "name": "SetVerticalRotationSpeedMax", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "VerticalRotationSpeedMax", + "=", + "Value" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "the vertical rotation acceleration of the object.", + "fullName": "Vertical rotation acceleration", + "functionType": "ExpressionAndCondition", + "group": "First person camera gamepad mapper vertical rotation configuration", + "name": "VerticalRotationAcceleration", + "sentence": "the vertical rotation acceleration", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "VerticalRotationAcceleration" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "ActionWithOperator", + "getterName": "VerticalRotationAcceleration", + "group": "First person camera gamepad mapper vertical rotation configuration", + "name": "SetVerticalRotationAcceleration", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "VerticalRotationAcceleration", + "=", + "Value" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "the vertical rotation deceleration of the object.", + "fullName": "Vertical rotation deceleration", + "functionType": "ExpressionAndCondition", + "group": "First person camera gamepad mapper vertical rotation configuration", + "name": "VerticalRotationDeceleration", + "sentence": "the vertical rotation deceleration", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "VerticalRotationDeceleration" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "ActionWithOperator", + "getterName": "VerticalRotationDeceleration", + "group": "First person camera gamepad mapper vertical rotation configuration", + "name": "SetVerticalRotationDeceleration", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "VerticalRotationDeceleration", + "=", + "Value" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "the minimum vertical camera angle of the object.", + "fullName": "Minimum vertical camera angle", + "functionType": "ExpressionAndCondition", + "group": "First person camera gamepad mapper vertical rotation configuration", + "name": "VerticalAngleMin", + "sentence": "the minimum vertical camera angle", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "VerticalAngleMin" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "ActionWithOperator", + "getterName": "VerticalAngleMin", + "group": "First person camera gamepad mapper vertical rotation configuration", + "name": "SetVerticalAngleMin", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "VerticalAngleMin", + "=", + "Value" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "the maximum vertical camera angle of the object.", + "fullName": "Maximum vertical camera angle", + "functionType": "ExpressionAndCondition", + "group": "First person camera gamepad mapper vertical rotation configuration", + "name": "VerticalAngleMax", + "sentence": "the maximum vertical camera angle", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "VerticalAngleMax" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "ActionWithOperator", + "getterName": "VerticalAngleMax", + "group": "First person camera gamepad mapper vertical rotation configuration", + "name": "SetVerticalAngleMax", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "VerticalAngleMax", + "=", + "Value" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "the z position offset of the object.", + "fullName": "Z position offset", + "functionType": "ExpressionAndCondition", + "group": "First person camera gamepad mapper position configuration", + "name": "OffsetZ", + "sentence": "the z position offset", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "OffsetZ" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "ActionWithOperator", + "getterName": "OffsetZ", + "group": "First person camera gamepad mapper position configuration", + "name": "SetOffsetZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "OffsetZ", + "=", + "Value" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::FirstPersonGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "doStepPreEvents" + }, + { + "folderName": "Layers and cameras", + "children": [ + { + "functionName": "LookFromObjectEyes" + } + ] + }, + { + "folderName": "First person camera gamepad mapper horizontal rotation configuration", + "children": [ + { + "functionName": "HorizontalRotationSpeedMax" + }, + { + "functionName": "SetHorizontalRotationSpeedMax" + }, + { + "functionName": "HorizontalRotationAcceleration" + }, + { + "functionName": "SetHorizontalRotationAcceleration" + }, + { + "functionName": "HorizontalRotationDeceleration" + }, + { + "functionName": "SetHorizontalRotationDeceleration" + } + ] + }, + { + "folderName": "First person camera gamepad mapper vertical rotation configuration", + "children": [ + { + "functionName": "VerticalRotationSpeedMax" + }, + { + "functionName": "SetVerticalRotationSpeedMax" + }, + { + "functionName": "VerticalRotationAcceleration" + }, + { + "functionName": "SetVerticalRotationAcceleration" + }, + { + "functionName": "VerticalRotationDeceleration" + }, + { + "functionName": "SetVerticalRotationDeceleration" + }, + { + "functionName": "VerticalAngleMin" + }, + { + "functionName": "SetVerticalAngleMin" + }, + { + "functionName": "VerticalAngleMax" + }, + { + "functionName": "SetVerticalAngleMax" + } + ] + }, + { + "folderName": "First person camera gamepad mapper position configuration", + "children": [ + { + "functionName": "OffsetZ" + }, + { + "functionName": "SetOffsetZ" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Behavior", + "label": "3D capability", + "extraInformation": [ + "Scene3D::Base3DBehavior" + ], + "choices": [], + "name": "Object3D" + }, + { + "value": "1", + "type": "Number", + "label": "Gamepad identifier (1, 2, 3 or 4)", + "name": "GamepadIdentifier" + }, + { + "value": "Right", + "type": "Choice", + "label": "Camera joystick", + "choices": [ + { + "label": "Left", + "value": "Left" + }, + { + "label": "Right", + "value": "Right" + } + ], + "name": "CameraStick" + }, + { + "value": "180", + "type": "Number", + "unit": "AngularSpeed", + "label": "Maximum rotation speed", + "group": "Horizontal rotation", + "name": "HorizontalRotationSpeedMax" + }, + { + "value": "360", + "type": "Number", + "label": "Rotation acceleration", + "group": "Horizontal rotation", + "name": "HorizontalRotationAcceleration" + }, + { + "value": "720", + "type": "Number", + "label": "Rotation deceleration", + "group": "Horizontal rotation", + "name": "HorizontalRotationDeceleration" + }, + { + "value": "120", + "type": "Number", + "unit": "AngularSpeed", + "label": "Maximum rotation speed", + "group": "Vertical rotation", + "name": "VerticalRotationSpeedMax" + }, + { + "value": "240", + "type": "Number", + "label": "Rotation acceleration", + "group": "Vertical rotation", + "name": "VerticalRotationAcceleration" + }, + { + "value": "480", + "type": "Number", + "label": "Rotation deceleration", + "group": "Vertical rotation", + "name": "VerticalRotationDeceleration" + }, + { + "value": "-90", + "type": "Number", + "unit": "DegreeAngle", + "label": "Minimum angle", + "group": "Vertical rotation", + "name": "VerticalAngleMin" + }, + { + "value": "90", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum angle", + "group": "Vertical rotation", + "name": "VerticalAngleMax" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Z position offset", + "group": "Position", + "name": "OffsetZ" + }, + { + "value": "0", + "type": "Number", + "unit": "AngularSpeed", + "label": "Current rotation speed Z", + "hidden": true, + "name": "CurrentRotationSpeedZ" + }, + { + "value": "0", + "type": "Number", + "unit": "AngularSpeed", + "label": "Current rotation speed Y", + "hidden": true, + "name": "CurrentRotationSpeedY" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "propertyName": "Object3D" + }, + { + "propertyName": "GamepadIdentifier" + }, + { + "propertyName": "CameraStick" + }, + { + "folderName": "Horizontal rotation", + "children": [ + { + "propertyName": "HorizontalRotationSpeedMax" + }, + { + "propertyName": "HorizontalRotationAcceleration" + }, + { + "propertyName": "HorizontalRotationDeceleration" + } + ] + }, + { + "folderName": "Vertical rotation", + "children": [ + { + "propertyName": "VerticalRotationSpeedMax" + }, + { + "propertyName": "VerticalRotationAcceleration" + }, + { + "propertyName": "VerticalRotationDeceleration" + }, + { + "propertyName": "VerticalAngleMin" + }, + { + "propertyName": "VerticalAngleMax" + } + ] + }, + { + "folderName": "Position", + "children": [ + { + "propertyName": "OffsetZ" + } + ] + }, + { + "propertyName": "CurrentRotationSpeedZ" + }, + { + "propertyName": "CurrentRotationSpeedY" + } + ] + } + }, + { + "description": "Control a 3D physics car with a gamepad.", + "fullName": "3D car gamepad mapper", + "helpPath": "", + "iconUrl": "", + "name": "PhysicsCar3DGamepadMapper", + "objectType": "", + "previewIconUrl": "", + "quickCustomizationVisibility": "hidden", + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "doStepPreEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Controller_X_is_connected" + }, + "parameters": [ + "", + "GamepadIdentifier", + "" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BooleanVariable" + }, + "parameters": [ + "UseArrows", + "True", + "" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Left\"", + "\"Left\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "Physics3D::PhysicsCar3D::SimulateLeftKey" + }, + "parameters": [ + "Object", + "PhysicsCar3D" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Right\"", + "\"Left\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "Physics3D::PhysicsCar3D::SimulateRightKey" + }, + "parameters": [ + "Object", + "PhysicsCar3D" + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BooleanVariable" + }, + "parameters": [ + "UseLeftStick", + "True", + "" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "1", + "\"Left\"", + "\"Any\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "Physics3D::PhysicsCar3D::SimulateSteeringStick" + }, + "parameters": [ + "Object", + "PhysicsCar3D", + "Gamepads::StickForceX(GamepadIdentifier, \"Left\")" + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BooleanVariable" + }, + "parameters": [ + "UseRightStick", + "True", + "" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "1", + "\"Right\"", + "\"Any\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "Physics3D::PhysicsCar3D::SimulateSteeringStick" + }, + "parameters": [ + "Object", + "PhysicsCar3D", + "Gamepads::StickForceX(GamepadIdentifier, \"Right\")" + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::Or" + }, + "parameters": [], + "subInstructions": [ + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "1", + "\"LT\"", + "\"Up\"" + ] + }, + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "1", + "\"RT\"", + "\"Up\"" + ] + } + ] + } + ], + "actions": [ + { + "type": { + "value": "Physics3D::PhysicsCar3D::SimulateAcceleratorStick" + }, + "parameters": [ + "Object", + "PhysicsCar3D", + "Gamepads::TriggerPressure(GamepadIdentifier, \"RT\") - Gamepads::TriggerPressure(GamepadIdentifier, \"LT\")" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "Buttons[HandBrakeButton]", + "\"Left\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "Physics3D::PhysicsCar3D::SimulateHandBrakeKey" + }, + "parameters": [ + "Object", + "PhysicsCar3D" + ] + } + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::PhysicsCar3DGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "doStepPreEvents" + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Behavior", + "label": "3D physics car", + "extraInformation": [ + "Physics3D::PhysicsCar3D" + ], + "choices": [], + "name": "PhysicsCar3D" + }, + { + "value": "1", + "type": "Number", + "label": "Gamepad identifier (1, 2, 3 or 4)", + "name": "GamepadIdentifier" + }, + { + "value": "true", + "type": "Boolean", + "label": "Use directional pad", + "group": "Controls", + "name": "UseArrows" + }, + { + "value": "true", + "type": "Boolean", + "label": "Use left stick", + "group": "Controls", + "name": "UseLeftStick" + }, + { + "value": "", + "type": "Boolean", + "label": "Use right stick", + "group": "Controls", + "name": "UseRightStick" + }, + { + "value": "B or Circle", + "type": "Choice", + "label": "Hand brake button", + "group": "Controls", + "choices": [ + { + "label": "A or Cross", + "value": "A or Cross" + }, + { + "label": "B or Circle", + "value": "B or Circle" + }, + { + "label": "X or Square", + "value": "X or Square" + }, + { + "label": "Y or Triangle", + "value": "Y or Triangle" + }, + { + "label": "LB or L1", + "value": "LB or L1" + }, + { + "label": "RB or R1", + "value": "RB or R1" + }, + { + "label": "LT or L2", + "value": "LT or L2" + }, + { + "label": "RT or R2", + "value": "RT or R2" + } + ], + "name": "HandBrakeButton" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "propertyName": "PhysicsCar3D" + }, + { + "propertyName": "GamepadIdentifier" + }, + { + "folderName": "Controls", + "children": [ + { + "propertyName": "UseArrows" + }, + { + "propertyName": "UseLeftStick" + }, + { + "propertyName": "UseRightStick" + }, + { + "propertyName": "HandBrakeButton" + } + ] + } + ] + } + }, + { + "description": "Control a top-down character with a gamepad.", + "fullName": "Top-down gamepad mapper", + "helpPath": "", + "iconUrl": "", + "name": "TopDownGamepadMapper", + "objectType": "", + "previewIconUrl": "", + "quickCustomizationVisibility": "hidden", + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "doStepPreEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Controller_X_is_connected" + }, + "parameters": [ + "", + "GamepadIdentifier", + "" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BooleanVariable" + }, + "parameters": [ + "UseArrows", + "True", + "" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Left\"", + "\"Left\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateLeftKey" + }, + "parameters": [ + "Object", + "TopDownMovement" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Right\"", + "\"Left\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateRightKey" + }, + "parameters": [ + "Object", + "TopDownMovement" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Up\"", + "\"Left\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateUpKey" + }, + "parameters": [ + "Object", + "TopDownMovement" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Button_pressed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Down\"", + "\"Left\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateDownKey" + }, + "parameters": [ + "Object", + "TopDownMovement" + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BooleanVariable" + }, + "parameters": [ + "UseLeftStick", + "True", + "" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "StringVariable" + }, + "parameters": [ + "StickMode", + "=", + "\"Analog\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateStick" + }, + "parameters": [ + "Object", + "TopDownMovement", + "Gamepads::StickRotationValue(GamepadIdentifier, \"Left\")", + "Gamepads::StickForce(GamepadIdentifier, \"Left\")" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "StringVariable" + }, + "parameters": [ + "StickMode", + "=", + "\"360°\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateStick" + }, + "parameters": [ + "Object", + "TopDownMovement", + "Gamepads::StickRotationValue(GamepadIdentifier, \"Left\")", + "sign(Gamepads::StickForce(GamepadIdentifier, \"Left\"))" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "StringVariable" + }, + "parameters": [ + "StickMode", + "=", + "\"8 Directions\"" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Left\"", + "\"Left\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateLeftKey" + }, + "parameters": [ + "Object", + "TopDownMovement" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Left\"", + "\"Right\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateRightKey" + }, + "parameters": [ + "Object", + "TopDownMovement" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Left\"", + "\"Up\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateUpKey" + }, + "parameters": [ + "Object", + "TopDownMovement" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Left\"", + "\"Down\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateDownKey" + }, + "parameters": [ + "Object", + "TopDownMovement" + ] + } + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BooleanVariable" + }, + "parameters": [ + "UseRightStick", + "True", + "" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "StringVariable" + }, + "parameters": [ + "StickMode", + "=", + "\"Analog\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateStick" + }, + "parameters": [ + "Object", + "TopDownMovement", + "Gamepads::StickRotationValue(GamepadIdentifier, \"Right\")", + "Gamepads::StickForce(GamepadIdentifier, \"Right\")" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "StringVariable" + }, + "parameters": [ + "StickMode", + "=", + "\"360°\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateStick" + }, + "parameters": [ + "Object", + "TopDownMovement", + "sign(Gamepads::StickForce(GamepadIdentifier, \"Right\"))", + "1" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "StringVariable" + }, + "parameters": [ + "StickMode", + "=", + "\"8 Directions\"" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Right\"", + "\"Left\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateLeftKey" + }, + "parameters": [ + "Object", + "TopDownMovement" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Right\"", + "\"Right\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateRightKey" + }, + "parameters": [ + "Object", + "TopDownMovement" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Right\"", + "\"Up\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateUpKey" + }, + "parameters": [ + "Object", + "TopDownMovement" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "Gamepads::C_Axis_pushed" + }, + "parameters": [ + "", + "GamepadIdentifier", + "\"Right\"", + "\"Down\"", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "TopDownMovementBehavior::SimulateDownKey" + }, + "parameters": [ + "Object", + "TopDownMovement" + ] + } + ] + } + ] + } + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "Gamepads::TopDownGamepadMapper", + "type": "behavior" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "doStepPreEvents" + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Behavior", + "label": "Top-down movement behavior", + "extraInformation": [ + "TopDownMovementBehavior::TopDownMovementBehavior" + ], + "choices": [], + "name": "TopDownMovement" + }, + { + "value": "1", + "type": "Number", + "label": "Gamepad identifier (1, 2, 3 or 4)", + "name": "GamepadIdentifier" + }, + { + "value": "true", + "type": "Boolean", + "label": "Use directional pad", + "group": "Controls", + "name": "UseArrows" + }, + { + "value": "true", + "type": "Boolean", + "label": "Use left stick", + "group": "Controls", + "name": "UseLeftStick" + }, + { + "value": "", + "type": "Boolean", + "label": "Use right stick", + "group": "Controls", + "name": "UseRightStick" + }, + { + "value": "Analog", + "type": "Choice", + "label": "Stick mode", + "group": "Controls", + "choices": [ + { + "label": "Analog", + "value": "Analog" + }, + { + "label": "360°", + "value": "360°" + }, + { + "label": "8 Directions", + "value": "8 Directions" + } + ], + "name": "StickMode" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "propertyName": "TopDownMovement" + }, + { + "propertyName": "GamepadIdentifier" + }, + { + "folderName": "Controls", + "children": [ + { + "propertyName": "UseArrows" + }, + { + "propertyName": "UseLeftStick" + }, + { + "propertyName": "UseRightStick" + }, + { + "propertyName": "StickMode" + } + ] + } + ] + } + } + ], + "eventsBasedObjects": [] + }, + { + "author": "", + "category": "Camera", + "dimension": "2D", + "extensionNamespace": "", + "fullName": "Smooth Camera", + "gdevelopVersion": ">=5.5.222", + "helpPath": "/tutorials/follow-player-with-camera/", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMy4wLjMsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iSWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgMzIgMzIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDMyIDMyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9DQoJLnN0MXtmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjEwO30NCjwvc3R5bGU+DQo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjQsMTNoLTZjLTEuMSwwLTItMC45LTItMlY1YzAtMS4xLDAuOS0yLDItMmg2YzEuMSwwLDIsMC45LDIsMnY2QzI2LDEyLjEsMjUuMSwxMywyNCwxM3oiLz4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yNiw4djEwYzAsMS4xLTAuOSwyLTIsMkg4Yy0xLjEsMC0yLTAuOS0yLTJWOGMwLTEuMSwwLjktMiwyLTJoOCIvPg0KPGNpcmNsZSBjbGFzcz0ic3QwIiBjeD0iMjEiIGN5PSI4IiByPSIyIi8+DQo8Y2lyY2xlIGNsYXNzPSJzdDAiIGN4PSIxMSIgY3k9IjE2IiByPSIxIi8+DQo8cmVjdCB4PSI5IiB5PSI5IiBjbGFzcz0ic3QwIiB3aWR0aD0iNCIgaGVpZ2h0PSIzIi8+DQo8cG9seWxpbmUgY2xhc3M9InN0MCIgcG9pbnRzPSIyMSwyOSAyMSwyOSAxMSwyOSAxMSwyOSAiLz4NCjxwb2x5bGluZSBjbGFzcz0ic3QwIiBwb2ludHM9IjE4LDIwIDE4LDI5IDE0LDI5IDE0LDIwICIvPg0KPHJlY3QgeD0iNyIgeT0iMyIgY2xhc3M9InN0MCIgd2lkdGg9IjQiIGhlaWdodD0iMyIvPg0KPC9zdmc+DQo=", + "name": "SmoothCamera", + "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Computers and Hardware/Computers and Hardware_camcoder_gopro_go_pro_camera.svg", + "shortDescription": "Smoothly scroll to follow an object.", + "version": "0.4.5", + "description": [ + "The camera follows an object according to:", + "- a frame rate independent catch-up speed to make the scrolling from smooth to strong", + "- a maximum speed to do linear following ([open the project online](https://editor.gdevelop.io/?project=example://platformer-with-tilemap)) or slow down the camera when teleporting the object", + "- a follow-free zone to avoid scrolling on small movements", + "- an offset to see further in one direction", + "- an extra delay and catch-up speed to give an impression of speed (useful for dash)", + "- position forecasting and delay to simulate a cameraman response time", + "", + "A platformer dedicated behavior allows to switch of settings when the character is in air or on the floor. This can be used to stabilize the camera when jumping." + ], + "origin": { + "identifier": "SmoothCamera", + "name": "gdevelop-extension-store" + }, + "tags": [ + "camera", + "scrolling", + "follow", + "smooth", + "platformer", + "platform" + ], + "authorIds": [ + "IWykYNRvhCZBN3vEgKEbBPOR3Oc2" + ], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT" + }, + "eventsBasedBehaviors": [ + { + "description": "Smoothly scroll to follow an object.", + "fullName": "Smooth Camera", + "helpPath": "", + "iconUrl": "", + "name": "SmoothCamera", + "objectType": "", + "previewIconUrl": "", + "quickCustomizationVisibility": "hidden", + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Update private properties through setters to check their values and initialize state." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetLeftwardSpeed" + }, + "parameters": [ + "Object", + "Behavior", + "LeftwardSpeed", + "log(1 - )" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetRightwardSpeed" + }, + "parameters": [ + "Object", + "Behavior", + "RightwardSpeed", + "log(1 - )" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetUpwardSpeed" + }, + "parameters": [ + "Object", + "Behavior", + "UpwardSpeed", + "log(1 - )" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetDownwardSpeed" + }, + "parameters": [ + "Object", + "Behavior", + "DownwardSpeed", + "log(1 - )" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetLeftwardSpeedMax" + }, + "parameters": [ + "Object", + "Behavior", + "LeftwardSpeedMax", + "log(1 - )" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetRightwardSpeedMax" + }, + "parameters": [ + "Object", + "Behavior", + "RightwardSpeedMax", + "log(1 - )" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetUpwardSpeedMax" + }, + "parameters": [ + "Object", + "Behavior", + "UpwardSpeedMax", + "log(1 - )" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetDownwardSpeedMax" + }, + "parameters": [ + "Object", + "Behavior", + "DownwardSpeedMax", + "log(1 - )" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetFollowFreeAreaLeft" + }, + "parameters": [ + "Object", + "Behavior", + "FollowFreeAreaLeft", + "log(1 - )" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetFollowFreeAreaRight" + }, + "parameters": [ + "Object", + "Behavior", + "FollowFreeAreaRight", + "log(1 - )" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetFollowFreeAreaTop" + }, + "parameters": [ + "Object", + "Behavior", + "FollowFreeAreaTop", + "log(1 - )" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetFollowFreeAreaBottom" + }, + "parameters": [ + "Object", + "Behavior", + "FollowFreeAreaBottom", + "log(1 - )" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "CameraDelay", + "=", + "CameraDelay" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPreEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "inverted": true, + "value": "BooleanVariable" + }, + "parameters": [ + "IsCalledManually", + "True", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "SmoothCamera::SmoothCamera::DoMoveCameraCloser" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Move the camera closer to the object. This action must be called after the object has moved for the frame.", + "fullName": "Move the camera closer", + "functionType": "Action", + "name": "MoveCameraCloser", + "sentence": "Move the camera closer to _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "The camera following is called with an action, the call from doStepPreEvents must be disabled to avoid to do it twice." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetBooleanVariable" + }, + "parameters": [ + "IsCalledManually", + "True", + "" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::DoMoveCameraCloser" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Move the camera closer to the object.", + "fullName": "Do move the camera closer", + "functionType": "Action", + "name": "DoMoveCameraCloser", + "private": true, + "sentence": "Do move the camera closer _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Delaying and forecasting can be used at the same time.\nForecasting only use the positions that are older than the one used for delaying.\nThe behavior uses a position history that is split in 2 arrays:\n- one for delaying the position (from TimeFromStart to TimeFromStart - CamearDelay)\n- one for forecasting the position (from TimeFromStart - CamearDelay to TimeFromStart - CamearDelay - ForecastHistoryDuration" + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SmoothCamera::SmoothCamera::UpdateDelayedPosition" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::UpdateForecastedPosition" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "At each frame, the camera must catchup the target by a given ratio (speed)\ncameraX(t) - targetX = (cameraX(t - 1) - targetX) * speed\n\nThe frame rate must not impact on the catch-up speed, we don't want a speed in ratio per frame but a speed ratio per second, like this:\ncameraX(t) - targetX = (cameraX(t - 1s) - targetX) * speed\n\nOk, but we still need to process each frame, we can use a exponent for this:\ncameraX(t) - targetX = (cameraX(t - timeDelta) - targetX) * speed^timeDelta\ncameraX(t) = targetX + (cameraX(t - timeDelta) - targetX) * exp(timeDelta * ln(speed))\n\npow is probably more efficient than precalculated log if the speed is changed continuously but this might be rare enough." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BooleanVariable" + }, + "parameters": [ + "FollowOnX", + "True", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "OldX", + "=", + "CameraX(Object.Layer(), 0)" + ] + } + ], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "CameraCenterX" + }, + "parameters": [ + "", + ">", + "Object.Behavior::FreeAreaRight()", + "Object.Layer()", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetCameraCenterX" + }, + "parameters": [ + "", + "=", + "Object.Behavior::FreeAreaRight()\n+ (CameraX(Object.Layer(), 0) - Object.Behavior::FreeAreaRight())\n* exp(TimeDelta() * LogLeftwardSpeed)", + "Object.Layer()", + "0" + ] + } + ], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "CameraCenterX" + }, + "parameters": [ + "", + "<", + "OldX - LeftwardSpeedMax * TimeDelta()", + "Object.Layer()", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetCameraCenterX" + }, + "parameters": [ + "", + "=", + "OldX - LeftwardSpeedMax * TimeDelta()", + "Object.Layer()", + "0" + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "CameraCenterX" + }, + "parameters": [ + "", + "<", + "Object.Behavior::FreeAreaLeft()", + "Object.Layer()", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetCameraCenterX" + }, + "parameters": [ + "", + "=", + "Object.Behavior::FreeAreaLeft()\n+ (CameraX(Object.Layer(), 0) - Object.Behavior::FreeAreaLeft())\n* exp(TimeDelta() * LogRightwardSpeed)", + "Object.Layer()", + "0" + ] + } + ], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "CameraCenterX" + }, + "parameters": [ + "", + ">", + "OldX + RightwardSpeedMax * TimeDelta()", + "Object.Layer()", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetCameraCenterX" + }, + "parameters": [ + "", + "=", + "OldX + RightwardSpeedMax * TimeDelta()", + "Object.Layer()", + "0" + ] + } + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BooleanVariable" + }, + "parameters": [ + "FollowOnY", + "True", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "OldY", + "=", + "CameraY(Object.Layer(), 0)" + ] + } + ], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "CameraCenterY" + }, + "parameters": [ + "", + ">", + "Object.Behavior::FreeAreaBottom()", + "Object.Layer()", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetCameraCenterY" + }, + "parameters": [ + "", + "=", + "Object.Behavior::FreeAreaBottom()\n+ (CameraY(Object.Layer(), 0) - Object.Behavior::FreeAreaBottom())\n* exp(TimeDelta() * LogUpwardSpeed)", + "Object.Layer()", + "0" + ] + } + ], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "CameraCenterY" + }, + "parameters": [ + "", + "<", + "OldY - UpwardSpeedMax * TimeDelta()", + "Object.Layer()", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetCameraCenterY" + }, + "parameters": [ + "", + "=", + "OldY - UpwardSpeedMax * TimeDelta()", + "Object.Layer()", + "0" + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "CameraCenterY" + }, + "parameters": [ + "", + "<", + "Object.Behavior::FreeAreaTop()", + "Object.Layer()", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetCameraCenterY" + }, + "parameters": [ + "", + "=", + "Object.Behavior::FreeAreaTop()\n+ (CameraY(Object.Layer(), 0) - Object.Behavior::FreeAreaTop())\n* exp(TimeDelta() * LogDownwardSpeed)", + "Object.Layer()", + "0" + ] + } + ], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "CameraCenterY" + }, + "parameters": [ + "", + ">", + "OldY + DownwardSpeedMax * TimeDelta()", + "Object.Layer()", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetCameraCenterY" + }, + "parameters": [ + "", + "=", + "OldY + DownwardSpeedMax * TimeDelta()", + "Object.Layer()", + "0" + ] + } + ] + } + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Delay the camera according to a maximum speed and catch up the delay.", + "fullName": "Wait and catch up", + "functionType": "Action", + "name": "WaitAndCatchUp", + "sentence": "Delay the camera of _PARAM0_ during: _PARAM2_ seconds according to the maximum speed _PARAM3_;_PARAM4_ seconds and catch up in _PARAM5_ seconds", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Maybe the catch-up show be done in constant pixel speed instead of constant time speed." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "WaitingEnd", + "=", + "TimeFromStart() + NewWaitingDuration" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "WaitingSpeedXMax", + "=", + "NewWaitingSpeedXMax" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "WaitingSpeedYMax", + "=", + "NewWaitingSpeedYMax" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "CameraDelayCatchUpDuration", + "=", + "NewCatchUpDuration" + ] + } + ] + }, + { + "disabled": true, + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "DebuggerTools::ConsoleLog" + }, + "parameters": [ + "\"Wait and catch up\"", + "\"info\"", + "\"SmoothCamera\"" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Waiting duration (in seconds)", + "name": "NewWaitingDuration", + "type": "expression" + }, + { + "description": "Waiting maximum camera target speed X", + "name": "NewWaitingSpeedXMax", + "type": "expression" + }, + { + "description": "Waiting maximum camera target speed Y", + "name": "NewWaitingSpeedYMax", + "type": "expression" + }, + { + "description": "Catch up duration (in seconds)", + "name": "NewCatchUpDuration", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Draw the targeted and actual camera position.", + "fullName": "Draw debug", + "functionType": "Action", + "name": "DrawDebug", + "sentence": "Draw targeted and actual camera position for _PARAM0_ on _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "PrimitiveDrawing::FillOpacity" + }, + "parameters": [ + "ShapePainter", + "=", + "0" + ] + } + ] + }, + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Path used by the forecasting", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::CompareNumbers" + }, + "parameters": [ + "Object.VariableChildCount(__SmoothCamera.ForecastHistoryTime)", + ">", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "Index", + "=", + "0" + ] + }, + { + "type": { + "value": "PrimitiveDrawing::OutlineColor" + }, + "parameters": [ + "ShapePainter", + "\"245;166;35\"" + ] + }, + { + "type": { + "value": "PrimitiveDrawing::BeginFillPath" + }, + "parameters": [ + "ShapePainter", + "Object.Variable(__SmoothCamera.ForecastHistoryX[0])", + "Object.Variable(__SmoothCamera.ForecastHistoryY[0])" + ] + } + ], + "events": [ + { + "type": "BuiltinCommonInstructions::Repeat", + "repeatExpression": "Object.VariableChildCount(__SmoothCamera.ForecastHistoryX)", + "conditions": [], + "actions": [ + { + "type": { + "value": "PrimitiveDrawing::PathLineTo" + }, + "parameters": [ + "ShapePainter", + "Object.Variable(__SmoothCamera.ForecastHistoryX[Index])", + "Object.Variable(__SmoothCamera.ForecastHistoryY[Index])" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "Index", + "+", + "1" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "PrimitiveDrawing::EndFillPath" + }, + "parameters": [ + "ShapePainter" + ] + } + ] + } + ] + } + ], + "parameters": [] + }, + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Follow-free area.", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::Or" + }, + "parameters": [], + "subInstructions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "FollowFreeAreaLeft", + "!=", + "0" + ] + }, + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "FollowFreeAreaRight", + "!=", + "0" + ] + }, + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "FollowFreeAreaTop", + "!=", + "0" + ] + }, + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "FollowFreeAreaBottom", + "!=", + "0" + ] + } + ] + } + ], + "actions": [ + { + "type": { + "value": "PrimitiveDrawing::OutlineColor" + }, + "parameters": [ + "ShapePainter", + "\"126;211;33\"" + ] + }, + { + "type": { + "value": "PrimitiveDrawing::Rectangle" + }, + "parameters": [ + "ShapePainter", + "Object.Behavior::FreeAreaLeft() - 1", + "Object.Behavior::FreeAreaTop() - 1", + "Object.Behavior::FreeAreaRight() + 1", + "Object.Behavior::FreeAreaBottom() + 1" + ] + } + ] + } + ], + "parameters": [] + }, + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Linear regression vector used by the forecasting.", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "PrimitiveDrawing::OutlineColor" + }, + "parameters": [ + "ShapePainter", + "\"208;2;27\"" + ] + }, + { + "type": { + "value": "PrimitiveDrawing::LineV2" + }, + "parameters": [ + "ShapePainter", + "ProjectedOldestX", + "ProjectedOldestY", + "ProjectedNewestX", + "ProjectedNewestY", + "1" + ] + } + ] + } + ], + "parameters": [] + }, + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Targeted and actual camera position", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "PrimitiveDrawing::Circle" + }, + "parameters": [ + "ShapePainter", + "ForecastedX", + "ForecastedY", + "3" + ] + }, + { + "type": { + "value": "PrimitiveDrawing::LineV2" + }, + "parameters": [ + "ShapePainter", + "CameraX(Object.Layer(), 0)", + "CameraY(Object.Layer(), 0) - 4", + "CameraX(Object.Layer(), 0)", + "CameraY(Object.Layer(), 0) + 4", + "1" + ] + }, + { + "type": { + "value": "PrimitiveDrawing::LineV2" + }, + "parameters": [ + "ShapePainter", + "CameraX(Object.Layer(), 0) - 4", + "CameraY(Object.Layer(), 0)", + "CameraX(Object.Layer(), 0) + 4", + "CameraY(Object.Layer(), 0)", + "1" + ] + } + ] + } + ], + "parameters": [] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Shape painter", + "name": "ShapePainter", + "supplementaryInformation": "PrimitiveDrawing::Drawer", + "type": "objectList" + } + ], + "objectGroups": [] + }, + { + "description": "Enable or disable the following on X axis.", + "fullName": "Follow on X", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetFollowOnX", + "sentence": "The camera follows _PARAM0_ on X axis: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetBooleanVariable" + }, + "parameters": [ + "FollowOnX", + "False", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BooleanVariable" + }, + "parameters": [ + "Value", + "True", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetBooleanVariable" + }, + "parameters": [ + "FollowOnX", + "True", + "" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Follow on X axis", + "name": "Value", + "type": "yesorno" + } + ], + "objectGroups": [] + }, + { + "description": "Enable or disable the following on Y axis.", + "fullName": "Follow on Y", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetFollowOnY", + "sentence": "The camera follows _PARAM0_ on Y axis: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetBooleanVariable" + }, + "parameters": [ + "FollowOnY", + "False", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BooleanVariable" + }, + "parameters": [ + "Value", + "True", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetBooleanVariable" + }, + "parameters": [ + "FollowOnY", + "True", + "" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Follow on Y axis", + "name": "Value", + "type": "yesorno" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera follow free area right border.", + "fullName": "Follow free area right border", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetFollowFreeAreaRight", + "sentence": "Change the camera follow free area right border of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "FollowFreeAreaRight", + "=", + "max(0, Value)" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Follow free area right border", + "name": "Value", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera follow free area left border.", + "fullName": "Follow free area left border", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetFollowFreeAreaLeft", + "sentence": "Change the camera follow free area left border of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "FollowFreeAreaLeft", + "=", + "max(0, Value)" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Follow free area left border", + "name": "Value", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera follow free area top border.", + "fullName": "Follow free area top border", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetFollowFreeAreaTop", + "sentence": "Change the camera follow free area top border of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "FollowFreeAreaTop", + "=", + "max(0, Value)" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Follow free area top border", + "name": "Value", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera follow free area bottom border.", + "fullName": "Follow free area bottom border", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetFollowFreeAreaBottom", + "sentence": "Change the camera follow free area bottom border of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "FollowFreeAreaBottom", + "=", + "max(0, Value)" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Follow free area bottom border", + "name": "Value", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera leftward maximum speed (in pixels per second).", + "fullName": "Leftward maximum speed", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetLeftwardSpeedMax", + "sentence": "Change the camera leftward maximum speed of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "LeftwardSpeedMax", + "=", + "max(0, Value)" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Leftward maximum speed (in pixels per second)", + "name": "Value", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera rightward maximum speed (in pixels per second).", + "fullName": "Rightward maximum speed", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetRightwardSpeedMax", + "sentence": "Change the camera rightward maximum speed of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "RightwardSpeedMax", + "=", + "max(0, Value)" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Rightward maximum speed (in pixels per second)", + "name": "Value", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera upward maximum speed (in pixels per second).", + "fullName": "Upward maximum speed", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetUpwardSpeedMax", + "sentence": "Change the camera upward maximum speed of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "UpwardSpeedMax", + "=", + "max(0, Value)" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Upward maximum speed (in pixels per second)", + "name": "Value", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera downward maximum speed (in pixels per second).", + "fullName": "Downward maximum speed", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetDownwardSpeedMax", + "sentence": "Change the camera downward maximum speed of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "DownwardSpeedMax", + "=", + "max(0, Value)" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Downward maximum speed (in pixels per second)", + "name": "Value", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera leftward catch-up speed (in ratio per second).", + "fullName": "Leftward catch-up speed", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetLeftwardSpeed", + "sentence": "Change the camera leftward catch-up speed of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "LeftwardSpeed", + "=", + "clamp(0, 1, Value)" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "LogLeftwardSpeed", + "=", + "log(1 - Value)" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Leftward catch-up speed (in ratio per second)", + "name": "Value", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera rightward catch-up speed (in ratio per second).", + "fullName": "Rightward catch-up speed", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetRightwardSpeed", + "sentence": "Change the camera rightward catch-up speed of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "RightwardSpeed", + "=", + "clamp(0, 1, Value)" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "LogRightwardSpeed", + "=", + "log(1 - Value)" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Rightward catch-up speed (in ratio per second)", + "name": "Value", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera downward catch-up speed (in ratio per second).", + "fullName": "Downward catch-up speed", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetDownwardSpeed", + "sentence": "Change the camera downward catch-up speed of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "DownwardSpeed", + "=", + "clamp(0, 1, Value)" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "LogDownwardSpeed", + "=", + "log(1 - Value)" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Downward catch-up speed (in ratio per second)", + "name": "Value", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera upward catch-up speed (in ratio per second).", + "fullName": "Upward catch-up speed", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetUpwardSpeed", + "sentence": "Change the camera upward catch-up speed of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "UpwardSpeed", + "=", + "clamp(0, 1, Value)" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "LogUpwardSpeed", + "=", + "log(1 - Value)" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Upward catch-up speed (in ratio per second)", + "name": "Value", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the camera offset on X axis of the object. This is not the current difference between the object and the camera position.", + "fullName": "Camera offset X", + "functionType": "ExpressionAndCondition", + "group": "Camera configuration", + "name": "OffsetX", + "sentence": "the camera offset on X axis", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "CameraOffsetX" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "ActionWithOperator", + "getterName": "OffsetX", + "group": "Camera configuration", + "name": "SetOffsetXOp", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "CameraOffsetX", + "=", + "Value" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera offset on X axis of an object.", + "fullName": "Camera Offset X", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetOffsetX", + "private": true, + "sentence": "Change the camera offset on X axis of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Deprecated use SetOffsetXOp instead." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetOffsetXOp" + }, + "parameters": [ + "Object", + "Behavior", + "=", + "Value", + "" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Camera offset X", + "name": "Value", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the camera offset on Y axis of the object. This is not the current difference between the object and the camera position.", + "fullName": "Camera offset Y", + "functionType": "ExpressionAndCondition", + "group": "Camera configuration", + "name": "OffsetY", + "sentence": "the camera offset on Y axis", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "CameraOffsetY" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "ActionWithOperator", + "getterName": "OffsetY", + "group": "Camera configuration", + "name": "SetOffsetYOp", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "CameraOffsetY", + "=", + "Value" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera offset on Y axis of an object.", + "fullName": "Camera Offset Y", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetOffsetY", + "private": true, + "sentence": "Change the camera offset on Y axis of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Deprecated use SetOffsetYOp instead." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetOffsetYOp" + }, + "parameters": [ + "Object", + "Behavior", + "=", + "CameraOffsetY", + "" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Camera offset Y", + "name": "CameraOffsetY", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera forecast time (in seconds).", + "fullName": "Forecast time", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetForecastTime", + "sentence": "Change the camera forecast time of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastTime", + "=", + "min(0, Value)" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Forecast time", + "name": "Value", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Change the camera delay (in seconds).", + "fullName": "Camera delay", + "functionType": "Action", + "group": "Camera configuration", + "name": "SetCameraDelay", + "sentence": "Change the camera delay of _PARAM0_: _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "CameraDelay", + "=", + "max(0, Value)" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Camera delay", + "name": "Value", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Return follow free area left border X.", + "fullName": "Free area left", + "functionType": "Expression", + "group": "Private", + "name": "FreeAreaLeft", + "private": true, + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "ForecastedX + CameraOffsetX - FollowFreeAreaLeft" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Return follow free area right border X.", + "fullName": "Free area right", + "functionType": "Expression", + "group": "Private", + "name": "FreeAreaRight", + "private": true, + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "ForecastedX + CameraOffsetX + FollowFreeAreaRight" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Return follow free area bottom border Y.", + "fullName": "Free area bottom", + "functionType": "Expression", + "group": "Private", + "name": "FreeAreaBottom", + "private": true, + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "ForecastedY + CameraOffsetY + FollowFreeAreaBottom" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Return follow free area top border Y.", + "fullName": "Free area top", + "functionType": "Expression", + "group": "Private", + "name": "FreeAreaTop", + "private": true, + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "ForecastedY + CameraOffsetY - FollowFreeAreaTop" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Update delayed position and delayed history. This is called in doStepPreEvents.", + "fullName": "Update delayed position", + "functionType": "Action", + "group": "Private", + "name": "UpdateDelayedPosition", + "private": true, + "sentence": "Update delayed position and delayed history of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Add the previous position to have enough (2) positions to evaluate the extra delay for waiting mode." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "SmoothCamera::SmoothCamera::IsWaiting" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + }, + { + "type": { + "value": "BuiltinCommonInstructions::CompareNumbers" + }, + "parameters": [ + "Object.VariableChildCount(__SmoothCamera.ObjectTime)", + "=", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "ObjectVariablePushNumber" + }, + "parameters": [ + "Object", + "__SmoothCamera.ObjectTime", + "TimeFromStart()" + ] + }, + { + "type": { + "value": "ObjectVariablePushNumber" + }, + "parameters": [ + "Object", + "__SmoothCamera.ObjectX", + "DelayedCenterX" + ] + }, + { + "type": { + "value": "ObjectVariablePushNumber" + }, + "parameters": [ + "Object", + "__SmoothCamera.ObjectY", + "DelayedCenterY" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Use the object center when no delay is asked." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "DelayedCenterX", + "=", + "Object.CenterX()" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "DelayedCenterY", + "=", + "Object.CenterY()" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "inverted": true, + "value": "SmoothCamera::SmoothCamera::IsDelayed" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "SmoothCamera::SmoothCamera::AddForecastHistoryPosition" + }, + "parameters": [ + "Object", + "Behavior", + "TimeFromStart()", + "Object.CenterX()", + "Object.CenterY()", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::Or" + }, + "parameters": [], + "subInstructions": [ + { + "type": { + "value": "SmoothCamera::SmoothCamera::IsDelayed" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::IsWaiting" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + } + ] + } + ], + "actions": [ + { + "type": { + "value": "ObjectVariablePushNumber" + }, + "parameters": [ + "Object", + "__SmoothCamera.ObjectTime", + "TimeFromStart()" + ] + }, + { + "type": { + "value": "ObjectVariablePushNumber" + }, + "parameters": [ + "Object", + "__SmoothCamera.ObjectX", + "Object.CenterX()" + ] + }, + { + "type": { + "value": "ObjectVariablePushNumber" + }, + "parameters": [ + "Object", + "__SmoothCamera.ObjectY", + "Object.CenterY()" + ] + } + ], + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Remove history entries that are too old to be useful for delaying and pass it to the history for forecasting." + }, + { + "infiniteLoopWarning": true, + "type": "BuiltinCommonInstructions::While", + "whileConditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::CompareNumbers" + }, + "parameters": [ + "Object.VariableChildCount(__SmoothCamera.ObjectTime)", + ">=", + "2" + ] + }, + { + "type": { + "value": "VarObjet" + }, + "parameters": [ + "Object", + "__SmoothCamera.ObjectTime[1]", + "<", + "TimeFromStart() - Object.Behavior::CurrentDelay()" + ] + } + ], + "conditions": [], + "actions": [ + { + "type": { + "value": "SmoothCamera::SmoothCamera::AddForecastHistoryPosition" + }, + "parameters": [ + "Object", + "Behavior", + "Object.Variable(__SmoothCamera.ObjectTime[0])", + "Object.Variable(__SmoothCamera.ObjectX[0])", + "Object.Variable(__SmoothCamera.ObjectY[0])", + "" + ] + }, + { + "type": { + "value": "ObjectVariableRemoveAt" + }, + "parameters": [ + "Object", + "__SmoothCamera.ObjectTime", + "0" + ] + }, + { + "type": { + "value": "ObjectVariableRemoveAt" + }, + "parameters": [ + "Object", + "__SmoothCamera.ObjectX", + "0" + ] + }, + { + "type": { + "value": "ObjectVariableRemoveAt" + }, + "parameters": [ + "Object", + "__SmoothCamera.ObjectY", + "0" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Don't move the camera if there is not enough history." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "DelayedCenterX", + "=", + "Object.Variable(__SmoothCamera.ObjectX[0])" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "DelayedCenterY", + "=", + "Object.Variable(__SmoothCamera.ObjectY[0])" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::CompareNumbers" + }, + "parameters": [ + "Object.VariableChildCount(__SmoothCamera.ObjectTime)", + ">=", + "2" + ] + }, + { + "type": { + "value": "VarObjet" + }, + "parameters": [ + "Object", + "__SmoothCamera.ObjectTime[0]", + "<", + "TimeFromStart() - Object.Behavior::CurrentDelay()" + ] + } + ], + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Add the extra delay that could be needed to respect the speed limit in waiting mode.\n\nspeedRatio = min(speedMaxX / historySpeedX, speedMaxY / historySpeedY)\ndelay += min(0, timeDelta * (1 - speedRatio))" + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "SmoothCamera::SmoothCamera::IsWaiting" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "CameraExtraDelay", + "+", + "max(0, TimeDelta() * (1 - min(WaitingSpeedXMax * abs(Object.Variable(__SmoothCamera.ObjectX[1]) - Object.Variable(__SmoothCamera.ObjectX[0])), WaitingSpeedYMax * abs(Object.Variable(__SmoothCamera.ObjectY[1]) - Object.Variable(__SmoothCamera.ObjectY[0]))) / (Object.Variable(__SmoothCamera.ObjectTime[1]) - Object.Variable(__SmoothCamera.ObjectTime[0]))))" + ] + } + ], + "events": [ + { + "disabled": true, + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "DebuggerTools::ConsoleLog" + }, + "parameters": [ + "\"Extra delay: \" + ToString(CameraExtraDelay)", + "\"info\"", + "\"SmoothCamera\"" + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "The time with delay is now between the first 2 indexes" + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "DelayedCenterX", + "=", + "lerp(Object.Variable(__SmoothCamera.ObjectX[1]), Object.Variable(__SmoothCamera.ObjectX[0]), ((TimeFromStart() - Object.Behavior::CurrentDelay()) - Object.Variable(__SmoothCamera.ObjectTime[1])) / (Object.Variable(__SmoothCamera.ObjectTime[0]) - Object.Variable(__SmoothCamera.ObjectTime[1])))" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "DelayedCenterY", + "=", + "lerp(Object.Variable(__SmoothCamera.ObjectY[1]), Object.Variable(__SmoothCamera.ObjectY[0]), ((TimeFromStart() - Object.Behavior::CurrentDelay()) - Object.Variable(__SmoothCamera.ObjectTime[1])) / (Object.Variable(__SmoothCamera.ObjectTime[0]) - Object.Variable(__SmoothCamera.ObjectTime[1])))" + ] + } + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "inverted": true, + "value": "SmoothCamera::SmoothCamera::IsDelayed" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + }, + { + "type": { + "inverted": true, + "value": "SmoothCamera::SmoothCamera::IsWaiting" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "ObjectVariableClearChildren" + }, + "parameters": [ + "Object", + "__SmoothCamera.ObjectTime" + ] + }, + { + "type": { + "value": "ObjectVariableClearChildren" + }, + "parameters": [ + "Object", + "__SmoothCamera.ObjectX" + ] + }, + { + "type": { + "value": "ObjectVariableClearChildren" + }, + "parameters": [ + "Object", + "__SmoothCamera.ObjectY" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "inverted": true, + "value": "SmoothCamera::SmoothCamera::IsWaiting" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + }, + { + "type": { + "value": "BuiltinCommonInstructions::Once" + }, + "parameters": [] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "CameraDelayCatchUpSpeed", + "=", + "CameraExtraDelay / CameraDelayCatchUpDuration" + ] + } + ], + "events": [ + { + "disabled": true, + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "DebuggerTools::ConsoleLog" + }, + "parameters": [ + "\"Start to catch up\"", + "\"info\"", + "\"SmoothCamera\"" + ] + } + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "inverted": true, + "value": "SmoothCamera::SmoothCamera::IsWaiting" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + }, + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "CameraExtraDelay", + ">", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "CameraExtraDelay", + "=", + "max(0, CameraExtraDelay -CameraDelayCatchUpSpeed * TimeDelta())" + ] + } + ], + "events": [ + { + "disabled": true, + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "DebuggerTools::ConsoleLog" + }, + "parameters": [ + "\"Catching up delay: \" + ToString(CameraExtraDelay)", + "\"info\"", + "\"SmoothCamera\"" + ] + } + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Check if the camera following target is delayed from the object.", + "fullName": "Camera is delayed", + "functionType": "Condition", + "name": "IsDelayed", + "private": true, + "sentence": "The camera of _PARAM0_ is delayed", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::CompareNumbers" + }, + "parameters": [ + "Object.Behavior::CurrentDelay()", + ">", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Return the current camera delay.", + "fullName": "Current delay", + "functionType": "Expression", + "name": "CurrentDelay", + "private": true, + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "CameraDelay + CameraExtraDelay" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Check if the camera following is waiting at a reduced speed.", + "fullName": "Camera is waiting", + "functionType": "Condition", + "name": "IsWaiting", + "private": true, + "sentence": "The camera of _PARAM0_ is waiting", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "WaitingEnd", + ">", + "TimeFromStart()" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Add a position to the history for forecasting. This is called 2 times in UpadteDelayedPosition.", + "fullName": "Add forecast history position", + "functionType": "Action", + "group": "Private", + "name": "AddForecastHistoryPosition", + "private": true, + "sentence": "Add the time:_PARAM2_ and position: _PARAM3_; _PARAM4_ to the forecast history of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::Or" + }, + "parameters": [], + "subInstructions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "ForecastHistoryDuration", + ">", + "0" + ] + }, + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "ForecastTime", + ">", + "0" + ] + } + ] + } + ], + "actions": [ + { + "type": { + "value": "ObjectVariablePushNumber" + }, + "parameters": [ + "Object", + "__SmoothCamera.ForecastHistoryTime", + "Time" + ] + }, + { + "type": { + "value": "ObjectVariablePushNumber" + }, + "parameters": [ + "Object", + "__SmoothCamera.ForecastHistoryX", + "ObjectX" + ] + }, + { + "type": { + "value": "ObjectVariablePushNumber" + }, + "parameters": [ + "Object", + "__SmoothCamera.ForecastHistoryY", + "ObjectY" + ] + } + ], + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Remove history entries that are too old to be useful.\nKeep at least 2 positions because no forecast can be done with less positions." + }, + { + "infiniteLoopWarning": true, + "type": "BuiltinCommonInstructions::While", + "whileConditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::CompareNumbers" + }, + "parameters": [ + "Object.VariableChildCount(__SmoothCamera.ForecastHistoryTime)", + ">=", + "3" + ] + }, + { + "type": { + "value": "VarObjet" + }, + "parameters": [ + "Object", + "__SmoothCamera.ForecastHistoryTime[0]", + "<", + "TimeFromStart() - CameraDelay - CameraExtraDelay - ForecastHistoryDuration" + ] + } + ], + "conditions": [], + "actions": [ + { + "type": { + "value": "ObjectVariableRemoveAt" + }, + "parameters": [ + "Object", + "__SmoothCamera.ForecastHistoryTime", + "0" + ] + }, + { + "type": { + "value": "ObjectVariableRemoveAt" + }, + "parameters": [ + "Object", + "__SmoothCamera.ForecastHistoryX", + "0" + ] + }, + { + "type": { + "value": "ObjectVariableRemoveAt" + }, + "parameters": [ + "Object", + "__SmoothCamera.ForecastHistoryY", + "0" + ] + } + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "Time", + "name": "Time", + "type": "expression" + }, + { + "description": "Object X", + "name": "ObjectX", + "type": "expression" + }, + { + "description": "Object Y", + "name": "ObjectY", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Update forecasted position. This is called in doStepPreEvents.", + "fullName": "Update forecasted position", + "functionType": "Action", + "group": "Private", + "name": "UpdateForecastedPosition", + "private": true, + "sentence": "Update forecasted position of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastedX", + "=", + "DelayedCenterX" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastedY", + "=", + "DelayedCenterY" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Simple linear regression\ny = A * x + B\n\nA = Covariance / VarianceX\nB = MeanY - A * MeanX\n\nNote than we could use only one position every N positions to reduce the process time,\nbut if we really need efficient process JavaScript and circular queues are a must." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::CompareNumbers" + }, + "parameters": [ + "Object.VariableChildCount(__SmoothCamera.ForecastHistoryTime)", + ">=", + "2" + ] + }, + { + "type": { + "value": "BuiltinCommonInstructions::Or" + }, + "parameters": [], + "subInstructions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "ForecastHistoryDuration", + ">", + "0" + ] + }, + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "ForecastTime", + ">", + "0" + ] + } + ] + } + ], + "actions": [], + "events": [ + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Mean X", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryMeanX", + "=", + "0" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "Index", + "=", + "0" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Repeat", + "repeatExpression": "Object.VariableChildCount(__SmoothCamera.ForecastHistoryX)", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryMeanX", + "+", + "Object.Variable(__SmoothCamera.ForecastHistoryX[Index])" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "Index", + "+", + "1" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryMeanX", + "/", + "Object.VariableChildCount(__SmoothCamera.ForecastHistoryX)" + ] + } + ] + } + ], + "parameters": [] + }, + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Mean Y", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryMeanY", + "=", + "0" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "Index", + "=", + "0" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Repeat", + "repeatExpression": "Object.VariableChildCount(__SmoothCamera.ForecastHistoryY)", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryMeanY", + "+", + "Object.Variable(__SmoothCamera.ForecastHistoryY[Index])" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "Index", + "+", + "1" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryMeanY", + "/", + "Object.VariableChildCount(__SmoothCamera.ForecastHistoryY)" + ] + } + ] + }, + { + "disabled": true, + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "DebuggerTools::ConsoleLog" + }, + "parameters": [ + "\"Mean: \" + ToString(ForecastHistoryMeanX) + \" \" + ToString(ForecastHistoryMeanY)", + "", + "" + ] + } + ] + } + ], + "parameters": [] + }, + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Variance and Covariance", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "VarianceX = sum((X[i] - MeanX)²)\nVarianceY = sum((Y[i] - MeanY)²)\nCovariance = sum((X[i] - MeanX) * (Y[i] - MeanY))" + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryVarianceX", + "=", + "0" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryVarianceY", + "=", + "0" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryCovariance", + "=", + "0" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "Index", + "=", + "0" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Repeat", + "repeatExpression": "Object.VariableChildCount(__SmoothCamera.ForecastHistoryX)", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryVarianceX", + "+", + "pow(Object.Variable(__SmoothCamera.ForecastHistoryX[Index]) - ForecastHistoryMeanX, 2)" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryVarianceY", + "+", + "pow(Object.Variable(__SmoothCamera.ForecastHistoryY[Index]) - ForecastHistoryMeanY, 2)" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryCovariance", + "+", + "(Object.Variable(__SmoothCamera.ForecastHistoryX[Index]) - ForecastHistoryMeanX)\n*\n(Object.Variable(__SmoothCamera.ForecastHistoryY[Index]) - ForecastHistoryMeanY)" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "Index", + "+", + "1" + ] + } + ] + }, + { + "disabled": true, + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "DebuggerTools::ConsoleLog" + }, + "parameters": [ + "\"Variances: \" + ToString(ForecastHistoryVarianceX) + \" \" + ToString(ForecastHistoryVarianceY) + \" \" + ToString(ForecastHistoryCovariance)", + "\"info\"", + "\"SmoothCamera\"" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::CompareNumbers" + }, + "parameters": [ + "abs(ForecastHistoryVarianceX)", + "<", + "1" + ] + }, + { + "type": { + "value": "BuiltinCommonInstructions::CompareNumbers" + }, + "parameters": [ + "abs(ForecastHistoryVarianceY)", + "<", + "1" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastedX", + "=", + "DelayedCenterX" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastedY", + "=", + "DelayedCenterY" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::Or" + }, + "parameters": [], + "subInstructions": [ + { + "type": { + "value": "BuiltinCommonInstructions::CompareNumbers" + }, + "parameters": [ + "abs(ForecastHistoryVarianceX)", + ">=", + "1" + ] + }, + { + "type": { + "value": "BuiltinCommonInstructions::CompareNumbers" + }, + "parameters": [ + "abs(ForecastHistoryVarianceY)", + ">=", + "1" + ] + } + ] + } + ], + "actions": [], + "events": [ + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Linear function parameters", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "y = A * x + B\n\nA = Covariance / VarianceX\nB = MeanY - A * MeanX" + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::CompareNumbers" + }, + "parameters": [ + "abs(ForecastHistoryVarianceX)", + ">=", + "abs(ForecastHistoryVarianceY)" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryLinearA", + "=", + "ForecastHistoryCovariance / ForecastHistoryVarianceX" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryLinearB", + "=", + "ForecastHistoryMeanY - ForecastHistoryLinearA * ForecastHistoryMeanX" + ] + } + ], + "events": [ + { + "disabled": true, + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "DebuggerTools::ConsoleLog" + }, + "parameters": [ + "\"Linear: \" + ToString(ForecastHistoryLinearA) + \" \" + ToString(ForecastHistoryLinearB)", + "\"info\"", + "\"SmoothCamera\"" + ] + } + ] + }, + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Projection", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SmoothCamera::SmoothCamera::ProjectHistoryEnds" + }, + "parameters": [ + "Object", + "Behavior", + "Object.Variable(__SmoothCamera.ForecastHistoryX[0])", + "Object.Variable(__SmoothCamera.ForecastHistoryY[0])", + "Object.Variable(__SmoothCamera.ForecastHistoryX[Object.VariableChildCount(__SmoothCamera.ForecastHistoryX) - 1])", + "Object.Variable(__SmoothCamera.ForecastHistoryY[Object.VariableChildCount(__SmoothCamera.ForecastHistoryY) - 1])", + "" + ] + } + ] + } + ], + "parameters": [] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Axis permutation to avoid a ratio between 2 numbers near 0." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::CompareNumbers" + }, + "parameters": [ + "abs(ForecastHistoryVarianceX)", + "<", + "abs(ForecastHistoryVarianceY)" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryLinearA", + "=", + "ForecastHistoryCovariance / ForecastHistoryVarianceY" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastHistoryLinearB", + "=", + "ForecastHistoryMeanX - ForecastHistoryLinearA * ForecastHistoryMeanY" + ] + } + ], + "events": [ + { + "disabled": true, + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "DebuggerTools::ConsoleLog" + }, + "parameters": [ + "\"Linear: \" + ToString(ForecastHistoryLinearA) + \" \" + ToString(ForecastHistoryLinearB)", + "\"info\"", + "\"SmoothCamera\"" + ] + } + ] + }, + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Projection", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SmoothCamera::SmoothCamera::ProjectHistoryEnds" + }, + "parameters": [ + "Object", + "Behavior", + "Object.Variable(__SmoothCamera.ForecastHistoryY[0])", + "Object.Variable(__SmoothCamera.ForecastHistoryX[0])", + "Object.Variable(__SmoothCamera.ForecastHistoryY[Object.VariableChildCount(__SmoothCamera.ForecastHistoryY) - 1])", + "Object.Variable(__SmoothCamera.ForecastHistoryX[Object.VariableChildCount(__SmoothCamera.ForecastHistoryX) - 1])", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Permute back axis" + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "Index", + "=", + "ProjectedOldestX" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ProjectedOldestX", + "=", + "ProjectedOldestY" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ProjectedOldestY", + "=", + "Index" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "Index", + "=", + "ProjectedNewestX" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ProjectedNewestX", + "=", + "ProjectedNewestY" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ProjectedNewestY", + "=", + "Index" + ] + } + ] + } + ], + "parameters": [] + }, + { + "disabled": true, + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "DebuggerTools::ConsoleLog" + }, + "parameters": [ + "\"Oldest: \" + ToString(ProjectedOldestX) + \" \" + ToString(ProjectedOldestY)", + "\"info\"", + "\"SmoothCamera\"" + ] + } + ] + }, + { + "disabled": true, + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "DebuggerTools::ConsoleLog" + }, + "parameters": [ + "\"Newest: \" + ToString(ProjectedNewestX) + \" \" + ToString(ProjectedNewestY)", + "\"info\"", + "\"SmoothCamera\"" + ] + } + ] + } + ] + }, + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Forecasted position", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastedX", + "=", + "ProjectedNewestX + ( ProjectedNewestX - ProjectedOldestX) * Object.Behavior::ForecastTimeRatio()" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ForecastedY", + "=", + "ProjectedNewestY + ( ProjectedNewestY - ProjectedOldestY) * Object.Behavior::ForecastTimeRatio()" + ] + } + ] + }, + { + "disabled": true, + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "DebuggerTools::ConsoleLog" + }, + "parameters": [ + "\"Forecasted: \" + ToString(ForecastedX) + \" \" + ToString(ForecastedY)", + "\"info\"", + "\"SmoothCamera\"" + ] + } + ] + } + ], + "parameters": [] + } + ], + "parameters": [] + } + ] + } + ], + "parameters": [] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Project history ends position to have the vector on the line from linear regression. This function is only called by UpdateForecastedPosition.", + "fullName": "Project history ends", + "functionType": "Action", + "group": "Private", + "name": "ProjectHistoryEnds", + "private": true, + "sentence": "Project history oldest: _PARAM2_;_PARAM3_ and newest position: _PARAM4_;_PARAM5_ of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Perpendicular line:\npA = -1/a; \npB = -pA * x + y\n\nIntersection:\n/ ProjectedY = a * ProjectedX + b\n\\ ProjectedY = pA * ProjectedX + b\n\nSolution that is cleaned out from indeterminism (like 0 / 0 or infinity / infinity):\nProjectedX= (x + (y - b) * a) / (a² + 1)\nProjectedY = y + (x * a - y + b) / (a² + 1)" + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ProjectedNewestX", + "=", + "(NewestX + (NewestY - ForecastHistoryLinearB) * ForecastHistoryLinearA) / (1 + pow(ForecastHistoryLinearA, 2))" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ProjectedNewestY", + "=", + "NewestY + (NewestX * ForecastHistoryLinearA - NewestY \n+ ForecastHistoryLinearB) / (1 + pow(ForecastHistoryLinearA, 2))" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ProjectedOldestX", + "=", + "(OldestX + (OldestY - ForecastHistoryLinearB) * ForecastHistoryLinearA) / (1 + pow(ForecastHistoryLinearA, 2))" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "ProjectedOldestY", + "=", + "OldestY + (OldestX * ForecastHistoryLinearA - OldestY \n+ ForecastHistoryLinearB) / (1 + pow(ForecastHistoryLinearA, 2))" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + }, + { + "description": "OldestX", + "name": "OldestX", + "type": "expression" + }, + { + "description": "OldestY", + "name": "OldestY", + "type": "expression" + }, + { + "description": "Newest X", + "name": "NewestX", + "type": "expression" + }, + { + "description": "Newest Y", + "name": "NewestY", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Return the ratio between forecast time and the duration of the history. This function is only called by UpdateForecastedPosition.", + "fullName": "Forecast time ratio", + "functionType": "Expression", + "group": "Private", + "name": "ForecastTimeRatio", + "private": true, + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetReturnNumber" + }, + "parameters": [ + "- ForecastTime / (Object.Variable(__SmoothCamera.ForecastHistoryTime[0]) - Object.Variable(__SmoothCamera.ForecastHistoryTime[Object.VariableChildCount(__SmoothCamera.ForecastHistoryTime) - 1]))" + ] + } + ] + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothCamera", + "type": "behavior" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "doStepPreEvents" + }, + { + "functionName": "MoveCameraCloser" + }, + { + "functionName": "DoMoveCameraCloser" + }, + { + "functionName": "WaitAndCatchUp" + }, + { + "functionName": "DrawDebug" + }, + { + "folderName": "Camera configuration", + "children": [ + { + "functionName": "SetFollowOnX" + }, + { + "functionName": "SetFollowOnY" + }, + { + "functionName": "SetFollowFreeAreaRight" + }, + { + "functionName": "SetFollowFreeAreaLeft" + }, + { + "functionName": "SetFollowFreeAreaTop" + }, + { + "functionName": "SetFollowFreeAreaBottom" + }, + { + "functionName": "SetLeftwardSpeedMax" + }, + { + "functionName": "SetRightwardSpeedMax" + }, + { + "functionName": "SetUpwardSpeedMax" + }, + { + "functionName": "SetDownwardSpeedMax" + }, + { + "functionName": "SetLeftwardSpeed" + }, + { + "functionName": "SetRightwardSpeed" + }, + { + "functionName": "SetDownwardSpeed" + }, + { + "functionName": "SetUpwardSpeed" + }, + { + "functionName": "OffsetX" + }, + { + "functionName": "SetOffsetXOp" + }, + { + "functionName": "SetOffsetX" + }, + { + "functionName": "OffsetY" + }, + { + "functionName": "SetOffsetYOp" + }, + { + "functionName": "SetOffsetY" + }, + { + "functionName": "SetForecastTime" + }, + { + "functionName": "SetCameraDelay" + } + ] + }, + { + "folderName": "Private", + "children": [ + { + "functionName": "FreeAreaLeft" + }, + { + "functionName": "FreeAreaRight" + }, + { + "functionName": "FreeAreaBottom" + }, + { + "functionName": "FreeAreaTop" + }, + { + "functionName": "UpdateDelayedPosition" + }, + { + "functionName": "AddForecastHistoryPosition" + }, + { + "functionName": "UpdateForecastedPosition" + }, + { + "functionName": "ProjectHistoryEnds" + }, + { + "functionName": "ForecastTimeRatio" + } + ] + }, + { + "functionName": "IsDelayed" + }, + { + "functionName": "CurrentDelay" + }, + { + "functionName": "IsWaiting" + } + ] + }, + "propertyDescriptors": [ + { + "value": "0.9", + "type": "Number", + "label": "Leftward catch-up speed (in ratio per second)", + "group": "Catch-up speed", + "name": "LeftwardSpeed" + }, + { + "value": "0.9", + "type": "Number", + "label": "Rightward catch-up speed (in ratio per second)", + "group": "Catch-up speed", + "name": "RightwardSpeed" + }, + { + "value": "0.9", + "type": "Number", + "label": "Upward catch-up speed (in ratio per second)", + "group": "Catch-up speed", + "name": "UpwardSpeed" + }, + { + "value": "0.9", + "type": "Number", + "label": "Downward catch-up speed (in ratio per second)", + "group": "Catch-up speed", + "name": "DownwardSpeed" + }, + { + "value": "true", + "type": "Boolean", + "label": "Follow on X axis", + "name": "FollowOnX" + }, + { + "value": "true", + "type": "Boolean", + "label": "Follow on Y axis", + "name": "FollowOnY" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Follow free area left border", + "group": "Position", + "advanced": true, + "name": "FollowFreeAreaLeft" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Follow free area right border", + "group": "Position", + "advanced": true, + "name": "FollowFreeAreaRight" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Follow free area top border", + "group": "Position", + "advanced": true, + "name": "FollowFreeAreaTop" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Follow free area bottom border", + "group": "Position", + "advanced": true, + "name": "FollowFreeAreaBottom" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Camera offset X", + "group": "Position", + "advanced": true, + "name": "CameraOffsetX" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Camera offset Y", + "group": "Position", + "advanced": true, + "name": "CameraOffsetY" + }, + { + "value": "0", + "type": "Number", + "unit": "Second", + "label": "Camera delay", + "group": "Timing", + "deprecated": true, + "name": "CameraDelay" + }, + { + "value": "0", + "type": "Number", + "unit": "Second", + "label": "Forecast time", + "group": "Timing", + "deprecated": true, + "name": "ForecastTime" + }, + { + "value": "0", + "type": "Number", + "unit": "Second", + "label": "Forecast history duration", + "group": "Timing", + "deprecated": true, + "name": "ForecastHistoryDuration" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "LogLeftwardSpeed" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "LogRightwardSpeed" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "LogDownwardSpeed" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "LogUpwardSpeed" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "DelayedCenterX" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "DelayedCenterY" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "ForecastHistoryMeanX" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "ForecastHistoryMeanY" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "ForecastHistoryVarianceX" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "ForecastHistoryCovariance" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "ForecastHistoryLinearA" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "ForecastHistoryLinearB" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "ForecastedX" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "ForecastedY" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "ProjectedNewestX" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "ProjectedNewestY" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "ProjectedOldestX" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "ProjectedOldestY" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "ForecastHistoryVarianceY" + }, + { + "value": "", + "type": "Number", + "label": "Index (local variable)", + "hidden": true, + "name": "Index" + }, + { + "value": "0", + "type": "Number", + "label": "", + "hidden": true, + "name": "CameraDelayCatchUpSpeed" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "CameraExtraDelay" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "WaitingSpeedXMax" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "WaitingSpeedYMax" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "WaitingEnd" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "CameraDelayCatchUpDuration" + }, + { + "value": "9000", + "type": "Number", + "unit": "PixelSpeed", + "label": "Leftward maximum speed", + "group": "Maximum speed", + "advanced": true, + "name": "LeftwardSpeedMax" + }, + { + "value": "9000", + "type": "Number", + "unit": "PixelSpeed", + "label": "Rightward maximum speed", + "group": "Maximum speed", + "advanced": true, + "name": "RightwardSpeedMax" + }, + { + "value": "9000", + "type": "Number", + "unit": "PixelSpeed", + "label": "Upward maximum speed", + "group": "Maximum speed", + "advanced": true, + "name": "UpwardSpeedMax" + }, + { + "value": "9000", + "type": "Number", + "unit": "PixelSpeed", + "label": "Downward maximum speed", + "group": "Maximum speed", + "advanced": true, + "name": "DownwardSpeedMax" + }, + { + "value": "", + "type": "Number", + "label": "OldX (local variable)", + "hidden": true, + "name": "OldX" + }, + { + "value": "", + "type": "Number", + "label": "OldY (local variable)", + "hidden": true, + "name": "OldY" + }, + { + "value": "", + "type": "Boolean", + "label": "", + "hidden": true, + "name": "IsCalledManually" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Catch-up speed", + "children": [ + { + "propertyName": "LeftwardSpeed" + }, + { + "propertyName": "RightwardSpeed" + }, + { + "propertyName": "UpwardSpeed" + }, + { + "propertyName": "DownwardSpeed" + } + ] + }, + { + "propertyName": "FollowOnX" + }, + { + "propertyName": "FollowOnY" + }, + { + "folderName": "Position", + "children": [ + { + "propertyName": "FollowFreeAreaLeft" + }, + { + "propertyName": "FollowFreeAreaRight" + }, + { + "propertyName": "FollowFreeAreaTop" + }, + { + "propertyName": "FollowFreeAreaBottom" + }, + { + "propertyName": "CameraOffsetX" + }, + { + "propertyName": "CameraOffsetY" + } + ] + }, + { + "folderName": "Timing", + "children": [ + { + "propertyName": "CameraDelay" + }, + { + "propertyName": "ForecastTime" + }, + { + "propertyName": "ForecastHistoryDuration" + } + ] + }, + { + "propertyName": "LogLeftwardSpeed" + }, + { + "propertyName": "LogRightwardSpeed" + }, + { + "propertyName": "LogDownwardSpeed" + }, + { + "propertyName": "LogUpwardSpeed" + }, + { + "propertyName": "DelayedCenterX" + }, + { + "propertyName": "DelayedCenterY" + }, + { + "propertyName": "ForecastHistoryMeanX" + }, + { + "propertyName": "ForecastHistoryMeanY" + }, + { + "propertyName": "ForecastHistoryVarianceX" + }, + { + "propertyName": "ForecastHistoryCovariance" + }, + { + "propertyName": "ForecastHistoryLinearA" + }, + { + "propertyName": "ForecastHistoryLinearB" + }, + { + "propertyName": "ForecastedX" + }, + { + "propertyName": "ForecastedY" + }, + { + "propertyName": "ProjectedNewestX" + }, + { + "propertyName": "ProjectedNewestY" + }, + { + "propertyName": "ProjectedOldestX" + }, + { + "propertyName": "ProjectedOldestY" + }, + { + "propertyName": "ForecastHistoryVarianceY" + }, + { + "propertyName": "Index" + }, + { + "propertyName": "CameraDelayCatchUpSpeed" + }, + { + "propertyName": "CameraExtraDelay" + }, + { + "propertyName": "WaitingSpeedXMax" + }, + { + "propertyName": "WaitingSpeedYMax" + }, + { + "propertyName": "WaitingEnd" + }, + { + "propertyName": "CameraDelayCatchUpDuration" + }, + { + "folderName": "Maximum speed", + "children": [ + { + "propertyName": "LeftwardSpeedMax" + }, + { + "propertyName": "RightwardSpeedMax" + }, + { + "propertyName": "UpwardSpeedMax" + }, + { + "propertyName": "DownwardSpeedMax" + } + ] + }, + { + "propertyName": "OldX" + }, + { + "propertyName": "OldY" + }, + { + "propertyName": "IsCalledManually" + } + ] + } + }, + { + "description": "Smoothly scroll to follow a character and stabilize the camera when jumping.", + "fullName": "Smooth platformer camera", + "helpPath": "", + "iconUrl": "", + "name": "SmoothPlatformerCamera", + "objectType": "", + "previewIconUrl": "", + "quickCustomizationVisibility": "hidden", + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "doStepPreEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "inverted": true, + "value": "PlatformBehavior::IsJumping" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + }, + { + "type": { + "inverted": true, + "value": "PlatformBehavior::IsFalling" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + } + ], + "actions": [ + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetFollowFreeAreaBottom" + }, + "parameters": [ + "Object", + "SmoothCamera", + "FloorFollowFreeAreaTop", + "" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetFollowFreeAreaTop" + }, + "parameters": [ + "Object", + "SmoothCamera", + "FloorFollowFreeAreaBottom", + "" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetUpwardSpeed" + }, + "parameters": [ + "Object", + "SmoothCamera", + "FloorUpwardSpeed", + "" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetDownwardSpeed" + }, + "parameters": [ + "Object", + "SmoothCamera", + "FloorDownwardSpeed", + "" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetUpwardSpeedMax" + }, + "parameters": [ + "Object", + "SmoothCamera", + "FloorUpwardSpeedMax", + "" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetDownwardSpeedMax" + }, + "parameters": [ + "Object", + "SmoothCamera", + "FloorDownwardSpeedMax", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::Or" + }, + "parameters": [], + "subInstructions": [ + { + "type": { + "value": "PlatformBehavior::IsJumping" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + }, + { + "type": { + "value": "PlatformBehavior::IsFalling" + }, + "parameters": [ + "Object", + "PlatformerCharacter" + ] + } + ] + } + ], + "actions": [ + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetFollowFreeAreaBottom" + }, + "parameters": [ + "Object", + "SmoothCamera", + "AirFollowFreeAreaTop", + "" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetFollowFreeAreaTop" + }, + "parameters": [ + "Object", + "SmoothCamera", + "AirFollowFreeAreaBottom", + "" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetUpwardSpeed" + }, + "parameters": [ + "Object", + "SmoothCamera", + "AirUpwardSpeed", + "" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetDownwardSpeed" + }, + "parameters": [ + "Object", + "SmoothCamera", + "AirDownwardSpeed", + "" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetUpwardSpeedMax" + }, + "parameters": [ + "Object", + "SmoothCamera", + "AirUpwardSpeedMax", + "" + ] + }, + { + "type": { + "value": "SmoothCamera::SmoothCamera::SetDownwardSpeedMax" + }, + "parameters": [ + "Object", + "SmoothCamera", + "AirDownwardSpeedMax", + "" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "SmoothCamera::SmoothPlatformerCamera", + "type": "behavior" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "doStepPreEvents" + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Behavior", + "label": "Platformer character behavior", + "extraInformation": [ + "PlatformBehavior::PlatformerObjectBehavior" + ], + "choices": [], + "name": "PlatformerCharacter" + }, + { + "value": "", + "type": "Behavior", + "label": "Smooth camera behavior", + "extraInformation": [ + "SmoothCamera::SmoothCamera" + ], + "choices": [], + "name": "SmoothCamera" + }, + { + "value": "", + "type": "Number", + "label": "", + "hidden": true, + "name": "JumpOriginY" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Follow free area top in the air", + "group": "Position", + "name": "AirFollowFreeAreaTop" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Follow free area bottom in the air", + "group": "Position", + "name": "AirFollowFreeAreaBottom" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Follow free area top on the floor", + "group": "Position", + "name": "FloorFollowFreeAreaTop" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Follow free area bottom on the floor", + "group": "Position", + "name": "FloorFollowFreeAreaBottom" + }, + { + "value": "0.95", + "type": "Number", + "label": "Upward speed in the air (in ratio per second)", + "group": "Catch-up speed", + "name": "AirUpwardSpeed" + }, + { + "value": "0.95", + "type": "Number", + "label": "Downward speed in the air (in ratio per second)", + "group": "Catch-up speed", + "name": "AirDownwardSpeed" + }, + { + "value": "0.9", + "type": "Number", + "label": "Upward speed on the floor (in ratio per second)", + "group": "Catch-up speed", + "name": "FloorUpwardSpeed" + }, + { + "value": "0.9", + "type": "Number", + "label": "Downward speed on the floor (in ratio per second)", + "group": "Catch-up speed", + "name": "FloorDownwardSpeed" + }, + { + "value": "9000", + "type": "Number", + "unit": "PixelSpeed", + "label": "Upward maximum speed in the air", + "group": "Maximum speed", + "name": "AirUpwardSpeedMax" + }, + { + "value": "9000", + "type": "Number", + "unit": "PixelSpeed", + "label": "Downward maximum speed in the air", + "group": "Maximum speed", + "name": "AirDownwardSpeedMax" + }, + { + "value": "9000", + "type": "Number", + "unit": "PixelSpeed", + "label": "Upward maximum speed on the floor", + "group": "Maximum speed", + "name": "FloorUpwardSpeedMax" + }, + { + "value": "9000", + "type": "Number", + "unit": "PixelSpeed", + "label": "Downward maximum speed on the floor", + "group": "Maximum speed", + "name": "FloorDownwardSpeedMax" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "propertyName": "PlatformerCharacter" + }, + { + "propertyName": "SmoothCamera" + }, + { + "propertyName": "JumpOriginY" + }, + { + "folderName": "Position", + "children": [ + { + "propertyName": "AirFollowFreeAreaTop" + }, + { + "propertyName": "AirFollowFreeAreaBottom" + }, + { + "propertyName": "FloorFollowFreeAreaTop" + }, + { + "propertyName": "FloorFollowFreeAreaBottom" + } + ] + }, + { + "folderName": "Catch-up speed", + "children": [ + { + "propertyName": "AirUpwardSpeed" + }, + { + "propertyName": "AirDownwardSpeed" + }, + { + "propertyName": "FloorUpwardSpeed" + }, + { + "propertyName": "FloorDownwardSpeed" + } + ] + }, + { + "folderName": "Maximum speed", + "children": [ + { + "propertyName": "AirUpwardSpeedMax" + }, + { + "propertyName": "AirDownwardSpeedMax" + }, + { + "propertyName": "FloorUpwardSpeedMax" + }, + { + "propertyName": "FloorDownwardSpeedMax" + } + ] + } + ] + } + } + ], + "eventsBasedObjects": [] + }, + { + "author": "Westboy31", + "category": "Visual effect", + "dimension": "2D", + "extensionNamespace": "", + "fullName": "Flash and transition painter", + "gdevelopVersion": ">=5.5.222", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLW1vdmllLWZpbHRlciIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0xOCA0TDIwIDdIMTdMMTUgNEgxM0wxNSA3SDEyTDEwIDRIOEwxMCA3SDdMNSA0SDRDMi45IDQgMiA0LjkgMiA2TDIgMThDMiAxOS4xIDIuOSAyMCA0IDIwSDIwQzIxLjEgMjAgMjIgMTkuMSAyMiAxOFY0SDE4TTExLjI1IDE1LjI1TDEwIDE4TDguNzUgMTUuMjVMNiAxNEw4Ljc1IDEyLjc1TDEwIDEwTDExLjI1IDEyLjc1TDE0IDE0TDExLjI1IDE1LjI1TTE2Ljk0IDExLjk0TDE2IDE0TDE1LjA2IDExLjk0TDEzIDExTDE1LjA2IDEwLjA2TDE2IDhMMTYuOTQgMTAuMDZMMTkgMTFMMTYuOTQgMTEuOTRaIiAvPjwvc3ZnPg==", + "name": "FlashTransitionPainter", + "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/movie-filter.svg", + "shortDescription": "Screen transitions painted with plain color fill using Shape Painter.", + "version": "0.2.0", + "description": [ + "Paint transition effects", + "- Fade in, fade out", + "- Right to left", + "- Top to bottom", + "- Circular", + "", + "A blur effect can be added to the painter layer to smooth the transition." + ], + "origin": { + "identifier": "FlashTransitionPainter", + "name": "gdevelop-extension-store" + }, + "tags": [ + "flash", + "transition", + "effect" + ], + "authorIds": [], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT" + }, + "eventsBasedBehaviors": [ + { + "description": "Paint all over the screen a color for a period of time.", + "fullName": "Flash and transition painter", + "helpPath": "", + "iconUrl": "", + "name": "FlashTransitionPainter", + "objectType": "PrimitiveDrawing::Drawer", + "previewIconUrl": "", + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "ActivateBehavior" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "PrimitiveDrawing::Drawer", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "FlashTransitionPainter::FlashTransitionPainter", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Ensure shape painter properties are set correctly for this extension to work.\n" + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "BuiltinCommonInstructions::Once" + }, + "parameters": [] + } + ], + "actions": [ + { + "type": { + "value": "PrimitiveDrawing::ClearBetweenFrames" + }, + "parameters": [ + "Object", + "no" + ] + }, + { + "type": { + "value": "PrimitiveDrawing::OutlineSize" + }, + "parameters": [ + "Object", + "=", + "0" + ] + }, + { + "type": { + "value": "PrimitiveDrawing::UseRelativeCoordinates" + }, + "parameters": [ + "Object", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "Progress", + "=", + "min(1, Object.ObjectTimerElapsedTime(\"__FlashTransitionPainter_Time\") / Duration)" + ] + }, + { + "type": { + "value": "PrimitiveDrawing::Drawer::ClearShapes" + }, + "parameters": [ + "Object" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "Progress", + "=", + "1" + ] + } + ], + "actions": [ + { + "type": { + "value": "ActivateBehavior" + }, + "parameters": [ + "Object", + "Behavior", + "" + ] + }, + { + "type": { + "value": "PauseObjectTimer" + }, + "parameters": [ + "Object", + "\"__FlashTransitionPainter_Time\"" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "StringVariable" + }, + "parameters": [ + "Direction", + "=", + "\"Backward\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "Progress", + "=", + "1 - Progress" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "StringVariable" + }, + "parameters": [ + "Direction", + "=", + "\"Both\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "Progress", + "=", + "min(2 * Progress, 2 * (1 - Progress))" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "Progress", + ">", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "PrimitiveDrawing::FillOpacity" + }, + "parameters": [ + "Object", + "=", + "MaxOpacity" + ] + } + ], + "events": [ + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Flash", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "StringVariable" + }, + "parameters": [ + "Type", + "=", + "\"Flash\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "PrimitiveDrawing::FillOpacity" + }, + "parameters": [ + "Object", + "=", + "MaxOpacity * Progress" + ] + }, + { + "type": { + "value": "PrimitiveDrawing::Rectangle" + }, + "parameters": [ + "Object", + "CameraBorderLeft(Object.Layer())", + "CameraBorderTop(Object.Layer())", + "CameraBorderRight(Object.Layer())", + "CameraBorderBottom(Object.Layer())" + ] + } + ] + } + ], + "parameters": [] + }, + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Horizontal", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "from left to right" + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "StringVariable" + }, + "parameters": [ + "Type", + "=", + "\"Horizontal\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "PrimitiveDrawing::Rectangle" + }, + "parameters": [ + "Object", + "CameraBorderLeft(Object.Layer())", + "CameraBorderTop(Object.Layer())", + "lerp(CameraBorderLeft(Object.Layer()), CameraBorderRight(Object.Layer()), Progress)", + "CameraBorderBottom(Object.Layer())" + ] + } + ] + } + ], + "parameters": [] + }, + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Vertical", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "from top to bottom" + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "StringVariable" + }, + "parameters": [ + "Type", + "=", + "\"Vertical\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "PrimitiveDrawing::Rectangle" + }, + "parameters": [ + "Object", + "CameraBorderLeft(Object.Layer())", + "CameraBorderTop(Object.Layer())", + "CameraBorderRight(Object.Layer())", + "lerp(CameraBorderTop(Object.Layer()), CameraBorderBottom(Object.Layer()), Progress)" + ] + } + ] + } + ], + "parameters": [] + }, + { + "colorB": 228, + "colorG": 176, + "colorR": 74, + "creationTime": 0, + "name": "Circular", + "source": "", + "type": "BuiltinCommonInstructions::Group", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "A circle scale up from the middle." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "StringVariable" + }, + "parameters": [ + "Type", + "=", + "\"Circular\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "PrimitiveDrawing::Circle" + }, + "parameters": [ + "Object", + "CameraCenterX(Object.Layer())", + "CameraCenterY(Object.Layer())", + "(DistanceBetweenPositions(0, 0, CameraWidth(Object.Layer()), CameraHeight(Object.Layer())) / 2 + 1) * Progress" + ] + } + ] + } + ], + "parameters": [] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "PrimitiveDrawing::Drawer", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "FlashTransitionPainter::FlashTransitionPainter", + "type": "behavior" + } + ], + "objectGroups": [] + }, + { + "description": "Paint Effect.", + "fullName": "Paint Effect", + "functionType": "Action", + "name": "PaintEffect", + "sentence": "Paint effect type _PARAM4_ of _PARAM0_ with direction _PARAM5_ and color _PARAM2_ for _PARAM3_ seconds", + "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Initialise all variables and then activate the behavior.\nIf user doesn't assign value to color and type , we take the last value registred." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "inverted": true, + "value": "BehaviorActivated" + }, + "parameters": [ + "Object", + "Behavior" + ] + } + ], + "actions": [ + { + "type": { + "value": "ActivateBehavior" + }, + "parameters": [ + "Object", + "Behavior", + "yes" + ] + }, + { + "type": { + "value": "UnPauseObjectTimer" + }, + "parameters": [ + "Object", + "\"__FlashTransitionPainter_Time\"" + ] + }, + { + "type": { + "value": "ResetObjectTimer" + }, + "parameters": [ + "Object", + "\"__FlashTransitionPainter_Time\"" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "Duration", + "=", + "NewDuration" + ] + }, + { + "type": { + "value": "SetStringVariable" + }, + "parameters": [ + "Direction", + "=", + "NewDirection" + ] + }, + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "Progress", + "=", + "0" + ] + } + ], + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetStringVariable" + }, + "parameters": [ + "Type", + "=", + "\"Flash\"" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "StringVariable" + }, + "parameters": [ + "NewType", + "!=", + "\"\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetStringVariable" + }, + "parameters": [ + "Type", + "=", + "NewType" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "StringVariable" + }, + "parameters": [ + "Color", + "!=", + "\"\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "PrimitiveDrawing::FillColor" + }, + "parameters": [ + "Object", + "Color" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "MaxOpacity", + "=", + "255" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "NewMaxOpacity", + "!=", + "0" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetNumberVariable" + }, + "parameters": [ + "MaxOpacity", + "=", + "NewMaxOpacity" + ] + } + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "PrimitiveDrawing::Drawer", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "FlashTransitionPainter::FlashTransitionPainter", + "type": "behavior" + }, + { + "description": "Color", + "name": "Color", + "type": "color" + }, + { + "description": "Duration", + "name": "NewDuration", + "type": "expression" + }, + { + "description": "Type of effect ", + "name": "NewType", + "supplementaryInformation": "[\"Flash\",\"Horizontal\",\"Vertical\",\"Circular\"]", + "type": "stringWithSelector" + }, + { + "description": "Direction transition", + "name": "NewDirection", + "supplementaryInformation": "[\"Both\",\"Forward\",\"Backward\"]", + "type": "stringWithSelector" + }, + { + "description": "End opacity", + "name": "NewMaxOpacity", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint effect ended.", + "fullName": "Paint effect ended ", + "functionType": "Condition", + "name": "PaintEffectIsEnd", + "sentence": "When paint effect of _PARAM0_ ends", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "ObjectTimerPaused" + }, + "parameters": [ + "Object", + "\"__FlashTransitionPainter_Time\"" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "PrimitiveDrawing::Drawer", + "type": "object" + }, + { + "description": "Behavior", + "name": "Behavior", + "supplementaryInformation": "FlashTransitionPainter::FlashTransitionPainter", + "type": "behavior" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "PaintEffect" + }, + { + "functionName": "PaintEffectIsEnd" + } + ] + }, + "propertyDescriptors": [ + { + "value": "0", + "type": "Number", + "unit": "Dimensionless", + "label": "", + "hidden": true, + "name": "Progress" + }, + { + "value": "0", + "type": "Number", + "label": "", + "hidden": true, + "name": "Duration" + }, + { + "value": "", + "type": "String", + "label": "Type of effect ", + "hidden": true, + "name": "Type" + }, + { + "value": "", + "type": "String", + "label": "Direction of transition", + "hidden": true, + "name": "Direction" + }, + { + "value": "255", + "type": "Number", + "label": "The maximum of the opacity only for flash", + "hidden": true, + "name": "MaxOpacity" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "propertyName": "Progress" + }, + { + "propertyName": "Duration" + }, + { + "propertyName": "Type" + }, + { + "propertyName": "Direction" + }, + { + "propertyName": "MaxOpacity" + } + ] + } + } + ], + "eventsBasedObjects": [] + } + ], + "externalLayouts": [ + { + "associatedLayout": "", + "name": "functions", + "instances": [], + "editionSettings": {} + } + ] +} diff --git a/WorldOfSolariaV1.json.autosave b/WorldOfSolariaV1.json.autosave new file mode 100644 index 0000000..c7d561e --- /dev/null +++ b/WorldOfSolariaV1.json.autosave @@ -0,0 +1 @@ +{"firstLayout":"","gdVersion":{"build":279,"major":5,"minor":6,"revision":0},"initialGDVersion":"5.6.279","properties":{"adaptGameResolutionAtRuntime":true,"antialiasingMode":"MSAA","antialisingEnabledOnMobile":false,"folderProject":false,"orientation":"landscape","packageName":"com.example.gamename","pixelsRounding":true,"projectUuid":"459bb859-e4c7-45fe-a4a8-13e8403e786f","scaleMode":"nearest","sizeOnStartupMode":"adaptWidth","templateSlug":"","version":"1.0.0","name":"WorldOfSolariaV1","description":"","author":"","windowWidth":768,"windowHeight":432,"latestCompilationDirectory":"","maxFPS":60,"minFPS":20,"verticalSync":false,"platformSpecificAssets":{"android-icon-144":"","android-icon-192":"","android-icon-36":"","android-icon-48":"","android-icon-72":"","android-icon-96":"","android-windowSplashScreenAnimatedIcon":"","desktop-icon-512":"","ios-icon-100":"","ios-icon-1024":"","ios-icon-114":"","ios-icon-120":"","ios-icon-144":"","ios-icon-152":"","ios-icon-167":"","ios-icon-180":"","ios-icon-20":"","ios-icon-29":"","ios-icon-40":"","ios-icon-50":"","ios-icon-57":"","ios-icon-58":"","ios-icon-60":"","ios-icon-72":"","ios-icon-76":"","ios-icon-80":"","ios-icon-87":""},"loadingScreen":{"backgroundColor":0,"backgroundFadeInDuration":0.2,"backgroundImageResourceName":"","gdevelopLogoStyle":"light","logoAndProgressFadeInDuration":0.2,"logoAndProgressLogoFadeInDelay":0.0,"minDuration":1.5,"progressBarColor":16777215,"progressBarHeight":20.0,"progressBarMaxWidth":200.0,"progressBarMinWidth":40.0,"progressBarWidthPercent":30.0,"showGDevelopSplash":true,"showProgressBar":true},"watermark":{"placement":"bottom-left","showWatermark":true},"authorIds":[],"authorUsernames":[],"categories":[],"playableDevices":[],"extensionProperties":[],"platforms":[{"name":"GDevelop JS platform"}],"currentPlatform":"GDevelop JS platform"},"resources":{"resources":[{"file":"assets/NewSprite.png","kind":"image","metadata":"{\"extension\":\".png\"}","name":"NewSprite","smoothed":false,"userAdded":false},{"file":"assets/tempLogo.png","kind":"image","metadata":"{\"extension\":\".png\"}","name":"tempLogo","smoothed":false,"userAdded":false},{"file":"assets/tempLogo.png","kind":"image","metadata":"","name":"assets/tempLogo.png","smoothed":false,"userAdded":false},{"file":"assets/tempLogo3.png","kind":"image","metadata":"","name":"assets/tempLogo3.png","smoothed":false,"userAdded":false},{"file":"assets/NewSprite2.png","kind":"image","metadata":"{\"extension\":\".png\"}","name":"NewSprite2","smoothed":false,"userAdded":false},{"file":"assets/tempTitle.png","kind":"image","metadata":"","name":"assets/tempTitle.png","smoothed":false,"userAdded":false}]},"objects":[{"assetStoreId":"","name":"shp_fade","persistentUuid":"7c029e6d-47df-4889-bb1b-6130d9888e56","type":"PrimitiveDrawing::Drawer","variables":[],"effects":[],"behaviors":[{"name":"FlashTransitionPainter","type":"FlashTransitionPainter::FlashTransitionPainter","Progress":0.0,"Duration":0.0,"Type":"","Direction":"","MaxOpacity":255.0}],"fillOpacity":255.0,"outlineSize":1,"outlineOpacity":255.0,"absoluteCoordinates":false,"clearBetweenFrames":true,"antialiasing":"none","fillColor":{"r":255.0,"g":255.0,"b":255.0},"outlineColor":{"r":0.0,"g":0.0,"b":0.0}}],"objectsFolderStructure":{"folderName":"__ROOT","children":[{"folderName":"Fade","children":[{"objectName":"shp_fade"}]}]},"objectsGroups":[],"variables":[{"name":"host","type":"string","value":""}],"layouts":[{"b":255,"disableInputWhenNotFocused":true,"mangledName":"Splash","name":"Splash","r":247,"standardSortMethod":true,"stopSoundsOnStartup":true,"title":"","v":249,"uiSettings":{"grid":true,"gridType":"rectangular","gridWidth":16.0,"gridHeight":16.0,"gridDepth":32.0,"gridOffsetX":0.0,"gridOffsetY":0.0,"gridOffsetZ":0.0,"gridColor":10401023.0,"gridAlpha":0.8,"snap":true,"zoomFactor":1.1726229638177635,"windowMask":false,"selectedLayer":"","gameEditorMode":"instances-editor"},"objectsGroups":[],"variables":[],"instances":[{"angle":0.0,"customSize":true,"depth":1.0,"height":224.0,"keepRatio":true,"layer":"","name":"spr_studioLogo","persistentUuid":"a65e3907-a834-4122-b84c-e184ed30d7a5","width":480.0,"x":144.0,"y":96.0,"zOrder":1,"numberProperties":[],"stringProperties":[],"initialVariables":[]},{"angle":0.0,"customSize":false,"height":0.0,"keepRatio":true,"layer":"","name":"shp_fade","persistentUuid":"43c12b31-9f4a-4fd7-970e-a848140da139","width":0.0,"x":640.0,"y":0.0,"zOrder":2,"numberProperties":[],"stringProperties":[],"initialVariables":[]}],"objects":[{"adaptCollisionMaskAutomatically":true,"assetStoreId":"","name":"spr_studioLogo","persistentUuid":"d8d7a523-1dfa-4cd4-9080-3d6c7deb792f","type":"Sprite","updateIfNotVisible":false,"variables":[],"effects":[],"behaviors":[],"animations":[{"name":"tempLogo","useMultipleDirections":false,"directions":[{"looping":false,"metadata":"{\"pskl\":{}}","timeBetweenFrames":0.08,"sprites":[{"hasCustomCollisionMask":true,"image":"tempLogo","points":[],"originPoint":{"name":"origine","x":0.0,"y":0.0},"centerPoint":{"automatic":true,"name":"centre","x":0.0,"y":0.0},"customCollisionMask":[[{"x":0.0,"y":0.0},{"x":640.0,"y":0.0},{"x":640.0,"y":304.0},{"x":0.0,"y":304.0}]]}]}]}]}],"objectsFolderStructure":{"folderName":"__ROOT","children":[{"folderName":"Sprites","children":[{"objectName":"spr_studioLogo"}]}]},"events":[{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Scene Start","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"SceneJustBegins"},"parameters":[""]}],"actions":[{"type":{"value":"CenterWindow"},"parameters":[""]},{"type":{"value":"SetWindowSize"},"parameters":["","768","432",""]},{"type":{"value":"FlashTransitionPainter::FlashTransitionPainter::PaintEffect"},"parameters":["shp_fade","FlashTransitionPainter","\"0;0;0\"","1","\"Flash\"","\"Backward\"","255",""]},{"type":{"value":"Wait"},"parameters":["3"]},{"type":{"value":"FlashTransitionPainter::FlashTransitionPainter::PaintEffect"},"parameters":["shp_fade","FlashTransitionPainter","\"0;0;0\"","1","\"Flash\"","\"Forward\"","255",""]},{"type":{"value":"Wait"},"parameters":["1"]},{"type":{"value":"Scene"},"parameters":["","\"Title\"",""]}]}],"parameters":[]},{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Host Device","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"SystemInfo::HasTouchScreen"},"parameters":[""]}],"actions":[{"type":{"value":"SetStringVariable"},"parameters":["host","=","\"touchscreen\""]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"SystemInfo::IsNativeDesktopApp"},"parameters":[""]}],"actions":[{"type":{"value":"SetStringVariable"},"parameters":["host","=","\"desktop\""]}]}],"parameters":[]},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[]}],"layers":[{"ambientLightColorB":200,"ambientLightColorG":200,"ambientLightColorR":200,"camera2DPlaneMaxDrawingDistance":5000.0,"camera3DFarPlaneDistance":10000.0,"camera3DFieldOfView":45.0,"camera3DNearPlaneDistance":3.0,"cameraType":"","followBaseLayerCamera":false,"isLightingLayer":false,"isLocked":false,"name":"","renderingType":"","visibility":true,"cameras":[{"defaultSize":true,"defaultViewport":true,"height":0.0,"viewportBottom":1.0,"viewportLeft":0.0,"viewportRight":1.0,"viewportTop":0.0,"width":0.0}],"effects":[{"effectType":"Scene3D::HemisphereLight","name":"3D Ambient Hemisphere Light","doubleParameters":{"elevation":40.0,"intensity":0.33,"rotation":300.0},"stringParameters":{"groundColor":"127;127;127","skyColor":"255;255;255","top":"Z+"},"booleanParameters":{}},{"effectType":"Scene3D::DirectionalLight","name":"3D Sun Light","doubleParameters":{"distanceFromCamera":1500.0,"elevation":40.0,"frustumSize":4000.0,"intensity":0.75,"minimumShadowBias":0.0,"rotation":300.0},"stringParameters":{"color":"255;255;255","shadowQuality":"medium","top":"Z+"},"booleanParameters":{"isCastingShadow":true}}]}],"behaviorsSharedData":[{"name":"Animation","type":"AnimatableCapability::AnimatableBehavior"},{"name":"Effect","type":"EffectCapability::EffectBehavior"},{"name":"FlashTransitionPainter","type":"FlashTransitionPainter::FlashTransitionPainter"},{"name":"Flippable","type":"FlippableCapability::FlippableBehavior"},{"name":"Opacity","type":"OpacityCapability::OpacityBehavior"},{"name":"Resizable","type":"ResizableCapability::ResizableBehavior"},{"name":"Scale","type":"ScalableCapability::ScalableBehavior"}]},{"b":255,"disableInputWhenNotFocused":true,"mangledName":"Title","name":"Title","r":247,"standardSortMethod":true,"stopSoundsOnStartup":true,"title":"","v":249,"uiSettings":{},"objectsGroups":[],"variables":[],"instances":[{"angle":0.0,"customSize":true,"depth":1.0,"height":432.0,"keepRatio":true,"layer":"","name":"spr_tempTitle","persistentUuid":"7c69ad43-c862-4f49-b2a0-f7aa2a009e17","width":768.0,"x":0.0,"y":0.0,"zOrder":1,"numberProperties":[],"stringProperties":[],"initialVariables":[]},{"angle":0.0,"customSize":false,"height":0.0,"keepRatio":true,"layer":"","name":"shp_fade","persistentUuid":"b2376dc0-a75e-41fc-b571-46598d263229","width":0.0,"x":768.0,"y":0.0,"zOrder":2,"numberProperties":[],"stringProperties":[],"initialVariables":[]}],"objects":[{"adaptCollisionMaskAutomatically":true,"assetStoreId":"","name":"spr_tempTitle","persistentUuid":"d772eb58-a6cd-4786-9454-1d305a42c932","type":"Sprite","updateIfNotVisible":false,"variables":[],"effects":[],"behaviors":[],"animations":[{"name":"","useMultipleDirections":false,"directions":[{"looping":false,"timeBetweenFrames":0.08,"sprites":[{"hasCustomCollisionMask":true,"image":"assets/tempTitle.png","points":[],"originPoint":{"name":"origine","x":0.0,"y":0.0},"centerPoint":{"automatic":true,"name":"centre","x":0.0,"y":0.0},"customCollisionMask":[[{"x":0.0,"y":0.0},{"x":640.0,"y":0.0},{"x":640.0,"y":480.0},{"x":0.0,"y":480.0}]]}]}]}]}],"objectsFolderStructure":{"folderName":"__ROOT","children":[{"objectName":"spr_tempTitle"}]},"events":[{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Scene Start","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"SceneJustBegins"},"parameters":[""]}],"actions":[{"type":{"value":"CenterWindow"},"parameters":[""]},{"type":{"value":"SetWindowSize"},"parameters":["","768","432",""]},{"type":{"value":"FlashTransitionPainter::FlashTransitionPainter::PaintEffect"},"parameters":["shp_fade","FlashTransitionPainter","\"0;0;0\"","1","\"Flash\"","\"Backward\"","255",""]}]}],"parameters":[]},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[]}],"layers":[{"ambientLightColorB":200,"ambientLightColorG":200,"ambientLightColorR":200,"camera2DPlaneMaxDrawingDistance":5000.0,"camera3DFarPlaneDistance":10000.0,"camera3DFieldOfView":45.0,"camera3DNearPlaneDistance":3.0,"cameraType":"","followBaseLayerCamera":false,"isLightingLayer":false,"isLocked":false,"name":"","renderingType":"","visibility":true,"cameras":[{"defaultSize":true,"defaultViewport":true,"height":0.0,"viewportBottom":1.0,"viewportLeft":0.0,"viewportRight":1.0,"viewportTop":0.0,"width":0.0}],"effects":[{"effectType":"Scene3D::HemisphereLight","name":"3D Ambient Hemisphere Light","doubleParameters":{"elevation":40.0,"intensity":0.33,"rotation":300.0},"stringParameters":{"groundColor":"127;127;127","skyColor":"255;255;255","top":"Z+"},"booleanParameters":{}},{"effectType":"Scene3D::DirectionalLight","name":"3D Sun Light","doubleParameters":{"distanceFromCamera":1500.0,"elevation":40.0,"frustumSize":4000.0,"intensity":0.75,"minimumShadowBias":0.0,"rotation":300.0},"stringParameters":{"color":"255;255;255","shadowQuality":"medium","top":"Z+"},"booleanParameters":{"isCastingShadow":true}}]}],"behaviorsSharedData":[{"name":"Animation","type":"AnimatableCapability::AnimatableBehavior"},{"name":"Effect","type":"EffectCapability::EffectBehavior"},{"name":"FlashTransitionPainter","type":"FlashTransitionPainter::FlashTransitionPainter"},{"name":"Flippable","type":"FlippableCapability::FlippableBehavior"},{"name":"Opacity","type":"OpacityCapability::OpacityBehavior"},{"name":"Resizable","type":"ResizableCapability::ResizableBehavior"},{"name":"Scale","type":"ScalableCapability::ScalableBehavior"}]}],"externalEvents":[],"eventsFunctionsExtensions":[{"author":"Bouh","category":"Input","dimension":"","extensionNamespace":"","fullName":"Gamepads (controllers)","gdevelopVersion":">=5.5.222","helpPath":"/all-features/gamepad","iconUrl":"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLWdhbWVwYWQtdmFyaWFudC1vdXRsaW5lIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTYsOUg4VjExSDEwVjEzSDhWMTVINlYxM0g0VjExSDZWOU0xOC41LDlBMS41LDEuNSAwIDAsMSAyMCwxMC41QTEuNSwxLjUgMCAwLDEgMTguNSwxMkExLjUsMS41IDAgMCwxIDE3LDEwLjVBMS41LDEuNSAwIDAsMSAxOC41LDlNMTUuNSwxMkExLjUsMS41IDAgMCwxIDE3LDEzLjVBMS41LDEuNSAwIDAsMSAxNS41LDE1QTEuNSwxLjUgMCAwLDEgMTQsMTMuNUExLjUsMS41IDAgMCwxIDE1LjUsMTJNMTcsNUE3LDcgMCAwLDEgMjQsMTJBNyw3IDAgMCwxIDE3LDE5QzE1LjA0LDE5IDEzLjI3LDE4LjIgMTIsMTYuOUMxMC43MywxOC4yIDguOTYsMTkgNywxOUE3LDcgMCAwLDEgMCwxMkE3LDcgMCAwLDEgNyw1SDE3TTcsN0E1LDUgMCAwLDAgMiwxMkE1LDUgMCAwLDAgNywxN0M4LjY0LDE3IDEwLjA5LDE2LjIxIDExLDE1SDEzQzEzLjkxLDE2LjIxIDE1LjM2LDE3IDE3LDE3QTUsNSAwIDAsMCAyMiwxMkE1LDUgMCAwLDAgMTcsN0g3WiIgLz48L3N2Zz4=","name":"Gamepads","previewIconUrl":"https://resources.gdevelop-app.com/assets/Icons/gamepad-variant-outline.svg","shortDescription":"Gamepad/controller support: buttons, sticks, triggers, vibration. Mapper behaviors for 2D/3D.","version":"0.9.2","description":["Add support for gamepads (or other physical controllers).","","It gives access to:","- button presses,","- axis positions and force,","- trigger pressure,","- configurable deadzone,","- vibration,","- automatic \"gamepad mapper\" behaviors for 2D and 3D movement behaviors (platformer characters, top-down movement, 3D character etc...). Add one of these to the object with the movement behavior (i.e: the player most of the time) and the behavior will then be controlled automatically by the gamepad (it works by reading the gamepad state and simulating controls). No need for additional events to make it work once the behaviors are set up.","","The Bomberman-like example handles 4 players with gamepads ([open the project online](https://editor.gdevelop.io/?project=example://goose-bomberman))."],"origin":{"identifier":"Gamepads","name":"gdevelop-extension-store"},"tags":["controllers","gamepads","joysticks","axis","xbox","ps4","platformer","platform","top-down"],"authorIds":["2OwwM8ToR9dx9RJ2sAKTcrLmCB92","taRwmWxwAFYFL9yyBwB3cwBw0BO2","mnImQKdn8nQxwzkS5D6a1JB27V23","IWykYNRvhCZBN3vEgKEbBPOR3Oc2"],"dependencies":[],"globalVariables":[],"sceneVariables":[{"name":"Buttons","type":"structure","children":[{"name":"A or Cross","type":"string","value":"A"},{"name":"B or Circle","type":"string","value":"B"},{"name":"LB or L1","type":"string","value":"LB"},{"name":"LT or L2","type":"string","value":"LT"},{"name":"RB or R1","type":"string","value":"RB"},{"name":"RT or R2","type":"string","value":"RT"},{"name":"X or Square","type":"string","value":"X"},{"name":"Y or Triangle","type":"string","value":"Y"}]}],"eventsFunctions":[{"fullName":"","functionType":"Action","name":"onFirstSceneLoaded","sentence":"","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["if (gdjs._extensionController) {\r"," return;\r","}\r","\r","/**\r"," * Associate controller button ids to button names\r"," */\r","const controllerButtonNames = {\r"," \"XBOX\": {\r"," 0: \"A\",\r"," 1: \"B\",\r"," 2: \"X\",\r"," 3: \"Y\",\r"," 4: \"LB\",\r"," 5: \"RB\",\r"," 6: \"LT\",\r"," 7: \"RT\",\r"," 8: \"BACK\",\r"," 9: \"START\",\r"," 10: \"CLICK_STICK_LEFT\",\r"," 11: \"CLICK_STICK_RIGHT\",\r"," 12: \"UP\",\r"," 13: \"DOWN\",\r"," 14: \"LEFT\",\r"," 15: \"RIGHT\",\r"," 16: \"NONE\",\r"," 17: \"NONE\"\r"," },\r"," \"PS4\": {\r"," 0: \"CROSS\",\r"," 1: \"CIRCLE\",\r"," 2: \"SQUARE\",\r"," 3: \"TRIANGLE\",\r"," 4: \"L1\",\r"," 5: \"R1\",\r"," 6: \"L2\",\r"," 7: \"R2\",\r"," 8: \"SHARE\",\r"," 9: \"OPTIONS\",\r"," 10: \"CLICK_STICK_LEFT\",\r"," 11: \"CLICK_STICK_RIGHT\",\r"," 12: \"UP\",\r"," 13: \"DOWN\",\r"," 14: \"LEFT\",\r"," 15: \"RIGHT\",\r"," 16: \"PS_BUTTON\",\r"," 17: \"CLICK_TOUCHPAD\"\r"," }\r","};\r","\r","/**\r"," * @param {number} playerId\r"," */\r","function getGamepad(playerId) {\r"," /** @type {Gamepad[]} */\r"," const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];\r"," return gamepads[playerId];\r","}\r","\r","/** @type {{[playerId: number]: Player}} */\r","const players = {};\r","\r","/**\r"," * @param {number} playerId\r"," */\r","function getPlayer(playerId) {\r"," let player = players[playerId];\r"," if (!player) {\r"," player = new Player(playerId);\r"," players[playerId] = player;\r"," }\r"," return player;\r","}\r","\r","class Player {\r"," /** @type {number} */\r"," playerId;\r"," mapping = 'DEFAULT';\r"," lastButtonUsed = -1;\r"," deadzone = 0.2;\r"," /** @type {{[buttonId: number]: ButtonState}} */\r"," buttonStates = {};\r"," rumble = { elapsedTime: 0, duration: 0, weakMagnitude: 0, strongMagnitude: 0 };\r","\r"," /**\r"," * @param {number} playerId\r"," */\r"," constructor(playerId) {\r"," this.playerId = playerId;\r"," }\r","\r"," /**\r"," * @param {number} buttonId\r"," */\r"," getButtonState(buttonId) {\r"," let buttonState = this.buttonStates[buttonId];\r"," if (!buttonState) {\r"," buttonState = new ButtonState();\r"," this.buttonStates[buttonId] = buttonState;\r"," }\r"," return buttonState;\r"," }\r","\r"," /**\r"," * @param {number} buttonId\r"," */\r"," isButtonPressed(buttonId) {\r"," return this.getButtonState(buttonId).isPressed;\r"," }\r","\r"," /**\r"," * @param {number} buttonId\r"," */\r"," isButtonJustPressed(buttonId) {\r"," return this.getButtonState(buttonId).isJustPressed();\r"," }\r","\r"," /**\r"," * @param {number} buttonId\r"," */\r"," isButtonReleased(buttonId) {\r"," return this.getButtonState(buttonId).isReleased();\r"," }\r","\r"," isAnyButtonReleased() {\r"," for (const buttonId in this.buttonStates) {\r"," const buttonState = this.buttonStates[buttonId];\r"," if (buttonState.isReleased()) {\r"," return true;\r"," }\r"," }\r"," return false;\r"," }\r","\r"," isAnyButtonPressed() {\r"," for (const buttonId in this.buttonStates) {\r"," const buttonState = this.buttonStates[buttonId];\r"," if (buttonState.isPressed) {\r"," return true;\r"," }\r"," }\r"," return false;\r"," }\r","}\r","\r","class ButtonState {\r"," wasPressed = false;\r"," isPressed = false;\r","\r"," isReleased() {\r"," return this.wasPressed && !this.isPressed;\r"," }\r","\r"," isJustPressed() {\r"," return !this.wasPressed && this.isPressed;\r"," }\r","}\r","\r","// Async tasks are run before everything.\r","// This is a hack to make sure that button states are updated\r","// before mapping behavior events.\r","const frameBeginningTask = new class extends gdjs.AsyncTask {\r"," update() {\r"," /** @type {Gamepad[]} */\r"," const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];\r"," for (let playerId = 0; playerId < gamepads.length; playerId++) {\r"," const gamepad = gamepads[playerId];\r"," if (gamepad == null) {\r"," // The gamepad is not connected.\r"," continue;\r"," }\r"," const player = getPlayer(playerId);\r","\r"," for (let buttonId = 0; buttonId < Object.keys(gamepad.buttons).length; buttonId++) {\r"," const buttonState = player.getButtonState(buttonId);\r"," buttonState.wasPressed = buttonState.isPressed;\r"," buttonState.isPressed = gamepad.buttons[buttonId].pressed;\r"," if (buttonState.isJustPressed()) {\r"," player.lastButtonUsed = buttonId;\r"," }\r"," }\r"," }\r"," return false;\r"," }\r","}();\r","\r","/**\r"," * @param {gdjs.RuntimeScene} runtimeScene\r"," */\r","function addFrameBeginningTaskIfNeeded(runtimeScene) {\r"," const taskManager = runtimeScene.getAsyncTasksManager();\r"," for (const taskWithCallback of taskManager.tasksWithCallback) {\r"," if (taskWithCallback.asyncTask === frameBeginningTask) {\r"," return;\r"," }\r"," }\r"," // Async tasks are run before everything.\r"," // This is a hack to make sure that button states are updated\r"," // before mapping behavior events.\r"," taskManager.addTask(frameBeginningTask);\r","}\r","\r","/**\r"," * @param {gdjs.RuntimeScene} runtimeScene\r"," */\r","function onScenePostEvents(runtimeScene) {\r"," addFrameBeginningTaskIfNeeded(runtimeScene);\r"," /** @type {Gamepad[]} */\r"," const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];\r"," for (let playerId = 0; playerId < gamepads.length; playerId++) {\r"," let gamepad = gamepads[playerId];\r"," if (gamepad == null) {\r"," // The gamepad is not connected.\r"," continue;\r"," }\r"," const player = getPlayer(playerId);\r"," const rumble = player.rumble;\r"," rumble.elapsedTime += runtimeScene.getElapsedTime(runtimeScene) / 1000;\r"," if (rumble.duration - rumble.elapsedTime <= 0 &&\r"," (rumble.weakMagnitude || rumble.strongMagnitude)\r"," ) {\r"," rumble.weakMagnitude = 0;\r"," rumble.strongMagnitude = 0;\r"," }\r"," }\r","}\r","\r","/**\r"," * @param {string} type\r"," * @param {number} buttonId\r"," */\r","function getInputString(type, buttonId) {\r"," if (!controllerButtonNames[type]) {\r"," return \"UNKNOWN_BUTTON\";\r"," }\r"," return controllerButtonNames[type][buttonId];\r","}\r","\r","function getButtonId(buttonName) {\r"," switch (buttonName) {\r"," case 'A':\r"," case 'CROSS':\r"," return 0;\r"," case 'B':\r"," case 'CIRCLE':\r"," return 1;\r"," case 'X':\r"," case 'SQUARE':\r"," return 2;\r"," case 'Y':\r"," case 'TRIANGLE':\r"," return 3;\r"," case 'LB':\r"," case 'L1':\r"," return 4;\r"," case 'RB':\r"," case 'R1':\r"," return 5;\r"," case 'LT':\r"," case 'L2':\r"," return 6;\r"," case 'RT':\r"," case 'R2':\r"," return 7;\r"," case 'UP':\r"," return 12;\r"," case 'DOWN':\r"," return 13;\r"," case 'LEFT':\r"," return 14;\r"," case 'RIGHT':\r"," return 15;\r"," case 'BACK':\r"," case 'SHARE':\r"," return 8;\r"," case 'START':\r"," case 'OPTIONS':\r"," return 9;\r"," case 'CLICK_STICK_LEFT':\r"," return 10;\r"," case 'CLICK_STICK_RIGHT':\r"," return 11;\r"," //PS4\r"," case 'PS_BUTTON':\r"," return 16;\r"," case 'CLICK_TOUCHPAD':\r"," return 17;\r"," default:\r"," console.error('The gamepad button: ' + buttonName + ' is not valid.');\r"," return null;\r"," }\r","}\r","\r","/**\r"," * @param {number} playerId\r"," * @param {string} directionName\r"," * @param {number} axisValueX\r"," * @param {number} axisValueY\r"," */\r","function isAxisPushed(playerId, directionName, axisValueX, axisValueY) {\r"," switch (directionName) {\r"," case 'LEFT':\r"," return getNormalizedAxisValue(axisValueX, playerId) < 0;\r"," case 'RIGHT':\r"," return getNormalizedAxisValue(axisValueX, playerId) > 0;\r"," case 'UP':\r"," return getNormalizedAxisValue(axisValueY, playerId) < 0;\r"," case 'DOWN':\r"," return getNormalizedAxisValue(axisValueY, playerId) > 0;\r"," case 'ANY':\r"," return getNormalizedAxisValue(axisValueX, playerId) < 0\r"," || getNormalizedAxisValue(axisValueX, playerId) > 0\r"," || getNormalizedAxisValue(axisValueY, playerId) < 0\r"," || getNormalizedAxisValue(axisValueY, playerId) > 0\r"," default:\r"," console.error('The value stick direction is not valid.');\r"," return false;\r"," }\r","}\r","\r","/**\r"," * @param {number} deltaX\r"," * @param {number} deltaY\r"," */\r","function axisToAngle(deltaX, deltaY) {\r"," const rad = Math.atan2(deltaY, deltaX);\r"," const deg = rad * (180 / Math.PI);\r"," return deg;\r","}\r","\r","/**\r"," * @param {{id: string}} gamepad\r"," */\r","function isXbox(gamepad) {\r"," return (gamepad ? (\r"," gamepad.id.toUpperCase().indexOf(\"XBOX\") !== -1\r"," // \"XINPUT\" cannot be used to check if it is a xbox controller is just a generic\r"," // name reported in Firefox corresponding to the driver being used by the controller\r"," // https://gamefaqs.gamespot.com/boards/916373-pc/73341312?page=1\r"," ) : false);\r","}\r","\r","/**\r"," * Returns the new value taking into account the dead zone for the player_ID given\r"," * @param {number} value\r"," * @param {number} playerID\r"," */\r","function getNormalizedAxisValue(value, playerID) {\r"," // gdjs._extensionController = gdjs._extensionController || { deadzone: 0.2 };\r","\r"," // Anything smaller than this is assumed to be 0,0\r"," const deadzone = getPlayer(playerID).deadzone;\r","\r"," if (Math.abs(value) < deadzone) {\r"," return 0;\r"," } else {\r"," // We're outside the dead zone, but we'd like to smooth\r"," // this value out so it still runs nicely between 0..1.\r"," // That is, we don't want it to jump suddenly from 0 to\r"," // deadzone.\r","\r"," // Remap value from\r"," // deadzone..1 to 0..(1-deadzone)\r"," // or from\r"," // -1..-deadzone to -(1-deadzone)..0\r"," value = value - Math.sign(value) * deadzone;\r","\r"," // Remap value from\r"," // 0..(1-deadzone) to 0..1\r"," // or from\r"," // -(1-deadzone)..0 to -1..0\r"," return value / (1 - deadzone);\r"," }\r","}\r","\r","gdjs._extensionController = {\r"," getPlayer,\r"," controllerButtonNames,\r"," getInputString,\r"," getButtonId,\r"," axisToAngle,\r"," isXbox,\r"," getNormalizedAxisValue,\r"," isAxisPushed,\r"," getGamepad,\r"," onScenePostEvents,\r"," frameBeginningTask,\r"," addFrameBeginningTaskIfNeeded,\r","}"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"parameters":[],"objectGroups":[]},{"fullName":"","functionType":"Action","name":"onSceneLoaded","sentence":"","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":"gdjs._extensionController.addFrameBeginningTaskIfNeeded(runtimeScene);","parameterObjects":"","useStrict":true,"eventsSheetExpanded":false}],"parameters":[],"objectGroups":[]},{"fullName":"","functionType":"Action","name":"onScenePostEvents","sentence":"","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["gdjs._extensionController.onScenePostEvents(runtimeScene);",""],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"parameters":[],"objectGroups":[]},{"fullName":"Accelerated speed","functionType":"Expression","name":"AcceleratedSpeed","private":true,"sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["AcceleratedSpeed","=","CurrentSpeed"]}],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"NumberVariable"},"parameters":["TargetedSpeed","<","0"]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Reduce the speed to match the stick force."},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"NumberVariable"},"parameters":["CurrentSpeed","<","TargetedSpeed"]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["AcceleratedSpeed","=","min(TargetedSpeed, CurrentSpeed + Acceleration * TimeDelta())"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"NumberVariable"},"parameters":["CurrentSpeed",">","TargetedSpeed"]},{"type":{"value":"NumberVariable"},"parameters":["CurrentSpeed","<","0"]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["AcceleratedSpeed","-","Acceleration * TimeDelta()"]}]},{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Turn back at least as fast as it would stop."},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"NumberVariable"},"parameters":["CurrentSpeed",">=","0"]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["AcceleratedSpeed","=","max(TargetedSpeed, CurrentSpeed - max(Acceleration , Deceleration) * TimeDelta())"]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"NumberVariable"},"parameters":["TargetedSpeed",">","0"]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Reduce the speed to match the stick force."},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"NumberVariable"},"parameters":["CurrentSpeed",">","TargetedSpeed"]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["AcceleratedSpeed","=","max(TargetedSpeed, CurrentSpeed - Acceleration * TimeDelta())"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"NumberVariable"},"parameters":["CurrentSpeed","<","TargetedSpeed"]},{"type":{"value":"NumberVariable"},"parameters":["CurrentSpeed",">","0"]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["AcceleratedSpeed","+","Acceleration * TimeDelta()"]}]},{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Turn back at least as fast as it would stop."},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"NumberVariable"},"parameters":["CurrentSpeed","<=","0"]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["AcceleratedSpeed","=","min(TargetedSpeed, CurrentSpeed + max(Acceleration , Deceleration) * TimeDelta())"]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"NumberVariable"},"parameters":["TargetedSpeed","=","0"]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"NumberVariable"},"parameters":["CurrentSpeed","<","0"]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["AcceleratedSpeed","=","min(0, CurrentSpeed + Acceleration * TimeDelta())"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"NumberVariable"},"parameters":["CurrentSpeed",">","0"]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["AcceleratedSpeed","=","max(0, CurrentSpeed - Acceleration * TimeDelta())"]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["clamp(AcceleratedSpeed, -SpeedMax, SpeedMax)"]}]}],"variables":[{"name":"AcceleratedSpeed","type":"number","value":0.0}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Current speed","name":"CurrentSpeed","type":"expression"},{"description":"Targeted speed","name":"TargetedSpeed","type":"expression"},{"description":"Max speed","name":"SpeedMax","type":"expression"},{"description":"Acceleration","name":"Acceleration","type":"expression"},{"description":"Deceleration","name":"Deceleration","type":"expression"}],"objectGroups":[]},{"description":"Get the value of the pressure on a gamepad trigger.","fullName":"Pressure on a gamepad trigger","functionType":"Expression","name":"TriggerPressure","sentence":"Player _PARAM1_ push axis _PARAM2_ to _PARAM3_","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","const trigger = eventsFunctionContext.getArgument(\"Trigger\").toUpperCase();\r","\r","if (trigger != \"LT\" && trigger != \"RT\" && trigger != \"L2\" && trigger != \"R2\") {\r"," console.error('Parameter trigger is not valid in expression: \"Pressure on a gamepad trigger\"');\r"," return;\r","}\r","/** @type {Gamepad} */\r","const gamepad = gdjs._extensionController.getGamepad(playerId);\r","if (!gamepad) {\r"," // The gamepad is not connected.\r"," return;\r","}\r","switch (trigger) {\r"," case 'LT':\r"," case 'L2':\r"," eventsFunctionContext.returnValue = gamepad.buttons[6].value;\r"," break;\r","\r"," case 'RT':\r"," case 'R2':\r"," eventsFunctionContext.returnValue = gamepad.buttons[7].value;\r"," break;\r","\r"," default:\r"," eventsFunctionContext.returnValue = -1;\r"," break;\r","}"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"expressionType":{"type":"expression"},"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"},{"description":"Trigger button","name":"Trigger","supplementaryInformation":"[\"LT\",\"RT\",\"L2\",\"R2\"]","type":"stringWithSelector"}],"objectGroups":[]},{"description":"the force of gamepad stick (from 0 to 1).","fullName":"Stick force","functionType":"ExpressionAndCondition","name":"StickForce","sentence":"the gamepad _PARAM1_ _PARAM2_ stick force","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["const { getNormalizedAxisValue } = gdjs._extensionController;\r","\r","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","const stick = eventsFunctionContext.getArgument(\"Stick\").toUpperCase();\r","\r","if (stick !== \"LEFT\" && stick !== \"RIGHT\") {\r"," console.error('Parameter stick is not valid in expression: \"Value of a stick force\"');\r"," return;\r","}\r","/** @type {Gamepad} */\r","const gamepad = gdjs._extensionController.getGamepad(playerId);\r","if (!gamepad) {\r"," // The gamepad is not connected.\r"," return;\r","}\r","const axisValueX = stick === 'RIGHT' ? gamepad.axes[2] : gamepad.axes[0];\r","const axisValueY = stick === 'RIGHT' ? gamepad.axes[3] : gamepad.axes[1];\r","\r","eventsFunctionContext.returnValue = gdjs.evtTools.common.clamp(\r"," Math.abs(getNormalizedAxisValue(axisValueX, playerId)) +\r"," Math.abs(getNormalizedAxisValue(axisValueY, playerId)), 0, 1);\r",""],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"expressionType":{"type":"expression"},"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"},{"description":"Stick: \"Left\" or \"Right\"","name":"Stick","supplementaryInformation":"[\"Left\",\"Right\"]","type":"stringWithSelector"}],"objectGroups":[]},{"description":"Get the rotation value of a gamepad stick.\nIf the deadzone value is high, the angle value is rounded to main axes, left, left, up, down.\nAn zero deadzone value give a total freedom on the angle value.","fullName":"Value of a stick rotation (deprecated)","functionType":"Expression","name":"StickRotationValue","private":true,"sentence":"Player _PARAM1_ push axis _PARAM2_ to _PARAM3_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["Gamepads::StickAngle(PlayerId, Stick)"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"},{"description":"Stick: \"Left\" or \"Right\"","name":"Stick","supplementaryInformation":"[\"Left\",\"Right\"]","type":"stringWithSelector"}],"objectGroups":[]},{"description":"Return the angle of a gamepad stick.\nIf the deadzone value is high, the angle value is rounded to main axes, left, left, up, down.\nAn zero deadzone value give a total freedom on the angle value.","fullName":"Stick angle","functionType":"Expression","name":"StickAngle","sentence":"","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["const { getNormalizedAxisValue } = gdjs._extensionController;\r","\r","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","const stick = eventsFunctionContext.getArgument(\"Stick\").toUpperCase();\r","\r","if (stick !== \"LEFT\" && stick !== \"RIGHT\") {\r"," console.error('Parameter stick is not valid in expression: \"Value of a stick rotation\"');\r"," return;\r","}\r","/** @type {Gamepad} */\r","const gamepad = gdjs._extensionController.getGamepad(playerId);\r","if (!gamepad) {\r"," // The gamepad is not connected.\r"," return;\r","}\r","const axisValueX = stick === 'RIGHT' ? gamepad.axes[2] : gamepad.axes[0];\r","const axisValueY = stick === 'RIGHT' ? gamepad.axes[3] : gamepad.axes[1];\r","\r","eventsFunctionContext.returnValue = gdjs._extensionController.axisToAngle(\r"," getNormalizedAxisValue(axisValueX, playerId),\r"," getNormalizedAxisValue(axisValueY, playerId));"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"expressionType":{"type":"expression"},"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"},{"description":"Stick: \"Left\" or \"Right\"","name":"Stick","supplementaryInformation":"[\"Left\",\"Right\"]","type":"stringWithSelector"}],"objectGroups":[]},{"description":"Get the value of axis of a gamepad stick.","fullName":"Value of a gamepad axis (deprecated)","functionType":"Expression","name":"AxisValue","private":true,"sentence":"Player _PARAM1_ push axis _PARAM2_ to _PARAM3_","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","const stick = eventsFunctionContext.getArgument(\"stick\").toUpperCase();\r","const direction = eventsFunctionContext.getArgument(\"direction\").toUpperCase();\r","\r","if (stick != \"LEFT\" && stick != \"RIGHT\") {\r"," console.error('Parameter stick is not valid in expression: \"Value of a gamepad axis\"');\r"," return;\r","}\r","if (direction != \"UP\" && direction != \"DOWN\" && direction != \"LEFT\" && direction != \"RIGHT\" && direction != \"HORIZONTAL\" && direction != \"VERTICAL\") {\r"," console.error('Parameter direction is not valid in expression: \"Value of a gamepad axis\"');\r"," return;\r","}\r","/** @type {Gamepad} */\r","const gamepad = gdjs._extensionController.getGamepad(playerId);\r","if (!gamepad) {\r"," // The gamepad is not connected.\r"," return;\r","}\r","let parameterError = false;\r","switch (stick) {\r"," case 'LEFT':\r"," switch (direction) {\r"," case 'LEFT':\r"," if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[0], playerId) < 0) {\r"," eventsFunctionContext.returnValue = -gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[0], playerId);\r"," }\r"," break;\r","\r"," case 'RIGHT':\r"," if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[0], playerId) > 0) {\r"," eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[0], playerId);\r"," }\r"," break;\r","\r"," case 'UP':\r"," if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[1], playerId) < 0) {\r"," eventsFunctionContext.returnValue = -gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[1], playerId);\r"," }\r"," break;\r","\r"," case 'DOWN':\r"," if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[1], playerId) > 0) {\r"," eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[1], playerId);\r"," }\r"," break;\r","\r"," case \"HORIZONTAL\":\r"," eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[0], playerId);\r"," break;\r","\r"," case \"VERTICAL\":\r"," eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[1], playerId);\r"," break;\r","\r"," default:\r"," break;\r"," }\r"," break;\r","\r"," case 'RIGHT':\r"," switch (direction) {\r"," case 'LEFT':\r"," if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[2], playerId) < 0) {\r"," eventsFunctionContext.returnValue = -gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[2], playerId);\r"," }\r"," break;\r","\r"," case 'RIGHT':\r"," if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[2], playerId) > 0) {\r"," eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[2], playerId);\r"," }\r"," break;\r","\r"," case 'UP':\r"," if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[3], playerId) < 0) {\r"," eventsFunctionContext.returnValue = -gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[3], playerId);\r"," }\r"," break;\r","\r"," case 'DOWN':\r"," if (gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[3], playerId) > 0) {\r"," eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[3], playerId);\r"," }\r"," break;\r","\r"," case \"HORIZONTAL\":\r"," eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[2], playerId);\r"," break;\r","\r"," case \"VERTICAL\":\r"," eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[3], playerId);\r"," break;\r","\r"," default:\r"," break;\r"," }\r"," break;\r","\r"," default:\r"," break;\r","}\r",""],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"expressionType":{"type":"expression"},"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"},{"description":"Stick: \"Left\" or \"Right\"","name":"stick","supplementaryInformation":"[\"Left\",\"Right\"]","type":"stringWithSelector"},{"description":"Direction","name":"direction","supplementaryInformation":"[\"Up\",\"Down\",\"Left\",\"Right\",\"Horizontal\",\"Vertical\"]","type":"stringWithSelector"}],"objectGroups":[]},{"description":"Return the gamepad stick force on X axis (from -1 at the left to 1 at the right).","fullName":"Stick X force","functionType":"Expression","name":"StickForceX","sentence":"","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const playerId = eventsFunctionContext.getArgument(\"Gamepad\") - 1;\r","const stick = eventsFunctionContext.getArgument(\"Stick\").toLowerCase();\r","\r","if (stick != \"left\" && stick != \"right\") {\r"," console.error('Parameter stick is not valid in expression: \"Value of a gamepad axis\"');\r"," return;\r","}\r","/** @type {Gamepad} */\r","const gamepad = gdjs._extensionController.getGamepad(playerId);\r","if (!gamepad) {\r"," // The gamepad is not connected.\r"," return;\r","}\r","const axisIndex = stick === 'right' ? 2 : 0;\r","eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[axisIndex], playerId);\r",""],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"expressionType":{"type":"expression"},"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"Gamepad","type":"expression"},{"description":"Stick: \"Left\" or \"Right\"","name":"Stick","supplementaryInformation":"[\"Left\",\"Right\"]","type":"stringWithSelector"}],"objectGroups":[]},{"description":"Return the gamepad stick force on Y axis (from -1 at the top to 1 at the bottom).","fullName":"Stick Y force","functionType":"Expression","name":"StickForceY","sentence":"","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const playerId = eventsFunctionContext.getArgument(\"Gamepad\") - 1;\r","const stick = eventsFunctionContext.getArgument(\"Stick\").toLowerCase();\r","\r","if (stick != \"left\" && stick != \"right\") {\r"," console.error('Parameter stick is not valid in expression: \"Value of a gamepad axis\"');\r"," return;\r","}\r","/** @type {Gamepad} */\r","const gamepad = gdjs._extensionController.getGamepad(playerId);\r","if (!gamepad) {\r"," // The gamepad is not connected.\r"," return;\r","}\r","const axisIndex = stick === 'right' ? 3 : 1;\r","eventsFunctionContext.returnValue = gdjs._extensionController.getNormalizedAxisValue(gamepad.axes[axisIndex], playerId);\r",""],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"expressionType":{"type":"expression"},"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"Gamepad","type":"expression"},{"description":"Stick: \"Left\" or \"Right\"","name":"Stick","supplementaryInformation":"[\"Left\",\"Right\"]","type":"stringWithSelector"}],"objectGroups":[]},{"description":"Test if a button is released on a gamepad. Buttons can be:\n* Xbox: \"A\", \"B\", \"X\", \"Y\", \"LB\", \"RB\", \"LT\", \"RT\", \"BACK\", \"START\",\n* PS4: \"CROSS\", \"SQUARE\", \"CIRCLE\", \"TRIANGLE\", \"L1\", \"L2\", \"R1\", \"R2\", \"SHARE\", \"OPTIONS\", \"PS_BUTTON\", \"CLICK_TOUCHPAD\",\n* Other: \"UP\", \"DOWN\", \"LEFT\", \"RIGHT\", \"CLICK_STICK_LEFT\", \"CLICK_STICK_RIGHT\".","fullName":"Gamepad button released","functionType":"Condition","name":"C_Button_released","sentence":"Button _PARAM2_ of gamepad _PARAM1_ is released","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","const button = eventsFunctionContext.getArgument(\"Button\").toUpperCase();\r","\r","let buttonId = gdjs._extensionController.getButtonId(button);\r","if (buttonId === null) {\r"," return;\r","}\r","const player = gdjs._extensionController.getPlayer(playerId)\r","eventsFunctionContext.returnValue = player.isButtonReleased(buttonId);"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"},{"description":"Name of the button","name":"Button","supplementaryInformation":"[\"A\",\"Cross\",\"B\",\"Circle\",\"X\",\"Square\",\"Y\",\"Triangle\",\"LB\",\"L1\",\"RB\",\"R1\",\"LT\",\"L2\",\"RT\",\"R2\",\"Up\",\"Down\",\"Left\",\"Right\",\"Back\",\"Share\",\"Start\",\"Options\",\"Click_Stick_Left\",\"Click_Stick_Right\",\"PS_Button\",\"Click_Touchpad\"]","type":"stringWithSelector"}],"objectGroups":[]},{"description":"Check if a button was just pressed on a gamepad. Buttons can be:\n* Xbox: \"A\", \"B\", \"X\", \"Y\", \"LB\", \"RB\", \"LT\", \"RT\", \"BACK\", \"START\",\n* PS4: \"CROSS\", \"SQUARE\", \"CIRCLE\", \"TRIANGLE\", \"L1\", \"L2\", \"R1\", \"R2\", \"SHARE\", \"OPTIONS\", \"PS_BUTTON\", \"CLICK_TOUCHPAD\",\n* Other: \"UP\", \"DOWN\", \"LEFT\", \"RIGHT\", \"CLICK_STICK_LEFT\", \"CLICK_STICK_RIGHT\".","fullName":"Gamepad button just pressed","functionType":"Condition","name":"IsButtonJustPressed","sentence":"Button _PARAM2_ of gamepad _PARAM1_ was just pressed","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","const button = eventsFunctionContext.getArgument(\"Button\").toUpperCase();\r","\r","let buttonId = gdjs._extensionController.getButtonId(button);\r","if (buttonId === null) {\r"," return;\r","}\r","const player = gdjs._extensionController.getPlayer(playerId)\r","eventsFunctionContext.returnValue = player.isButtonJustPressed(buttonId);"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"},{"description":"Name of the button","name":"Button","supplementaryInformation":"[\"A\",\"Cross\",\"B\",\"Circle\",\"X\",\"Square\",\"Y\",\"Triangle\",\"LB\",\"L1\",\"RB\",\"R1\",\"LT\",\"L2\",\"RT\",\"R2\",\"Up\",\"Down\",\"Left\",\"Right\",\"Back\",\"Share\",\"Start\",\"Options\",\"Click_Stick_Left\",\"Click_Stick_Right\",\"PS_Button\",\"Click_Touchpad\"]","type":"stringWithSelector"}],"objectGroups":[]},{"description":"Return the index of the last pressed button of a gamepad.","fullName":"Last pressed button (id)","functionType":"Expression","name":"LastButtonID","sentence":"","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","eventsFunctionContext.returnValue = gdjs._extensionController.getPlayer(playerId).lastButtonUsed;"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"expressionType":{"type":"expression"},"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"}],"objectGroups":[]},{"description":"Check if any button is pressed on a gamepad.","fullName":"Any gamepad button pressed","functionType":"Condition","name":"C_Any_Button_pressed","sentence":"Any button of gamepad _PARAM1_ is pressed","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","const player = gdjs._extensionController.getPlayer(playerId)\r","eventsFunctionContext.returnValue = player.isAnyButtonPressed();\r",""],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"}],"objectGroups":[]},{"description":"Return the last button pressed. \nButtons for Xbox and PS4 can be:\n* Xbox: \"A\", \"B\", \"X\", \"Y\", \"LB\", \"RB\", \"LT\", \"RT\", \"BACK\", \"START\",\n* PS4: \"CROSS\", \"SQUARE\", \"CIRCLE\", \"TRIANGLE\", \"L1\", \"L2\", \"R1\", \"R2\", \"SHARE\", \"OPTIONS\", \"PS_BUTTON\", \"CLICK_TOUCHPAD\",\n* Both: \"UP\", \"DOWN\", \"LEFT\", \"RIGHT\", \"CLICK_STICK_LEFT\", \"CLICK_STICK_RIGHT\".","fullName":"Last pressed button (string)","functionType":"StringExpression","name":"LastButtonString","sentence":"Button _PARAM2_ of gamepad _PARAM1_ is pressed","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","const controllerType = eventsFunctionContext.getArgument(\"controller_type\").toUpperCase();\r","/** @type {Gamepad} */\r","const gamepad = gdjs._extensionController.getGamepad(playerId);\r","if (!gamepad) {\r"," // The gamepad is not connected.\r"," return;\r","}\r","const lastButtonUsedID = gdjs._extensionController.getPlayer(playerId).lastButtonUsed;\r","eventsFunctionContext.returnValue = gdjs._extensionController.getInputString(controllerType, lastButtonUsedID);\r",""],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"expressionType":{"type":"string"},"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"},{"description":"Controller type","name":"controller_type","supplementaryInformation":"[\"Xbox\",\"PS4\"]","type":"stringWithSelector"}],"objectGroups":[]},{"description":"Return the number of gamepads.","fullName":"Gamepad count","functionType":"Expression","name":"GamepadCount","sentence":"","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];\r","let lastGamepadIndex = -1;\r","for (let playerId = 0; playerId < gamepads.length; playerId++) {\r"," // Gamepads can be disconnected and become null\r"," if (gamepads[playerId]) {\r"," lastGamepadIndex = playerId\r"," }\r","}\r","eventsFunctionContext.returnValue = lastGamepadIndex + 1;"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"expressionType":{"type":"expression"},"parameters":[],"objectGroups":[]},{"description":"Check if a button is pressed on a gamepad. \nButtons can be:\n* Xbox: \"A\", \"B\", \"X\", \"Y\", \"LB\", \"RB\", \"LT\", \"RT\", \"BACK\", \"START\",\n* PS4: \"CROSS\", \"SQUARE\", \"CIRCLE\", \"TRIANGLE\", \"L1\", \"L2\", \"R1\", \"R2\", \"SHARE\", \"OPTIONS\", \"PS_BUTTON\", \"CLICK_TOUCHPAD\",\n* Other: \"UP\", \"DOWN\", \"LEFT\", \"RIGHT\", \"CLICK_STICK_LEFT\", \"CLICK_STICK_RIGHT\".","fullName":"Gamepad button pressed","functionType":"Condition","name":"C_Button_pressed","sentence":"Button _PARAM2_ of gamepad _PARAM1_ is pressed","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","const button = eventsFunctionContext.getArgument(\"button\").toUpperCase();\r","\r","const buttonId = gdjs._extensionController.getButtonId(button);\r","if (buttonId === null) {\r"," return;\r","}\r","const player = gdjs._extensionController.getPlayer(playerId)\r","eventsFunctionContext.returnValue = player.isButtonPressed(buttonId);\r",""],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"},{"description":"Name of the button","name":"button","supplementaryInformation":"[\"A\",\"Cross\",\"B\",\"Circle\",\"X\",\"Square\",\"Y\",\"Triangle\",\"LB\",\"L1\",\"RB\",\"R1\",\"LT\",\"L2\",\"RT\",\"R2\",\"Up\",\"Down\",\"Left\",\"Right\",\"Back\",\"Share\",\"Start\",\"Options\",\"Click_Stick_Left\",\"Click_Stick_Right\",\"PS_Button\",\"Click_Touchpad\"]","type":"stringWithSelector"}],"objectGroups":[]},{"description":"Return the value of the deadzone applied to a gamepad sticks, between 0 and 1.","fullName":"Gamepad deadzone for sticks","functionType":"Expression","name":"Deadzone","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[]},{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","eventsFunctionContext.returnValue = gdjs._extensionController.getPlayer(playerId).deadzone;"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"expressionType":{"type":"expression"},"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"}],"objectGroups":[]},{"description":"Set the deadzone for sticks of the gamepad. The deadzone is an area for which movement on sticks won't be taken into account (instead, the stick will be considered as not moved). Deadzone is between 0 and 1, and is by default 0.2.","fullName":"Set gamepad deadzone for sticks","functionType":"Action","name":"A_Set_deadzone","sentence":"Set deadzone for sticks on gamepad: _PARAM1_ to _PARAM2_","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","const newDeadzone = eventsFunctionContext.getArgument(\"deadzone\");\r","\r","// https://github.com/4ian/GDevelop-extensions/pull/33#issuecomment-618224857\r","gdjs._extensionController.getPlayer(playerId).deadzone = gdjs.evtTools.common.clamp(newDeadzone, 0, 1);\r",""],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"},{"description":"Deadzone for sticks, 0.2 by default (0 to 1)","name":"deadzone","type":"expression"}],"objectGroups":[]},{"description":"Check if a stick of a gamepad is pushed in a given direction.","fullName":"Gamepad stick pushed (axis)","functionType":"Condition","name":"C_Axis_pushed","sentence":"_PARAM2_ stick of gamepad _PARAM1_ is pushed in direction _PARAM3_","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","const stick = eventsFunctionContext.getArgument(\"stick\").toUpperCase();\r","const direction = eventsFunctionContext.getArgument(\"direction\").toUpperCase();\r","\r","if (stick != \"LEFT\" && stick != \"RIGHT\") {\r"," console.error('Parameter stick in condition: \"Gamepad stick pushed (axis)\", is not valid, must be LEFT or RIGHT');\r"," return;\r","}\r","if (direction != \"UP\" && direction != \"DOWN\" && direction != \"LEFT\" && direction != \"RIGHT\" && direction != \"ANY\") {\r"," console.error('Parameter direction in condition: \"Gamepad stick pushed (axis)\", is not valid, must be UP, DOWN, LEFT or RIGHT');\r"," return;\r","}\r","/** @type {Gamepad} */\r","const gamepad = gdjs._extensionController.getGamepad(playerId);\r","if (!gamepad) {\r"," // The gamepad is not connected.\r"," return;\r","}\r","const axisValueX = stick === 'RIGHT' ? gamepad.axes[2] : gamepad.axes[0];\r","const axisValueY = stick === 'RIGHT' ? gamepad.axes[3] : gamepad.axes[1];\r","eventsFunctionContext.returnValue = gdjs._extensionController.isAxisPushed(playerId, direction, axisValueX, axisValueY);\r",""],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"},{"description":"Stick: \"Left\" or \"Right\"","name":"stick","supplementaryInformation":"[\"Left\",\"Right\"]","type":"stringWithSelector"},{"description":"Direction","name":"direction","supplementaryInformation":"[\"Up\",\"Down\",\"Left\",\"Right\",\"Any\"]","type":"stringWithSelector"}],"objectGroups":[]},{"description":"Return the number of connected gamepads.","fullName":"Connected gamepads count","functionType":"Expression","name":"ConnectedGamepadsCount","sentence":"","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];\r","let connectedGamepadCount = 0;\r","for (let playerId = 0; playerId < gamepads.length; playerId++) {\r"," // Gamepads can be disconnected and become null\r"," if (gamepads[playerId]) {\r"," connectedGamepadCount++;\r"," }\r","}\r","eventsFunctionContext.returnValue = connectedGamepadCount;\r",""],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"expressionType":{"type":"expression"},"parameters":[],"objectGroups":[]},{"description":"Return a string containing informations about the specified gamepad.","fullName":"Gamepad type","functionType":"StringExpression","name":"GamepadType","sentence":"Player _PARAM1_ use _PARAM2_ controller","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;","/** @type {Gamepad} */","const gamepad = gdjs._extensionController.getGamepad(playerId);","if (!gamepad) {"," // The gamepad is not connected."," return;","}","eventsFunctionContext.returnValue = (gamepad && gamepad.id) ? gamepad.id : \"No information for player \" + (playerId + 1)",""],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"expressionType":{"type":"string"},"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"}],"objectGroups":[]},{"description":"Check if the specified gamepad has the specified information in its description. Useful to know if the gamepad is a Xbox or PS4 controller.","fullName":"Gamepad type","functionType":"Condition","name":"C_Controller_type","sentence":"Gamepad _PARAM1_ is a _PARAM2_ controller","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;","const controllerType = eventsFunctionContext.getArgument(\"controller_type\").toUpperCase();","/** @type {Gamepad} */","const gamepad = gdjs._extensionController.getGamepad(playerId);","if (!gamepad) {"," // The gamepad is not connected."," return;","}","if (controllerType == \"XBOX\") {"," eventsFunctionContext.returnValue = gdjs._extensionController.isXbox(gamepad);","} else {"," eventsFunctionContext.returnValue = gamepad ? gamepad.id.toUpperCase().indexOf(controllerType) !== -1 : false;","}"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"},{"description":"Type: \"Xbox\", \"PS4\", \"Steam\" or \"PS3\" (among other)","name":"controller_type","type":"string"}],"objectGroups":[]},{"description":"Check if a gamepad is connected.","fullName":"Gamepad connected","functionType":"Condition","name":"C_Controller_X_is_connected","sentence":"Gamepad _PARAM1_ is plugged and connected","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;","/** @type {Gamepad[]} */","const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];","// If gamepad was disconnected it will be null (so this will return false)","// If gamepad was never connected it will be undefined (so this will return false)","eventsFunctionContext.returnValue = !!gamepads[playerId];"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"}],"objectGroups":[]},{"description":"Generate a vibration on the specified controller. Might only work if the game is running in a recent web browser.","fullName":"Gamepad vibration","functionType":"Action","name":"A_Vibrate_controller","sentence":"Make gamepad _PARAM1_ vibrate for _PARAM2_ seconds","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;","const duration = eventsFunctionContext.getArgument(\"Duration\") || 1;","/** @type {Gamepad} */","const gamepad = gdjs._extensionController.getGamepad(playerId);","if (!gamepad) {"," // The gamepad is not connected."," return;","}","//Vibration work only on game in browser.","if (gamepad.vibrationActuator) {"," gamepad.vibrationActuator.playEffect(\"dual-rumble\", {"," startDelay: 0,"," duration: duration * 1000,"," weakMagnitude: 1.0,"," strongMagnitude: 1.0"," });","}"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"},{"description":"Time of the vibration, in seconds (optional, default value is 1)","name":"Duration","type":"expression"}],"objectGroups":[]},{"description":"Generate an advanced vibration on the specified controller. Incompatible with Firefox.","fullName":"Advanced gamepad vibration","functionType":"Action","name":"A_Advanced_Vibration_Controller","sentence":"Make gamepad _PARAM1_ vibrate for _PARAM2_ seconds with the vibration magnitude of _PARAM3_ and _PARAM4_","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["const { clamp } = gdjs.evtTools.common;","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;","const duration = eventsFunctionContext.getArgument(\"Duration\") || 1;","const strongRumbleMagnitude = clamp(eventsFunctionContext.getArgument(\"StrongMagnitude\"), 0, 1);","const weakRumbleMagnitude = clamp(eventsFunctionContext.getArgument(\"WeakMagnitude\"), 0, 1);","/** @type {Gamepad} */","const gamepad = gdjs._extensionController.getGamepad(playerId);","if (!gamepad) {"," // The gamepad is not connected."," return;","}","//Vibration work only on game in browser.","if (gamepad.vibrationActuator) {"," gamepad.vibrationActuator.playEffect(\"dual-rumble\", {"," startDelay: 0,"," duration: duration * 1000,"," weakMagnitude: weakRumbleMagnitude,"," strongMagnitude: strongRumbleMagnitude"," });","}","const player = gdjs._extensionController.getPlayer(playerId)","player.rumble.duration = duration;","player.rumble.elapsedTime = 0;","player.rumble.weakMagnitude = weakRumbleMagnitude;","player.rumble.strongMagnitude = strongRumbleMagnitude;"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"},{"description":"Time of the vibration, in seconds (optional, default value is 1)","name":"Duration","type":"expression"},{"description":"Strong rumble magnitude (from 0 to 1)","name":"StrongMagnitude","type":"expression"},{"description":"Weak rumble magnitude (from 0 to 1)","name":"WeakMagnitude","type":"expression"}],"objectGroups":[]},{"description":"Change a vibration on the specified controller. Incompatible with Firefox.","fullName":"Change gamepad active vibration","functionType":"Action","name":"A_Change_Vibration_Magnitude","sentence":"Change the vibration magnitude of _PARAM2_ & _PARAM3_ on gamepad _PARAM1_","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["const { clamp } = gdjs.evtTools.common;","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;","const player = gdjs._extensionController.getPlayer(playerId);","const elapsedTime = player.rumble.elapsedTime || 0;","const originalDuration = player.rumble.duration || 1;","const strongRumbleMagnitude = clamp(eventsFunctionContext.getArgument(\"StrongMagnitude\"), 0, 1);","const weakRumbleMagnitude = clamp(eventsFunctionContext.getArgument(\"WeakMagnitude\"), 0, 1);","/** @type {Gamepad} */","const gamepad = gdjs._extensionController.getGamepad(playerId);","if (!gamepad) {"," // The gamepad is not connected."," return;","}","if (originalDuration - elapsedTime <= 0) return;","//Vibration work only on game in browser.","if (gamepad.vibrationActuator) {"," gamepad.vibrationActuator.playEffect(\"dual-rumble\", {"," startDelay: 0,"," duration: 1000 * (originalDuration - elapsedTime),"," weakMagnitude: weakRumbleMagnitude,"," strongMagnitude: strongRumbleMagnitude"," });","}","","player.rumble.weakMagnitude = weakRumbleMagnitude;","player.rumble.strongMagnitude = strongRumbleMagnitude;"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"},{"description":"Strong rumble magnitude (from 0 to 1)","name":"StrongMagnitude","type":"expression"},{"description":"Weak rumble magnitude (from 0 to 1)","name":"WeakMagnitude","type":"expression"}],"objectGroups":[]},{"description":"Check if any button is released on a gamepad.","fullName":"Any gamepad button released","functionType":"Condition","name":"C_any_button_released","sentence":"Any button of gamepad _PARAM1_ is released","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[]},{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["\r","const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","const player = gdjs._extensionController.getPlayer(playerId)\r","eventsFunctionContext.returnValue = player.isAnyButtonReleased();"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":true}],"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"}],"objectGroups":[]},{"description":"Return the strength of the weak vibration motor on the gamepad of a player.","fullName":"Weak rumble magnitude","functionType":"Expression","name":"WeakVibrationMagnitude","sentence":"","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","eventsFunctionContext.returnValue = gdjs._extensionController.getPlayer(playerId).rumble.weakMagnitude;"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":false}],"expressionType":{"type":"expression"},"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"}],"objectGroups":[]},{"description":"Return the strength of the strong vibration motor on the gamepad of a player.","fullName":"Strong rumble magnitude","functionType":"Expression","name":"StrongVibrationMagnitude","sentence":"","events":[{"type":"BuiltinCommonInstructions::JsCode","inlineCode":["const playerId = eventsFunctionContext.getArgument(\"PlayerId\") - 1;\r","eventsFunctionContext.returnValue = gdjs._extensionController.getPlayer(playerId).rumble.strongMagnitude;"],"parameterObjects":"","useStrict":true,"eventsSheetExpanded":false}],"expressionType":{"type":"expression"},"parameters":[{"description":"The gamepad identifier: 1, 2, 3 or 4","name":"PlayerId","type":"expression"}],"objectGroups":[]}],"eventsFunctionsFolderStructure":{"folderName":"__ROOT","children":[{"functionName":"onFirstSceneLoaded"},{"functionName":"onSceneLoaded"},{"functionName":"onScenePostEvents"},{"functionName":"AcceleratedSpeed"},{"functionName":"TriggerPressure"},{"functionName":"StickForce"},{"functionName":"StickRotationValue"},{"functionName":"StickAngle"},{"functionName":"AxisValue"},{"functionName":"StickForceX"},{"functionName":"StickForceY"},{"functionName":"C_Button_released"},{"functionName":"IsButtonJustPressed"},{"functionName":"LastButtonID"},{"functionName":"C_Any_Button_pressed"},{"functionName":"LastButtonString"},{"functionName":"GamepadCount"},{"functionName":"C_Button_pressed"},{"functionName":"Deadzone"},{"functionName":"A_Set_deadzone"},{"functionName":"C_Axis_pushed"},{"functionName":"ConnectedGamepadsCount"},{"functionName":"GamepadType"},{"functionName":"C_Controller_type"},{"functionName":"C_Controller_X_is_connected"},{"functionName":"A_Vibrate_controller"},{"functionName":"A_Advanced_Vibration_Controller"},{"functionName":"A_Change_Vibration_Magnitude"},{"functionName":"C_any_button_released"},{"functionName":"WeakVibrationMagnitude"},{"functionName":"StrongVibrationMagnitude"}]},"eventsBasedBehaviors":[{"description":"Control a platformer character with a gamepad.","fullName":"Platformer gamepad mapper","helpPath":"","iconUrl":"","name":"PlatformerGamepadMapper","objectType":"","previewIconUrl":"","quickCustomizationVisibility":"hidden","eventsFunctions":[{"fullName":"","functionType":"Action","name":"doStepPreEvents","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Controller_X_is_connected"},"parameters":["","GamepadIdentifier",""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BooleanVariable"},"parameters":["UseArrows","True",""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","GamepadIdentifier","\"Left\"","\"Left\""]}],"actions":[{"type":{"value":"PlatformBehavior::SimulateLeftKey"},"parameters":["Object","PlatformerCharacter"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","GamepadIdentifier","\"Right\"","\"Left\""]}],"actions":[{"type":{"value":"PlatformBehavior::SimulateRightKey"},"parameters":["Object","PlatformerCharacter"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","GamepadIdentifier","\"Up\"","\"Left\""]}],"actions":[{"type":{"value":"PlatformBehavior::SimulateUpKey"},"parameters":["Object","PlatformerCharacter"]},{"type":{"value":"PlatformBehavior::SimulateLadderKey"},"parameters":["Object","PlatformerCharacter"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","GamepadIdentifier","\"Down\"","\"Left\""]}],"actions":[{"type":{"value":"PlatformBehavior::SimulateDownKey"},"parameters":["Object","PlatformerCharacter"]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BooleanVariable"},"parameters":["UseLeftStick","True",""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Left\"","\"Left\"",""]}],"actions":[{"type":{"value":"PlatformBehavior::SimulateLeftKey"},"parameters":["Object","PlatformerCharacter"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Left\"","\"Right\"",""]}],"actions":[{"type":{"value":"PlatformBehavior::SimulateRightKey"},"parameters":["Object","PlatformerCharacter"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Left\"","\"Up\"",""]}],"actions":[{"type":{"value":"PlatformBehavior::SimulateUpKey"},"parameters":["Object","PlatformerCharacter"]},{"type":{"value":"PlatformBehavior::SimulateLadderKey"},"parameters":["Object","PlatformerCharacter"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Left\"","\"Down\"",""]}],"actions":[{"type":{"value":"PlatformBehavior::SimulateDownKey"},"parameters":["Object","PlatformerCharacter"]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BooleanVariable"},"parameters":["UseRightStick","True",""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Right\"","\"Left\"",""]}],"actions":[{"type":{"value":"PlatformBehavior::SimulateLeftKey"},"parameters":["Object","PlatformerCharacter"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Right\"","\"Right\"",""]}],"actions":[{"type":{"value":"PlatformBehavior::SimulateRightKey"},"parameters":["Object","PlatformerCharacter"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Right\"","\"Up\"",""]}],"actions":[{"type":{"value":"PlatformBehavior::SimulateUpKey"},"parameters":["Object","PlatformerCharacter"]},{"type":{"value":"PlatformBehavior::SimulateLadderKey"},"parameters":["Object","PlatformerCharacter"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Right\"","\"Down\"",""]}],"actions":[{"type":{"value":"PlatformBehavior::SimulateDownKey"},"parameters":["Object","PlatformerCharacter"]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","GamepadIdentifier","Buttons[JumpButton]","\"Left\""]}],"actions":[{"type":{"value":"PlatformBehavior::SimulateJumpKey"},"parameters":["Object","PlatformerCharacter"]}]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::PlatformerGamepadMapper","type":"behavior"}],"objectGroups":[]}],"eventsFunctionsFolderStructure":{"folderName":"__ROOT","children":[{"functionName":"doStepPreEvents"}]},"propertyDescriptors":[{"value":"","type":"Behavior","label":"Platformer character behavior","extraInformation":["PlatformBehavior::PlatformerObjectBehavior"],"choices":[],"name":"PlatformerCharacter"},{"value":"1","type":"Number","label":"Gamepad identifier (1, 2, 3 or 4)","name":"GamepadIdentifier"},{"value":"true","type":"Boolean","label":"Use directional pad","group":"Controls","name":"UseArrows"},{"value":"true","type":"Boolean","label":"Use left stick","group":"Controls","name":"UseLeftStick"},{"value":"","type":"Boolean","label":"Use right stick","group":"Controls","name":"UseRightStick"},{"value":"A or Cross","type":"Choice","label":"Jump button","group":"Controls","choices":[{"label":"A or Cross","value":"A or Cross"},{"label":"B or Circle","value":"B or Circle"},{"label":"X or Square","value":"X or Square"},{"label":"Y or Triangle","value":"Y or Triangle"},{"label":"LB or L1","value":"LB or L1"},{"label":"RB or R1","value":"RB or R1"},{"label":"LT or L2","value":"LT or L2"},{"label":"RT or R2","value":"RT or R2"}],"name":"JumpButton"}],"propertiesFolderStructure":{"folderName":"__ROOT","children":[{"propertyName":"PlatformerCharacter"},{"propertyName":"GamepadIdentifier"},{"folderName":"Controls","children":[{"propertyName":"UseArrows"},{"propertyName":"UseLeftStick"},{"propertyName":"UseRightStick"},{"propertyName":"JumpButton"}]}]}},{"description":"Control a 3D physics character with a gamepad.","fullName":"3D platformer gamepad mapper","helpPath":"","iconUrl":"","name":"Platformer3DGamepadMapper","objectType":"","previewIconUrl":"","quickCustomizationVisibility":"hidden","eventsFunctions":[{"fullName":"","functionType":"Action","name":"doStepPreEvents","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Controller_X_is_connected"},"parameters":["","GamepadIdentifier",""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::StickForce"},"parameters":["",">","0","GamepadIdentifier","JoystickIdentifier",""]}],"actions":[{"type":{"value":"Physics3D::PhysicsCharacter3D::SetForwardAngle"},"parameters":["Object","PhysicsCharacter3D","=","Gamepads::StickAngle(GamepadIdentifier, JoystickIdentifier) + CameraAngle(Object.Layer())"]},{"type":{"value":"Physics3D::PhysicsCharacter3D::SimulateStick"},"parameters":["Object","PhysicsCharacter3D","-90","Gamepads::StickForce(GamepadIdentifier, JoystickIdentifier)"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","GamepadIdentifier","Buttons[JumpButton]","\"Left\""]}],"actions":[{"type":{"value":"Physics3D::PhysicsCharacter3D::SimulateJumpKey"},"parameters":["Object","PhysicsCharacter3D"]}]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::Platformer3DGamepadMapper","type":"behavior"}],"objectGroups":[]}],"eventsFunctionsFolderStructure":{"folderName":"__ROOT","children":[{"functionName":"doStepPreEvents"}]},"propertyDescriptors":[{"value":"","type":"Behavior","label":"3D physics character","extraInformation":["Physics3D::PhysicsCharacter3D"],"choices":[],"name":"PhysicsCharacter3D"},{"value":"1","type":"Number","label":"Gamepad identifier (1, 2, 3 or 4)","name":"GamepadIdentifier"},{"value":"Left","type":"Choice","label":"Walk joystick","group":"Controls","choices":[{"label":"Left","value":"Left"},{"label":"Right","value":"Right"}],"name":"JoystickIdentifier"},{"value":"A or Cross","type":"Choice","label":"Jump button","group":"Controls","choices":[{"label":"A or Cross","value":"A or Cross"},{"label":"B or Circle","value":"B or Circle"},{"label":"X or Square","value":"X or Square"},{"label":"Y or Triangle","value":"Y or Triangle"},{"label":"LB or L1","value":"LB or L1"},{"label":"RB or R1","value":"RB or R1"},{"label":"LT or L2","value":"LT or L2"},{"label":"RT or R2","value":"RT or R2"}],"name":"JumpButton"}],"propertiesFolderStructure":{"folderName":"__ROOT","children":[{"propertyName":"PhysicsCharacter3D"},{"propertyName":"GamepadIdentifier"},{"folderName":"Controls","children":[{"propertyName":"JoystickIdentifier"},{"propertyName":"JumpButton"}]}]}},{"description":"Control a 3D physics character with a gamepad.","fullName":"3D shooter gamepad mapper","helpPath":"","iconUrl":"","name":"Shooter3DGamepadMapper","objectType":"","previewIconUrl":"","quickCustomizationVisibility":"hidden","eventsFunctions":[{"fullName":"","functionType":"Action","name":"doStepPreEvents","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Controller_X_is_connected"},"parameters":["","GamepadIdentifier",""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::StickForce"},"parameters":["",">","0","GamepadIdentifier","WalkStick",""]}],"actions":[{"type":{"value":"Physics3D::PhysicsCharacter3D::SimulateStick"},"parameters":["Object","PhysicsCharacter3D","Gamepads::StickAngle(GamepadIdentifier, WalkStick)","Gamepads::StickForce(GamepadIdentifier, WalkStick)"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","GamepadIdentifier","Buttons[JumpButton]","\"Left\""]}],"actions":[{"type":{"value":"Physics3D::PhysicsCharacter3D::SimulateJumpKey"},"parameters":["Object","PhysicsCharacter3D"]}]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::Shooter3DGamepadMapper","type":"behavior"}],"objectGroups":[]}],"eventsFunctionsFolderStructure":{"folderName":"__ROOT","children":[{"functionName":"doStepPreEvents"}]},"propertyDescriptors":[{"value":"","type":"Behavior","label":"3D physics character","extraInformation":["Physics3D::PhysicsCharacter3D"],"choices":[],"name":"PhysicsCharacter3D"},{"value":"1","type":"Number","label":"Gamepad identifier (1, 2, 3 or 4)","name":"GamepadIdentifier"},{"value":"Left","type":"Choice","label":"Walk joystick","group":"Controls","choices":[{"label":"Left","value":"Left"},{"label":"Right","value":"Right"}],"name":"WalkStick"},{"value":"Right","type":"Choice","label":"Camera joystick","group":"Controls","choices":[{"label":"Left","value":"Left"},{"label":"Right","value":"Right"}],"name":"CameraStick"},{"value":"A or Cross","type":"Choice","label":"Jump button","group":"Controls","choices":[{"label":"A or Cross","value":"A or Cross"},{"label":"B or Circle","value":"B or Circle"},{"label":"X or Square","value":"X or Square"},{"label":"Y or Triangle","value":"Y or Triangle"},{"label":"LB or L1","value":"LB or L1"},{"label":"RB or R1","value":"RB or R1"},{"label":"LT or L2","value":"LT or L2"},{"label":"RT or R2","value":"RT or R2"}],"name":"JumpButton"}],"propertiesFolderStructure":{"folderName":"__ROOT","children":[{"propertyName":"PhysicsCharacter3D"},{"propertyName":"GamepadIdentifier"},{"folderName":"Controls","children":[{"propertyName":"WalkStick"},{"propertyName":"CameraStick"},{"propertyName":"JumpButton"}]}]}},{"description":"Control camera rotations with a gamepad.","fullName":"First person camera gamepad mapper","helpPath":"","iconUrl":"","name":"FirstPersonGamepadMapper","objectType":"","previewIconUrl":"","quickCustomizationVisibility":"hidden","eventsFunctions":[{"fullName":"","functionType":"Action","name":"doStepPreEvents","sentence":"","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"TODO It's probably a bad idea to rotate the object around Y."},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["CurrentRotationSpeedZ","=","Gamepads::AcceleratedSpeed(CurrentRotationSpeedZ, Gamepads::StickForceX(GamepadIdentifier, CameraStick) * HorizontalRotationSpeedMax, HorizontalRotationSpeedMax, HorizontalRotationAcceleration, HorizontalRotationDeceleration)"]},{"type":{"value":"SetAngle"},"parameters":["Object","+","CurrentRotationSpeedZ * TimeDelta()"]},{"type":{"value":"SetNumberVariable"},"parameters":["CurrentRotationSpeedY","=","Gamepads::AcceleratedSpeed(CurrentRotationSpeedY, Gamepads::StickForceY(GamepadIdentifier, CameraStick) * VerticalRotationSpeedMax, VerticalRotationSpeedMax, VerticalRotationAcceleration, VerticalRotationDeceleration)"]},{"type":{"value":"Scene3D::Base3DBehavior::SetRotationY"},"parameters":["Object","Object3D","+","CurrentRotationSpeedY * TimeDelta()"]},{"type":{"value":"Scene3D::Base3DBehavior::SetRotationY"},"parameters":["Object","Object3D","=","clamp(Object.Object3D::RotationY(), VerticalAngleMin, VerticalAngleMax)"]},{"type":{"value":"Gamepads::FirstPersonGamepadMapper::LookFromObjectEyes"},"parameters":["Object","Behavior",""]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"description":"Move the camera to look though _PARAM1_ eyes. The object must look to the right when all its angles are 0 and the top of its head be toward Z+.","fullName":"Look through object eyes","functionType":"Action","group":"Layers and cameras","name":"LookFromObjectEyes","private":true,"sentence":"Move the camera to look though _PARAM0_ eyes","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"CenterCameraOnObject"},"parameters":["","Object","","Object.Layer()",""]},{"type":{"value":"Scene3D::SetCameraZ"},"parameters":["","=","Object.Object3D::Z() + Object.Object3D::Depth() + OffsetZ","",""]},{"type":{"value":"Scene3D::SetCameraRotationX"},"parameters":["","=","- Object.Object3D::RotationY() + 90","GetArgumentAsString(\"Layer\")",""]},{"type":{"value":"Scene3D::SetCameraRotationY"},"parameters":["","=","Object.Object3D::RotationX()","GetArgumentAsString(\"Layer\")",""]},{"type":{"value":"SetCameraAngle"},"parameters":["","=","Object.Angle() + 90","Object.Layer()",""]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"description":"the maximum horizontal rotation speed of the object.","fullName":"Maximum horizontal rotation speed","functionType":"ExpressionAndCondition","group":"First person camera gamepad mapper horizontal rotation configuration","name":"HorizontalRotationSpeedMax","sentence":"the maximum horizontal rotation speed","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["HorizontalRotationSpeedMax"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"fullName":"","functionType":"ActionWithOperator","getterName":"HorizontalRotationSpeedMax","group":"First person camera gamepad mapper horizontal rotation configuration","name":"SetHorizontalRotationSpeedMax","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["HorizontalRotationSpeedMax","=","Value"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"description":"the horizontal rotation acceleration of the object.","fullName":"Horizontal rotation acceleration","functionType":"ExpressionAndCondition","group":"First person camera gamepad mapper horizontal rotation configuration","name":"HorizontalRotationAcceleration","sentence":"the horizontal rotation acceleration","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["HorizontalRotationAcceleration"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"fullName":"","functionType":"ActionWithOperator","getterName":"HorizontalRotationAcceleration","group":"First person camera gamepad mapper horizontal rotation configuration","name":"SetHorizontalRotationAcceleration","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["HorizontalRotationAcceleration","=","Value"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"description":"the horizontal rotation deceleration of the object.","fullName":"Horizontal rotation deceleration","functionType":"ExpressionAndCondition","group":"First person camera gamepad mapper horizontal rotation configuration","name":"HorizontalRotationDeceleration","sentence":"the horizontal rotation deceleration","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["HorizontalRotationDeceleration"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"fullName":"","functionType":"ActionWithOperator","getterName":"HorizontalRotationDeceleration","group":"First person camera gamepad mapper horizontal rotation configuration","name":"SetHorizontalRotationDeceleration","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["HorizontalRotationDeceleration","=","Value"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"description":"the maximum vertical rotation speed of the object.","fullName":"Maximum vertical rotation speed","functionType":"ExpressionAndCondition","group":"First person camera gamepad mapper vertical rotation configuration","name":"VerticalRotationSpeedMax","sentence":"the maximum vertical rotation speed","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["VerticalRotationSpeedMax"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"fullName":"","functionType":"ActionWithOperator","getterName":"VerticalRotationSpeedMax","group":"First person camera gamepad mapper vertical rotation configuration","name":"SetVerticalRotationSpeedMax","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["VerticalRotationSpeedMax","=","Value"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"description":"the vertical rotation acceleration of the object.","fullName":"Vertical rotation acceleration","functionType":"ExpressionAndCondition","group":"First person camera gamepad mapper vertical rotation configuration","name":"VerticalRotationAcceleration","sentence":"the vertical rotation acceleration","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["VerticalRotationAcceleration"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"fullName":"","functionType":"ActionWithOperator","getterName":"VerticalRotationAcceleration","group":"First person camera gamepad mapper vertical rotation configuration","name":"SetVerticalRotationAcceleration","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["VerticalRotationAcceleration","=","Value"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"description":"the vertical rotation deceleration of the object.","fullName":"Vertical rotation deceleration","functionType":"ExpressionAndCondition","group":"First person camera gamepad mapper vertical rotation configuration","name":"VerticalRotationDeceleration","sentence":"the vertical rotation deceleration","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["VerticalRotationDeceleration"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"fullName":"","functionType":"ActionWithOperator","getterName":"VerticalRotationDeceleration","group":"First person camera gamepad mapper vertical rotation configuration","name":"SetVerticalRotationDeceleration","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["VerticalRotationDeceleration","=","Value"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"description":"the minimum vertical camera angle of the object.","fullName":"Minimum vertical camera angle","functionType":"ExpressionAndCondition","group":"First person camera gamepad mapper vertical rotation configuration","name":"VerticalAngleMin","sentence":"the minimum vertical camera angle","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["VerticalAngleMin"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"fullName":"","functionType":"ActionWithOperator","getterName":"VerticalAngleMin","group":"First person camera gamepad mapper vertical rotation configuration","name":"SetVerticalAngleMin","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["VerticalAngleMin","=","Value"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"description":"the maximum vertical camera angle of the object.","fullName":"Maximum vertical camera angle","functionType":"ExpressionAndCondition","group":"First person camera gamepad mapper vertical rotation configuration","name":"VerticalAngleMax","sentence":"the maximum vertical camera angle","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["VerticalAngleMax"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"fullName":"","functionType":"ActionWithOperator","getterName":"VerticalAngleMax","group":"First person camera gamepad mapper vertical rotation configuration","name":"SetVerticalAngleMax","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["VerticalAngleMax","=","Value"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"description":"the z position offset of the object.","fullName":"Z position offset","functionType":"ExpressionAndCondition","group":"First person camera gamepad mapper position configuration","name":"OffsetZ","sentence":"the z position offset","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["OffsetZ"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]},{"fullName":"","functionType":"ActionWithOperator","getterName":"OffsetZ","group":"First person camera gamepad mapper position configuration","name":"SetOffsetZ","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["OffsetZ","=","Value"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::FirstPersonGamepadMapper","type":"behavior"}],"objectGroups":[]}],"eventsFunctionsFolderStructure":{"folderName":"__ROOT","children":[{"functionName":"doStepPreEvents"},{"folderName":"Layers and cameras","children":[{"functionName":"LookFromObjectEyes"}]},{"folderName":"First person camera gamepad mapper horizontal rotation configuration","children":[{"functionName":"HorizontalRotationSpeedMax"},{"functionName":"SetHorizontalRotationSpeedMax"},{"functionName":"HorizontalRotationAcceleration"},{"functionName":"SetHorizontalRotationAcceleration"},{"functionName":"HorizontalRotationDeceleration"},{"functionName":"SetHorizontalRotationDeceleration"}]},{"folderName":"First person camera gamepad mapper vertical rotation configuration","children":[{"functionName":"VerticalRotationSpeedMax"},{"functionName":"SetVerticalRotationSpeedMax"},{"functionName":"VerticalRotationAcceleration"},{"functionName":"SetVerticalRotationAcceleration"},{"functionName":"VerticalRotationDeceleration"},{"functionName":"SetVerticalRotationDeceleration"},{"functionName":"VerticalAngleMin"},{"functionName":"SetVerticalAngleMin"},{"functionName":"VerticalAngleMax"},{"functionName":"SetVerticalAngleMax"}]},{"folderName":"First person camera gamepad mapper position configuration","children":[{"functionName":"OffsetZ"},{"functionName":"SetOffsetZ"}]}]},"propertyDescriptors":[{"value":"","type":"Behavior","label":"3D capability","extraInformation":["Scene3D::Base3DBehavior"],"choices":[],"name":"Object3D"},{"value":"1","type":"Number","label":"Gamepad identifier (1, 2, 3 or 4)","name":"GamepadIdentifier"},{"value":"Right","type":"Choice","label":"Camera joystick","choices":[{"label":"Left","value":"Left"},{"label":"Right","value":"Right"}],"name":"CameraStick"},{"value":"180","type":"Number","unit":"AngularSpeed","label":"Maximum rotation speed","group":"Horizontal rotation","name":"HorizontalRotationSpeedMax"},{"value":"360","type":"Number","label":"Rotation acceleration","group":"Horizontal rotation","name":"HorizontalRotationAcceleration"},{"value":"720","type":"Number","label":"Rotation deceleration","group":"Horizontal rotation","name":"HorizontalRotationDeceleration"},{"value":"120","type":"Number","unit":"AngularSpeed","label":"Maximum rotation speed","group":"Vertical rotation","name":"VerticalRotationSpeedMax"},{"value":"240","type":"Number","label":"Rotation acceleration","group":"Vertical rotation","name":"VerticalRotationAcceleration"},{"value":"480","type":"Number","label":"Rotation deceleration","group":"Vertical rotation","name":"VerticalRotationDeceleration"},{"value":"-90","type":"Number","unit":"DegreeAngle","label":"Minimum angle","group":"Vertical rotation","name":"VerticalAngleMin"},{"value":"90","type":"Number","unit":"DegreeAngle","label":"Maximum angle","group":"Vertical rotation","name":"VerticalAngleMax"},{"value":"0","type":"Number","unit":"Pixel","label":"Z position offset","group":"Position","name":"OffsetZ"},{"value":"0","type":"Number","unit":"AngularSpeed","label":"Current rotation speed Z","hidden":true,"name":"CurrentRotationSpeedZ"},{"value":"0","type":"Number","unit":"AngularSpeed","label":"Current rotation speed Y","hidden":true,"name":"CurrentRotationSpeedY"}],"propertiesFolderStructure":{"folderName":"__ROOT","children":[{"propertyName":"Object3D"},{"propertyName":"GamepadIdentifier"},{"propertyName":"CameraStick"},{"folderName":"Horizontal rotation","children":[{"propertyName":"HorizontalRotationSpeedMax"},{"propertyName":"HorizontalRotationAcceleration"},{"propertyName":"HorizontalRotationDeceleration"}]},{"folderName":"Vertical rotation","children":[{"propertyName":"VerticalRotationSpeedMax"},{"propertyName":"VerticalRotationAcceleration"},{"propertyName":"VerticalRotationDeceleration"},{"propertyName":"VerticalAngleMin"},{"propertyName":"VerticalAngleMax"}]},{"folderName":"Position","children":[{"propertyName":"OffsetZ"}]},{"propertyName":"CurrentRotationSpeedZ"},{"propertyName":"CurrentRotationSpeedY"}]}},{"description":"Control a 3D physics car with a gamepad.","fullName":"3D car gamepad mapper","helpPath":"","iconUrl":"","name":"PhysicsCar3DGamepadMapper","objectType":"","previewIconUrl":"","quickCustomizationVisibility":"hidden","eventsFunctions":[{"fullName":"","functionType":"Action","name":"doStepPreEvents","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Controller_X_is_connected"},"parameters":["","GamepadIdentifier",""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BooleanVariable"},"parameters":["UseArrows","True",""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","GamepadIdentifier","\"Left\"","\"Left\""]}],"actions":[{"type":{"value":"Physics3D::PhysicsCar3D::SimulateLeftKey"},"parameters":["Object","PhysicsCar3D"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","GamepadIdentifier","\"Right\"","\"Left\""]}],"actions":[{"type":{"value":"Physics3D::PhysicsCar3D::SimulateRightKey"},"parameters":["Object","PhysicsCar3D"]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BooleanVariable"},"parameters":["UseLeftStick","True",""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","1","\"Left\"","\"Any\"",""]}],"actions":[{"type":{"value":"Physics3D::PhysicsCar3D::SimulateSteeringStick"},"parameters":["Object","PhysicsCar3D","Gamepads::StickForceX(GamepadIdentifier, \"Left\")"]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BooleanVariable"},"parameters":["UseRightStick","True",""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","1","\"Right\"","\"Any\"",""]}],"actions":[{"type":{"value":"Physics3D::PhysicsCar3D::SimulateSteeringStick"},"parameters":["Object","PhysicsCar3D","Gamepads::StickForceX(GamepadIdentifier, \"Right\")"]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BuiltinCommonInstructions::Or"},"parameters":[],"subInstructions":[{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","1","\"LT\"","\"Up\""]},{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","1","\"RT\"","\"Up\""]}]}],"actions":[{"type":{"value":"Physics3D::PhysicsCar3D::SimulateAcceleratorStick"},"parameters":["Object","PhysicsCar3D","Gamepads::TriggerPressure(GamepadIdentifier, \"RT\") - Gamepads::TriggerPressure(GamepadIdentifier, \"LT\")"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","GamepadIdentifier","Buttons[HandBrakeButton]","\"Left\""]}],"actions":[{"type":{"value":"Physics3D::PhysicsCar3D::SimulateHandBrakeKey"},"parameters":["Object","PhysicsCar3D"]}]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::PhysicsCar3DGamepadMapper","type":"behavior"}],"objectGroups":[]}],"eventsFunctionsFolderStructure":{"folderName":"__ROOT","children":[{"functionName":"doStepPreEvents"}]},"propertyDescriptors":[{"value":"","type":"Behavior","label":"3D physics car","extraInformation":["Physics3D::PhysicsCar3D"],"choices":[],"name":"PhysicsCar3D"},{"value":"1","type":"Number","label":"Gamepad identifier (1, 2, 3 or 4)","name":"GamepadIdentifier"},{"value":"true","type":"Boolean","label":"Use directional pad","group":"Controls","name":"UseArrows"},{"value":"true","type":"Boolean","label":"Use left stick","group":"Controls","name":"UseLeftStick"},{"value":"","type":"Boolean","label":"Use right stick","group":"Controls","name":"UseRightStick"},{"value":"B or Circle","type":"Choice","label":"Hand brake button","group":"Controls","choices":[{"label":"A or Cross","value":"A or Cross"},{"label":"B or Circle","value":"B or Circle"},{"label":"X or Square","value":"X or Square"},{"label":"Y or Triangle","value":"Y or Triangle"},{"label":"LB or L1","value":"LB or L1"},{"label":"RB or R1","value":"RB or R1"},{"label":"LT or L2","value":"LT or L2"},{"label":"RT or R2","value":"RT or R2"}],"name":"HandBrakeButton"}],"propertiesFolderStructure":{"folderName":"__ROOT","children":[{"propertyName":"PhysicsCar3D"},{"propertyName":"GamepadIdentifier"},{"folderName":"Controls","children":[{"propertyName":"UseArrows"},{"propertyName":"UseLeftStick"},{"propertyName":"UseRightStick"},{"propertyName":"HandBrakeButton"}]}]}},{"description":"Control a top-down character with a gamepad.","fullName":"Top-down gamepad mapper","helpPath":"","iconUrl":"","name":"TopDownGamepadMapper","objectType":"","previewIconUrl":"","quickCustomizationVisibility":"hidden","eventsFunctions":[{"fullName":"","functionType":"Action","name":"doStepPreEvents","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Controller_X_is_connected"},"parameters":["","GamepadIdentifier",""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BooleanVariable"},"parameters":["UseArrows","True",""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","GamepadIdentifier","\"Left\"","\"Left\""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateLeftKey"},"parameters":["Object","TopDownMovement"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","GamepadIdentifier","\"Right\"","\"Left\""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateRightKey"},"parameters":["Object","TopDownMovement"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","GamepadIdentifier","\"Up\"","\"Left\""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateUpKey"},"parameters":["Object","TopDownMovement"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Button_pressed"},"parameters":["","GamepadIdentifier","\"Down\"","\"Left\""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateDownKey"},"parameters":["Object","TopDownMovement"]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BooleanVariable"},"parameters":["UseLeftStick","True",""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"StringVariable"},"parameters":["StickMode","=","\"Analog\""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateStick"},"parameters":["Object","TopDownMovement","Gamepads::StickRotationValue(GamepadIdentifier, \"Left\")","Gamepads::StickForce(GamepadIdentifier, \"Left\")"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"StringVariable"},"parameters":["StickMode","=","\"360°\""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateStick"},"parameters":["Object","TopDownMovement","Gamepads::StickRotationValue(GamepadIdentifier, \"Left\")","sign(Gamepads::StickForce(GamepadIdentifier, \"Left\"))"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"StringVariable"},"parameters":["StickMode","=","\"8 Directions\""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Left\"","\"Left\"",""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateLeftKey"},"parameters":["Object","TopDownMovement"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Left\"","\"Right\"",""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateRightKey"},"parameters":["Object","TopDownMovement"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Left\"","\"Up\"",""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateUpKey"},"parameters":["Object","TopDownMovement"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Left\"","\"Down\"",""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateDownKey"},"parameters":["Object","TopDownMovement"]}]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BooleanVariable"},"parameters":["UseRightStick","True",""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"StringVariable"},"parameters":["StickMode","=","\"Analog\""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateStick"},"parameters":["Object","TopDownMovement","Gamepads::StickRotationValue(GamepadIdentifier, \"Right\")","Gamepads::StickForce(GamepadIdentifier, \"Right\")"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"StringVariable"},"parameters":["StickMode","=","\"360°\""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateStick"},"parameters":["Object","TopDownMovement","sign(Gamepads::StickForce(GamepadIdentifier, \"Right\"))","1"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"StringVariable"},"parameters":["StickMode","=","\"8 Directions\""]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Right\"","\"Left\"",""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateLeftKey"},"parameters":["Object","TopDownMovement"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Right\"","\"Right\"",""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateRightKey"},"parameters":["Object","TopDownMovement"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Right\"","\"Up\"",""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateUpKey"},"parameters":["Object","TopDownMovement"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"Gamepads::C_Axis_pushed"},"parameters":["","GamepadIdentifier","\"Right\"","\"Down\"",""]}],"actions":[{"type":{"value":"TopDownMovementBehavior::SimulateDownKey"},"parameters":["Object","TopDownMovement"]}]}]}]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"Gamepads::TopDownGamepadMapper","type":"behavior"}],"objectGroups":[]}],"eventsFunctionsFolderStructure":{"folderName":"__ROOT","children":[{"functionName":"doStepPreEvents"}]},"propertyDescriptors":[{"value":"","type":"Behavior","label":"Top-down movement behavior","extraInformation":["TopDownMovementBehavior::TopDownMovementBehavior"],"choices":[],"name":"TopDownMovement"},{"value":"1","type":"Number","label":"Gamepad identifier (1, 2, 3 or 4)","name":"GamepadIdentifier"},{"value":"true","type":"Boolean","label":"Use directional pad","group":"Controls","name":"UseArrows"},{"value":"true","type":"Boolean","label":"Use left stick","group":"Controls","name":"UseLeftStick"},{"value":"","type":"Boolean","label":"Use right stick","group":"Controls","name":"UseRightStick"},{"value":"Analog","type":"Choice","label":"Stick mode","group":"Controls","choices":[{"label":"Analog","value":"Analog"},{"label":"360°","value":"360°"},{"label":"8 Directions","value":"8 Directions"}],"name":"StickMode"}],"propertiesFolderStructure":{"folderName":"__ROOT","children":[{"propertyName":"TopDownMovement"},{"propertyName":"GamepadIdentifier"},{"folderName":"Controls","children":[{"propertyName":"UseArrows"},{"propertyName":"UseLeftStick"},{"propertyName":"UseRightStick"},{"propertyName":"StickMode"}]}]}}],"eventsBasedObjects":[]},{"author":"","category":"Camera","dimension":"2D","extensionNamespace":"","fullName":"Smooth Camera","gdevelopVersion":">=5.5.222","helpPath":"/tutorials/follow-player-with-camera/","iconUrl":"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMy4wLjMsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iSWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgMzIgMzIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDMyIDMyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9DQoJLnN0MXtmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjEwO30NCjwvc3R5bGU+DQo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjQsMTNoLTZjLTEuMSwwLTItMC45LTItMlY1YzAtMS4xLDAuOS0yLDItMmg2YzEuMSwwLDIsMC45LDIsMnY2QzI2LDEyLjEsMjUuMSwxMywyNCwxM3oiLz4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yNiw4djEwYzAsMS4xLTAuOSwyLTIsMkg4Yy0xLjEsMC0yLTAuOS0yLTJWOGMwLTEuMSwwLjktMiwyLTJoOCIvPg0KPGNpcmNsZSBjbGFzcz0ic3QwIiBjeD0iMjEiIGN5PSI4IiByPSIyIi8+DQo8Y2lyY2xlIGNsYXNzPSJzdDAiIGN4PSIxMSIgY3k9IjE2IiByPSIxIi8+DQo8cmVjdCB4PSI5IiB5PSI5IiBjbGFzcz0ic3QwIiB3aWR0aD0iNCIgaGVpZ2h0PSIzIi8+DQo8cG9seWxpbmUgY2xhc3M9InN0MCIgcG9pbnRzPSIyMSwyOSAyMSwyOSAxMSwyOSAxMSwyOSAiLz4NCjxwb2x5bGluZSBjbGFzcz0ic3QwIiBwb2ludHM9IjE4LDIwIDE4LDI5IDE0LDI5IDE0LDIwICIvPg0KPHJlY3QgeD0iNyIgeT0iMyIgY2xhc3M9InN0MCIgd2lkdGg9IjQiIGhlaWdodD0iMyIvPg0KPC9zdmc+DQo=","name":"SmoothCamera","previewIconUrl":"https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Computers and Hardware/Computers and Hardware_camcoder_gopro_go_pro_camera.svg","shortDescription":"Smoothly scroll to follow an object.","version":"0.4.5","description":["The camera follows an object according to:","- a frame rate independent catch-up speed to make the scrolling from smooth to strong","- a maximum speed to do linear following ([open the project online](https://editor.gdevelop.io/?project=example://platformer-with-tilemap)) or slow down the camera when teleporting the object","- a follow-free zone to avoid scrolling on small movements","- an offset to see further in one direction","- an extra delay and catch-up speed to give an impression of speed (useful for dash)","- position forecasting and delay to simulate a cameraman response time","","A platformer dedicated behavior allows to switch of settings when the character is in air or on the floor. This can be used to stabilize the camera when jumping."],"origin":{"identifier":"SmoothCamera","name":"gdevelop-extension-store"},"tags":["camera","scrolling","follow","smooth","platformer","platform"],"authorIds":["IWykYNRvhCZBN3vEgKEbBPOR3Oc2"],"dependencies":[],"globalVariables":[],"sceneVariables":[],"eventsFunctions":[],"eventsFunctionsFolderStructure":{"folderName":"__ROOT"},"eventsBasedBehaviors":[{"description":"Smoothly scroll to follow an object.","fullName":"Smooth Camera","helpPath":"","iconUrl":"","name":"SmoothCamera","objectType":"","previewIconUrl":"","quickCustomizationVisibility":"hidden","eventsFunctions":[{"fullName":"","functionType":"Action","name":"onCreated","sentence":"","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Update private properties through setters to check their values and initialize state."},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SmoothCamera::SmoothCamera::SetLeftwardSpeed"},"parameters":["Object","Behavior","LeftwardSpeed","log(1 - )"]},{"type":{"value":"SmoothCamera::SmoothCamera::SetRightwardSpeed"},"parameters":["Object","Behavior","RightwardSpeed","log(1 - )"]},{"type":{"value":"SmoothCamera::SmoothCamera::SetUpwardSpeed"},"parameters":["Object","Behavior","UpwardSpeed","log(1 - )"]},{"type":{"value":"SmoothCamera::SmoothCamera::SetDownwardSpeed"},"parameters":["Object","Behavior","DownwardSpeed","log(1 - )"]},{"type":{"value":"SmoothCamera::SmoothCamera::SetLeftwardSpeedMax"},"parameters":["Object","Behavior","LeftwardSpeedMax","log(1 - )"]},{"type":{"value":"SmoothCamera::SmoothCamera::SetRightwardSpeedMax"},"parameters":["Object","Behavior","RightwardSpeedMax","log(1 - )"]},{"type":{"value":"SmoothCamera::SmoothCamera::SetUpwardSpeedMax"},"parameters":["Object","Behavior","UpwardSpeedMax","log(1 - )"]},{"type":{"value":"SmoothCamera::SmoothCamera::SetDownwardSpeedMax"},"parameters":["Object","Behavior","DownwardSpeedMax","log(1 - )"]},{"type":{"value":"SmoothCamera::SmoothCamera::SetFollowFreeAreaLeft"},"parameters":["Object","Behavior","FollowFreeAreaLeft","log(1 - )"]},{"type":{"value":"SmoothCamera::SmoothCamera::SetFollowFreeAreaRight"},"parameters":["Object","Behavior","FollowFreeAreaRight","log(1 - )"]},{"type":{"value":"SmoothCamera::SmoothCamera::SetFollowFreeAreaTop"},"parameters":["Object","Behavior","FollowFreeAreaTop","log(1 - )"]},{"type":{"value":"SmoothCamera::SmoothCamera::SetFollowFreeAreaBottom"},"parameters":["Object","Behavior","FollowFreeAreaBottom","log(1 - )"]},{"type":{"value":"SetNumberVariable"},"parameters":["CameraDelay","=","CameraDelay"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"fullName":"","functionType":"Action","name":"doStepPreEvents","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"inverted":true,"value":"BooleanVariable"},"parameters":["IsCalledManually","True",""]}],"actions":[{"type":{"value":"SmoothCamera::SmoothCamera::DoMoveCameraCloser"},"parameters":["Object","Behavior",""]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"description":"Move the camera closer to the object. This action must be called after the object has moved for the frame.","fullName":"Move the camera closer","functionType":"Action","name":"MoveCameraCloser","sentence":"Move the camera closer to _PARAM0_","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"The camera following is called with an action, the call from doStepPreEvents must be disabled to avoid to do it twice."},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetBooleanVariable"},"parameters":["IsCalledManually","True",""]},{"type":{"value":"SmoothCamera::SmoothCamera::DoMoveCameraCloser"},"parameters":["Object","Behavior",""]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"description":"Move the camera closer to the object.","fullName":"Do move the camera closer","functionType":"Action","name":"DoMoveCameraCloser","private":true,"sentence":"Do move the camera closer _PARAM0_","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Delaying and forecasting can be used at the same time.\nForecasting only use the positions that are older than the one used for delaying.\nThe behavior uses a position history that is split in 2 arrays:\n- one for delaying the position (from TimeFromStart to TimeFromStart - CamearDelay)\n- one for forecasting the position (from TimeFromStart - CamearDelay to TimeFromStart - CamearDelay - ForecastHistoryDuration"},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SmoothCamera::SmoothCamera::UpdateDelayedPosition"},"parameters":["Object","Behavior",""]},{"type":{"value":"SmoothCamera::SmoothCamera::UpdateForecastedPosition"},"parameters":["Object","Behavior",""]}]},{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"At each frame, the camera must catchup the target by a given ratio (speed)\ncameraX(t) - targetX = (cameraX(t - 1) - targetX) * speed\n\nThe frame rate must not impact on the catch-up speed, we don't want a speed in ratio per frame but a speed ratio per second, like this:\ncameraX(t) - targetX = (cameraX(t - 1s) - targetX) * speed\n\nOk, but we still need to process each frame, we can use a exponent for this:\ncameraX(t) - targetX = (cameraX(t - timeDelta) - targetX) * speed^timeDelta\ncameraX(t) = targetX + (cameraX(t - timeDelta) - targetX) * exp(timeDelta * ln(speed))\n\npow is probably more efficient than precalculated log if the speed is changed continuously but this might be rare enough."},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BooleanVariable"},"parameters":["FollowOnX","True",""]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["OldX","=","CameraX(Object.Layer(), 0)"]}],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"CameraCenterX"},"parameters":["",">","Object.Behavior::FreeAreaRight()","Object.Layer()","0"]}],"actions":[{"type":{"value":"SetCameraCenterX"},"parameters":["","=","Object.Behavior::FreeAreaRight()\n+ (CameraX(Object.Layer(), 0) - Object.Behavior::FreeAreaRight())\n* exp(TimeDelta() * LogLeftwardSpeed)","Object.Layer()","0"]}],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"CameraCenterX"},"parameters":["","<","OldX - LeftwardSpeedMax * TimeDelta()","Object.Layer()","0"]}],"actions":[{"type":{"value":"SetCameraCenterX"},"parameters":["","=","OldX - LeftwardSpeedMax * TimeDelta()","Object.Layer()","0"]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"CameraCenterX"},"parameters":["","<","Object.Behavior::FreeAreaLeft()","Object.Layer()","0"]}],"actions":[{"type":{"value":"SetCameraCenterX"},"parameters":["","=","Object.Behavior::FreeAreaLeft()\n+ (CameraX(Object.Layer(), 0) - Object.Behavior::FreeAreaLeft())\n* exp(TimeDelta() * LogRightwardSpeed)","Object.Layer()","0"]}],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"CameraCenterX"},"parameters":["",">","OldX + RightwardSpeedMax * TimeDelta()","Object.Layer()","0"]}],"actions":[{"type":{"value":"SetCameraCenterX"},"parameters":["","=","OldX + RightwardSpeedMax * TimeDelta()","Object.Layer()","0"]}]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BooleanVariable"},"parameters":["FollowOnY","True",""]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["OldY","=","CameraY(Object.Layer(), 0)"]}],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"CameraCenterY"},"parameters":["",">","Object.Behavior::FreeAreaBottom()","Object.Layer()","0"]}],"actions":[{"type":{"value":"SetCameraCenterY"},"parameters":["","=","Object.Behavior::FreeAreaBottom()\n+ (CameraY(Object.Layer(), 0) - Object.Behavior::FreeAreaBottom())\n* exp(TimeDelta() * LogUpwardSpeed)","Object.Layer()","0"]}],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"CameraCenterY"},"parameters":["","<","OldY - UpwardSpeedMax * TimeDelta()","Object.Layer()","0"]}],"actions":[{"type":{"value":"SetCameraCenterY"},"parameters":["","=","OldY - UpwardSpeedMax * TimeDelta()","Object.Layer()","0"]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"CameraCenterY"},"parameters":["","<","Object.Behavior::FreeAreaTop()","Object.Layer()","0"]}],"actions":[{"type":{"value":"SetCameraCenterY"},"parameters":["","=","Object.Behavior::FreeAreaTop()\n+ (CameraY(Object.Layer(), 0) - Object.Behavior::FreeAreaTop())\n* exp(TimeDelta() * LogDownwardSpeed)","Object.Layer()","0"]}],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"CameraCenterY"},"parameters":["",">","OldY + DownwardSpeedMax * TimeDelta()","Object.Layer()","0"]}],"actions":[{"type":{"value":"SetCameraCenterY"},"parameters":["","=","OldY + DownwardSpeedMax * TimeDelta()","Object.Layer()","0"]}]}]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"description":"Delay the camera according to a maximum speed and catch up the delay.","fullName":"Wait and catch up","functionType":"Action","name":"WaitAndCatchUp","sentence":"Delay the camera of _PARAM0_ during: _PARAM2_ seconds according to the maximum speed _PARAM3_;_PARAM4_ seconds and catch up in _PARAM5_ seconds","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Maybe the catch-up show be done in constant pixel speed instead of constant time speed."},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["WaitingEnd","=","TimeFromStart() + NewWaitingDuration"]},{"type":{"value":"SetNumberVariable"},"parameters":["WaitingSpeedXMax","=","NewWaitingSpeedXMax"]},{"type":{"value":"SetNumberVariable"},"parameters":["WaitingSpeedYMax","=","NewWaitingSpeedYMax"]},{"type":{"value":"SetNumberVariable"},"parameters":["CameraDelayCatchUpDuration","=","NewCatchUpDuration"]}]},{"disabled":true,"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"DebuggerTools::ConsoleLog"},"parameters":["\"Wait and catch up\"","\"info\"","\"SmoothCamera\""]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Waiting duration (in seconds)","name":"NewWaitingDuration","type":"expression"},{"description":"Waiting maximum camera target speed X","name":"NewWaitingSpeedXMax","type":"expression"},{"description":"Waiting maximum camera target speed Y","name":"NewWaitingSpeedYMax","type":"expression"},{"description":"Catch up duration (in seconds)","name":"NewCatchUpDuration","type":"expression"}],"objectGroups":[]},{"description":"Draw the targeted and actual camera position.","fullName":"Draw debug","functionType":"Action","name":"DrawDebug","sentence":"Draw targeted and actual camera position for _PARAM0_ on _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"PrimitiveDrawing::FillOpacity"},"parameters":["ShapePainter","=","0"]}]},{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Path used by the forecasting","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BuiltinCommonInstructions::CompareNumbers"},"parameters":["Object.VariableChildCount(__SmoothCamera.ForecastHistoryTime)",">","0"]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["Index","=","0"]},{"type":{"value":"PrimitiveDrawing::OutlineColor"},"parameters":["ShapePainter","\"245;166;35\""]},{"type":{"value":"PrimitiveDrawing::BeginFillPath"},"parameters":["ShapePainter","Object.Variable(__SmoothCamera.ForecastHistoryX[0])","Object.Variable(__SmoothCamera.ForecastHistoryY[0])"]}],"events":[{"type":"BuiltinCommonInstructions::Repeat","repeatExpression":"Object.VariableChildCount(__SmoothCamera.ForecastHistoryX)","conditions":[],"actions":[{"type":{"value":"PrimitiveDrawing::PathLineTo"},"parameters":["ShapePainter","Object.Variable(__SmoothCamera.ForecastHistoryX[Index])","Object.Variable(__SmoothCamera.ForecastHistoryY[Index])"]},{"type":{"value":"SetNumberVariable"},"parameters":["Index","+","1"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"PrimitiveDrawing::EndFillPath"},"parameters":["ShapePainter"]}]}]}],"parameters":[]},{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Follow-free area.","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BuiltinCommonInstructions::Or"},"parameters":[],"subInstructions":[{"type":{"value":"NumberVariable"},"parameters":["FollowFreeAreaLeft","!=","0"]},{"type":{"value":"NumberVariable"},"parameters":["FollowFreeAreaRight","!=","0"]},{"type":{"value":"NumberVariable"},"parameters":["FollowFreeAreaTop","!=","0"]},{"type":{"value":"NumberVariable"},"parameters":["FollowFreeAreaBottom","!=","0"]}]}],"actions":[{"type":{"value":"PrimitiveDrawing::OutlineColor"},"parameters":["ShapePainter","\"126;211;33\""]},{"type":{"value":"PrimitiveDrawing::Rectangle"},"parameters":["ShapePainter","Object.Behavior::FreeAreaLeft() - 1","Object.Behavior::FreeAreaTop() - 1","Object.Behavior::FreeAreaRight() + 1","Object.Behavior::FreeAreaBottom() + 1"]}]}],"parameters":[]},{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Linear regression vector used by the forecasting.","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"PrimitiveDrawing::OutlineColor"},"parameters":["ShapePainter","\"208;2;27\""]},{"type":{"value":"PrimitiveDrawing::LineV2"},"parameters":["ShapePainter","ProjectedOldestX","ProjectedOldestY","ProjectedNewestX","ProjectedNewestY","1"]}]}],"parameters":[]},{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Targeted and actual camera position","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"PrimitiveDrawing::Circle"},"parameters":["ShapePainter","ForecastedX","ForecastedY","3"]},{"type":{"value":"PrimitiveDrawing::LineV2"},"parameters":["ShapePainter","CameraX(Object.Layer(), 0)","CameraY(Object.Layer(), 0) - 4","CameraX(Object.Layer(), 0)","CameraY(Object.Layer(), 0) + 4","1"]},{"type":{"value":"PrimitiveDrawing::LineV2"},"parameters":["ShapePainter","CameraX(Object.Layer(), 0) - 4","CameraY(Object.Layer(), 0)","CameraX(Object.Layer(), 0) + 4","CameraY(Object.Layer(), 0)","1"]}]}],"parameters":[]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Shape painter","name":"ShapePainter","supplementaryInformation":"PrimitiveDrawing::Drawer","type":"objectList"}],"objectGroups":[]},{"description":"Enable or disable the following on X axis.","fullName":"Follow on X","functionType":"Action","group":"Camera configuration","name":"SetFollowOnX","sentence":"The camera follows _PARAM0_ on X axis: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetBooleanVariable"},"parameters":["FollowOnX","False",""]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BooleanVariable"},"parameters":["Value","True",""]}],"actions":[{"type":{"value":"SetBooleanVariable"},"parameters":["FollowOnX","True",""]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Follow on X axis","name":"Value","type":"yesorno"}],"objectGroups":[]},{"description":"Enable or disable the following on Y axis.","fullName":"Follow on Y","functionType":"Action","group":"Camera configuration","name":"SetFollowOnY","sentence":"The camera follows _PARAM0_ on Y axis: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetBooleanVariable"},"parameters":["FollowOnY","False",""]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BooleanVariable"},"parameters":["Value","True",""]}],"actions":[{"type":{"value":"SetBooleanVariable"},"parameters":["FollowOnY","True",""]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Follow on Y axis","name":"Value","type":"yesorno"}],"objectGroups":[]},{"description":"Change the camera follow free area right border.","fullName":"Follow free area right border","functionType":"Action","group":"Camera configuration","name":"SetFollowFreeAreaRight","sentence":"Change the camera follow free area right border of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["FollowFreeAreaRight","=","max(0, Value)"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Follow free area right border","name":"Value","type":"expression"}],"objectGroups":[]},{"description":"Change the camera follow free area left border.","fullName":"Follow free area left border","functionType":"Action","group":"Camera configuration","name":"SetFollowFreeAreaLeft","sentence":"Change the camera follow free area left border of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["FollowFreeAreaLeft","=","max(0, Value)"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Follow free area left border","name":"Value","type":"expression"}],"objectGroups":[]},{"description":"Change the camera follow free area top border.","fullName":"Follow free area top border","functionType":"Action","group":"Camera configuration","name":"SetFollowFreeAreaTop","sentence":"Change the camera follow free area top border of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["FollowFreeAreaTop","=","max(0, Value)"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Follow free area top border","name":"Value","type":"expression"}],"objectGroups":[]},{"description":"Change the camera follow free area bottom border.","fullName":"Follow free area bottom border","functionType":"Action","group":"Camera configuration","name":"SetFollowFreeAreaBottom","sentence":"Change the camera follow free area bottom border of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["FollowFreeAreaBottom","=","max(0, Value)"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Follow free area bottom border","name":"Value","type":"expression"}],"objectGroups":[]},{"description":"Change the camera leftward maximum speed (in pixels per second).","fullName":"Leftward maximum speed","functionType":"Action","group":"Camera configuration","name":"SetLeftwardSpeedMax","sentence":"Change the camera leftward maximum speed of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["LeftwardSpeedMax","=","max(0, Value)"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Leftward maximum speed (in pixels per second)","name":"Value","type":"expression"}],"objectGroups":[]},{"description":"Change the camera rightward maximum speed (in pixels per second).","fullName":"Rightward maximum speed","functionType":"Action","group":"Camera configuration","name":"SetRightwardSpeedMax","sentence":"Change the camera rightward maximum speed of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["RightwardSpeedMax","=","max(0, Value)"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Rightward maximum speed (in pixels per second)","name":"Value","type":"expression"}],"objectGroups":[]},{"description":"Change the camera upward maximum speed (in pixels per second).","fullName":"Upward maximum speed","functionType":"Action","group":"Camera configuration","name":"SetUpwardSpeedMax","sentence":"Change the camera upward maximum speed of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["UpwardSpeedMax","=","max(0, Value)"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Upward maximum speed (in pixels per second)","name":"Value","type":"expression"}],"objectGroups":[]},{"description":"Change the camera downward maximum speed (in pixels per second).","fullName":"Downward maximum speed","functionType":"Action","group":"Camera configuration","name":"SetDownwardSpeedMax","sentence":"Change the camera downward maximum speed of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["DownwardSpeedMax","=","max(0, Value)"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Downward maximum speed (in pixels per second)","name":"Value","type":"expression"}],"objectGroups":[]},{"description":"Change the camera leftward catch-up speed (in ratio per second).","fullName":"Leftward catch-up speed","functionType":"Action","group":"Camera configuration","name":"SetLeftwardSpeed","sentence":"Change the camera leftward catch-up speed of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["LeftwardSpeed","=","clamp(0, 1, Value)"]},{"type":{"value":"SetNumberVariable"},"parameters":["LogLeftwardSpeed","=","log(1 - Value)"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Leftward catch-up speed (in ratio per second)","name":"Value","type":"expression"}],"objectGroups":[]},{"description":"Change the camera rightward catch-up speed (in ratio per second).","fullName":"Rightward catch-up speed","functionType":"Action","group":"Camera configuration","name":"SetRightwardSpeed","sentence":"Change the camera rightward catch-up speed of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["RightwardSpeed","=","clamp(0, 1, Value)"]},{"type":{"value":"SetNumberVariable"},"parameters":["LogRightwardSpeed","=","log(1 - Value)"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Rightward catch-up speed (in ratio per second)","name":"Value","type":"expression"}],"objectGroups":[]},{"description":"Change the camera downward catch-up speed (in ratio per second).","fullName":"Downward catch-up speed","functionType":"Action","group":"Camera configuration","name":"SetDownwardSpeed","sentence":"Change the camera downward catch-up speed of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["DownwardSpeed","=","clamp(0, 1, Value)"]},{"type":{"value":"SetNumberVariable"},"parameters":["LogDownwardSpeed","=","log(1 - Value)"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Downward catch-up speed (in ratio per second)","name":"Value","type":"expression"}],"objectGroups":[]},{"description":"Change the camera upward catch-up speed (in ratio per second).","fullName":"Upward catch-up speed","functionType":"Action","group":"Camera configuration","name":"SetUpwardSpeed","sentence":"Change the camera upward catch-up speed of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["UpwardSpeed","=","clamp(0, 1, Value)"]},{"type":{"value":"SetNumberVariable"},"parameters":["LogUpwardSpeed","=","log(1 - Value)"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Upward catch-up speed (in ratio per second)","name":"Value","type":"expression"}],"objectGroups":[]},{"description":"the camera offset on X axis of the object. This is not the current difference between the object and the camera position.","fullName":"Camera offset X","functionType":"ExpressionAndCondition","group":"Camera configuration","name":"OffsetX","sentence":"the camera offset on X axis","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["CameraOffsetX"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"fullName":"","functionType":"ActionWithOperator","getterName":"OffsetX","group":"Camera configuration","name":"SetOffsetXOp","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["CameraOffsetX","=","Value"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"description":"Change the camera offset on X axis of an object.","fullName":"Camera Offset X","functionType":"Action","group":"Camera configuration","name":"SetOffsetX","private":true,"sentence":"Change the camera offset on X axis of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Deprecated use SetOffsetXOp instead."},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SmoothCamera::SmoothCamera::SetOffsetXOp"},"parameters":["Object","Behavior","=","Value",""]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Camera offset X","name":"Value","type":"expression"}],"objectGroups":[]},{"description":"the camera offset on Y axis of the object. This is not the current difference between the object and the camera position.","fullName":"Camera offset Y","functionType":"ExpressionAndCondition","group":"Camera configuration","name":"OffsetY","sentence":"the camera offset on Y axis","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["CameraOffsetY"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"fullName":"","functionType":"ActionWithOperator","getterName":"OffsetY","group":"Camera configuration","name":"SetOffsetYOp","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["CameraOffsetY","=","Value"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"description":"Change the camera offset on Y axis of an object.","fullName":"Camera Offset Y","functionType":"Action","group":"Camera configuration","name":"SetOffsetY","private":true,"sentence":"Change the camera offset on Y axis of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Deprecated use SetOffsetYOp instead."},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SmoothCamera::SmoothCamera::SetOffsetYOp"},"parameters":["Object","Behavior","=","CameraOffsetY",""]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Camera offset Y","name":"CameraOffsetY","type":"expression"}],"objectGroups":[]},{"description":"Change the camera forecast time (in seconds).","fullName":"Forecast time","functionType":"Action","group":"Camera configuration","name":"SetForecastTime","sentence":"Change the camera forecast time of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ForecastTime","=","min(0, Value)"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Forecast time","name":"Value","type":"expression"}],"objectGroups":[]},{"description":"Change the camera delay (in seconds).","fullName":"Camera delay","functionType":"Action","group":"Camera configuration","name":"SetCameraDelay","sentence":"Change the camera delay of _PARAM0_: _PARAM2_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["CameraDelay","=","max(0, Value)"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Camera delay","name":"Value","type":"expression"}],"objectGroups":[]},{"description":"Return follow free area left border X.","fullName":"Free area left","functionType":"Expression","group":"Private","name":"FreeAreaLeft","private":true,"sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["ForecastedX + CameraOffsetX - FollowFreeAreaLeft"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"description":"Return follow free area right border X.","fullName":"Free area right","functionType":"Expression","group":"Private","name":"FreeAreaRight","private":true,"sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["ForecastedX + CameraOffsetX + FollowFreeAreaRight"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"description":"Return follow free area bottom border Y.","fullName":"Free area bottom","functionType":"Expression","group":"Private","name":"FreeAreaBottom","private":true,"sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["ForecastedY + CameraOffsetY + FollowFreeAreaBottom"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"description":"Return follow free area top border Y.","fullName":"Free area top","functionType":"Expression","group":"Private","name":"FreeAreaTop","private":true,"sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["ForecastedY + CameraOffsetY - FollowFreeAreaTop"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"description":"Update delayed position and delayed history. This is called in doStepPreEvents.","fullName":"Update delayed position","functionType":"Action","group":"Private","name":"UpdateDelayedPosition","private":true,"sentence":"Update delayed position and delayed history of _PARAM0_","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Add the previous position to have enough (2) positions to evaluate the extra delay for waiting mode."},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"SmoothCamera::SmoothCamera::IsWaiting"},"parameters":["Object","Behavior",""]},{"type":{"value":"BuiltinCommonInstructions::CompareNumbers"},"parameters":["Object.VariableChildCount(__SmoothCamera.ObjectTime)","=","0"]}],"actions":[{"type":{"value":"ObjectVariablePushNumber"},"parameters":["Object","__SmoothCamera.ObjectTime","TimeFromStart()"]},{"type":{"value":"ObjectVariablePushNumber"},"parameters":["Object","__SmoothCamera.ObjectX","DelayedCenterX"]},{"type":{"value":"ObjectVariablePushNumber"},"parameters":["Object","__SmoothCamera.ObjectY","DelayedCenterY"]}]},{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Use the object center when no delay is asked."},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["DelayedCenterX","=","Object.CenterX()"]},{"type":{"value":"SetNumberVariable"},"parameters":["DelayedCenterY","=","Object.CenterY()"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"inverted":true,"value":"SmoothCamera::SmoothCamera::IsDelayed"},"parameters":["Object","Behavior",""]}],"actions":[{"type":{"value":"SmoothCamera::SmoothCamera::AddForecastHistoryPosition"},"parameters":["Object","Behavior","TimeFromStart()","Object.CenterX()","Object.CenterY()",""]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BuiltinCommonInstructions::Or"},"parameters":[],"subInstructions":[{"type":{"value":"SmoothCamera::SmoothCamera::IsDelayed"},"parameters":["Object","Behavior",""]},{"type":{"value":"SmoothCamera::SmoothCamera::IsWaiting"},"parameters":["Object","Behavior",""]}]}],"actions":[{"type":{"value":"ObjectVariablePushNumber"},"parameters":["Object","__SmoothCamera.ObjectTime","TimeFromStart()"]},{"type":{"value":"ObjectVariablePushNumber"},"parameters":["Object","__SmoothCamera.ObjectX","Object.CenterX()"]},{"type":{"value":"ObjectVariablePushNumber"},"parameters":["Object","__SmoothCamera.ObjectY","Object.CenterY()"]}],"events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Remove history entries that are too old to be useful for delaying and pass it to the history for forecasting."},{"infiniteLoopWarning":true,"type":"BuiltinCommonInstructions::While","whileConditions":[{"type":{"value":"BuiltinCommonInstructions::CompareNumbers"},"parameters":["Object.VariableChildCount(__SmoothCamera.ObjectTime)",">=","2"]},{"type":{"value":"VarObjet"},"parameters":["Object","__SmoothCamera.ObjectTime[1]","<","TimeFromStart() - Object.Behavior::CurrentDelay()"]}],"conditions":[],"actions":[{"type":{"value":"SmoothCamera::SmoothCamera::AddForecastHistoryPosition"},"parameters":["Object","Behavior","Object.Variable(__SmoothCamera.ObjectTime[0])","Object.Variable(__SmoothCamera.ObjectX[0])","Object.Variable(__SmoothCamera.ObjectY[0])",""]},{"type":{"value":"ObjectVariableRemoveAt"},"parameters":["Object","__SmoothCamera.ObjectTime","0"]},{"type":{"value":"ObjectVariableRemoveAt"},"parameters":["Object","__SmoothCamera.ObjectX","0"]},{"type":{"value":"ObjectVariableRemoveAt"},"parameters":["Object","__SmoothCamera.ObjectY","0"]}]},{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Don't move the camera if there is not enough history."},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["DelayedCenterX","=","Object.Variable(__SmoothCamera.ObjectX[0])"]},{"type":{"value":"SetNumberVariable"},"parameters":["DelayedCenterY","=","Object.Variable(__SmoothCamera.ObjectY[0])"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BuiltinCommonInstructions::CompareNumbers"},"parameters":["Object.VariableChildCount(__SmoothCamera.ObjectTime)",">=","2"]},{"type":{"value":"VarObjet"},"parameters":["Object","__SmoothCamera.ObjectTime[0]","<","TimeFromStart() - Object.Behavior::CurrentDelay()"]}],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Add the extra delay that could be needed to respect the speed limit in waiting mode.\n\nspeedRatio = min(speedMaxX / historySpeedX, speedMaxY / historySpeedY)\ndelay += min(0, timeDelta * (1 - speedRatio))"},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"SmoothCamera::SmoothCamera::IsWaiting"},"parameters":["Object","Behavior",""]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["CameraExtraDelay","+","max(0, TimeDelta() * (1 - min(WaitingSpeedXMax * abs(Object.Variable(__SmoothCamera.ObjectX[1]) - Object.Variable(__SmoothCamera.ObjectX[0])), WaitingSpeedYMax * abs(Object.Variable(__SmoothCamera.ObjectY[1]) - Object.Variable(__SmoothCamera.ObjectY[0]))) / (Object.Variable(__SmoothCamera.ObjectTime[1]) - Object.Variable(__SmoothCamera.ObjectTime[0]))))"]}],"events":[{"disabled":true,"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"DebuggerTools::ConsoleLog"},"parameters":["\"Extra delay: \" + ToString(CameraExtraDelay)","\"info\"","\"SmoothCamera\""]}]}]},{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"The time with delay is now between the first 2 indexes"},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["DelayedCenterX","=","lerp(Object.Variable(__SmoothCamera.ObjectX[1]), Object.Variable(__SmoothCamera.ObjectX[0]), ((TimeFromStart() - Object.Behavior::CurrentDelay()) - Object.Variable(__SmoothCamera.ObjectTime[1])) / (Object.Variable(__SmoothCamera.ObjectTime[0]) - Object.Variable(__SmoothCamera.ObjectTime[1])))"]},{"type":{"value":"SetNumberVariable"},"parameters":["DelayedCenterY","=","lerp(Object.Variable(__SmoothCamera.ObjectY[1]), Object.Variable(__SmoothCamera.ObjectY[0]), ((TimeFromStart() - Object.Behavior::CurrentDelay()) - Object.Variable(__SmoothCamera.ObjectTime[1])) / (Object.Variable(__SmoothCamera.ObjectTime[0]) - Object.Variable(__SmoothCamera.ObjectTime[1])))"]}]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"inverted":true,"value":"SmoothCamera::SmoothCamera::IsDelayed"},"parameters":["Object","Behavior",""]},{"type":{"inverted":true,"value":"SmoothCamera::SmoothCamera::IsWaiting"},"parameters":["Object","Behavior",""]}],"actions":[{"type":{"value":"ObjectVariableClearChildren"},"parameters":["Object","__SmoothCamera.ObjectTime"]},{"type":{"value":"ObjectVariableClearChildren"},"parameters":["Object","__SmoothCamera.ObjectX"]},{"type":{"value":"ObjectVariableClearChildren"},"parameters":["Object","__SmoothCamera.ObjectY"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"inverted":true,"value":"SmoothCamera::SmoothCamera::IsWaiting"},"parameters":["Object","Behavior",""]},{"type":{"value":"BuiltinCommonInstructions::Once"},"parameters":[]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["CameraDelayCatchUpSpeed","=","CameraExtraDelay / CameraDelayCatchUpDuration"]}],"events":[{"disabled":true,"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"DebuggerTools::ConsoleLog"},"parameters":["\"Start to catch up\"","\"info\"","\"SmoothCamera\""]}]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"inverted":true,"value":"SmoothCamera::SmoothCamera::IsWaiting"},"parameters":["Object","Behavior",""]},{"type":{"value":"NumberVariable"},"parameters":["CameraExtraDelay",">","0"]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["CameraExtraDelay","=","max(0, CameraExtraDelay -CameraDelayCatchUpSpeed * TimeDelta())"]}],"events":[{"disabled":true,"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"DebuggerTools::ConsoleLog"},"parameters":["\"Catching up delay: \" + ToString(CameraExtraDelay)","\"info\"","\"SmoothCamera\""]}]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"description":"Check if the camera following target is delayed from the object.","fullName":"Camera is delayed","functionType":"Condition","name":"IsDelayed","private":true,"sentence":"The camera of _PARAM0_ is delayed","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BuiltinCommonInstructions::CompareNumbers"},"parameters":["Object.Behavior::CurrentDelay()",">","0"]}],"actions":[{"type":{"value":"SetReturnBoolean"},"parameters":["True"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"description":"Return the current camera delay.","fullName":"Current delay","functionType":"Expression","name":"CurrentDelay","private":true,"sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["CameraDelay + CameraExtraDelay"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"description":"Check if the camera following is waiting at a reduced speed.","fullName":"Camera is waiting","functionType":"Condition","name":"IsWaiting","private":true,"sentence":"The camera of _PARAM0_ is waiting","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"NumberVariable"},"parameters":["WaitingEnd",">","TimeFromStart()"]}],"actions":[{"type":{"value":"SetReturnBoolean"},"parameters":["True"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"description":"Add a position to the history for forecasting. This is called 2 times in UpadteDelayedPosition.","fullName":"Add forecast history position","functionType":"Action","group":"Private","name":"AddForecastHistoryPosition","private":true,"sentence":"Add the time:_PARAM2_ and position: _PARAM3_; _PARAM4_ to the forecast history of _PARAM0_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BuiltinCommonInstructions::Or"},"parameters":[],"subInstructions":[{"type":{"value":"NumberVariable"},"parameters":["ForecastHistoryDuration",">","0"]},{"type":{"value":"NumberVariable"},"parameters":["ForecastTime",">","0"]}]}],"actions":[{"type":{"value":"ObjectVariablePushNumber"},"parameters":["Object","__SmoothCamera.ForecastHistoryTime","Time"]},{"type":{"value":"ObjectVariablePushNumber"},"parameters":["Object","__SmoothCamera.ForecastHistoryX","ObjectX"]},{"type":{"value":"ObjectVariablePushNumber"},"parameters":["Object","__SmoothCamera.ForecastHistoryY","ObjectY"]}],"events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Remove history entries that are too old to be useful.\nKeep at least 2 positions because no forecast can be done with less positions."},{"infiniteLoopWarning":true,"type":"BuiltinCommonInstructions::While","whileConditions":[{"type":{"value":"BuiltinCommonInstructions::CompareNumbers"},"parameters":["Object.VariableChildCount(__SmoothCamera.ForecastHistoryTime)",">=","3"]},{"type":{"value":"VarObjet"},"parameters":["Object","__SmoothCamera.ForecastHistoryTime[0]","<","TimeFromStart() - CameraDelay - CameraExtraDelay - ForecastHistoryDuration"]}],"conditions":[],"actions":[{"type":{"value":"ObjectVariableRemoveAt"},"parameters":["Object","__SmoothCamera.ForecastHistoryTime","0"]},{"type":{"value":"ObjectVariableRemoveAt"},"parameters":["Object","__SmoothCamera.ForecastHistoryX","0"]},{"type":{"value":"ObjectVariableRemoveAt"},"parameters":["Object","__SmoothCamera.ForecastHistoryY","0"]}]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"Time","name":"Time","type":"expression"},{"description":"Object X","name":"ObjectX","type":"expression"},{"description":"Object Y","name":"ObjectY","type":"expression"}],"objectGroups":[]},{"description":"Update forecasted position. This is called in doStepPreEvents.","fullName":"Update forecasted position","functionType":"Action","group":"Private","name":"UpdateForecastedPosition","private":true,"sentence":"Update forecasted position of _PARAM0_","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ForecastedX","=","DelayedCenterX"]},{"type":{"value":"SetNumberVariable"},"parameters":["ForecastedY","=","DelayedCenterY"]}]},{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Simple linear regression\ny = A * x + B\n\nA = Covariance / VarianceX\nB = MeanY - A * MeanX\n\nNote than we could use only one position every N positions to reduce the process time,\nbut if we really need efficient process JavaScript and circular queues are a must."},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BuiltinCommonInstructions::CompareNumbers"},"parameters":["Object.VariableChildCount(__SmoothCamera.ForecastHistoryTime)",">=","2"]},{"type":{"value":"BuiltinCommonInstructions::Or"},"parameters":[],"subInstructions":[{"type":{"value":"NumberVariable"},"parameters":["ForecastHistoryDuration",">","0"]},{"type":{"value":"NumberVariable"},"parameters":["ForecastTime",">","0"]}]}],"actions":[],"events":[{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Mean X","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryMeanX","=","0"]},{"type":{"value":"SetNumberVariable"},"parameters":["Index","=","0"]}]},{"type":"BuiltinCommonInstructions::Repeat","repeatExpression":"Object.VariableChildCount(__SmoothCamera.ForecastHistoryX)","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryMeanX","+","Object.Variable(__SmoothCamera.ForecastHistoryX[Index])"]},{"type":{"value":"SetNumberVariable"},"parameters":["Index","+","1"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryMeanX","/","Object.VariableChildCount(__SmoothCamera.ForecastHistoryX)"]}]}],"parameters":[]},{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Mean Y","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryMeanY","=","0"]},{"type":{"value":"SetNumberVariable"},"parameters":["Index","=","0"]}]},{"type":"BuiltinCommonInstructions::Repeat","repeatExpression":"Object.VariableChildCount(__SmoothCamera.ForecastHistoryY)","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryMeanY","+","Object.Variable(__SmoothCamera.ForecastHistoryY[Index])"]},{"type":{"value":"SetNumberVariable"},"parameters":["Index","+","1"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryMeanY","/","Object.VariableChildCount(__SmoothCamera.ForecastHistoryY)"]}]},{"disabled":true,"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"DebuggerTools::ConsoleLog"},"parameters":["\"Mean: \" + ToString(ForecastHistoryMeanX) + \" \" + ToString(ForecastHistoryMeanY)","",""]}]}],"parameters":[]},{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Variance and Covariance","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"VarianceX = sum((X[i] - MeanX)²)\nVarianceY = sum((Y[i] - MeanY)²)\nCovariance = sum((X[i] - MeanX) * (Y[i] - MeanY))"},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryVarianceX","=","0"]},{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryVarianceY","=","0"]},{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryCovariance","=","0"]},{"type":{"value":"SetNumberVariable"},"parameters":["Index","=","0"]}]},{"type":"BuiltinCommonInstructions::Repeat","repeatExpression":"Object.VariableChildCount(__SmoothCamera.ForecastHistoryX)","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryVarianceX","+","pow(Object.Variable(__SmoothCamera.ForecastHistoryX[Index]) - ForecastHistoryMeanX, 2)"]},{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryVarianceY","+","pow(Object.Variable(__SmoothCamera.ForecastHistoryY[Index]) - ForecastHistoryMeanY, 2)"]},{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryCovariance","+","(Object.Variable(__SmoothCamera.ForecastHistoryX[Index]) - ForecastHistoryMeanX)\n*\n(Object.Variable(__SmoothCamera.ForecastHistoryY[Index]) - ForecastHistoryMeanY)"]},{"type":{"value":"SetNumberVariable"},"parameters":["Index","+","1"]}]},{"disabled":true,"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"DebuggerTools::ConsoleLog"},"parameters":["\"Variances: \" + ToString(ForecastHistoryVarianceX) + \" \" + ToString(ForecastHistoryVarianceY) + \" \" + ToString(ForecastHistoryCovariance)","\"info\"","\"SmoothCamera\""]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BuiltinCommonInstructions::CompareNumbers"},"parameters":["abs(ForecastHistoryVarianceX)","<","1"]},{"type":{"value":"BuiltinCommonInstructions::CompareNumbers"},"parameters":["abs(ForecastHistoryVarianceY)","<","1"]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ForecastedX","=","DelayedCenterX"]},{"type":{"value":"SetNumberVariable"},"parameters":["ForecastedY","=","DelayedCenterY"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BuiltinCommonInstructions::Or"},"parameters":[],"subInstructions":[{"type":{"value":"BuiltinCommonInstructions::CompareNumbers"},"parameters":["abs(ForecastHistoryVarianceX)",">=","1"]},{"type":{"value":"BuiltinCommonInstructions::CompareNumbers"},"parameters":["abs(ForecastHistoryVarianceY)",">=","1"]}]}],"actions":[],"events":[{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Linear function parameters","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"y = A * x + B\n\nA = Covariance / VarianceX\nB = MeanY - A * MeanX"},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BuiltinCommonInstructions::CompareNumbers"},"parameters":["abs(ForecastHistoryVarianceX)",">=","abs(ForecastHistoryVarianceY)"]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryLinearA","=","ForecastHistoryCovariance / ForecastHistoryVarianceX"]},{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryLinearB","=","ForecastHistoryMeanY - ForecastHistoryLinearA * ForecastHistoryMeanX"]}],"events":[{"disabled":true,"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"DebuggerTools::ConsoleLog"},"parameters":["\"Linear: \" + ToString(ForecastHistoryLinearA) + \" \" + ToString(ForecastHistoryLinearB)","\"info\"","\"SmoothCamera\""]}]},{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Projection","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SmoothCamera::SmoothCamera::ProjectHistoryEnds"},"parameters":["Object","Behavior","Object.Variable(__SmoothCamera.ForecastHistoryX[0])","Object.Variable(__SmoothCamera.ForecastHistoryY[0])","Object.Variable(__SmoothCamera.ForecastHistoryX[Object.VariableChildCount(__SmoothCamera.ForecastHistoryX) - 1])","Object.Variable(__SmoothCamera.ForecastHistoryY[Object.VariableChildCount(__SmoothCamera.ForecastHistoryY) - 1])",""]}]}],"parameters":[]}]},{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Axis permutation to avoid a ratio between 2 numbers near 0."},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BuiltinCommonInstructions::CompareNumbers"},"parameters":["abs(ForecastHistoryVarianceX)","<","abs(ForecastHistoryVarianceY)"]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryLinearA","=","ForecastHistoryCovariance / ForecastHistoryVarianceY"]},{"type":{"value":"SetNumberVariable"},"parameters":["ForecastHistoryLinearB","=","ForecastHistoryMeanX - ForecastHistoryLinearA * ForecastHistoryMeanY"]}],"events":[{"disabled":true,"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"DebuggerTools::ConsoleLog"},"parameters":["\"Linear: \" + ToString(ForecastHistoryLinearA) + \" \" + ToString(ForecastHistoryLinearB)","\"info\"","\"SmoothCamera\""]}]},{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Projection","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SmoothCamera::SmoothCamera::ProjectHistoryEnds"},"parameters":["Object","Behavior","Object.Variable(__SmoothCamera.ForecastHistoryY[0])","Object.Variable(__SmoothCamera.ForecastHistoryX[0])","Object.Variable(__SmoothCamera.ForecastHistoryY[Object.VariableChildCount(__SmoothCamera.ForecastHistoryY) - 1])","Object.Variable(__SmoothCamera.ForecastHistoryX[Object.VariableChildCount(__SmoothCamera.ForecastHistoryX) - 1])",""]}]},{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Permute back axis"},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["Index","=","ProjectedOldestX"]},{"type":{"value":"SetNumberVariable"},"parameters":["ProjectedOldestX","=","ProjectedOldestY"]},{"type":{"value":"SetNumberVariable"},"parameters":["ProjectedOldestY","=","Index"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["Index","=","ProjectedNewestX"]},{"type":{"value":"SetNumberVariable"},"parameters":["ProjectedNewestX","=","ProjectedNewestY"]},{"type":{"value":"SetNumberVariable"},"parameters":["ProjectedNewestY","=","Index"]}]}],"parameters":[]},{"disabled":true,"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"DebuggerTools::ConsoleLog"},"parameters":["\"Oldest: \" + ToString(ProjectedOldestX) + \" \" + ToString(ProjectedOldestY)","\"info\"","\"SmoothCamera\""]}]},{"disabled":true,"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"DebuggerTools::ConsoleLog"},"parameters":["\"Newest: \" + ToString(ProjectedNewestX) + \" \" + ToString(ProjectedNewestY)","\"info\"","\"SmoothCamera\""]}]}]},{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Forecasted position","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ForecastedX","=","ProjectedNewestX + ( ProjectedNewestX - ProjectedOldestX) * Object.Behavior::ForecastTimeRatio()"]},{"type":{"value":"SetNumberVariable"},"parameters":["ForecastedY","=","ProjectedNewestY + ( ProjectedNewestY - ProjectedOldestY) * Object.Behavior::ForecastTimeRatio()"]}]},{"disabled":true,"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"DebuggerTools::ConsoleLog"},"parameters":["\"Forecasted: \" + ToString(ForecastedX) + \" \" + ToString(ForecastedY)","\"info\"","\"SmoothCamera\""]}]}],"parameters":[]}],"parameters":[]}]}],"parameters":[]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]},{"description":"Project history ends position to have the vector on the line from linear regression. This function is only called by UpdateForecastedPosition.","fullName":"Project history ends","functionType":"Action","group":"Private","name":"ProjectHistoryEnds","private":true,"sentence":"Project history oldest: _PARAM2_;_PARAM3_ and newest position: _PARAM4_;_PARAM5_ of _PARAM0_","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Perpendicular line:\npA = -1/a; \npB = -pA * x + y\n\nIntersection:\n/ ProjectedY = a * ProjectedX + b\n\\ ProjectedY = pA * ProjectedX + b\n\nSolution that is cleaned out from indeterminism (like 0 / 0 or infinity / infinity):\nProjectedX= (x + (y - b) * a) / (a² + 1)\nProjectedY = y + (x * a - y + b) / (a² + 1)"},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ProjectedNewestX","=","(NewestX + (NewestY - ForecastHistoryLinearB) * ForecastHistoryLinearA) / (1 + pow(ForecastHistoryLinearA, 2))"]},{"type":{"value":"SetNumberVariable"},"parameters":["ProjectedNewestY","=","NewestY + (NewestX * ForecastHistoryLinearA - NewestY \n+ ForecastHistoryLinearB) / (1 + pow(ForecastHistoryLinearA, 2))"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["ProjectedOldestX","=","(OldestX + (OldestY - ForecastHistoryLinearB) * ForecastHistoryLinearA) / (1 + pow(ForecastHistoryLinearA, 2))"]},{"type":{"value":"SetNumberVariable"},"parameters":["ProjectedOldestY","=","OldestY + (OldestX * ForecastHistoryLinearA - OldestY \n+ ForecastHistoryLinearB) / (1 + pow(ForecastHistoryLinearA, 2))"]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"},{"description":"OldestX","name":"OldestX","type":"expression"},{"description":"OldestY","name":"OldestY","type":"expression"},{"description":"Newest X","name":"NewestX","type":"expression"},{"description":"Newest Y","name":"NewestY","type":"expression"}],"objectGroups":[]},{"description":"Return the ratio between forecast time and the duration of the history. This function is only called by UpdateForecastedPosition.","fullName":"Forecast time ratio","functionType":"Expression","group":"Private","name":"ForecastTimeRatio","private":true,"sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetReturnNumber"},"parameters":["- ForecastTime / (Object.Variable(__SmoothCamera.ForecastHistoryTime[0]) - Object.Variable(__SmoothCamera.ForecastHistoryTime[Object.VariableChildCount(__SmoothCamera.ForecastHistoryTime) - 1]))"]}]}],"expressionType":{"type":"expression"},"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothCamera","type":"behavior"}],"objectGroups":[]}],"eventsFunctionsFolderStructure":{"folderName":"__ROOT","children":[{"functionName":"onCreated"},{"functionName":"doStepPreEvents"},{"functionName":"MoveCameraCloser"},{"functionName":"DoMoveCameraCloser"},{"functionName":"WaitAndCatchUp"},{"functionName":"DrawDebug"},{"folderName":"Camera configuration","children":[{"functionName":"SetFollowOnX"},{"functionName":"SetFollowOnY"},{"functionName":"SetFollowFreeAreaRight"},{"functionName":"SetFollowFreeAreaLeft"},{"functionName":"SetFollowFreeAreaTop"},{"functionName":"SetFollowFreeAreaBottom"},{"functionName":"SetLeftwardSpeedMax"},{"functionName":"SetRightwardSpeedMax"},{"functionName":"SetUpwardSpeedMax"},{"functionName":"SetDownwardSpeedMax"},{"functionName":"SetLeftwardSpeed"},{"functionName":"SetRightwardSpeed"},{"functionName":"SetDownwardSpeed"},{"functionName":"SetUpwardSpeed"},{"functionName":"OffsetX"},{"functionName":"SetOffsetXOp"},{"functionName":"SetOffsetX"},{"functionName":"OffsetY"},{"functionName":"SetOffsetYOp"},{"functionName":"SetOffsetY"},{"functionName":"SetForecastTime"},{"functionName":"SetCameraDelay"}]},{"folderName":"Private","children":[{"functionName":"FreeAreaLeft"},{"functionName":"FreeAreaRight"},{"functionName":"FreeAreaBottom"},{"functionName":"FreeAreaTop"},{"functionName":"UpdateDelayedPosition"},{"functionName":"AddForecastHistoryPosition"},{"functionName":"UpdateForecastedPosition"},{"functionName":"ProjectHistoryEnds"},{"functionName":"ForecastTimeRatio"}]},{"functionName":"IsDelayed"},{"functionName":"CurrentDelay"},{"functionName":"IsWaiting"}]},"propertyDescriptors":[{"value":"0.9","type":"Number","label":"Leftward catch-up speed (in ratio per second)","group":"Catch-up speed","name":"LeftwardSpeed"},{"value":"0.9","type":"Number","label":"Rightward catch-up speed (in ratio per second)","group":"Catch-up speed","name":"RightwardSpeed"},{"value":"0.9","type":"Number","label":"Upward catch-up speed (in ratio per second)","group":"Catch-up speed","name":"UpwardSpeed"},{"value":"0.9","type":"Number","label":"Downward catch-up speed (in ratio per second)","group":"Catch-up speed","name":"DownwardSpeed"},{"value":"true","type":"Boolean","label":"Follow on X axis","name":"FollowOnX"},{"value":"true","type":"Boolean","label":"Follow on Y axis","name":"FollowOnY"},{"value":"0","type":"Number","unit":"Pixel","label":"Follow free area left border","group":"Position","advanced":true,"name":"FollowFreeAreaLeft"},{"value":"0","type":"Number","unit":"Pixel","label":"Follow free area right border","group":"Position","advanced":true,"name":"FollowFreeAreaRight"},{"value":"0","type":"Number","unit":"Pixel","label":"Follow free area top border","group":"Position","advanced":true,"name":"FollowFreeAreaTop"},{"value":"0","type":"Number","unit":"Pixel","label":"Follow free area bottom border","group":"Position","advanced":true,"name":"FollowFreeAreaBottom"},{"value":"0","type":"Number","unit":"Pixel","label":"Camera offset X","group":"Position","advanced":true,"name":"CameraOffsetX"},{"value":"0","type":"Number","unit":"Pixel","label":"Camera offset Y","group":"Position","advanced":true,"name":"CameraOffsetY"},{"value":"0","type":"Number","unit":"Second","label":"Camera delay","group":"Timing","deprecated":true,"name":"CameraDelay"},{"value":"0","type":"Number","unit":"Second","label":"Forecast time","group":"Timing","deprecated":true,"name":"ForecastTime"},{"value":"0","type":"Number","unit":"Second","label":"Forecast history duration","group":"Timing","deprecated":true,"name":"ForecastHistoryDuration"},{"value":"","type":"Number","label":"","hidden":true,"name":"LogLeftwardSpeed"},{"value":"","type":"Number","label":"","hidden":true,"name":"LogRightwardSpeed"},{"value":"","type":"Number","label":"","hidden":true,"name":"LogDownwardSpeed"},{"value":"","type":"Number","label":"","hidden":true,"name":"LogUpwardSpeed"},{"value":"","type":"Number","label":"","hidden":true,"name":"DelayedCenterX"},{"value":"","type":"Number","label":"","hidden":true,"name":"DelayedCenterY"},{"value":"","type":"Number","label":"","hidden":true,"name":"ForecastHistoryMeanX"},{"value":"","type":"Number","label":"","hidden":true,"name":"ForecastHistoryMeanY"},{"value":"","type":"Number","label":"","hidden":true,"name":"ForecastHistoryVarianceX"},{"value":"","type":"Number","label":"","hidden":true,"name":"ForecastHistoryCovariance"},{"value":"","type":"Number","label":"","hidden":true,"name":"ForecastHistoryLinearA"},{"value":"","type":"Number","label":"","hidden":true,"name":"ForecastHistoryLinearB"},{"value":"","type":"Number","label":"","hidden":true,"name":"ForecastedX"},{"value":"","type":"Number","label":"","hidden":true,"name":"ForecastedY"},{"value":"","type":"Number","label":"","hidden":true,"name":"ProjectedNewestX"},{"value":"","type":"Number","label":"","hidden":true,"name":"ProjectedNewestY"},{"value":"","type":"Number","label":"","hidden":true,"name":"ProjectedOldestX"},{"value":"","type":"Number","label":"","hidden":true,"name":"ProjectedOldestY"},{"value":"","type":"Number","label":"","hidden":true,"name":"ForecastHistoryVarianceY"},{"value":"","type":"Number","label":"Index (local variable)","hidden":true,"name":"Index"},{"value":"0","type":"Number","label":"","hidden":true,"name":"CameraDelayCatchUpSpeed"},{"value":"","type":"Number","label":"","hidden":true,"name":"CameraExtraDelay"},{"value":"","type":"Number","label":"","hidden":true,"name":"WaitingSpeedXMax"},{"value":"","type":"Number","label":"","hidden":true,"name":"WaitingSpeedYMax"},{"value":"","type":"Number","label":"","hidden":true,"name":"WaitingEnd"},{"value":"","type":"Number","label":"","hidden":true,"name":"CameraDelayCatchUpDuration"},{"value":"9000","type":"Number","unit":"PixelSpeed","label":"Leftward maximum speed","group":"Maximum speed","advanced":true,"name":"LeftwardSpeedMax"},{"value":"9000","type":"Number","unit":"PixelSpeed","label":"Rightward maximum speed","group":"Maximum speed","advanced":true,"name":"RightwardSpeedMax"},{"value":"9000","type":"Number","unit":"PixelSpeed","label":"Upward maximum speed","group":"Maximum speed","advanced":true,"name":"UpwardSpeedMax"},{"value":"9000","type":"Number","unit":"PixelSpeed","label":"Downward maximum speed","group":"Maximum speed","advanced":true,"name":"DownwardSpeedMax"},{"value":"","type":"Number","label":"OldX (local variable)","hidden":true,"name":"OldX"},{"value":"","type":"Number","label":"OldY (local variable)","hidden":true,"name":"OldY"},{"value":"","type":"Boolean","label":"","hidden":true,"name":"IsCalledManually"}],"propertiesFolderStructure":{"folderName":"__ROOT","children":[{"folderName":"Catch-up speed","children":[{"propertyName":"LeftwardSpeed"},{"propertyName":"RightwardSpeed"},{"propertyName":"UpwardSpeed"},{"propertyName":"DownwardSpeed"}]},{"propertyName":"FollowOnX"},{"propertyName":"FollowOnY"},{"folderName":"Position","children":[{"propertyName":"FollowFreeAreaLeft"},{"propertyName":"FollowFreeAreaRight"},{"propertyName":"FollowFreeAreaTop"},{"propertyName":"FollowFreeAreaBottom"},{"propertyName":"CameraOffsetX"},{"propertyName":"CameraOffsetY"}]},{"folderName":"Timing","children":[{"propertyName":"CameraDelay"},{"propertyName":"ForecastTime"},{"propertyName":"ForecastHistoryDuration"}]},{"propertyName":"LogLeftwardSpeed"},{"propertyName":"LogRightwardSpeed"},{"propertyName":"LogDownwardSpeed"},{"propertyName":"LogUpwardSpeed"},{"propertyName":"DelayedCenterX"},{"propertyName":"DelayedCenterY"},{"propertyName":"ForecastHistoryMeanX"},{"propertyName":"ForecastHistoryMeanY"},{"propertyName":"ForecastHistoryVarianceX"},{"propertyName":"ForecastHistoryCovariance"},{"propertyName":"ForecastHistoryLinearA"},{"propertyName":"ForecastHistoryLinearB"},{"propertyName":"ForecastedX"},{"propertyName":"ForecastedY"},{"propertyName":"ProjectedNewestX"},{"propertyName":"ProjectedNewestY"},{"propertyName":"ProjectedOldestX"},{"propertyName":"ProjectedOldestY"},{"propertyName":"ForecastHistoryVarianceY"},{"propertyName":"Index"},{"propertyName":"CameraDelayCatchUpSpeed"},{"propertyName":"CameraExtraDelay"},{"propertyName":"WaitingSpeedXMax"},{"propertyName":"WaitingSpeedYMax"},{"propertyName":"WaitingEnd"},{"propertyName":"CameraDelayCatchUpDuration"},{"folderName":"Maximum speed","children":[{"propertyName":"LeftwardSpeedMax"},{"propertyName":"RightwardSpeedMax"},{"propertyName":"UpwardSpeedMax"},{"propertyName":"DownwardSpeedMax"}]},{"propertyName":"OldX"},{"propertyName":"OldY"},{"propertyName":"IsCalledManually"}]}},{"description":"Smoothly scroll to follow a character and stabilize the camera when jumping.","fullName":"Smooth platformer camera","helpPath":"","iconUrl":"","name":"SmoothPlatformerCamera","objectType":"","previewIconUrl":"","quickCustomizationVisibility":"hidden","eventsFunctions":[{"fullName":"","functionType":"Action","name":"doStepPreEvents","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"inverted":true,"value":"PlatformBehavior::IsJumping"},"parameters":["Object","PlatformerCharacter"]},{"type":{"inverted":true,"value":"PlatformBehavior::IsFalling"},"parameters":["Object","PlatformerCharacter"]}],"actions":[{"type":{"value":"SmoothCamera::SmoothCamera::SetFollowFreeAreaBottom"},"parameters":["Object","SmoothCamera","FloorFollowFreeAreaTop",""]},{"type":{"value":"SmoothCamera::SmoothCamera::SetFollowFreeAreaTop"},"parameters":["Object","SmoothCamera","FloorFollowFreeAreaBottom",""]},{"type":{"value":"SmoothCamera::SmoothCamera::SetUpwardSpeed"},"parameters":["Object","SmoothCamera","FloorUpwardSpeed",""]},{"type":{"value":"SmoothCamera::SmoothCamera::SetDownwardSpeed"},"parameters":["Object","SmoothCamera","FloorDownwardSpeed",""]},{"type":{"value":"SmoothCamera::SmoothCamera::SetUpwardSpeedMax"},"parameters":["Object","SmoothCamera","FloorUpwardSpeedMax",""]},{"type":{"value":"SmoothCamera::SmoothCamera::SetDownwardSpeedMax"},"parameters":["Object","SmoothCamera","FloorDownwardSpeedMax",""]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BuiltinCommonInstructions::Or"},"parameters":[],"subInstructions":[{"type":{"value":"PlatformBehavior::IsJumping"},"parameters":["Object","PlatformerCharacter"]},{"type":{"value":"PlatformBehavior::IsFalling"},"parameters":["Object","PlatformerCharacter"]}]}],"actions":[{"type":{"value":"SmoothCamera::SmoothCamera::SetFollowFreeAreaBottom"},"parameters":["Object","SmoothCamera","AirFollowFreeAreaTop",""]},{"type":{"value":"SmoothCamera::SmoothCamera::SetFollowFreeAreaTop"},"parameters":["Object","SmoothCamera","AirFollowFreeAreaBottom",""]},{"type":{"value":"SmoothCamera::SmoothCamera::SetUpwardSpeed"},"parameters":["Object","SmoothCamera","AirUpwardSpeed",""]},{"type":{"value":"SmoothCamera::SmoothCamera::SetDownwardSpeed"},"parameters":["Object","SmoothCamera","AirDownwardSpeed",""]},{"type":{"value":"SmoothCamera::SmoothCamera::SetUpwardSpeedMax"},"parameters":["Object","SmoothCamera","AirUpwardSpeedMax",""]},{"type":{"value":"SmoothCamera::SmoothCamera::SetDownwardSpeedMax"},"parameters":["Object","SmoothCamera","AirDownwardSpeedMax",""]}]}],"parameters":[{"description":"Object","name":"Object","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"SmoothCamera::SmoothPlatformerCamera","type":"behavior"}],"objectGroups":[]}],"eventsFunctionsFolderStructure":{"folderName":"__ROOT","children":[{"functionName":"doStepPreEvents"}]},"propertyDescriptors":[{"value":"","type":"Behavior","label":"Platformer character behavior","extraInformation":["PlatformBehavior::PlatformerObjectBehavior"],"choices":[],"name":"PlatformerCharacter"},{"value":"","type":"Behavior","label":"Smooth camera behavior","extraInformation":["SmoothCamera::SmoothCamera"],"choices":[],"name":"SmoothCamera"},{"value":"","type":"Number","label":"","hidden":true,"name":"JumpOriginY"},{"value":"0","type":"Number","unit":"Pixel","label":"Follow free area top in the air","group":"Position","name":"AirFollowFreeAreaTop"},{"value":"0","type":"Number","unit":"Pixel","label":"Follow free area bottom in the air","group":"Position","name":"AirFollowFreeAreaBottom"},{"value":"0","type":"Number","unit":"Pixel","label":"Follow free area top on the floor","group":"Position","name":"FloorFollowFreeAreaTop"},{"value":"0","type":"Number","unit":"Pixel","label":"Follow free area bottom on the floor","group":"Position","name":"FloorFollowFreeAreaBottom"},{"value":"0.95","type":"Number","label":"Upward speed in the air (in ratio per second)","group":"Catch-up speed","name":"AirUpwardSpeed"},{"value":"0.95","type":"Number","label":"Downward speed in the air (in ratio per second)","group":"Catch-up speed","name":"AirDownwardSpeed"},{"value":"0.9","type":"Number","label":"Upward speed on the floor (in ratio per second)","group":"Catch-up speed","name":"FloorUpwardSpeed"},{"value":"0.9","type":"Number","label":"Downward speed on the floor (in ratio per second)","group":"Catch-up speed","name":"FloorDownwardSpeed"},{"value":"9000","type":"Number","unit":"PixelSpeed","label":"Upward maximum speed in the air","group":"Maximum speed","name":"AirUpwardSpeedMax"},{"value":"9000","type":"Number","unit":"PixelSpeed","label":"Downward maximum speed in the air","group":"Maximum speed","name":"AirDownwardSpeedMax"},{"value":"9000","type":"Number","unit":"PixelSpeed","label":"Upward maximum speed on the floor","group":"Maximum speed","name":"FloorUpwardSpeedMax"},{"value":"9000","type":"Number","unit":"PixelSpeed","label":"Downward maximum speed on the floor","group":"Maximum speed","name":"FloorDownwardSpeedMax"}],"propertiesFolderStructure":{"folderName":"__ROOT","children":[{"propertyName":"PlatformerCharacter"},{"propertyName":"SmoothCamera"},{"propertyName":"JumpOriginY"},{"folderName":"Position","children":[{"propertyName":"AirFollowFreeAreaTop"},{"propertyName":"AirFollowFreeAreaBottom"},{"propertyName":"FloorFollowFreeAreaTop"},{"propertyName":"FloorFollowFreeAreaBottom"}]},{"folderName":"Catch-up speed","children":[{"propertyName":"AirUpwardSpeed"},{"propertyName":"AirDownwardSpeed"},{"propertyName":"FloorUpwardSpeed"},{"propertyName":"FloorDownwardSpeed"}]},{"folderName":"Maximum speed","children":[{"propertyName":"AirUpwardSpeedMax"},{"propertyName":"AirDownwardSpeedMax"},{"propertyName":"FloorUpwardSpeedMax"},{"propertyName":"FloorDownwardSpeedMax"}]}]}}],"eventsBasedObjects":[]},{"author":"Westboy31","category":"Visual effect","dimension":"2D","extensionNamespace":"","fullName":"Flash and transition painter","gdevelopVersion":">=5.5.222","helpPath":"","iconUrl":"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLW1vdmllLWZpbHRlciIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0xOCA0TDIwIDdIMTdMMTUgNEgxM0wxNSA3SDEyTDEwIDRIOEwxMCA3SDdMNSA0SDRDMi45IDQgMiA0LjkgMiA2TDIgMThDMiAxOS4xIDIuOSAyMCA0IDIwSDIwQzIxLjEgMjAgMjIgMTkuMSAyMiAxOFY0SDE4TTExLjI1IDE1LjI1TDEwIDE4TDguNzUgMTUuMjVMNiAxNEw4Ljc1IDEyLjc1TDEwIDEwTDExLjI1IDEyLjc1TDE0IDE0TDExLjI1IDE1LjI1TTE2Ljk0IDExLjk0TDE2IDE0TDE1LjA2IDExLjk0TDEzIDExTDE1LjA2IDEwLjA2TDE2IDhMMTYuOTQgMTAuMDZMMTkgMTFMMTYuOTQgMTEuOTRaIiAvPjwvc3ZnPg==","name":"FlashTransitionPainter","previewIconUrl":"https://resources.gdevelop-app.com/assets/Icons/movie-filter.svg","shortDescription":"Screen transitions painted with plain color fill using Shape Painter.","version":"0.2.0","description":["Paint transition effects","- Fade in, fade out","- Right to left","- Top to bottom","- Circular","","A blur effect can be added to the painter layer to smooth the transition."],"origin":{"identifier":"FlashTransitionPainter","name":"gdevelop-extension-store"},"tags":["flash","transition","effect"],"authorIds":[],"dependencies":[],"globalVariables":[],"sceneVariables":[],"eventsFunctions":[],"eventsFunctionsFolderStructure":{"folderName":"__ROOT"},"eventsBasedBehaviors":[{"description":"Paint all over the screen a color for a period of time.","fullName":"Flash and transition painter","helpPath":"","iconUrl":"","name":"FlashTransitionPainter","objectType":"PrimitiveDrawing::Drawer","previewIconUrl":"","eventsFunctions":[{"fullName":"","functionType":"Action","name":"onCreated","sentence":"","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"ActivateBehavior"},"parameters":["Object","Behavior",""]}]}],"parameters":[{"description":"Object","name":"Object","supplementaryInformation":"PrimitiveDrawing::Drawer","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"FlashTransitionPainter::FlashTransitionPainter","type":"behavior"}],"objectGroups":[]},{"fullName":"","functionType":"Action","name":"doStepPostEvents","sentence":"","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Ensure shape painter properties are set correctly for this extension to work.\n"},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"BuiltinCommonInstructions::Once"},"parameters":[]}],"actions":[{"type":{"value":"PrimitiveDrawing::ClearBetweenFrames"},"parameters":["Object","no"]},{"type":{"value":"PrimitiveDrawing::OutlineSize"},"parameters":["Object","=","0"]},{"type":{"value":"PrimitiveDrawing::UseRelativeCoordinates"},"parameters":["Object",""]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["Progress","=","min(1, Object.ObjectTimerElapsedTime(\"__FlashTransitionPainter_Time\") / Duration)"]},{"type":{"value":"PrimitiveDrawing::Drawer::ClearShapes"},"parameters":["Object"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"NumberVariable"},"parameters":["Progress","=","1"]}],"actions":[{"type":{"value":"ActivateBehavior"},"parameters":["Object","Behavior",""]},{"type":{"value":"PauseObjectTimer"},"parameters":["Object","\"__FlashTransitionPainter_Time\""]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"StringVariable"},"parameters":["Direction","=","\"Backward\""]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["Progress","=","1 - Progress"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"StringVariable"},"parameters":["Direction","=","\"Both\""]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["Progress","=","min(2 * Progress, 2 * (1 - Progress))"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"NumberVariable"},"parameters":["Progress",">","0"]}],"actions":[{"type":{"value":"PrimitiveDrawing::FillOpacity"},"parameters":["Object","=","MaxOpacity"]}],"events":[{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Flash","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"StringVariable"},"parameters":["Type","=","\"Flash\""]}],"actions":[{"type":{"value":"PrimitiveDrawing::FillOpacity"},"parameters":["Object","=","MaxOpacity * Progress"]},{"type":{"value":"PrimitiveDrawing::Rectangle"},"parameters":["Object","CameraBorderLeft(Object.Layer())","CameraBorderTop(Object.Layer())","CameraBorderRight(Object.Layer())","CameraBorderBottom(Object.Layer())"]}]}],"parameters":[]},{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Horizontal","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"from left to right"},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"StringVariable"},"parameters":["Type","=","\"Horizontal\""]}],"actions":[{"type":{"value":"PrimitiveDrawing::Rectangle"},"parameters":["Object","CameraBorderLeft(Object.Layer())","CameraBorderTop(Object.Layer())","lerp(CameraBorderLeft(Object.Layer()), CameraBorderRight(Object.Layer()), Progress)","CameraBorderBottom(Object.Layer())"]}]}],"parameters":[]},{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Vertical","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"from top to bottom"},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"StringVariable"},"parameters":["Type","=","\"Vertical\""]}],"actions":[{"type":{"value":"PrimitiveDrawing::Rectangle"},"parameters":["Object","CameraBorderLeft(Object.Layer())","CameraBorderTop(Object.Layer())","CameraBorderRight(Object.Layer())","lerp(CameraBorderTop(Object.Layer()), CameraBorderBottom(Object.Layer()), Progress)"]}]}],"parameters":[]},{"colorB":228,"colorG":176,"colorR":74,"creationTime":0,"name":"Circular","source":"","type":"BuiltinCommonInstructions::Group","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"A circle scale up from the middle."},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"StringVariable"},"parameters":["Type","=","\"Circular\""]}],"actions":[{"type":{"value":"PrimitiveDrawing::Circle"},"parameters":["Object","CameraCenterX(Object.Layer())","CameraCenterY(Object.Layer())","(DistanceBetweenPositions(0, 0, CameraWidth(Object.Layer()), CameraHeight(Object.Layer())) / 2 + 1) * Progress"]}]}],"parameters":[]}]}],"parameters":[{"description":"Object","name":"Object","supplementaryInformation":"PrimitiveDrawing::Drawer","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"FlashTransitionPainter::FlashTransitionPainter","type":"behavior"}],"objectGroups":[]},{"description":"Paint Effect.","fullName":"Paint Effect","functionType":"Action","name":"PaintEffect","sentence":"Paint effect type _PARAM4_ of _PARAM0_ with direction _PARAM5_ and color _PARAM2_ for _PARAM3_ seconds","events":[{"type":"BuiltinCommonInstructions::Comment","color":{"b":109,"g":230,"r":255,"textB":0,"textG":0,"textR":0},"comment":"Initialise all variables and then activate the behavior.\nIf user doesn't assign value to color and type , we take the last value registred."},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"inverted":true,"value":"BehaviorActivated"},"parameters":["Object","Behavior"]}],"actions":[{"type":{"value":"ActivateBehavior"},"parameters":["Object","Behavior","yes"]},{"type":{"value":"UnPauseObjectTimer"},"parameters":["Object","\"__FlashTransitionPainter_Time\""]},{"type":{"value":"ResetObjectTimer"},"parameters":["Object","\"__FlashTransitionPainter_Time\""]},{"type":{"value":"SetNumberVariable"},"parameters":["Duration","=","NewDuration"]},{"type":{"value":"SetStringVariable"},"parameters":["Direction","=","NewDirection"]},{"type":{"value":"SetNumberVariable"},"parameters":["Progress","=","0"]}],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetStringVariable"},"parameters":["Type","=","\"Flash\""]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"StringVariable"},"parameters":["NewType","!=","\"\""]}],"actions":[{"type":{"value":"SetStringVariable"},"parameters":["Type","=","NewType"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"StringVariable"},"parameters":["Color","!=","\"\""]}],"actions":[{"type":{"value":"PrimitiveDrawing::FillColor"},"parameters":["Object","Color"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["MaxOpacity","=","255"]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"NumberVariable"},"parameters":["NewMaxOpacity","!=","0"]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["MaxOpacity","=","NewMaxOpacity"]}]}]}],"parameters":[{"description":"Object","name":"Object","supplementaryInformation":"PrimitiveDrawing::Drawer","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"FlashTransitionPainter::FlashTransitionPainter","type":"behavior"},{"description":"Color","name":"Color","type":"color"},{"description":"Duration","name":"NewDuration","type":"expression"},{"description":"Type of effect ","name":"NewType","supplementaryInformation":"[\"Flash\",\"Horizontal\",\"Vertical\",\"Circular\"]","type":"stringWithSelector"},{"description":"Direction transition","name":"NewDirection","supplementaryInformation":"[\"Both\",\"Forward\",\"Backward\"]","type":"stringWithSelector"},{"description":"End opacity","name":"NewMaxOpacity","type":"expression"}],"objectGroups":[]},{"description":"Paint effect ended.","fullName":"Paint effect ended ","functionType":"Condition","name":"PaintEffectIsEnd","sentence":"When paint effect of _PARAM0_ ends","events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"ObjectTimerPaused"},"parameters":["Object","\"__FlashTransitionPainter_Time\""]}],"actions":[{"type":{"value":"SetReturnBoolean"},"parameters":["True"]}]}],"parameters":[{"description":"Object","name":"Object","supplementaryInformation":"PrimitiveDrawing::Drawer","type":"object"},{"description":"Behavior","name":"Behavior","supplementaryInformation":"FlashTransitionPainter::FlashTransitionPainter","type":"behavior"}],"objectGroups":[]}],"eventsFunctionsFolderStructure":{"folderName":"__ROOT","children":[{"functionName":"onCreated"},{"functionName":"doStepPostEvents"},{"functionName":"PaintEffect"},{"functionName":"PaintEffectIsEnd"}]},"propertyDescriptors":[{"value":"0","type":"Number","unit":"Dimensionless","label":"","hidden":true,"name":"Progress"},{"value":"0","type":"Number","label":"","hidden":true,"name":"Duration"},{"value":"","type":"String","label":"Type of effect ","hidden":true,"name":"Type"},{"value":"","type":"String","label":"Direction of transition","hidden":true,"name":"Direction"},{"value":"255","type":"Number","label":"The maximum of the opacity only for flash","hidden":true,"name":"MaxOpacity"}],"propertiesFolderStructure":{"folderName":"__ROOT","children":[{"propertyName":"Progress"},{"propertyName":"Duration"},{"propertyName":"Type"},{"propertyName":"Direction"},{"propertyName":"MaxOpacity"}]}}],"eventsBasedObjects":[]}],"externalLayouts":[{"associatedLayout":"","name":"functions","instances":[],"editionSettings":{}}]} \ No newline at end of file diff --git a/assets/tempLogo.png b/assets/tempLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..9c14d408d296cc84a9ebc8cd1fae271c53330f38 GIT binary patch literal 60192 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 JPDHLkV1i_M3Az9P literal 0 HcmV?d00001 diff --git a/assets/tempTitle.png b/assets/tempTitle.png new file mode 100644 index 0000000000000000000000000000000000000000..238b07673d4641614f5b45f3422cefdbaf2215c2 GIT binary patch literal 132357 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 literal 0 HcmV?d00001