Script to measure the passage of time? - javascript

I'm currently developing a small game for a class using Crafty, and our game requires the passage of time. To give context, it's a tamagotchi-like game where the player controls a creature and feeds it, grooms it, etc., when required, so we need to measure time for things such as "every five minutes the creature will be hungry" or "after a certain amount of time (say, 20 minutes) the creature will die of natural causes and the game will end". My problem is that I'm not sure what is the best way to go about this. Should I use setInterval? setTimeout? My own timer class? I don't know what's the most common solution for instances like these. So far I've tried the first two options without successful results.
I also tried looking for any crafy functions for time; and the closest I could find was
Crafty.bind("EnterFrame", function() { ... }), so I could 'manipulate' time frame by frame, but this didn't work either. Thanks in advance.

When the game starts, get a timestamp with new Date().getTime(), and keep it in a variable. On regular intervals (you can use setInterval), compare that with the current timestamp, and act according to how much time has passed.
I suggest building an array with the timed events, and checking its elements from the timer callback. Something like this:
var startTime = new Date().getTime();
// List of timed events
// (times are in milliseconds)
var events = [
{ time: 5000, text: "do something after 5 secs"},
{ time: 10000, text: "do something after 10 secs"},
{ time: 20000, text: "do something after 20 secs"}
];
// Check for events every second
setInterval(function() {
var timePassed = new Date().getTime() - startTime;
console.log("passed: " + timePassed + " milliseconds");
// Check all events
for(var i=events.length-1; i>=0; i--) {
// If an event has expired, remove it from the list,
// (and do whatever tou need to do)
if(events[i].time <= timePassed) {
// log the event text to the console
console.log(timePassed + "ms passed. " + events[i].text);
// remove from array
events.splice(i, 1);
}
}
}, 1000);
DEMO (open your browser console to see the output).

Rather than use the single timestamp as in bfavartto's answer, you could expand that to set multiple, dynamic timestamps in a "time" array (or object) or even simply as individual variables and then update them as actions occur.
A simple version would be something like:
// Initialize the variables at the beginning of the game
var lifeStamp = new Date().getTime();
var foodStamp = lifeStamp ;
var groomStamp = lifeStamp ;
function feed() {
/*** Do feed-realted stuff here ***/
// reset the "feed" timestamp
foodStamp = new Date().getTime();
}
function groom() {
/*** Do groom-realted stuff ***/
// reset the "groom" timestamp
groomStamp = new Date().getTime();
}
That way, you could keep your intervals, but reset them by resetting the timestamps that your intervals compare against for different types of actions. At the same time, the "life" timestamp would stay the same, while the other ones changed.
Edit: Re-looking at bfavartto's answer, it looks like you would need to store off and "original" list of any action-specific events as well, so that, as you reset the timestamps, you could reset the actions that go with them.
Edit #2: One more thing . . . if you want these creatures to last past the current page load, you might want to look into using cookies or HTML5's LocalStorage to store these timestamps. That would allow you to (practically) use much longer intervals, as well as let users leave the page and come back to pick up where they left off (though, I'd imagine that there would be a considerable amount of other data that would need to be stored as well, in order to allow users to leave and come back).

Related

How to measure graphics performance while drawing in JS?

