How can I generate new set of smiling faces at random position after user click on extra smiling face? - javascript

I have been trying to get the smiley faces to generate in new random position by putting the function delete_all_children() at appropriate locations, but everytime, it won't run properly. Instead, if I ignore the randomized location after finding the extra picture, the game runs properly but it is a build up from existing smiley faces, which makes the game easier.
I want the new faces to generate in random location.
Please help!
<DOCTYPE! html>
<html>
<head>
<title>Matching Game - Smiling :)</title>
<style>
div, img {position: absolute;}
div {width: 500px; height: 500px;}
#rightSide {left: 500px; border-left: 1px solid black}
</style>
<script type="text/javascript">
var numberOfFace = 5;
var count = 0;
var theBody = document.getElementsByTagName("body")[0];
function generateFaces() {
var theLeftSide = document.getElementById('leftSide');
var theRightSide = document.getElementById('rightSide');
while (count < numberOfFace) {
var top_random = (Math.random() * 400);
var left_random = (Math.random() * 400);
var smiling_face = document.createElement("img");
smiling_face.src = "http://home.cse.ust.hk/~rossiter/mooc/matching_game/smile.png";
smiling_face.style.top = Math.floor(top_random) + "px";
smiling_face.style.left = Math.floor(left_random) + "px";
theLeftSide.appendChild(smiling_face);
count ++;
};
leftSideImages = theLeftSide.cloneNode(true);
leftSideImages.removeChild(leftSideImages.lastChild);
theRightSide.appendChild(leftSideImages);
theLeftSide.lastChild.onclick = function nextLevel(event) {
event.stopPropagation();
numberOfFace += 5;
generateFaces();
};
theBody.onclick = function gameOver() {
alert("Game Over!");
theBody.onclick = null;
theLeftSide.lastChild.onclick = null;
};
function delete_all_children() {
var theNode = document.getElementById("theBody");
while (theNode.firstChild) {
theNode.removeChild(theNode.firstChild);
};
};
};
</script>
</head>
<body onload="generateFaces()">
<h1>Matching Game</h1>
<p>Click on the extra smiling face on the left!</p>
<div id="leftSide"></div>
<div id="rightSide"></div>
</body>
</html>

Related

Clicking on an image not working as intended

I made a game where you need to click the image on the left side of the screen that you do not see on the opposite side to get to the next level. For some reason, when you click any image on the left side you still go to the next level. When you click the wrong image it should say game over. Right now it only does that when the whitespace is clicked. Any tips?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Matching Game</title>
<style>
img {
position: absolute;
}
div {
position: absolute;
width: 500px;
height: 500px;
}
#rightSide {
left: 500px;
border-left: 1px solid;
}
</style>
</head>
<body onload="generateFaces()">
<h1>Matching Game</h1>
<p>Click on the extra smiling face on the left.</p>
<div id="leftSide"></div>
<div id="rightSide"></div>
<script >
let numberOfFaces = 5;
const theLeftSide = document.querySelector("#leftSide");
const theRightSide = document.querySelector("#rightSide");
function generateFaces() {
for (let i = 0; i < numberOfFaces; i++) {
let face = document.createElement("img");
face.src = 'images/smile.png';
const randomTop = Math.floor(Math.random() * 400) + 1;
const randomLeft = Math.floor(Math.random() * 400) + 1;
face.style.top = randomTop + 'px';
face.style.left = randomLeft + 'px';
theLeftSide.appendChild(face);
theLeftSide.lastChild.addEventListener('click', nextLevel);
document.body.addEventListener('click', gameOver);
}
const leftSideImages = theLeftSide.cloneNode(true);
leftSideImages.removeChild(leftSideImages.lastChild);
theRightSide.appendChild(leftSideImages);
function nextLevel(event) {
event.stopPropagation();
numberOfFaces += 5;
while (theLeftSide.firstChild) {
theLeftSide.removeChild(theLeftSide.firstChild);
}
while (theRightSide.firstChild) {
theRightSide.removeChild(theRightSide.firstChild);
}
generateFaces();
}
function gameOver() {
alert('Game Over!');
document.body.removeEventListener('click', gameOver);
theLeftSide.lastChild.removeEventListener('click', nextLevel);
}
}
</script>
</body>
</html>
notice
for (let i = 0; i < numberOfFaces; i++) {
let face = document.createElement("img");
...
theLeftSide.appendChild(face);
// you do this in every loop
theLeftSide.lastChild.addEventListener('click', nextLevel);
}
put the theLeftSide.lastChild.addEventListener('click', nextLevel); outside loop for it to work

