๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Project/Toy Project

ํฌ์ผ“๋ชฌ ๊ฒŒ์ž„ ๋งŒ๋“ค๊ธฐ (Javascript, HTML, CSS)

by joooing 2021. 1. 23.
๋ฐ˜์‘ํ˜•

ํ•œ ์ค„ ์†Œ๊ฐœ ๐Ÿ•น


ํฌ์ผ“๋ณผ์„ ์ฃผ์›Œ ํฌ์ผ“๋ชฌ์„ ์žก์•„ ๊ฒฝํ—˜์น˜๋ฅผ ์Œ“๊ณ , ๋ ˆ๋ฒจ์„ ์˜ฌ๋ฆฌ๋Š” ๊ฒŒ์ž„์ด๋‹ค. 

๋กœ๊ทธ์ธ ํ™”๋ฉด

์ฃผ์š” ๊ธฐ๋Šฅ


1. ๋กœ๊ทธ์ธ ํ™”๋ฉด

์ž…๋ ฅํ•œ ์•„์ด๋””๋กœ ๊ฒŒ์ž„์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค. ์•„์ด๋””๋Š” ์„ธ ๊ธ€์ž ์ด์ƒ์œผ๋กœ ์ง€์ •ํ•ด์•ผํ•œ๋‹ค. ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ†ตํ•ด ๊ธ€์ž์ˆ˜๋ฅผ ํ™•์ธํ•ด ์„ธ๊ธ€์ž ๋ฏธ๋งŒ์ผ ๊ฒฝ์šฐ ์ž…๋ ฅ์ฐฝ์ด ๋นจ๊ฐ„์ƒ‰์œผ๋กœ ๋ฐ”๋€Œ๋ฉฐ ๋‹ค์‹œ ์ž…๋ ฅํ•˜๋ผ๋Š” ํ”ผ๋“œ๋ฐฑ์„ ๋ณด๋‚ธ๋‹ค.

 

 

2. ๋ ˆ๋ฒจ์— ๋”ฐ๋ฅธ ํ…Œ๋งˆ ๋ณ€๊ฒฝ & ๊ฒฝํ—˜์น˜ ์–ป๋Š” TIP

์ผ์ •ํ•œ ๊ฒฝํ—˜์น˜๊ฐ€ ์Œ“์ด๋ฉด ๋ ˆ๋ฒจ์ด ์˜ฌ๋ผ๊ฐ€๊ณ , ๋ ˆ๋ฒจ์— ๋”ฐ๋ผ ํ…Œ๋งˆ๊ฐ€ ํ’€ → ๋ฐ”๋‹ค → ์ˆฒ์œผ๋กœ ๋ฐฐ๊ฒฝ๊ณผ ํฌ์ผ“๋ชฌ ํƒ€์ž…์ด ๋ฐ”๋€Œ๊ฒŒ ๋œ๋‹ค. ๊ฒฝํ—˜์น˜๋Š” ํฌ์ผ“๋ชฌ์„ ์žก์•„์•ผ ์˜ฌ๋ผ๊ฐ„๋‹ค.

 

TIP 1. ํฌ์ผ“๋ชฌ

ํฌ์ผ“๋ชฌ์ด ์›€์ง์ด๋Š” ์†๋„๋Š” ๋žœ๋คํ•˜๊ฒŒ ์ง€์ •๋˜๋Š”๋ฐ, ๊ฒฝํ—˜์น˜๋ฅผ ์†๋„์— ๋น„๋ก€ํ•˜๊ฒŒ ์ฆ๊ฐ€ํ•˜๋„๋ก ์„ค์ •ํ•ด๋‘ฌ์„œ ๋น ๋ฅธ ํฌ์ผ“๋ชฌ์„ ์žก์„์ˆ˜๋ก ๋” ๋งŽ์€ ๊ฒฝํ—˜์น˜๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

 

TIP 2. ํฌ์ผ“๋ณผ

ํฌ์ผ“๋ชฌ์„ ์žก์„ ๋•Œ๋งˆ๋‹ค ํฌ์ผ“๋ณผ์˜ ๊ฐœ์ˆ˜๋Š” ํ•˜๋‚˜์”ฉ ๊ฐ์†Œํ•œ๋‹ค. ํฌ์ผ“๋ณผ์ด 0๊ฐœ๊ฐ€ ๋˜๋ฉด ๋” ์ด์ƒ ํฌ์ผ“๋ชฌ์ด ์žกํžˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ค‘๊ฐ„ ์ค‘๊ฐ„ ํฌ์ผ“๋ณผ๋„ ์ฃผ์›Œ์•ผ ๊ณ„์† ๊ฒŒ์ž„์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ํฌ์ผ“๋ณผ๋„ ์ข…๋ฅ˜์— ๋”ฐ๋ผ ์ฆ๊ฐ€ํ•˜๋Š” ๊ฐœ์ˆ˜๋ฅผ ๋‹ค๋ฅด๊ฒŒ ์„ค์ •ํ•ด ๋‘์—ˆ๋‹ค. (๋นจ๊ฐ„์ƒ‰+1, ํŒŒ๋ž€์ƒ‰+5, ๋…ธ๋ž€์ƒ‰+50)

 

 

3. ๋กœ๊ทธ์ธ ์ •๋ณด ์ €์žฅ

Local Storage์— ID, ๋ ˆ๋ฒจ, ๊ฒฝํ—˜์น˜, ์žก์€ ํฌ์ผ“๋ชฌ์ˆ˜, ํฌ์ผ“๋ณผ ์ˆ˜์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•ด๋‘์–ด ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์ข…๋ฃŒํ•˜๊ฑฐ๋‚˜ ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•œ ํ›„์—๋„ ๋™์ผํ•œ ์•„์ด๋””๋กœ ์ ‘์†์„ ํ•˜๋ฉด ๊ธฐ์กด์— ํ•˜๋˜ ๋ถ€๋ถ„๋ถ€ํ„ฐ ์ด์–ด์„œ ๊ฒŒ์ž„์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค.

 

 

 

๊ตฌํ˜„ ๊ณผ์ •


1. ๊ธฐํš

๋ธŒ๋ ˆ์ธ ์Šคํ† ๋ฐ

