드디어 나도 html, css 그리고 javascript만으로 만들 수 있는 간단한 게임인 Enemy Rain에 도전할 수 있게되었다.
구현할 기능은 사실 많이없지만 개발을 배운지 한 달도 안된 상태에서 하기에는 만만하게 볼 수 없는 작업이었다.
이번에 에너미 레인을 만들게 되면서 처음 알게 된 거지만, 인스타그램의 아이콘 등 이미지는 사실 각자 하나의 이미지 파일이 아니라 하나의 판에 이미지들을 모아두고 css로 좌표를 조절해서 필요한 이미지만 보여지게 만드는 것이라는...
간단하게 말하자면 딱 하나의 이미지만 보일 정도로 구멍을 뚫어놓고 그 밑에서 여러 이미지를 모아둔 판을 이리 저리 움직이며 필요한 이미지만 구멍으로 보여지게 하는 것!
if(e.key === 'a'){
hero.style.backgroundPosition = '70px'
}
⬆︎ 위 처럼 css 스타일에서 backgroundPosition을 사용해서 좌표를 설정해주면 해당 이미지판이 그 위치로 이동하게 된다. 미리 만들어놓은 div같은 태그의 width값과 height값을 이미지 크기에 맞게 설정해 두면 마치 그 이미지만 보이게 하는 '구멍'이 된다! 이 div태그에 css로 background-position 프로퍼티를 설정해주면 됨! 대신에 background-image 프로퍼티로 css에서 이미지를 추가해야한다. html에서 img 태그로 이미지를 넣으면 안됨!
히어로 이미지가 들어갈 div태그를 정중앙에 배치시켰다.
게임 배경화면은 img태그와 히어로가 들어갈 div태그를 다른 부모 div 태그로 함께 감쌌다.
.bgContainer {
display: flex;
align-items: center;
position: relative;
}
.hero {
position: absolute;
bottom: 0;
left: 400px;
width: 35px;
height: 54px;
background-image: url(../img/hero.png);
background-position: 0px;
}
이렇게 부모태그에 positon: relative;를 하고 히어로 태그에는 position: absolute에 left: 400px;을 주어 중앙으로 오게 했다.
const hero = document.getElementsByClassName('hero')[0];
window.addEventListener('keydown', move)
function move(e){
if(e.key === 'a' || e.key === 'ㅁ'){
hero.style.backgroundPosition = '70px'
} else if(e.key === 'd' || e.key === 'ㅇ'){
hero.style.backgroundPosition = '35px'
} else if(e.key === 's' || e.key ==='ㄴ'){
hero.style.backgroundPosition = '0px'
} else if(e.key === 'w' || e.key === 'ㅈ'){
hero.style.backgroundPosition = '105px'
}
}
맥북에서 방향키의 keycode를 찾지 못해서 a,w,s,d 키로 일단 만들었다. 또 영문으로 쳤을때와 한글로 변경했을 때 keycode가 다르다는 것을 알게됐다. keydown 이벤트를 걸고 move라는 함수를 실행되게 했다. 키 이벤트가 발생할때마다 hero의 background의 값이 바뀌게 만들었다. 키가 눌리면 캐릭터의 이미지가 바뀌면서 바라보는 방향이 달라지게 된다.
자바스크립트 DOM으로 .here의 left 프로퍼티에 접근하여 px값을 수정하여 위치를 이동하게 만들려고 시도했다.
const hero = documennt.getElementsByClassName('here')[0];
const leftValue = hero.style.left;
위 방법으로 접근하려 하였으나.. 스타일.css파일처럼 외부에서 import 된 style 속성 값은 읽어올수 없다고 한다! (충격..)
이런 경우를 해결해주는 매서드가 바로 getComtuptedStyle()다.
let style = window.getComputedStyle('Element');
let leftValue = style.left;
currentStyle() 메소드는 css에서 정한 단위로 결과 값을 보여준다. getComputedStyle() 메소드는 항상 'px' 단위로 결과 값을 보여준다.
const hero = document.getElementsByClassName('hero')[0] // 히어로
const cssOfHero = window.getComputedStyle(hero); // .hero의 css에 접근
let leftValue = cssOfHero.left; // .here의 css 효과중 left의 값
let leftValueWithoutPx = parseInt(leftValue);
window.addEventListener('keydown', move)
function move(e){
if(leftValueWithoutPx >=0 && leftValueWithout <= 760){
if(e.key === 'a' || e.key === 'ㅁ'){
hero.style.backgroundPosition = '70px'
let toLeft = leftValueWithoutPx -= 5;
hero.style.left = toLeft+'px';
} else if(e.key === 'd' || e.key === 'ㅇ'){
hero.style.backgroundPosition = '35px'
let toRight = leftValueWithoutPx += 5;
hero.style.left = toRight+'px';
}
}
캐릭터를 좌우로 움직였을때 배경화면의 끝에서 더 벗어나지 않도록 하기위해 초반에 시도핸 코드다.
힘들게 getComputedStyle로 left 값을 가져오고 다시 parseInt 함수로 px을 떼어네 넘버로 바꾸주고 다시 px을 더해 hero.style.left에 더해주는.. 과정을 거쳤다.
게다가 결정적으로 화면 끝까지가면 벗어나지는 않지만 저 조건문의 조건을 벗어나게 되면서 움직일 수 없게되어버렸다...
그러다 알게된 함수가 offset!
offset함수를 통해 요소의 좌표값을 알아낼 수 있다. 힘들게 getComputedStyle로 접근해서 알아낼 필요 없이 .hero.offsetLeft로 왼쪽에서부터의 좌표를 알 수 있다 ..
function move(e){
if((e.key === 'a'|| e.key ==='ㅁ') && hero.offsetLeft > 0){
hero.style.left = (hero.offsetLeft - 5)+'px';
hero.style.backgroundPosition = '70px';
} else if((e.key === 'd'||e.key ==='ㅇ') && hero.offsetLeft < 770){
hero.style.left = (hero.offsetLeft + 5)+'px';
hero.style.backgroundPosition = '35px';
}
}
캐릭터가 배경을 넘어가지 않도록 조건도 다시 수정했다. 훨씬 더 간결해져서 만족... offsetLeft를 한 조건에 넣지 않고 각각 방향에 나누어 놓으니 화면 끝까지 가고 멈춰버리는 현상을 해결 할 수 있었다.
window.getComputedStyle('Element') 로 css 프로퍼티에 접근할 수 있다.
offsetLeft 같은 offset 시리즈들을 활용하여 요소의 위치를 알 수있다. (부모 요소에 대해 상대적인 요소가 우선이며 부모 요소의 position: relative가 아니라면 더 상위 요소를 찾고 전부 relative가 아니라면 절대위치 값을 리턴한다.
3.css에서 background-image로 이미지를 넣을 수 있고 background-position으로 해당 이미지의 위치를 조절할 수 있다.