Dom html javascript about onclick

I want to generate five image imgs first in left side, then remove the lastchild of it and copy the rest to the right side. If user clicks the extra img in left side, then clear all and generate more 5(10) img in left and copy 9 to the right side, and so on. If user clicks the wrong place, alert ("game over").Here is my code:
<html>
<head>
<style>
img{
position: absolute;
}
div{
position: absolute;
width: 500px;
height: 500px;
}
#rightSide { left: 500px;
border-left: 1px solid black;
}
</style>
<script>
var numberOfFaces = 5;
function generateFaces(){
var theLeftSide = document.getElementById("leftSide");
for (var i = 0; i < numberOfFaces; i++){
var img = document.createElement("img");
img.src = "smile.png";
var randomTop = Math.random() * 400;
var randomLeft = Math.random() * 400;
img.style.top = randomTop + "px";
img.style.left = randomLeft + "px";
theLeftSide.appendChild(img);
}
var theRightSide = document.getElementById("rightSide");
leftSideImages = theLeftSide.cloneNode(true);
leftSideImages.removeChild(leftSideImages.lastChild);
document.getElementById("rightSide").appendChild(leftSideImages);
var theBody = document.getElementByTagName("body")[0];
theLeftSide.lastChild.onclick = function nextLevel(event){
event.stopPropagation();
while (theBody.firstChild){
theBody.removeChild(theBody.firstChild);
}
numberOfFaces += 5;
generateFaces();
}
theBody.onclick = function gameover(){
alert("Game Over");
thBody.onclick = null;
theLeftSide.lastChild.onclick = null;
}
}
window.onload = generateFaces;
</script>
</head>
<body>
<h1>Matching Game</h1>
<p>click on the extra smiling face on the left</p>
<div id = "leftSide">
</div>
<div id = "rightSide">
</div>
</body>
</html>
I could generate and clone at first time, but when I click, nothing happens, so what is the problem?
This may be a typing error.
var theBody = document.getElementsByTagName("body")[0];
your code: var theBody = document.getElementByTagName("body")[0];
I suggest to use a good editor for html. I fixed the error with Jetbrain phpStorm but better ones may exist.
Bellow is a modified version that worked for me. Notice that in this version I added the events on all children instead of the whole document body. I don't know but for me it feels more accurate not to end the game on a user clicks on a white space for example.
<html>
<head>
<style>
img{
position: absolute;
}
div{
position: absolute;
width: 500px;
height: 500px;
}
#rightSide { left: 500px;
border-left: 1px solid black;
}
</style>
<script>
var numberOfFaces = 5;
var theBody;
var theLeftSide;
var theRightSide;
function generateFaces(){
theBody = document.getElementsByTagName("body")[0];
theLeftSide = document.getElementById("leftSide");
theRightSide = document.getElementById("rightSide");
for (var i = 0; i < numberOfFaces; i++){
var img = document.createElement("img");
img.src = "smile.png";
var randomTop = Math.random() * 400;
var randomLeft = Math.random() * 400;
img.style.top = randomTop + "px";
img.style.left = randomLeft + "px";
if(theLeftSide != null)
theLeftSide.appendChild(img);
else
{
alert("Game Over");
return;
}
}
var leftSideImages = theLeftSide.cloneNode(true);
leftSideImages.removeChild(leftSideImages.lastChild);
document.getElementById("rightSide").appendChild(leftSideImages);
addEvents();
}
function addEvents(){
for(var i=0; i < theLeftSide.childNodes.length; i++){
theLeftSide.childNodes[i].onclick = nextLevel;
}
}
function removeEvents(){
for(var i=0; i < theLeftSide.childNodes.length; i++){
theLeftSide.childNodes[i].onclick = null;
}
}
function nextLevel(event){
if(this == theLeftSide.lastChild){
event.stopPropagation();
theLeftSide.innerHTML = "";
theRightSide.innerHTML = "";
numberOfFaces += 5;
generateFaces();
}
else
{
alert("Game Over");
removeEvents();
}
}
window.onload = generateFaces;
</script>
</head>
<body>
<h1>Matching Game</h1>
<p>click on the extra smiling face on the left</p>
<div id = "leftSide">
</div>
<div id = "rightSide">
</div>
</body>
</html>