์ •๋ง ํ•˜๋‚˜์˜ ๊ฒŒ์ž„์„ ๋งŒ๋“ ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด์„œ ๋‚ด๊ฐ€ ๊ฒŒ์ž„ํ•  ๋•Œ ๋ฌด์Šจ ๊ธฐ๋Šฅ์„ ์ผ๊ณ  ์–ด๋–ค๊ฒŒ ํ•„์š”ํ–ˆ์ง€? ํ•˜๊ณ  ํ•œ๋ช…์˜ ์‚ฌ์šฉ์ž ์ž…์žฅ์—์„œ ๋‚˜๋ฆ„ ์ง„์ง€ํ•˜๊ฒŒ ์ƒ๊ฐํ•ด๋ณธ ๊ฒƒ ๊ฐ™๋‹ค. ํŽ˜์–ด๋ถ„๊ณผ ์คŒ์„ ์ผœ๊ณ  ๋ธŒ๋ ˆ์ธ ์Šคํ† ๋ฐ๋ถ€ํ„ฐ ํ–ˆ๋Š”๋ฐ, ๋‘˜ ๋‹ค ๋ญ”๊ฐ€๊ฐ€ ์ƒ๊ฐ๋‚˜๋ฉด ํ•„ํ„ฐ๋ง์—†์ด(?) ๋ฐ”๋กœ๋ฐ”๋กœ ๋งํ•˜๊ณ ๋ณด๋Š” ์Šคํƒ€์ผ์ด๋ผ ์ƒ๊ฐ๋“ค์ด ๋น ๋ฅด๊ณ  ๋‹ค์–‘ํ•˜๊ฒŒ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

๋ฐ›์•„์“ฐ๊ธฐ

์•„์ง ๋ชจ๋ฅด๋Š” ๊ธฐ๋Šฅ๋“ค์ด ๋„ˆ๋ฌด ๋งŽ๊ธฐ๋„ ํ•˜๊ณ  ์‹ฌ์ง€์–ด ์šฐ๋ฆฌ๊ฐ€ ์–ด๋””๊นŒ์ง€ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์„ ์ง€์กฐ์ฐจ๋„ ๊ฐ€๋Š ๋„ ๋˜์ง€ ์•Š์•˜๋‹ค. ๊ทธ๋ž˜์„œ ์ผ๋‹จ ๊ฐ€๋Šฅํ•œ ์ง€๋Š” ํ•ด๋ณด๋ฉด์„œ ํŒ๋‹จํ•˜๊ธฐ๋กœ ํ•˜๊ณ  ๋ชจ๋“  ์ƒ๊ฐ์„ ๋…ธ์…˜์— ๋‹ค ์ ์–ด๋‘์—ˆ๋‹ค. ๋Œ€๋žต ์ด์•ผ๊ธฐ๋ฅผ ๋๋‚ด๊ณ  ์ ์–ด๋‘” ๋‚ด์šฉ๋“ค์„ ๋ณด๋ฉฐ ์ง€์šธ๊ฑด ์ง€์šฐ๊ณ  ๋น„์Šทํ•œ๊ฑด ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๋‚˜๋ˆ  ๋ฌถ์–ด๋ณด๋‹ˆ ์ „๋ฐ˜์ ์ธ ๊ทธ๋ฆผ์ด ์žกํ˜”๋‹ค.

 

์šฐ์„ ์ˆœ์œ„ ์ •ํ•˜๊ธฐ

์ดํ‹€ ์ •๋„๋ฐ–์— ์‹œ๊ฐ„์ด ๋‚จ์ง€ ์•Š์•„ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ •ํ•ด์„œ ๊ฐ€์žฅ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋ถ€ํ„ฐ ๊ตฌํ˜„ํ•ด์•ผ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๊ณ , ๋ฐ”๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์€ ๊ธฐ๋Šฅ๋“ค๋ถ€ํ„ฐ ์ฐจ๋ก€๋กœ bare, advanced, nightmare ๋ผ๊ณ  ์ด๋ฆ„์„ ๋ถ™์—ฌ ๋‹จ๊ณ„๋ฅผ ์ •ํ•˜๊ณ  ํ•˜๋‚˜์”ฉ ์™„์„ฑํ•ด๋‚˜๊ฐ”๋‹ค.

 

 

 


2. ์™€์ด์–ด ํ”„๋ ˆ์ž„ ์„ค๊ณ„

์ „์ฒด์ ์ธ ํ‹€์€ ๋‹Œํ…๋„ ์Šค์œ„์น˜์™€ ๋น„์Šทํ•˜๊ฒŒ ๊ตฌ์„ฑํ•˜๊ณ , ๋‚ด๋ถ€ ํ™”๋ฉด(main-section)์—์„œ ๊ฒŒ์ž„์„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„ํ–ˆ๋‹ค. ์ผ๋Ÿฌ์ŠคํŠธ๋ฅผ ์ด์šฉํ•ด ์™€์ด์–ด ํ”„๋ ˆ์ž„์„ ์™„์„ฑํ–ˆ๋‹ค.

๋ฐฐ๊ฒฝ๊ณผ ์บ๋ฆญํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ด ์‹ค์ œ ํฌ๊ธฐ๋ฅผ ํ™•์ธํ•˜๊ณ , ์™„์„ฑ๋œ ๋ชจ์Šต์„ ๋Œ€๋žต์ ์œผ๋กœ ์‹œ๊ฐํ™”ํ•ด๋ณด์•˜๋‹ค.

 


3. HTML/CSS, Javascript

HTML - audio ํƒœ๊ทธ
CSS - transition
CSS, JS - cursor ์ด๋ฏธ์ง€๋กœ ๋ฐ”๊พธ๊ธฐ
CSS - margin, flex๋กœ ๋ฒ„ํŠผ ๋ฐฐ์น˜
CSS - ๊ฒŒ์ž„์˜์—ญ - ์ •๋ณดํ‘œ์‹œ์˜์—ญ ๋ถ„๋ฆฌ
HTML, JS - ๊ฒฝํ—˜์ง€ ๊ฒŒ์ด์ง€๋ฐ” (progress ํƒœ๊ทธ)
CSS - ํฌ์ผ“๋ชฌ animation ์ถ”๊ฐ€
JS - ์ถฉ๋Œ ์ธ์‹ (ํฌ์ผ“๋ณผ์ด ๋ฒฝ์—์„œ ํŠ•๊ฒจ๋‚˜๊ฐ€๋Š” ํšจ๊ณผ)
JS - ํฌ์ผ“๋ชฌ์˜ ์›€์ง์ž„ ๋‹ค์–‘ํ™” (class, ์ƒ์†๊ณผ ๋‹คํ˜•์„ฑ)
JS - ์œ ์ € ์ •๋ณด ์ €์žฅ (LocalStorage, data ๊ฐ์ฒด, JSON)

 

HTML - audio ํƒœ๊ทธ

๊ฒŒ์ž„์— ์ข€ ๋” ๋ชฐ์ž…ํ•  ์ˆ˜ ์žˆ๊ฒŒ ์‹คํ–‰์‹œ ํฌ์ผ“๋ชฌ bgm์ด ๋‚˜์˜ค๋„๋ก ํ–ˆ๋‹ค. audio๋ผ๋Š” ํƒœ๊ทธ์˜ src์†์„ฑ์—๋Š” ๊ฐ€์ง€๊ณ  ์žˆ๋˜ mp3ํŒŒ์ผ์˜ url์„ ์ž…๋ ฅํ–ˆ๊ณ ,  ์ž๋™ ์žฌ์ƒ๋˜๋„๋ก autoplay๋ผ๋Š” ์†์„ฑ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค. 

 

