I'm still struggling with my simple javascript game. Here is my previous question: Simple javascript game, hide / show random square
Some square show and hide randomely for a few seconds and you have to click on them. I use RaphaelJS to draw the square and a few of JQuery ($.each() function)
I can't make the hide/show with the setInterval working for each square. The function made by Mishelle looks good but I get a "This is not a function" error.. I've test different stuff but it's not as obvious as I thought :/
window.onload = function() {
var paper = new Raphael(document.getElementById('canvas_container'), 500, 500);
// random function to for the x and y axis of the square
function random(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var rectanglemain = paper.rect(0, 0, 500, 500).attr({fill: "white",});
var win_click = 0; // set the var to count the click on the square
var recs = [];
for(var i = 0; i < 50; i++) {
var x = random(1,450);
var y = random(1,450);
var rec = paper.rect(x, y, 50, 50).attr({fill: 'blue'});
recs.push(rec); // add the square in an array
recs[i].click(function () {
//counting the clicks
win_click = win_click + 1;
})
function hideSquare() {recs[i].hide();}
hideSquare();
}
rectanglemain.click(function () {
alert('you click on ' + win_click + ' squares');
});
/* here is a function made by Mishelle on my previous question, unfortunately I can't make it work (this is not a function error).
function showBriefly (timeFromNow, duration) {
window.setTimeout(this.rec.show, timeFromNow);
window.setTimeout(this.rec.hide, timeFromNow + duration);
}
recs[2].showBriefly(1000, 3000); to test the function
*/
}
Thanks for the help :)
try
window.setTimeout(function(){this.rec.show();}, timeFromNow )
Just came across your problem, just in case you read this and you want to know what was the problem. this is undefined within the callback, thus you need to store which rectangle you were referring to in a variable (I've called it square), see my code:
showBriefly: function(timeFromNow, duration) {
square = this.box;
setTimeout(function(){square.show();}, timeFromNow )
setTimeout(function(){square.hide();}, timeFromNow + duration )
}
Cheers
Related
I am using Leaflet to add 3 markers on a floor plan. It works fine. then I tried to let Math.random to produce the coordinates in pixels every 3 secs, remove the old marker and add a new marker. But I found the setTimeout() doesn't work. I tried many solutions, all failed. Please could you guide?
one more question: the control.scale doesn't work either. The scale is still at the bottomleft and ft bar is still there.
I am using Leaflet to add 3 markers on a floor plan. It works fine. then I tried to let Math.random to produce the coordinates in pixels every 3 secs, remove the old marker and add a new marker. But I found the setTimeout() doesn't work. I tried many solutions, all failed. Please could you guide?
one more question: the control.scale doesn't work either. The scale is still at the bottomleft and ft bar is still there.
<script>
var map = L.map('map', {
crs: L.CRS.Simple,
Zoom: 0,
maxZoom:16,
minZoom: -5
});
var bounds = [[0,0], [1079,2159]]; // [y, x]
var image = L.imageOverlay('officemap.jpeg', bounds).addTo(map);
map.setView( [539,1075], 0); // ([y , x] , zoom)
map.fitBounds(bounds);
//L.control.scale('topleft', '50', 'True', 'False', 'True' ).addTo(map); // doesn't work !!!
L.control.scale().addTo(map);
var yx = L.latLng;
var xy = function(x, y) {
if (L.Util.isArray(x)) { // When doing xy([x, y]);
return yx(x[1], x[0]);
}
return yx(y, x); // When doing xy(x, y);
};
function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var sol = xy(1079, 539);
//var mizar = xy(2159, 1079);
//var mizar = xy(getRandomIntInclusive(0, 2159), getRandomIntInclusive(0, 1079));
var kruegerZ = xy(0, 0);
var maker_text="I am good!!!";
//var maker_text_array =['Name:', 'Age:', 'Group:'];
L.marker(sol).addTo(map).bindTooltip( 'Sol');
L.marker(kruegerZ).addTo(map).bindTooltip(maker_text);
//var previous_maker=null;
var current_marker=null;
/*
function sleep(milliseconds) {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
};
*/
var i="100";
var mizar = xy(getRandomIntInclusive(0, 2159), getRandomIntInclusive(0, 1079));
current_marker=L.marker(mizar).addTo(map).bindTooltip(i);
function del_add(){
alter("in set");
map.removeLayer(current_marker);
mizar= xy(getRandomIntInclusive(0, 2159), getRandomIntInclusive(0, 1079));
current_marker=L.marker(mizar).addTo(map).bindTooltip("I am OK");
};
//for(var j=0; j<10; j++){
setTimeout("del_add()", 100);
//};
//alert("done");
// var travel = L.polyline([sol, deneb]).addTo(map);
</script>
Change
setTimeout("del_add()", 100);
To
setTimeout(del_add, 100);
Firstly setTimetout takes two arguments, first one is function (not a string as in your example) and second one is time in ms.
If you just removed the quotes it would immediately trigger the function. It would be equivalent to this:
setTimetou(det_all(), 100);
// Equivalent to:
const foo = det_all();
setTimetou(foo, 100);
Wheres if you remove the round brackets you get equivalent to this
setTimetou(det_all, 100);
// Equivalent to:
setTimeout(() => det_all(), 100);
And this is what you need!
As I said setTimeout takes fucntion. If you wrinte foo() you immediately invoke the function and with combination with setTimeout(foo()) you are passing the result of the function to the setTimetou instead of the function itself
I am trying to create something like a Grid-Image-Box-Slider. Now what I am trying to achieve is that after a period of time (e.g 5 seconds) one of the images will be changed randomly. So, my script follows:
var currentImages = [1, 2];
(function imgCarousel() {
var min = 1;
var max = 6;
currentImgSlot = pickImageSlot();
var pickedImage = pickImage();
setTimeout(function () {
console.log("Image Slot: " + currentImgSlot + "<br> Image: " + pickedImage);
//var bgImgElem = document.getElementsByClassName('bg1');
var sheet = new CSSStyleSheet();
sheet.replaceSync('.bg' + currentImgSlot + ' {background-image: url("assets/img/' + pickedImage + '.jpg") !important}');
document.adoptedStyleSheets = [sheet];
return imgCarousel();
}, 5000)
})()
function pickImageSlot() {
var min = 1;
var max = 2;
var generatedImgSlot = generateRandomNumber(max, min);
if (generatedImgSlot == currentImgSlot) {
return pickImageSlot();
}
return generatedImgSlot;
}
function pickImage() {
var min = 1;
var max = 6;
var generatedImg = generateRandomNumber(max, min);
if (currentImages[currentImgSlot] == generatedImg) {
return pickImage();
}
currentImages[currentImgSlot] = generatedImg;
return generatedImg;
}
function generateRandomNumber(max, min) {
return Math.round(Math.random() * (max - min) + min)
}
So, here you can see that inside the imgCarousel() function I am using the setTimeout to change the background-image randomly after 5 seconds and then calling the same function again recursively. So, according to this code after each five seconds only one image should be changed. But, in reality, sometimes both of the images get changed at the same time. I don't know what is causing this issue.
Any help would be much appreciated. For your convenience I am sharing my code repo here:
Git Repo
Live Demo
It's a bit difficult to notice, but if you pay attention, in your live demo you'll actually see that each time they both change, one returns to the default. This is because you're actually just overriding the adoptedStyleSheets property with a new array consisting only of the latest override, so your other image will simultaneously return to the primary style sheet's image (the default).
There is no problem with the setTimeout, the issue is just that you need to be able to support both images being different from the default, instead of exactly one. You already keep both images in currentImages, so each time the timeout runs you can iterate over them and set each one's image in the new adopted style sheet.
Naively, something like this might work:
setTimeout(function () {
console.log("Image Slot: " + currentImgSlot + "<br> Image: " + pickedImage);
//var bgImgElem = document.getElementsByClassName('bg1');
var sheet = new CSSStyleSheet();
for(var i = 1; i < 2; i++) {
sheet.replaceSync('.bg' + i + ' {background-image: url("assets/img/' + currentImages[i]+ '.jpg") !important}');
}
document.adoptedStyleSheets = [sheet];
return imgCarousel();
}, 5000)
Your currentImages seems to be used with a random number between 1 and 2, but arrays are 0-based, so I'm not sure what your intended usage is there, but this should get you on the right track.
I am working on a randomising function for a game in javascript and jquery. I have written this to randomise the position of a square in a 8x8x64px grid, and give the player a point when their character moves over it. The function works once, but wont repeat.
The relevant script
Every time the player moves it searches for
if (xNum==ptX && yNum==ptY) {
getPoint();
pointRand();
}
yNum and xNum is the player's coordinates and ptY and ptX is the point's. Movement occurs on keyUp for the arrow keys, and the if is also executed then.
Corresponding functions
//Score
var ptAllow = true;
var pt = 0;
var ptX = 7;
var ptY = 7;
var yPt = ptX*64+"px";
var xPt = ptY*64+"px";
function getPoint() {
if (ptAllow == true) {
pt++;
document.getElementById("scoreCounter").innerHTML = "score: "+pt;
document.getElementById("scoreFin").innerHTML = "score: "+pt;
}
}
function pointRand() {
ptX = Math.floor(Math.random() * 8) + 1;
ptY = Math.floor(Math.random() * 8) + 1;
ptX--;
ptY--;
yPt = ptX*64+"px";
xPt = ptY*64+"px";
$("#point").animate({"left": xPt, "top": yPt}, 100);
}
Like I said, It works perfectly the first time you move over a point, but after that nothing happens. . ptAllow is set to false once the player hits an obstacle, and the game is over.
Edit: There are no errors in the browser console, and the reason for adding and subtracting in pointRand() is that math.floor does not seem to work with a lowest value of zero.
I created a code that throws an element to up with an acceleration(works like gravity) value and falls down when changed_lenght reaches to zero;
"mouseenter" is triggering this function. When mouse leaves and enters quickly the function starts over and over again, and not stoping the previous ones so it looks so bad.
I wonder is there any way to check if previous one was ended before starting the function. Or any other solution that can help me ?
here is my JS codes:
$('#outher').mouseenter(function moveone(){
var t = 0;
var v = 20;
var p = 275;
var a = 5;
var moveoneint = setInterval(jump, 50);
function jump(){
t++;
x = (v*t) - (0.5 * a * t * t);
p = (p - x);
if(x <= 0){
clearInterval(moveoneint);
t = 0;
var movetwo = setInterval(fall, 50);
function fall(){
t++;
x = (0.5 * a * t * t );
p = (p + x);
document.getElementById('inner').style.top = p + 'px';
if(p >= 275){
clearInterval(movetwo);
}
}
}
else{
document.getElementById('inner').style.top = p + 'px';
}
}
});
and Here is a Fiddle:
http://jsfiddle.net/ctarimli/TJte8/
You can simply remove the mouseenter handler until the animation has completed.
JSFIDDLE
Basically,
var $outher = $('#outher');
var onMouseEnter = function() {
$outher.off('mouseenter', onMouseEnter);
// do all your animation logic, and once complete...
$outher.on('mouseenter', onMouseEnter);
};
$outher.on('mouseenter', onMouseEnter);
If you are open to third-party library code, then throttle /debounce will do what you want. Note that the page mentions jQuery, but the library does not actually require jQuery.
In particular, look at the examples for the $.throttle method.
Use jQuery is to check if div is animating
if(!$('.inner').is(':animated'))
{
//Your code
}
I am using jQuery to generate and add a random amount of Clouds to the Header of the page and move them left on the specified interval. Everything is working fine, execpt the interval only runs once for each Cloud and not again. Here is my code:
if(enableClouds) {
var cloudCount = Math.floor(Math.random() * 11); // Random Number between 1 & 10
for(cnt = 0; cnt < cloudCount; cnt++) {
var cloudNumber = Math.floor(Math.random() * 4);
var headerHeight = $('header').height() / 2;
var cloudLeft = Math.floor(Math.random() * docWidth);
var cloudTop = 0;
var thisHeight = 0;
var cloudType = "one";
if(cloudNumber == 2) {
cloudType = "two";
}else if(cloudNumber == 3) {
cloudType = "three";
}
$('header').append('<div id="cloud' + cnt + '" class="cloud ' + cloudType + '"></div>');
thisHeight = $('#cloud' + cnt).height();
headerHeight -= thisHeight;
cloudTop = Math.floor(Math.random() * headerHeight);
$('#cloud' + cnt).css({
'left' : cloudLeft,
'top' : cloudTop
});
setInterval(moveCloud(cnt), 100);
}
function moveCloud(cloud) {
var thisLeft = $('#cloud' + cloud).css('left');
alert(thisLeft);
}
}
Any help is appreciated!
This is the way to go:
setInterval((function(i){
return function(){
moveCloud(i);
};
})(cnt), 100);
Engineer gave you the code you need. Here's what's happening.
The setInterval function takes a Function object and an interval. A Function object is simply an object that you can call, like so:
/* Create it */
var func = function() { /* ... blah ... */};
/* Call it */
var returnVal = func(parameters)
The object here is func. If you call it, what you get back is the return value.
So, in your code:
setInterval(moveCloud(cnt), 100);
you're feeding setInterval the return value of the call moveCloud(cnt), instead of the the function object moveCloud. So that bit is broken.
An incorrect implementation would be:
for(cnt = 0; cnt < cloudCount; cnt++) {
/* ... other stuff ... */
var interval = setInterval(function() {
moveCloud(cnt);
}, 100);
}
Now, you're feeding it a function object, which is correct. When this function object is called, it's going to call moveCloud. The problem here is the cnt.
What you create here is a closure. You capture a reference to the variable cnt. When the function object that you passed to setInterval is called, it sees the reference to cnt and tries to resolve it. When it does this, it gets to the variable that you iterated over, looks at its value and discovers that it is equal to cloudCount. Problem is, does not map on to a Cloud that you created (you have clouds 0 to (cloudCount -1)), so at best, nothing happens, at worst, you get an error.
The right way to go is:
setInterval((function(i){
return function(){
moveCloud(i);
};
})(cnt), 100);
This uses an 'immediate function' that returns a function. You create a function:
function(i){
return function(){
moveCloud(i);
};
}
that returns another function (let's call it outer) which, when called with a value i, calls moveCloud with that value.
Then, we immediately call outer with our value cnt. What this gives us is a function which, when called, calls moveCloud with whatever the value of cnt is at this point in time. This is exactly what we want!
And that's why we do it that way.