아래로 떨어지면서 쌓이는 애니메이션 도와주세요ㅠㅠ!!!!
본문
아래로 떨어지면서 쌓이는 애니메이션을 구현하고 싶은데 js 만으로 구현이 될까요 ????ㅠㅠ
전부 리엑트로 구현한 것만 나와서 ㅠㅠ.... 오픈코드 아시는분 부탁드립니다 ,,!!!
답변 5
단순 위에서 아래로 중력에 의한 오브젝트 정렬이라면
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Falling Circles Simulation</title>
<style>
body {
margin: 0;
overflow: hidden;
}
canvas {
display: block;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const circles = [];
const numCircles = 6;
const gravity = 0.1;
const friction = 0.99;
const minRadius = 10;
const maxRadius = 100;
const canvasWidth = 500;
const canvasHeight = 500;
const boxHeight = 100;
canvas.width = canvasWidth;
canvas.height = canvasHeight;
class Circle {
constructor(x, y, radius, vx = 0, vy = 0) {
this.x = x;
this.y = y;
this.radius = radius;
this.vx = vx;
this.vy = vy;
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(0, 150, 255, 0.7)';
ctx.fill();
ctx.strokeStyle = 'rgba(0, 100, 200, 0.9)';
ctx.stroke();
}
update() {
this.vy += gravity;
this.vx *= friction;
this.vy *= friction;
this.x += this.vx;
this.y += this.vy;
if (this.x + this.radius > canvasWidth) {
this.x = canvasWidth - this.radius;
this.vx *= -0.8;
}
if (this.x - this.radius < 0) {
this.x = this.radius;
this.vx *= -0.8;
}
if (this.y + this.radius > canvasHeight - boxHeight) {
this.y = canvasHeight - boxHeight - this.radius;
this.vy *= -0.8;
}
for (const other of circles) {
if (other !== this) {
const dx = this.x - other.x;
const dy = this.y - other.y;
const distance = Math.sqrt(dx * dx + dy * dy);
const minDistance = this.radius + other.radius;
if (distance < minDistance) {
const angle = Math.atan2(dy, dx);
const overlap = minDistance - distance;
// Separate the circles
this.x += Math.cos(angle) * (overlap / 2);
this.y += Math.sin(angle) * (overlap / 2);
other.x -= Math.cos(angle) * (overlap / 2);
other.y -= Math.sin(angle) * (overlap / 2);
// Simple collision response
const normalX = dx / distance;
const normalY = dy / distance;
const relativeVelocityX = this.vx - other.vx;
const relativeVelocityY = this.vy - other.vy;
const dotProduct = (relativeVelocityX * normalX) + (relativeVelocityY * normalY);
if (dotProduct > 0) {
const coefficientOfRestitution = 0.8; // Bounciness factor
const massSum = this.radius + other.radius;
const impulse = (2 * dotProduct) / massSum;
this.vx -= impulse * other.radius * normalX;
this.vy -= impulse * other.radius * normalY;
other.vx += impulse * this.radius * normalX;
other.vy += impulse * this.radius * normalY;
}
}
}
}
}
}
function generateRandomCircle() {
const radius = Math.random() * (maxRadius - minRadius) + minRadius;
const x = Math.random() * (canvasWidth - radius * 2) + radius;
const y = Math.random() * -500 - radius;
const vx = (Math.random() - 0.5) * 2;
const vy = (Math.random() - 0.5) * 2;
return new Circle(x, y, radius, vx, vy);
}
function createCircles() {
for (let i = 0; i < numCircles; i++) {
circles.push(generateRandomCircle());
}
}
function drawBox() {
ctx.fillStyle = 'rgba(100, 100, 100, 0.5)';
ctx.fillRect(0, canvasHeight - boxHeight, canvasWidth, boxHeight);
}
function animate() {
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
drawBox();
for (const circle of circles) {
circle.update();
circle.draw();
}
requestAnimationFrame(animate);
}
createCircles();
animate();
</script>
</body>
</html>
이정도면 될것 같은데 이게 단순 math로 구현하기엔 변수가 너무 많습니다.
별도 플러그인도 해외에서 찾아보면 있을것 같기도 한데
구글신에게 의뢰해보세요..
!-->아래의 코드 한번 참고를 해보시겠어요..
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Falling Animation</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
margin: 0;
overflow: hidden;
}
.container {
position: relative;
width: 300px;
height: 400px;
border: 2px solid #ccc;
border-radius: 10px;
overflow: hidden;
background-color: white;
}
.shape {
position: absolute;
width: 50px;
height: 50px;
background-color: red;
}
.shape.square {
border-radius: 0;
background-color: blue;
}
.shape.rectangle {
width: 30px;
height: 60px;
border-radius: 10px;
background-color: green;
}
.shape.triangle {
width: 0;
height: 0;
border-left: 25px solid transparent;
border-right: 25px solid transparent;
border-bottom: 50px solid yellow;
background-color: transparent;
}
</style>
</head>
<body>
<div class="container">
<div class="shape"></div>
<div class="shape square"></div>
<div class="shape rectangle"></div>
<div class="shape triangle"></div>
</div>
<script>
document.addEventListener("DOMContentLoaded", () => {
const shapes = document.querySelectorAll('.shape');
const containerHeight = document.querySelector('.container').offsetHeight;
shapes.forEach((shape, index) => {
let delay = index * 0.5; // 각 도형마다 0.5초 간격으로 떨어지게 설정
shape.style.top = `-50px`; // 초기 위치 위로 설정
shape.style.left = `${Math.random() * 250}px`; // 무작위 위치 설정
// 애니메이션 시작
setTimeout(() => {
shape.style.transition = `top 2s ease-in-out`;
shape.style.top = `${containerHeight - shape.offsetHeight}px`; // 바닥까지 떨어지게 설정
}, delay * 1000);
});
});
</script>
</body>
</html>
js 로는 어렵습니다..
아예 불가능한건 아닌데..
물리엔진 구현에는 한계가 있어서요...
떨어져야 하는 위치가 정해져 있다면 js+css 만으로도 가능해보이고
수박게임 처럼 위치가 불규칙적이라면 단순 js 만으로는 불가합니다.
혹시 원하시는 형태로 정확히 동작하는 샘플 주소나 다른 코드 경로 찍어주실 수 있으세요~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Falling Circles Simulation</title>
<style>
body {
margin: 0;
overflow: hidden;
}
canvas {
display: block;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const circles = [];
const numCircles = 6; // 떨어질 오브젝트 갯수
const gravity = 0.1; // 적용될 중력
const friction = 0.99; // 낙하 가속도
const minRadius = 10; // 오브젝트 최소 크기
const maxRadius = 100; // 오브젝트 최대 크기
const canvasWidth = 500; // 캔바스 너비
const canvasHeight = 500; // 캔바스 높이
const boxHeight = 100; // border
const Circlestexts = ['하나', '둘', '셋', '넷', '다섯', '여섯']; // 오브젝트 갯수만큼 텍스트 배열
const Circlesbg = ['#fff100', '#cc0000', '#111111', '#444444', '#888888', '#000000']; // 오브젝트 갯수만큼 배경컬러 배열
canvas.width = canvasWidth;
canvas.height = canvasHeight;
class Circle {
constructor(x, y, radius, vx = 0, vy = 0, text = '', bgColor = '#fff') {
this.x = x;
this.y = y;
this.radius = radius;
this.vx = vx;
this.vy = vy;
this.text = text;
this.bgColor = bgColor;
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.bgColor;
ctx.fill();
ctx.strokeStyle = 'rgba(0, 100, 200, 0.9)';
ctx.stroke();
// Draw text
ctx.font = 'bold 20px Arial';
ctx.fillStyle = '#000';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(this.text, this.x, this.y);
}
update() {
this.vy += gravity;
this.vx *= friction;
this.vy *= friction;
this.x += this.vx;
this.y += this.vy;
if (this.x + this.radius > canvasWidth) {
this.x = canvasWidth - this.radius;
this.vx *= -0.8;
}
if (this.x - this.radius < 0) {
this.x = this.radius;
this.vx *= -0.8;
}
if (this.y + this.radius > canvasHeight - boxHeight) {
this.y = canvasHeight - boxHeight - this.radius;
this.vy *= -0.8;
}
for (const other of circles) {
if (other !== this) {
const dx = this.x - other.x;
const dy = this.y - other.y;
const distance = Math.sqrt(dx * dx + dy * dy);
const minDistance = this.radius + other.radius;
if (distance < minDistance) {
const angle = Math.atan2(dy, dx);
const overlap = minDistance - distance;
// Separate the circles
this.x += Math.cos(angle) * (overlap / 2);
this.y += Math.sin(angle) * (overlap / 2);
other.x -= Math.cos(angle) * (overlap / 2);
other.y -= Math.sin(angle) * (overlap / 2);
// Simple collision response
const normalX = dx / distance;
const normalY = dy / distance;
const relativeVelocityX = this.vx - other.vx;
const relativeVelocityY = this.vy - other.vy;
const dotProduct = (relativeVelocityX * normalX) + (relativeVelocityY * normalY);
if (dotProduct > 0) {
const coefficientOfRestitution = 0.8; // Bounciness factor
const massSum = this.radius + other.radius;
const impulse = (2 * dotProduct) / massSum;
this.vx -= impulse * other.radius * normalX;
this.vy -= impulse * other.radius * normalY;
other.vx += impulse * this.radius * normalX;
other.vy += impulse * this.radius * normalY;
}
}
}
}
}
}
function generateRandomCircle(index) {
const radius = Math.random() * (maxRadius - minRadius) + minRadius;
const x = Math.random() * (canvasWidth - radius * 2) + radius;
const y = Math.random() * -500 - radius;
const vx = (Math.random() - 0.5) * 2;
const vy = (Math.random() - 0.5) * 2;
const text = Circlestexts[index];
const bgColor = Circlesbg[index];
return new Circle(x, y, radius, vx, vy, text, bgColor);
}
function createCircles() {
for (let i = 0; i < numCircles; i++) {
circles.push(generateRandomCircle(i));
}
}
function drawBox() {
ctx.fillStyle = 'rgba(100, 100, 100, 0.5)';
ctx.fillRect(0, canvasHeight - boxHeight, canvasWidth, boxHeight);
}
function animate() {
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
drawBox();
for (const circle of circles) {
circle.update();
circle.draw();
}
requestAnimationFrame(animate);
}
createCircles();
animate();
</script>
</body>
</html>
이후엔 직접 한번 코드를 파보세요..
!-->