<audio src="bgms/guidepost.mp3" autoplay></audio>

 

CSS - transition

ํฌ์ผ“๋ชฌ๋“ค์ด ์žกํžˆ๋ฉด ํ™”๋ฉด์—์„œ ์‚ฌ๋ผ์ง€๋Š”๋ฐ, ์ด ๋•Œ ๊ฐ‘์ž๊ธฐ ์‚ฌ๋ผ์ง€๊ธฐ๋ณด๋‹ค๋Š” fadeout๋˜๋Š” ๋Š๋‚Œ์œผ๋กœ ์Šค๋ฅด๋ฅต..ํ•˜๊ณ  ์‚ฌ๋ผ์กŒ์œผ๋ฉด ์ข‹๊ฒ ๋‹ค๊ณ  ์ƒ๊ฐํ•ด์„œ CSS์—์„œ transition ์†์„ฑ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค. ํด๋ฆญ๋œ ํฌ์ผ“๋ชฌ ๊ฐ์ฒด์˜ classList์—๋งŒ hidden ํด๋ž˜์Šค๊ฐ€ ์ถ”๊ฐ€๋˜๋„๋ก ํ•ด ํด๋ฆญ ์‹œ transition์ด ๋™์ž‘๋˜๋„๋ก ํ–ˆ๋‹ค. transition์—๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜ ์†๋„์™€ ์‹คํ–‰์‹œ๊ฐ„์„ ์„ค์ •ํ•˜๋Š” ์†์„ฑ์ด ์žˆ์–ด์„œ, ํˆฌ๋ช…๋„์ธ opacity๋ฅผ ์ ์ ˆํžˆ ๋‚ฎ์ถ”๋Š” ์‹์œผ๋กœ ํŽ˜์ด๋“œ์•„์›ƒ ํšจ๊ณผ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

.hidden {
  visibility: hidden;
  opacity: 0;
  transition: visibility 0s 0.7s, opacity 0.7s linear;
}

 

CSS, JS - cursor ์ด๋ฏธ์ง€๋กœ ๋ฐ”๊พธ๊ธฐ

์‚ฌ์‹ค ์ปค์„œ๋ฅผ ์ด๋ฏธ์ง€๋กœ ๋ฐ”๊พผ๋‹ค๊ธฐ ๋ณด๋‹ค๋Š”, ์ด๋ฏธ์ง€๊ฐ€ ๋ฐฐ๊ฒฝ์œผ๋กœ ์„ค์ •๋œ <div> ์š”์†Œ ํ•˜๋‚˜๊ฐ€ ๋งˆ์šฐ์Šค์˜ ์ขŒํ‘œ๋ฅผ ์ซ’์•„๋‹ค๋‹ˆ๋„๋ก ํ–ˆ๋‹ค. ์šฐ์„  ์š”์†Œ์— ๋งˆ์šฐ์Šค ์ปค์„œ๊ฐ€ ์˜ฌ๋ผ๊ฐ”์„ ๋•Œ ๋ณด์—ฌ์ค„ ๋ชจ์–‘์„ ์ง€์ •ํ•˜๋Š” cursor ์†์„ฑ์˜ ๊ฐ’์„ cursor : none ์œผ๋กœ ํ•ด์„œ ์›๋ž˜ ์ปค์„œ๋Š” ๋ณด์ด์ง€ ์•Š๊ฒŒํ•ด์ฃผ์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  50*50ํฌ๊ธฐ์˜ <div>์— cursor๋ผ๋Š” ํด๋ž˜์Šค๋ช…์„ ๋ถ™์ด๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ์†์„ฑ์„ ์ง€์ •ํ•ด์ฃผ์—ˆ๋‹ค.

 

z-index๋Š” ์–ด๋Š ๊ฐ์ฒด๊ฐ€ ์•ž์œผ๋กœ ๋‚˜์˜ค๊ณ , ๋’ค์— ๋‚˜์˜ฌ์ง€ ๋ฐฐ์น˜ ์ˆœ์„œ๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ์†์„ฑ์ธ๋ฐ, z-index๊ฐ’์„ ํฌ๊ฒŒ ๊ฐ€์ง„ ์š”์†Œ์ผ์ˆ˜๋ก ์œ„์— ์œ„์น˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•ญ์ƒ ๋งจ ์œ„์— ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ๋„‰๋„‰ํžˆ 1000์œผ๋กœ ์„ค์ •ํ•ด์ฃผ์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ์†์„ฑ์€ position์— relative, absolute, fixed์ด ์ ์šฉ๋˜์–ด์•ผ๋งŒ ์ž‘๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ์— position์€ absolute๋กœ ์„ค์ •ํ–ˆ๋‹ค.

 

// CSS
* {
  cursor: none;
}

.cursor {
  width: 50px;
  height: 50px;
  background-image: url('images/cursor-img.png');
  position: absolute
  z-index: 1000;
}

 

๋งˆ์šฐ์Šค ์ขŒํ‘œ ๊ณ„์‚ฐ์—๋Š” pageX์™€ pageY๋ผ๋Š” event์†์„ฑ์„ ์‚ฌ์šฉํ–ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ € ์ƒ์—์„œ ํ˜„์žฌ ๋งˆ์šฐ์Šค ์ปค์„œ์˜ ์œ„์น˜๊ฐ’์„ ๊ตฌํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์ด๋ฒคํŠธ ์†์„ฑ์ธ๋ฐ, ๋งˆ์šฐ์Šค ์ปค์„œ์˜ ์œ„์น˜๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ณ„์‚ฐํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— mousemove๋ผ๋Š” ์ด๋ฒคํŠธ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ–ˆ๋‹ค.

//Javascript
let mouseCursor = document.querySelector(".cursor");
window.addEventListener("mousemove", cursor);

function cursor(e) {
  mouseCursor.style.left = e.pageX + "px";
  mouseCursor.style.top = e.pageY + "px";
}

 

 

CSS - margin, flex๋กœ ๋ฒ„ํŠผ ๋ฐฐ์น˜

