Iv been going trough the documentation and iv found a bunch of stuff about timers and the timemanager and such, but nothing that works to retrieve object timers…
this is driving me nutts, can someone give any sort of example on how to do it or what methods to use?
Im trying to add timers to the culling script that im developing.
I can simply exclude objects that have timers and that would fix it in a simple manner, but i was trying to see if it was possible to bake into the original script.
Any help would be appreciated <3
1 Like
The place to start is the sprite runtime. I’ve never used timers in Javascript.
https://docs.gdevelop.io/GDJS%20Runtime%20Documentation/classes/gdjs.SpriteRuntimeObject.html
There are a lot of timer methods. Just click the method and make sure it’s not depreciated. I noticed a couple were.
These 2 seem to get the time. The difference is whether they return NaN or zero if a timer doesn’t exist.
getTimerElapsedTimeInSecondsOrNaN
getTimerElapsedTimeInSeconds
I’m not at a PC. It seems straightforward.
Remember to use Object[#] or something that goes through all instances. I’m still a little fuzy with the later.
I’m curious now. So, I might try it later.
1 Like
I worked it out just as you posted, but thanks a bunch anyways, your always a massive help!
Honestly… i got all the documentation i could, when i couldnt find it there, i went direct to the source… as it turns out, timer stuff was all organized next to each other on there, it was much easier to grab.
I got it working! If you want to geek on some code, you can be the first to see v4.0 of the Object Culling script
- It now also keeps track of object timers!
- It stores the timer when the object is culled
- When the object is recreated, it adds the timer back to the object
- It checks the elapsed time between cull and recreating and adds it to the objects timer value
// Initialize the deletedObjects object if it doesn't exist
if (!runtimeScene.deletedObjects) {
runtimeScene.deletedObjects = {};
}
// Get the camera position and size once
const cameraLayer = runtimeScene.getLayer("");
const cameraX = cameraLayer.getCameraX();
const cameraY = cameraLayer.getCameraY();
const cameraWidth = cameraLayer.getCameraWidth();
const cameraHeight = cameraLayer.getCameraHeight();
// Get the value of the CullBuffer scene variable once
const cullBuffer = runtimeScene.getVariables().get("CullBuffer").getAsNumber();
// Calculate the boundaries for object culling based on the CullBuffer variable once
const leftBoundary = cameraX - cameraWidth / 2 - cullBuffer;
const rightBoundary = cameraX + cameraWidth / 2 + cullBuffer;
const topBoundary = cameraY - cameraHeight / 2 - cullBuffer;
const bottomBoundary = cameraY + cameraHeight / 2 + cullBuffer;
// Get all instances of objects in the scene
const allObjectsInstances = runtimeScene.getAdhocListOfAllInstances();
// Arrays to hold objects for deletion and recreation
const objectsToDelete = [];
const objectsToStoreAndDelete = [];
// Process a subset of objects each frame to avoid spikes in CPU usage
const maxObjectsPerFrame = 50; // Adjust this number based on performance needs
const startIndex = runtimeScene.getVariables().has("CullStartIndex")
? runtimeScene.getVariables().get("CullStartIndex").getAsNumber()
: 0;
const endIndex = Math.min(startIndex + maxObjectsPerFrame, allObjectsInstances.length);
runtimeScene.getVariables().get("CullStartIndex").setNumber(endIndex === allObjectsInstances.length ? 0 : endIndex);
// Get the current scene time
const currentTime = runtimeScene.getTimeManager().getTimeFromStart() / 1000; // Time in seconds
// Iterate over a subset of objects in the scene
for (let i = startIndex; i < endIndex; i++) {
const object = allObjectsInstances[i];
const objectName = object.getName();
const objectLayer = object.getLayer();
// Only process objects on the base layer
if (objectLayer !== "") continue;
const variables = object.getVariables();
// Check if the object has a variable named "ExcludeCull" and its value is true
if (variables.has("ExcludeCull") && variables.get("ExcludeCull").getAsBoolean()) {
continue; // Skip culling for this object if "ExcludeCull" is true
}
// Get the bounding box of the object
const aabb = object.getAABB();
const objectLeft = aabb.min[0];
const objectRight = aabb.max[0];
const objectTop = aabb.min[1];
const objectBottom = aabb.max[1];
// Check if the object is completely outside the culling boundaries
if (objectRight < leftBoundary || objectLeft > rightBoundary || objectBottom < topBoundary || objectTop > bottomBoundary) {
// Check if the object has a variable named "Cull" and its value is true
if (variables.has("Cull") && variables.get("Cull").getAsBoolean()) {
objectsToDelete.push(object); // Queue the object for direct deletion
} else {
// Store the position, name, properties, timers, and culling time to recreate later
if (!runtimeScene.deletedObjects[objectName]) {
runtimeScene.deletedObjects[objectName] = [];
}
// Common properties for all objects
const objectProperties = {
x: object.getX(),
y: object.getY(),
zOrder: object.getZOrder(),
angle: object.getAngle(),
layer: objectLayer,
hidden: object.isHidden(), // Store hidden state
variables: {},
timers: {}, // Object to store timer names and elapsed time
cullTime: currentTime // Store the current time when the object is culled
};
// Store object variables
const objectVariablesList = variables._variables.items;
for (const variableName in objectVariablesList) {
if (objectVariablesList.hasOwnProperty(variableName)) {
objectProperties.variables[variableName] = objectVariablesList[variableName].getAsString();
}
}
// Check for and store optional properties
if (object.getWidth) {
objectProperties.width = object.getWidth();
}
if (object.getHeight) {
objectProperties.height = object.getHeight();
}
if (object.getOpacity) {
objectProperties.opacity = object.getOpacity();
}
// Store object timers directly from _timers
if (object._timers && object._timers.items) {
const timerItems = object._timers.items;
for (const timerName in timerItems) {
if (timerItems.hasOwnProperty(timerName)) {
objectProperties.timers[timerName] = timerItems[timerName].getTime() / 1000.0; // Store the timer value in seconds
console.log(`Stored timer ${timerName} for object ${objectName} with time ${objectProperties.timers[timerName]}`);
}
}
} else {
console.log(`Object ${objectName} does not support timers or has no timers.`);
}
runtimeScene.deletedObjects[objectName].push(objectProperties);
// Queue the object for deletion and storage
objectsToStoreAndDelete.push(object);
}
}
}
// Perform deletion of objects that are fully culled
for (let i = 0; i < objectsToDelete.length; i++) {
objectsToDelete[i].deleteFromScene(runtimeScene);
}
// Perform deletion of objects that are stored and then deleted
for (let i = 0; i < objectsToStoreAndDelete.length; i++) {
objectsToStoreAndDelete[i].deleteFromScene(runtimeScene);
}
// Get the current scene time for restoring objects
const restoreTime = runtimeScene.getTimeManager().getTimeFromStart() / 1000; // Time in seconds
// Recreate objects within the boundaries
const deletedObjects = runtimeScene.deletedObjects;
for (let objectName in deletedObjects) {
const objectList = deletedObjects[objectName];
for (let i = objectList.length - 1; i >= 0; i--) {
const data = objectList[i];
const objectLeft = data.x;
const objectRight = data.x + (data.width || 0);
const objectTop = data.y;
const objectBottom = data.y + (data.height || 0);
// Check if the position is within the recreation boundaries
if (objectRight >= leftBoundary && objectLeft <= rightBoundary && objectBottom >= topBoundary && objectTop <= bottomBoundary) {
// Calculate the elapsed time since culling
const elapsedTime = restoreTime - data.cullTime;
// Recreate the object
const newObject = runtimeScene.createObject(objectName);
newObject.setPosition(data.x, data.y);
newObject.setZOrder(data.zOrder);
newObject.setAngle(data.angle);
newObject.setLayer(data.layer);
// Restore optional properties
if (data.width !== undefined && newObject.setWidth) {
newObject.setWidth(data.width);
}
if (data.height !== undefined && newObject.setHeight) {
newObject.setHeight(data.height);
}
if (data.opacity !== undefined && newObject.setOpacity) {
newObject.setOpacity(data.opacity);
}
// Restore hidden state
if (data.hidden !== undefined) {
newObject.hide(data.hidden);
}
// Restore variables
const targetVariables = newObject.getVariables();
const sourceVariables = data.variables;
for (const variableName in sourceVariables) {
if (sourceVariables.hasOwnProperty(variableName)) {
targetVariables.get(variableName).setString(sourceVariables[variableName]);
}
}
// Restore timers and add elapsed time
const objectTimers = data.timers;
for (const timerName in objectTimers) {
const timerValue = objectTimers[timerName];
newObject.resetTimer(timerName); // Reset the timer with the same name
newObject._timers.get(timerName).setTime((timerValue + elapsedTime) * 1000); // Add elapsed time to the timer value
console.log(`Restored timer ${timerName} for object ${objectName} with time ${timerValue + elapsedTime} seconds`);
}
// Remove from the list after recreation
objectList.splice(i, 1);
}
}
}
// Cleanup empty lists to free memory
for (let objectName in deletedObjects) {
if (deletedObjects[objectName].length === 0) {
delete deletedObjects[objectName];
}
}
1 Like