diff --git a/Core/GDCore/Extensions/Builtin/CameraExtension.cpp b/Core/GDCore/Extensions/Builtin/CameraExtension.cpp index d139bb75a555..e90116d56da6 100644 --- a/Core/GDCore/Extensions/Builtin/CameraExtension.cpp +++ b/Core/GDCore/Extensions/Builtin/CameraExtension.cpp @@ -288,69 +288,97 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(gd::Pla .AddParameter("expression", _("New value")) .MarkAsAdvanced(); - extension.AddExpression("CameraWidth", _("Width of a camera of a layer"), _("Width of a camera of a layer"), _("Camera"), "res/actions/camera.png") + extension.AddCondition("LayerTimeScale", + _("Layer time scale"), + _("Compare the time scale applied on the objects of the layer."), + _("The time scale of layer _PARAM1_ is _PARAM2__PARAM3_"), + _("Layers and cameras/Time"), + "res/conditions/time24.png", + "res/conditions/time.png") + .AddCodeOnlyParameter("currentScene", "") + .AddParameter("layer", _("Layer (base layer if empty)"), "",true).SetDefaultValue("\"\"") + .AddParameter("relationalOperator", _("Sign of the test")) + .AddParameter("expression", _("Value to test")) + .MarkAsAdvanced() + .SetManipulatedType("number"); + + extension.AddAction("ChangeLayerTimeScale", + _("Change layer time scale"), + _("Change the time scale applied on the objects of the layer."), + _("Set time scale of layer _PARAM1_ to _PARAM2_"), + _("Layers and cameras/Time"), + "res/actions/time24.png", + "res/actions/time.png") + .AddCodeOnlyParameter("currentScene", "") + .AddParameter("layer", _("Layer (base layer if empty)"), "",true).SetDefaultValue("\"\"") + .AddParameter("expression", _("Scale (1: Default, 2: 2x faster, 0.5: 2x slower...)")); + + extension.AddExpression("CameraWidth", _("Width of a camera of a layer"), _("Width of a camera of a layer"), _("Layers and cameras"), "res/actions/camera.png") .AddCodeOnlyParameter("currentScene", "") .AddParameter("layer", _("Layer")) .AddParameter("expression", _("Camera number (default : 0)")).SetDefaultValue("0"); - extension.AddExpression("CameraHeight", _("Height of a camera of a layer"), _("Height of a camera of a layer"), _("Camera"), "res/actions/camera.png") + extension.AddExpression("CameraHeight", _("Height of a camera of a layer"), _("Height of a camera of a layer"), _("Layers and cameras"), "res/actions/camera.png") .AddCodeOnlyParameter("currentScene", "") .AddParameter("layer", _("Layer")) .AddParameter("expression", _("Camera number (default : 0)")).SetDefaultValue("0"); - extension.AddExpression("CameraViewportLeft", _("X position of the top left side point of a render zone"), _("X position of the top left side point of a render zone"), _("Camera"), "res/actions/camera.png") + extension.AddExpression("CameraViewportLeft", _("X position of the top left side point of a render zone"), _("X position of the top left side point of a render zone"), _("Layers and cameras"), "res/actions/camera.png") .AddCodeOnlyParameter("currentScene", "") .AddParameter("layer", _("Layer")) .AddParameter("expression", _("Camera number (default : 0)")).SetDefaultValue("0"); - extension.AddExpression("CameraViewportTop", _("Y position of the top left side point of a render zone"), _("Y position of the top left side point of a render zone"), _("Camera"), "res/actions/camera.png") + extension.AddExpression("CameraViewportTop", _("Y position of the top left side point of a render zone"), _("Y position of the top left side point of a render zone"), _("Layers and cameras"), "res/actions/camera.png") .AddCodeOnlyParameter("currentScene", "") .AddParameter("layer", _("Layer")) .AddParameter("expression", _("Camera number (default : 0)")).SetDefaultValue("0"); - extension.AddExpression("CameraViewportRight", _("X position of the bottom right side point of a render zone"), _("X position of the bottom right side point of a render zone"), _("Camera"), "res/actions/camera.png") + extension.AddExpression("CameraViewportRight", _("X position of the bottom right side point of a render zone"), _("X position of the bottom right side point of a render zone"), _("Layers and cameras"), "res/actions/camera.png") .AddCodeOnlyParameter("currentScene", "") .AddParameter("layer", _("Layer")) .AddParameter("expression", _("Camera number (default : 0)")).SetDefaultValue("0"); - extension.AddExpression("CameraViewportBottom", _("Y position of the bottom right side point of a render zone"), _("Y position of the bottom right side point of a render zone"), _("Camera"), "res/actions/camera.png") + extension.AddExpression("CameraViewportBottom", _("Y position of the bottom right side point of a render zone"), _("Y position of the bottom right side point of a render zone"), _("Layers and cameras"), "res/actions/camera.png") .AddCodeOnlyParameter("currentScene", "") .AddParameter("layer", _("Layer")) .AddParameter("expression", _("Camera number (default : 0)")).SetDefaultValue("0"); - extension.AddExpression("CameraX", _("Camera X position"), _("Camera X position"), _("Camera"), "res/actions/camera.png") + extension.AddExpression("CameraX", _("Camera X position"), _("Camera X position"), _("Layers and cameras"), "res/actions/camera.png") .AddCodeOnlyParameter("currentScene", "") .AddParameter("layer", _("Layer"), "",true).SetDefaultValue("\"\"") .AddParameter("expression", _("Camera number (default : 0)"), "",true).SetDefaultValue("0"); - extension.AddExpression("VueX", _("Camera X position"), _("Camera X position"), _("Camera"), "res/actions/camera.png") + extension.AddExpression("VueX", _("Camera X position"), _("Camera X position"), _("Layers and cameras"), "res/actions/camera.png") .SetHidden() .AddCodeOnlyParameter("currentScene", "") .AddParameter("layer", _("Layer"), "",true).SetDefaultValue("\"\"") .AddParameter("expression", _("Camera number (default : 0)"), "",true).SetDefaultValue("0"); - extension.AddExpression("CameraY", _("Camera Y position"), _("Camera Y position"), _("Camera"), "res/actions/camera.png") + extension.AddExpression("CameraY", _("Camera Y position"), _("Camera Y position"), _("Layers and cameras"), "res/actions/camera.png") .AddCodeOnlyParameter("currentScene", "") .AddParameter("layer", _("Layer"), "",true).SetDefaultValue("\"\"") .AddParameter("expression", _("Camera number (default : 0)"), "",true).SetDefaultValue("0"); - extension.AddExpression("VueY", _("Camera Y position"), _("Camera Y position"), _("Camera"), "res/actions/camera.png") + extension.AddExpression("VueY", _("Camera Y position"), _("Camera Y position"), _("Layers and cameras"), "res/actions/camera.png") .SetHidden() .AddCodeOnlyParameter("currentScene", "") .AddParameter("layer", _("Layer"), "",true).SetDefaultValue("\"\"") .AddParameter("expression", _("Camera number (default : 0)"), "",true).SetDefaultValue("0"); - extension.AddExpression("CameraRotation", _("Angle of a camera of a layer"), _("Angle of a camera of a layer"), _("Camera"), "res/actions/camera.png") + extension.AddExpression("CameraRotation", _("Angle of a camera of a layer"), _("Angle of a camera of a layer"), _("Layers and cameras"), "res/actions/camera.png") .AddCodeOnlyParameter("currentScene", "") .AddParameter("layer", _("Layer"), "",true).SetDefaultValue("\"\"") .AddParameter("expression", _("Camera number (default : 0)"), "",true).SetDefaultValue("0"); - extension.AddExpression("VueRotation", _("Angle of a camera of a layer"), _("Angle of a camera of a layer"), _("Camera"), "res/actions/camera.png") + extension.AddExpression("VueRotation", _("Angle of a camera of a layer"), _("Angle of a camera of a layer"), _("Layers and cameras"), "res/actions/camera.png") .SetHidden() .AddCodeOnlyParameter("currentScene", "") .AddParameter("layer", _("Layer"), "",true).SetDefaultValue("\"\"") .AddParameter("expression", _("Camera number (default : 0)"), "",true).SetDefaultValue("0"); + extension.AddExpression("LayerTimeScale", _("Time scale"), _("Time scale"), _("Layers and cameras"), "res/actions/time.png") + .AddCodeOnlyParameter("currentScene", "") + .AddParameter("layer", _("Layer")); #endif } diff --git a/Core/GDCore/Extensions/Builtin/TimeExtension.cpp b/Core/GDCore/Extensions/Builtin/TimeExtension.cpp index b2906a243797..6e42baaa43aa 100644 --- a/Core/GDCore/Extensions/Builtin/TimeExtension.cpp +++ b/Core/GDCore/Extensions/Builtin/TimeExtension.cpp @@ -106,7 +106,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(gd::Platf "res/actions/time24.png", "res/actions/time.png") .AddCodeOnlyParameter("currentScene", "") - .AddParameter("expression", _("Scale (1 : Default, 2 : Faster, 0.5 : Slower...)")); + .AddParameter("expression", _("Scale (1: Default, 2: 2x faster, 0.5: 2x slower...)")); extension.AddExpression("TimeDelta", _("Time elapsed since the last image"), _("Time elapsed since the last image"), _("Time"), "res/actions/time.png") .AddCodeOnlyParameter("currentScene", ""); diff --git a/Extensions/PanelSpriteObject/panelspriteruntimeobject.js b/Extensions/PanelSpriteObject/panelspriteruntimeobject.js index 37390c36302b..2e287b6a4f76 100644 --- a/Extensions/PanelSpriteObject/panelspriteruntimeobject.js +++ b/Extensions/PanelSpriteObject/panelspriteruntimeobject.js @@ -45,7 +45,7 @@ gdjs.PanelSpriteRuntimeObject.prototype.onDeletedFromScene = function(runtimeSce } }; -gdjs.PanelSpriteRuntimeObject.prototype.updateTime = function() { +gdjs.PanelSpriteRuntimeObject.prototype.update = function() { this._renderer.ensureUpToDate(); } diff --git a/Extensions/ParticleSystem/ParticleEmitterObject.cpp b/Extensions/ParticleSystem/ParticleEmitterObject.cpp index cb89bf0784bc..7cc03fa62dd3 100644 --- a/Extensions/ParticleSystem/ParticleEmitterObject.cpp +++ b/Extensions/ParticleSystem/ParticleEmitterObject.cpp @@ -483,17 +483,14 @@ void ParticleEmitterBase::UpdateLifeTime() particleSystem->particleModel->setLifeTime(particleLifeTimeMin,particleLifeTimeMax); } -RuntimeParticleEmitterObject::RuntimeParticleEmitterObject(RuntimeScene & scene_, const ParticleEmitterObject & particleEmitterObject): - RuntimeObject(scene_, particleEmitterObject), +RuntimeParticleEmitterObject::RuntimeParticleEmitterObject(RuntimeScene & scene, const ParticleEmitterObject & particleEmitterObject): + RuntimeObject(scene, particleEmitterObject), hasSomeParticles(true) { ParticleEmitterBase::operator=(particleEmitterObject); - //Store a pointer to the scene - scene = &scene_; - CreateParticleSystem(); - SetTexture(scene_, GetParticleTexture()); + SetTexture(scene, GetParticleTexture()); OnPositionChanged(); } @@ -683,13 +680,14 @@ void ParticleEmitterBase::SetZoneRadius(float newValue) if ( particleSystem && particleSystem->zone ) particleSystem->zone->setRadius(zoneRadius); } -void RuntimeParticleEmitterObject::UpdateTime(float deltaTime) +void RuntimeParticleEmitterObject::Update(const RuntimeScene & scene) { + double elapsedTimeInSeconds = static_cast(GetElapsedTime(scene))/1000000.0; if ( GetParticleSystem() ) - hasSomeParticles = GetParticleSystem()->particleSystem->update(deltaTime); + hasSomeParticles = GetParticleSystem()->particleSystem->update(elapsedTimeInSeconds); if (GetDestroyWhenNoParticles() && !hasSomeParticles) - DeleteFromScene(const_cast(*scene)); //Ugly const cast + DeleteFromScene(const_cast(scene)); //Ugly const cast } void ParticleEmitterBase::SetParticleGravityAngle( float newAngleInDegree ) diff --git a/Extensions/ParticleSystem/ParticleEmitterObject.h b/Extensions/ParticleSystem/ParticleEmitterObject.h index 937a5dd65913..0a5a01ea198a 100644 --- a/Extensions/ParticleSystem/ParticleEmitterObject.h +++ b/Extensions/ParticleSystem/ParticleEmitterObject.h @@ -259,7 +259,7 @@ public : virtual float GetWidth() const {return 32;}; virtual float GetHeight() const {return 32;}; - virtual void UpdateTime(float timeElapsed); + virtual void Update(const RuntimeScene & scene); bool NoMoreParticles() const {return !hasSomeParticles;}; @@ -281,7 +281,6 @@ public : private: bool hasSomeParticles; - const RuntimeScene * scene; ///< Pointer to the scene. Initialized during LoadRuntimeResources call. }; #endif // PARTICLEEMITTEROBJECT_H diff --git a/Extensions/PathBehavior/PathBehavior.cpp b/Extensions/PathBehavior/PathBehavior.cpp index cf921cb83d5b..cf7accc44222 100644 --- a/Extensions/PathBehavior/PathBehavior.cpp +++ b/Extensions/PathBehavior/PathBehavior.cpp @@ -120,7 +120,7 @@ void PathBehavior::DoStepPreEvents(RuntimeScene & scene) } // add to the current time along the path - timeOnSegment += static_cast(scene.GetTimeManager().GetElapsedTime()) + timeOnSegment += static_cast(object->GetElapsedTime(scene)) / 1000000.0 * speed; // if I reached the end of this segment, move to a new segment diff --git a/Extensions/PathfindingBehavior/PathfindingBehavior.cpp b/Extensions/PathfindingBehavior/PathfindingBehavior.cpp index 7ed07a28fc81..cd25ff5d0ef6 100644 --- a/Extensions/PathfindingBehavior/PathfindingBehavior.cpp +++ b/Extensions/PathfindingBehavior/PathfindingBehavior.cpp @@ -458,7 +458,7 @@ void PathfindingBehavior::DoStepPreEvents(RuntimeScene & scene) if (path.empty() || reachedEnd) return; //Update the speed of the object - float timeDelta = static_cast(scene.GetTimeManager().GetElapsedTime()) / 1000000.0; + float timeDelta = static_cast(object->GetElapsedTime(scene)) / 1000000.0; speed += acceleration*timeDelta; if ( speed > maxSpeed ) speed = maxSpeed; angularSpeed = angularMaxSpeed; //No acceleration for angular speed for now diff --git a/Extensions/PathfindingBehavior/pathfindingruntimebehavior.js b/Extensions/PathfindingBehavior/pathfindingruntimebehavior.js index 344e93b32e69..15385d673852 100644 --- a/Extensions/PathfindingBehavior/pathfindingruntimebehavior.js +++ b/Extensions/PathfindingBehavior/pathfindingruntimebehavior.js @@ -271,7 +271,7 @@ gdjs.PathfindingRuntimeBehavior.prototype.doStepPreEvents = function(runtimeScen if (this._path.length === 0 || this._reachedEnd) return; //Update the speed of the object - var timeDelta = runtimeScene.getTimeManager().getElapsedTime()/1000; + var timeDelta = this.owner.getElapsedTime(runtimeScene)/1000; this._speed += this._acceleration*timeDelta; if ( this._speed > this._maxSpeed ) this._speed = this._maxSpeed; this._angularSpeed = this._angularMaxSpeed; diff --git a/Extensions/PlatformBehavior/PlatformerObjectBehavior.cpp b/Extensions/PlatformBehavior/PlatformerObjectBehavior.cpp index 5f15d949a285..3d0d655e810e 100644 --- a/Extensions/PlatformBehavior/PlatformerObjectBehavior.cpp +++ b/Extensions/PlatformBehavior/PlatformerObjectBehavior.cpp @@ -96,7 +96,7 @@ void PlatformerObjectBehavior::DoStepPreEvents(RuntimeScene & scene) if ( !sceneManager ) return; - double timeDelta = static_cast(scene.GetTimeManager().GetElapsedTime()) / 1000000.0; + double timeDelta = static_cast(object->GetElapsedTime(scene)) / 1000000.0; //0.1) Get the player input: diff --git a/Extensions/PlatformBehavior/platformerobjectruntimebehavior.js b/Extensions/PlatformBehavior/platformerobjectruntimebehavior.js index 92c065a2dbdd..20ff0a2c685b 100644 --- a/Extensions/PlatformBehavior/platformerobjectruntimebehavior.js +++ b/Extensions/PlatformBehavior/platformerobjectruntimebehavior.js @@ -62,7 +62,7 @@ gdjs.PlatformerObjectRuntimeBehavior.prototype.doStepPreEvents = function(runtim var SHIFTKEY = 16; var SPACEKEY = 32; var object = this.owner; - var timeDelta = runtimeScene.getTimeManager().getElapsedTime()/1000; + var timeDelta = this.owner.getElapsedTime(runtimeScene)/1000; //0.1) Get the player input: var requestedDeltaX = 0; diff --git a/Extensions/TextEntryObject/TextEntryObject.cpp b/Extensions/TextEntryObject/TextEntryObject.cpp index b0f742bbcd8b..09371b9d68ab 100644 --- a/Extensions/TextEntryObject/TextEntryObject.cpp +++ b/Extensions/TextEntryObject/TextEntryObject.cpp @@ -40,7 +40,6 @@ TextEntryObject::TextEntryObject(gd::String name_) : RuntimeTextEntryObject::RuntimeTextEntryObject(RuntimeScene & scene_, const TextEntryObject & textEntryObject) : RuntimeObject(scene_, textEntryObject), text(), - scene(&scene_), activated(true) { } @@ -48,12 +47,12 @@ RuntimeTextEntryObject::RuntimeTextEntryObject(RuntimeScene & scene_, const Text /** * \brief Used to update input */ -void RuntimeTextEntryObject::UpdateTime(float) +void RuntimeTextEntryObject::Update(const RuntimeScene & scene) { - if (!activated || scene == NULL) return; + if (!activated) return; //Retrieve text entered - const auto & characters = scene->GetInputManager().GetCharactersEntered(); + const auto & characters = scene.GetInputManager().GetCharactersEntered(); for (std::size_t i = 0;i(scene.GetTimeManager().GetElapsedTime())/1000000.0; + float timeDelta = static_cast(object->GetElapsedTime(scene))/1000000.0; if (direction != -1) { directionInRad = static_cast(direction)*gd::Pi()/4.0; diff --git a/Extensions/TopDownMovementBehavior/topdownmovementruntimebehavior.js b/Extensions/TopDownMovementBehavior/topdownmovementruntimebehavior.js index 21bb53a81ee4..deee0f4b936a 100644 --- a/Extensions/TopDownMovementBehavior/topdownmovementruntimebehavior.js +++ b/Extensions/TopDownMovementBehavior/topdownmovementruntimebehavior.js @@ -94,7 +94,7 @@ gdjs.TopDownMovementRuntimeBehavior.prototype.doStepPreEvents = function(runtime var DOWNKEY = 40; var SHIFTKEY = 16; var object = this.owner; - var timeDelta = runtimeScene.getTimeManager().getElapsedTime()/1000; + var timeDelta = this.owner.getElapsedTime(runtimeScene)/1000; //Get the player input: this._leftKey |= !this._ignoreDefaultControls && runtimeScene.getGame().getInputManager().isKeyPressed(LEFTKEY); diff --git a/GDCpp/GDCpp/Extensions/Builtin/CameraExtension.cpp b/GDCpp/GDCpp/Extensions/Builtin/CameraExtension.cpp index 74c65ee26e0a..9a8775925aab 100644 --- a/GDCpp/GDCpp/Extensions/Builtin/CameraExtension.cpp +++ b/GDCpp/GDCpp/Extensions/Builtin/CameraExtension.cpp @@ -49,6 +49,10 @@ CameraExtension::CameraExtension() GetAllConditions()["LayerVisible"].SetFunctionName("LayerVisible").SetIncludeFile("GDCpp/Extensions/Builtin/RuntimeSceneTools.h"); + GetAllConditions()["LayerTimeScale"].SetFunctionName("GetLayerTimeScale").SetIncludeFile("GDCpp/Extensions/Builtin/RuntimeSceneCameraTools.h"); + GetAllActions()["ChangeLayerTimeScale"].SetFunctionName("SetLayerTimeScale").SetIncludeFile("GDCpp/Extensions/Builtin/RuntimeSceneCameraTools.h"); + GetAllExpressions()["LayerTimeScale"].SetFunctionName("GetLayerTimeScale").SetIncludeFile("GDCpp/Extensions/Builtin/RuntimeSceneCameraTools.h"); + GetAllExpressions()["CameraWidth"].SetFunctionName("GetCameraWidth").SetIncludeFile("GDCpp/Extensions/Builtin/RuntimeSceneCameraTools.h"); GetAllExpressions()["CameraHeight"].SetFunctionName("GetCameraHeight").SetIncludeFile("GDCpp/Extensions/Builtin/RuntimeSceneCameraTools.h"); GetAllExpressions()["CameraViewportLeft"].SetFunctionName("GetCameraViewportLeft").SetIncludeFile("GDCpp/Extensions/Builtin/RuntimeSceneCameraTools.h"); @@ -64,4 +68,3 @@ CameraExtension::CameraExtension() #endif } - diff --git a/GDCpp/GDCpp/Extensions/Builtin/RuntimeSceneCameraTools.cpp b/GDCpp/GDCpp/Extensions/Builtin/RuntimeSceneCameraTools.cpp index 15d24f00ad8c..e2f6bcf71d66 100644 --- a/GDCpp/GDCpp/Extensions/Builtin/RuntimeSceneCameraTools.cpp +++ b/GDCpp/GDCpp/Extensions/Builtin/RuntimeSceneCameraTools.cpp @@ -140,7 +140,7 @@ void GD_API CenterCameraOnObjectWithLimits(RuntimeScene & scene, RuntimeObject * float xOffset = 0; float yOffset = 0; - double elapsedTime = static_cast(scene.GetTimeManager().GetElapsedTime()) / 1000000.0; + double elapsedTime = static_cast(object->GetElapsedTime(scene)) / 1000000.0; if (anticipateObjectMove) { xOffset = object->TotalForceX() * elapsedTime; @@ -166,7 +166,7 @@ void GD_API CenterCameraOnObject(RuntimeScene & scene, RuntimeObject * object, float xOffset = 0; float yOffset = 0; - double elapsedTime = static_cast(scene.GetTimeManager().GetElapsedTime()) / 1000000.0; + double elapsedTime = static_cast(object->GetElapsedTime(scene)) / 1000000.0; if (anticipateObjectMove) { xOffset = object->TotalForceX() * elapsedTime; @@ -221,3 +221,13 @@ void GD_API SetCameraViewport( RuntimeScene & scene, const gd::String & layer, RuntimeCamera & camera = scene.GetRuntimeLayer(layer).GetCamera(cameraNb); camera.SetViewport(viewportLeft, viewportTop, viewportRight, viewportBottom); } + +double GD_API GetLayerTimeScale(RuntimeScene & scene, const gd::String & layer) +{ + return scene.GetRuntimeLayer(layer).GetTimeScale(); +} + +void GD_API SetLayerTimeScale(RuntimeScene & scene, const gd::String & layer, double timeScale) +{ + scene.GetRuntimeLayer(layer).SetTimeScale(timeScale); +} diff --git a/GDCpp/GDCpp/Extensions/Builtin/RuntimeSceneCameraTools.h b/GDCpp/GDCpp/Extensions/Builtin/RuntimeSceneCameraTools.h index 70fe2d73cece..fa551e218433 100644 --- a/GDCpp/GDCpp/Extensions/Builtin/RuntimeSceneCameraTools.h +++ b/GDCpp/GDCpp/Extensions/Builtin/RuntimeSceneCameraTools.h @@ -27,5 +27,8 @@ void GD_API CenterCameraOnObject(RuntimeScene & scene, RuntimeObject * object, b void GD_API ActDeleteCamera(RuntimeScene & scene, const gd::String & layer, std::size_t camera); void GD_API AddCamera( RuntimeScene & scene, const gd::String & layer, float width, float height, float viewportLeft, float viewportTop, float viewportRight, float viewportBottom ); void GD_API SetCameraViewport( RuntimeScene & scene, const gd::String & layer, std::size_t cameraNb, float viewportLeft, float viewportTop, float viewportRight, float viewportBottom ); +double GD_API GetLayerTimeScale(RuntimeScene & scene, const gd::String & layer); +void GD_API SetLayerTimeScale(RuntimeScene & scene, const gd::String & layer, double timeScale); + #endif // RUNTIMESCENECAMERATOOLS_H diff --git a/GDCpp/GDCpp/Extensions/Builtin/RuntimeSceneTools.cpp b/GDCpp/GDCpp/Extensions/Builtin/RuntimeSceneTools.cpp index 50dfab5c152f..d91cd027a963 100644 --- a/GDCpp/GDCpp/Extensions/Builtin/RuntimeSceneTools.cpp +++ b/GDCpp/GDCpp/Extensions/Builtin/RuntimeSceneTools.cpp @@ -84,9 +84,9 @@ void GD_API MoveObjects( RuntimeScene & scene ) { RuntimeObjNonOwningPtrList allObjects = scene.objectsInstances.GetAllObjects(); - double elapsedTime = static_cast(scene.GetTimeManager().GetElapsedTime()) / 1000000.0; for (std::size_t id = 0;id < allObjects.size();++id) { + double elapsedTime = static_cast(allObjects[id]->GetElapsedTime(scene)) / 1000000.0; allObjects[id]->SetX(allObjects[id]->GetX() + allObjects[id]->TotalForceX() * elapsedTime); allObjects[id]->SetY(allObjects[id]->GetY() + allObjects[id]->TotalForceY() * elapsedTime); diff --git a/GDCpp/GDCpp/Runtime/RuntimeLayer.cpp b/GDCpp/GDCpp/Runtime/RuntimeLayer.cpp index 6f1f61cefbb1..9c971fef4735 100644 --- a/GDCpp/GDCpp/Runtime/RuntimeLayer.cpp +++ b/GDCpp/GDCpp/Runtime/RuntimeLayer.cpp @@ -5,16 +5,23 @@ */ #include "RuntimeLayer.h" #include "GDCpp/Runtime/Project/Layer.h" +#include "GDCpp/Runtime/RuntimeScene.h" #include RuntimeLayer::RuntimeLayer(gd::Layer & layer, const sf::View & defaultView) : name(layer.GetName()), - isVisible(layer.GetVisibility()) + isVisible(layer.GetVisibility()), + timeScale(1) { for (std::size_t i = 0;i= 0) timeScale = timeScale_; } + + /** + * \brief Return the time elapsed since the last frame, in microseconds, for the layer. + * This can be different than the time elapsed on the scene + */ + signed long long GetElapsedTime(const RuntimeScene & scene) const; + private: gd::String name; ///< The name of the layer bool isVisible; ///< True if the layer is visible std::vector < RuntimeCamera > cameras; ///< The camera displayed by the layer + double timeScale; ///< Time scale that is applied on the (objects of the) layer. }; #endif // RUNTIMELAYER_H diff --git a/GDCpp/GDCpp/Runtime/RuntimeObject.cpp b/GDCpp/GDCpp/Runtime/RuntimeObject.cpp index 9f07ab7b5126..68e1f20005f2 100644 --- a/GDCpp/GDCpp/Runtime/RuntimeObject.cpp +++ b/GDCpp/GDCpp/Runtime/RuntimeObject.cpp @@ -124,6 +124,12 @@ std::size_t RuntimeObject::GetNumberOfProperties() const } #endif +signed long long RuntimeObject::GetElapsedTime(const RuntimeScene & scene) const +{ + const RuntimeLayer & theLayer = scene.GetRuntimeLayer(layer); + return theLayer.GetElapsedTime(scene); +} + void RuntimeObject::DeleteFromScene(RuntimeScene & scene) { name = ""; @@ -316,7 +322,7 @@ void RuntimeObject::RotateTowardAngle(float angleInDegrees, float speed, Runtime return; } - float timeDelta = static_cast(scene.GetTimeManager().GetElapsedTime()) / 1000000.0; + float timeDelta = static_cast(GetElapsedTime(scene)) / 1000000.0; float angularDiff = GDpriv::MathematicalTools::angleDifference(GetAngle(), angleInDegrees); bool diffWasPositive = angularDiff >= 0; @@ -331,7 +337,7 @@ void RuntimeObject::RotateTowardAngle(float angleInDegrees, float speed, Runtime void RuntimeObject::Rotate(float speed, RuntimeScene & scene) { - float timeDelta = static_cast(scene.GetTimeManager().GetElapsedTime()) / 1000000.0; + float timeDelta = static_cast(GetElapsedTime(scene)) / 1000000.0; SetAngle(GetAngle()+speed*timeDelta); } diff --git a/GDCpp/GDCpp/Runtime/RuntimeObject.h b/GDCpp/GDCpp/Runtime/RuntimeObject.h index f7ea8bbd0143..af51778483a5 100644 --- a/GDCpp/GDCpp/Runtime/RuntimeObject.h +++ b/GDCpp/GDCpp/Runtime/RuntimeObject.h @@ -243,10 +243,17 @@ class GD_API RuntimeObject virtual bool CursorOnObject(RuntimeScene & scene, bool accurate); /** - * \brief Called at each frame so as to update internal object's things using time (such as animation for a sprite). + * \brief Called at each frame, before events and rendering. * \note The default implementation does nothing. */ - virtual void UpdateTime(float timeElapsed) {}; + virtual void Update(const RuntimeScene & scene) {}; + + /** + * \brief Return the time elapsed since the last frame, in microseconds, for the object. + * + * Objects can have different elapsed time if they are on layers with different time scales. + */ + signed long long GetElapsedTime(const RuntimeScene & scene) const; /** * \brief Get the width of the object, in pixels. diff --git a/GDCpp/GDCpp/Runtime/RuntimeScene.cpp b/GDCpp/GDCpp/Runtime/RuntimeScene.cpp index 360aca806ca0..047c17fc9d0f 100644 --- a/GDCpp/GDCpp/Runtime/RuntimeScene.cpp +++ b/GDCpp/GDCpp/Runtime/RuntimeScene.cpp @@ -290,10 +290,19 @@ bool RuntimeScene::OrderObjectsByZOrder(RuntimeObjNonOwningPtrList & objList) RuntimeLayer & RuntimeScene::GetRuntimeLayer(const gd::String & name) { - for (std::size_t i = 0;i(timeManager.GetElapsedTime())/1000000.0; - for (std::size_t id = 0;idSetX( allObjects[id]->GetX() + (allObjects[id]->TotalForceX() * elapsedTime)); - allObjects[id]->SetY( allObjects[id]->GetY() + (allObjects[id]->TotalForceY() * elapsedTime)); - allObjects[id]->UpdateTime(elapsedTime); - allObjects[id]->UpdateForce(elapsedTime); - allObjects[id]->DoBehaviorsPostEvents(*this); + double elapsedTimeInSeconds = static_cast(object->GetElapsedTime(*this))/1000000.0; + object->SetX( object->GetX() + (object->TotalForceX() * elapsedTimeInSeconds)); + object->SetY( object->GetY() + (object->TotalForceY() * elapsedTimeInSeconds)); + object->Update(*this); + object->UpdateForce(elapsedTimeInSeconds); + object->DoBehaviorsPostEvents(*this); } } diff --git a/GDCpp/GDCpp/Runtime/RuntimeScene.h b/GDCpp/GDCpp/Runtime/RuntimeScene.h index 31fd2acae480..1a9b84009ed8 100644 --- a/GDCpp/GDCpp/Runtime/RuntimeScene.h +++ b/GDCpp/GDCpp/Runtime/RuntimeScene.h @@ -96,6 +96,11 @@ class GD_API RuntimeScene : public Scene */ RuntimeLayer & GetRuntimeLayer(const gd::String & name); + /** + * Get the layer with specified name. + */ + const RuntimeLayer & GetRuntimeLayer(const gd::String & name) const; + /** * \brief Return the shared data for a behavior. * \warning Be careful, no check is made to ensure that the shared data exist. diff --git a/GDCpp/GDCpp/Runtime/RuntimeSpriteObject.cpp b/GDCpp/GDCpp/Runtime/RuntimeSpriteObject.cpp index 83a24ea452c6..386ba2f359a8 100644 --- a/GDCpp/GDCpp/Runtime/RuntimeSpriteObject.cpp +++ b/GDCpp/GDCpp/Runtime/RuntimeSpriteObject.cpp @@ -317,11 +317,12 @@ void RuntimeSpriteObject::UpdateCurrentSprite() const needUpdateCurrentSprite = false; } -void RuntimeSpriteObject::UpdateTime(float elapsedTime) +void RuntimeSpriteObject::Update(const RuntimeScene & scene) { if ( animationStopped || currentAnimation >= GetAnimationsCount() ) return; - timeElapsedOnCurrentSprite += elapsedTime * animationSpeedScale; + double elapsedTimeInSeconds = static_cast(GetElapsedTime(scene))/1000000.0; + timeElapsedOnCurrentSprite += elapsedTimeInSeconds * animationSpeedScale; const gd::Direction & direction = animations[currentAnimation].Get().GetDirection( currentDirection ); diff --git a/GDCpp/GDCpp/Runtime/RuntimeSpriteObject.h b/GDCpp/GDCpp/Runtime/RuntimeSpriteObject.h index b6dd787d6121..86c9d0baf9aa 100644 --- a/GDCpp/GDCpp/Runtime/RuntimeSpriteObject.h +++ b/GDCpp/GDCpp/Runtime/RuntimeSpriteObject.h @@ -65,7 +65,7 @@ class GD_API RuntimeSpriteObject : public RuntimeObject virtual std::size_t GetNumberOfProperties() const; #endif - virtual void UpdateTime(float timeElapsed); + virtual void Update(const RuntimeScene & scene); virtual void OnPositionChanged() {needUpdateCurrentSprite = true;}; diff --git a/GDJS/GDJS/Extensions/Builtin/CameraExtension.cpp b/GDJS/GDJS/Extensions/Builtin/CameraExtension.cpp index 9d613d716613..4b510e6b1dc9 100644 --- a/GDJS/GDJS/Extensions/Builtin/CameraExtension.cpp +++ b/GDJS/GDJS/Extensions/Builtin/CameraExtension.cpp @@ -48,6 +48,10 @@ CameraExtension::CameraExtension() GetAllActions()["SetLayerEffectParameter"].SetFunctionName("gdjs.evtTools.camera.setLayerEffectParameter"); + GetAllConditions()["LayerTimeScale"].SetFunctionName("gdjs.evtTools.camera.getLayerTimeScale"); + GetAllActions()["ChangeLayerTimeScale"].SetFunctionName("gdjs.evtTools.camera.setLayerTimeScale"); + GetAllExpressions()["LayerTimeScale"].SetFunctionName("gdjs.evtTools.camera.getLayerTimeScale"); + StripUnimplementedInstructionsAndExpressions(); //Unimplemented things are listed here: /* AddAction("AddCamera", diff --git a/GDJS/Runtime/cocos-renderers/runtimescene-cocos-renderer.js b/GDJS/Runtime/cocos-renderers/runtimescene-cocos-renderer.js index 539b170ed244..a70958f9622b 100644 --- a/GDJS/Runtime/cocos-renderers/runtimescene-cocos-renderer.js +++ b/GDJS/Runtime/cocos-renderers/runtimescene-cocos-renderer.js @@ -20,9 +20,16 @@ gdjs.RuntimeSceneCocosRenderer = function(runtimeScene, runtimeGameRenderer) onEnter: function() { this._super(); this.scheduleUpdate(); + + // Hide the first frame of the scene (until update is called) + // to let the scene render method run (including scene events). + // This can avoid a glitchy first frame where objects are shown before + // events are run. + this.visible = false; }, update: function(dt) { runtimeGameRenderer.onSceneUpdated(dt*1000); + this.visible = true; } }); this._cocosScene = new ContainerScene(); diff --git a/GDJS/Runtime/events-tools/cameratools.js b/GDJS/Runtime/events-tools/cameratools.js index 3335b0cf48e1..23d8d6994c0b 100644 --- a/GDJS/Runtime/events-tools/cameratools.js +++ b/GDJS/Runtime/events-tools/cameratools.js @@ -84,11 +84,12 @@ gdjs.evtTools.camera.setCameraZoom = function(runtimeScene, newZoom, layer, came gdjs.evtTools.camera.centerCamera = function(runtimeScene, object, anticipateMove, layer, cameraId) { if ( !runtimeScene.hasLayer(layer) || object == null ) { return; } - var elapsedTimeInSeconds = runtimeScene.getTimeManager().getElapsedTime() / 1000; var layer = runtimeScene.getLayer(layer); var xOffset = 0; var yOffset = 0; if ( anticipateMove && !object.hasNoForces() ) { var objectAverageForce = object.getAverageForce(); + var elapsedTimeInSeconds = obj.getElapsedTime(runtimeScene) / 1000; + xOffset = objectAverageForce.getX() * elapsedTimeInSeconds; yOffset = objectAverageForce.getY() * elapsedTimeInSeconds; } @@ -100,11 +101,12 @@ gdjs.evtTools.camera.centerCamera = function(runtimeScene, object, anticipateMov gdjs.evtTools.camera.centerCameraWithinLimits = function(runtimeScene, object, left, top, right, bottom, anticipateMove, layer, cameraId) { if ( !runtimeScene.hasLayer(layer) || object == null ) { return; } - var elapsedTimeInSeconds = runtimeScene.getTimeManager().getElapsedTime() / 1000; var layer = runtimeScene.getLayer(layer); var xOffset = 0; var yOffset = 0; if ( anticipateMove && !object.hasNoForces() ) { var objectAverageForce = object.getAverageForce(); + var elapsedTimeInSeconds = obj.getElapsedTime(runtimeScene) / 1000; + xOffset = objectAverageForce.getX() * elapsedTimeInSeconds; yOffset = objectAverageForce.getY() * elapsedTimeInSeconds; } @@ -126,3 +128,13 @@ gdjs.evtTools.camera.setLayerEffectParameter = function(runtimeScene, layer, eff return runtimeScene.getLayer(layer).setEffectParameter(effect, parameter, value); } + +gdjs.evtTools.camera.setLayerTimeScale = function(runtimeScene, layer, timeScale) { + if ( !runtimeScene.hasLayer(layer) ) { return; } + return runtimeScene.getLayer(layer).setTimeScale(timeScale); +} + +gdjs.evtTools.camera.getLayerTimeScale = function(runtimeScene, layer) { + if ( !runtimeScene.hasLayer(layer) ) { return 1; } + return runtimeScene.getLayer(layer).getTimeScale(); +} diff --git a/GDJS/Runtime/gd.js b/GDJS/Runtime/gd.js index af0113deea2e..3048a1b1f484 100644 --- a/GDJS/Runtime/gd.js +++ b/GDJS/Runtime/gd.js @@ -171,16 +171,30 @@ gdjs.getBehaviorConstructor = function(name) { return gdjs.behaviorsTypes.get(""); //Create a base empty runtime behavior. }; +/** + * Create a static array that won't need a new allocation each time it's used. + */ gdjs.staticArray = function(owner) { owner._staticArray = owner._staticArray || []; return owner._staticArray; } +/** + * Create a second static array that won't need a new allocation each time it's used. + */ gdjs.staticArray2 = function(owner) { owner._staticArray2 = owner._staticArray2 || []; return owner._staticArray2; } +/** + * Create a static object that won't need a new allocation each time it's used. + */ +gdjs.staticObject = function(owner) { + owner._staticObject = owner._staticObject || {}; + return owner._staticObject; +} + Array.prototype.remove = function(from) { //Adapted from the nice article available at //https://www.scirra.com/blog/76/how-to-write-low-garbage-real-time-javascript diff --git a/GDJS/Runtime/layer.js b/GDJS/Runtime/layer.js index 50897b051dca..9b2e4b410cc1 100644 --- a/GDJS/Runtime/layer.js +++ b/GDJS/Runtime/layer.js @@ -18,6 +18,7 @@ gdjs.Layer = function(layerData, runtimeScene) this._name = layerData.name; this._cameraRotation = 0; this._zoomFactor = 1; + this._timeScale = 1; this._hidden = !layerData.visibility; this._effects = layerData.effects || []; this._cameraX = runtimeScene.getGame().getDefaultWidth()/2; @@ -221,3 +222,30 @@ gdjs.Layer.prototype.setEffectsDefaultParameters = function() { } } }; + +/** + * Set the time scale for the objects on the layer: + * time will be slower if time scale is < 1, faster if > 1. + * @method setTimeScale + * @param timeScale {Number} The new time scale (must be positive). + */ +gdjs.Layer.prototype.setTimeScale = function(timeScale) { + if ( timeScale >= 0 ) this._timeScale = timeScale; +}; + +/** + * Get the time scale for the objects on the layer. + * @method getTimeScale + */ +gdjs.Layer.prototype.getTimeScale = function() { + return this._timeScale; +}; + +/** + * Return the time elapsed since the last frame, + * in milliseconds, for objects on the layer. + * @method getElapsedTime + */ +gdjs.Layer.prototype.getElapsedTime = function(runtimeScene) { + return runtimeScene.getTimeManager().getElapsedTime() * this._timeScale; +} diff --git a/GDJS/Runtime/runtimegame.js b/GDJS/Runtime/runtimegame.js index 17bf7d511dfd..524ba731c453 100644 --- a/GDJS/Runtime/runtimegame.js +++ b/GDJS/Runtime/runtimegame.js @@ -266,16 +266,16 @@ gdjs.RuntimeGame.prototype.startGameLoop = function() { this._injectExternalLayout); //Uncomment to profile the first x frames of the game. - /*var x = 250; - var startTime = Date.now(); - console.profile("Stepping for " + x + " frames") - for(var i = 0; i < x; ++i) { - this._sceneStack.step(16); - } - console.profileEnd(); - var time = Date.now() - startTime; - console.log("Took", time, "ms"); - return;*/ + // var x = 500; + // var startTime = Date.now(); + // console.profile("Stepping for " + x + " frames") + // for(var i = 0; i < x; ++i) { + // this._sceneStack.step(16); + // } + // console.profileEnd(); + // var time = Date.now() - startTime; + // console.log("Took", time, "ms"); + // return; //The standard game loop var that = this; diff --git a/GDJS/Runtime/runtimeobject.js b/GDJS/Runtime/runtimeobject.js index 02fa2c511fe5..d1dbef44ae75 100644 --- a/GDJS/Runtime/runtimeobject.js +++ b/GDJS/Runtime/runtimeobject.js @@ -96,18 +96,32 @@ gdjs.RuntimeObject.forcesGarbage = []; //Global container for unused forces, avo //Common members functions related to the object and its runtimeScene : /** - * Called each time the scene is rendered. + * Return the time elapsed since the last frame, + * in milliseconds, for the object. * - * @method updateTime - * @param elapsedTime {Number} The time elapsedTime since the last frame, in **seconds**. + * Objects can have different elapsed time if they are on layers with different time scales. + * + * @method getElapsedTime + * @param runtimeScene The RuntimeScene the object belongs to. */ -gdjs.RuntimeObject.prototype.updateTime = function(elapsedTime) { +gdjs.RuntimeObject.prototype.getElapsedTime = function(runtimeScene) { + //TODO: Memoize? + var theLayer = runtimeScene.getLayer(this.layer); + return theLayer.getElapsedTime(runtimeScene); +} + +/** + * Called once during the game loop, before events and rendering. + * @method update + * @param runtimeScene The gdjs.RuntimeScene the object belongs to. + */ +gdjs.RuntimeObject.prototype.update = function(runtimeScene) { //Nothing to do. }; /** * Called when the object is created from an initial instance at the startup of the scene.
- * Note this.common properties ( position, angle, z order... ) have already been setup. + * Note that common properties (position, angle, z order...) have already been setup. * * @method extraInitializationFromInitialInstance * @param initialInstanceData The data of the initial instance. @@ -285,7 +299,7 @@ gdjs.RuntimeObject.prototype.rotateTowardAngle = function(angle, speed, runtimeS var diffWasPositive = angularDiff >= 0; var newAngle = this.getAngle() + (diffWasPositive ? -1.0 : 1.0) - * speed * runtimeScene.getTimeManager().getElapsedTime() / 1000; + * speed * this.getElapsedTime(runtimeScene) / 1000; if (gdjs.evtTools.common.angleDifference(newAngle, angle) > 0 ^ diffWasPositive) newAngle = angle; this.setAngle(newAngle); @@ -295,8 +309,7 @@ gdjs.RuntimeObject.prototype.rotateTowardAngle = function(angle, speed, runtimeS }; gdjs.RuntimeObject.prototype.rotate = function(speed, runtimeScene) { - this.setAngle(this.getAngle() + - speed * runtimeScene.getTimeManager().getElapsedTime() / 1000); + this.setAngle(this.getAngle() + speed * this.getElapsedTime(runtimeScene) / 1000); }; /** @@ -419,6 +432,7 @@ gdjs.RuntimeObject.prototype.getVariableNumber = gdjs.RuntimeObject.getVariableN gdjs.RuntimeObject.getVariableString = function(variable) { return variable.getAsString(); }; +gdjs.RuntimeObject.prototype.getVariableString = gdjs.RuntimeObject.getVariableString; /** * Get the number of children from a variable @@ -432,8 +446,6 @@ gdjs.RuntimeObject.getVariableChildCount = function(variable) { return Object.keys(variable.getAllChildren()).length; }; -gdjs.RuntimeObject.prototype.getVariableString = gdjs.RuntimeObject.getVariableString; - /** * Shortcut to set the value of a variable considered as a number * @method setVariableNumber diff --git a/GDJS/Runtime/runtimescene.js b/GDJS/Runtime/runtimescene.js index 620ac7afc5ef..7cf2549a18ef 100644 --- a/GDJS/Runtime/runtimescene.js +++ b/GDJS/Runtime/runtimescene.js @@ -365,9 +365,8 @@ gdjs.RuntimeScene.prototype._updateObjects = function() { //It is *mandatory* to create and iterate on a external list of all objects, as the behaviors //may delete the objects. this._constructListOfAllInstances(); - var elapsedTimeInSeconds = this._timeManager.getElapsedTime() / 1000; for( var i = 0, len = this._allInstancesList.length;i + + + + Project + + 800 + 600 + + 60 + 10 + false + + + + + + + + + + + + + + + + + + + + + + + + + GDevelop JS platform + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BuiltinCommonInstructions::Standard + + + + + + + + + + + + + + + 0.3 + + + + + + + NewObject + 300 + 0 + 1 + + + + + + + + "New layer 1" + 2 + + + + + + + + "New layer" + 0.5 + + + + + + + + BuiltinCommonInstructions::Standard + + + + + + NewObject + 180 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +