Move a div within another div with arrow keys - javascript

I am new in JavaScript, so I have some difficulties with it. I would like to move a small div within another bigger div with arrow keys - left, up, right and down. I have the code below but it does not work properly.
HTML and CSS
<div id="rectangle">
<div id="square"></div>
</div>
#rectangle {
width: 320px;
height: 200px;
border: 1px solid;
margin: auto;
position: relative;
}
#square {
width: 40px;
height: 40px;
background-color: deepskyblue;
position: absolute;
left: 0;
top:0;
}
Javascript
var rectangle = document.getElementById("rectangle");
var square = document.getElementById("square");
var currentPositionX = 0;
var currentPositionY = 0;
function moveSquare(event) {
if (event.keyCode == 37) {
currentPositionX -= 40;
square.style.left = currentPositionX + 'px';
if (currentPositionX <= 0) {
currentPositionX += 40;
}
}
if (event.keyCode == 38) {
currentPositionY -= 40;
square.style.top = currentPositionY + 'px';
if (currentPositionY <= 0) {
currentPositionY += 40;
}
}
if (event.keyCode == 39) {
currentPositionX += 40;
square.style.left = currentPositionX + 'px';
if (currentPositionX >= 280) {
currentPositionX -= 40;
}
}
if (event.keyCode == 40) {
currentPositionY += 40;
square.style.top = currentPositionY + 'px';
if (currentPositionY >= 160) {
currentPositionY -= 40;
}
}
}
document.onkeydown = moveSquare;

I have tested the code and found that when you are near the borders it's not working properly (Perhaps this was the original question?). On this i tested another simpler solution: I just changed your moveSquare function to only do work when you are inside your bounds (I mean, you shouldn't be always incrementing/decrementing position and then check if you are out of bounds to correct it).
function moveSquare(event) {
if (event.keyCode == 37) {
if (currentPositionX > 0) {
currentPositionX -= 40;
square.style.left = currentPositionX + 'px';
}
}
if (event.keyCode == 38) {
if (currentPositionY > 0) {
currentPositionY -= 40;
square.style.top = currentPositionY + 'px';
}
}
if (event.keyCode == 39) {
if (currentPositionX < 280) {
currentPositionX += 40;
square.style.left = currentPositionX + 'px';
}
}
if (event.keyCode == 40) {
if (currentPositionY < 160) {
currentPositionY += 40;
square.style.top = currentPositionY + 'px';
}
}
}
Here is the jsfiddle: https://jsfiddle.net/epL4a9Lq/
Please, next time be more specific on your error (i would comment this before answering but i have no reputation yet for that).
Hope this helps!

Related

How do I make an image move on keys up down left right?

