ํ ์ค ์๊ฐ ๐น
ํฌ์ผ๋ณผ์ ์ฃผ์ ํฌ์ผ๋ชฌ์ ์ก์ ๊ฒฝํ์น๋ฅผ ์๊ณ , ๋ ๋ฒจ์ ์ฌ๋ฆฌ๋ ๊ฒ์์ด๋ค.
์ฃผ์ ๊ธฐ๋ฅ
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๋ฅผ ์ด์ฉํด๋ณด๊ธฐ๋ก ํ๋ค. ๋ณต๋ถํ์ง ์์๋ ๋ช ๋ น์ด๋ง ์ ๋ ฅํ๋ฉด ๋ฐ๋ก๋ฐ๋ก ์์ ๋ ๋ถ๋ถ๋ง ์ถ๊ฐํ ์๋ ์๊ณ , ์ปค๋ฐ ๊ธฐ๋ก๊ณผ ์์ ํ ๋ถ๋ถ์ ๋ํ ๊ธฐ๋ก์ด ๋จ์์ ์ด๋ค ๋ถ๋ถ์ ์ด๋ป๊ฒ ๊ณ ์ณค๋ ์ง ํ์ธํ๊ธฐ์๋ ์ข๋ค๋ ๊ฑธ ๋ชธ์ ๋๋ ์ ์์๋ค.
๋ถ์กฑํ ์ ๋ณด์, ๋ถ์
๊ผผ๊ผผํ ์ฑ๊ฒฉ์ด ์๋๋ผ ์์ํ ์ค์๋ฅผ ๋ง์ด ํ๋๋ฐ, ํ์ด๋ถ์ด ๋งค์ ๋์ผ๋ก ์ง์ผ๋ณด์๋ค๊ฐ ์ค์ํ ๋ถ๋ถ๋ค์ ์ ์ง์ด๋ด์ฃผ์ ์ ์ค๋ฅ๋ค์ ๋ฏธ๋ฆฌ ๋ฐฉ์งํ ์ ์์๋ค. ํ์ํ ์์ค๋ค๋ ๋ถ์ ์ ํ๋๊น ํผ์ ํ ๋๋ณด๋ค ๋๋ฐฐ๋ก ๋น ๋ฅด๊ฒ ์ฐพ์ ์ ์์๊ณ , ํ๋ช ์ด ์ฝ๋๋ฅผ ์์ฑํ๋ ๋์ ๋ค๋ฅธ ํ๋ช ์ ์ ์ฉํ ๋งํ ์๋ก์ด ๊ธฐ๋ฅ์ ์ฐพ์์ค๋ ๋ฑ ํจ์ฌ ํจ์จ์ ์ผ๋ก ์งํํ ์ ์์๋ค. ์ฌ์ค ํผ์์์ผ๋ฉด ๋น์ฐํ ์ดํ๋์ ๊ธฐํํ๊ฑธ ๋ค ๋๋ด์ง ๋ชปํ ๊ฑฐ๋ผ๊ณ ์๊ฐํด ๋์ถฉ ๋ง๋ฌด๋ฆฌ ์ง์์ ์๋ ์์์ ๊ฒ ๊ฐ๋ค. ํ์ด๋ถ๋ ์๊ฐ์ด ๋์๋๋๋ก ์คํ ๊น์? ๋ผ๊ณ ์ ๊ทน์ ์ผ๋ก ๋ง์ํด์ฃผ์ ๋๋ถ์ ๋๋ ์๋ฒฝ๊น์ง ์ ๋ ์์๊ณ ํ ์ ๋๋ก ์ ๊ทน์ ์ผ๋ก ์ํ ์ ์์๊ณ , ์ฒ์ ๊ธฐํํ๋๋ก ์ ๋ง๋ฌด๋ฆฌ ์ง์ ์ ์๋ ๊ฒ ๊ฐ๋ค.
'Project > Toy Project' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋ ์จ APP ๋ง๋ค๊ธฐ (OpenWeather API ํ์ฉ) (5) | 2021.01.05 |
---|---|
ํ์๊ฐ์ ํ์ด์ง ๋ง๋ค๊ธฐ (์ ํจ์ฑ ๊ฒ์ฌ) (0) | 2020.12.25 |
twittler ๋ชฉ์ (HTML, CSS ํ๋์ฝ๋ฉ) (3) | 2020.12.18 |
๋๊ธ