별을 보는 어린 왕자[Javascript]
html5의 canvas로 애니메이션을 만드는 과정이 꽤 재밌게 느껴져서 이것저것 만져보던 차에, 간단하게 별을 보는 어린 왕자의 모습을 구현해봤다.
화면 중앙 하단에 행성 위에 올라가 있는 어린 왕자가 있고 그 위로 별들이 회전하고 있는 형태로 구상했다. 그리고 인터랙티브한 요소를 넣어봤는데, 유저가 화면을 클릭하고 있으면 별들의 속도가 점점 증가하게 만들었다.
⭐️ 별 만들기
class Particle {
constructor(moveRadius, step, position, size) {
this.moveRadius = moveRadius;
this.step = step;
this.position = position;
this.size = size;
this.acc = 0.0001;
this.cnt = 100;
}
...
}
기본적으로 별의 속성값을 갖는 Particle 클래스를 정의했다. moveRadius는 회전반경, step은 프레임 별로 이동할 거리, position은 현재 회전 각도, size는 별의 크기이다. 지금생각해보니 position은 변수명을 angle로 하는게 나을 것 같다.
class Particle {
...
draw() {
let x = Math.cos(this.position) * this.moveRadius + canvas.width / 2;
let y = Math.sin(this.position) * this.moveRadius + canvas.height;
ctx.beginPath();
drawStar(x, y, 5, this.size, this.size / 2);
ctx.closePath();
ctx.strokeStyle = "white";
ctx.stroke();
}
update() {
if (!isAccelerated) {
if (this.cnt >= 101) {
this.cnt -= 1;
}
this.position += this.step * (this.acc * this.cnt * this.cnt);
this.draw();
} else {
if (this.cnt <= 300) {
this.cnt += 1;
}
this.position += this.step * (this.acc * this.cnt * this.cnt);
this.draw();
}
}
}
Particle 클래스의 함수들이다. draw 함수를 통해 별을 그리고, update 함수로 별들의 속도를 조절한다. 속이 빈 별을 만들기 위해 stroke를 사용했다.
function drawStar(positionX, positionY, spikes, outerRadius, innerRadius) {
let rotation = (Math.PI / 2) * 3;
let x = positionX;
let y = positionY;
let step = Math.PI / spikes;
ctx.beginPath();
ctx.moveTo(positionX, positionY - outerRadius);
for (let i = 0; i < spikes; i++) {
x = positionX + Math.cos(rotation) * outerRadius;
y = positionY + Math.sin(rotation) * outerRadius;
ctx.lineTo(x, y);
rotation += step;
x = positionX + Math.cos(rotation) * innerRadius;
y = positionY + Math.sin(rotation) * innerRadius;
ctx.lineTo(x, y);
rotation += step;
}
ctx.lineTo(positionX, positionY - outerRadius);
ctx.closePath();
}
Particle 클래스의 draw 함수 내부에서 별을 그리는데 이용되는 drawStar 함수이다. 설정된 각도로 점을 찍어가며 별을 그린다. spikes 인자로 별을 꼭지점 개수를 조절할 수 있는데 아래 그림을 보자.
spike = 3
꼭지점이 3개라 그냥 삼각형처럼 그려진다.
spike = 5
이게 제일 별모양 같다.
spike = 7
이건 별이라기보단 타격이펙트(?) 처럼 생겼다.
어쨌든 꼭지점은 5로 두는게 제일 맘에들었다.
✏️ 초기화 및 애니메이션 구현
function init() {
particleArray = [];
for (let i = 0; i < 600; i++) {
let moveRadius = Math.random() * canvas.width + 250;
let step = Math.random() * 0.0002 + 0.002;
let position = Math.random() * Math.PI * 2;
let size = Math.random() * 8 + 0.5;
particleArray.push(new Particle(moveRadius, step, position, size));
}
}
init 함수를 한 번 실행시켜서 별들을 만들고 particleArray에 넣어준다. 별들의 속성은 랜덤함수를 이용하여 다양하게 만들어 준다.
function animate() {
requestAnimationFrame(animate);
if (!isAccelerated) {
ctx.fillStyle = `rgba(0,10,32,0.1)`;
} else {
ctx.fillStyle = `rgba(0,10,32,0.05)`;
}
ctx.fillRect(0, 0, innerWidth, innerHeight);
for (let i = 0; i < particleArray.length; i++) {
particleArray[i].update();
}
drawPrince();
}
requestAnimationFrame 함수로 animate를 계속 불러준다. 그리고 별들이 움직일때, 이전 위치에 잔상 효과를 주기 위해 ctx.fillStyle에 알파값을 주었다. 이후 모든 별을 계속 업데이트 해준다.
🤴 어린 왕자 그리기
무료 이미지 하나를 다운받아서 넣어주었다.
function drawPrince() {
var img = new Image();
img.src = "prince.png";
img.onload = function () {
ctx.drawImage(img, canvas.width / 2 - 150, canvas.height / 1.4, 300, 300);
};
}
이까지 하면 아래와 같은 결과를 볼 수 있다.
👆 인터랙티브한 요소 넣기
var isAccelerated = false;
window.addEventListener("mousedown", handleIsAccelerated, false);
window.addEventListener("mouseup", handleIsAccelerated, false);
window.addEventListener("touchstart", handleIsAccelerated, false);
일단 화면을 누르고 있는지, 떼고있는지를 체크하기 위해 이벤트리스너와 변수 하나를 사용하였다. 모바일 환경에서도 돌려보려고 touchstart를 넣어봤는데, 내 아이폰에서는 작동을 안하더라. 뭘 잘못한 것 같긴한데 일단 패스.
화면을 클릭했을 때 별들의 속도를 증가시키고싶었다. 근데 선형으로 업데이트하니 급가속, 급정지하는 것처럼 보여 부자연스러웠다. 그래서 가속도 개념을 사용하였다. 다시 클래스 내부의 update 함수를 보자
class Particle {
...
update() {
if (!isAccelerated) {
if (this.cnt >= 101) {
this.cnt -= 1;
}
this.position += this.step * (this.acc * this.cnt * this.cnt);
this.draw();
} else {
if (this.cnt <= 300) {
this.cnt += 1;
}
this.position += this.step * (this.acc * this.cnt * this.cnt);
this.draw();
}
}
}
this.position이 현재 별의 회전반경인데, 이 값을 계속 업데이트하고 있는데, 매 가속도 this.acc에 this.cnt의 제곱을 곱해주고있다. 이렇게 하면, 매 반복마다 화면을 누르고 있던 시간의 제곱에 비례하여 별의 위치가 바뀌므로 상당히 자연스럽게 속도가 바뀐다.
이제 다 구현했으니 결과를 보자.
별의 속도가 빨라지며 꼬리가 길어지는 모션이 제대로 보인다.
😃 후기
항상 canvas로 도형이나 그려보며 끄적대다가 뭔가 그럴듯한 작품(?)을 처음으로 만들어봤다. 구글링 열심히 해가며 후딱후딱 만들어 봤는데, 생각보다 결과물이 괜찮은 것 같아서 만족스럽다.
근데 자바스크립트를 자주 사용하진 않다보니, 코드 구조가 누더기처럼 이리저리 갖다 붙인 느낌이라 좀 불만족스럽다. 다음 번 프로젝트에서는 클래스를 좀 이쁘게 사용해보자.
그리고 깃헙의 페이지 기능이 꽤 괜찮은 것 같다. 이런 가벼운 프로젝트들의 데모를 무료로 편하게 호스팅할 수 있음에 감사한다.
Author And Source
이 문제에 관하여(별을 보는 어린 왕자[Javascript]), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@harveydev24/별을-보는-어린-왕자저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)