I'm writing a web process to emulate the Connect4 board game. I have set it out using an Agile controller with seven columns and six rows with each cell referenced as c1r1 as below.
$scope.c1r1 = $scope.counterWhite;
$scope.c1r2 = $scope.counterWhite;
$scope.c1r3 = $scope.counterWhite;
.
.
$scope.c7r4 = $scope.counterWhite;
$scope.c7r5 = $scope.counterWhite;
$scope.c7r6 = $scope.counterWhite;
When the user clicks on any cell it raises an event which I want to show the counter dropping through the available cells, with code as below
$scope.c1r1 = $scope.counterYellow;
setTimeout(fillC1(), 1000);
$scope.c1r1 = $scope.counterWhite;
$scope.c1r2 = $scope.counterYellow;
setTimeout(fillC1(), 1000);
$scope.c1r2 = $scope.counterWhite;
$scope.c1r3 = $scope.counterYellow;
setTimeout(fillC1(), 1000);
$scope.c1r3 = $scope.counterWhite;
$scope.c1r4 = $scope.counterYellow;
setTimeout(fillC1(), 1000);
$scope.c1r4 = $scope.counterWhite;
$scope.c1r5 = $scope.counterYellow;
setTimeout(fillC1(), 1000);
$scope.c1r5 = $scope.counterWhite;
$scope.c1r6 = $scope.counterYellow;
When I run it nothing happens and the counter just appears at the bottom so I need a thread to make it work properly but as JavaScript doesn't do threading I wondered if there was another answer like Web Workers.
Right, the way you set up your cells is part of the problem.
Instead of that load of $scope.cXrY variables, use arrays:
$scope.cells = [];
var x, y;
for(x = 0; x < 7; x ++){
$scope.cells[x] = [];
for(y = 0; y < 6; y ++){
$scope.cells[x][y] = $scope.counterWhite;
}
}
There you go, all your cells in one variable.
Instead of $scope.c2r4, you'd use $scope.cells[2][4].
Now, for the counter going over the cells:
function iterateOverCells(){
fillC1()
$scope.cells[x][y] = $scope.counterWhite; // Make the previous cell white
x++; // Get next cell position
if(x >= 7){
x = 0;
y++;
}
$scope.cells[x][y] = $scope.counterYellow; // Current cell yellow
if(x < 7 && y < 6) // If we're not at the last cell
setTimeout(iterateOverCells, 1000); // Go to the next cell in 1 second
}
var x = 0, y = 0;
$scope.cells[x][y] = $scope.counterYellow; // Make the first cell yellow
setTimeout(iterateOverCells, 1000); // Next cell in 1 second
Web Workers don't have access to the DOM, they are for calculations. I'm not sure why you want to use a background thread, but here's how you can do it:
Let's assume you wrote a script with your background code, which posts messages when it's done with stuff (will get back to that in a sec:
function doWork() {
postMessage("did something");
setTimeout(doWork, 2000);
}
doWork();
Now, check that the browser supports web workers, create one, and listen on the messages published from it:
if(typeof(w) == "undefined") {
executer = new Worker("background.js");
}
executer.onmessage = function(event){
document.getElementById("results").innerHTML = event.data;
};
When you're done with it, you can remove it like so:
executer.terminate();
Related
Im trying create some type of number generator on webpage. I want to show like five numbers before the generated number show. For better imagine, you can look to google generator. When you click generate, it shows like 3-4 numbers before generated number. I use setInterval or setTimeout but i dont know how it works. My js code:
var button = document.querySelector("button");
button.addEventListener("click",function() {
for (var i = 0; i < 8; i++) {
setInterval(textC,5);
}
});
function textC(){
number.textContent = Math.floor(Math.random() * 1000) + 1;
}
Thanks for every help!
The issue with setInterval() is that it will continue forever unless cleared, causing you to keep generating random numbers. Instead you can use setTimeout(), but set the timeout to change based on the value of i in the for loop. That way, each interval will occur 50 m/s after the other.
See example below:
const button = document.querySelector("button");
const number = document.querySelector("#number");
button.addEventListener("click", function() {
for (let i = 0; i < 5; i++) {
setTimeout(textC, 50 * i);
}
});
function textC() {
number.textContent = Math.floor(Math.random() * 1000) + 1;
}
<p id="number"></p>
<button>Generate</button>
Don't use a loop (why not?). Just nest setTimeout and call it until a predefined threshold is reached. It gives you maximum control.
var button = document.querySelector("button");
var number = document.querySelector("#number");
const nRuns = 12;
const timeout = 100;
let iterator = 0;
button.addEventListener( "click", textC);
function textC(){
number.textContent = `${Math.floor(Math.random() * 1000) + 1}\n`;
iterator += 1;
if (iterator < nRuns) {
setTimeout(textC, timeout)
} else{
iterator = 0;
// you control the loop, so it's time for some extra text after it
number.textContent += ` ... and that concludes this series of random numbers`;
}
}
<p id="number"></p>
<button>Generate</button>
I'm trying to create a sort of ecosystem where objects spawn over time. However, when I try using setInterval to increase the amount it doesn't work. It works when I call the function on its own, but not when I use setInterval.
var plantSpawn = 5;
function createPlants() {
setInterval(reproducePlants, 5000);
for(var i=0; i<plantSpawn; i++){
var plant = new Object();
plant.x = Math.random() * canvas.width;
plant.y = Math.random() * canvas.height;
plant.rad = 2;
plant.skin = 'green';
myPlants[i] = plant;
}
}
function reproducePlants() {
plantSpawn += 5;
}
My goal for this is for every 5 seconds, 5 new plants appear. However, when I use the reproducePlants function with setInterval it does not work.
Note: I am calling createPlants() later in my code which makes the first 5 plants show up, but the next 5 won't show up. I am just showing the code that I'm trying to fix
The creation code must be moved inside the function that is repeatedly called.
NOTE: This is not an efficient way if you are going to call reproducePlants infinitely many times, since the myPlants array is reconstructed every time.
// Init with 0, because we increment it inside reproduce Plants
var plantSpawn = 0;
var myPlants = [];
function createPlants() {
reproducePlants();
setInterval(reproducePlants, 5000);
}
function reproducePlants() {
const canvas = document.getElementsByTagName('canvas')[0];
plantSpawn += 5;
for(var i = 0; i < plantSpawn; i++) {
var plant = new Object();
plant.x = Math.random() * canvas.width;
plant.y = Math.random() * canvas.height;
plant.rad = 2;
plant.skin = 'green';
myPlants[i] = plant;
}
}
You don't necessarily need to call the createPlants function from the reproducePlants function. You could add a call after both the functions. If I understand what you are trying to achieve that should do it.
You need to move the code that creates the plants (the for() chunck) inside the function that is called every 5 seconds (reproduce plants). So each time the function is called it will create the plants.
If you are trying to add only the 5 new plants every 5 seconds to your plants array you shouldn't recreate the array each time. It's better to keep track of the last index you have added and then continue right after that.
I created a variable called lastCreatedIndex so you can understand better what is going on. So the first time the code will run plants[i] from 0 to 4, the second 5 to 9...
var myPlants = [];
var lastCreatedIndex;
var plantSpawn;
function createPlants() {
plantSpawn = 5; //Initialize with 5 plants
lastCreatedIndex = 0; // Starts from index 0
reproducePlants();
setInterval(reproducePlants, 5000);
}
function reproducePlants() {
for(var i = 0 + lastCreatedIndex; i < plantSpawn; i++) {
var plant = new Object();
plant.x = Math.random() * canvas.width;
plant.y = Math.random() * canvas.height;
plant.rad = 2;
plant.skin = 'green';
myPlants[i] = plant;
console.log(i); // Output the number of the plant that has been added
}
lastCreatedIndex = i; //Update the last index value
plantSpawn += 5;
}
I'm trying to make bomberman using vanilla JS, for my examination project.
I am a little stuck right now with how to take out the bombs in the array and push them into the array again after they explode.
They need to explode after 2 seconds.
My code for bombs:
function bombPlayerOne() {
let ss = new createjs.SpriteSheet(game.q.getResult('bomb'))
let temp = new createjs.Sprite(ss, "bombIt");
temp.x = playerOne.x;
temp.y = playerOne.y;
game.stage.addChild(temp);
powerUps.bombs.push(temp);
console.log("player one placed a bomb");
for (var i = powerUps.bombs.length - 1; i > 0; i--) {
powerUps.bombs.splice;
// TODO : tween bomber ud...
powerUps.bombs.push;
}
}
function bombPlayerTwo() {
let ss = new createjs.SpriteSheet(game.q.getResult('bomb'))
let temp = new createjs.Sprite(ss, "bombIt");
temp.x = playerTwo.x;
temp.y = playerTwo.y;
game.stage.addChild(temp);
powerUps.bombs.push(temp);
console.log("player two placed a bomb");
for (var i = powerUps.bombs.length - 1; i > 0; i--) {
powerUps.bombs.splice;
// TODO : tween bomber ud...
powerUps.bombs.push;
}
}
So you have a few options, and FYI this isn't necessarily a javascript question so much as how do you handle game logic/code design type of question.
1) A bomb when placed contains a reference back to it's owner. ie
bomb.owner = playerOne
2) You have a manager that controls the state of a level, which keeps track of bombs
LevelManager.player1Bombs = ....
3) You have an array of bombs placed belonging to each player, which you then update during your logic update calls.
function gameUpdate(long milliSecondsSinceLastFrame){
for(bomb in playerOne.placedBombs){
if(bomb.isExploded){
//do other cleanup
playerOne.availableBombs ++;
}
}
//... do same for player 2 etc
}
All of them have their own advantages/disadvantages.
I am currently making a minefield game using JavaScript only. I have a problem at the end of the game. I have three difficulty levels so easy gives the user 45 guesses, intermediate 40 guesses and advanced is 35 guesses. However, for some reason when I have it set on intermediate/advanced it keeps going to 45 guesses instead of where it should stop.
After ive spent ages looking at it and changing different things such as the names of the variables and editing code. The guesses were working correctly so each guess actually counted as 1 guess now they are counting as 3. The code is now stopping at 35.
var number_of_guesses = 0;
var maximum_guesses = 45;
var intermediate_guesses = 40;
var advanced_guesses = 35;
var number_of_hits = 0;
var number_of_misses = 0;
var element = opener.document.getElementById("easy");
if (element.checked === true)
{
maximum_guesses = 45;
}
var intermediate = opener.document.getElementById("intermediate");
if (element.checked === true)
{
intermediate_guesses = 40;
}
var advanced = opener.document.getElementById("advanced");
if (element.checked === true)
{
advanced_guesses = 35;
}
number_of_guesses++;
if (number_of_guesses > maximum_guesses)
{
window.alert("Sorry, you have run out of guesses!");
return;
}
number_of_guesses++;
if (number_of_guesses > intermediate_guesses)
{
window.alert("Sorry, you have run out of guesses!");
return;
}
number_of_guesses++;
if (number_of_guesses > intermediate_guesses)
{
window.alert("Sorry, you have run out of guesses!");
return;
}
Can someone please tell me:
a) How to make each guess count as 1 instead of 3?
b) How to set each difficulty correctly?
Try having all three options set the maximum_guesses variable, rather than having three different variables for the different difficulties. Then just check that one variable.
var number_of_guesses = 0;
var maximum_guesses = 45;
var number_of_hits = 0;
var number_of_misses = 0;
// notice the missing intermediate_guesses and advanced_guesses vars
var element = opener.document.getElementById("easy");
if (element.checked)
{
maximum_guesses = 45;
}
var intermediate = opener.document.getElementById("intermediate");
if (intermediate.checked)
{
maximum_guesses = 40; // changed this to maximum_guesses
}
var advanced = opener.document.getElementById("advanced");
if (advanced.checked)
{
maximum_guesses = 35; // changed this to maximum_guesses
}
number_of_guesses++; // you only need this once
if (number_of_guesses > maximum_guesses)
{
window.alert("Sorry, you have run out of guesses!");
return;
}
EDIT: You also had a typo in that when you were checking wether or not the intermediate and advanced checkboxes were checked, you were still checking the easy element.
EDIT 2: Also, in your code, you were calling number_of_guesses++; three times, which was why each guess was counting 3 times. For them to only count as one, you only needed the first one. Each time you check, the number will stay the same, so you don't need to increment it three times.
EDIT 3: In my code, notice how I removed the === false parts in your if statements where you checked wether or not the checkboxes were checked.
I am trying to run a loop that will continuously change the color by randomly generating hex codes. I tried to search on here but couldn't find anything doing this.
I can't figure out how to get a loop to run and change the color continuously (until the end of a loop). I am new to JavaScript.
Here's my JSFiddle.
HTML
<body>
<div id="outer">
<div id="test">Generate colors.</div>
</div>
</body>
JS
for ( i = 0; i < 20000; i++ ) {
var t = document.getElementById('test');
var z = '#'+(Math.random()*0xFFFFFF<<0).toString(16);
t.style.color = z
}
You can't change colors in a loop, the color of the element won't change until you exit the code and return control to the browser.
You can use an interval to run code and return the control to the browser each time:
window.setInterval(function(){
var t = document.getElementById('test');
var z = '#'+(Math.random()*0xFFFFFF<<0).toString(16);
t.style.color = z
}, 100);
Demo: http://jsfiddle.net/et3qtr3t/
You were right with the commented setInterval you have on fiddle. It will make the colors change periodically (according to the milliseconds defined).
But you have to remove the for loop, because it will run instantly and you won't even see the changes... You'll have to manage your own variable counter, and clear the interval after it:
http://jsfiddle.net/kkfnjpsh/5/
var i = 0;
var runner = setInterval(function(){
if(i < 20000) {
var t = document.getElementById('test');
var z = '#'+(Math.random()*0xFFFFFF<<0).toString(16);
t.style.color = z;
i++;
}
else {
clearInterval(runner);
}
}, 3000);
I know it's already been answered, but mine includes the cleartimeout to set a timer.
var myVar = setInterval(function(){changeColor()}, 1000);
setTimeout(function(){clearInterval(myVar)}, 5000);
The second argument in the call to setTimeout could serve as your timer, so that the animation stops afterwards, in this case, it's set to 5 seconds.
function changeColor() {
var t = document.getElementById('test');
var z = '#'+(Math.random()*0xFFFFFF<<0).toString(16);
t.style.color = z;
console.log(z);
}
Result: Result
You don't loop - you interval:
var target= document.getElementById('test'),
colorChange = function() {
target.style.color = '#'+(Math.random()*0xFFFFFF<<0).toString(16);
};
// run interval
var d = setInterval(function() {
colorChange();
}, 500);
// clear after 5s
setTimeout(function() {
clearInterval(d);
}, 5000);
Working JSFiddle: http://jsfiddle.net/046q6ohf/