Javascript glitchy game - javascript

I have a game and when you hit the Obs's you get a game over screen. On it has a retry button and it resets it, it works most of the time but after the third or fourth retry it does not reset it. It just keeps it where it is. Why does it do that? Below is the code I used for the reset and a link. Thanks.
if (collides($(value), $('#player'))) {
$('#levelOne').stop();
$('#player').css('border', 'solid 1px yellow');
//GAME OVER SCREEN START
$('#GameOver').fadeIn();
$('#retry').click(function () {
$('#GameOver').fadeOut();
// NEW LOGIC
$("#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()
});
}
http://jsfiddle.net/38bod36e/101/

You are constantly adding click event listeners in the handleCollisions function (this part: $('#retry').click(function () {), which is bound to kill your performance sooner or later because the number of events created/called will get insanely big. That is something you need to take care of to get rid of the glitches.
I moved the click handler function outside and it works just fine. I've also disabled the console log on every frame because it kills the performance as well.
See it here: http://jsfiddle.net/38bod36e/103/
Be careful with stuff like that if you want a consistent performance. See in the console how the number of events grows with every frame rendered in your original code: http://jsfiddle.net/38bod36e/105/

Related

getBoundingClientRect during throttled scroll event handling

I faced an issue during my project developing, it's related to a difference between getBoundingClientRect values with and without preventive break points during debugging. Trying to minimize repro, I got following.
const scrollHandler = () => {
setTimeout(() => {
const top = document.getElementById('test').getBoundingClientRect().top;
console.log(top);
});
};
document.getElementById('viewport').addEventListener('scroll', scrollHandler);
where the viewport is just scrollable div with fixed height. The content of the viewport is big enough to be able to fire at least one scroll event. I also created Plunker demo. All magic happens inside of setTimeout callback.
Now the steps. Success scenario.
Set break point at the beginning of the setTimeout callback.
Fire scroll event.
Make "step over" to obtain top value.
Execute document.getElementById('test').getBoundingClientRect().top in the console.
The results of 3 and 4 are the same.
Failed scenario.
Set break point at the end of the setTimeout callback.
Fire scroll event.
Get the value of top variable (no action is needed).
Execute document.getElementById('test').getBoundingClientRect().top in the console.
The results of 3 and 4 are not the same.
To avoid any misunderstanding with this repro, I recorded a short demo movie with the above steps.
In my project I'm doing calculations in a similar environment (throttled scroll events) and getting wrong results that don't match expectations. But when I debug it, I'm getting different picture; a preventive break point fixes calculations.
Is it a bug or known issue? Or did I miss something? should I refuse to use getBoundingClientRect in such a situation?
I'm not sure what it is that you are looking for but assume your animation on scroll isn't working as expected.
There is a tip on throttling scroll here that is incorrect. Let's say you throttle to every 30 milliseconds. If page stops scrolling 25 milliseconds after last animation then you're stuck with a scroll position 25 milliseconds before it stopped scrolling.
Maybe a better way to do it is this (can test in the console on this page):
var ol = document.querySelectorAll("ol")[2];
window.onscroll = ((lastExecuted)=>{
const expensiveHandler = e => {
lastExecuted=Date.now();
//do some animation maybe with requestAnimationFrame
// it may prevent overloading but could make animation
// glitchy if system is busy
console.log("1:",ol.getBoundingClientRect().top);
};
var timerID
return e=>{
if(Date.now()-lastExecuted>19){
//only animate once every 20 milliseconds
clearTimeout(timerID);
expensiveHandler(e);
}else{
//make sure the last scroll event does the right animation
// delay of 20 milliseconds
console.log("nope")
clearTimeout(timerID);//only the last is needed
timerID=setTimeout(e=>expensiveHandler(e),20);
}
}
})(Date.now())

How to deal with over 100 moving rectangles without lag

I have this fiddle : https://jsfiddle.net/reko91/e6uwqnof/2/
On button press it creates 50 rectangles that all move down towards the bottom of the screen.
for(i=0;i<50;i++){
enemyArray.push(new enemy(normalBullet.x+i*5, normalBullet.y, normalBullet.speed, 1, 10, "#F00"));
}
Works fine on first click, but once I start adding more, it really starts to lag. Is there a best of practice way of dealing with hundreds of moving elements ? Or is HTML and Javascript not the best language to deal with this amount of moving data ?
Your main problem is in the update function:
function update() {
// enemy.update();
//if (keystate[SpaceBar]) {
$('#newEnemy').click(function() {
createNewEnemy()
})
//...
}
Probably a mistake, but you're attaching the event every time update gets called, which is 60 times per seconds! (Until it can't do it anymore, that is.)
This means that every time you press the button, you generate a ton of elements right in the canvas.
Move the event listener addition outsite update and you're golden.
You are assigning button pushes inside the frame loop, so when you push it, it's actually calling the button push however many times the loop has run.
Move this code outside:
$('#newEnemy').click(function() {
console.log("createEnemy");
createNewEnemy()
});

SetInterval loop relatively confusing to me

HTML
<div id="backspace" ng-click="deleteString(''); decrementCursor();">
JS
<script>
$scope.deleteString = function() {
if($scope.cursorPosVal > 0){
//$scope.name = $scope.name - letter;
$scope.name = [$scope.name.slice(0, $scope.cursorPosVal - 1) + $scope.name.slice($scope.cursorPosVal)].join('');
console.log($scope.name);
setTimeout(function(){ setCaretPosition("inputBox", $scope.cursorPosVal); }, 30);
} else {
$scope.cursorPosVal = 1;
}
};
</script>
I am designing an on screen touchscreen keyboard. This is my backspace button. I am going to make it so that when you click and hold the backspace button, it starts removing characters automatically. I don't know where to begin with creating a setInterval, and I know a setInterval is exactly what I need to use here.
If I'm not wrong, you want that while you're keeping your button pressed, a function repeats itself.
You're right with setInterval(). However, the way you manage the event is wrong.
Take a look at this fiddle (It's not your code, but a simple example is the best way to understand):
http://jsfiddle.net/daq9atdd/1/
$(function(){
var interval = null;
$('#myButton').mousedown(function(){
interval = setInterval(function(){
console.log('Hello !');
}, 250);
});
$('#myButton').mouseup(function(){
clearInterval(interval);
});
});
I start the interval when the button is pressed, store it, and clear it when the button is released.
You’re so sure about setInterval.
If browser briefly hangs for whatever reason (say some background task), setInterval would go on queueing your backspace calls until it has some CPU time. This means user may see no change and hold backspace longer than needed, and then see a whole bunch of characters suddenly vanish when browser is back to normal.
Thus by setting a timeout after every call you’re making sure user won’t remove more characters than needed. Might be important if the goal is to improve UX.
Example implementation with AngularJS directives and setTimeout
See also:
setTimeout or setInterval?
noKid’s fiddle updated with setTimeout in mind

Jquery Cycle changing options on the fly

I want to change the options for jquery cycle dynamically on the page. Specifically, I want the speed to drop. According to one of it's creator, you can use 'cycle.opts' to do this. In my example I have specifically
$('.cycle-streams').cycle({
fx: 'scrollVert',
continuous: 1,
speed: 1000,
delay: 0,
easing: 'linear'
});
var changedOpts = $('.cycle-streams').data('cycle.opts');
$('.cycle-streams').mouseover(function() {
var changedOpts = $('.cycle-streams').data('cycle.opts');
changedOpts.speed = 1000000000000;
$('.cycle-streams').data('cycle.opts', changedOpts);
});
I've been working on this for some time now and am lost as to what I'm doing wrong. Any help would be appreciated. The jsfiddle is here... http://jsfiddle.net/bmXgj/
I changed your fiddle to this:
var changedOpts = $('.cycle-streams').data('cycle.opts');
$('.cycle-streams').mouseover(function() {
//hover in
$('.cycle-streams').cycle('pause');
changedOpts.speedIn = 500;
changedOpts.speedOut = 500;
$('.cycle-streams').cycle('next');
$('.cycle-streams').cycle('resume');
});
$('.cycle-streams').mouseout(function() {
//hover out
$('.cycle-streams').cycle('pause');
changedOpts.speedIn = 3000;
changedOpts.speedOut = 3000;
//$('.cycle-streams').cycle('next');
$('.cycle-streams').cycle('resume');
});​
I noticed that you were re-declaring 'changedOpts' for some reason. When I watched this variable in the console, it was coming out as undefined. Since you already defined it I just kept using it.
also you were never resetting the state of the cycle. I added pause and resume. It appears to work now but it is not perfect. The last side needs to clear before the new speeds will be used, so drastic jumps (3000 to 500 for example) allow for a noticeable delay when trying to speed up. I also added a next statement.
I noticed that when the plugin was handling next it was clearing the timeouts. So I figured if I stored the remaining time (Pause), then moved to the next slide (next), then resumed the show (resume) that the time would be restored. This seems to be working.
The 'next' action, is not needed when going from fast to slow because you will not usually notice the 'orphan' slide when leaving the container because it is cycling quickly. I put it in there for good measure in case your speeds are not that far apart.
Also I noticed you were only changing one speed. I am assuming, without looking at the guts of the plugin, that the 'speed' option is used at initialization only. After adding the other two speeds I got the right action. After reviewing the 'guts' of the plugin, I am certain that the speed option is used for synchronizing the other two speeds. If they all do not match you may get out of sync. The initialization code uses the 'speed' to set 'speedIn' and 'speedOut', so we need to change those two to affect the 'running' speed.
http://jsfiddle.net/bmXgj/6/
EDIT: did not need to pause and resume.
EDIT2: I did need the pause and resume, but I also needed a next. Also the 'speed' option can be ignored once it is set the first time to start the cycle. It appears to be shorthand for speedIn = speedOut = X

How can I reveal content and maintain its visibility when mousing to a child element?

I'm asking a question very similar to this one—dare I say identical?
An example is currently in the bottom navigation on this page.
I'm looking to display the name and link of the next and previous page when a user hovers over their respective icons. I'm pretty sure my solution will entail binding or timers, neither of which I'm seeming to understand very well at the moment.
Currently, I have:
$(document).ready(function() {
var dropdown = $('span.hide_me');
var navigator = $('a.paginate_link');
dropdown.hide();
$(navigator).hover(function(){
$(this).siblings(dropdown).fadeIn();
}, function(){
setTimeout(function(){
dropdown.fadeOut();
}, 3000);
});
});
with its respective HTML (some ExpressionEngine code included—apologies):
<p class="older_entry">Older<span class="hide_me">Older entry:
<br />
{title}</span></p>
{/exp:weblog:next_entry}
<p class="blog_home">Blog Main<span class="hide_me">Back to the blog</span></p>
{exp:weblog:prev_entry weblog="blog"}
<p class="newer_entry">Newer<span class="hide_me">Newer entry:
<br />
{title}</span></p>
This is behaving pretty strangely at the moment. Sometimes it waits three seconds, sometimes it waits one second, sometimes it doesn't fade out altogether.
Essentially, I'm looking to fade in 'span.hide_me' on hover of the icons ('a.paginate_link'), and I'd like it to remain visible when users mouse over the span.
Think anyone could help walk me through this process and understand exactly how the timers and clearing of the timers is working?
Thanks so much, Stack Overflow. You guys have been incredible as I walk down this road of learning to make the internet.
If you just want to get it working, you can try to use a tooltip plugin like this one.
If you want to understand how this should be done: first, get rid of the timeout, and make it work without it. The difference (from the user's point of view) is very small, and it simplifies stuff (developing and debugging). After you get it working like you want, put the timeout back in.
Now, the problem is you don't really want to hide the shown element on the navigator mouse-out event. You want to hide it in its own mouse out event. So I think you can just pass the first argument to the navigator hover function, and add another hover to dropdowns, that will have an empty function as a first argument, and the hiding code in its second argument.
EDIT (according to your response to stefpet's answer)
I understand that you DO want the dropdown to disappear if the mouse moves out of the navigator, UNLESS its moved to the dropdown itself. This complicates a little, but here is how it can be done: on both types of items mouse-out event, you set a timer that calls a function that hides the dropdown. lets say the timer is 1 second. on both kind of item mouse-in even, you clear this timer (see the w3school page on timing for syntax, etc). plus, in the navigator's mouse-in you have to show the dropdown.
Another issue with the timer in your code is that it will always execute when mouse-out. Due to the 3 seconds delay you might very well trigger it again when mouse-over but since the timer still exist it will fade out despite you actually have the mouse over the element.
Moving the mouse back and forth quickly will trigger multiple timers.
Try to get it to work without the timer first, then (if really needed) add the additional complexity with the delay (which you must keep track of and remove/reset depending on state).
Here was the final working code, for anyone who comes across this again. Feel free to let me know if I could have improved it in any ways:
$(document).ready(function() {
var dropdown = $('span.hide_me');
var navigator = $('a.paginate_link');
dropdown.hide();
$(navigator).hover(function(){
clearTimeout(emptyTimer);
$(this).siblings(dropdown).fadeIn();
}, function(){
emptyTimer = setTimeout(function(){
dropdown.fadeOut();
}, 500);
});
$(dropdown).hover(function(){
clearTimeout(emptyTimer);
}, function(){
emptyTimer = setTimeout(function(){
dropdown.fadeOut();
}, 500);
});
});

Categories