Bonjour aux Alsanautes, je vous soumets ceci qui m'amuse beaucoup : comment transcoder le code suivant d'un canvas 2D en pur javascript sans canvas, c-à-d que l'on puisse articuler par css une class balloon aisément.
Le projet ne se limite pas au code qui suit parce que j'envisage d'écrire un clic pour une explosion des ballons avec un transfert de force en proximité, transform scale(1.5), filter:blur(_px) et transition opacity ... avec random et setInterval pour ne conserver que le dernier avec une annonce : - "le ballon gagnant est _".
Le code html qui suit est fonctionnel, c-à-d qu'il fonctionne bien (à vous de le constater et de le confirmer).
Ce code contient html, css et js :
Modifié par Gout-de-l-esprit (07 Dec 2024 - 08:06)
Le projet ne se limite pas au code qui suit parce que j'envisage d'écrire un clic pour une explosion des ballons avec un transfert de force en proximité, transform scale(1.5), filter:blur(_px) et transition opacity ... avec random et setInterval pour ne conserver que le dernier avec une annonce : - "le ballon gagnant est _".
Le code html qui suit est fonctionnel, c-à-d qu'il fonctionne bien (à vous de le constater et de le confirmer).
Ce code contient html, css et js :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Animation des Ballons</title>
<style>
body {
margin: 0;
overflow: hidden;
}
canvas {
display: block;
position:relative;
margin:auto;
top:50px;
background-image: linear-gradient(to bottom, #5f87ff, #959f93);
}
#startButton{
z-index:2;
position:absolute;
display:inline-block;
margin:20px 50%;
width:180px;
padding:10px;
left:-100px;
box-shadow:6px 6px 9px rgba(0,0,0,0.4)}
#startButton:active{box-shadow:none}
</style>
</head>
<body>
<button id="startButton">Démarrer l'animation</button>
<canvas id="canvas"></canvas>
<script>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
canvas.width = window.innerWidth - 100;
canvas.height = window.innerHeight - 100;
//canvas.width = window.innerWidth;
//canvas.height = window.innerHeight;
// Constantes
const gravity = 0.99; // Gravité
const friction = 0.95; // Frottement
const maxSpeed = 5; // Vitesse maximale
const balloonCount = 12; // Nombre de ballons***au choix*****************************************
const restingThreshold = 0.1; // Seuil pour considérer un ballon comme au repos
const overlapThreshold = 2 * 75; // Seuil de chevauchement entre ballons (diamètre)
// Classe pour un ballon
class Balloon {
constructor(number, x, y, radius) {
this.number = number;
this.x = x;
this.y = y;
this.radius = radius;
this.dx = (Math.random() + 4.5) * 5; // Vitesse horizontale
this.dy = Math.random() * maxSpeed * 2 - 3; // Vitesse verticale plus forte pour donner un angle de chute*/
this.color = `hsl(${Math.random() * 360}, 70%, 80%)`; // Couleur pastel aléatoire
this.rotation = Math.random() * Math.PI * 2; // Rotation aléatoire
this.rotationSpeed = Math.random() * 0.7 - 0.05; // Vitesse de rotation
this.isResting = false; // État du ballon (en mouvement ou au repos)
}
// Dessiner le ballon avec ombre interne
draw() {
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.rotation);
// Dessiner le ballon
ctx.beginPath();
ctx.arc(0, 0, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
// Dessiner l'ombre interne
const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, this.radius);
gradient.addColorStop(0, 'rgba(0, 0, 0, 0.4)'); // Centre transparent 0.4
gradient.addColorStop(1, 'rgba(0, 0, 0, 0.8)'); // Bord sombre
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.arc(0, 0, this.radius, 0, Math.PI * 2);
ctx.fill();
// Dessiner le numéro
ctx.fillStyle = '#fff';
ctx.font = `${this.radius / 1.2}px Arial`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(this.number, 0, 0);
ctx.restore();
}
// Mise à jour de la position et de la vitesse
update(balloons) {
// Appliquer la gravité
this.dy += gravity;
// Arrêter les ballons au repos
if (Math.abs(this.dy) < restingThreshold && this.y + this.radius >= canvas.height) {
this.dy = 0;
this.dx *= 0.95; // Réduction de la vitesse horizontale
this.isResting = true;
} else {
this.isResting = false;
}
// Déplacement
this.x += this.dx;
this.y += this.dy;
// Rotation en fonction de la vitesse horizontale (sans facteur de division incorrect)
this.rotationSpeed = this.dx / this.radius; // Utilisation directe de dx pour la rotation
this.rotation += this.rotationSpeed; // Mise à jour de la rotation
// Collision avec le sol
if (this.y + this.radius > canvas.height) {
this.y = canvas.height - this.radius;
this.dy *= -friction; // Rebondir avec un peu de friction ****************************
this.rotationSpeed *= friction; // Réduire la vitesse de rotation lors du rebond
}
// Collision avec les murs latéraux
if (this.x + this.radius > canvas.width || this.x - this.radius < 0) {
this.dx *= -friction * 2 / 3; // Petite modif subtile
if (this.x + this.radius > canvas.width) this.x = canvas.width - this.radius;
if (this.x - this.radius < 0) this.x = this.radius;
}
// Collision avec d'autres ballons
for (let i = 0; i < balloons.length; i++) {
if (this === balloons[i]) continue;
const dist = Math.hypot(this.x - balloons[i].x, this.y - balloons[i].y);
if (dist - this.radius * 2 < 0) {
resolveCollision(this, balloons[i]);
}
}
this.draw();
}
}
// Fonction pour résoudre la collision entre deux ballons
function resolveCollision(balloon1, balloon2) {
const dist = Math.hypot(balloon1.x - balloon2.x, balloon1.y - balloon2.y);
const overlap = balloon1.radius * 2 - dist;
if (overlap > 0) {
const angle = Math.atan2(balloon1.y - balloon2.y, balloon1.x - balloon2.x);
const normalX = Math.cos(angle);
const normalY = Math.sin(angle);
// Calculer la vitesse relative entre les deux ballons
const relativeVelocityX = balloon1.dx - balloon2.dx;
const relativeVelocityY = balloon1.dy - balloon2.dy;
// Calculer la vitesse le long de la normale de la collision
const velocityAlongNormal = relativeVelocityX * normalX + relativeVelocityY * normalY;
// Calculer la restitution (rebond) de la collision
if (velocityAlongNormal > 0) return;
const restitution = 1; // Coefficient de restitution (rebond parfait)
const impulse = (2 * velocityAlongNormal) / (balloon1.radius + balloon2.radius);
// Appliquer l'impulsion pour ajuster les vitesses des ballons
balloon1.dx -= impulse * balloon2.radius * normalX;
balloon1.dy -= impulse * balloon2.radius * normalY;
balloon2.dx += impulse * balloon1.radius * normalX;
balloon2.dy += impulse * balloon1.radius * normalY;
// Appliquer la rotation après la collision
const rotationChange1 = overlap * impulse * normalX;
const rotationChange2 = overlap * impulse * normalX;
balloon1.rotationSpeed += rotationChange1 / balloon1.radius;
balloon2.rotationSpeed += rotationChange2 / balloon2.radius;
// Déplacer les ballons pour éviter la superposition
const moveDistance = overlap / 2;
balloon1.x -= moveDistance * normalX;
balloon1.y -= moveDistance * normalY;
balloon2.x += moveDistance * normalX;
balloon2.y += moveDistance * normalY;
}
}
// Fonction pour empêcher la superposition des ballons
function preventOverlap(balloons) {
for (let i = 0; i < balloons.length; i++) {
for (let j = i + 1; j < balloons.length; j++) {
const dist = Math.hypot(balloons[i].x - balloons[j].x, balloons[i].y - balloons[j].y);
if (dist < 2 * balloons[i].radius) {
// Si les ballons sont trop proches, les séparer
const angle = Math.atan2(balloons[i].y - balloons[j].y, balloons[i].x - balloons[j].x);
const overlap = 2 * balloons[i].radius - dist;
const moveX = Math.cos(angle) * overlap / 2;
const moveY = Math.sin(angle) * overlap / 2;
// Déplacer les ballons pour respecter la distance minimale
balloons[i].x += moveX;
balloons[i].y += moveY;
balloons[j].x -= moveX;
balloons[j].y -= moveY;
}
}
}
}
// Initialiser les ballons
let balloons = [];
for (let i = 0; i < balloonCount; i++) {
let balloon = new Balloon(i + 1, Math.random() * (canvas.width - 150) + 75, Math.random() * (canvas.height - 150) + 75, 75);
balloons.push(balloon);
}
// Animer les ballons
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
preventOverlap(balloons);
for (let balloon of balloons) {
balloon.update(balloons);
}
requestAnimationFrame(animate);
}
// Démarrer l'animation au clic sur le bouton
document.getElementById("startButton").addEventListener("click", () => {
animate();
});
</script>
</body>
</html>
Modifié par Gout-de-l-esprit (07 Dec 2024 - 08:06)