2023. 2. 26. 22:48ㆍ개발 일지/패스트캠퍼스\챌린지
Part2. Canvas 챕터 02 - 3 파티클과 폭죽의 기본원리 강의 시작!
이번 시간에서는 particle을 반복사용하기 위해 particle을 클래스로 만들어 사용하고 폭죽의 기본 원리를 제작해보는 시간을 갖도록 한다.우선 js 폴더에 Particle.js 파일을 생성한 다음 그 안에 Particle class를 CanvasOption을 상속받도록 만든다. 그리고 기본적으로 사용할 함수들 constructor, update, draw를 정의하고 constructor가 x, y를 인자로 받도록 만들어준다.그리고 constructor에서 super를 호출하고 this.x, this.y로 x와 y를 초기화 해준다.draw 함수에는 ctx.beginPath와 closePath 사이에 원을 그려주는 로직을 추가해준다.아래는 Particle 클래스의 코드이다.
import CanvasOption from "./CanvasOption.js";
export default class Particle extends CanvasOption {
constructor(x, y) {
super();
this.x = x;
this.y = y;
}
update() {
}
draw() {
this.ctx.beginPath();
this.ctx.arc(this.x, this.y, 10, 0, Math.PI * 2);
this.ctx.fill();
this.ctx.closePath();
}
}
그 후 Canvas class의 생성자에서 this.particles를 빈배열로 초기화 해주고 createPartices 라는 함수를 정의하고 그 안에서 Particle들을 생성하도록 구현해준다.
import Particle from "./js/Particle.js";
...
class Canvas extends CanvasOption {
constructor() {
super();
this.particles = [];
}
init() {
...
this.createParticles();
}
createParticles() {
const PARTICLE_NUM = 1;
for (let i = 0; i < PARTICLE_NUM; i++){
const x = 300;
const y = 300;
this.particles.push(new Particle(x,y));
}
}
...
render() {
...
this.particles.forEach(particle => {
particle.update();
particle.draw();
});
...
}
}
이러면 canvas 안에 검은 원이 생긴다. 그 후 Particle의 update에 this.y += 1을 넣어주면 원이 내려가지만 화면이 갱신되면서 내려가는 것이 아니라 한붓그리기 처럼 선을 그리며 내려간다.
이를 이전에 화면 클리어 해주던 방식이 아닌 fillRect를 사용해서 배경색을 사용함과 동시에 화면을 클리어하는 방식으로 구현해본다.
우선 CanvasOption에 this.bgColor로 '#000000'을 선언해주 Canvas class의 render 안에 있는 frame 함수 안에 this.ctx.fillStyle을 bgColor로 설정해주고 this.ctx.fillRect에 인자로 (0, 0, this.canvasWidth, this.canvasHeight) 를 넣어줘 0, 0, 0의 위치에 화면 전체를 bgColor로 칠하도록 구현한다.
그리고 Particle class에서 draw 함수에서 ctx의 fillStyle을 '#fff'로 설정해주고 확인을 하면 검은 화면에 하얀 원이 점점 아래로 내려가는 모습을 확인할 수 있다.
하지만 이대로는 원이 한 곳에서만 생성이 되므로 random값으로 생성되는 위치를 정할 수 있도록 js 폴더에 utils.js 파일을 만들고 randomNumBetween 함수를 구현해준다.
그리고 반복문 안에서 x와 y를 할당해주던 것을 반복문 바깥에서 할당해주고 x 이동 속도와 y 이동 속도를 -5에서 5사이의 랜덤한 값을 받아서 파티클을 생성하도록 구현해준다.
그리고 파티클 생성 갯수를 2000으로 설정해주고 확인을 하면 많은 수의 파티클이 여러 방향으로 퍼지는 것을 확인할 수 있다. 다만 네모난 모양으로 퍼지고 있지만 우선적으로 파티클이 화면 밖으로 나가더라도 계속해서 2000개의 파티클 연산이 지속되고 있어 하드웨어에 많은 부담이 가서 이를 해결을 해야한다.
이를 해결하기 위해서 particle에 opacity 변수를 선언해주고 draw함수에서 '#fff' 로 설정해주던 fillStyle을 `rgba(255, 255, 25, ${this.opacity})`로 설정을 변경한다.
그리고 update 함수에서 opacity의 값을 0.01씩 빼주도록 구현하고 Canvas class의 render함수 안의 frame 함수 안에서 particle의 opactity 값을 관찰하여 0보다 작으면 particles 배열에서 제거하도록 구현하게 되면 파티클이 점점 투명해지면서 사라지게 되고 연산도 멈추게 된다.
아래는 Particle.js와 utils.js, index.js의 전체 코드들이다.
import CanvasOption from "./CanvasOption.js";
export default class Particle extends CanvasOption{
constructor(x, y, vx, vy){
super();
this.x = x;
this.y = y;
this.vx = vx;
this.vy = vy;
this.opacity = 1;
}
update() {
this.x += this.vx;
this.y += this.vy;
this.opacity -= 0.01;
}
draw() {
this.ctx.fillStyle = `rgba(255, 255, 255, ${this.opacity}`;
this.ctx.beginPath();
this.ctx.arc(this.x, this.y, 10, 0, Math.PI * 2);
this.ctx.fill();
this.ctx.closePath();
}
}
export const randomNumBetween = (min, max) => {
return Math.random() * (max - min) + min;
}
import CanvasOption from "./js/CanvasOption.js";
import Particle from "./js/Particle.js";
import { randomNumBetween } from "./js/utils.js";
class Canvas extends CanvasOption {
constructor() {
super();
this.particles = []
}
init() {
this.canvasWidth = innerWidth;
this.canvasHeight = innerHeight;
this.canvas.width = this.canvasWidth * this.dpr;
this.canvas.height = this.canvasHeight * this.dpr;
this.ctx.scale(this.dpr, this.dpr);
this.canvas.style.width = this.canvasWidth + 'px';
this.canvas.style.height = this.canvasHeight + 'px';
this.createParticles();
}
createParticles() {
const PARTICLE_NUM = 2000;
const x = randomNumBetween(0, this.canvasWidth);
const y = randomNumBetween(0, this.canvasHeight);
for (let i = 0; i < PARTICLE_NUM; i++){
const vx = randomNumBetween(-5, 5);
const vy = randomNumBetween(-5, 5);
this.particles.push(new Particle(x, y, vx, vy));
}
}
render() {
let now, delta;
let then = Date.now();
const frame = () => {
requestAnimationFrame(frame);
now = Date.now();
delta = now - then;
if (delta < this.interval) return;
this.ctx.fillStyle = this.bgColor;
this.ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
this.particles.forEach((particle, index) => {
particle.update();
particle.draw();
if(particle.opacity < 0) this.particles.splice(index, 1);
})
then = now - (delta % this.interval);
}
requestAnimationFrame(frame);
}
}
const canvas = new Canvas();
window.addEventListener('load', () => {
canvas.init();
canvas.render();
});
window.addEventListener('resize', () => {
canvas.init();
});
파티클이 실제로 지워졌는지 확인하려면 f12를 눌러 개발자 도구를 키고 ... 버튼을 누르고 more tools > performance monitor를 클릭하면 CPU사용량이 나오는데 이를 통해 연산이 계속 진행되고 있는지 확인할 수 있다.
패스트캠퍼스 [직장인 실무교육]
프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.
fastcampus.co.kr
본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.
'개발 일지 > 패스트캠퍼스\챌린지' 카테고리의 다른 글
[패스트캠퍼스] 챌린지 9일차 2.28 (0) | 2023.02.28 |
---|---|
[패스트캠퍼스] 8일차 2. 27 (0) | 2023.02.27 |
[패스트캠퍼스] 챌린지 6일차 2.25 (0) | 2023.02.25 |
[패스트캠퍼스] 챌린지 5일차 2.24 (0) | 2023.02.24 |
[패스트캠퍼스] 챌린지 4일차 2.23 (0) | 2023.02.23 |