HTML5 Javascript Canvas Collision 2
Spsoi
Posted on February 10, 2022
Читать сверху вниз
Будет пополнятся
Финал
Красим шарики под курсором
jsfiddle.net
function Particle (x, y, radius, color) { // шарик
// 2
this.x =x;
this.y = y;
this.radius = radius;
this.color = randomColor(colors);// !*
this.mass = 1;
this.opacity = 0; // !* // Прозрачность
this.velocity = {
x: (Math.random() - 0.5) * 5,// !*
y: (Math.random() - 0.5) * 5,// !*
}
this.update = particles => {
this.draw();
for (let i = 0; i < particles.length; i++) {
if (this === particles[i]) { continue }
if (getDistance(this.x, this.y, particles[i].x, particles[i].y) - this.radius * 2 < 0) {
resolveCollision(this, particles[i]); // !*
}
}
if (this.x - this.radius <= 0 ||
this.x + this.radius >= innerWidth) {
this.velocity.x = -this.velocity.x;
}
if (this.y - this.radius <= 0 ||
this.y + this.radius >= innerHeight) {
this.velocity.y = -this.velocity.y;
}
// В консоль что шарик под курсором мыши.
if (getDistance(mouse.x, mouse.y, this.x, this.y) < 120 && this.opacity < 0.2) { //*!
this.opacity += 0.02;
console.log('Под курсором');
}else if (this.opacity > 0) {
this.opacity -= 0.02;
this.opacity = Math.max(0, this.opacity);
}
this.x += this.velocity.x;
this.y += this.velocity.y;
}
this.draw = function () {
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
c.save(); //*! // сохраняем состаяние
c.globalAlpha = this.opacity;
c.fillStyle = this.color;
c.fill(); //*!
c.restore();//*! // востанавливаем состояние после c.save()
c.strokeStyle = this.color; //*!
c.stroke();
c.closePath();
}
}
Отскок не только от края но и от других частиц, кругов и т.д
function rotate(velocity, angle) { // !*
const rotatedVelocities = {
x: velocity.x * Math.cos(angle) - velocity.y * Math.sin(angle),
y: velocity.x * Math.sin(angle) + velocity.y * Math.cos(angle)
};
return rotatedVelocities;
}
function resolveCollision(particle, otherParticle) { // !*
const xVelocityDiff = particle.velocity.x - otherParticle.velocity.x;
const yVelocityDiff = particle.velocity.y - otherParticle.velocity.y;
const xDist = otherParticle.x - particle.x;
const yDist = otherParticle.y - particle.y;
// Предотвращение случайного наложения частиц
if (xVelocityDiff * xDist + yVelocityDiff * yDist >= 0) {
// Угол захвата между двумя сталкивающимися частицами
const angle = -Math.atan2(otherParticle.y - particle.y, otherParticle.x - particle.x);
// Сохраняем массу в переменную для лучшей читаемости в уравнении столкновения
const m1 = particle.mass;
const m2 = otherParticle.mass;
// Скорость до уравнения
const u1 = rotate(particle.velocity, angle);
const u2 = rotate(otherParticle.velocity, angle);
// Скорость после 1d уравнения столкновения
const v1 = { x: u1.x * (m1 - m2) / (m1 + m2) + u2.x * 2 * m2 / (m1 + m2), y: u1.y };
const v2 = { x: u2.x * (m1 - m2) / (m1 + m2) + u1.x * 2 * m2 / (m1 + m2), y: u2.y };
// Конечная скорость после поворота оси обратно в исходное положение
const vFinal1 = rotate(v1, -angle);
const vFinal2 = rotate(v2, -angle);
// Поменяй местами скорости частиц для реалистичного эффекта отскока
particle.velocity.x = vFinal1.x;
particle.velocity.y = vFinal1.y;
otherParticle.velocity.x = vFinal2.x;
otherParticle.velocity.y = vFinal2.y;
}
}
function Particle (x, y, radius, color) { // шарик
// 2
this.x =x;
this.y = y;
this.radius = radius;
this.color = color;
this.mass = 1;
this.velocity = {
x: Math.random() - 0.5,
y: Math.random() - 0.5,
}
this.update = particles => {
this.draw();
for (let i = 0; i < particles.length; i++) {
if (this === particles[i]) { continue }
if (getDistance(this.x, this.y, particles[i].x, particles[i].y) - this.radius * 2 < 0) {
resolveCollision(this, particles[i]); // !*
}
}
if (this.x - this.radius <= 0 ||
this.x + this.radius >= innerWidth) {
this.velocity.x = -this.velocity.x;
}
if (this.y - this.radius <= 0 ||
this.y + this.radius >= innerHeight) {
this.velocity.y = -this.velocity.y;
}
this.x += this.velocity.x;
this.y += this.velocity.y;
}
this.draw = function () {
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
c.fillStyle = this.color;
// c.fill(); //*!
c.stroke();
c.closePath();
}
}
Отскок от краёв экрана
function Particle (x, y, radius, color) { // шарик
// 2
this.x =x;
this.y = y;
this.radius = radius;
this.color = color;
this.velocity = {
x: Math.random() - 0.5,
y: Math.random() - 0.5,
}
this.update = particles => {
this.draw();
for (let i = 0; i < particles.length; i++) {
if (this === particles[i]) { continue }
if (getDistance(this.x, this.y, particles[i].x, particles[i].y) - this.radius * 2 < 0) {
console.log('has collided');
}
}
if (this.x - this.radius <= 0 || // !*
this.x + this.radius >= innerWidth) {
this.velocity.x = -this.velocity.x;
}
if (this.y - this.radius <= 0 || // !*
this.y + this.radius >= innerHeight) {
this.velocity.y = -this.velocity.y;
}
this.x += this.velocity.x;
this.y += this.velocity.y;
}
this.draw = function () {
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
c.fillStyle = this.color;
// c.fill(); //*!
c.stroke();
c.closePath();
}
}
Отслеживаем столкновения и пересечения кругов + анимируем
jsfiddle.net
function Particle (x, y, radius, color) { // шарик
// 2
this.x =x;
this.y = y;
this.radius = radius;
this.color = color;
this.velocity = { // !*
x: Math.random() - 0.5,
y: Math.random() - 0.5,
}
this.update = particles => { // !*
this.draw();
for (let i = 0; i < particles.length; i++) {// !*
if (this === particles[i]) { continue }
if (getDistance(this.x, this.y, particles[i].x, particles[i].y) - this.radius * 2 < 0) {
console.log('has collided');
}
}
this.x += this.velocity.x;// !*
this.y += this.velocity.y;// !*
}
this.draw = function () {
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
c.fillStyle = this.color;
// c.fill(); //*!
c.stroke();
c.closePath();
}
}
function animate() {
requestAnimationFrame(animate);
c.clearRect(0,0, canvas.width, canvas.height);
particles.forEach(particle => { // !*
particle.update(particles);// !*
})
}
Круги теперь не уходят за экран canvas на половину.
function init() { // точка входа
particles = [];
//1
for (let i = 0; i < 4; i++) {
const radius = 100;
let x = randomIntFromRange(radius, canvas.width - radius); // !*
let y = randomIntFromRange(radius, canvas.height - radius); // !*
const color = 'blue';
if ( i != 0 ) { // Если идёт пересечение кругов, отрисуй в другом месте.
for (let j = 0; j < particles.length; j++ ) {
if (getDistance(x, y, particles[j].x, particles[j].y) - radius * 2 < 0) {
x = randomIntFromRange(radius, canvas.width - radius); // !*
y = randomIntFromRange(radius, canvas.height - radius); // !*
j = -1;
}
}
}
particles.push (new Particle(x, y, radius, color))
}
}
Отрисуем 4 круга, если идёт пересечение кругов, отрисовать этот круг в другом месте.
function getDistance(x1, y1, x2, y2) { // расчёт дистанции до центра кругов
let xDistance = x2 -x1;
let yDistance = y2 -y1;
let distance = Math.pow(xDistance, 2) + Math.pow(yDistance, 2); // Теорема Пифагора
return Math.sqrt(distance); // квадратный корень числа
}
function init() { // точка входа
particles = [];
//1
for (let i = 0; i < 4; i++) {
let x = Math.random() * innerWidth;
let y = Math.random() * innerHeight;
const radius = 100;
const color = 'blue';
if ( i != 0 ) { // !* // Если идёт пересечение кругов, отрисуй в другом месте.
for (let j = 0; j < particles.length; j++ ) {
if (getDistance(x, y, particles[j].x, particles[j].y) - radius * 2 < 0) {
x = Math.random() * innerWidth;
y = Math.random() * innerHeight;
j = -1;
}
}
}
particles.push (new Particle(x, y, radius, color))
}
}
jsfiddle.net
Отрисуем 400 кружков
canvas = document.querySelector('#canvas');
let c = canvas.getContext('2d');
canvas.width = innerWidth;
canvas.height = innerHeight;
let mouse = {
x: innerWidth / 2,
y: innerHeight / 2
}
let colors = [
'#2185c5',
'#7ECEFD',
'#FFF6E5',
'#FF7F66'
];
document.addEventListener("mousemove", function(event){
mouse.x = event.clientX;
mouse.y = event.clientY;
});
addEventListener("resize", function(){
console.log()
canvas.width = innerWidth;
canvas.height = innerHeight;
// init();
});
function randomIntFromRange(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function randomColor (color){
return color[Math.floor(Math.random() * color.length)];
}
addEventListener("click", function () {
init();
})
function Particle (x, y, radius, color) { // шарик
// 2
this.x =x;
this.y = y;
this.radius = radius;
this.color = color;
this.update = function() {
this.draw();
}
this.draw = function () {
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
c.fillStyle = this.color;
c.fill();
c.stroke();
c.closePath();
}
}
let particles; //!*
function init() { // точка входа
particles = []; //!*
//1
for (let i = 0; i < 400; i++) { //!*
const x = Math.random() * innerWidth;
const y = Math.random() * innerHeight;
const radius = 10;
const color = 'blue';
particles.push (new Particle(x, y, radius, color))
}
}
function animate() {
requestAnimationFrame(animate);
c.clearRect(0,0, canvas.width, canvas.height);
particles.forEach(object => { //!*
object.update();
})
}
init();
animate();
style.css
canvas {
border: 1px solid #000;
}
index.html
<!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">
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body>
<canvas id="canvas" width="300" height="300"></canvas>
<script src="canvas.js" ></script>
</body>
</html>
💖 💪 🙅 🚩
Spsoi
Posted on February 10, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.