Подскажите как реализовать функцию для рандомных элементов?
Ребята строго не судите мой код я только учусь! Но конструктивной критике буду рад!
проблема следующая решил для практики создать что то на подобие страницы с вкладками на которых игры простые! вот на втором этапе завис и не могу решить проблема в том что мне нужно что бы объекты #rock+i которые я создаю в js появлялись с разной периодичностью и двигались в низ с разной скоростью пробовал многое получалось сделать только так что бы одновременно и с одной и той же скоростью они двигались. Крч получается все кроме задуманного. Пробовал и через массив и через цикл. как можно реализовать такое? подскажите плз! Да и в принципе если есть возможность было бы не плохо получить мнение профессионалов по моему коду, понятно что он кривой но хотелось бы узнать на чем нужно поработать мне!

var $btn = document.querySelector('#start');
var $game = document.querySelector('#game');
var $time =document.querySelector('#time') ;
var $app = document.querySelector('.wrapper-marks-js');
var $isGame = false;
var $timeHeader = document.querySelector('#time-header');
var $result = document.querySelector('#result-header');
var $resultText = 0;
var $appContent = document.querySelector('#app');
var $appContentId = document.querySelectorAll('.app');
$btn.addEventListener('click',startGame);
function startGame (){
$timeHeader.classList.remove('hide');
$result.classList.add('hide');
$resultText=0;
document.querySelector('#result').textContent = $resultText;
$isGame = true;
if ($isGame && document.querySelector('#game-time').value>0 ){
var $valueTime = document.querySelector('#game-time').value;
$time.textContent = $valueTime;
var interval = setInterval(function (){
var time = parseFloat($time.textContent);
if (time<=0){
clearInterval(interval);
endGame();
}else{
$time.textContent = (time-0.1).toFixed(1);
}
},100);
$btn.classList.add('hide');
$game.style.backgroundColor = '#fff';
renderBox();
}else{
}
}
function renderBox(){
var box = document.createElement('div');
var size = Math.round(Math.random()*(100-20)+20);
var left = Math.round(Math.random()*(207-5)+5);
var top = Math.round(Math.random()*(207-5)+5);
///случайная генерация цвета
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
box.style.height = box.style.width = size+'px';
box.style.position = 'absolute';
box.style.backgroundColor = getRandomColor();
box.style.top = top+'px';
box.style.left = left+'px';
box.style.cursor = 'pointer';
box.classList.add('box-last');
$game.insertAdjacentElement("afterbegin",box);
if ($isGame){
box.addEventListener('click',function(){
box.remove();
renderBox();
$resultText+=1;
document.querySelector('#result').textContent = $resultText;
});
}else{
box.remove();
}
}
function endGame(){
$isGame = false;
$btn.classList.remove('hide');
$game.style.backgroundColor = '#ccc';
$timeHeader.classList.add('hide');
$result.classList.remove('hide');
var $hideBox = document.querySelector('.box-last');
$hideBox.classList.add('hide');
}
colors=['red','green','blue'];
colors[0] = '#ff9393' ;
colors[30] = 'green' ;
colors[60] = 'blue' ;
colors[90] = 'red' ;
// вкладки игровые
for (i=0; i<30*4; i+=30){
var radio = document.createElement('input');
radio.setAttribute('id','tab-btn-'+i);
radio.setAttribute('name','tab-btn-radio');
radio.setAttribute('type','radio');
radio.classList.add('radio-tbs');
var mark = document.createElement('label');
mark.setAttribute('for','tab-btn-'+i);
mark.classList.add('mark_game');
mark.style.left = 40+i+'px';
$app.insertAdjacentElement("afterbegin",mark);
$app.insertAdjacentElement("afterbegin",radio);
mark.style.backgroundColor = colors[i];
radio.addEventListener('change',function(){
for (i=0; i<4; i++){
$appContentId[i].classList.remove('show');
}
idNumber= this.getAttribute('id');
var isNumber;
var Show;
if (idNumber.length === 9){
isNumber= idNumber.slice(-2);
Show= 'app'+isNumber;
}else if(idNumber.length === 10){
isNumber= idNumber.slice(-3);
Show= 'app'+isNumber;
}
Show= 'app'+isNumber;
idContent = document.querySelector('#'+Show);
idContent.classList.add('show');
idContent.style.backgroundColor=colors[isNumber.substr(1)];
});
}
// ---------Game-Two-----------
var $btnTwo = document.querySelector('#start-two');
var $gameTwo = document.querySelector('#game-two');
var $plane = document.querySelector('.plane');
$btnTwo.addEventListener('click',startGameTwo);
function startGameTwo (){
$gameTwo.style.backgroundImage = "url('img/space.jpg')";
$btnTwo.classList.add('hide');
$rock= document.querySelector('#rock');
var go = true;
document.addEventListener('keydown', function manual(event){
// console.log('Key: ', event.key);
// console.log('keyCode: ', event.keyCode);
// console.log( $plane.style.left);
if(event.keyCode === 65){
string=$plane.style.left.substring(0, $plane.style.left.length - 1);
$plane.style.left = Number(string)-2+'%';
if(Number(string)<=4){
$plane.style.left = 4+'%';
}
console.log(string);
console.log(go);
}else if(event.keyCode === 68){
string=$plane.style.left.substring(0, $plane.style.left.length - 1);
$plane.style.left = Number(string)+2+'%';
if(Number(string)>=96){
$plane.style.left = 96+'%';
}
}else if(event.keyCode === 87){
string=$plane.style.bottom.substring(0, $plane.style.bottom.length - 1);
$plane.style.bottom = Number(string)+2+'%';
if(Number(string)>=20){
$plane.style.bottom = 20+'%';
}
}else if(event.keyCode === 83){
string=$plane.style.bottom.substring(0, $plane.style.bottom.length - 1);
$plane.style.bottom = Number(string)-2+'%';
if(Number(string)<=0){
$plane.style.bottom = 0+'%';
}
}
});
function rockdrop(){
time = Math.round(Math.random()*(50-10)+10);
for (i=0; i<=5; i++){
var rockSide = Math.round(Math.random()*(94-6)+6);
$rockItem = document.createElement('img');
$gameTwo.insertAdjacentElement("afterbegin",$rockItem);
$rockItem.setAttribute('id',"rock"+i);
rockId= document.querySelector('#rock'+i);
rockId.style.bottom = 575+'px';
rockId.style.left = rockSide+'%';
$rockItem.setAttribute('src',"./img/rock (1).svg");
$rockItem.classList.add('rock');
}
$rockArray=Array.from(document.querySelectorAll('.rock'));
function dropDown (Item){
Item.style.bottom = parseInt(Item.style.bottom)-1+'px';
}
console.log($rockArray);
function drop (){
for (var key in $rockArray){
setTimeout(setInterval(dropDown($rockArray[key]),time),time);
if ( parseInt($rockArray[key].style.bottom) <= -53){
$rockArray[key].remove();
}
}
}
drop();
}
rockdrop();
}
// это мои попытки реализовать функцию.
// if(document.getElementsByClassName('rock').length > 0){
// $rockArray=Array.from(document.querySelectorAll('.rock'));
// for (var key in $rockArray){
// function drop (){
// $rockArray[key].style.bottom = parseInt($rockArray[key].style.bottom)-1+'px';
// if ( parseInt($rockArray[key].style.bottom) <= -53){
// $rockArray[key].remove();
// }else{
// // rockdrop();
// }
// }
// setInterval(drop,time);
// }
// }
// setTimeout(setInterval(drop(),100),500);
// if (document.getElementsByClassName('rock').length >= 5){
// break;
// }else if(document.getElementsByClassName('rock').length < 5){
// // for(s=0; s<=5; s++){
// // time = Math.round(Math.random()*(600-500)+500);
// // setInterval(rockdrop(s),time);
// // setTimeout(setInterval(drop,100),time);
// // }
// }
// iterator+=1;
// }
// }
// var $rockArray = document.querySelectorAll('.rock');
// rockdrop();
/* Animation */
@keyframes slide {
from {top: 0;}
50% {top: -10;}
to {top: -20;}
}
/* ---------------------------- */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
outline: none;
}
body {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
padding: 20px;
overflow: hidden;
background: linear-gradient(#CB356B, #BD3F32);
}
.app {
display: none;
position: relative;
background: #ff9393;
padding: 20px;
width: 600px;
margin: 0 auto;
box-shadow: 0 1px 30px 0 rgba(0,0,0,0.14), 0 0px 0px 0 rgba(0,0,0,.12), 0 0px 0px 0px rgba(0,0,0,.3);
border-radius: 10px;
}
.app__header {
padding: 20px;
text-align: center;
}
.app__content {
display: flex;
position: relative;
align-items: center;
justify-content: center;
}
.app__footer {
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
.input {
display: flex;
flex-direction: column;
margin-bottom: 10px;
}
.input label {
display: inline-block;
max-width: 100%;
margin-bottom: 3px;
color: #acacac;
font-family: GothamPro,sans-serif;
font-size: .8rem;
font-weight: normal;
line-height: 1.2rem;
}
.input input {
display: block;
width: 100%;
max-height: 2.8rem;
padding: .8rem 1rem;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: 1.4;
color: #000;
background: #fff none;
border: 1px solid #999;
border-radius: 5px;
}
.game {
position: relative;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #ccc;
background: #ccc;
min-height: 300px;
min-width: 300px;
max-width: 300px;
max-height: 300px;
}
.game-two{
position: relative;
min-height: 575px;
min-width: 575px;
max-width: 575px;
max-height: 575px;
background: #ccc;
}
.hide {
display: none!important;
}
.btn {
position: absolute;
z-index: 1;
display: inline-block;
padding: 1rem 2.3rem;
margin-bottom: 0;
font-weight: normal;
font-family: GothamPro, sans-serif;
font-size: 1rem;
line-height: 1.3rem;
text-align: center;
white-space: nowrap;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
user-select: none;
background: #fad64e;
color: #3f3f3f;
border: none;
border-radius: 2.8rem;
transition: transform .2s ease-in-out,box-shadow .2s ease-in-out,-webkit-transform .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;
will-change: transform;
}
.btn:disabled {
background: #ccc!important;
border: 1px solid #ccc;
color: #000;
cursor: not-allowed;
}
.btn:active {
transition: transform .1s ease-in-out,box-shadow .1s ease-in-out!important;
transform: none!important;
box-shadow: none!important;
}
.btn:hover {
box-shadow: 0 6px 16px 0 rgba(0,0,0,.2);
transform: translateY(-1px);
}
.wrapper-marks{
margin: 0 auto;
width: 197px;
height: 50px;
background: none;
position: relative;
/* top: -15px;
left: 0; */
}
.mark_game{
position: absolute;
top: 0;
background-color: #000;
width: 28px;
height: 50px;
/* z-index: -1; */
border-radius: 10px;
}
.mark_game:hover{
cursor: pointer;
top: -20px;
animation-duration: 0.8s;
animation-name: slide;
}
.mark_game_active{
top: -20px;
}
.wrapper-marks-js{
width: 100%;
height: 100%;
display: flex;
justify-content: space-around;
position: absolute;
top: 31px;
left: -230px;
}
.radio-tbs{
display: none;
}
#tab-btn-0:checked~#app-0,
#tab-btn-30:checked~#app-30,
#tab-btn-60:checked~#app-60,
#tab-btn-90:checked~#app-90 {
display: block;
}
input[type="radio"]:checked+label {
top: -20px;
}
.show {
display: block;
}
#app-30.app {
width: 850px
}
.plane {
position:absolute;
bottom: 1%;
/* left: 50%; */
width: 50px;
height: 55px;
transform: translate(-50%);
}
.rock {
position:absolute;
bottom: 100%;
left: 50%;
width: 50px;
height: 55px;
transform: translate(-50%);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="styles.css">
<title>JS Game</title>
</head>
<body>
<div class="wrapper-marks">
<div class="wrapper-marks-js">
<!-- <div class="mark_game"></div> -->
</div>
</div>
<div class="app show" id="app-0">
<div class="app__header">
<h1 id="time-header">Время игры: <span id="time"></span></h1>
<h1 id="result-header" class="hide">Ваш результат: <span id="result"></span></h1>
</div>
<div class="app__content">
<button class="btn" id="start">Начать</button>
<div class="game" id="game"></div>
</div>
<div class="app__footer">
<div class="input">
<label for="game-time">Время игры, (сек)</label>
<input type="number" id="game-time" min="5" step="1" value="5">
</div>
</div>
</div>
<div class="app" id="app-30">
<div class="app__header">
</div>
<div class="app__content">
<button class="btn" id="start-two">Начать</button>
<div class="game-two" id="game-two">
<img style="left: 50%;" class="plane" id="plane" src="./img/plane.svg" alt="">
<!-- <img class="rock" id="rock" src="./img/rock (1).svg" alt=""> -->
</div>
</div>
<div class="app__footer">
<div class="input">
</div>
</div>
</div>
<div class="app" id="app-60">
<div class="app__header">
<h1 id="time-header">Вкладка 3 <span id="time"></span></h1>
<h1 id="result-header" class="hide">Ваш результат: <span id="result"></span></h1>
</div>
<div class="app__content">
<button class="btn" id="start">Начать</button>
<div class="game" id="game"></div>
</div>
<div class="app__footer">
<div class="input">
<label for="game-time">Время игры, (сек)</label>
<input type="number" id="game-time" min="5" step="1" value="5">
</div>
</div>
</div>
<div class="app" id="app-90">
<div class="app__header">
<h1 id="time-header">вкладка 4 <span id="time"></span></h1>
<h1 id="result-header" class="hide">Ваш результат: <span id="result"></span></h1>
</div>
<div class="app__content">
<button class="btn" id="start">Начать</button>
<div class="game" id="game"></div>
</div>
<div class="app__footer">
<div class="input">
<label for="game-time">Время игры, (сек)</label>
<input type="number" id="game-time" min="5" step="1" value="5">
</div>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
Ответы (1 шт):
Здесь задача появления объектов в разное время решена с помощью функции createItemsToFall(), которая сначала создает все временные отрезки на которых будут появляться новые объекты (исходя из MAX_TIME - время игры и MAX_INTERVAL/MIN_INTERVAL - диапазон временных интервалов появления новых объектов). Затем в цикле объявляется очередная setTimeout(), которая через текущий временной интервал добавит в itemsToFall новый объект.
Уже в функции drawItems() каждому объекту из itemsToFall назначаются новые координаты по Y и, если объект не достиг конца, отрисовывается. В противном случае, объект удаляется из набора (Set).
Вместо анимации на canvas можно так же добавлять абсолютно позиционированные html-элементы с меняющимся атрибутом top.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const w = canvas.width = 600;
const h = canvas.height = 180;
const MAX_SPEED = 4;
const MIN_SPEED = 1;
const MAX_SIZE = 40;
const MIN_SIZE = 15;
const MAX_TIME = 8000;
const MAX_INTERVAL = 500;
const MIN_INTERVAL = 100;
const itemsToFall = createItemsToFall();
const start = performance.now();
drawItems();
function createItem(){
return {
speed : ((Math.random()*(MAX_SPEED-MIN_SPEED)+MIN_SPEED)*10|0)/10,
x : (Math.random()*(w - MAX_SIZE))|0 + MAX_SIZE/2,
color : `rgb(${(Math.random()*255)|0},${(Math.random()*255)|0},${(Math.random()*255)|0})`,
size : (Math.random()*(MAX_SIZE-MIN_SIZE)+MIN_SIZE)|0,
y : 0
}
}
function createItemsToFall(){
const arr = [];
const set = new Set();
let time = 0;
while(time < MAX_TIME){
time += (Math.random()*(MAX_INTERVAL - MIN_INTERVAL)+MIN_INTERVAL)|0;
arr.push(time);
}
arr.splice(arr.length-1, 1);
arr.forEach(interval => {
setTimeout(() => {set.add(createItem())},interval);
})
return set;
}
function drawItems(){
ctx.clearRect(0,0,w,h);
for (let item of itemsToFall){
item.y += item.speed;
if(item.y-item.size/2 > h){
itemsToFall.delete(item);
continue;
}
ctx.fillStyle = item.color;
ctx.fillRect(item.x-item.size/2,item.y-item.size/2,item.size,item.size);
}
let raf = requestAnimationFrame(drawItems);
if(performance.now() > start + MAX_TIME){
cancelAnimationFrame(raf);
ctx.fillRect(0,0,w,h);
ctx.font = "48px serif";
ctx.textAlign = 'center';
ctx.textBaseLine = 'middle';
ctx.fillStyle = 'white';
ctx.fillText("Time is over", w/2, h/2);
}
}
<canvas id="canvas"></canvas>