Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Нужна помощь с анимацией (https://javascript.ru/forum/misc/84951-nuzhna-pomoshh-s-animaciejj.html)

Im_Ilya 13.02.2023 22:33

Нужна помощь с анимацией
 
Написал код с анимацией, хотел чисто на js без css вообщем квадрат стоит по центру экрана потом двигается на верх до конца экрана, потом на права до конца, потом вниз до конца потом налево и вверх обратно на свое место. И проблема у меня такая получилась вверх и направо он у меня идет, а вот вниз не хочет, точнее начинает идти потом проскакивает часть экрана и все, на лево вообще стоит на месте. не знаю что делать помогите
let box=document.getElementById(`red`);
let delay=10; //скорость
let coords=box.getBoundingClientRect(); //координаты в начальной точке
let windowWidth=document.documentElement.clientWidth;//размер экрана
let windowHeight=document.documentElement.clientHeight;//размер экрана
let count=0;          //
let countLeft=0;     //
let countBottom=0;// Счетчики
let countRight=0;   //
function edge()
{
    let coords2=box.getBoundingClientRect(); // отслеживаю координаты

    if(coords2.y!=0)   //двигаюсь вверх пока координата х не станет 0
    {
        setTimeout(edge,delay);
        box.style.bottom= count+'px';
        count++;
        
    }else
    if(coords2.x!=windowWidth-box.offsetWidth) //на право
    {
        
        setTimeout(edge,delay);
        box.style.left= countLeft+'px';
        countLeft++;
        
    }
    /* else 
    if(coords2.y!=windowHeight-box.offsetHeight) //вниз не работает как надо
    {
        setTimeout(edge,delay);
        box.style.top = countBottom +'px';
        countBottom++;
    } */
    /* else 
    if(coords2.x==coords.x) //на лево вообще не срабатывает
    {
        setTimeout(edge,delay);
        box.style.right= countRight+'px';
        countRight++;
    } */
    
    
    /*Это чисто проверки для себя не влияет на работу кода*/
    console.log(coords2.x);
    console.log(coords2.y);
    console.log('*******');
    
}

//edge();

console.log(windowWidth,windowHeight);
console.log(coords.x,coords.y);

рони 13.02.2023 22:51

Im_Ilya,
canvas Движение объектов по массиву координат

MallSerg 14.02.2023 06:09

https://javascript.ru/forum/misc/496...tml#post326928

voraa 14.02.2023 08:35

Анимацию через requestAnimationFrame нужно делать
<!DOCTYPE html>
<html>
<head>
<style>
#red {
	position: absolute;
	width: 25px;
	height: 25px;
	background-color: red;
}
body {
	height: 100%;
}
</style>
</head>
<body>
	<div id="red"></div>
	<button id="start">Start</button>
	<script>
		let box= document.getElementById('red');
		const boxrect = box.getBoundingClientRect();
		const boxWidth = boxrect.width;
		const boxHeight = boxrect.height
		const windowWidth=innerWidth;
		const windowHeight=innerHeight;
		const x0 = (windowWidth - boxWidth)/2;
		const y0 = (windowHeight - boxHeight)/2
		box.style.left = x0 + 'px';
		box.style.top = y0 + 'px';
		
		let direction = 'up';
		const rightX = windowWidth - boxWidth;
		const bottomY = windowHeight - boxHeight;
		
		const speed = 100; // px/s
		
		
		let lastT;
		let curX = x0;
		let curY = y0;
		
		const move = (nowT) => {
			if (lastT === undefined) lastT = nowT;
			let stop = false;
			const dt = nowT - lastT;
			const d = speed * dt / 1000;
			lastT = nowT;
			switch (direction) {
				case 'up':
					if (curY <= y0) {
						curY = Math.max(curY - d, 0);
						if (curY == 0) direction = 'right';
					} else {
						curY = Math.max(curY - d, y0);
						if (curY == y0) stop = true;
					}
					break;
				case 'right' :
					curX = Math.min(curX + d, rightX);
					if (curX == rightX) direction = 'down';
					break;
				case 'down':
					curY = Math.min (curY + d, bottomY);
					if (curY == bottomY) direction = 'left';
					break
				case 'left' :
					curX = Math.max(curX - d, x0);
					if (curX == x0) direction = 'up';
					break;					
			}
			box.style.top = curY + 'px';
			box.style.left = curX + 'px';

			if (!stop) 
				requestAnimationFrame(move);
			else
				lastT = undefined;
		}
		
		const start = document.getElementById('start');
		start.addEventListener ('click', () => requestAnimationFrame(move))
	</script>
</body>
</html>

Im_Ilya 14.02.2023 14:27

voraa,
не подскажите почему у меня анимация работала не так как надо? ведь логически то все верно. мне нужно понять может там нюансы какие-то есть?

Im_Ilya 14.02.2023 14:33

MallSerg,
не подскажите почему у меня анимация работала не так как надо? ведь логически то все верно. мне нужно понять может там нюансы какие-то есть?

Im_Ilya 14.02.2023 14:33

