[JS Canvas] 폭발 이펙트
어제 밤에 나는 이 웹사이트에 들어가봤다.
뭔가 다 예뻐 보이는 것들 중에 뭔가 내가 할 수 있을거 같은게 눈에 들어왔다. 그래서 어려울거 같지만 시도해봤다.
오늘은 코드가 좀 길어서 설명하기 힘드니 주석을 열심히 썼습니다. 양해 부탁드려요 ㅠㅠ
//랜더링
function render() {
//화면 지우기
clear()
//그리기
RenderList.forEach(i => i.draw())
}
//이펙트 색깔을 담을 리스트
const Palette = [
new RGB(32, 118, 187),
new RGB(183, 111, 176),
new RGB(244, 122, 158),
new RGB(255, 152, 128),
new RGB(255, 97, 55),
new RGB(255, 198, 104),
new RGB(249, 248, 113),
]
function clickCanvas(event) {
//이펙트 시작 위치
const start = new Vector(event.offsetX, event.offsetY)
//Index는 Palette의 Index
CurrentIndex += 1
if (CurrentIndex >= Palette.length) {
CurrentIndex = 0
}
//원소 추가
RenderList.push(new Explode(start.x, start.y, CurrentIndex, LastIndex))
//RenderList의 원소가 10개가 넘을시 예전 이펙트부터 삭제
if (RenderList.length > 10) {
RenderList.shift()
}
LastIndex = CurrentIndex
}
//Add Listener
canvas.addEventListener("click", clickCanvas)
오늘도 마찬가지로 이벤트 함수부터 추가 해준다. 이번 프로젝트에는 클릭 이벤트만 있으니 "click"만 추가해 준다. 그리고 클릭했을때는 RenderList에 추가하여 render함수에서 처리할수 있도록 해준다. 그리고 이펙트가 많으면 렉이 걸릴수 있으니까 RenderList의 원소가 10개가 넘으면 shift를 하여 예전 이펙트부터 없에준다.
class RGB {
constructor(r, g, b, a = 1) {
this.R = r
this.G = g
this.B = b
this.A = a
}
toString() {
//fillStyle, strokeStyle에서 사용할수 있게
return `rgb(${this.R}, ${this.G}, ${this.B}, ${this.A})`
}
//불투명도
alpha(value) {
return new RGB(this.R, this.G, this.B, value)
}
}
RGB 클래스를 만들어 색깔을 관리하기 쉽게 만든다.
class Explode {
constructor(x, y, CurrentIndex, LastIndex) {
//진행할 색깔의 인덱스
this.CurrentIndex = CurrentIndex
//이전 이펙트의 인덱스
this.LastIndex = LastIndex
//이펙트의 크기, 불투명도 관련 변수
this.life_current = 0
this.life_last = 0
//this.life_last 감소량
this.decrease = 0
//시작되는 위치(클릭한 위치)
this.start = new Vector(x, y)
//파티클
this.particle = new Particle(x, y, LastIndex)
}
draw() {
//Current
selectColor(this.CurrentIndex)
ctx.arc(this.start.x, this.start.y, this.life_current, 0, HALF, false)
ctx.fill()
this.life_current += 15
//Last
ctx.beginPath()
let alpha_color = Palette[this.LastIndex]
//불투명도 조절
alpha_color = alpha_color.alpha(0.3 - this.life_last * 0.0012)
ctx.fillStyle = alpha_color.toString()
let r = this.life_last * 2
if (this.decrease > 0 && this.this.decrease < 2) {
this.decrease += 0.5
}
ctx.arc(this.start.x, this.start.y, r, 0, HALF, false)
ctx.fill()
this.life_last += 2 - this.decrease
//Particle
this.particle.draw()
}
}
먼저 Explode라는 클래스를 만들어서 누르는 곳에 터지는 원이 커지는 걸 구현했다. 그리고 색이 바뀌면서 이전 색깔이 알파(불투명도)만 낮춰서 작은 폭발로 나오길래 Last_...로 만들어줬다.(자세한건 코드 확인!)
//각각의 입자
class Atom {
constructor(x, y, vel_x, vel_y, r) {
//현재 위치
this.pos = new Vector(x, y)
this.velocity = new Vector(vel_x, vel_y)
this.r = r
}
draw() {
ctx.beginPath()
ctx.arc(this.pos.x, this.pos.y, this.r, 0, HALF, false)
ctx.fill()
}
move() {
this.pos.add(this.velocity)
//감속
//getSym을 줘서 음수면 +0.01을, 양수면 -0.01을 더하게하여 감속
this.velocity.x -= getSym(this.velocity.x) * 0.01
this.velocity.y -= getSym(this.velocity.y) * 0.01
//크기 감소
this.r -= 0.1
//반지름이 0보다 작아지면 0으로 고정
if (this.r < 0) {
this.r = 0
}
}
}
class Particle {
constructor(x, y, index) {
//시작점(마우스 클릭 지점)
this.start = new Vector(x, y)
//파티클의 색깔 인덱스
this.index = index
//입자들을 담은 리스트
this.atoms = []
this.init()
}
init() {
//PARTICLE_COUNT라는 상수의 크기 만큼 입자 생성
for (var i = 0; i < PARTICLE_COUNT; i++) {
//시작 위치에서 ±(0~50)만큼 위치 조절
const pos = new Vector(this.start.x + rand(50) * randSym(),
this.start.y + rand(50) * randSym())
//속도 = 입자의 위치 - 시작 위치
const vel = new Vector(pos.x - this.start.x, pos.y - this.start.y)
//설정한 입자 추가
//new Atom(위치x,위치 y, 속도x, 속도y, 반지름)
this.atoms.push(new Atom(pos.x, pos.y,
vel.x / 12, vel.y / 12, rand(20, 70)))//크기 랜덤
}
}
draw() {
selectColor(this.index)
this.atoms.forEach(i => {
i.move()
i.draw()
})
}
}
그리고 누를 때 이전 배경 색상이 파티클로 나오길래 Particle이라는 클래스를 구현해 주었다. 입자를 50개 정도 만들어주고 랜덤하게 배치, 랜덤한 크기를 주고 흩어지게 한다. (자세한건 코드를 확인해주세요)
그러면
짜잔! 내 영혼을 갈아만든 작품이 완성되었다!
오늘은 처음으로 웹 클론 코딩을 해봤는데 결과가 잘나와서 기분이 좋다. 파티클 부분에서 좀 힘들었지만 만들어보니 별거 아니었던거 같다. 226줄로 프론트엔드 프로젝트 중에서는 가장 긴 코드가 되겠다!
소스코드 : https://github.com/Function1790/ExplosionEffect
GitHub - Function1790/ExplosionEffect: with JS
with JS. Contribute to Function1790/ExplosionEffect development by creating an account on GitHub.
github.com