Dom element infinitely incrementing - javascript

I'm in my first steps of creating an auto aim system for the enemy bot but I can't even seem to get him to shoot properly.
I create a div element, and move it in a direction. This happens every 4 seconds. I delete the div before the next one gets created. This works. But somehow it creates more and more elements over time and soon turns into a massive amount of divs all flying in the same direction.
** make the bullet here **
function makeBullet() {
if (player.enemy) {
if (player.enemyBullet.bulletInterval == true) {
console.log("working");
player.enemyBullet.bullet = document.createElement('div');
player.enemyBullet.bullet.className = 'bullet';
gameArea.appendChild(player.enemyBullet.bullet);
player.enemyBullet.bullet.x = player.enemy.x;
player.enemyBullet.bullet.y = player.enemy.y;
player.enemyBullet.bullet.style.left = player.enemyBullet.bullet.x + 'px';
player.enemyBullet.bullet.style.top = player.enemyBullet.bullet.y + 'px';
player.enemyBullet.bulletInterval = false;
setInterval(function () {
player.enemyBullet.bulletInterval = true;
}, 4000);
}
}
}
** Move Bullet **
function moveBullet() {
let bullets = document.querySelectorAll('.bullet');
bullets.forEach(function (item) {
item.x += 3;
item.y -= 3;
item.style.left = item.x + 'px';
item.style.top = item.y + 'px';
if(item.y < 200){
item.parentElement.removeChild(item);
player.enemyBullet.bullet = null;
}
})
}
** invoked in request Animation function **
function playGame() {
if (player.inplay) {
moveBomb();
moveBullet();
makeBullet();
window.requestAnimationFrame(playGame);
}
}
** Initiate interval boolean here **
let player = {
enemyBullet: {
bulletInterval: true
}
}
** LINK TO JS FIDDLE FULL PROJECT ** (click here to see what's happening)
https://jsfiddle.net/mugs17/j7f12a0n/

You are using setInterval like set timeout. However setInterval does not only execute one time. Once you've called setInterval the first time, calling it again makes a new different interval that also executes every 4 seconds.
So each time your function gets invoked its creating a new Interval which is why your div elements are increasing as time goes on
Instead wrap the entire create bullet code inside setInterval and make it execute only once by setting a boolean conditional and then immediately changing that conditional to false. Like this:
if (player.enemy) {
if (player.enemyBullet.bulletInterval == true) {
player.enemyBullet.bulletInterval = false;
console.log("working");
setInterval(function () {
player.enemyBullet.bullet = document.createElement('div');
player.enemyBullet.bullet.className = 'bullet';
gameArea.appendChild(player.enemyBullet.bullet);
player.enemyBullet.bullet.x = player.enemy.x;
player.enemyBullet.bullet.y = player.enemy.y;
player.enemyBullet.bullet.style.left = player.enemyBullet.bullet.x + 'px';
player.enemyBullet.bullet.style.top = player.enemyBullet.bullet.y + 'px';
}, 4000);
}
}
}

Related

JS: setInterval running as if there were multiple intervals set