рони,
не подскажите почему у меня анимация работала не так как надо? ведь логически то все верно. мне нужно понять может там нюансы какие-то есть?

рони 14.02.2023 14:54

Im_Ilya,
не используйте ==при сравнении, точные числа в вычислении координат редкость! лучше >= , >, <, <=.
и не плодите однотипные сообщения.

Im_Ilya 14.02.2023 14:59

рони,
т.е. поэтому он у меня перескакивает часть экрана?

рони 14.02.2023 15:26

Цитата:

Сообщение от Im_Ilya
т.е. поэтому он у меня перескакивает часть экрана?

не только это, ещё лучше оставить только left и top

Im_Ilya 14.02.2023 15:51

рони,
Я думал об этом, а потом подумал в чем разница?)) если не сложно можете объяснить почему предпочтительнее использовать left и top

рони 14.02.2023 16:49

движение по периметру
 
Im_Ilya,
как-то так ... (два раза не жмакать, дождитесь окончания)
<!DOCTYPE html>
<html>

<head>
    <style>
        #red {
            position: fixed;
            width: 25px;
            height: 25px;
            background-color: red;
            left: 0;
            top: 0;
            right: 0;
            bottom: 0;
            margin: auto;
        }

        body {
            height: 100%;
        }
    </style>
</head>

<body>
    <div id="red"></div>
    <button id="start">Start</button>
    <script>
        let box = document.getElementById(`red`);
        let delay = 10; //скорость
        let coords = box.getBoundingClientRect();
        let {
            left: x,
            top: y
        } = coords;
        let l = 0,
            t = 0;

        function edge() {
            if (l == 0 && t > -2 * y && t <= 0) {
                box.style.top = `${--t}px`;
                setTimeout(edge, delay);
            } else
            if (l < 2 * x && t <= -2 * y) {
                box.style.left = `${++l}px`;
                setTimeout(edge, delay);
            } else if (l >= 2 * x && t < 2 * y) {
                box.style.top = `${++t}px`;
                setTimeout(edge, delay);
            } else if (l > 0 && t >= 2 * y) {
                box.style.left = `${--l}px`;
                setTimeout(edge, delay);
            } else if (l <= 0 && t > 0) {
                box.style.top = `${--t}px`;
                t > 0 && setTimeout(edge, delay);
            }
        }
        const start = document.getElementById('start')
        start.addEventListener('click', edge)
    </script>
</body>

</html>

voraa 14.02.2023 16:56

Цитата:

Сообщение от Im_Ilya
ведь логически то все верно.

Нет.
У вас если coords2.y != 0, то всегда будет срабатывать первое условие
if(coords2.y!=0)
до условия
if(coords2.y!=windowHeight-box.offsetHeight)
дело не дойдет.

А какой смысл, двигаясь вверх, менять bottom, а двигаясь вниз - менять top очень трудно представить.

Im_Ilya 15.02.2023 12:35

рони,
voraa,
Спасибо большое, благодаря вам я разобрался. Сейчас отредактирую свою функцию.

voraa 15.02.2023 12:51

Цитата:

Сообщение от Im_Ilya
Сейчас отредактирую свою функцию.

Только не делайте анимацию, через timeout.
Вы ставите delay = 10. Но если у монитора частота обновления экрана 60гц, то не будет через 10мс экран обновляться. Все равно будет через 1000/60 = 16.7 мс. Из за этого движение будет дерганным и не равномерным.
А requestAnimationFrame для этого и создана, что бы синхронизировать обновления страницы с частотой обновления экрана.

Im_Ilya 15.02.2023 13:07

voraa,
Хорошо. Спасибо за совет. Я почитал про эту функцию когда ваш пример разбирал, только единственное я не понял из вашего примера что за переменные NowT и LastT?

voraa 15.02.2023 13:18

В функцию, которая вызывается requestAnimationFrame передается параметр - время (Это некоторое время от окончания загрузки страницы). Зная время предыдущего вызова функции по requestAnimationFrame и текущего, мы можем определить какое время прошло между вызовами. Это же не всегда четко 16.7. Иногда и больше - браузер сам это решает.

LastT - время предыдущего вызова
NowT - время текущего вызова

Зная время между вызовами (const dt = nowT - lastT )и скорость (speed) с которой должен перемещаться элемент, можно высчитать на какое расстояние он должен сместиться между этими двумя вызовами.
const d = speed * dt / 1000;

Im_Ilya 15.02.2023 13:39

voraa,
Круто! Сам бы я не догадался, не тот уровень пока что)) Но все приходит с опытом

Im_Ilya 18.02.2023 21:43

voraa,
Подскажите еще, откуда передается параметр nowT? Я не могу сообразить

рони 18.02.2023 22:24

Цитата:

Сообщение от Im_Ilya
параметр nowT?

https://developer.mozilla.org/ru/doc...AnimationFrame
Цитата:

Callback методу передаётся один аргумент, DOMHighResTimeStamp, который содержит текущее время (количество миллисекунд, прошедших с момента time origin).
время прошедшее от создания страницы.


Часовой пояс GMT +3, время: 15:20.