๋ฒ„ํŠผ ๋„ค๊ฐœ๋ฅผ ์–ด๋–ป๊ฒŒ ๋งˆ๋ฆ„๋ชจ๊ผด๋กœ ๋ฐฐ์น˜ํ• ๊นŒ ๊ณ ๋ฏผํ•˜๋‹ค๊ฐ€ (๋” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์žˆ์„ ๊ฒƒ ๊ฐ™์ง€๋งŒ ์•„์ง ์“ธ์ค„ ์•„๋Š”๊ฒŒ flex๋ฟ์ด๋ผ,,) flex์™€ margin๊ฐ’์„ ์กฐ์ •ํ•˜๋ฉด ๊ฐ€๋Šฅํ•  ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. ์ผ๋‹จ ๋ฒ„ํŠผ์€ top / left&right / bottom ์ด๋ ‡๊ฒŒ ์„ธ๊ฐœ์˜ div๋กœ ๋จผ์ € ๊ตฌ๋ถ„ํ–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  left&right ์•ˆ์— ๋“ค์–ด์žˆ๋Š” left, right div ์š”์†Œ๋Š” justify-content ์†์„ฑ์„ space-between์œผ๋กœ ์ง€์ •ํ•ด ์ƒ์œ„div์˜ ์–‘ ์˜†์— ๋ถ™์„ ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  margin๊ฐ’์„ ์Œ์ˆ˜(-5px)๋กœ ์ง€์ •ํ•ด div๋ผ๋ฆฌ ๊ฒน์น˜๊ฒŒ ๋งŒ๋“ค์–ด ์คŒ์œผ๋กœ์จ ์ข€ ๋” ๋ฒ„ํŠผ๋ผ๋ฆฌ ๊ฐ€๊น๊ฒŒ ๋ถ™์–ด์žˆ๊ฒŒ ํ–ˆ๋‹ค.

 

 

// HTML
<div class="small-btns">
  <button class="small-btn top-btn">โ–ฒ</button>
  <div class="samll-btn left-right-btn">
    <button class="small-btn left-btn">โ—€</button>
    <button class="small-btn right-btn">โ–ถ</button>
  </div>
  <button class="small-btn bottom-btn">โ–ผ</button>
</div>

 

// CSS
.small-btns {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.left-right-btn {
  width: 130px;
  display: flex;
  justify-content: space-between;
  margin-top: -5px;
  margin-bottom: -5px;
}

 

 

CSS - ๊ฒŒ์ž„์˜์—ญ & ์ •๋ณดํ‘œ์‹œ์˜์—ญ ๋ถ„๋ฆฌ

ํฌ์ผ“๋ชฌ์„ ์žก์„ ๋•Œ ์ •๋ณดํ‘œ์‹œ๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ์š”์†Œ๋“ค ์—์„œ๋Š” ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ํ•˜๋ ค๊ณ  ๊ฒŒ์ž„ ์‹คํ–‰ ์˜์—ญ๊ณผ ์ •๋ณด ํ‘œ์‹œ ์˜์—ญ์„ ๋ถ„๋ฆฌํ–ˆ๋‹ค. (์•„๋ž˜ ์‚ฌ์ง„ ์ฐธ๊ณ ) ๋ถ€๋ชจ ์š”์†Œ์ธ main-section์„ ๊ธฐ์ค€์œผ๋กœ ํ•˜์œ„ ์š”์†Œ๋“ค์— position:relative๋ฅผ ์ ์šฉํ•˜๊ณ  top ๊ฐ’์„ ์กฐ์ •ํ•ด ๋‘ ํ•˜์œ„์š”์†Œ ์œ„์น˜๋ฅผ ๋™์ผํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ๊ฒน์ณ ๋ณด์ด๋„๋ก ํ–ˆ๋‹ค. 

 

1. main-section = ์ „์ฒด ๊ฒŒ์ž„ ์ฐฝ (์ƒ์œ„์š”์†Œ)

3. main-info = ํ”„๋กœํ•„, ๋ ˆ๋ฒจ, ๊ฒฝํ—˜์น˜, ํฌ์ผ“๋ชฌ/ํฌ์ผ“๋ณผ ์ •๋ณด๋งŒ ํ‘œ์‹œํ•  ๋ฟ ์–ด๋–ค ์ด๋ฒคํŠธ๋„ ์‹คํ–‰๋˜์ง€ ์•Š์Œ (ํ•˜์œ„์š”์†Œ1)

2. main-game = ์บ๋ฆญํ„ฐ๋“ค์ด ๋“ฑ์žฅํ•˜๊ณ  ํด๋ฆญ์ด๋ฒคํŠธ๋“ค์ด ์ ์šฉ๋˜๋Š” ๊ณณ (ํ•˜์œ„์š”์†Œ2)

 

ํŠนํžˆ ๊ฒŒ์ž„์˜์—ญ(main-game) ์œ„์— ์ •๋ณด์˜์—ญ(main-info)์ด ์žˆ์–ด์„œ, ์–ด๋”œ ํด๋ฆญํ•ด๋„ ์ •๋ณด์˜์—ญ๋งŒ click๋˜์–ด๋ฒ„๋ฆฌ๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํฌ์ผ“๋ชฌ์ด ๊ฒŒ์ž„์˜์—ญ์—์„œ ๋“ฑ์žฅํ•ด๋„ ํฌ์ผ“๋ชฌ์ด ์•„๋‹Œ ์ •๋ณด์˜์—ญ์—์„œ๋งŒ click event๊ฐ€ ๋ฐœ์ƒํ•ด๋ฒ„๋ ธ๋‹ค. ๋ฌธ์ œ ํ•ด๊ฒฐ์„ ์œ„ํ•ด ์ •๋ณด์˜์—ญ(main-info)์˜ CSS ์†์„ฑ์— pointer-events : none; ์„ ์ถ”๊ฐ€ํ•ด ๋ชจ๋“  ์ด๋ฒคํŠธ๋ฅผ ๋ฌดํšจํ™”ํ•˜๋„๋ก ํ–ˆ๋‹ค.

#main-info {
  pointer-events: none;
}

 

 

HTML, JS - ๊ฒฝํ—˜์ง€ ๊ฒŒ์ด์ง€๋ฐ”

๊ฒฝํ—˜์น˜์— ๋”ฐ๋ผ ๊ฒŒ์ด์ง€๋ฐ”๊ฐ€ ์ฐจ์˜ค๋ฅด๋„๋ก ํ•˜๊ณ  ์‹ถ์–ด์„œ ์ฐพ์•„๋ณด๋‹ˆ progress๋ผ๋Š” html ํƒœ๊ทธ๊ฐ€ ์žˆ์—ˆ๋‹ค. data-label๋กœ ๋‚ด๋ถ€์— ํ‘œ์‹œ๋  ํ…์ŠคํŠธ๋ฅผ, value๋กœ ํ˜„์žฌ๊ฐ’์„, max๋กœ ์ตœ๋Œ€๊ฐ’์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. Javascript์—์„œ data-label์— ์ƒˆ๋กœ์šด ํ…์ŠคํŠธ๋ฅผ ์‚ฝ์ž…ํ•˜๊ณ , value๊ฐ’์„ ์ฆ๊ฐ€์‹œ์ผœ์ฃผ๋Š” ์‹์œผ๋กœ ๊ฒฝํ—˜์น˜์— ๋”ฐ๋ผ ์ด ์š”์†Œ์˜ ์†์„ฑ๊ฐ’๋“ค์ด ๋ฐ”๋€Œ๊ฒŒ ํ–ˆ๋‹ค. 

 

