Показать сообщение отдельно
  #11 (permalink)  
Старый 19.10.2019, 05:28
Аватар для Malleys
Профессор
Отправить личное сообщение для Malleys Посмотреть профиль Найти все сообщения от Malleys
 
Регистрация: 20.12.2009
Сообщений: 1,714

Сообщение от рони
мне бы шарики прыг-скок от стенки и от друг друга на js.
Это физика: Impulse, Momentum, Two-dimensional elastic collision.

В этом примере учитывается позиция, импульс, масса. А вы можете добавить ещё больше физики, например, учитывать температуру, деформацию, гравитацию и пр. И сделать более интересный пример!
<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<style>
		html, body, canvas {
			display: block;
			margin: 0;
			background: black;
		}
	</style>
</head>

<body>
	<script>

function getRandomRGBColorString() {
	return "#" + ("000000" + Math.floor(0xffffff * Math.random()).toString(16)).slice(-6);
}

function distance(x1, y1, x2, y2) {
	const xDist = x2 - x1;
	const yDist = y2 - y1;

	return Math.sqrt(xDist ** 2 + yDist ** 2);
}

function rotate(velocity, angle) {
	return {
		x: velocity.x * Math.cos(angle) - velocity.y * Math.sin(angle),
		y: velocity.x * Math.sin(angle) + velocity.y * Math.cos(angle)
	};
}

function resolveCollision(a, b) {
	const dvx = a.velocity.x - b.velocity.x;
	const dvy = a.velocity.y - b.velocity.y;
	const dx = b.x - a.x;
	const dy = b.y - a.y;

	if (dvx * dx + dvy * dy >= 0) {
		const angle = -Math.atan2(dy, dx);
		const m1 = a.mass;
		const m2 = b.mass;
		const u1 = rotate(a.velocity, angle);
		const u2 = rotate(b.velocity, angle);
		const v1 = {
			x: (u1.x * (m1 - m2) + 2 * m2 * u2.x) / (m1 + m2),
			y: u1.y
		};
		const v2 = {
			x: (u2.x * (m2 - m1) + 2 * m1 * u1.x) / (m1 + m2),
			y: u2.y
		};

		a.velocity = rotate(v1, -angle);
		b.velocity = rotate(v2, -angle);
	}
}

class Circle {
	constructor(x, y, r) {
		const speed = 20 * Math.random();
		this.x = x;
		this.y = y;
		this.r = r;
		this.color = getRandomRGBColorString();
		this.mass = r / 3;
		this.velocity = {
			x: (Math.random() - 0.5) * speed,
			y: (Math.random() - 0.5) * speed
		}
	}

	render(context) {
		context.fillStyle = this.color;
		context.beginPath();
		context.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
		context.fill();
	}
}

class App {
	constructor(node) {
		const canvas = document.createElement("canvas");
		const context = canvas.getContext("2d");
		node.appendChild(canvas);

		addEventListener("resize", () => {
			canvas.width = innerWidth;
			canvas.height = innerHeight;
			this.init();
		});

		dispatchEvent(new Event("resize"));

		this.render(context);
	}

	init() {
		this.circles = [];

		for (let i = 0; i < 30; i++) {
			const r = 10 + 20 * Math.random();
			let x = Math.random() * (innerWidth - r * 2) + r;
			let y = Math.random() * (innerHeight - r * 2) + r;

			if (i !== 0) {
				for (let j = 0, k = 0; j < this.circles.length; j++) {
					if (distance(x, y, this.circles[j].x, this.circles[j].y) - r * 2 < 0) {
						x = Math.random() * (innerWidth - r * 2) + r;
						y = Math.random() * (innerHeight - r * 2) + r;
						j = -1;
						/* если вдруг новый шарик не удалось разместить */
						if(++k > 1000) break;
					}
				}
			}

			this.circles.push(new Circle(x, y, r));
		}
	}

	render(context) {
		context.clearRect(0, 0, innerWidth, innerHeight);

		for (const circle of this.circles) {
			if (circle.x + circle.r > innerWidth || circle.x - circle.r < 0) {
				circle.velocity.x = -circle.velocity.x;
			}

			if (circle.y + circle.r > innerHeight || circle.y - circle.r < 0) {
				circle.velocity.y = -circle.velocity.y;
			}

			circle.x += circle.velocity.x;
			circle.y += circle.velocity.y;

			for(const anOtherCircle of this.circles) {
				if (circle === anOtherCircle) continue;
				if (distance(circle.x, circle.y, anOtherCircle.x, anOtherCircle.y) - circle.r - anOtherCircle.r < 0)
					resolveCollision(circle, anOtherCircle);
			}

			circle.render(context);
		}

		requestAnimationFrame(() => this.render(context));
	}
}

new App(document.body);

	</script>
</body>

</html>

Последний раз редактировалось Malleys, 19.10.2019 в 10:50. Причина: Исправил индексы в формуле и упростил её.
Ответить с цитированием