본문 바로가기

html+CSS+JS

[쫌쫌따리 스터디] 피하기 게임(dodge) 만들어보기 #1 - player 캐릭터 움직이게 만들기

반응형

계산기, 계산기 수학게임, ㅋ톡 대화 보기에 이어서

테트리스보다 이게 더 쉬우니 한 번 만들어보는게 어떻겠냐는 말을 들어

이번 쫌쫌따리 스터디로는 피하기 게임을 만들어보려 합니다.

 

피하기 게임은 형태가 참 다양합니다.

세로로 움직여서 오른쪽에서 날아오는 무언가를 피하는 게임도 있고,

무수히 쏟아지는 공을 바닥에서 캐릭터가 달리면서 피하기도 하고

랜덤으로 사방에서 쏟아져 나오는 총알(?)을 우주선을 상하좌우로 움직여 피하기도 합니다.

 

저는 우측처럼 상하좌우 랜덤으로 움직이고, 피해야 하는게 시간이 갈수록 많이 나오는 걸 하려고 합니다.

우주선말고 다른 귀여운 거 없을까 싶어서 고민하다가 슬라임을 플레이어 캐릭터로 하고,

쏟아져 나오는 검정하트(unlike)를 피하는 거로 만들려고 해요.

 

기능 요점

1. 슬라임(플레이어 캐릭터) 방향키 따라 움직이게 만들기

2. 부드럽게 움직이게 만들기

3. 하트 랜덤하게 움직이게 만들기

4. 검정 하트에 닿으면 죽게 만들기

5. 시간이 지날수록 총알 늘리기

6. 기타 UI 이쁘게 만들기

7. 된다면... 핑크 하트로 점수 추가 기능?

 

 

1일차 진행 과정

우선 플레이어 캐릭터 만드는 작업이 제일 우선이겠죠?

html, css는 매우 간단하게 했습니다.

<div class="container">
  <div id="player"></div>
</div>
.container {
  height: 100vh;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
}
#player {
  width:21px;
  height:18px;
  background: url(./image/slime_default.gif) center no-repeat;
}

처음에 가운데 위치시키는 건 가장 만만한 display:flex를 사용했고,

#player는 이미지 사이즈에 맞춰서 넓이, 높이를 정했습니다.

 

이미지는 구글 검색 중 보인 너무 귀여운 슬라임 소스를 다운 받아서 움짤 버전으로 만들었습니다.

혹시 만들어보실 분들은 참고하시라고 링크 남겨둬요.

무료로도 다운받을 수 있는데 너무 귀여워서 저는 후원했습니다

 

2D Pixel Slime Set by tienlev

an pixel slime assets with 7 difference colors, 8 animations.

tienlev.itch.io

 

여튼 이렇게 하니 이런 식으로 화면 중앙에서 뾰잉뾰잉하게 움직이게 됐습니다.

화면 중앙에서 움직이는 슬라임
움직이는 슬라임:3

 

이 뒤로는 js를 만들어야겠죠?

const $playable = document.getElementById("player");
      $container = document.querySelector(".container");

먼저 필요한 요소를 정의하는 상수를 만듭니다.

개인적으로는 요소 상수에는 앞에 $를 붙이는 편이에요.

 

// 키보드 눌렀을 때 이벤트
window.addEventListener("keydown", function(e){
  // 무슨 키 눌렀는지 확인
  // 이동량 계산
  // 위치 업데이트
  // 위치 제한
  // 움직임 반영
})

// 키보드 뗐을 때 이벤트
window.addEventListener("keyup", function(e){
  // 무슨 키 뗐는지 확인
})

키보드를 눌렀을 때는 'keydown' 이벤트를, 뗐을 때는 'keyup' 이벤트를 통해 추적합니다.

각각 함수 내에서 어떤 부분을 체크해야 하는지 주석으로 미리 추가해뒀어요.

 

그리고 각 함수 내에서 console.log(e)를 통해서 어떤 부분을 사용할지 고민해서

key를 통해 클래스를 부여해서 슬라임의 외형을 바꾸고,

keyCode를 통해 움직임을 부여하려고 결심했습니다.

 

key는 자판키의 이름(ex. ArrowUp = 위쪽 화살표),

keyCode는 자판키에 부여된 번호(ex. 37 = 위쪽 화살표)입니다.

 

처음에는 key만으로 전부 하려고 했는데, 방향키를 2개 누르는 경우를 맞다보니 바꼈어요.

const keyMap = [];

window.addEventListener("keydown", function(e){
  // 무슨 키 눌렀는지 확인
  keyMap[e.keyCode] = true;
  $playable.classList.add(e.key);
})

window.addEventListener("keyup", function(e){
  // 무슨 키 눌렀는지 확인
  keyMap[e.keyCode] = false;
  $playable.classList.remove(e.key);
})

그래서 상단에 'keyMap'이라는 빈 배열을 추가해서,

자판키에 부여된 번호에 따라 누른 번호는 true로 바뀌게 만들었고,

player 요소에 방향 버튼에 따라 클래스를 추가했습니다.

 

마찬가지로 자판키를 뗐을 때에 반대 급부에 해당하는 작업도 추가해뒀고요.

화살표키 누를 때마다 클래스 바뀜
화살표키 누를 때마다 클래스 바뀜