So, I've been trying to figure out JS, and what better way to do so than to make a small project. It's a small trivia game, and it has a question timer I've made using setInterval. Unfortunately, after answering multiple questions, the interval's behaviour gets very weird - it runs the command twice every time. I guess it's my faulty implementation of buttonclicks?
By the way, if my code is awful I am sorry, I've been desperate to fix the issue and messed with it a lot.
function startGame(){
if (clicked === true){
return;
}
else{
$("#textPresented").html("Which anthem is this?");
$("#button").css("display", "none");
currentCountry = getRndInteger(0,8);
console.log(currentCountry);
var generatedURL = anthemnflags[currentCountry];
console.log(generatedURL);
audios.setAttribute("src", generatedURL);
audios.play();
$("#button").html("I know!");
$("#button").css("display", "block");
$("#button").click(function () {
continueManager();
});
y=10;
console.log("cleared y" + y);
x = setInterval(function(){
y = y - 1;
console.log("Counting down..." + y)
}, 1000);
console.log("INTERVAL SET");
}
}
Here is the console output:
cleared y10 flaggame.js:59:17
INTERVAL SET flaggame.js:64:17
AbortError: The fetching process for the media resource was aborted by the user agent at the user's request. flaggame.js:49
Counting down...9 flaggame.js:62:20 ---- THESE TWO ARE BEING PRINTED AT THE SAME TIME
Counting down...8 flaggame.js:62:20 ---- THESE TWO ARE BEING PRINTED AT THE SAME TIME
Counting down...7 flaggame.js:62:20
Counting down...6 flaggame.js:62:20
Counting down...5 flaggame.js:62:20
Counting down...4 flaggame.js:62:20
Counting down...3 flaggame.js:62:20
Counting down...2 flaggame.js:62:20
Counting down...1 flaggame.js:62:20
Counting down...0
THE REST OF MY CODE:
function middleGame(){
$("#button").css("display", "none");
var n = document.querySelectorAll(".flagc").length;
correctIMG = getRndInteger(0,n-1);
showFlags();
var taken = new Array();
for (var i = 0; i < n; ++i){
if (i === correctIMG){
images[i].attr("src", "res/" + flagsfiles[currentCountry]);
taken[currentCountry] = true;
}
else{
var randomFlag = getRndInteger(0, flagsfiles.length);
if (randomFlag !== currentCountry && taken[randomFlag] !== true){
images[i].attr("src", "res/" + flagsfiles[randomFlag]);
taken[randomFlag] = true;
}
}
}
$(".flagc").click(function(){
clickregister(this);
});
}
function continueManager(){
if (!clicked){
audios.pause()
clearInterval(x);
x = 0;
clicked = true;
middleGame();
return;
}
}
function clickregister(buttonClicked){
if ($(buttonClicked).attr("id") != correctIMG){
points = points - 1;
flagARR[$(buttonClicked).attr("id")].css("display", "none");
console.log("INCORRECT");
}
else{
if (y >= 0) {
var addedPoints = 1 + y;
points = points + addedPoints;
$("#points").html(points);
}
else{
points = points + 1;
}
hideFlags();
clicked = false;
startGame();
}
}
$(function(){
hideFlags();
$("#textPresented").html("When you're ready, click the button below!");
$("#button").html("I am ready!");
$("#button").click(function () {
if (!gameStarted){
gameStarted = true;
alert("STARTING GAME");
startGame();
}
});
});
Basically this is how it works:
When the "I am ready" button is clicked, startGame() is called. It plays a random tune and counts down, until the player hits the "I know" button. That button SHOULD stop the interval and start the middleGame() function, which shows 4 images, generates a random correct image and awaits input, checks if it's true, then launches startGame() again.
The first and second cycles are perfect - after the third one things get messy.
I also noticed that the "INCORRECT" log gets printed twice, why?
EDIT: here is the minimized code that has the same issue:
var x;
var gameStarted = false;
var y;
var clicked;
$(function(){
$("#button").click(function () {
if (!gameStarted){
gameStarted = true;
startGame();
}
});
});
function startGame(){
console.log("startgame()");
if (clicked === true){
return;
}
else{
console.log("!true");
$("#button").css("display", "block");
$("#button").click(function () {
continueManager();
});
y=10;
x = setInterval(function(){
y = y - 1;
console.log(y);
}, 1000);
}
}
function continueManager(){
if (!clicked){
clearInterval(x);
x = 0;
clicked = true;
middleGame();
return;
}
}
function middleGame(){
$("#button").css("display", "none");
var taken = new Array();
$(".flagc").click(function(){
clickregister(this);
});
}
function clickregister(buttonClicked){
console.log("clickgregister");
//Irrelevant code that checks the answers
clicked = false;
startGame();
}
EDIT2: It appears that my clickregister() function gets called twice, and that function then calls startGame() twice.
EDIT3: I have found the culprit! It's these lines of code:
$(".flagc").click(function(){
console.log("button" + $(this).attr("id") + "is clicked");
clickregister(this);
});
They get called twice, for the same button
I fixed it!
It turns out all I had to do was to add
$(".flagc").unbind('click');
Before the .click() function!
You need to clear the interval first then call it again. You can do that by creating a variable outside of the event listener scope and in the event listener check if the variable contains anything if yes then clear the interval of x. After clearing the interval you can reset it.
Something like this:
<button class="first" type="submit">Button</button>
const btn = document.querySelector('.first');
let x;
btn.addEventListener("click", () => {
x && clearInterval(x)
x = setInterval(() => console.log("yoo"), 500)
})
This is because if you don't clear the interval of x it will create a new one on every button press.