I have watched at least 30 tutorials on how to make an image move up, down, left or right on the keys pressed, but not a single one was helpful to me.
I want to put in an image, and if you press the left or right key and it would move in that direction.
What is the shortest way to do this?
I know it's something with subtracting or adding the X axis, but how do I add the X and Y on a page so it can move?
is it something with keycode?
NOTE: Take care of -ve in left and top.
const image = document.querySelector(".image-continer");
document.addEventListener("keydown", (e) => {
const key = e.keyCode;
const cs = getComputedStyle(image);
const change = 10;
const regex = /[\d\.]*/;
const left = cs.left;
const top = cs.top;
const leftNumber = left.match(regex);
const topNumber = top.match(regex);
// LEFT key pressed
if (key === 37) {
image.style.left = `${parseFloat(leftNumber[0]) - change}px`;
}
// TOP key pressed
if (key === 38) {
image.style.top = `${parseFloat(topNumber[0]) - change}px`;
}
// RIGHT key pressed
if (key === 39) {
image.style.left = `${parseFloat(leftNumber[0]) + change}px`;
}
// DOWN key pressed
if (key === 40) {
image.style.top = `${parseFloat(topNumber[0]) + change}px`;
}
});
html,
body {
height: 100%;
margin: 0;
}
.image-continer {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
<div class="image-continer">🙂</div>
This method allows move image diagonally.
let img = document.getElementById("myimage"),
w = img.offsetWidth/2,
h = img.offsetHeight/2,
x = img.offsetLeft,
y = img.offsetTop,
step = 10, //number of pixels to move
keys = [];
document.addEventListener("keydown", function(e)
{
let l=null, u=null;
if (keys.indexOf(e.key) == -1)
keys[keys.length] = e.key;
for(let i = 0; i < keys.length; i++)
{
let key = keys[i];
if (key == "ArrowLeft")
{
l += -step;
}
if (key == "ArrowRight")
{
l += step;
}
if (key == "ArrowUp")
{
u += -step;
}
if (key == "ArrowDown")
{
u += step;
}
}
if (l === null && u === null)
return;
e.preventDefault();
e.stopPropagation();
if (l !== null)
x += l;
if (u !== null)
y += u;
if (x < w)
x = w;
if (y < h)
y = h;
if (x > img.parentNode.offsetWidth - w)
x = img.parentNode.offsetWidth - w;
if (y > img.parentNode.offsetHeight - h)
y = img.parentNode.offsetHeight - h;
img.style.left = x + "px";
img.style.top = y + "px";
}, false);
document.addEventListener("keyup", function(e)
{
keys.splice(keys.indexOf(e.key), 1);
}, false);
body,
html
{
height: 100%;
}
img
{
top: 50%;
left: 50%;
position: absolute;
transform: translate(-50%,-50%);
transition: left 0.3s ease, top 0.3s ease;
box-shadow: 0 0 10px 2px lightblue;
}
<img id="myimage" src="https://lh3.googleusercontent.com/s1j_z7YCGft2EBNfnpXel8v02F8QkQKvp-_UjkR8SFaE5ciwPX9IugLMYvo_cCBzzuThRD7dVwwLO3H7XnvbD0JNnyVDmw_mPd8T5NH7yzQSSirZcA=w100">
Example with JQuery:
$(document).on('keydown', function(event) { // if a key is pressed...
if (event.which === 39) { // then if the key the right arrow key...
$('.image').animate({ // then animate it with JQuery...
left: `+=${$('.image').width() * 3}`
}, 'slow'); // and do it slowly
} else if (event.which === 37) { // otherwise if the key is the left arrow key...
$('.image').animate({ // then animate it with JQuery...
left: `-=${$('.image').width() * 3}`
}, 'slow'); // and do it slowly
} else if (event.which === 38) { // otherwise if it is the up arrow key...
$('.image').animate({ // then animate it with JQuery...
top: `-=${$('.image').width() * 3}`
}, 'slow'); // and do it slowly
} else if (event.which === 40) { // otherwise if it is the down arrow key...
$('.image').animate({ // then animate it with JQuery
top: `+=${$('.image').width() * 3}`
}, 'slow'); // and do it slowly
}
event.preventDefault();
});
I got the solution:
var x = 0;
var y = 0;
var keys = {};
image.style.left = (x) + "px";
image.style.top = (y) + "px";
document.addEventListener("keyup", (e) => {
keys[e.keyCode] = false;
});
document.addEventListener("keydown", (e) => {
keys[e.keyCode] = true;
if(keys[37] {
x += 5;
image.style.left = (x) + "px";
}
if(keys[39] {
x -= 5;
image.style.left = (x) + "px";
}
});

How do I make css offset smoother with Javascript?

I have a Player controller using the position attributes and javascript but it is kinda snappy. What do I do?
I tried making an infinite loop then adding a time out to slow it down to the client's computers frames but it just outputted the same result, snappy. Also, I wrote this in Atom and I compiled it on the Google Chrome Web Browser.
Javascript
var player = document.getElementById('Player');
var ctx = player.getContext("2d");
var playerXPos = 0;
var playerYPos = 0;
var playerSpeed = 5;
ctx.fillStyle = "Red";
ctx.fillRect(0,0,50,50);
function animate(key) {
if (key.keyCode == 39) { //Right Arrow
playerXPos += playerSpeed;
player.style.left = playerXPos + "px";
}
if (key.keyCode == 37) { //Left Arrow
playerXPos -= playerSpeed;
player.style.left = playerXPos + "px";
}
if (key.keyCode == 38) { //Up Arrow
playerYPos -= playerSpeed;
player.style.top = playerYPos + "px";
}
if (key.keyCode == 40) { //Down Arrow
playerYPos += playerSpeed;
player.style.top = playerYPos + "px";
}
else {
return false;
}
}
document.onkeydown = animate;
HTML part (lol html is not a programming language but whatever)
<!DOCTYPE html>
<html>
<head>
<title>Player Test</title>
<style>
#Player {
position: relative;
}
</style>
<body>
<canvas id="Player"></canvas>
<script src="App/playerController.js" type="text/javascript"></script>
</body>
</html>
I want it to be smooth. I think I should use linear algebra but I am not that advance in javascript. I am actually a beginner.
You can use the CSS transition property to get a smoother effect. You need to set the initial top and left positions of your element in your CSS since these are the properties that you are changing with your JS. I've set the animation to last 0.5s, but this can be adjusted to be faster or slower as you'd prefer:
var player = document.getElementById('Player');
var ctx = player.getContext("2d");
var playerXPos = 0;
var playerYPos = 0;
var playerSpeed = 5;
ctx.fillStyle = "Red";
ctx.fillRect(0, 0, 50, 50);
function animate(key) {
if (key.keyCode == 39) { //Right Arrow
playerXPos += playerSpeed;
player.style.left = playerXPos + "px";
}
if (key.keyCode == 37) { //Left Arrow
playerXPos -= playerSpeed;
player.style.left = playerXPos + "px";
}
if (key.keyCode == 38) { //Up Arrow
playerYPos -= playerSpeed;
player.style.top = playerYPos + "px";
}
if (key.keyCode == 40) { //Down Arrow
playerYPos += playerSpeed;
player.style.top = playerYPos + "px";
} else {
return false;
}
}
document.onkeydown = animate;
#Player {
position: relative;
left: 0;
top: 0;
-webkit-transition: all 0.5s;
/* For Safari 3.1 to 6.0 */
transition: all 0.5s;
}
<canvas id="Player"></canvas>
You could try this:
var player = document.getElementById('Player');
var ctx = player.getContext("2d");
var playerXPos = 0;
var playerYPos = 0;
var playerXSpeed = 0;
var playerYSpeed = 0;
ctx.fillStyle = "Red";
ctx.fillRect(0,0,50,50);
setInterval(function(){
playerXPos += playerXSpeed;
player.style.left = playerXPos + "px";
playerYPos += playerYSpeed;
player.style.top = playerYPos + "px";
},5)
function animate(event) {
let x = event.which || event.keyCode
switch (x) {
case 39://Right Arrow
playerXSpeed = 1
break
case 37://Left Arrow
playerXSpeed = -1
break
case 38://Up Arrow
playerYSpeed = -1;
break
case 40://Down Arrow
playerYSpeed = 1;
break
}
}
document.onkeydown = animate;
document.onkeyup = function(){
let x = event.which || event.keyCode
switch (x) {
case 39://Right Arrow
case 37://Left Arrow
playerXSpeed = 0
break
case 38://Up Arrow
case 40://Down Arrow
playerYSpeed = 0;
break
}
}

Wall detection on canvas JS

I made this script which moves a smaller div inside it's parent container, but I need it so that it doesn't go past the boundaries of the parent (represented by the 1px black line border). Could someone help me?
var guy = document.getElementById("guy");
var container = document.getElementById("container");
var guyLeft = 0;
var y = 0;
function anim(e) {
if (e.keyCode == 39) {
guyLeft += 2;
guy.style.left = guyLeft + "px";
}
else if (e.keyCode == 37) {
guyLeft -= 2;
guy.style.left = guyLeft + "px";
}
else if (e.keyCode == 40) {
y += 2;
guy.style.top = y + "px";
}
else if (e.keyCode == 38) {
y -= 2;
guy.style.top = y + "px";
}
}
document.onkeydown = anim;
#container {
height:300px;
width:300px;
outline: 2px solid black;
position:relative;
}
#guy {
position:absolute;
height:20px;
width:20px;
outline: 1px solid black;
background-color:red; left: 0;
}
<div id="container">
<div id="guy"></div>
</div>
You could use an IF statement to detect when the character is at the edge.
With your example your JavaScript would become:
var guy = document.getElementById("guy");
var container = document.getElementById("container");
var guyLeft = 0;
var y = 0;
function anim(e) {
if (e.keyCode == 39 && guyLeft <= 278) {
guyLeft += 2; guy.style.left = guyLeft + "px";
}
else if (e.keyCode == 37 && guyLeft >= 2) {
guyLeft -= 2; guy.style.left = guyLeft + "px";
}
else if (e.keyCode == 40 && y <= 278) {
y += 2; guy.style.top = y + "px";
}
else if (e.keyCode == 38 && y >= 2) {
y -= 2; guy.style.top = y + "px";
}
} document.onkeydown = anim;
Here's a working example:
var guy = document.getElementById("guy");
var container = document.getElementById("container");
var guyLeft = 0;
var y = 0;
function anim(e) {
if (e.keyCode == 39 && guyLeft <= 278) {
guyLeft += 2; guy.style.left = guyLeft + "px";
}
else if (e.keyCode == 37 && guyLeft >= 2) {
guyLeft -= 2; guy.style.left = guyLeft + "px";
}
else if (e.keyCode == 40 && y <= 278) {
y += 2; guy.style.top = y + "px";
}
else if (e.keyCode == 38 && y >= 2) {
y -= 2; guy.style.top = y + "px";
}
} document.onkeydown = anim;
#container {
height:300px;
width:300px;
outline: 2px solid black;
position:relative; }
#guy {
position:absolute;
height:20px;
width:20px;
outline: 1px solid black;
background-color:red; left: 0;
}
<div id="container"> <div id="guy"></div></div>