클래스에 따라 배경 이미지를 변경해서 화살표 방향에 따라 움직이는 모션도 다르게 해두니 더 귀엽지 않나요?

 

window.addEventListener("keydown", function(e){
  // 이동량 계산
  const moveX = keyMap[37] ? -10 : keyMap[39] ? 10 : 0;
  const moveY = keyMap[38] ? -10 : keyMap[40] ? 10 : 0;
})

이동량을 줘야해서 moveX를 통해 좌우, moveY를 통해 상하로 얼만큼 움직일지 적었습니다.

눌린 키는 keyMap에서 true로 해두었기 때문에, 상하와 좌우 상수를 나누어 받아서 동시에 움직이는 것이 가능하도록 만든 겁니다.

어차피 키가 눌릴 때마다 상수값을 받는 거라 변수가 아닌 상수로 해도 괜찮습니다.

 

이걸 if문으로 경우의 수마다 다 조건을 걸다보니 반복되는게 많아서 고민해서 줄여보고, chatGPT한테 가서도 좀 더 줄여봤습니다. 덕분에 조건연산자를 쓰는 방식을 좀 더 알게 된 느낌?😊

 

const wholeW = ($container.clientWidth/2)-100,
      wholeH = ($container.clientHeight/2)-100,
      playerPos = { x: 0, y: 0 };

이제 좌표값을 주려고 하는데 움직일 수 있는 영역에 제한을 둬야 할 것 같아

.container의 넓이, 높이를 통한 값, #player의 좌표 객체를 전역 상수로 만들었습니다.

 

window.addEventListener("keydown", function(e){
  // 위치 업데이트
  playerPos.x += moveX;
  playerPos.y += moveY;

  // 위치 제한
  if (playerPos.x < -wholeW) playerPos.x = -wholeW;
  if (playerPos.x > wholeW) playerPos.x = wholeW;
  if (playerPos.y < -wholeH) playerPos.y = -wholeH;
  if (playerPos.y > wholeH) playerPos.y = wholeH;

  // 움직임 반영
  $playable.style.transform = `translate(${playerPos.x}px, ${playerPos.y}px)`;
})

객체를 상수로 설정해도 객체 내부 파라미터의 값은 바꿀 수 있기에

위에서 이동량을 반영한 moveX와 moveY를 통해 플레이어의 좌표값을 업데이트 합니다.

 

그리고 wholeX, wholeY를 통해 이동량이 위치 제한을 넘기지 않도록 설정해주고,

#player 요소에 translate를 적용시켜 업데이트 된 좌표값을 반영시킵니다.

내가 방향키를 누르는대로 뽈뽈대는 슬라임
내가 방향키를 누르는대로 뽈뽈대는 슬라임

 

 

이렇게 마치고 나니 한 2~3시간 지났더라고요.

그리고 이렇게 정리하는게 근 4시간이나 걸렸지만...

 

 

 

 

주저리 TMI 잡담

 

세상에는 할 게 너무나도 많습니다. 수많은 일들이 산더미처럼 쌓여있죠.

정보는 끊임없이 쏟아지며, 다양한 취미를 즐길 기회, 자기계발의 기회도 넘치고 있습니다.

직장을 다니면서도 하루 2시간, 4시간 심지어는 그 이상으로 공부를 하거나 자기 계발을 하시는 분들이 있다는 이야기를 때때로 듣습니다.

많은 정보와 수없는 기회를 다 잡으면 좋겠다고 생각하고, 분명 내게 이득이 될 것을 알지만,

놓치는 것들이 너무나도 많고 앞으로 더 많아질 것을 알아 무력감을 느끼고 허탈해지는 것 같습니다.

 

이런 상황에서 스스로를 돌보기 위해서라도 적당한 페이스로 일상에 살을 더하는 것은 어떨까 생각하고 있습니다.

쫌쫌따리 스터디도 저 스스로의 페이스에 맞춰서 뭔가 조금씩이라도 해보고자 하고 있는 중입니다.

일이주의 간격이 생기더라도 천천히, 제가 힘들지 않을 때, 원할 때 조금씩.

블로그에 공부 내용을 정리하는 것도 마찬가지에요. 저만의 속도와 시간에 맞춰서 진행하고자 합니다.

그동안 계산기, 계산기 수학게임, ㅋ톡 대화 보기를 만들어봤다고 적었는데, 그것들도요.

 

같이 시작한 누군가보다는 늦을 수 있고, 그 사이 잊는 것들이 생길 수 있지만 그럼에도 조금씩 무언가를 해보려고 합니다.

무언가를 또 하나 해낸 거잖아요? 실패를 하더라도 그게 쌓이는 거니까요.

바쁜 일상 속, 삶을 살아가려 노력하는 스스로를 칭찬하고 격려하기를 잊지 마세요.

어제보다 조금씩 나아지며 성장해 나가는 과정에서 스스로를 축복하는 것은 큰 힘이 될 거라 생각합니다.

 

 

 

그럼 제가 심적으로 여유가 있거나, 문득 하고 싶어지거나 할 때 다음 편으로 찾아뵙겠습니다.

삶에 쫓기기 보다는 삶을 바라보며 느긋하게 여유를 가지고 사시길 바랍니다:)

 

반응형