How can I check if an attractor is strange?

Lately I learned a bit about strange attractors, and I created the following programm in JS:
var ctx, clock, width, height, pixSize;
var x,y,a,b,c,d;
window.onload = function(){
start();
};
function start(random=true){
window.cancelAnimationFrame(clock);
if(random){
a = 6*Math.random()-3;
b = 6*Math.random()-3;
c = 2*Math.random()-0.5;
d = 2*Math.random()-0.5;
}
canvasSetup();
clearCanvas();
x = Math.random()-Math.random();
y = Math.random()-Math.random();
clock = requestAnimationFrame(main);
}
function save(){
var text = JSON.stringify({
a:a,
b:b,
c:c,
d:d
});
window.prompt("Copy to clipboard: Ctrl+C", text);
}
function load(){
var input = JSON.parse(window.prompt("Import Save:"));
a = input.a;
b = input.b;
c = input.c;
d = input.d;
start(false);
}
function canvasSetup(){
canvas = document.getElementById('canvas');
width = window.innerWidth-5;
height = window.innerHeight-5;
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext('2d');
var min = Math.min(width,height);
var scale = min/4;
ctx.translate(width/2, height/2);
ctx.scale(scale, scale);
pixSize = 1/scale/2;
ctx.globalCompositeOperation = "lighter";
}
function clearCanvas(){
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0,0,width,height);
ctx.restore();
}
function main(){
for(var i=0;i<10000;i++){
var xnew = Math.sin(y*b)+c*Math.sin(x*b);
var ynew = Math.sin(x*a)+d*Math.sin(y*a);
x = xnew;
y = ynew;
plot(x,y,"rgb(50,5,1)");
}
clock = requestAnimationFrame(main);
}
function plot(x,y,color="white"){
ctx.fillStyle = color;
ctx.fillRect(x,-y,pixSize,pixSize);
}
body {
background-color: black;
color: white;
font-family: Consolas;
font-size: 13px;
margin: 0;
padding: 0;
}
#buttons{
position: absolute;
top: 0;
left: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Strange Attractor</title>
<link rel="stylesheet" href="style.css">
<script src="rules.js"></script>
<script src="script.js"></script>
</head>
<body>
<div align="center">
<canvas id="canvas"></canvas>
</div>
<div id="buttons">
<button onclick="start()">New Attractor</button><br>
<button onclick="save()">Save</button><br>
<button onclick="load()">Load</button>
</div>
</body>
</html>
It's taking 4 random Parameters (a,b,c,d) and uses the formular
var xnew = Math.sin(y*b)+c*Math.sin(x*b);
var ynew = Math.sin(x*a)+d*Math.sin(y*a);
x = xnew;
y = ynew;
for the new point. In some cases this indeed creates a fancy strange sttractor:
But in other cases I only get a single line or a few points. Is there a simple way to look at the parameters and find out, if the attrator they create will be strange?
I know, that I could save a bunch of values, compare them with each other and test in that way, if the picture might be intresting, but I'd love a different solution...
I hope you can help :)
EDIT:
To look at speccific values you can simply use the save and load buttons in the js sketch above...

Is this a browser issue with HTML5 and javascript?