Why JS animation is stuck?

I want the box to traverse the inside of the container from left to right, then down, then right to left and finally back up to the original position. The examples I found all include extra array pos = [180,180]. I don't understand why do I need it when my IF conditions seem to cover all positions.
window.onload = function() {
var t = setInterval(slide, 5);
pos1 = [0, 0];
var box = document.getElementById('sqr');
function slide() {
if (pos1[0] < 180 && pos1[1] < 180) {
pos1[0]++;
box.style.left = pos1[0] + "px";
} else if (pos1[0] >= 180 && pos1[1] < 180) {
pos1[1]++;
box.style.top = pos1[1] + "px";
} else if (pos1[0] >= 180 && pos1[1] >= 180) {
pos1[0]--;
box.style.left = pos1[0] + "px";
} else if (pos1[0] <= 0 && pos1[1] >= 180) {
pos1[1]--;
box.style.top = pos1[1] + "px";
}
}
}
#contain {
position: relative;
width: 200px;
height: 200px;
background-color: pink;
}
#sqr {
position: absolute;
width: 20px;
height: 20px;
background-color: blue;
}
<div id="contain">
<div id="sqr"></div>
</div>
Once the box gets to the maximum X and Y positions, the program is still checking to make sure the box hasn't reached the maximum yet, which causes the all IF conditions to fail. You could do it by checking for Y=0 for the first "leg", X=MAX for the next, Y=MAX for the next, and then X=0 for the last, but instead of that, you can set a "state" which has 4 values to determine which "leg" of the animation is being run, and then just run it for 180 iterations each.
window.onload = function() {
var t = setInterval(slide, 5);
pos1 = [0, 0];
var box = document.getElementById('sqr');
state = 0;
iterations = 0;
function slide() {
if (iterations >= 180) {state = (state + 1) % 4; iterations = 0;}
if (state === 0) pos1[0]++;
else if (state == 1) pos1[1]++;
else if (state == 2) pos1[0]--;
else if (state == 3) pos1[1]--;
iterations++;
box.style.left = pos1[0] + "px";
box.style.top = pos1[1] + "px";
}
}
#contain {
position: relative;
width: 200px;
height: 200px;
background-color: pink;
}
#sqr {
position: absolute;
width: 20px;
height: 20px;
background-color: blue;
}
<div id="contain">
<div id="sqr"></div>
</div>
window.onload = function() {
var t = setInterval(slide, 5);
var box = document.getElementById('sqr');
var left = 0,
top = 0;
function slide() {
var pos1 = [parseInt(box.style.left || 0), parseInt(box.style.top || 0)]
console.log(pos1);
if (pos1[0] == 0 && pos1[1] == 0) { //Top left, go right
left = 1;
top = 0;
} else if (pos1[0] == 180 && pos1[1] == 0) { //Top right, go down
left = 0;
top = 1;
} else if (pos1[0] == 180 && pos1[1] == 180) { //Bottom right, go left
left = -1;
top = 0;
} else if (pos1[0] == 0 && pos1[1] == 180) { //Bottom left, go up
left = 0;
top = -1;
}
box.style.left = (parseInt(box.style.left || 0) + left) + "px";
box.style.top = (parseInt(box.style.top || 0) + top) + "px";
}
}
#contain {
position: relative;
width: 200px;
height: 200px;
background-color: pink;
}
#sqr {
position: absolute;
width: 20px;
height: 20px;
background-color: blue;
}
<div id="contain">
<div id="sqr"></div>
</div>
Here's my take on it. React according to the position of the element, when it reaches a corner, change directions. This makes things easier, since we do not rely on actual positions to know where to go next step...
It is because, when animation gets to pos1 = [180, 180], it executes:
else if (pos1[0] >= 180 && pos1[1] >= 180) {
pos1[0]--;
box.style.left = pos1[0] + "px";
}
And then pos1 = [179, 180], which is not covered by the code.
I suggest using something like that:
var direction = 0; //0 - right, 1 - down, 2 - left, 3 - up
function slide() {
if (pos1[0] < 180 && pos1[1] = 0) {
direction = 0;
} else if (pos1[0] = 180 && pos1[1] < 180) {
direction = 1;
} else if (pos1[0] > 0 && pos1[1] = 180) {
direction = 2;
} else if (pos1[0] = 0 && pos1[1] > 0) {
direction = 3;
}
switch(direction){
case 0:
pos1[0]++;
break;
case 1:
pos1[1]++;
break;
case 2:
pos1[0]--;
break;
case 3:
pos1[1]--;
break;
}
box.style.left = pos1[0] + "px";
box.style.top = pos1[1] + "px";
}
I'm not usually a fan of doing someone's homework for them, but I got intrigued as to what would make it work and couldn't help myself. shrugs
The if statements have been tailored to be more explicit with what they need. This of course was achieved by following the methods suggested to you by #j08691, by just adding a console.log(pos1); at the top of each if section.
This is just for reference, in fact, #Salketer has managed to post before me and it looks a lot cleaner than this. The real answer is in the comments by #j08691
window.onload = function() {
var t = setInterval(slide, 5),
pos1 = [0, 0],
box = document.getElementById('sqr');
function slide() {
if (pos1[0] < 180 && pos1[1] === 0) {
console.log(pos1);
pos1[0]++;
box.style.left = pos1[0] + "px";
} else if (pos1[0] === 180 && pos1[1] < 180) {
console.log(pos1);
pos1[1]++;
box.style.top = pos1[1] + "px";
} else if ((pos1[0] <= 180 && pos1[0] >= 1) && pos1[1] === 180) {
console.log(pos1);
pos1[0]--;
box.style.left = pos1[0] + "px";
} else if (pos1[0] === 0 && pos1[1] <= 180) {
console.log(pos1);
pos1[1]--;
box.style.top = pos1[1] + "px";
}
}
}
#contain {
position: relative;
width: 200px;
height: 200px;
background-color: pink;
}
#sqr {
position: absolute;
width: 20px;
height: 20px;
background-color: blue;
}
<div id="contain">
<div id="sqr"></div>
</div>

