항해 플러스에서 연말기간 (12월 22일 - 24년 1월 1일) 동안 코육대를 진행한다.
제2회인걸 보면 1회도 했었던데.. 그동안 전혀 몰랐다. 😅 IT단톡방에서 공유받아 알게되었다.
코육대란 특정 기간동안 특정 기능을 주제로 프로젝트를 만드는 건데, 연말기간동안 심심하기도 했고 github 잔디좀 심어볼겸 하게되었다.
주제는 총 4가지로, 개발자의 고백, 크리스마스 선물 월드컵, 눈 닦기, 신년카드 이다.
처음엔 개발자의 고백이란 타이틀이 가장 맘에 들었었는데, 상세 내용을 살펴보고 눈 닦기로 맘을 굳혔다.
나름대로 주제를 고른 나만의 기준이 있었는데, 그 기준에 눈 닦기 주제가 가장 알맞았다.
1. api 서버를 구현할 필요가 없을 것.
2. 기능이 복잡하지 않을 것.
3. 평소에 생각해보지 못한 주제였으면!
4. 시간을 많이 잡아먹는 주제가 아닐 것.
❄️ 눈 닦기
요약하자면 아래와 같다.
1. 하늘에 object가 계속 내릴 것.
2. 내린 object는 화면에 쌓인 것 처럼 표현할 것.
3. 특정한 event로 object를 치울 수 있을 것.
🚀 기능구현 일지
0단계: 컨셉잡기
`react` 로 구현하기로 했다.
왜 next.js 로 하지 않았냐면, 굳이..? 싶었다. 눈닦기 프로젝트가 SSG 환경에서 구현이 되면 성능이 더 좋다고는 생각이 들지 않았다.
게다가 내가 구현할 눈닦기는 모든 기능이 클라에서 이루어질텐데, 서버에서 generate되는 next.js 의 이점을 제대로 활용하지 못할 것이라 판단했다. 그리고 하도 next.js를 하다보니 react csr환경 개발 방법을 잊어가는 것 같아 next.js가 아닌 react csr환경을 선택했다.
이왕 이렇게 된거 평소에 해보고 싶었던 것들을 모두 넣어보기로 했다. 예를들어, 번들러는 vite, 상태관리도구는 zustand를 선택했다.
다음으론, 눈을 어떻게 표현하는게 좋을까를 고민을 많이 했다.
웹으로 눈을 내리게 하고 쌓게 하려다 보니.. 어떻게든 어색해보일 수 밖에 없을 것 같았다. 그래서 아싸리 이상한 느낌이 극대화해서 오히려 이상해보이지 않도록(!) 컨셉을 잡았는데.. 그건 바로 8bit 컨셉이다.
눈이 네모로 내려도 이상해보이지 않을 것 같았다.
1단계: 화면에 눈이 내리게 하기
dom element로 눈을 구현할 수 있을까?
내가 선택한 라이브러리는 react였기 때문에 dom으로 화면에 눈이 내리는 것과 눈이 쌓이는 것을 구현해야만 했다.
물론 three js로 3d로 구현해낼 수야 있겠지만, 능숙하지 않았고, 개인적으로 하루에 2-3시간동안만 집중하기로 했기 때문에
오래걸릴 것 같았다.
그래서 생각해낸 것은 `canvas`! canvas로 눈을 그려낸다면 성능문제도 없고 가벼울 것이라 생각했다.
처음은 일단 canvas에 눈이 내리는 것처럼 구현해보기로 했다.
놀랍게도 자바스크립트로 canvas로 눈을 그려내는 건 정말정말 구글에 많았다. 관련된 아티클을 참고해가면서 canvas에 그려내는 로직을 만들어냈다.
참고했던 블로그는 아래와 같다.
사실 구글링하면 `canvas` 에 눈 내리는 건 정도는 누구나 할 수 있기 때문에 큰 어려움은 없었다.
난 더 나아가 명령형으로 되어있는 로직들을 선언적으로 component화를 하고싶어졌다.
<SnowCanvas width={screen.width} height={screen.height}>
<SnowCanvas.Flake />
</SnowCanvas>
그 결과, 요런 형태가 되었다.
`<SnowCanvas/>` 는 cavas element를 리턴하고, `<Flake/>`는 canvas내에 눈을 그려낸다.
2단계: 화면에 눈이 쌓이도록
생각보다 쉽게 구현했다. 아이디어는 아래와 같았다.
1. 화면을 NxM 2차원 배열로 나타낸다.
2. 시간이 지날 때 마다 랜덤으로 (n,m) 에 숫자를 카운트 한다.
숫자가 있는 부분에 white로 background를 주고 숫자가 커질 때 마다 투명도가 낮아지도록 했다.
3단계: 눈을 치울 수 있도록
사실 이 부분이 제일 관건이였고 가장 많은 시간을 할애했다. 어떻게 치우는 동작을 구현할까?
처음에는 화면에 쌓인 눈 부분에 마우스를 올리면 눈이 사라지도록 구현했다.
하지만, 해당 액션은 너무 어색했다.
그래서 선택한 방법은, 마우스가 움직일 때 마다 눈이 밀리도록 구현하는 것이였다.
결과영상부터 보면 이해하기 쉽다.
구현한 로직을 요약하자면 아래와 같다.
1. 화면에 마우스를 움직일 때 마다 마우스의 x,y 좌표를 가져온다.
2. 그 x,y 좌표에 근처에 위치해 있는 눈이 있으면 ,
const isCrush = (mouseX: number, mouseY: number, frostX: number, frostY: number) => {
const diffX = mouseX - frostX
const diffY = mouseY - frostY
const mousePointerRadius = Math.pow(diffX, 2) + Math.pow(diffY, 2)
return Math.sqrt(mousePointerRadius) <= 50
}
마우스가 움직인 방향으로 눈이 밀리도록 했다.
const move = (mouseX: number, mouseY: number, frostX: number, frostY: number) => {
const diffX = mouseX - frostX
const diffY = mouseY - frostY
const movePosition = toReverseMouseMove(frostX, frostY, diffX, diffY)
return {
x: movePosition.x,
y: movePosition.y,
}
}
이 기능을 위해 졸업이후로 손을 놓았던 수학개념을 다시 봤다. (원과 점사이의 거리, 원과 원이 내접하는 조건...ㄱ-)
여러가지 깨부하면서... 성공했다.
4단계: 이런저런 기능 추가
이 이후는 컨셉에 맞춰 로고 타이틀을 만들고, 필요한 이미지 에셋들을 준비해서 디자인했다.
그냥 눈닦는 기능만 있다보니 심심해보여서 나름대로 스토리를 추가했다.
이것 말고도 더 추가하고 싶은 기능이 많았는데, 여러 일을 동시에 진행하다보니 다 하지못해 아쉬웠다.
🥹 참여 후기
재미있었다. 하루에 2-3시간해서 한 4일....? 정도 걸렸다. 허허...
머릿속에 더 많은 기능들이 있었는데 다 넣지못해 아쉽다. 코드들도 더 최적화하고 싶었는데.. 여유롭지는 않아서 다 챙기지는 못했다.
위 사진은 프로젝트를 구현해내면서 진행한 issue들이다. 작업을 진행하면서 바로바로 떠오르는 구현사항들을 issue 발행해놓고 하나씩 처리해나갔다. 한번에 이렇게 보니 뿌듯하네욤.
뭔가 회고에서 이런저런 얘기를 많이 담아보고 싶었는데.. 평소에 글과 담을 쌓아서 인지.. 막상 쓰려고하니 잘 안써지네용.
사소하게나마 기능 하나정도는 만들어보고 올해를 보낼 수 있어서 뿌듯했다. 추후 3회가 열린다면 그때도 도전해보고 싶다. 🥹
'📦Others' 카테고리의 다른 글
좋은 개발자의 조건 <커뮤니케이션을 잘하는 개발자> (1) | 2023.11.04 |
---|---|
[careerly] 개발자로서 좋아할 12개의 사이트 (0) | 2023.10.29 |
백준에서 Javascript 자바스크립트 언어로 문제 풀기 (0) | 2023.10.03 |
CPU, GPU (0) | 2023.05.17 |
Batch2 (0) | 2021.01.08 |