<progress id="level-gauge" data-label="EXP 0/100" value="0" max="100"></progress>

 

๋‹ค๋ฅธ ํ•จ์ˆ˜์—์„œ this.timeBetweenSteps๋ผ๋Š” ์บ๋ฆญํ„ฐ๊ฐ€ ์›€์ง์ด๋Š” ์†๋„๊ฐ’์„ ๋žœ๋ค์œผ๋กœ ์ง€์ •ํ•ด๋‘” ๋ณ€์ˆ˜๊ฐ€ ์žˆ์—ˆ๋Š”๋ฐ, ์ด ๋žœ๋คํ•œ ์†๋„์— ๋น„๋ก€ํ•˜๊ฒŒ ๊ฒฝํ—˜์น˜(exp)๋ฅผ ์„ค์ •ํ•˜๊ณ  ์‹ถ์—ˆ๋‹ค. ์บ๋ฆญํ„ฐ๊ฐ€ ๋น ๋ฅด๊ฒŒ ์›€์ง์ผ ์ˆ˜๋ก ๋งŽ์€ ๊ฒฝํ—˜์น˜๋ฅผ ์–ป๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ์†๋„๊ฐ’์ด 100์ด ๋„˜์–ด๊ฐ€์„œ ๊ทธ๋ƒฅ ๋”ํ•ด์ฃผ๋ฉด ํ•œ๋ฒˆ์— ๊ฒฝํ—˜์น˜๊ฐ€ 100์ด์ƒ์”ฉ ์ถ”๊ฐ€๋˜์–ด๋ฒ„๋ฆฌ๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด์„œ ์ ์ ˆํ•˜๊ฒŒ ๊ฒฝํ—˜์น˜๋กœ ํ™˜์‚ฐํ•ด์ฃผ๋Š” ์‹์„ ๋งŒ๋“ค์—ˆ๋‹ค. 

 

function pocketInfoChange() {
  curObj.exp += (20 - Math.round(this.timeBetweenSteps / 100));  
  // (๋Œ€์ถฉ ๋žœ๋ค์ง€์ •๋˜๋Š” this.timeBetweenSteps๊ฐ’์— ๋น„๋ก€ํ•˜๊ฒŒ ๊ฒฝํ—˜์น˜(exp)๋ฅผ ์ค€๋‹ค๋Š” ์‹)
  progress.setAttribute('data-label', `EXP ${curObj.exp}/100`);
  progress.value = curObj.exp;
  if (curObj.exp >= 100) {    // ๊ฒฝํ—˜์น˜๊ฐ€ 100์ด๋˜๋ฉด ๋ ˆ๋ฒจ์—…, ๊ฒฝํ—˜์น˜ ์ดˆ๊ธฐํ™”
    curObj.level++;
    levelText.textContent = `Level ${curObj.level}`;
    curObj.exp -= 100;
    progress.setAttribute('data-label', `EXP ${curObj.exp}/100`);
    progress.value = curObj.exp;
  }
}

 

 

CSS - ํฌ์ผ“๋ชฌ animation ์ถ”๊ฐ€

animation๋„ ์š”์†Œ์— ์ ์šฉ๋˜๋Š” CSS ์Šคํƒ€์ผ์„ ๋‹ค๋ฅธ ์Šคํƒ€์ผ๋กœ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์ „ํ™˜์‹œ์ผœ ์ฃผ๋Š” ์†์„ฑ์ด๋‹ค. transition๋ณด๋‹ค ๋” ๋‹ค์–‘ํ•œ ํšจ๊ณผ๋ฅผ ์‰ฝ๊ฒŒ ๋‚ผ ์ˆ˜ ์žˆ์–ด์„œ ์บ๋ฆญํ„ฐ๋“ค์ด ์ด์ด ๋›ฐ์–ด๋‹ค๋‹ˆ๋„๋ก bounce ํšจ๊ณผ๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ–ˆ๋‹ค. ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ง€์†์‹œ๊ฐ„, ์†๋„ ๋“ฑ์„ ์กฐ์ •ํ•˜๋Š” animation, ๊ทธ๋ฆฌ๊ณ  ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ๊ฐ ๊ตฌ๊ฐ„๋ณ„๋กœ ์–ด๋–ค ์Šคํƒ€์ผ์„ ์ ์šฉ์‹œํ‚ฌ์ง€ ์ •ํ•˜๋Š” @keyframes ๋ฅผ ์ด์šฉํ–ˆ๋‹ค. ์š”์†Œ์˜ ์œ„์น˜, ๋ชจ์–‘ ๋“ฑ์˜ ๋ณ€ํ™”๋ฅผ ์•„๋ž˜์ฒ˜๋Ÿผ keyframes์— ์„ค์ •ํ•ด๋‘๊ณ , animation ์†์„ฑ์„ ํ†ตํ•ด ๋ณ€ํ™”๊ฐ€ ์ผ์–ด๋‚˜๋Š” ์‹œ๊ฐ„(1s), ํšŸ์ˆ˜(infinite) ๋“ฑ์„ ์ง€์ •ํ•ด์ฃผ์—ˆ๋‹ค.

 

 

.toy {
  animation: bounce 1s infinite alternate;
}

@keyframes bounce {
  100% {
    top: -10px;
  }
}

 

 

JS - ์ถฉ๋Œ ์ธ์‹ (ํฌ์ผ“๋ณผ์ด ๋ฒฝ์—์„œ ํŠ•๊ฒจ๋‚˜๊ฐ€๋Š” ํšจ๊ณผ)

๋žœ๋คํ•œ X, Y์ถ• ์œ„์น˜์—์„œ ๋ชฌ์Šคํ„ฐ๋ณผ๋“ค์ด ์ƒ์„ฑ๋˜๊ณ , ํ™”๋ฉด(maingame)์˜ ํฌ๊ธฐ๋ฅผ ๋ฒ—์–ด๋‚˜๋ฉด ์›€์ง์ด๋Š” ๋ฐฉํ–ฅ์„ ๋ฐ”๊พธ๋„๋ก ํ•ด์„œ ๊ณต์ด ๋ฒฝ์—์„œ ํŠ•๊ฒจ๋‚˜๊ฐ€๋Š” ๋“ฏํ•œ ํšจ๊ณผ๋ฅผ ์ฃผ์—ˆ๋‹ค.

 