Spaceship movement

I am creating a mini space ship game with a feel similar to escape velocity. I cannot seem to get inertia to work correctly.
I am also having problems with the turning functions. If I tap the left or right arrow keys then it does not follow anything similar to the circular type movement that should be happening.
$(function() {
var canvas = Raphael('game', 1000, 800);
var background = canvas.rect(0, 0, 1000, 800);
background.attr("fill", "black");
var ship = canvas.rect(200, 200, 10, 35);
ship.attr("fill", "red");
ship.angle = 0;
ship.turnrate = 4;
ship.maxSpeed = 2;
ship.acc = 0;
ship.accSpeed = 0.25;
ship.vel = [0,0];
var up = 0;
var left = 0;
var right = 0;
var speedx = 0;
var speedy = 0;
function moveShip() {
if (left == 1) {
ship.angle = (ship.angle - ship.turnrate) % 360;
}
if (right == 1) {
ship.angle = (ship.angle + ship.turnrate) % 360;
}
if (up == 1) {
if (ship.acc < ship.maxSpeed) {
ship.acc += ship.accSpeed;
}
if (ship.acc > ship.maxSpeed) {
ship.acc = ship.speed;
}
}
if (up == 0) {
if (ship.acc > 0) {
ship.acc -= ship.accSpeed;
}
if (ship.acc < 0) {
ship.acc = 0;
}
}
speedx = ship.vel[0] + ship.acc * Math.sin(ship.angle);
speedy = ship.vel[1] + ship.acc * Math.cos(ship.angle);
ship.vel = [speedx, speedy];
ship.transform("");
ship.rotate(ship.angle);
ship.attr({x: ship.vel[0], y: ship.vel[1]});
$("#stats").text("ship.angle: " + ship.angle
+ " vel[0]: " + ship.vel[0] + " vel[1]: " + ship.vel[1]
+ " ship.speed: " + ship.maxSpeed + " speedx: " + speedx + " speedy: " + speedy);
}
function keyPressed(evt) {
if (evt.keyCode == 38) {
up = 1;
}
if (evt.keyCode == 37) {
left = 1;
}
if (evt.keyCode == 39) {
right = 1;
}
}
function keyReleased(evt) {
if (evt.keyCode == 38) {
up = 0;
}
if (evt.keyCode == 37) {
left = 0;
}
if (evt.keyCode == 39) {
right = 0;
}
}
function gameloop() {
moveShip();
}
$(document).keydown(keyPressed);
$(document).keyup(keyReleased);
setInterval(gameloop, 30);
});
I have been searching stack overflow and the internet, but most questions out there are to do with the classic Space Invaders type game which does not involve turning or inertia.
Any help would be appreciated, I really just want to have a good understanding of what I am missing.
Are you sure you want to change the acceleration of a ship with the arrow keys? Remember, acceleration is the rate of change of the velocity. This means, if you have a constant acceleration then you velocity will start to grow and grow and grow. Pretty soon you will have a ship that is going way too fast.
The results from the chatroom, here for posterity:
$(function() {
var canvas = Raphael('game', 1000, 800);
var background = canvas.rect(0, 0, 1000, 800);
background.attr("fill", "black");
var ship = canvas.rect(200, 200, 10, 35);
ship.attr("fill", "red");
ship.angle = 0;
ship.turnrate = 4;
ship.maxSpeed = 0.25;
ship.acc = 0.25;
ship.vel = [0,0];
ship.pos = [500,400];
var up = 0;
var left = 0;
var right = 0;
var speedx = 0;
var speedy = 0;
function moveShip() {
if (left == 1) {
ship.angle = (ship.angle - ship.turnrate) % 360;
}
if (right == 1) {
ship.angle = (ship.angle + ship.turnrate) % 360;
}
if (up == 1) {
speedx = ship.vel[0] + ship.acc * Math.sin(ship.angle * Math.PI / 180);
speedy = ship.vel[1] - ship.acc * Math.cos(ship.angle * Math.PI / 180);
ship.vel = [speedx, speedy];
}
ship.pos = [ship.pos[0] + speedx, ship.pos[1] + speedy];
ship.transform("");
ship.rotate(ship.angle);
ship.attr({x: ship.pos[0], y: ship.pos[1]});
$("#stats").text("ship.angle: " + ship.angle
+ " vel[0]: " + ship.vel[0] + " vel[1]: " + ship.vel[1]
+ " ship.speed: " + ship.maxSpeed + " speedx: " + speedx + " speedy: " + speedy);
}
function keyPressed(evt) {
if (evt.keyCode == 38) {
up = 1;
}
if (evt.keyCode == 37) {
left = 1;
}
if (evt.keyCode == 39) {
right = 1;
}
}
function keyReleased(evt) {
if (evt.keyCode == 38) {
up = 0;
}
if (evt.keyCode == 37) {
left = 0;
}
if (evt.keyCode == 39) {
right = 0;
}
}
function gameloop() {
moveShip();
}
$(document).keydown(keyPressed);
$(document).keyup(keyReleased);
setInterval(gameloop, 30);
});​
There were two bugs fixed. A pos attribute was added, so that velocity and position can be updated separately. Also, Math.sin and Math.cos take angles in radians, so we converted the angle for those functions.
You can play with the results: http://jsfiddle.net/mJcN7/8/

Categories

Resources