I have a relatively simple website (small browser game) that does not perform well. Its graphic part is flickering and I'd like to measure how long it takes to draw different elements.
I draw in the method triggered by
window.requestAnimationFrame(() => this.drawAll());
To measure time, I've added to my drawing functions elements that capture the current time:
let t0 = new Date().getTime();
...
let t1 = new Date().getTime();
...
let t2 = new Date().getTime();
The intent was to display the delta between those numbers in the console, but the problem is that if you do it in the real-time console just freezes.
The idea I have is to accumulate time information and display it once a second (or for every 100 refresh cycles), but I'm wondering if there is any better way to do so?
Thanks!
EDIT: Idea to accumulate information did not work well: each part I'm concerned about is rendered decently fast and new Date().getTime() only counts milliseconds. The alternative is to use 'performance.now()' - it counts fractions of ms.
I hate leaving questions without the answer.
Due to lack of better responses, I'll convert 'EDIT' part of the question to an answer:
I did end up with a few improvements to the idea:
Use 'performance.now()' instead of 'new Date().getTime()' to capture time
Don't output time snippets to console on every render event, but instead accumulate the duration of events in static variables as well as count the number of render events. When the counter reaches 100 (or any number that can help reasonably indicate performance difference) output accumulated data to console.
something like this:
static performanceEventCounter=0;
static duration1=0;
static duration2=0;
render() {
let t0=performance.now();
...
let t1=performance.now();
...
let t2=performance.now();
duration1+=t1-t0;
duration2+=t2-t1;
if(++performanceEventCounter>100) {
console.log('duration1=${duration1}, duration2=${duration2}');
performanceEventCounter=0;
duration1=0;
duration2=0;
}

How to sleep a certain amount of seconds in the Phaser-Framework

In my game i'm trying to make a variable go up gradually, so i need to be able to sleep a certain amount of time before I increment the variable again.
1) Use a timer. This will allow you to execute one off delayed events, or execute that function call repeatedly.
An example, as the phaser website basically gives you examples of everything if you search for it,
http://phaser.io/examples/v2/time/basic-timed-event
Also, from the docs
http://phaser.io/docs/2.4.8/Phaser.Timer.html
Should you need to repeat, note the function "loop" (I would post the link, but i don't have enough reputation yet).
2) The alternative is simply to tie in to Phaser's game tick. Within your state (if this is where you are executing you variable incrementation), create an update function (this will be called every game update). You can access time since last update.
Look up the class Phaser.Timer (again, i cannot post the link).
See the properties elapsed and elapsedMS. You could use this to manually track time elapsed since your last incremental event (behind the scenes, this is basically what phaser tweens or timed events are doing).
eg:
var timeSinceLastIncrement = 0;
function update()
{
// Update the variable that tracks total time elapsed
timeSinceLastIncrement += game.time.elapsed;
if (timeSinceLastIncrement >= 10) // eg, update every 10 seconds
{
timeSinceLastIncreemnt = 0;
// Do your timed code here.
}
}
Note, that option 1 is cleaner, and likely to be the preferred solution. I present option 2 simply to suggest how this can be done manually (and in fact, how it is generally done in frameworks like phaser behind the scenes).

If elements are touching, split their width in half?