๊ณ„์† ๋ณ€ํ•˜๋Š” ์ƒ๋Œ€์ ์ธ ์œ„์น˜๊ฐ’์„ ๋ฐ”ํƒ•์œผ๋กœ 0.02์ดˆ๋งˆ๋‹ค ๊ฐ’์„ ๊ฐฑ์‹ ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋„๋กํ•ด์„œ ์ž์—ฐ์Šค๋Ÿฌ์šด ๋™์ž‘์ฒ˜๋Ÿผ ๋ณด์ด๋„๋ก ํ–ˆ๋‹ค. ๊ตฌ๊ธ€๋ง์„ ํ†ตํ•ด ์ฐพ์•„๋‚ธ ์‹์ธ๋ฐ ๊ฒŒ์ž„์— ๋งž๋„๋ก ๊ฐ’๋“ค๊ณผ ๋ณ€์ˆ˜๋ฅผ ์กฐ๊ธˆ์”ฉ ์กฐ์ •ํ•ด์„œ ์ ์šฉํ•ด ๋ณด์•˜๋‹ค. (์‹์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์„ค๋ช…์€ ๋‹ค๋ฅธ ๊ธ€์—์„œ ๋‹ค๋ค„๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค,,)

 

function makeMonsterBall() {
  ...
  
  let nX = Math.random() * 960;
  let nY = Math.random() * 520;
  let nStepSize = 4;
  let nStepX = nStepSize;
  let nStepY = nStepSize;
  let nTimerID = 0;
  let nEndX = 0;
  let nEndY = 0;
  
  nEndX = maingame.offsetWidth - monsterBall.offsetWidth;
  nEndY = maingame.offsetHeight - monsterBall.offsetHeight;
  if(nTimerID === 0) {
   nTimerID=setInterval(startMove, 20);
  }

  function startMove(){
    nX += nStepX;
    nY += nStepY;
    if (nX > nEndX) {nStepX =- nStepSize;}
    if (nX < 0) {nStepX = nStepSize;}
    if (nY > nEndY) {nStepY =- nStepSize;}
    if (nY < 0) {nStepY = nStepSize;}
    monsterBall.style.left = nX + 'px';
    monsterBall.style.top = nY + 'px';
 }
}

 

 

JS - ํฌ์ผ“๋ชฌ์˜ ์›€์ง์ž„ ๋‹ค์–‘ํ™” (class, ์ƒ์†๊ณผ ๋‹คํ˜•์„ฑ)

์›€์ง์ž„์ด ๊ฐ™์€ ์บ๋ฆญํ„ฐ๋“ค์€ ํ•˜๋‚˜์˜ class๋กœ ์ƒ์„ฑํ•ด์ฃผ์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋น„์Šทํ•œ ํŠน์ง•์„ ๊ฐ–๋Š” ์บ๋ฆญํ„ฐ๋“ค์€ ์ƒˆ๋กœ์šด class๋ฅผ ์ •์˜ํ•˜๊ณ  extends ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๊ธฐ๋ณธ์ ์ธ ๊ธฐ๋Šฅ์€ ๊ณต์œ ํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ๊ณ , ์ข€ ๋” ์†์„ฑ์„ ์ถ”๊ฐ€ํ•จ์œผ๋กœ์จ ๋‹คํ˜•์„ฑ์„ ๊ตฌํ˜„ํ•ด๋ณด์•˜๋‹ค. 

 

์˜ˆ๋ฅผ๋“ค์–ด Pocketmon์ด๋ผ๋Š” ์œ„์น˜๋ฅผ ์„ค์ •ํ•˜๊ณ (setPosition), ์˜ค๋ฅธ์ชฝ์—์„œ ์™ผ์ชฝ์œผ๋กœ ์ด๋™ํ•˜๋Š” ๊ธฐ๋ณธ์ ์ธ ๋™์ž‘(move)์„ ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง„ ํด๋ž˜์Šค๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•˜์ž. ๊ทธ๋ฆฌ๊ณ  setPosition์ด๋ผ๋Š” ์œ„์น˜ ์„ค์ • ๋ฉ”์„œ๋“œ๋Š” ์œ ์ง€ํ•˜๊ณ  ์›€์ง์ž„๋งŒ ์•„๋ž˜์„œ ์œ„๋กœ ์ด๋™ํ•˜๋„๋ก ํ•˜๊ณ ์‹ถ๋‹ค๋ฉด, ์ผ๋‹จ extends์™€ super ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด Pocketmon ํด๋ž˜์Šค์˜ ์†์„ฑ๋“ค์„ ์ƒ์†๋ฐ›๋Š” ์ƒˆ๋กœ์šด ํด๋ž˜์Šค (ToTopPoketmon)๋ฅผ ๋งŒ๋“ ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์›€์ง์ž„์„ ์กฐ์ •ํ•˜๋Š” move ๋ฉ”์„œ๋“œ๋งŒ ์•„๋ž˜์„œ ์œ„๋กœ ์›€์ง์ด๋„๋ก ๋ฐ”๊ฟ”์ค€๋‹ค. ์ด๋Ÿฐ ์‹์œผ๋กœ class ํ‚ค์›Œ๋“œ๋กœ ๋‹ค์–‘ํ•œ ํฌ์ผ“๋ชฌ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด 40์ข… ์ •๋„์˜ ํฌ์ผ“๋ชฌ์ด 5๊ฐ€์ง€ ์ •๋„์˜ ๋‹ค์–‘ํ•œ ์›€์ง์ž„์„ ๊ฐ–๋„๋ก ๋งŒ๋“ค์–ด ์ฃผ์—ˆ๋‹ค.

 

class Pocketmon {
  constructor(top, left, timeBetweenSteps) {
    // ์ƒ๋žต
    this.step();
    this.setPosition(top, left);
    this.move();
  }
  
  createDancerElement() { }
  step() { }
  setPosition(top, left) { }
  
  move() {
    this.$node.animate({ transform: 'translateX(-100px)' }, this.timeBetweenSteps);
    this.$node.style.left = `${Number(this.$node.style.left.slice(0, -2)) - 100}px`;
    setTimeout(this.move.bind(this), this.timeBetweenSteps);
  }
}

 

class ToTopPocketmon extends Pocketmon {
    constructor() {
        super(...arguments)
    }
    move() {
        this.$node.animate({ transform: 'translateY(-50px)' }, this.timeBetweenSteps);
        this.$node.style.top = `${Number(this.$node.style.top.slice(0, -2)) - 50}px`;
        setTimeout(this.move.bind(this), this.timeBetweenSteps);
    }
}

 

 

์œ ์ € ์ •๋ณด ์ €์žฅ - LocalStorage, data ๊ฐ์ฒด, JSON

