first of all i'm pretty new to JS.
i'm trying to make a memory game but i have the next problem.
the code :
function cardClicked(elCard) {
// If the user clicked an already flipped card - do nothing and return from the function
if (elCard.classList.contains('flipped')) {
return;
}
// Flip it
elCard.classList.add('flipped');
// This is a first card, only keep it in the global variable
if (elPreviousCard === null) {
elPreviousCard = elCard;
} else {
// get the data-card attribute's value from both cards
var card1 = elPreviousCard.getAttribute('data-card');
var card2 = elCard.getAttribute('data-card');
// No match, schedule to flip them back in 1 second
if (card1 !== card2) {
setTimeout(function () {
elCard.classList.remove('flipped');
elPreviousCard.classList.remove('flipped');
elPreviousCard = null;
}, 1000)
wrongPick.play();
} else {
// Yes! a match!
flippedCouplesCount++;
elPreviousCard = null;
rightPick.play();
}
}
i would like to prevent the user from clicking more then two times (it's a memory game.) can someone tell me how can i implement this into my code please?
You can set a global variable to isClickable initially set to true, enter the code check if its true, if it isn't, return, else go ahead and set it to false and do a timeout to set it to true again, like:
var isClickable = true;
function cardClicked(elCard) {
if (!isClickable) return;
isClickable = false;
setTimeout(function () {
isClickable = true;
}, 500)
...
Since it's a card game I would do the following:
Make array of elements:
var cards = (
{
"card":"numberOfCard",
"isclicked" :"yes/no"
}
);
And then every time somebody clicks on card I would change isClickable to no so next time event occures I would prevent it.
create variable for example opened_cards that store how many card opened, if less than 2 allow open another card else do nothing.
var opened_cards = 0;
function cardClicked(elCard) {
// do check here
if (opened_cards < 2) {
// less than 2 card opened do operation
opened_cards++;
if (elCard.classList.contains('flipped')) {
return;
}
// Flip it
elCard.classList.add('flipped');
// This is a first card, only keep it in the global variable
if (elPreviousCard === null) {
elPreviousCard = elCard;
}
else {
// get the data-card attribute's value from both cards
var card1 = elPreviousCard.getAttribute('data-card');
var card2 = elCard.getAttribute('data-card');
// No match, schedule to flip them back in 1 second
if (card1 !== card2) {
setTimeout(function() {
opened_cards -= 2;
elCard.classList.remove('flipped');
elPreviousCard.classList.remove('flipped');
elPreviousCard = null;
}, 1000);
wrongPick.play();
}
else {
// Yes! a match!
opened_cards = 0;
flippedCouplesCount++;
elPreviousCard = null;
rightPick.play();
}
}
}
}
Related
I am learning to code or rather - even reading the code at this moment.
Could anyone please explain me, why those lines are there and what do they do?
if (noClicking) return;
if (e.target.classList.contains("flipped")) return;
What is the purpose of those two lines?
function handleCardClick(e) {
// you can use event.target to see which element was clicked
if (noClicking) return;
if (e.target.classList.contains("flipped")) return;
let currentCard = e.target;
currentCard.style.backgroundColor = currentCard.classList[0];
if (!card1 || !card2) {
currentCard.classList.add("flipped");
card1 = card1 || currentCard;
card2 = currentCard === card1 ? null : currentCard;
}
if (card1 && card2) {
noClicking = true;
// debugger
let gif1 = card1.className;
let gif2 = card2.className;
if (gif1 === gif2) {
cardsFlipped += 2;
card1.removeEventListener("click", handleCardClick);
card2.removeEventListener("click", handleCardClick);
card1 = null;
card2 = null;
noClicking = false;
} else {
setTimeout(function() {
card1.style.backgroundColor = "";
card2.style.backgroundColor = "";
card1.classList.remove("flipped");
card2.classList.remove("flipped");
card1 = null;
card2 = null;
noClicking = false;
}, 1000);
}
}
if (cardsFlipped === COLORS.length) alert("game over!");
}
if (noClicking) return;
if (e.target.classList.contains("flipped")) return;
The lines below those 2 lines will not be executed if one of the 2 lines are returned.
It means if noClicking == true or e.target.classList.contains("flipped") == true, then all the lines below those 2 lines will not be executed.
While the answers already given are correct, I thought it could help to understand why those lines are there in place. They are called guard clauses. Their purpose is to make your code more efficient.
Think of a scenario like this:
function myFunc(someParam) {
/*
do something that takes a lot of time/resources
... then somewhere you find someParam was invalid!
so all the calculations done until now was useless
*/
}
So instead of checking the validity of arguments, global variables, etc. when you need them in the function, you check for them in the beginning of the function such as like this:
function myFunc(someParam) {
//let's say valid() is a function that checks for validity of the param,
//returns true if valid, false if invalid.
if(!valid(someParam)) return;
/*
do something that takes a lot of time/resources
... then your function will only run the expensive code
if it is sure that there are no invalid arguments passed to it.
*/
}
It doesn't always have to be just return. This is your choice. Maybe the function always returns some positive number, then you could return -1 as such:
const getRoot = (num) => {
if(num < 0) return -1;
//get square root of the number
return abs(Math.sqrt(num));
}
//Then when you call the function, you could check if the result is not -1,
//to make sure you passed the correct arguments.
if (getRoot(-1) < 0)
console.error("Uh oh, you passed a negative number to the square root function");
Or you could throw an Error:
function myFunc (someParam) {
if(!valid(someParam)) throw new Error("wrong param bruh");
//do something...
}
So I am trying to develop a Tic Tac Toe game for practice with javascript but I've hit a roadblock. I have an if statement that should be returning true but it isn't. Here is a sample.
var game = true;
var x = 'X';
var o = 'O';
var blank = '';
var turn = x;
var board = [blank, blank, blank,
blank, blank, blank,
blank, blank, blank];
function write() {
$('td').click(function() {
//Making sure that the block that was clicked can only be clicked once
var id = $(event.target).attr('id');
var digit = parseInt(id.slice(-1));
//check to see of the block has been clicked on
if (board[digit] = blank) {
board[digit] = turn;
$(board[digit]).html(turn.toUpperCase());
if (turn = x) {
turn = o;
} else if (turn = o) {
turn = x;
}
} else {
alert("That box has already been clicked on!")
}
});
}
You have two issues at first glance.
First, event is undefined. Define it as a function parameter in your .click call.
$('td').click(function(event) { /* rest of the code */ }
Second, as Pointy commented, = is for assignment, == and === are meant for comparisons.
Thus
if (board[digit] = blank) { /**/ }
needs to be
if (board[digit] === blank) { /**/ }
Regarding the difference between == and === you can get more information here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness
Short version, prefer === unless you're absolutely sure you know what you're doing and want to explicitly use ==.
if (board[digit] === blank) {
^^
ETA: I don't believe this question is a duplicate to the one linked. I know how to return a private variable (as shown below in the code), this question was about how to call a private function within the same object.
I'm having trouble finding relevant information for javascript specifically. I have an object declared and within that object I have declared four functions (three that are object methods and one that is not).I want to make the fourth one an object method so that I can call it separately from jquery (timer.displayTime(); ) but when I do that startIntervalTimer use of the function stops working. Is what I'm trying to do even possible?
var startStopTime = function() {
//This function is currently called inside startIntervalTimer();
function displayTime() {
//Display correct time
};
//I WANT SOMETHING LIKE THIS INSTEAD BUT (SEE startIntervalTimer)
this.displayTime = function() {
//Display correct time
}
var intervalTimer;
this.startIntervalTimer = function() {
console.log(timeSetMS);
intervalTimer = setInterval(function() {
if(timeSetMS > 0) {
timeSetMS -= 1000;
displayTime(); //THIS IS WHERE AND HOW IT IS CALLED
this.displayTime(); //THIS IS WHAT I'M GOING FOR, BUT IT WON'T WORK
console.log(timeSetMS);
} else if(timeSetMS <= 0) {
clearInterval(intervalTimer);
console.log("timer stopped");
}
}, 1000
);
}
};
and then in the jquery I have:
var timer = new startStopTime();
$("#timer-container, #timer-label").click(function() {
if(power == "off") {
power = "on";
timer.startIntervalTimer();
} else if (power == "on") {
power = "off";
timer.stopTimer();
}
});
//I want to add this, below
$("#session-length").click(function() {
//Change the display
timer.displayTime();
displayTime(); // This won't work obviously because it's out of scope
});
You can declare another variable inside the object, ie. self:
var startStopTime = function() {
//declare self
var self = this;
this.displayTime = function() {
//Display correct time
}
var intervalTimer;
this.startIntervalTimer = function() {
console.log(timeSetMS);
intervalTimer = setInterval(function() {
if(timeSetMS > 0) {
timeSetMS -= 1000;
displayTime();
self.displayTime(); // use self instead
console.log(timeSetMS);
} else if(timeSetMS <= 0) {
clearInterval(intervalTimer);
console.log("timer stopped");
}
}, 1000
);
}
};
I have a function which "types" out a header title as though it is being typed on the screen.
The typer only starts typing once a particular section of my site is "active" or is seen on the screen.
At present, it takes the outputID aka the area where this text will be typed into. There are two instances of this function being run, each with different outputIDs - I only want the function to run once per outputID.
This is how the function is initially called.
<h2 id="typer-get-in-touch" class="typer" data-text="Get in Toche^^^^^ Touch"></h2>
if(anchorLink == 'contact'){
var outputID = $("#typer-get-in-touch");
textTyping(outputID);
}else if(anchorLink == 'expertise'){
var outputID = $("#typer-expertise");
textTyping(outputID);
}
This is the textTyping function
function textTyping(outputID){
$(outputID).show();
var textString = $(outputID).data("text");
var textArray = textString.split("");
var texttypeing = setInterval(
function() {
typeOutText(outputID,textArray);
}, 170);
function typeOutText(outputID,textArray) {
if (textArray[0] == "^"){
outputID.text(function(index, text){
return text.replace(/(\s+)?.$/, '');
});
textArray.shift();
}else {
if (textArray.length > 0) {
outputID.append(textArray.shift());
} else {
clearTimeout(texttypeing);
}
}
}
}
My issue at present is that the function runs multiple types, and continues to type each time the original anchorLink trigger is achieved. The result is that is writes the title many times e.g:
Get In TouchGet In TouchGet In Touch
Each time the section is navigated to, the typing starts again.
How can I run this function only ONCE per outputID? So once the outputID has been used, the function can no longer run for that data?
JSFiddle of non-working example: https://jsfiddle.net/qLez8zeq/
JSFiddle of mplungjan's solution: https://jsfiddle.net/qLez8zeq/1/
Change
function textTyping(outputID){
$(outputID).show();
var textString = $(outputID).data("text");
to
function textTyping(outputID){
var textString = $(outputID).data("text");
if (textString=="") return;
$(outputID).data("text","");
$(outputID).show();
FIDDLE
What you need to do is to bind the event handler for each ID and then unbind it after it's been triggered the first time. Since you're already using jQuery, you can use the "one" method to do exactly this for each outputID:
$( "#typer-get-in-touch" ).one( "click", function() {
textTyping(outputID);
});
I suppose you could store your processed outputIds into an array and then check if the given outputId is present in the array before starting?
Define your array, check for the existence, if not found, do code example:
var processedIds = [];
function textTyping(outputID) {
var foundItem = false;
for (var i = 0; i < processedIds.length; i++)
{
if (processedIds[i] == outputID) {
foundItem = true;
break;
}
}
if (!foundItem) {
//the rest of your code goes here
}
}
You can add some check at the beginning of your function:
var called = {};
function textTyping(outputID) {
if (called[outputID]) {
return;
}
called[outputID] = true;
// your code
}
I would like to be able to trap the double key press (for the Char T for example) in order to do some special processing.I would like the key presses to happen fast enough to not be interpreted as two separate presses, just like the double click.
Any ideas how i can achieve this?
When the key(s) are hit, make a note of the time. Then compare it with the time you noted the last time they key(s) were hit.
If the difference is within your threshold, consider it a double. Otherwise, don't. Rough example:
var delta = 500;
var lastKeypressTime = 0;
function KeyHandler(event)
{
if ( String.fromCharCode(event.charCode).toUpperCase()) == 'T' )
{
var thisKeypressTime = new Date();
if ( thisKeypressTime - lastKeypressTime <= delta )
{
doDoubleKeypress();
// optional - if we'd rather not detect a triple-press
// as a second double-press, reset the timestamp
thisKeypressTime = 0;
}
lastKeypressTime = thisKeypressTime;
}
}
Have a variable (perhaps first_press) that you set to true when a keypress event happens, and start a timer that will reset the variable to false after a set amount of time (however fast you want them to press the keys).
In your keypress event, if that variable is true then you have a double press.
Example:
var first_press = false;
function key_press() {
if(first_press) {
// they have already clicked once, we have a double
do_double_press();
first_press = false;
} else {
// this is their first key press
first_press = true;
// if they don't click again in half a second, reset
window.setTimeout(function() { first_press = false; }, 500);
}
}
I know is too late to answer but here goes how I have implemented that:
let pressed;
let lastPressed;
let isDoublePress;
const handleDoublePresss = key => {
console.log(key.key, 'pressed two times');
}
const timeOut = () => setTimeout(() => isDoublePress = false, 500);
const keyPress = key => {
pressed = key.keyCode;
if (isDoublePress && pressed === lastPressed) {
isDoublePress = false;
handleDoublePresss(key);
} else {
isDoublePress = true;
timeOut();
}
lastPressed = pressed;
}
window.onkeyup = key => keyPress(key);