I'm working on a Javascript/jQuery calendar which includes a month view and a day view. Clicking the days will change the date, which will update the date variables in the day view.
The day view is split up into half hour segments from midnight to 11:00 PM. Clicking on any half hour <tr> (the day view is a table) will create an event between that time clicked and an hour in the future, as well as append a div on top of the calendar, spanning the range of time and positioned at the correct starting point (each pixel is a minute...)
There is a problem, however. If you create an "event" between a certain time span where there is already one in place, they overlap. This is the default behavior, obviously, but what I would like to happen is that if an event is created between a range of dates that is already occupied by an event, they align side by side so that they're not overlapping.
This resembles the behavior seen in the iCal app for mac:
Now my first thought to achieve such a goal was to use collision detection, but all the jQuery plugins for this are bloated or require the elements to be draggable.
Then I thought there might be a way in CSS to do this, where if two elements are overlapping, they split the width evenly.
Then I thought that's ridiculously far fetched, so I'm wondering how I can achieve this as easily as possible.
I'll post the full code in a jsFiddle, but for the most important function would be insertEvent which looks like this:
function insertEvent(start, end){
var end_minutes = new Date(end).getMinutes();
var end_border = new Date(new Date(end).setMinutes(end_minutes + 2));
//$(".day_date").html(start + "<br />" + end);
var diff = Math.abs(end_border - new Date(start));
var minutes = Math.floor((diff/1000)/60);
var start_element = $("td").find("[data-date='" + start + "']");
var offset = start_element.offset().top - $(".second").offset().top;
var this_element = $("<div class='event' style='height:" + minutes + "px;margin-top:" + offset + "px;'></div>");
$(".right").prepend(this_element);
}
This takes two parameters in the javascript new Date() format, one for the start date and one for the end date.
The fiddle: http://jsfiddle.net/charlescarver/HwdwL/
One of the the problems I see with your approach is that there isn't a structure to the storage of the data. I've built a calendar in Javascript before and it's not easy work. First, make sure you have some kind of abstraction for the calendar event. Something like:
function CalendarEvent(startDateTime, endDateTime) {
this.startDateTime = startDateTime;
this.endDateTime = endDateTime;
}
CalendarEvent.prototype.start = function() {
return this.startDateTime.getTime();
};
CalendarEvent.prototype.end = function() {
return this.endDateTime.getTime();
};
CalendarEvent.new = function(startDateTime, endDateTime) {
// This is a little factory method. It prevents calendar events
// from having end times that fall before the start time.
// USE THIS TO INSTANTIATE A NEW CALENDAR EVENT
if(endDateTime.getTime() < startDateTime.getTime()) {
throw new Error("End time falls before start time");
}
return new CalendarEvent(startDateTime, endDateTime);
};
CalendarEvent.compare = function(eventOne, eventTwo) {
// this is a class method to compare two events
// If used with sort it will sort by startDateTime
return eventOne.start() - eventTwo.start();
};
// ... add any other methods you need
Next you're going to want to sort the calendar events. I would sort by start time. Then once it is sorted you can actually re-render everything when changes are made. As long as you sort correctly, determining if a calendar event collides is as simple as this:
CalendarEvent.prototype.intersects = function(otherEvent) {
// If the other event starts after this one ends
// then they don't intersect
if(otherEvent.start() > this.end()) {
return false;
}
// If the other event ends before this one starts
// then they don't intersect
if(otherEvent.end() < this.start()) {
return false;
}
// Everything else is true
return true;
};
Because the data is sorted you know that if two or more calendar events intersect they will have to share the space. Granted, you must think about a few things when you divide the space. Do you want a naive implementation where you just share the space equally from left to right (left having the earliest start time). If so your visual representation could look like this if it had 4 events that shared a space (each block is an event):
However if your events have strange shapes they might cause your calendar to look strange. Consider the following:
In this instance event 2 takes up a lot of vertical space and all the space underneath event 1 is unused. Maybe for a better UX you don't want that kind of thing to happen. If so you should design your rendering algorithm accordingly. Just remember that it is probably easiest to re-render on every change that you encounter, but it's all about how you store the data. If you do not store the data in some kind of structure that is easily traversed then you won't be able to do this kind of thing.
But to complete the answer to your question, here is a fairly naive example. I haven't tested it so this is a pretty big assumption of it working. It is not entirely complete you will have to edit the rendering for yourself. This is merely to give you an idea of how to get it to work. It could definitely look prettier:
function renderCalendarEvents(calendarEvents) {
// Sort the calendar events (assuming calendarEvents is an array)
var sortedEvents = calendarEvents.sort(CalendarEvent.compare);
var index = 0;
// renderEvents is an anonymous function that will be called every time
// you need to render an event
// it returns it's columnDivisor.
var renderEvent = function(position) {
var currentEvent = sortedEvents[index];
var nextEvent = sortedEvents[index + 1];
// The default column divisor is determined by
// the current x-position + 1
var columnDivisor = position + 1;
// Increment before any recursion
index += 1;
// Check if nextEvent even exists
if(nextEvent) {
// If the nextEvent intersects with the current event
// then recurse
if(currentEvent.intersects(nextEvent)) {
// We need to tell the next event that it starts at the
// column position that is immediately +1 to the current event
columnDivisor = renderEvent(position + 1);
}
}
// placeEvent() is some function you can call to actually place
// the calendar event element on the page
// The position is the x-position of the current event
// The columnDivisor is a count of the amount of events sharing this column
placeEvent(currentEvent, position, columnDivisor);
return columnDivisor;
};
while(true) {
// render events until we're done
renderEvent(0);
if(index >= sortedEvents.length) {
break;
}
}
}
Essentially the idea with this particular algorithm is that if the nextEvent on the list exists and that event intersects with the currentEvent then we need to split the width of the currentEvent. It keeps on recursing until it finds no more intersections then it makes it's way back up the chain of recursive calls. I skipped the actual DOM manipulation logic because really the hard part is determining how much you need to split the actual column in order to get these events to fit. So hopefully this all makes a little bit of sense.
EDIT:
To be much more clear, in order to add this to your existing code I would replace your insertEvent function with something like this. I don't write all of the logic for you so you'll have to do some of your own writing. But that's half the fun :-).
function insertEvent(start, end) {
var newEvent = Calendar.new(start, end);
// you'll have to store the array somewhere.
// i'm just assuming some kind of global right now
eventsArray.push(newEvent);
// You'll want to destroy any event elements
destroyCurrentEventElements();
// Now run the rendering function
renderCalendarEvents(eventsArray);
}

