I'm looking for some help with my java script game as i have just started getting into it now,
my problem is that my animation loops infinitely on autopay and reloads the page every time it meets the condition to restart,
what I want to achieve is have a start button that would start the game and the animation and score on click and if the condition for restart is met I have to press the start button again to play again
I would appreciate all the help I could get
const skate = document.getElementById("skate");
const rock = document.getElementById("rock");
const score = document.getElementById("score");
function jump() {
skate.classList.add("jump-animation");
setTimeout(() =>
skate.classList.remove("jump-animation"), 500);
}
document.addEventListener('keypress', (event) => {
if (!skate.classList.contains('jump-animation')) {
jump();
}
})
setInterval(() => {
const skateTop = parseInt(window.getComputedStyle(skate)
.getPropertyValue('top'));
const rockLeft = parseInt(window.getComputedStyle(rock)
.getPropertyValue('left'));
score.innerText++;
if (rockLeft < 0) {
rock.style.display = 'none';
} else {
rock.style.display = ''
}
if (rockLeft < 50 && rockLeft > 0 && skateTop > 150) {
location.reload();
}
}, 50);
#score { text-align: center; }
#game {
width: 600px;
height: 300px;
border: 2px solid black;
margin: auto;
background-image: url("./background.gif");
background-size: cover;
}
#skate {
height: 75px;
width: 75px;
top: 220px;
position: relative;
background-image: url("./skateboard.png");
background-size: cover;
}
#rock {
width: 50px;
height: 50px;
position: relative;
top: 175px;
left: 550px;
background-image: url("./rock.png");
background-size: cover;
animation: rock 1.33s infinite;
}
#keyframes rock {
0%{left: 550px;}
100%{left: -50px;}
}
.jump-animation {
animation: jump 0.5s;
}
#keyframes jump {
0%{top: 225px;}
50%{top: 75px;}
75%{top: 75px;}
100%{top: 225px;}
}
<div id="game">
<div id="skate"></div>
<div id="rock"></div>
</div>
<h1 id="score">0</h1>
The trick here is to have a variable at the top scope of this module to track the ID of the current animation so that the animation/interval can be turned off if the user presses the start button before the current game ends. It should also turn off once the end-game condition is met, although I'm not really sure why window.getComputedStyle() is being used to compute the variables used for that condition, but I guess it's still a work in progress.
EDIT: Somehow I didn't notice that the player and obstacle were already in the game so I added colors to them for easier debugging, at least on my end. This time I made it so that the rock will lose then immediately regain a class for its animation, but the re-addition needs to be asynchronous even if the delay is 0ms.
index.html
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="game">
<div id="skate"></div>
<div id="rock"></div>
</div>
<h1 id="score">0</h1>
</div>
<div>
<button id="new-game">New Game </button>
</div>
</body>
<script>
const skate = document.getElementById("skate");
const rock = document.getElementById("rock");
const score = document.getElementById("score");
const newGameButton = document.getElementById("new-game");
function jump() {
skate.classList.add("jump-animation");
setTimeout(() => skate.classList.remove("jump-animation"), 500);
}
document.addEventListener('keypress', (event) => {
if (!skate.classList.contains('jump-animation')) {
jump();
}
});
let animationId;
newGameButton.addEventListener('click', () => {
resetScore();
resetRockAnimation();
playScoreAnimation();
function resetScore() {
clearInterval(animationId);
score.innerText = 0;
}
function resetRockAnimation() {
rock.classList = [];
setTimeout(() => rock.classList.add('rock-animation'), 0);
}
function playScoreAnimation() {
animationId = setInterval(() => {
const skateTop = parseInt(window.getComputedStyle(skate).getPropertyValue('top'));
const rockLeft = parseInt(window.getComputedStyle(rock).getPropertyValue('left'));
score.innerText++;
if (rockLeft < 0) {
rock.style.display = 'none';
}
else {
rock.style.display = '';
}
if (rockLeft < 50 && rockLeft > 0 && skateTop > 150) {
clearInterval(animationId);
}
}, 50);
}
});
</script>
style.css
#score {
text-align: center;
}
#game {
width: 600px;
height: 300px;
border: 2px solid black;
margin: auto;
background-image: url("./background.gif");
background-size: cover;
}
#skate {
height: 75px;
width: 75px;
top: 225px;
position: relative;
background-image: url("./skateboard.png");
background-size: cover;
background-color: slategrey;
}
#rock {
width: 50px;
height: 50px;
position: relative;
top: 175px;
left: 550px;
background-image: url("./rock.png");
background-size: cover;
background-color: lightcoral ;
}
.rock-animation {
animation: rock 1.33s infinite;
}
#keyframes rock {
0% {
left: 550px;
}
100% {
left: -50px;
}
}
.jump-animation {
animation: jump 0.5s;
}
#keyframes jump {
0% {
top: 225px;
}
50% {
top: 75px;
}
75% {
top: 75px;
}
100% {
top: 225px;
}
}
Related
I made this audio player but the codesandbox does not work in mobile devices. It works perfectly fine in desktop.
I get 'Could not get the stack frame of error' error when i try to play song from my phone.
Audio player
The player gets audio files data in a javascript object and they get built into a list. The audios start playing when list item is clicked. The code looks like this
$(function () {
$("#time-progress").progress({ percent: 0 });
let audio = new Audio();
const songs = [
{
artist: "Yaru Makaveli & Yada Sads",
image: "https://i.ytimg.com/vi/rI2vJENDvmY/maxresdefault.jpg",
title: "Cypher Weyn",
song: "cypherweyn2.mp3"
},
{
artist: "Abebe Araya",
image: "https://i.ytimg.com/vi/mp_cR7pVEcw/maxresdefault.jpg",
title: "Natsnet",
song: "natsnet.mp3"
},
{
artist: "Shewit & Semere",
image: "https://i.ytimg.com/vi/ucolLdVzRyg/maxresdefault.jpg",
title: "Betey",
song: "betey.mp3"
},
{
artist: "Q Rap M.O.DB",
image: "https://i.scdn.co/image/ab6761610000e5eb749c5e25b3d167fd3008914b",
title: "Waero",
song: "waero.mp3"
},
{
artist: "Yaru Makaveli & Yada Sads",
image: "https://i.ytimg.com/vi/rI2vJENDvmY/maxresdefault.jpg",
title: "Tealime",
song: "tealime.mp3"
},
{
artist: "Eden Gebreselassie",
image:
"https://is4-ssl.mzstatic.com/image/thumb/Music116/v4/00/4a/14/004a1407-eaed-45d3-048d-12dae76b7d3f/artwork.jpg/375x375bb.jpg",
title: "Goblel",
song: "goblel.mp3"
},
{
artist: "Amanuel Yemane",
image: "https://i.ytimg.com/vi/iukjMznrHcI/maxresdefault.jpg",
title: "Adi Latni",
song: "adilatni.mp3"
},
{
artist: "Tmnit Welday",
image: "https://i.ytimg.com/vi/MqVT5GdW6hQ/maxresdefault.jpg",
title: "Segar",
song: "segar.mp3"
}
];
let list_of_songs = songs
.map(function (song, index) {
return ` <div class="item" data-src="${song.song}"" data-title="${song.title}" data-artist="${song.artist}" data-index=${index} data-image=${song.image}>
<img class="ui avatar image" src="${song.image}"">
<div class="content">
<div id="equalizer">
<div id="bar1"></div>
<div id="bar2"></div>
<div id="bar3"></div>
<div id="bar4"></div>
</div>
<i class="icon button-overlay circle outline"></i>
<span class="header">${song.title}</span>
<div class="description">${song.artist}</div>
</div>
</div>`;
})
.join("");
let play = document.querySelector("#play");
let currentSong = 0;
document.getElementById("song-list").innerHTML = list_of_songs;
audio = new Audio(`./music/${songs[0].song}`);
let icons = document.querySelectorAll(".icon");
$(document).on("click", ".item", function () {
let { src, artist, title, image, index } = this.dataset;
currentSong = Number(index);
let list_items = document.querySelectorAll(".item");
list_items.forEach((e) => {
e.classList.remove("active");
});
this.classList.add("active");
let newaudio = new Audio(`./music/${src}`);
if (audio.currentTime > 0 && !audio.paused && audio.src == newaudio.src) {
play.classList.remove("pause");
play.classList.add("play");
audio.pause();
this.querySelector(".button-overlay").classList.add("play");
this.querySelector(".button-overlay").classList.remove("pause");
} else if (
audio.currentTime > 0 &&
audio.paused &&
audio.src == newaudio.src
) {
play.classList.remove("play");
play.classList.add("pause");
this.querySelector(".button-overlay").classList.add("pause");
this.querySelector(".button-overlay").classList.remove("play");
audio.play();
} else {
this.querySelector(".button-overlay").classList.add("pause");
this.querySelector(".button-overlay").classList.remove("play");
playSong(src, artist, title, image);
}
});
audio.addEventListener("timeupdate", function (e) {
let currentTime = audio.currentTime;
let duration = audio.duration;
let minutes = Math.floor(currentTime / 60);
minutes = minutes >= 10 ? minutes : "0" + minutes;
let seconds = Math.floor(currentTime % 60);
seconds = seconds >= 10 ? seconds : "0" + seconds;
document.querySelector("#timer").innerText = `${minutes}:${seconds}`;
//progress
let status = Math.floor((currentTime / duration) * 100);
$("#time-progress").progress({ percent: status });
});
let artist_img = document.querySelector(".artist-image");
let song_title = document.querySelector("#title");
icons.forEach((icon) => {
icon.addEventListener("click", (e) => {
let type = e.target.dataset.type;
let image, src, artist, title;
var list_items = document.querySelectorAll(".item");
switch (type) {
case "play":
if (audio.currentTime > 0) {
play.classList.remove("play");
play.classList.add("pause");
play.dataset.type = "pause";
audio.play();
} else {
currentSong = 0;
let item = document.querySelector(".item");
item.classList.add("active");
item.querySelector(".icon").classList.add("pause");
document
.querySelector(".item")
.querySelector(".button-overlay")
.classList.remove("play");
const { song, artist, title, image } = songs[0];
playSong(song, title, artist, image);
}
break;
case "pause":
audio.pause();
artist_img.classList.remove("rotate-image");
e.target.classList.remove("pause");
e.target.classList.add("play");
e.target.dataset.type = "play";
break;
case "prev":
currentSong =
currentSong - 1 < 0 ? songs.length - 1 : currentSong - 1;
list_items.forEach((e) => {
e.classList.remove("active");
});
list_items[currentSong].classList.add("active");
var off =
$(".item.active").offset().top - $("#song-list").offset().top;
$("#song-list").scrollTop(off);
image = songs[currentSong].image;
src = songs[currentSong].song;
artist = songs[currentSong].artist;
title = songs[currentSong].title;
playSong(src, title, artist, image);
break;
case "next":
currentSong =
currentSong + 1 > songs.length - 1 ? 0 : currentSong + 1;
list_items.forEach((e, index) => {
e.classList.remove("active");
});
list_items[currentSong].classList.add("active");
var off =
$(".item.active").offset().top - $("#song-list").offset().top;
$("#song-list").scrollTop(off);
image = songs[currentSong].image;
src = songs[currentSong].song;
artist = songs[currentSong].artist;
title = songs[currentSong].title;
playSong(src, title, artist, image);
break;
default:
break;
}
});
});
function playSong(src, artist, title, image) {
document.querySelector(
".artist-img-bg"
).style.backgroundImage = `url(${image})`;
audio.src = `./music/${src}`;
artist_img.src = `${image}`;
artist_img.classList.add("rotate-image");
song_title.innerText = `${artist} - ${title}`;
document.querySelector("#title").classList.add("song-title");
play.classList.remove("play");
play.classList.add("pause");
play.dataset.type = "pause";
audio.play();
}
$(document).on("click", ".button-overlay", function () {
if (audio.currentTime > 0) {
this.classList.remove("play");
this.classList.add("pause");
audio.play();
}
});
});
body {
margin: 0;
padding: 0;
z-index: 101;
}
.container {
padding: 15px;
margin: 0 auto;
width: 100%;
background: linear-gradient(#042a45, #7295ae);
display: flex;
height: 100vh;
align-items: center;
justify-content: center;
z-index: 100;
}
.music-player {
width: 400px;
height: auto;
background: linear-gradient(to top,#042a45, #7295ae);
border-radius: 1em;
display: flex;
align-items: center;
flex-direction: column;
padding: 10px;
}
#top-img-container {
width: 100%;
min-height: 200px;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
}
.artist-img-bg {
filter: blur(3px);
-webkit-filter: blur(3px);
background-repeat: no-repeat;
background-size: cover;
background-position: center;
position: absolute;
z-index: 1;
width: 100%;
min-height: 200px;
}
.artist-image {
margin-top: 20px ;
max-height: 300px;
width: 150px;height: 150px;max-width: 300px;
border-radius: 50%;
box-shadow: 0 0 10px 10px #154275;
position: absolute;
z-index: 999;
}
.rotate-image {
animation:rotate 100s infinite;
animation-timing-function: linear;
}
#keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(365deg);
}
}
.controls {
width: 100%;
margin-bottom: 2em;
margin-top: 1em;display: flex;
justify-content:space-around;
}
.icon {
color:aliceblue;
font-size: 1.5em !important;
cursor: pointer;
transition: transform .2s ease-in-out;
}
.icon:hover {
transform: scale(1.2);
}
.song-title-container {
position: relative;
overflow: hidden;
width: 90%;
margin: 10px auto 0;
}
.song-title {
margin: 10px 0 15px;
text-align: center;
color: #ffffff;
font-weight: 700;animation: song_title 7s infinite ease-in-out 3s;
animation-timing-function: linear;
position: relative;
}
#keyframes song_title {
0% {
left:0%;
} 49% {
left: -100%;
visibility: hidden;
} 50% {
left: 200%;
visibility: hidden;
}
51% {
left: 100%;
visibility: visible;
}
100% {
visibility: visible;
left: 0%
}
}
#timer, #song-list .header, #song-list .description {
color: white;
}
#playlist-title {
color: white;
width: 100%;
margin-left: 20px;
}
#song-list {
height: 200px;overflow-y: scroll;width: 95%;
background-color: #16415f;
border-radius: 1em;
}
#song-list .item {
cursor: pointer;
padding: 10px;
position: relative;
}
.item.active {
background-color: #38596e;
box-shadow: 0px 2px 10px #07141d;
}
.list-image {
position: relative;
display: inline;
}
.content .icon {
position: absolute;
left: 20px;
top: 20px;
visibility: hidden;
}
.item.active .content .button-overlay {
visibility: visible;
}
#song-list .avatar {
width: 3em;
height: 3em;
}
#song-list .item:hover {
background-color: #3a5a6f;
}
#equalizer {
position: absolute;
right: 5px;top: 50%;transform: translateY(-50%);width: 40px;
max-height: 20px;
visibility: hidden;
display: flex;
justify-content: space-evenly;
}
.item.active .content #equalizer {
visibility: visible;
}
#bar1, #bar2, #bar3, #bar4 {
background-color: #1aa303;
width: 2px;
}
#bar1 {
animation: bar1 1.2s linear infinite;
}
#bar2 {
animation: bar2 0.9s linear infinite;
}
#bar3 {
animation: bar2 1.4s linear infinite;
}
#bar4 {
animation: bar4 1s linear infinite;
}
#keyframes bar1 {
0% {
height: 5px;
}
50% {
height: 10px;
}
100% {
height: 5px;
}
}#keyframes bar2 {
0% {
height: 10px;
}
50% {
height: 5px;
}
100% {
height: 10px;
}
}
#keyframes bar3 {
0% {
height: 5px;
}
50% {
height: 10px;
}
100% {
height: 5px;
}
}
#keyframes bar4 {
0% {
height: 10px;
}
50% {
height:5px;
}
100% {
height: 10px;
}
}
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Music Player</title>
<link rel="stylesheet" href="./main.css" />
<link
href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css"
rel="stylesheet"
/>
</head>
<body>
<div class="ui-container container">
<div class="music-player">
<div id="top-img-container">
<div class="artist-img-bg"></div>
<img
src="https://i.pinimg.com/originals/1d/3a/26/1d3a2651f9ad02fb12aae08f618a2847.png"
class="artist-image"
alt="on and on"
/>
</div>
<div class="song-title-container">
<h3 id="title"></h3>
<div id="time-progress" class="ui tiny progress">
<div style="min-width: 1%" class="bar"></div>
<div id="timer" class="label">-00:00-</div>
</div>
</div>
<div class="controls">
<i data-type="prev" id="prev" class="icon backward"></i>
<i data-type="play" id="play" class="icon play circle outline"></i>
<i data-type="next" id="pause" class="icon forward"></i>
</div>
<h3 id="playlist-title">Playlist - Best of 2021</h3>
<div id="song-list" class="ui middle aligned divided list"></div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.js"></script>
<script type="text/javascript" src="./main.js"></script>
</body>
</html>
It works fine in desktop browsers but it does not work in mobile devices. What am I doin wrong?
I want to trigger an animation that makes the game screen fade to greyscale when the character dies. This is my first game so it is rather simple. I have not been able to successfully trigger the animation. I have not been able to successfully trigger the animation. Online, I found that document.getElementById("object").animationPlayState = "running" should work, but it doesn't. This is my game loop and CSS (game is a <div> in HTML).
link to full code in codepen (doesn't work properly): https://codepen.io/flyingchicken22/pen/NWgVrJq
CSS:
#game {
width: 600px;
height: 300px;
border: 2px solid black;
margin: auto;
background-image: url("https://t3.ftcdn.net/jpg/01/73/79/26/360_F_173792623_516juhwjkCCZJ9OyesyH7hf7r9zsyH5u.jpg");
background-size: cover;
animation: deathAnimation 2s;
animation-play-state: paused;
}
#keyframes deathAnimation {
0%{filter:none;}
100%{filter:grayscale(100%);}
}
Javascript:
var gameLoop = setInterval(() => {
dead = false
function rockAnimation() {
rock.classList.add('rockAnimation')
}
const knightTop = parseInt(window.getComputedStyle(knight).getPropertyValue('top'))
const rockLeft = parseInt(window.getComputedStyle(rock).getPropertyValue('left'))
if (rockLeft < 0) {
rock.style.display = 'none'
} else {
rock.style.display = ''
}
if (rockLeft < 90 && rockLeft > 50 && knightTop > 79) {
dead = true
}
score.innerText++
const deathAnimation = document.getElementById("deathAnimation")
const game = document.getElementById("game")
if (dead == true) {
clearInterval(gameLoop)
document.getElementById("youDied").innerHTML = "YOU DIED"
document.getElementById("playAgain").innerHTML = "Play Again?"
game.classList.add(deathAnimation)
document.getElementById("deathAnimation").style.animationPlayState = "running"
}
}, 50);
You are trying to return an HTML element that does not exist. Change document.getElementById("deathAnimation").style.animationPlayState = "running" to document.getElementById("game").style.animationPlayState = "running"
Try the following snippet
const background = document.getElementById('game')
const knight = document.getElementById('knight')
const rock = document.getElementById('rock')
const score = document.getElementById('score')
//transfers jump animation to script
function jump() {
knight.classList.add('jump-animation')
setTimeout(() => {
knight.classList.remove('jump-animation')
}, 500)
}
//When any key is pressed, run jump animation
document.addEventListener('keypress', () => {
if (!knight.classList.contains('jump-animation') && dead == false) {
jump();
}
})
//game loop
let dead
var gameLoop = setInterval(() => {
dead = false
function rockAnimation() {
rock.classList.add('rockAnimation')
}
const knightTop = parseInt(window.getComputedStyle(knight).getPropertyValue('top'))
const rockLeft = parseInt(window.getComputedStyle(rock).getPropertyValue('left'))
if (rockLeft < 0) {
rock.style.display = 'none'
} else {
rock.style.display = ''
}
if (rockLeft < 90 && rockLeft > 50 && knightTop > 79) {
dead = true
}
score.innerText++
const deathAnimation = document.getElementById("deathAnimation")
const game = document.getElementById("game")
if (dead == true) {
clearInterval(gameLoop)
document.getElementById("youDied").innerHTML = "YOU DIED"
game.classList.add(deathAnimation)
document.getElementById("game").style.animationPlayState = "running"
}
}, 50);
html {
background-color: black;
}
#score {
text-align: center;
color: rgba(102, 255, 0, 0.993);
}
#game {
width: 600px;
height: 300px;
border: 2px solid black;
margin: auto;
background-image: url("https://t3.ftcdn.net/jpg/01/73/79/26/360_F_173792623_516juhwjkCCZJ9OyesyH7hf7r9zsyH5u.jpg");
background-size: cover;
animation: deathAnimation 2s;
animation-play-state: paused;
}
#keyframes deathAnimation {
0%{filter:none;}
100%{filter:grayscale(100%);}
}
#knight {
height: 100px;
width: 75px;
position: relative;
top: 171px;
left: 50px;
background-image: url("https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/f57b5304-de59-49e3-b0f9-cc29a2458425/dcgy8i3-e6dac283-04a7-40e5-a333-cc645e172df7.png?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7InBhdGgiOiJcL2ZcL2Y1N2I1MzA0LWRlNTktNDllMy1iMGY5LWNjMjlhMjQ1ODQyNVwvZGNneThpMy1lNmRhYzI4My0wNGE3LTQwZTUtYTMzMy1jYzY0NWUxNzJkZjcucG5nIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmZpbGUuZG93bmxvYWQiXX0.0LapCzRi5sQjkqzwB5lwWQT_XH1BM4rSMZt7jrflMLk");
background-size: cover;
}
#rock {
height: 50px;
width: 50px;
position: relative;
top: 122px;
left: 550px;
background-image: url("http://pixelartmaker-data-78746291193.nyc3.digitaloceanspaces.com/image/da268f06e621b21.png");
background-size: cover;
animation: rockAnimation 1s linear;
}
#keyframes rockAnimation {
0%{left: 500px;}
100%{left: -50px;}
}
.jump-animation {
animation: jump 0.5s;
}
#keyframes jump {
0%{top: 171px;}
50%{top: 70px;}
75%{top: 70px;}
100%{top: 171px;}
}
#font-face {
font-family: VT323;
src: url(https://fonts.googleapis.com/css2?family=VT323&display=swap);
}
#gameName {
text-align: center;
color: rgba(102, 255, 0, 0.993);
font-size: 300%;
font-family: 'VT323';
}
#youDied {
text-align: center;
color: rgba(102, 255, 0, 0.993);
animation: youDied 2s infinite;
}
#keyframes youDied {
0%{color: rgba(102, 255, 0, 0.993);}
50%{color: black}
100%{color: rgba(102, 255, 0, 0.993);}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="game">
<div id="knight"></div>
<div id="rock"></div>
</div>
<h1 id="score">0</h1>
<h1 id="gameName">KNIGHT HOPPER</h1>
<h1 id="youDied"></h1>
<script src="script.js"></script>
</body>
</html>
I am trying to make connect4 HTML game and I know I will be better off using canvas elements instead of a grids of divs but is it possible to make transition translate type of css animation when moving HTML elements around like this (using appendChild)
const row1 = document.getElementById("row1")
const row2 = document.getElementById("row2")
const ball = document.getElementById("TheBall")
ball.addEventListener("click", (event, element) => {
let rowNum = parseInt(ball.dataset.row)
if(rowNum==1) {
row2.appendChild(ball)
ball.dataset.row = 2
} else {
row1.appendChild(ball)
ball.dataset.row = 1
}
})
#main {
left:100px;
width: 100px;
height: 100px;
display: flex;
flex-direction: column;
}
#main div {
margin: 50px 0;
width: 50px;
height: 50px;
}
#TheBall {
width: auto;
height: auto;
background-color: red;
border-radius: 100%;
}
<div id="main">
<div id="row1"> </div>
<div id="row2">
<div id="TheBall" data-row=2></div>
</div>
</div>
Click on the red dot to toggle position of ball
You can use animationend to check when the animation end and move the ball element between the divs
const row1 = document.getElementById("row1")
const row2 = document.getElementById("row2")
const ball = document.getElementById("TheBall")
ball.addEventListener('animationend', () => {
ball.classList.remove("animate-ball");
ball.style.animation = "";
let rowNum = parseInt(ball.dataset.row)
if (rowNum == 1) {
row2.appendChild(ball)
ball.dataset.row = 2
} else {
row1.appendChild(ball)
ball.dataset.row = 1
}
});
ball.addEventListener("click", (event, element) => {
let rowNum = parseInt(ball.dataset.row)
if (rowNum == 1) {
ball.style.animation = "MoveDown 1s linear";
} else {
ball.style.animation = "MoveUp 1s linear";
}
ball.classList.add("animate-ball");
})
#main {
left: 100px;
width: 100px;
height: 100px;
display: flex;
flex-direction: column;
}
#main div {
margin: 50px 0;
width: 50px;
height: 50px;
}
#TheBall {
position: relative;
width: auto;
height: auto;
background-color: red;
border-radius: 100%;
}
.animate-ball {
animation-iteration-count: 1;
position: absolute;
bottom: 0;
}
#keyframes MoveUp {
0% {
top: -50px;
}
100% {
top: -100px;
}
}
#keyframes MoveDown {
0% {
top: 0;
}
100% {
top: 50px;
}
}
<div id="main">
<div id="row1"> </div>
<div id="row2">
<div id="TheBall" data-row=2></div>
</div>
</div>
function lineComplete() {
let line = document.getElementById("line");
for (let percentage = 0; percentage <= 100; percentage++) {
setTimeout(function() {
line.style.width = `${percentage}%`;
}, percentage * 25);
if (percentage === 100) {
undo();
}
}
function undo() {
for (let percent = 100; percent >= 0; percent--) {
setTimeout(function() {
line.style.width = `${percent}%`;
}, percent * 25);
}
}
}
#outLine {
width: 60%;
height: 20px;
margin: 10px 0px;
background-image: linear-gradient(to right, #f12711, #f12711);
border-radius: 20px;
}
#line {
background-image: linear-gradient(to right, #f12711, #f5af19);
height: 100%;
width: 100%;
border-radius: 20px;
}
<body onload="lineComplete()">
<div id="outLine">
<div id="line"></div>
</div>
</body>
In the above snippet, I am trying to show a loader-like effect which I am able to achieve. The problem is that when the width of line is 100%, I am trying to fire the function undo. This also works fine. There is a loop in undo which decreases the width of line and gradually bring its width to 0%. The loop also works fine as I have tried to run it after replacing its contents with alert() and it worked fine. But with the present situation, the loop is not resizing the line. I think that it is not able to override the styles.
You can simplify your code like this. No forloop and setTimeout needed.
function lineComplete() {
let line = document.getElementById("line");
line.classList.add("active");
line.addEventListener("transitionend", () => {
line.classList.remove("active");
});
}
#outLine {
width: 60%;
height: 20px;
margin: 10px 0px;
background-image: linear-gradient(to right, #f12711, #f12711);
border-radius: 20px;
overflow: hidden;
}
#line {
background-image: linear-gradient(to right, #f12711, #f5af19);
height: 100%;
width: 0%;
border-radius: 20px;
transition: 2s linear;
}
#line.active {
width: 100%;
}
<body onload="lineComplete()">
<div id="outLine">
<div id="line"></div>
</div>
</body>
Also can be done with only animations:
#outLine {
width: 60%;
height: 20px;
margin: 10px 0px;
background-image: linear-gradient(to right, #f12711, #f12711);
border-radius: 20px;
overflow: hidden;
}
#line {
background-image: linear-gradient(to right, #f12711, #f5af19);
height: 100%;
width: 0%;
border-radius: 20px;
transition: 4s linear;
}
#line.active {
animation: linecomplete 2s linear forwards;
/* you can use "infinite" instead of "forwards" if you want */
}
#keyframes linecomplete {
50% {
width: 100%;
}
}
<div id="outLine">
<div id="line" class="active"></div>
</div>
function lineComplete() {
let line = document.getElementById("line");
for (let percentage = 0; percentage <= 100; percentage++) {
setTimeout(function() {
line.style.width = `${percentage}%`;
if (line.style.width === "100%") {
undo();
}
}, percentage * 25);
}
function undo() {
for (let percent = 100; percent >= 0; percent--) {
setTimeout(function() {
line.style.width = `${100 - percent}%`;
}, percent * 25);
}
}
}
#outLine {
width: 60%;
height: 20px;
margin: 10px 0px;
background-image: linear-gradient(to right, #f12711, #f12711);
border-radius: 20px;
}
#line {
background-image: linear-gradient(to right, #f12711, #f5af19);
height: 100%;
width: 100%;
border-radius: 20px;
}
<body onload="lineComplete()">
<div id="outLine">
<div id="line"></div>
</div>
</body>
The problem was that when you decrease, the later iterations are scheduled to run earlier than the earlier iterations. Let's negate percentage (100 - percentage) and it will work.
I need you guys to help as, I am new to programming. Why my second key code is not working. I'm not sure am I suppose to type that for my if loop. What I want my program to be is, when pressing "1", it goes to my first position that I set. And if I press "2" it will go to the second position if the current position is at my first position, if not it will go back to my start position.
Please help, below is my coding.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<!-- <meta http-equiv="refresh" content="30"> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
body {
height: 100%;
width: 100%;
background-image: url("TPHRG floorplan1.png");
background-repeat: no-repeat;
background-attachment: fixed;
/* background-position: center; */
background-size: 980px 400px, cover;
}
.robot_start_top {
top: 280px;
transition: top 2s;
}
.robot_start_left {
position: fixed;
left: 600px;
transition: all 2s;
}
.robot_end_left {
left: 570px;
}
.robot_end_top {
top: 180px;
}
.robot1_start_left {
position: fixed;
left: 570px;
transition: left 4s;
}
.robot1_end_left {
left: 520px;
}
.robot2_start_left {
position: fixed;
left: 520px;
transition: left 4s;
}
.robot2_end_left {
left: 470px;
}
.robot3_end_down {
top: 280px;
}
.robot3_end_right {
left: 600px;
}
</style>
</head>
<body onkeydown="move(event)">
<div class="robot_start_left robot_start_top" id="app">
<img id="robot" style= width:30px; height:40px" src="pic_8.PNG">
</div>
<script>
var move = function(event) {
if (event.keyCode === 49) {
const appDiv = document.getElementById("app");
setTimeout(function() {
appDiv.classList.add("robot_end_top");
}, 0);
setTimeout(function() {
appDiv.classList.add("robot_end_left");
}, 2000);
}
if (event.keyCode === 50) {
if (document.getElementById("app") === appDiv.classList.add("robot_end_left"))
{
const appDiv = document.getElementById("app");
setTimeout(function() {
appDiv.classList.add("robot_end_top");
}, 0);
setTimeout(function() {
appDiv.classList.add("robot2_end_left");
}, 2000);
}
else{
const appDiv = document.getElementById("app");
setTimeout(function() {
appDiv.classList.add("robot3_end_down");
}, 2000);
setTimeout(function() {
appDiv.classList.add("robot3_end_right");
}, 0)
setTimeout(function() { window.location.reload(true); }, 4000);
}}
};
</script>
</body>
</html>
Your missing a quotation (") in the style attribute of the img tag. I'm fixing that in the code below.
Important
I strongly suggest that you refactor the code so it's easier to build on, and to debug. I show how that can be done in the code below. The "move" methods are pretty similar, so you can write one function to handle all of them, instead of having separate methods that does almost the same thing.
Implementation
You need to remove all classes before adding new ones, or you will end up with having lots of classes on the #app element. But if you remove the classes, position: fixed will disappear, so I broke that property out and placed it under #app in the CSS. I also moved your "style" properties into an CSS class – #robot.
I renamed "move" to "moveRobot" as well. Gives more context when the methods are called moveTopLeft within the moveRobot method.
I also removed the last zero in the CSS classes, so the robot is visible when you're running the snippet.
Down below, I implemented your thoughts, but commented out all setTimeouts, so it's easier to follow what's going on. What you will discover is that if you remove the classes, the transition wont happen, because #app doesn't remember the last position of left and top.
What you actually need is to set left and top in code (ex. appDiv.styles.left = '300px'), and abandon the idea of adding classes to the robot. I believe that this will make the code shorter as well.
const appDiv = document.getElementById("app"); // Make this public so it's accessible everywhere;
var lastKeyStroke = -1;
var moveRobot = function(event) {
const KEY_NUM_ONE = 49,
KEY_NUM_TWO = 50;
let keyStroke = event.keyCode;
let pressedSameKeyTwice = keyStroke === lastKeyStroke; // not implemented
removeAllPreviousClasses();
console.clear();
if (keyStroke === KEY_NUM_ONE) {
console.log("pressed 1");
moveTopLeft();
}
else if (keyStroke === KEY_NUM_TWO) {
console.log("pressed 2");
moveTopRight();
}
else {
console.log("pressed anything else");
moveBottomRight();
}
lastKeyStroke = keyStroke;
}
function removeAllPreviousClasses() {
appDiv.className = "";
}
function moveTopLeft() {
//setTimeout(function() {
appDiv.classList.add("robot_end_top");
//}, 0);
//setTimeout(function() {
appDiv.classList.add("robot_end_left");
//}, 2000);
}
function moveTopRight() {
//setTimeout(function() {
appDiv.classList.add("robot_end_top");
//}, 0);
//setTimeout(function() {
appDiv.classList.add("robot2_end_left");
//}, 2000);
}
function moveBottomRight() {
//setTimeout(function() {
appDiv.classList.add("robot3_end_down");
//}, 2000);
//setTimeout(function() {
appDiv.classList.add("robot3_end_right");
//}, 0)
//setTimeout(function() { window.location.reload(true); }, 4000);
// removed excessive ending curly bracket
// }
}
body {
height: 100%;
width: 100%;
background-image: url("TPHRG floorplan1.png");
background-repeat: no-repeat;
background-attachment: fixed;
background-size: 980px 400px, cover;
}
#app {
position: fixed;
transition: left 2s, top 2s;
}
#robot { /* added these */
width: 30px;
height: 40px;
}
.robot3_end_down, /* added these together */
.robot_start_top {
top: 28px;
}
.robot_start_left {
left: 60px;
}
.robot_end_left {
left: 57px;
}
.robot_end_top {
top: 18px;
}
.robot1_start_left {
left: 57px;
}
.robot2_start_left, /* added these together */
.robot1_end_left {
left: 52px;
}
.robot2_end_left {
left: 47px;
}
.robot3_end_right {
left: 60px;
}
<body onkeydown="moveRobot(event)">
<div class="robot_start_left robot_start_top" id="app">
<img id="robot" src="https://simpleicon.com/wp-content/uploads/android.png">
</div>
</body>
There were some problems with the if else conditions and the const appDiv in the code its working fine now
var move = function (event) {
const appDiv = document.getElementById("app");
if (event.keyCode === 49) {
setTimeout(function () {
appDiv.classList.add("robot_end_top");
}, 0);
setTimeout(function () {
appDiv.classList.add("robot_end_left");
}, 2000);
}
else if (event.keyCode === 50) {
console.log('2')
if (document.getElementById("app") === appDiv.classList.add("robot_end_left")) {
const appDiv = document.getElementById("app");
setTimeout(function () {
appDiv.classList.add("robot_end_top");
}, 0);
setTimeout(function () {
appDiv.classList.add("robot2_end_left");
}, 2000);
}
}
else {
console.log('3')
const appDiv = document.getElementById("app");
setTimeout(function () {
appDiv.classList.add("robot3_end_down");
}, 2000);
setTimeout(function () {
appDiv.classList.add("robot3_end_right");
}, 0)
setTimeout(function () { window.location.reload(true); }, 4000);
}
}
;
body {
height: 100%;
width: 100%;
background-image: url("TPHRG floorplan1.png");
background-repeat: no-repeat;
background-attachment: fixed;
/* background-position: center; */
background-size: 980px 400px, cover;
}
.robot_start_top {
top: 280px;
transition: top 2s;
}
.robot_start_left {
position: fixed;
left: 600px;
transition: all 2s;
}
.robot_end_left {
left: 570px;
}
.robot_end_top {
top: 180px;
}
.robot1_start_left {
position: fixed;
left: 570px;
transition: left 4s;
}
.robot1_end_left {
left: 520px;
}
.robot2_start_left {
position: fixed;
left: 520px;
transition: left 4s;
}
.robot2_end_left {
left: 470px;
}
.robot3_end_down {
top: 280px;
}
.robot3_end_right {
left: 600px;
}
<body onkeydown="move(event)">
<div class="robot_start_left robot_start_top" id="app">
<img id="robot" style=width:30px; height:40px"
src="https://petapixel.com/assets/uploads/2019/02/mooncompositemain-800x800.jpg">
</div>
</body>