Using animate.css (link in description) how do I trigger an animation when a particular event is finished

I have an an image moving across the screen and out of viewport, when the image reaches a particular absolute position (right: - 200), I want to trigger the below animation. I am relatively new to programming, not sure how to track when a particular function is done so that I can trigger the below animation.
var $startLessonButton = $('.startLessonButtonUp');
$startLessonButton.mouseup(function() {
$(this).addClass('animated slideInLeft');
});
---------
var movingOutAnimationCounter = 2;
var movingOutCurrentPosition = window.innerWidth / 2 - 200
function moveTrumpOut() {
movingOutCurrentPosition -= 2;
trumpyWrapper.style.right = movingOutCurrentPosition + 'px';
if (movingOutAnimationCounter < 9 ) {
trumpy.src = '../images/trump_walking_out_' + movingOutAnimationCounter + '.png';
movingOutAnimationCounter += 1;
} else {
movingOutAnimationCounter = 1;
trumpy.src = '../images/trump_walking_out_' + movingOutAnimationCounter + '.png';
}
if (movingOutCurrentPosition > -200 ) {
requestAnimationFrame(moveTrumpOut);
}
}
All the best!
If you know time, when moving element is hidden, you can use this function:
setTimeout(function(){ $('.elem').addClass("animCssClass") }, 1000);
Last parameter, in this example: 1000 is time in ms, when function inside should execute. Run this function on mouseup when you adding class to moving element.

skip timer in JavaScript interval

I currently have a function that executes some code within a setInterval method. This is working as expected. The problem is I conditionally execute code within this timer. If the condition is not met it will still wait the timeout until trying again. Is there a way of 'skipping' the delay and only executing it when the condition is met.
You will notice in my demo there is a prolonged delay between outputting paragraph results 4 and 8 (as its delaying in between the checks). I would like there to be a consistent delay throughout the whole procedure.
DEMO https://jsfiddle.net/jdec4h0x/
var intAdd = setInterval(function() {
refIndex++
if(refIndex >= predefinedMaxLimit) {
refIndex = 0;
loopedThrough = true;
}
// if this exists then increment refIndex and try again
if (loopedThrough || !$(".myclass[data-mydata1='" + predefinedData2 + "'][data-mydata2='" + refIndex + "']").length) {
counter++;
$('p').last().after('<p>IN Cond Ref = ' + refIndex + '</p>');
// ** js code within this tiemout **
if (counter >= predefinedOutputP) clearInterval(intAdd);
}
}, 500);
You can't change the delay of the interval. Either you destroy and create an interval as Kevin B said or you use setTimeout, which you have to call every time anyway, and then use a delay or another depending on a condition.
/* ... */
if (conditionIsMet) intAdd = setTimeout(function() {}, 1000);
else intAdd = setTimeout(function() {}, 1);
/* ... */
An example here
There are multjple approaches as pointed out by other users.
I would use setTimeout. I'd put this in a function that resides within a loop. You can do this with a while loop. This then gives the the ability to break out when the condition is met. you will need to increment the timer on each loop.
Fiddle https://jsfiddle.net/jdec4h0x/4/
while (progress) {
refIndex++
if (refIndex >= predefinedMaxLimit) {
refIndex = 0;
loopedThrough = true;
}
if (loopedThrough || !$(".myclass[data-mydata1='" + predefinedData2 + "'][data-mydata2='" + refIndex + "']").length) {
counter++;
myTimer = myTimer + 500;
console.log(refIndex);
myFunction(refIndex);
if (counter >= predefinedOutputP) {
$('p').last().after('<p>Cleared Interval</p>');
progress = false;
}
}
}
function myFunction(ref) {
setTimeout(function() {
$('p').last().after('<p>IN Cond Ref = ' + ref + '</p>');
// ** js code within this tiemout **
}, myTimer)
}

Image animation with speed control