์ฐฝ์„ ์ƒˆ๋กœ๊ณ ์นจํ•˜๊ฑฐ๋‚˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์ข…๋ฃŒํ•ด๋„ ๋™์ผํ•œ ID๋กœ ์ ‘์†ํ•˜๋ฉด ์ด์ „ ๊ธฐ๋ก์ด ์œ ์ง€๋˜๋„๋ก ํ•˜๊ธฐ์œ„ํ•ด  Local Storage๋ฅผ ์ด์šฉํ–ˆ๋‹ค. ์ €์žฅ๋  ์ •๋ณด๋“ค์„ ํ•˜๋‚˜์˜ ๊ฐ์ฒด(infoData)์— ๋„ฃ์–ด๋‘๊ณ , ๊ฒŒ์ž„์ค‘์— ๊ณ„์†ํ•ด์„œ ์ด ๊ฐ์ฒด์˜ ์ •๋ณด๋“ค์ด ์—…๋ฐ์ดํŠธ ๋˜๋„๋ก ํ–ˆ๋‹ค. ์ €์žฅ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์—…๋ฐ์ดํŠธ๋œ infoData๊ฐ€ storageArr๋ผ๋Š” ๋ชจ๋“  ์œ ์ € ์ •๋ณด๊ฐ€ ๋‹ด๊ธด ๋ฐฐ์—ด์— ์ €์žฅ๋˜๊ณ  ์ด ๋ฐฐ์—ด์ด ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ถ”๊ฐ€๋œ๋‹ค. ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด id๊ฐ€ ์ผ์น˜ํ•˜๋Š” ๊ฐ์ฒด์˜ ์ •๋ณด๋“ค์ด ๊ฐ์ž์˜ ์œ„์น˜์— ์„ธํŒ…๋˜๋„๋ก ํ–ˆ๋‹ค.

 

์ €์žฅํ•  ๋•Œ๋Š” ์ด๋ฏธ storage์— ์กด์žฌํ•˜๋Š” id์ธ์ง€ ํ™•์ธ ํ›„ ์žˆ์œผ๋ฉด ๊ธฐ์กด๊ฐ์ฒด์— ๋ฎ์–ด์”Œ์šฐ๊ณ , ์ฒ˜์Œ ์ƒ์„ฑ๋œ id๋ผ๋ฉด ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด storage์— ์ถ”๊ฐ€ํ•ด์ฃผ๋Š” ์‹์œผ๋กœ ๋งŒ๋“ค์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ  JSON.stringify, JSON.parse๋ฅผ ์ด์šฉํ•จ์œผ๋กœ์จ ๋ฐ์ดํ„ฐ๋ฅผ ์˜๋„ํ•œ ๋Œ€๋กœ ์ธ์‹ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค.

   

let infoData = {pocketmonNum: 0, pocketballNum: 20, exp: 0, level: 1};
let storageArr = [];
if (!localStorage.pocketStorage) {
  localStorage.setItem('pocketStorage', JSON.stringify(storageArr));
} else {
  storageArr = JSON.parse(localStorage.pocketStorage);
}

 

// ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ํด๋ฆญ์‹œ
function handleLoginBtn() {
  // ...์ƒ๋žต
  infoData = storageSet(id);
  pocketballInfoNum.textContent = infoData.pocketballNum;
  pocketmonInfoNum.textContent = infoData.pocketmonNum;
  levelText.textContent = `Level ${infoData.level}`;
  userId.textContent = infoData.id;
  progress.value = infoData.exp;
  progress.setAttribute('data-label', `EXP ${infoData.exp}/100`);
  // ...์ƒ๋žต
}

 

// ์ €์žฅ ๋ฒ„ํŠผ ํด๋ฆญ์‹œ
function handleSaveBtn() {
  let check = false;
  for (let i in storageArr) {
    if (storageArr[i].id === infoData.id) {
      storageArr[i] = infoData;  
      check = true;
    }
  }
  if (!check) {
    storageArr.push(infoData);
  }
  localStorage.setItem('pocketStorage',JSON.stringify(storageArr));
}

 

 

๋Š๋‚€์ 


์ด๋ฒˆ์—๋Š” ๊ธฐ๋Šฅ๋„ ๊ธฐ๋Šฅ์ด์ง€๋งŒ ํ˜‘์—…์˜ ์ค‘์š”์„ฑ์„ ๋ฌด์—‡๋ณด๋‹ค ๊ฐ€์žฅ ํฌ๊ฒŒ ๊นจ๋‹ฌ์•˜๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ ๊ณ„์‚ฐ๊ธฐ, ํŠธ์œ„ํ‹€๋Ÿฌ, ๋‚ ์”จ ์•ฑ ๋“ฑ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋งŒ๋“œ๋Š” ์ž‘์€ ํ”„๋กœ์ ํŠธ(?)๋“ค์€ ํŽ˜์–ด๋ถ„๊ณผ ์งˆ๋ฌธ์ด๋‚˜ ์†Œํ†ต์€ ํ•˜์ง€๋งŒ ๊ธฐํš์ด๋‚˜ ๊ตฌํ˜„์€ ๊ฐ์ž ์ง„ํ–‰ํ•ด์™”๋‹ค. ์‚ฌ์‹ค ๋””์ž์ธ์ด๋‚˜ ๊ธฐํš์—๋Š” ๊ฐœ์ธ์˜ ์ทจํ–ฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ๋„ ํ•˜๊ณ  ๊ฐ์ž ํ•˜๊ณ ์‹ถ์€๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š์„๊นŒ? ์‹ถ๊ธฐ๋„ ํ•ด์„œ ์ด๋ฒˆ์—๋„ ๋‹น์—ฐํžˆ ์ด์ „์ฒ˜๋Ÿผ ์ง„ํ–‰ํ•  ์ค„ ์•Œ์•˜๋Š”๋ฐ, ํŽ˜์–ด๋ถ„์ด ๋จผ์ € ์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€ ๋‹ค ๊ฐ™์ดํ•˜์ž๊ณ  ์ œ์•ˆํ•ด์ฃผ์…”์„œ ํ•จ๊ป˜ ์ง„ํ–‰ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ์šฐ์„  ๊ฒฐ๋ก ์ ์œผ๋กœ๋Š” ์ ๊ทน์ ์œผ๋กœ ์ œ์•ˆํ•ด์ฃผ์‹  ๊ฒƒ์— ๋Œ€ํ•ด ๋„ˆ๋ฌด ๊ฐ์‚ฌํ•˜๊ฒŒ ์ƒ๊ฐํ•˜๊ณ  ์žˆ๋‹ค.

 

๋ณต์Šต