I'm doing html code in Atom IDE, but i don't get the desired result on the browser, however, when i try with the Atom's HTML preview, i can see the result i want to get.
Here are the screenshots of both the browser and the Atom's preview, please take a look on them:
Atom's HTML preview
Firefox
I've also tried to run the code on Chrome and Internet Explorer, and i get the same result.
Here is my code also:
<!DOCTYPE html>
<html>
<head>
<meta name="author" content="Carlos Cordova">
<meta charset="utf-8">
<title>Assessment 3 part 4 (Finishing the Game)</title>
<style>
img{
position: absolute;
}
div{
position: absolute;
width: 500px;
height: 500px;
}
#rightSide{
left: 500px;
border-left: 1px solid black;
}
</style>
<script>
var numberOfFaces = 5;
function generateFaces(){
for (var i = 0; i < numberOfFaces; i++) {
var newImage = document.createElement("img");
newImage.src = "http://home.cse.ust.hk/~rossiter/mooc/matching_game/smile.png";
newImage.style.top = Math.floor(Math.random()*400);
newImage.style.left = Math.floor(Math.random()*400);
theLeftSide = document.getElementById("leftSide");
theLeftSide.appendChild(newImage);
theRightSide = document.getElementById("rightSide");
leftSideImages = theLeftSide.cloneNode(true);
leftSideImages.removeChild(leftSideImages.lastChild);
theRightSide.appendChild(leftSideImages);
theBody = document.getElementsByTagName("body")[0];
theLeftSide = document.getElementById("leftSide");
theLeftSide.lastChild.onclick = function nextLevel(event){
event.stopPropagation();
numberOfFaces += 5;
deleteAllChildren();
generateFaces();
};
theBody.onclick = function gameOver(){
alert("Sorry, your game is over!");
theBody.onclick = null;
theLeftSide.lastChild.onclick = null;
};
function deleteAllChildren(){
theLeftSide = document.getElementById("leftSide");
while(theLeftSide.firstChild){
theLeftSide.removeChild(theLeftSide.firstChild);
}
theRightSide = document.getElementById("rightSide");
while(theRightSide.firstChild){
theRightSide.removeChild(theRightSide.firstChild);
}
}
}
/*console.log(theLeftSide.childNodes[0]);
console.log(theLeftSide.childNodes[1]);
console.log(theLeftSide.childNodes[2]);
console.log(theLeftSide.childNodes[3]);
console.log(theLeftSide.childNodes[4]);
*/
}
</script>
</head>
<body onload="generateFaces()">
<h1>Matching Game</h1>
<p>Click on the extra smiling face on the left.</p>
<div id="leftSide"></div>
<div id="rightSide"></div>
</body>
</html>
I will be very grateful to help me solve my problem.
The style attribute needs to be a string.
Example:
newImage.style.top = Math.floor(Math.random()*400)+"px";
newImage.style.left = Math.floor(Math.random()*400)+"px";
On the other side, you're setting the same id for different HTML elements.
This will result in in very unexpected behavior. If you need to reuse markers then make use of classes instead.
The problem with your code is that the img element needs the position by pixles:
newImage.style.top = Math.floor(Math.random() * 400) + "px";
newImage.style.left = Math.floor(Math.random() * 400) + "px";
See here: https://jsfiddle.net/wj4mx1dn/
Add px to your image position.
newImage.style.top = Math.floor(Math.random()*400) + 'px';
newImage.style.left = Math.floor(Math.random()*400) + 'px';
full code is here:
<script type="text/javascript">
'use strict';
var numberOfFaces = 5;
function generateFaces() {
function deleteAllChildren() {
theLeftSide = document.getElementById("leftSide");
while (theLeftSide.firstChild) {
theLeftSide.removeChild(theLeftSide.firstChild);
}
theRightSide = document.getElementById("rightSide");
while (theRightSide.firstChild) {
theRightSide.removeChild(theRightSide.firstChild);
}
}
var theBody = document.getElementsByTagName("body")[0];
var theLeftSide = document.getElementById("leftSide");
var theRightSide = document.getElementById("rightSide");
for (var i = 0; i < numberOfFaces; i++) {
var newImage = document.createElement("img");
theLeftSide.appendChild(newImage);
newImage.style.top = Math.floor(Math.random() * 400) + 'px';
newImage.style.left = Math.floor(Math.random() * 400) + 'px';
//theLeftSide = document.getElementById("leftSide");
newImage.src = "http://home.cse.ust.hk/~rossiter/mooc/matching_game/smile.png";
var leftSideImages = theLeftSide.cloneNode(true);
leftSideImages.removeChild(leftSideImages.lastChild);
theRightSide.appendChild(leftSideImages);
}
theLeftSide.lastChild.onclick = function nextLevel(event) {
event.stopPropagation();
numberOfFaces += 5;
deleteAllChildren();
generateFaces();
};
theBody.onclick = function gameOver() {
alert("Sorry, your game is over!");
theBody.onclick = null;
theLeftSide.lastChild.onclick = null;
};
/*console.log(theLeftSide.childNodes[0]);
console.log(theLeftSide.childNodes[1]);
console.log(theLeftSide.childNodes[2]);
console.log(theLeftSide.childNodes[3]);
console.log(theLeftSide.childNodes[4]);
*/
}
</script>

