I'm attempting to create a classic "Snake game" using only vanilla Javascript. I got an issue with the snake movements when arrow keys are pressed. It didn't work as supposed to.
The entire code is look like this.
HTML
<div class="canvas" id="canvas">
<div class="snake" id="snake"></div>
<div class="food-item" id="food-item"></div>
</div>
CSS
.canvas {
position: relative;
width: 500px;
height: 500px;
background-color: rgba(203, 200, 200, 0.51);
}
.snake {
width: 18px;
height: 18px;
transform: translate(215px, 246px);
background-color: rgba(180, 9, 180, 0.808);
border-radius: 25px;
}
JS
//the position of element before movement
var pos = 0;
let ele = document.getElementById("snake");
//Add an event for button press
window.addEventListener("keydown", (key) => {
var keycode = key.key;
return {
keycode: keycode,
start: start(keycode),
};
});
//movement of the element
function start(key) {
let keys = key;
function automove() {
try {
if (pos === 380) {
clearInterval(movement);
} else if (keys === "ArrowRight") {
pos++;
ele.style.transform = "translate(" + pos + "px)";
} else if (keys === "ArrowLeft") {
pos++;
ele.style.transform = "translate(" + -pos + "px)";
} else if (keys === "ArrowUp") {
pos++;
ele.style.transform = "translateY(" + pos + "px)";
} else if (keys === "ArrowDown") {
pos++;
ele.style.transform = "translateY(" + -pos + "px)";
} else {
console.log("invalid command: " + Error);
}
} catch (error) {
console.log("Error: " + error);
}
}
const movement = setInterval(automove, 1000);
return movement;
}
the behavior of the code is this
What I'm doing wrong here... is there any alternative way of doing this ?
It would be great if you can support with a vanillaJs answer.
For a snake game, you want the character to move even when no key is pressed.
So you need to store the direction somehow.
here's an updated version:
https://jsfiddle.net/wmvqgku4/1/
JS:
var posX = 200;
var posY = 160;
var ele = document.getElementById("snake");
const UP =0;
const RIGHT =1;
const DOWN =2;
const LEFT =3;
var dir = 1;
window.addEventListener("keydown", (key) => {
keyhandler(key.key)
});
window.onload = function () {
ele = document.getElementById("snake");
ele.style.top = posY + "px";
ele.style.left = posX + "px";
setInterval( automove, 300);
console.log("Started.");
}
function keyhandler(keys) {
try {
if (posX >= 380) {
clearInterval(movement);
}
if (keys === "ArrowRight") {
dir = RIGHT;
} else if (keys === "ArrowLeft") {
dir = LEFT;
} else if (keys === "ArrowUp") {
dir = UP;
} else if (keys === "ArrowDown") {
dir = DOWN;
} else {
console.log("invalid command: " + keys);
}
} catch (error) {
console.log("Error: " + error);
}
}
function automove() {
switch ( dir ) {
case UP: posY--; break;
case DOWN: posY++; break;
case LEFT: posX--; break;
case RIGHT: posX++; break;
}
console.log(dir);
ele.style.top = posY + "px";
ele.style.left = posX + "px";
}
CSS:
.canvas {
position: relative;
width: 500px;
height: 500px;
background-color: rgba(203, 200, 200, 0.51);
}
.snake {
width: 18px;
height: 18px;
position: absolute;
background-color: rgba(180, 9, 180, 0.808);
border-radius: 25px;
}
I made the snake position absolute, and als kept track of the x/y position, so you can add checks for the bounds.
I also changed it a bit, the keyhandler checks the keys and updates the direction variable.
the automove now only checks the direction, and updates the position.
Hope this helps.
Related
I am beginner in JavaScript and I'm trying to create a simple game. I'm looking for a way to stop the rectangle when it touches the screen border by stopping setInterval(), I can't get the value of the left screen border.
const element = document.querySelector('#rectangle');
let a = 1;
document.addEventListener('keydown', function (e) {
switch (e.keyCode) {
case 37:
let leftInterval = setInterval(moveLeft, 100);
break;
case 39:
let rightInterval = setInterval(moveRight, 100);
break;
}
});
window.addEventListener('load', () => {
rectangle.style.position = 'absolute';
rectangle.style.left = "44%";
});
let moveLeft = () => {
element.style.left = parseInt(element.style.left) - a + '%';
}
let moveRight = () => {
element.style.left = parseInt(element.style.left) + a + '%';
}
function clearinterval() {
if (element.style.left < 0)
clearinterval(leftInterval);
}
clearinterval();
body {
background-color: brown;
box-sizing: border-box;
width: 100%;
height: 100%;
}
#rectangle {
bottom: 2.5%;
background-color: burlywood;
width: 12%;
height: 14px;
}
<div id="rectangle"></div>
This will help you.
const element = document.querySelector('#rectangle');
let a = 1;
document.addEventListener('keydown', function (e) {
switch (e.keyCode) {
case 37:
let leftInterval = setInterval(moveLeft, 100);
break;
case 39:
let rightInterval = setInterval(moveRight, 100);
break;
}
});
window.addEventListener('load', () => {
rectangle.style.position = 'absolute';
rectangle.style.left = "44%";
});
let moveLeft = () => {
if (parseInt(window.getComputedStyle(element,null).getPropertyValue("left")) > 10) {
element.style.left = parseInt(element.style.left) - a + '%';
}
}
let moveRight = () => {
if (parseInt(window.getComputedStyle(element,null).getPropertyValue("right")) > 10) {
element.style.left = parseInt(element.style.left) + a + '%';
}
}
// function clearinterval() {
// // clearinterval(leftinterval);
// }
// clearinterval();
I am trying to make a snake game.
I made the movement and I added a die function so when the character hits the border, dies.
If the character dies going downward or upward, when it restart, the character continues the upward/downward movement.
When it dies going to the left or right, it restarts as it should.
HTML and Javascript:
var upDown = 0,
rightLeft = 0;
var k, move, character;
window.onload = function() {
move = setInterval(right, 10);
character = document.getElementById('character');
setInterval(die, 10);
}
document.onkeydown = function(event) {
k = event.keyCode;
}
function die() {
if (rightLeft > 1465 || rightLeft < 0 || upDown > 650 || upDown < 0) {
clearInterval(move);
upDown = 0;
rightLeft = 0;
character.style.left = 0 + "px";
character.style.top = 0 + "px";
move = setInterval(right, 10);
alert("You lost!");
}
}
function right() {
rightLeft++;
character.style.left = rightLeft + 'px';
if (k == 38) {
console.log(move);
clearInterval(move);
console.log(move);
move = setInterval(up, 10);
} else if (k == 40) {
clearInterval(move);
move = setInterval(down, 10);
}
}
function left() {
rightLeft--;
character.style.left = rightLeft + "px";
if (k == 38) {
clearInterval(move);
move = setInterval(up, 10);
} else if (k == 40) {
clearInterval(move);
move = setInterval(down, 10);
}
}
function down() {
upDown++;
character.style.top = upDown + "px";
if (k == 39) {
clearInterval(move);
move = setInterval(right, 10);
} else if (k == 37) {
clearInterval(move);
move = setInterval(left, 10);
}
}
function up() {
upDown--;
character.style.top = upDown + "px";
if (k == 39) {
clearInterval(move);
move = setInterval(right, 10);
} else if (k == 37) {
clearInterval(move);
move = setInterval(left, 10);
}
}
#character {
width: 50px;
height: 50px;
background-color: black;
position: absolute;
}
#playGround {
position: relative;
background-color: gray;
border-style: solid;
border-color: blue;
width: 1515px;
height: 700px;
}
<div id="playGround">
<div id="character"></div>
</div>
There is a lot of work to be done here, but as for your specific question: you forgot to reset the 'k' variable. Add the line k = 0 to the die() function.
Good luck!
So, I have an event listener keydown on arrow right, when you push the square moving on xPX but my parent element this w and h
set a 100px for example, and I would like to stop moving and I can't, I try with element.offsetWidth > 0 so them you can move.
Please look this fiddle : FIDDLE
Few errors in your code. I've commented fixes. Here is how i made it for the right arrow - you can apply same logic to the rest of the moves...
Code:
const carre = document.querySelector('.carre');
const main = document.querySelector('.main');
const w = main.offsetWidth - carre.offsetWidth; // this was wrong in your code
carre.style.left="0px"; // set start position
document.addEventListener('keyup', (event) => {
const positionLeft = parseInt(carre.style.left); //i've used style.left, rather, it gives expected numbers (10,20,30....)
if(event.keyCode == '39') {
if (positionLeft < w) { // this was fixed too
carre.style.left = (positionLeft) + 10 + 'px';
} else {
carre.style.left = '0'
}
}
})
DEmo:
const carre = document.querySelector('.carre');
const main = document.querySelector('.main');
const w = main.offsetWidth - carre.offsetWidth; // this was wrong in your code
carre.style.left="0px"; // set start position
document.addEventListener('keyup', (event) => {
const positionLeft = parseInt(carre.style.left); //i've used style.left, rather, it gives expected numbers (10,20,30....)
if(event.keyCode == '39') {
if (positionLeft < w) { // this was fixed too
carre.style.left = (positionLeft) + 10 + 'px';
} else {
carre.style.left = '0'
}
}
})
* {
box-sizing:border-box;
}
.carre {
position:absolute;
left: 0;
width: 50px;
height: 50px;
background-color: red;
}
.main {
position: relative;
width: 100px;
height: 100px;
border: 1px solid #000;
}
<main class="main">
<div class="carre"></div>
</main>
I rebuild your code:
document.addEventListener('keydown', (event) => {
const w = main.getBoundingClientRect().right - carre.getBoundingClientRect().right;
const positionLeft = carre.getBoundingClientRect().left;
if(event.keyCode == '39') {
if (w >= 0) {
carre.style.left = (positionLeft) + 10 + 'px';
} else {
carre.style.left = '0'
}
}
if (event.keyCode == '37') {
if (w >= 0) {
carre.style.left = (positionLeft) - 10 + 'px';
}else {
carre.style.left = '0'
}
}
})
I've done this simple animation but i have a feeling i've writted to much lines of code for such a simple task. Is there a way to achieve the same result but with less code ?
https://jsfiddle.net/qw82Lwy0/1/
function myMove() {
var elem = document.getElementById("animate");
var pos = 0;
var id = setInterval(frame, 5);
var flag = true;
function frame() {
if (flag) {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
if (pos == 350) {
flag = false;
}
} else if (!flag) {
pos--;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
if (pos == 0) {
flag = true;
}
}
}
}
P.S: No jquery or css animation, just javascript.
instead of using the flag and a seperate code for the 2 conditions you could just flip the incrementer like so:
function myMove() {
var elem = document.getElementById("animate");
var pos = 0;
var id = setInterval(frame, 5);
var changeVal = 1;
function frame() {
pos+=changeVal;
if ((pos >= 350) || (pos <= 0)) changeVal *= -1;
elem.style.top = elem.style.left = pos + 'px';
}
}
Animations can now be done in modern browsers using CSS. For example, your javascript animation can be condensed to just a few lines using a CSS transition.
See MDN for more details and examples of transitions and animations.
Run the code snippet below to try
window.ball.addEventListener('transitionend', toggle);
function toggle() {
window.ball.classList.toggle('move');
}
.animation {
position: relative;
background-color: lightyellow;
border: 1px solid gray;
height: 200px;
width: 200px;
}
#ball {
transition-property: left top background-color;
transition-duration: 2s;
position: absolute;
background-color: red;
border-radius: 12px;
height: 25px;
width: 25px;
left: 0;
top: 0;
}
#ball.move {
background-color: blue;
left: 175px;
top: 175px;
}
<button onclick="toggle()">Start</button>
<div class="animation"><div id="ball"></div></div>
Well, you could shorten your frame() function like so:
function myMove() {
var elem = document.getElementById("animate");
var pos = 0;
var id = setInterval(frame, 5);
var flag = true;
function frame() {
if (flag) {
pos++;
if (pos == 350) {
flag = false;
}
} else { // since you are checking if flag is true, the only other answer is false
pos--;
if (pos == 0) {
flag = true;
}
}
elem.style.top = pos + 'px'; // since this occurs in both cases
elem.style.left = pos + 'px'; // you can do it afterward
}
}
Use a function with 3 paraneters : posAdd, flagValue and posValue
function frame(posAdd,flagValue,posValue) {
if (flagValue) {
pos=pos+posAdd;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
if (pos == posValue) {
flag = !flagValue;
}
}
}
And call it twice : frame(1,true,350)
And frame(-1,false,0)
Essentially, I keep getting the message "document is not defined" when I run my .js doc on command line. I'm trying to create a super basic game where the user helps the squirrel get to the chestnuts by using arrow keys. So far I can't move the squirrel yet, and I suspect it has to do with the document is not defined error that I'm getting (lines 1-3 and maybe also 52 in the link).
You can find my code (html, css and js) in the following jsfiddle link
(http://jsfiddle.net/8Lbkcsq2/)
var squirrelImg = document.getElementById("squirrelImg");
var forest = document.getElementById("forest");
var chestnutImg = document.getElementById("chestnutsImg");
var squirrel = {
name: "Mr. Squirrel",
has_chestnuts: false,
hungry: true
};
var chestnuts = {
name: "chestnuts"
};
var positionLeft = 0;
var positionTop = 0;
function move(e) {
// 39 for right arrow
if (e.keyCode === 39) {
if (positionLeft < 850) {
positionLeft += 50;
squirrelImg.style.left = positionLeft + "px";
}
}
// 40 for down arrow
if (e.keyCode === 40) {
if (positionTop < 600) {
positionTop += 50;
squirrelImg.style.top = positionTop + "px";
}
}
// 37 for left arrow
if (e.keyCode === 37) {
positionLeft -= 50;
if (positionLeft < 0) {
positionLeft += 50; // CHANGE TO +=50 LATER
}
squirrelImg.style.left = positionLeft + "px";
}
// 38 for up arrow
if (e.keyCode === 38) {
positionTop -= 100;
if (positionTop < 0) {
positionTop += 50; // CHANGE TO +=50 LATER
}
squirrelImg.style.top = positionTop + "px";
}
foundChestnuts();
}
document.onKeyDown = move();
function foundChestnuts() {
if ((squirrelImg.style.top == "300px") && (squirrelImg.style.left == "750px")) {
squirrel.has_chestnuts = true;
alert("Thank you for helping Mr. Squirrel find his chestnuts!");
var eat = confirm("Should Mr.Squirrel eat his chestnuts?");
if (eat === true) {
alert("Time to eat!");
alert("Yum! Mr. Squirrel isn't hungry anymore!");
} else {
alert("I guess Mr. Squirrel can wait a little longer...");
}
} else {
squirrel.has_chestnuts = false;
}
}
body {
background-color: #b5916c;
}
h3 {
font-weight: bold;
text-decoration: underline;
}
p {
font-family:'Dancing Script', cursive;
font-size: large;
}
#forest {
background-image: url(http://s21.postimg.org/jyht762hj/forestfloor.jpg);
width: 850px;
height: 600px;
position: relative;
/*opacity: 0.5;*/
}
#squirrelImg {
position: absolute;
background-image: url(http://s24.postimg.org/wkqh9by4x/squirrel.png);
height: 100px;
width: 100px;
left: 0;
top: 0;
}
#chestnutsImg {
position: absolute;
background-image: url(http://s28.postimg.org/kgiubxhnd/chestnuts.jpg);
height: 100px;
width: 100px;
left: 750px;
top: 300px;
}
<body>
<h3>A Plea from Mr. Squirrel:</h3>
<p>My dearest human,</p>
<p>I seem to have misplaced my chestnuts and I am quite famished.</p>
<p>Would you mind assisting me in locating them?</p>
<p>Much obliged!</p>
<div id="forest">
<div id="squirrelImg"></div>
<div id="chestnutsImg"></div>
</div>
</body>
The issue is that move() requires an event to be passed to it but when you do document.onKeyDown = move(); no event is passed.
Change document.onKeyDown = move(); to document.addEventListener("keydown", move, false);
working jsfiddle
Add a event listener document.body.addEventListener('keydown', function(e) {...} instead of document.onKeyDown = move().
Updated Fiddle
var squirrelImg = document.getElementById("squirrelImg");
var forest = document.getElementById("forest");
var chestnutImg = document.getElementById("chestnutsImg");
var squirrel = {
name: "Mr. Squirrel",
has_chestnuts: false,
hungry: true
};
var chestnuts = {
name: "chestnuts"
};
var positionLeft = 0;
var positionTop = 0;
document.body.addEventListener('keydown', function(e) {
// 39 for right arrow
if (e.keyCode === 39) {
if (positionLeft < 850) {
positionLeft += 50;
squirrelImg.style.left = positionLeft + "px";
}
}
// 40 for down arrow
if (e.keyCode === 40) {
if (positionTop < 600) {
positionTop += 50;
squirrelImg.style.top = positionTop + "px";
}
}
// 37 for left arrow
if (e.keyCode === 37) {
positionLeft -= 50;
if (positionLeft < 0) {
positionLeft += 50; // CHANGE TO +=50 LATER
}
squirrelImg.style.left = positionLeft + "px";
}
// 38 for up arrow
if (e.keyCode === 38) {
positionTop -= 100;
if (positionTop < 0) {
positionTop += 50; // CHANGE TO +=50 LATER
}
squirrelImg.style.top = positionTop + "px";
}
foundChestnuts();
});
// combined 3 functions previously separated for foundChestnuts, eatChestnuts and hungerLevel into the function below
function foundChestnuts() {
if ((squirrelImg.style.top == "300px") && (squirrelImg.style.left == "750px")) {
squirrel.has_chestnuts = true;
alert("Thank you for helping Mr. Squirrel find his chestnuts!");
var eat = confirm("Should Mr.Squirrel eat his chestnuts?");
if (eat === true) {
alert("Time to eat!");
alert("Yum! Mr. Squirrel isn't hungry anymore!");
} else {
alert("I guess Mr. Squirrel can wait a little longer...");
}
} else {
squirrel.has_chestnuts = false;
}
}
body {
background-color: #b5916c;
}
h3 {
font-weight: bold;
text-decoration: underline;
}
p {
font-family: 'Dancing Script', cursive;
font-size: large;
}
#forest {
background-image: url(http://s21.postimg.org/jyht762hj/forestfloor.jpg);
width: 850px;
height: 600px;
position: relative;
/*opacity: 0.5;*/
}
#squirrelImg {
position: absolute;
background-image: url(http://s24.postimg.org/wkqh9by4x/squirrel.png);
height: 100px;
width: 100px;
left: 0;
top: 0;
}
#chestnutsImg {
position: absolute;
background-image: url(http://s28.postimg.org/kgiubxhnd/chestnuts.jpg);
height: 100px;
width: 100px;
left: 750px;
top: 300px;
}
<body>
<h3>A Plea from Mr. Squirrel:</h3>
<p>My dearest human,</p>
<p>I seem to have misplaced my chestnuts and I am quite famished.</p>
<p>Would you mind assisting me in locating them?</p>
<p>Much obliged!</p>
<div id="forest">
<div id="squirrelImg"></div>
<div id="chestnutsImg"></div>
</div>
</body>
please place the script before </body>, or in window.onload callback function.
Because document object is not created when you call document.getElementById.
Yes, the problem is document.onKeyDown = move(). The right event handler isdocument.onkeydown, and handler should be a function move, not a function result move(). So just changed to document.onkeydown=move