JavaScript: Is this timer reliable?

Today I was introduced to the world of Web Workers in JavaScript. This made me rethink about timers. I used to program timers the ugly way, like this.
var time = -1;
function timerTick()
{
time++;
setTimeout("timerTick()",1000);
$("#timeI").html(time);
}
I know this could be improved by saving the date when you start the timer, but I've never been a fan of that.
Now I came up with a method using Web Workers, I did a little benchmark and found it much more reliable. Since I am not an expert on JavaScript I would like to know if this function works correct or what problems it might have thanks in advance.
My JavaScript code (please note I use JQuery):
$(function() {
//-- Timer using web worker.
var worker = new Worker('scripts/task.js'); //External script
worker.onmessage = function(event) { //Method called by external script
$("#timeR").html(event.data)
};
};
The external script ('scripts/task.js'):
var time = -1;
function timerTick()
{
time++;
setTimeout("timerTick()",1000);
postMessage(time);
}
timerTick();
You can also view a live demo on my website.
If you're trying to reliably display seconds ticking by, then the ONLY reliable way to do that is to get the current time at the start and use the timer ONLY for updating the screen. On each tick, you get the current time, compute the actual elapsed seconds and display that. Neither setTimeout() nor setInterval() are guaranteed or can be used for accurately counting time.
You can do it like this:
var start = +(new Date);
setInterval(function() {
var now = +(new Date);
document.getElementById("time").innerHTML = Math.round((now - start)/1000);
}, 1000);
If the browser gets busy and timers are erratically spaced, you may get a slightly irregular update on screen, but the elapsed time will remain accurate when the screen is updated. Your method is susceptible to accumulating error in the elapsed time.
You can see this work here: http://jsfiddle.net/jfriend00/Gfwze/
The most accurate timer would be a comparison of two time stamps. You could increase the precision of your timer by updating more frequently (such as every 100ms). I prefer using setInterval() over setTimeout().

Counting down for x to 0 in Javascript?

I have from the backend a time on the format 00:12:54 and I display it to the screen. But, I would like to have this time to continue to go down. I have though to create a variable in javascript that will old the time and with setTimeout to loop to display with document.getElementById the new value. I think it can be problematic if I have many time to go down in same time. I might require an array?
How would you do that? If I have no other suggestion, I will try my way, but I am curious to know if it does have a more secure way to do it.
Do you know jQuery Framework? It's a Javascript framework that have a lot of utilities methods and functions that let you do Javascript stuff more easily.
Here is a count down plugin (haven't tested it).
I suggest you to download JQuery than download the plugin . Check the sample of code from the "relative" tab on the website. You can have something like :
$('#until2d4h').countdown({until: '+12M +54S'});
*The only drawback with what I suggest you is that you will require 2 .js to be added. Try to add them only when needed and you will be find.
General algorithm:
Read time from server.
Read the current time.
Call a function.
In your function, read the current time, get the delta from the initial time you read in step 2.
Subtract the delta from the initial time you read from the server in step 1 and display the remainder.
The function should call window.setTimeout to call itself in 1000ms (or adjust according to time elapsed within the function), if you want to continue counting down.
Here's a rough cut:
window.onload = function () {
var countdown_start_in_ms = 6000; // from server
function tick() {
var now = new Date().getTime();
var disp = start - now;
if (disp < 0) {
disp = 0;
}
var el = document.getElementById("countdown");
el.innerHTML =
// quick hack to format time
/(\d\d:\d\d:\d\d) ...$/.exec(new Date(disp).toUTCString())[1];
if (disp > 1000) {
var elapsed = new Date().getTime() - now;
window.setTimeout(tick, 1000 - elapsed);
} else {
// stop countdown and set color to light grey
el.style.color = "#ccc";
}
}
var start = new Date().getTime() + countdown_start_in_ms;
tick();
}
You won't like the taste of this one, but it'll do you good:
Google for 'javascript timer' and get your hands dirty reading through the various examples and tutorials returned by that search.
You'll learn a lot more than just how to write a count-down timer. :-)
Good luck!
Take a look at Grab hands and set your own time. and inspect its code. While it is written with Dojo, the "clock" part is in plain JavaScript. In your case the only difference is how to advance the counter — decrease rather than increase it.

Categories

Resources