Javascript Double moving game problome - javascript

In my game, when you die a game over screen but for some reason when you click main menu, then level one again, and move to the left or right it double moves him? Every time you click start I made it so that it resets it again just in case maybe that is why? here is the function that i think might be causing the problome?
$('#yes').click(function() {
$("#levelOne").css('margin-top', '-1520px');
$("#player").css('border', 'solid 1px green')
$("#player").css('margin-left', '223px');
$('#levelComplete').hide();
$('#levelOne').animate({
'margin-top': '+=1520px'
}, speed);
handleCollisions()
$('#startLevel1').hide();
});
link: http://jsfiddle.net/8h7n2oca/20/
Any thing helps, thanks

When the game resets, sounds like an event is being re-bound to your player (resulting in 2 duplicate events bound to your player) Make sure to unbind all relevant events on gameover / be careful in rebinding.
Thanks for the fiddle, I took at a look at your code. When you start the game, you call the function levelOne(), inside this function the following code runs:
document.addEventListener('keydown', function (evt) { /* your logic */ }
This code is binding an event listener on the keydown event to the document. When you call levelOne() after the game ends, this code runs again. Now you have two listeners bound to the document. So when you go to move your player, the code is fired twice.
Abstracting your game set up logic to a separate function to be run once on page load as suggested by GameAlchemist sounds like a good approach to prevent duplicate bindings and optimize your code.

Related

Methods to prevent triggering more than one event-functions in javascript

I have two events, one that triggers on touchstart and one that triggers on the custom event longTouch.
events: {
"touchstart .o_slide": "startDragEventHandler",
"longTouch .overview .o_slide": "slidePreview"
},
Basically, I need to make sure, that only one of the events fires at a time, to make sure, that when the users makes a longTouch to preview a slide (the slidePreview function), then the startDragEventHandler can't also be firing.
Problem is, that if the user longTouches to create e preview, but moves the finger just a little bit, then the drag functions will also initiate, messing up the UX.
Can I write code in one of the functions, that makes sure they other function will return before executing the body? Which different methods applies to this problem?

I'm having issues with clearTimeout() on a quotes rotator

I'm using this Codrops Blueprint to create a quotes rotator. I modified the rotator to have a next button, powered by the code below:
_startRotator: function() {
if (this.support) {
this._startProgress();
}
var timeout = setTimeout($.proxy(function() {
if (this.support) {
this._resetProgress();
}
this._next();
this._startRotator();
}, this), this.options.interval);
$(".testimonial-next").click($.proxy(function() {
clearTimeout(timeout);
if (this.support) {
this._resetProgress();
}
this._next();
this._startRotator();
}, this));
},
I added the .click function below the setTimeout function, and added the var to the setTimeout function.
When .testimonial-next is clicked, the rotator's timer is reset and the code in the timer is instantly executed. As far as I can tell, the timer restarts itself, so I shouldn't have to add code to do this.
On the website where this is put to use (see the "Testimonials" section), however, there seems to be a problem. There should be five quotes, in the order of Kim, Lynn, Shannon, Jennifer, and Chris. If the timer runs without being interrupted, everything works as expected. If the Next button is clicked, certain quotes seem to be skipped. Other times, the quotes stop rotating or randomly rotate at a high speed.
What am I doing wrong?
Your button click handler is attached again and again to the button, making a click result in several executions of the same code.
To solve this you can best move that piece of code out of the _startRotator function and move it somewhere where it will only be executed once.
That way, when you click, there will be only one handler that gets executed.
Less nice, but also a solution, would be to keep the code where it is, but always first remove any existing click handler, before you attach it again:
$(".testimonial-next").off('click').on('click', $.proxy(function() {
// etc...
But this is really an ugly solution. Try to move the code.

clearTimeout and clearInterval not working on mobile devices

I'm having problems getting standard javascript timers to clear on mobile devices (Android and iOS, phone and tablet).
My page contains 2 buttons, a play/pause toggle and a stop button (both FontAwesome icons), the simple HTML for which is:
<span class="fa fa-pause control-button" id="pause-button"></span>
<span class="fa fa-stop control-button" id="stop-button"></span>
The interval is initiated with the following function:
var interval = function() {
$('.control-button').fadeIn(300);
//initiate the interval
infiniteInterval = window.setInterval(Tiles.infiniteTick, speed);
};
Where speed is defined in an earlier function (default is 300). infiniteTick is a very simple function which is working fine. I haven't explained it here as it would require an explanation of the whole program but I can provide code if required.
The play and pause toggles are as follows:
$('body').on('click touchstart', '#pause-button', function() {
if ($(this).hasClass('fa-pause')) {
window.clearInterval(infiniteInterval);
$(this).removeClass('fa-pause');
$(this).addClass('fa-play');
} else {
infiniteInterval = window.setInterval(Tiles.infiniteTick, speed);
$(this).removeClass('fa-play');
$(this).addClass('fa-pause');
}
});
Finally, the interval is terminated with this (some purely aesthetic extras removed for simplicity)
$('body').on('click touchstart', '#stop-button', function() {
window.clearInterval(infiniteInterval);
$('.control-button').fadeOut(300);
});
I initially thought from researching this that it was due to click events not being properly registered, but as you can see I have added touchstart to all the click events and that has made no difference. It's working absolutely fine on all desktop browsers.
Any help is greatly appreciated, and I'd be happy to answer any further questions.
Thanks,
Ben
I've managed to fix the problem, which it turns out was twofold.
Firstly, the click event was firing twice. This was fixed using this SO question: jquery mobile click event fires twice
Secondly, I wasn't properly clearing the intervals.
Edited with #MjrKusanagi's comments
A simple call to clearInterval() before every setInterval() call has fixed the problem, making sure that the interval was always reset before starting again.
Original sketchy workaround:
I've called
infiniteInterval = null;
after every clearInterval() call, as well as wrapping the setInterval() calls with
if (infiniteInterval === null)
Thanks to everyone who commented and hopefully this will help someone sometime :)
First, your click event is firing twice because of this sentence:
$('body').on('click touchstart', '#pause-button', function() { ...
It listens to two events click and touchstart, thus it will be triggered twice, once on click event and once on touchstart event. This is also why your code works well on pc because there's no touchstart event in pc browsers.
So every time you touch that button, things happened like this:
1st event triggered
interval set, handle id is 1 (for example)
infiniteInterval = 1
2nd event triggered
another interval set, handle id is 2
infiniteInterval = 2
And now there's two timing cycles running instead of one, and you only have track of the second one. When you invoke clearInterval, only the handle id = 2 interval is cleared, and 1 is still running.
So the solution is:
Fix the twice-triggered events problem, by only listen to click. (try fastclick or zepto or other lib to deal with the click latency on mobile devices)
As your own answer said, set infiniteInterval to null, and if it is not null do not ever start another interval. (I think it is more elegant than "always clear before setting" works, as infiniteInterval works as a flag of running interval)
Hope these could solve your problem.

Understanding Threading in javascript

I have two div's in my html page
<div id="box1">
</div>
<div id="box2">
</div>
Both of them are absolutely positioned at different positions.
#box1,#box2 {
height: 100px;
width: 100px;
background-color: red;
position: absolute;
}
#box2 {
top :200px;
}
In my Javascript I am animating these two div's as shown below
$(document).ready(function() {
function animateBoxes() {
$("#box1").animate({left : "500px"},5000);
$("#box2").animate({left : "500px"},3000);
}
animateBoxes();
});
When my page loads both the div's start moving at the same time.
My question is if javascript is single threaded how can both the div's move at the same time.
Because the movement of the div's is handled by javascript by two animate functions, one on box1 and other on box2.
How both the animate functions got executed at the same time?
Javascript is single threaded meaning something if is stuck the whole script is stuck...and only way overcome this is spawn worker. To answer your question, Do You Know how animate function of jquery works...it sets timer to call function that updates div's position. So both div get positioned a little bit toward their goal. Timer is provided by javascript and is handled like an event. Javascript has event loop..which is reiterated by browser. Meaning as soon as js is done browser goes through all events and check if they have been fired and then run the function that is associated with them. Here animate function associate itself to timer event and gradually updates div's position, thus looking like it animated. And since it happens in steps the whole js doesn't have to wait for this animation to end to continue executing.
This is how events basically work in js:
browser starts executing the code..
every next action waits till last action is done.
when javascript reaches the code that is attaching function to event, js registers the event, let's say click event. Now it know that button has click event and it has this function.
Now after all code below has been executed browser starts new routine. To check for any event that have been fired.
...looping but no events..
you click button ...it adds that click event has fired to event loop check list.
browser again checks the event loop...it sees the event.
it runs the code for that event and clear it...
suppose you clicked two times...then the code of second event won't start executing till the first is done.
Timer is same but it fires every x amount of time has passed. But as you can see event loops gets stucked executing the function related to the event...the timer is not perfect.
let's say you set timer for 10 ms. And as 9ms had passed you clicked the button starting another event. So your button event starts executing..but it did something really long that took 5 ms.
so your timer actually fires at 14ms.
Take a look at this example: http://jsfiddle.net/82zLC/6/
This will give you idea that animation is divided into chunks which are update step by step...try changing t to 60.
JavaScript can act asynchronous in many situations. .animate() is an example of this. It pretty much has to act asynchronous, in order to not interrupt other page processes. If you are looking for the events to happen one-after-the-other, try looking into callbacks:
$("#box1").animate({left: "500px"},5000, function(){
$("#box2").animate({left: "500px"},5000);
});
When we pass the function to .animate(), it calls the function after it is done with the animation.

How do I prevent touchend event from apparently being "remembered" by the browser and firing subsequently at inappropriate times?

EDIT
Based on the number of views and the complete lack of responses I have to assume that I did a poor job of communicating my issue. I'm going to try to rectify that now.
I extended the HTMLElement prototype with a new tap method like so:
HTMLElement.prototype.tap = function (func) {
this.addEventListener("touchend", func, false);
};
I also created a custom tap event in jQuery:
$(document).delegate("*", "touchend", function (e) {
$(this).trigger("tap");
});
I also created a jQuery plugin called tap:
$.fn.tap = function (func) {
this.bind("tap", func);
};
If I try to use any of these with a callback function that includes an alert statement the callback executes twice. I tap the element to pop up the alert. I tap the "OK" button in the alert to close it. The next time I tap the screen no matter how long I wait the alert pops up again. This time tapping the "OK" button doesn't seem to set up another repeat.
However if the callback function doesn't include an alert statement (e.g. I use a console.log statement instead) the callback only executes the one time.
Does anyone know a way to deal with this? I'm about to try unhooking the event handler from within itself and then rebinding it afterwards, but that's nothing more than a hack if it's even successful.
I'd rather do things the "right" way. :-)
ORIGINAL
I just finished writing a "tap" function that I can use by extending the HTMLElement or Element prototypes as well as a custom "tap" event and "tap" plugin both for jQuery. I thought I had this in the bag until I decided to use a simple alert statement as test code.
When I use these with some element on my test page, they fire properly when I first "tap" the element, but the problem arises after I touch the alert's "OK" button and then, any amount of time later, tap the screen again at which point the event handler fires a second time.
At first I thought it was my custom code, but when I tried it with the following very basic JavaScript I was able to replicate the exact same issue.
document.getElementById("some-element").ontouchend = function (e) {
alert("Howdy doody!");
};
I imagine it must have something to do with the fact that I have to touch the screen again to execute the "OK" on the alert while still technically "inside" the event handler (since the alert is in effect "blocking" the completion of the handler function).
The fact that the behavior isn't replicated with the following slightly different code seems to support my imagination. :-)
document.getElementById("some-element").ontouchend = function (e) {
console.log("Howdy doody!");
};
If I include the above code in a page and touch that element after the callback fires I won't get a repeated firing of that callback function as opposed to the previous block of code where I'll see the alert pop up a second time the next time I tap the screen after hitting "OK" no matter where on the page I tap.
A strange issue indeed, and I haven't been able to find any information about why this might be happening. Does anyone have an idea what is happening?
I believe the visual, full-page alert being triggered on touch end is interfering with the touch event cycle. Try to call the alert after yielding to the DOM. eg.
setTimeout(function() {
alert('btn clicked');
}, 0);

Categories

Resources