๋งจ ์ฒ˜์Œ์— ์บ๋ฆญํ„ฐ๋“ค ๊ฐ„์˜ ํด๋ž˜์Šค ์ƒ์†์„ ๊ฐ€์žฅ ๋จผ์ € ๊ตฌํ˜„ํ–ˆ๋Š”๋ฐ ์ด ๋ถ€๋ถ„์—์„œ ์‚ด์ง ํ•ด๋งค๊ธฐ๋„ ํ–ˆ๋‹ค. ์ผ๋‹จ ์–ด์ฐŒ์ €์ฐŒ ์ฝ”๋“œ๋ฅผ ํ•จ๊ป˜ ์™„์„ฑํ•˜๊ณ ๋‚œ ํ›„, ๊ทธ๋Œ€๋กœ ๋ณต๋ถ™ํ•ด์„œ ์ฃผ๊ณ  ๋ฐ›์ง€ ์•Š๊ณ  ๋ฐฑ์ง€์ƒํƒœ์ธ ๋‚˜๋จธ์ง€ ํ•œ๋ช…์˜ ์ฝ”๋“œ์ฐฝ ํ™”๋ฉด์„ ๊ณต์œ ํ•ด ์ฒ˜์Œ๋ถ€ํ„ฐ ํ•จ๊ป˜ ๋‹ค์‹œ ์ž‘์„ฑํ•ด๋ณด๋Š” ์‹์œผ๋กœ ์ง„ํ–‰ํ–ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ค๋ณด๋‹ˆ ๋ณต์Šต๋„ ํ™•์‹คํ•˜๊ฒŒ ๋˜์–ด์„œ ๊ทธ ๋‹ค์Œ๋ถ€ํ„ฐ๋Š” ์›ํ™œํ•˜๊ฒŒ ์ง„ํ–‰ ํ•  ์ˆ˜ ์žˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค.

 

Git์œผ๋กœ ํ˜‘์—…ํ•ด๋ณด๊ธฐ

๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ํ•œ ๋ช…์˜ ๋ชจ๋‹ˆํ„ฐ๋ฅผ ๊ณต์œ ํ•ด ํ•จ๊ป˜ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋Š”๋ฐ, ํ•˜๋‹ค๋ณด๋‹ˆ ์ผ๋ถ€ ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์žˆ๋Š” ๋ถ€๋ถ„๋“ค์ด ์ƒ๊ฒจ์„œ ์ด ๋ถ€๋ถ„์€ ๋‹ค๋ฅธ ํ•œ๋ช…์ด ์ˆ˜์ •ํ•ด ์ฝ”๋“œ๋ฅผ ๋„˜๊ฒจ์ฃผ๊ธฐ๋กœ ํ–ˆ๋‹ค. ์›๋ž˜๊ฐ™์œผ๋ฉด ๊ทธ๋ƒฅ slack ๋ฉ”์„ธ์ง€๋กœ ์ฃผ๊ณ ๋ฐ›์•˜๊ฒ ์ง€๋งŒ Git workflow์— ๋Œ€ํ•ด ๋ฐฐ์šด ์ดํ›„์˜€๊ธฐ ๋•Œ๋ฌธ์— Git pull, push๋ฅผ ์ด์šฉํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค. ๋ณต๋ถ™ํ•˜์ง€ ์•Š์•„๋„ ๋ช…๋ น์–ด๋งŒ ์ž…๋ ฅํ•˜๋ฉด ๋ฐ”๋กœ๋ฐ”๋กœ ์ˆ˜์ •๋œ ๋ถ€๋ถ„๋งŒ ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ๊ณ , ์ปค๋ฐ‹ ๊ธฐ๋ก๊ณผ ์ˆ˜์ •ํ•œ ๋ถ€๋ถ„์— ๋Œ€ํ•œ ๊ธฐ๋ก์ด ๋‚จ์•„์„œ ์–ด๋–ค ๋ถ€๋ถ„์„ ์–ด๋–ป๊ฒŒ ๊ณ ์ณค๋Š” ์ง€ ํ™•์ธํ•˜๊ธฐ์—๋„ ์ข‹๋‹ค๋Š” ๊ฑธ ๋ชธ์†Œ ๋Š๋‚„ ์ˆ˜ ์žˆ์—ˆ๋‹ค. 

 

๋ถ€์กฑํ•œ ์  ๋ณด์™„, ๋ถ„์—…

๊ผผ๊ผผํ•œ ์„ฑ๊ฒฉ์ด ์•„๋‹ˆ๋ผ ์ž์ž˜ํ•œ ์‹ค์ˆ˜๋ฅผ ๋งŽ์ด ํ•˜๋Š”๋ฐ, ํŽ˜์–ด๋ถ„์ด ๋งค์˜ ๋ˆˆ์œผ๋กœ ์ง€์ผœ๋ณด์‹œ๋‹ค๊ฐ€ ์‹ค์ˆ˜ํ•œ ๋ถ€๋ถ„๋“ค์„ ์ž˜ ์ง‘์–ด๋‚ด์ฃผ์…”์„œ ์˜ค๋ฅ˜๋“ค์„ ๋ฏธ๋ฆฌ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ํ•„์š”ํ•œ ์†Œ์Šค๋“ค๋„ ๋ถ„์—…์„ ํ•˜๋‹ˆ๊นŒ ํ˜ผ์ž ํ•  ๋•Œ๋ณด๋‹ค ๋‘๋ฐฐ๋กœ ๋น ๋ฅด๊ฒŒ ์ฐพ์„ ์ˆ˜ ์žˆ์—ˆ๊ณ , ํ•œ๋ช…์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋™์•ˆ ๋‹ค๋ฅธ ํ•œ๋ช…์€ ์ ์šฉํ• ๋งŒํ•œ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ฐพ์•„์˜ค๋Š” ๋“ฑ ํ›จ์”ฌ ํšจ์œจ์ ์œผ๋กœ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์‚ฌ์‹ค ํ˜ผ์ž์˜€์œผ๋ฉด ๋‹น์—ฐํžˆ ์ดํ‹€๋™์•ˆ ๊ธฐํšํ•œ๊ฑธ ๋‹ค ๋๋‚ด์ง€ ๋ชปํ• ๊ฑฐ๋ผ๊ณ  ์ƒ๊ฐํ•ด ๋Œ€์ถฉ ๋งˆ๋ฌด๋ฆฌ ์ง€์—ˆ์„ ์ˆ˜๋„ ์žˆ์—ˆ์„ ๊ฒƒ ๊ฐ™๋‹ค. ํŽ˜์–ด๋ถ„๋„ ์‹œ๊ฐ„์ด ๋‚˜์‹œ๋Š”๋Œ€๋กœ ์คŒํ• ๊นŒ์š”? ๋ผ๊ณ  ์ ๊ทน์ ์œผ๋กœ ๋ง์”€ํ•ด์ฃผ์‹  ๋•๋ถ„์— ๋‚˜๋„ ์ƒˆ๋ฒฝ๊นŒ์ง€ ์ž ๋„ ์•ˆ์ž๊ณ  ํ•  ์ •๋„๋กœ ์ ๊ทน์ ์œผ๋กœ ์ž„ํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , ์ฒ˜์Œ ๊ธฐํšํ•œ๋Œ€๋กœ ์ž˜ ๋งˆ๋ฌด๋ฆฌ ์ง€์„ ์ˆ˜ ์žˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค.

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€