Why does the onclick event listener gets removed?

I am making a small matching game in javascript. Why does the onclick listener stop working after the first successful attempt. How do I rectify this issue.
I am expecting the listener to be attached to the last child element of the div with id "leftSide" even after I refresh all nodes by removing old nodes first.
<!DOCTYPE html>
<html>
<head>
<title>Matching Game</title>
<style>
img {
position: absolute;
}
div {
position: absolute;
width: 500px;
height: 500px;
}
#rightSide {
left: 500px;
border-left: 1px solid black;
}
</style>
</head>
<body>
<h2>Matching Game</h2>
<p>Click on the extra smile on the left</p>
<div id="leftSide"></div>
<div id="rightSide"></div>
<script>
var numberOfFaces = 5;
var theLeftSide = document.getElementById("leftSide");
var theRightSide = document.getElementById("rightSide");
function generateFaces() {
for (var i=0; i<=numberOfFaces; i++) {
new_img = document.createElement("img");
new_img.src="smile.png";
new_img.style.top=String(Math.floor(Math.random()*400))+"px";
new_img.style.left=String(Math.floor(Math.random()*400))+"px";
theLeftSide.appendChild(new_img);
}
// Clone all images to right side
leftSideImages = theLeftSide.cloneNode(true);
leftSideImages.removeChild(leftSideImages.lastChild);
theRightSide.appendChild(leftSideImages);
}
generateFaces()
var theBody = document.getElementsByTagName("body")[0];
theBody.onclick = function gameOver() {
alert("Game Over!");
theBody.onclick = null;
theLeftSide.lastChild.onclick = null;
};
theLeftSide.lastChild.onclick = function nextLevel(event) {
// remove child nodes
while (theLeftSide.firstChild) {
theLeftSide.removeChild(theLeftSide.firstChild);
}
while (theRightSide.firstChild) {
theRightSide.removeChild(theRightSide.firstChild);
}
// new nodes
event.stopPropagation();
numberOfFaces += 5;
generateFaces();
};
</script>
</body>
</html>
The problem is when you attach an event handler to an element, when that element is destroyed, the event is gone too (when the GC cleans). The theLeftSide.lastChild doesn't creates a reference to whatever last child element of theLeftSide is. It creates a reference to the current last child.
You must change the place you add the event handler to inside your generateFaces function, so everytime you change the theLeftSide children, you get again the last child, and add the event.
Take a look at the example below:
<!DOCTYPE html>
<html>
<head>
<title>Matching Game</title>
<style>
img {
position: absolute;
}
div {
position: absolute;
width: 500px;
height: 500px;
}
#rightSide {
left: 500px;
border-left: 1px solid black;
}
</style>
</head>
<body>
<h2>Matching Game</h2>
<p>Click on the extra smile on the left</p>
<div id="leftSide"></div>
<div id="rightSide"></div>
<script>
var numberOfFaces = 5;
var theLeftSide = document.getElementById("leftSide");
var theRightSide = document.getElementById("rightSide");
function generateFaces() {
for (var i = 0; i <= numberOfFaces; i++) {
new_img = document.createElement("img");
new_img.src = "http://www.webgranth.com/wp-content/uploads/2012/03/smile.png";
new_img.style.top = String(Math.floor(Math.random() * 400)) + "px";
new_img.style.left = String(Math.floor(Math.random() * 400)) + "px";
theLeftSide.appendChild(new_img);
}
// Clone all images to right side
leftSideImages = theLeftSide.cloneNode(true);
leftSideImages.removeChild(leftSideImages.lastChild);
theRightSide.appendChild(leftSideImages);
theLeftSide.lastChild.onclick = nextLevel;
}
generateFaces()
var theBody = document.getElementsByTagName("body")[0];
theBody.onclick = function gameOver() {
alert("Game Over!");
theBody.onclick = null;
theLeftSide.lastChild.onclick = null;
};
function nextLevel(event) {
// remove child nodes
while (theLeftSide.firstChild) {
theLeftSide.removeChild(theLeftSide.firstChild);
}
while (theRightSide.firstChild) {
theRightSide.removeChild(theRightSide.firstChild);
}
// new nodes
event.stopPropagation();
numberOfFaces += 5;
generateFaces();
};
</script>
</body>
</html>
Note: I've simpled changed the theLeftSide.lastChild.onclick = function nextLevel(event) {, to a simple function declaration: function nextLevel(event) {, and then added the event handler inside the generateFaces function: theLeftSide.lastChild.onclick = nextLevel;.
you could try something like this:
<!DOCTYPE html>
<html>
<head>
<title>Matching Game</title>
<style>
img {
position: absolute;
}
div {
position: absolute;
width: 500px;
height: 500px;
}
#rightSide {
left: 500px;
border-left: 1px solid black;
}
</style>
</head>
<body>
<h2>Matching Game</h2>
<p>Click on the extra smile on the left</p>
<div id="leftSide"></div>
<div id="rightSide"></div>
<script>
var numberOfFaces = 5;
var theLeftSide = document.getElementById("leftSide");
var theRightSide = document.getElementById("rightSide");
var clickLastChild = function clickLastChild() {
// remove child nodes
theLeftSide.lastChild.onclick = function (event) {
while (theLeftSide.firstChild) {
theLeftSide.removeChild(theLeftSide.firstChild);
}
while (theRightSide.firstChild) {
theRightSide.removeChild(theRightSide.firstChild);
}
// new nodes
event.stopPropagation();
numberOfFaces += 5;
generateFaces();
};
};
function generateFaces() {
for (var i = 0; i <= numberOfFaces; i++) {
new_img = document.createElement("img");
new_img.src = "smile.png";
new_img.style.top = String(Math.floor(Math.random() * 400)) + "px";
new_img.style.left = String(Math.floor(Math.random() * 400)) + "px";
theLeftSide.appendChild(new_img);
}
// Clone all images to right side
leftSideImages = theLeftSide.cloneNode(true);
leftSideImages.removeChild(leftSideImages.lastChild);
theRightSide.appendChild(leftSideImages);
clickLastChild();
}
generateFaces();
var theBody = document.getElementsByTagName("body")[0];
theBody.onclick = function gameOver() {
alert("Game Over!");
theBody.onclick = null;
theLeftSide.lastChild.onclick = null;
};
clickLastChild();
</script>
</body>
</html>
Here i made fully working jsfiddle
You have to call generateFaces() from game over scenario also.
And yes as #epascarello mentioned, you are losing click events as you are setting them to null.
Because you set the onclick to false
theBody.onclick = null;
theLeftSide.lastChild.onclick = null;
when you click the tbody.

Categories