We have some problem with our image animation with speed control.
It make use of a timeout to change the image, but we want to change the timeout value with a slider, but for some sort of reason, it doesn't work. Can someone help us out ?
We have a Jfiddle here: http://jsfiddle.net/Kbroeren/fmd4xbew/
Thanks! Kevin
var jArray = ["http://www.parijsalacarte.nl/images/mickey-mouse.jpg", "http://www.startpagina.nl/athene/dochters/cliparts-disney/images/donad%20duck-106.jpg", "http://images2.proud2bme.nl/hsfile_203909.jpg"];
var image_count = 0;
function rollover(image_id, millisecs) {
var image = document.getElementById(image_id);
image.src = jArray[image_count];
image_count++;
if (image_count >= jArray.length) {
image_count = 0;
}
var timeout = setTimeout("rollover('" + image_id + "'," + millisecs + ");", millisecs);
}
rollover("img1", 200);
$(function () {
var value;
var $document = $(document),
$inputRange = $('input[type="range"]');
// Example functionality to demonstrate a value feedback
function valueOutput(element) {
var value = element.value,
output = element.parentNode.getElementsByTagName('output')[0];
output.innerHTML = value;
}
for (var i = $inputRange.length - 1; i >= 0; i--) {
valueOutput($inputRange[i]);
};
$document.on('change', 'input[type="range"]', function (e) {
valueOutput(e.target);
rollover("img1", 200);
});
// end
$inputRange.rangeslider({
polyfill: false
});
});
You keep creating more and more infinite function calls without stopping them.
After you call your function the first time, it keeps calling itself.
then you call it again with different interval (millisecs) and it will also start call itself....
You can try two different approach.
1.Use setInterval instead of setTimeout. Use clearInterval to clear the interval before setting it with a new value.
/// Call animation() every 200 ms
var timer = setInterval("Animation()",200);
function ChageSpeed(miliseces){
///Stop calling Animation()
clearInterval(timer);
/// Start calling Animation() every "miliseces" ms
timer = setInterval("Animation()",miliseces);
}
function Animation(){
/// Animation code goes here
}
2.Or, Instead, Set your interval as a global variable (not cool) and just change it value when the user want to change the animation speed.
var millisecs = 200;
function rollover(image_id) {
var image = document.getElementById(image_id);
image.src = jArray[image_count];
image_count++;
if (image_count >= jArray.length) {
image_count = 0;
}
var timeout = setTimeout("rollover('" + image_id + "'," + millisecs + ");", millisecs);
}
$document.on('change', 'input[type="range"]', function (e) {
valueOutput(e.target);
millisecs = YourNewValue;
});

Setting a time for flicker animation on img

I'm using this code to make my logo flicker on my website. But It becomes annoying when it continues to flicker while browsing, how can I set a time to allow it to flicker for something like the first 15seconds on page load, then stops?
JS code I'm using:
$(document).ready(
function(){
var t;
const fparam = 100;
const uparam = 100;
window.flickr = function(){
if(Math.round(Math.random())){
$("#logodcoi").css("visibility","hidden");
t = setTimeout('window.unflickr()',uparam);
}
else
t = setTimeout('window.flickr()',fparam);
}
window.unflickr = function(){
if(Math.round(Math.random())){
$("#logodcoi").css("visibility","visible");
t = setTimeout('window.flickr()',fparam);
}
else
t = setTimeout('window.unflickr()',uparam);
}
t = setTimeout('window.flickr()',fparam);
});
You could have a counter, which you then use to decide whether you want to set another timeout. As a side note, you should never add functions to window and then passing a string to setTimeout. Always just pass the function itself:
$(document).ready(function(){
var t;
var amount = 0;
const fparam = 100;
const uparam = 100;
function timeout(f, t) { // this function delegates setTimeout
if(amount++ < 150) { // and checks the amount already (un)flickered
setTimeout(f, t); // (150 * 100 ms = 15 s)
}
}
var flickr = function(){
if(Math.round(Math.random())){
$("#logodcoi").css("visibility","hidden");
t = timeout(unflickr,uparam);
}
else
t = timeout(flickr,fparam);
};
var unflickr = function(){
if(Math.round(Math.random())){
$("#logodcoi").css("visibility","visible");
t = timeout(flickr,fparam);
}
else
t = timeout(unflickr,uparam);
};
t = timeout(flickr,fparam);
});
I see you're using jquery, you could use the following, if I remember correctly, all the stuff I use below has been in jquery since 1.0, so you should be good:
counter = 1;
function hideOrShow(){
$(".classToSelect").animate({"opacity": "toggle"}, 100);
counter = counter +1;
if (counter >= 21) clearInterval(flickerInterval);
}
flickerInterval = setInterval(hideOrShow, 100);
Change the selector, animation duration, and variable names to whatever you fancy/need.

Categories

Resources