자바스크립트 설명 부탁드립니다

조회수 467회

일단 설명을 위해 코드 전체를 가져온 점은 양해부탁드립니다

자바스크립트로 흔하게 많이 구현해보는 뱀먹이 게임입니다

원본은 외국 유튜버라 설명을 들어도 알 수 없어 여기에 올려봅니다

원본 게임은 https://pothonprogramming.github.io/content/snake/snake.html 여기서 가능합니다

(function() {

  var controller, display, game;

  controller = {

    down:false, left:false, right:false, up:false,

    keyUpDown:function(event) {

      var key_state = (event.type == "keydown")?true:false;

      switch(event.keyCode) {

        case 37: controller.left = key_state; break;
        case 38: controller.up = key_state; break;
        case 39: controller.right = key_state; break;
        case 40: controller.down = key_state; break;
      }
    }
  };

  display = {

    buffer:document.createElement("canvas").getContext("2d"),
    context:document.querySelector("canvas").getContext("2d"),

    graphics: {

      0: {

        canvas:document.createElement("canvas"),
        draw:function() {

          var context = this.canvas.getContext("2d");
          this.canvas.height = this.canvas.width = game.world.tile_size;

          context.fillStyle = "#202830";
          context.fillRect(0, 0, this.canvas.width, this.canvas.height);
          context.fillStyle = "#303840";
          context.fillRect(1, 1, this.canvas.width - 2, this.canvas.height - 2);

        }
      },

      1: {

        canvas:document.createElement("canvas"),
        draw:function() {

          var context = this.canvas.getContext("2d");
          this.canvas.height = this.canvas.width = game.world.tile_size;

          context.fillStyle = "#202830";
          context.fillRect(0, 0, this.canvas.width, this.canvas.height);
          context.fillStyle = "#ff9900";
          context.fillRect(1, 1, game.world.tile_size - 2, game.world.tile_size - 2);

        }
      },

      2: {

        canvas:document.createElement("canvas"),
        draw:function() {

          var context = this.canvas.getContext("2d");
          this.canvas.height = this.canvas.width = game.world.tile_size;

          context.fillStyle = "#202830";
          context.fillRect(0, 0, this.canvas.width, this.canvas.height);
          context.fillStyle = "#99ff00";
          context.fillRect(1, 1, game.world.tile_size - 2, game.world.tile_size - 2);

        }
      },
    },

    background_tile:0,
    segment:1,
    apple:2,

    render:function() {

      for (let index = 0; index < game.world.map.length; index ++) {

        let graphic = this.graphics[game.world.map[index]].canvas;

        this.buffer.drawImage(graphic, 0, 0, graphic.width, graphic.height, (index % game.world.columns) * game.world.tile_size, Math.floor(index / game.world.columns) * game.world.tile_size, game.world.tile_size, game.world.tile_size);

      }

      let leading_zeros = "SCORE: ";
      for (let index = 4 - game.score.toString().length; index > 0; -- index) {

        leading_zeros += "0";

      }

      this.output.innerHTML = leading_zeros + game.score;

      this.context.drawImage(this.buffer.canvas, 0, 0, this.buffer.canvas.width, this.buffer.canvas.height, 0, 0, this.context.canvas.width, this.context.canvas.height);

    },

    resize:function(event) {

      var client_height = document.documentElement.clientHeight;

      display.context.canvas.width = document.documentElement.clientWidth - 32;

      if (display.context.canvas.width > client_height - 64 || display.context.canvas.height > client_height - 64) {

        display.context.canvas.width = client_height - 64;

      }

      display.context.canvas.height = display.context.canvas.width;

      display.render();

      let elements = document.querySelectorAll(".hideable");

      for (let index = elements.length - 1; index > -1; -- index) {

        if (document.body.offsetHeight < document.body.scrollHeight) {

          elements[index].style.visibility = "hidden";

        } else {

          elements[index].style.visibility = "visible";

        }
      }
    }
  };

  game = {

    score:0,

    apple: {

      index:Math.floor(Math.random() * 400)

    },

    snake: {

      head_index:209,
      old_head_index:undefined,
      segment_indices:[209, 210],
      vector_x:0,
      vector_y:0

    },

    world:{

      columns:20,
      tile_size:10,
      map:new Array(400).fill(display.background_tile)

    },

    accumulated_time:0,
    time_step:250,

    reset:function() {

      this.score = 0;

      for (let index = this.snake.segment_indices.length - 1; index > -1; -- index) {

        this.world.map[this.snake.segment_indices[index]] = display.background_tile;

      }

      this.snake.segment_indices = [209, 210];
      this.snake.head_index = 209;
      this.snake.old_head_index = undefined;
      this.snake.vector_x = this.snake.vector_y = 0;
      this.world.map[game.apple.index] = display.apple;
      this.world.map[game.snake.segment_indices[0]] = display.segment;
      this.world.map[game.snake.segment_indices[1]] = display.segment;

      this.time_step = 250;

      this.loop();
      display.render();

    },

    loop:function(time_stamp) {

      if (controller.down) {

        game.snake.vector_x = 0;
        game.snake.vector_y = 1;

      } else if (controller.left) {

        game.snake.vector_x = -1;
        game.snake.vector_y = 0;

      } else if (controller.right) {

        game.snake.vector_x = 1;
        game.snake.vector_y = 0;

      } else if (controller.up) {

        game.snake.vector_x = 0;
        game.snake.vector_y = -1;

      }

      if (time_stamp >= game.accumulated_time + game.time_step) {

        game.accumulated_time = time_stamp;

        if (game.snake.vector_x != 0 || game.snake.vector_y != 0) {

          if (game.snake.head_index + game.snake.vector_y * game.world.columns + game.snake.vector_x == game.snake.old_head_index) {

            game.snake.vector_x = game.snake.vector_y = 0;
            window.requestAnimationFrame(game.loop);
            return;

          }

          let tail_index = game.snake.segment_indices.pop();
          game.world.map[tail_index] = display.background_tile;
          game.snake.old_head_index = game.snake.head_index;
          game.snake.head_index += game.snake.vector_y * game.world.columns + game.snake.vector_x;

          if (game.world.map[game.snake.head_index] == display.segment
            || game.snake.head_index < 0
            || game.snake.head_index > game.world.map.length - 1
            || (game.snake.vector_x == -1 && game.snake.head_index % game.world.columns == game.world.columns - 1)
            || (game.snake.vector_x == 1 && (game.snake.head_index % game.world.columns == 0))) {

            game.reset();
            return;

          }

          game.world.map[game.snake.head_index] = display.segment;
          game.snake.segment_indices.unshift(game.snake.head_index);

          if (game.snake.head_index == game.apple.index) {

            game.score ++;
            game.time_step = (game.time_step > 100)?game.time_step - 10:100;

            game.snake.segment_indices.push(tail_index);
            game.world.map[tail_index] = display.segment;
            game.apple.index = Math.floor(Math.random() * game.world.map.length);

            if (game.snake.segment_indices.length == game.world.map.length - 1) {

              game.reset();
              return;

            }

            while(game.world.map[game.apple.index] != display.background_tile) {

              game.apple.index ++;

              if (game.apple.index > game.world.map.length - 1) {

                game.apple.index = 0;

              }
            }

            game.world.map[game.apple.index] = display.apple;

          }

          display.render();

        }
      }

      window.requestAnimationFrame(game.loop);

    }
  };

  display.buffer.canvas.height = display.buffer.canvas.width = game.world.columns * game.world.tile_size;

  for(let object in display.graphics) {

    display.graphics[object].draw();

  };

  window.addEventListener("resize", display.resize);
  window.addEventListener("keydown", controller.keyUpDown);
  window.addEventListener("keyup", controller.keyUpDown);

  game.reset();
  display.resize();

})();

먼저 이 게임은 20x20 형식이던데 저는 10x10으로 바꾸고 싶었습니다

그래서

    world:{

      columns:20,
      tile_size:10,
      map:new Array(400).fill(display.background_tile)

    },

이 부분의 columns를 10으로 바꾸면 될 줄 알았습니다 그런데 바꿔도 아무런 변화가 없습니다

10x10으로 바꾸려면 어디를 손 대야할지 모르겠습니다

그리고 어제 질문했던 방향키는 웹뷰앱 형식으로 만들어 휴대폰으로도 가능하게끔 하고싶어 넣고싶습니다

그래서 html에

<div style="text-align:center; width:480px;">
<button onmousedown=controller.up>▲</button><br>
<button onmousedown=controller.left>◀</button>
<button onmousedown=controller.down>▼</button>
<button onmousedown=controller.right>▶</button><br>
</div>

이렇게 넣었는데 표시는 돼도 작동은 안합니다

저는 이동키 함수가

switch(event.keyCode) {

        case 37: controller.left = key_state; break;
        case 38: controller.up = key_state; break;
        case 39: controller.right = key_state; break;
        case 40: controller.down = key_state; break;
      }

여기라 생각해서 저걸 넣었습니다

이미 방향키로는 움직이니 그 함수를 넣으면 작동할 줄 알았습니다

버튼으로 움직이게 하려면 어떻게 해야하는지 설명 가능할까요?

2 답변

  • 좋아요

    2

    싫어요
    채택 취소하기

    안녕하세요. 굉장히 재밌는 게임을 만들고 계시는 것 같네요. 질문하신 내용에 대해 답변을 드리자면,

        world:{
    
          columns:20,
          tile_size:10,
          map:new Array(400).fill(display.background_tile)
    
        },
    

    이 부분에서 columns를 바꾸는 것만으로 보이는 칸의 개수는 변하지 않습니다. 사실 world 객체에서 보여주는 것보다 훨씬 더 많은 일이 뒤에서 일어나고 있습니다. 먼저, world 위에 있는 이 부분을 살펴봐야 됩니다.

        snake: {
    
          head_index:209,
          old_head_index:undefined,
          segment_indices:[209, 210],
          vector_x:0,
          vector_y:0
    
        },
    

    이 부분은 뱀의 상태에 대한 정의를 구현한 곳입니다., 그러니까 딱 페이지를 들어갔을 때 뱀의 가장 처음 상태가 여기로 쓰여지게 됩니다. 보시면 head_index가 209라고 되어있고, segment_indices가 209와 210의 두 개의 숫자로 이루어진 배열로 정의되어 있습니다.

    이것이 의미하는 것은 두 가지인데요, 첫 번째는 뱀이 머리가 게임의 기본 타일 총 400칸(20칸 x 20칸) 중에서 209번째 칸에 있다는 것이고, 두 번째는 뱀이 위치한 칸이 209번째, 210번째 칸이라는 얘기입니다.

    그래서 원본 게임을 보시면 진짜로 209번째, 210번째 칸에 뱀(주황색)이 그려져 있고 게임을 시작하시면 209번째 칸의 머리를 따라서 뱀이 움직이게 됩니다.

    다시 world로 돌아가서,

        world:{
    
          columns:20,
          tile_size:10,
          map:new Array(400).fill(display.background_tile)
    
        },
    

    columns를 10으로 바꾸시고, map의 배열의 길이를 100(10칸 x 10칸)으로 하시면 됩니다.

    그리고 snake에서는,

        snake: {
    
          head_index:55,
          old_head_index:undefined,
          segment_indices:[55, 56],
          vector_x:0,
          vector_y:0
    
        },
    

    머리가 중앙에 위치해야 되니 head_index를 한 55정도?로 바꾸시고, segment_indices를 [55, 56]으로 하시면 되겠습니다

    그런데 이렇게 해도 뱀의 위치는 여전히 바뀌지 않습니다. 왜일까요? 사실 snake를 바꿔봤자 소스 코드가 snake 객체를 그냥 직접 사용하지를 않습니다. 그니까 쉽게 말하자면 snake 객체 정의는 뻥입니다. 대신 게임이 처음 로드될 때, 또는 뱀이 벽이나 자기 몸에 부딪혀서 죽었을 때 world 아래 쪽에 위치한 reset이라는 함수를 호출하게 됩니다. 바로 이 reset이라는 함수 안에서 게임의 모든 것이 초기화됩니다. 이 부분을 바꿔주면 되겠죠?

        reset:function() {
    
          this.score = 0;
    
          for (let index = this.snake.segment_indices.length - 1; index > -1; -- index) {
    
            this.world.map[this.snake.segment_indices[index]] = display.background_tile;
    
          }
    
          this.snake.segment_indices = [55, 56];
          this.snake.head_index = 55;
          this.snake.old_head_index = undefined;
          this.snake.vector_x = this.snake.vector_y = 0;
          this.world.map[game.apple.index] = display.apple;
          this.world.map[game.snake.segment_indices[0]] = display.segment;
          this.world.map[game.snake.segment_indices[1]] = display.segment;
    
          this.time_step = 250;
    
          this.loop();
          display.render();
    
        }
    

    중간에 보시면 this.snake.blablabla하고 난잡하게 써져있습니다. 이 부분이 바로 뱀 객체를 진짜로 초기화하는 곳이 되겠습니다. 따라서 아까 하셨던 대로 segment_indices를 [55, 56]으로 바꿔주시고 head_index를 55로 바꿔주시면 됩니다!

    죄송하지만 아직 '그런데'가 한번 더 남았습니다. 새로고침을 계속 해보시면 사과가 맵에 나타나지가 않는 경우가 있습니다. 왜 그럴까요? 왜냐하면 정말 복잡하게도 apple은 자기 자신의 위치를 맵에 기반하여 만들지 않고 그냥 지 스스로 만들어냅니다. snake 위에 위치한 apple을 보시면 알 수 있습니다.

        apple: {
    
          index:Math.floor(Math.random() * 400)
    
        },
    

    보시면, apple이 우리가 정의한 map의 사이즈에 기반해 위치를 만들지 않습니다. 우리는 0부터 99까지의 배열에 기반한 100칸의 맵에서 사과가 나오도록 해야되기 때문에 Math.random() * 400이 아니라 Math.random() * 99라고 바꿔주시면 되겠습니다.

    아니 근데 왜 100이 아니라 99일까요? 사실 100이라고 하면 0부터 100까지 총 101개의 수를 생성하기 때문입니다. 게임 중에 101이 나오면 사과를 먹을 수가 없겠죠?

    아니 근데 왜 1부터 100이 아니라 0부터 99일까요? 그것은 아까 우리가 봤던 reset 함수 안을 자세히 살펴보면 알 수 있습니다.

    this.world.map[game.apple.index] = display.apple;
    

    map은 배열입니다. 우리가 100칸을 정의했으면 index가 0부터 99까지인 것이 당연합니다. 배열이니까요. 사과에 위치를 배열에 index로써 바로 대입하므로 1부터 100이 아니라 0부터 99로 하는 것이 맞습니다.

    여기까지 잘 따라오셨다면 문제 없이 잘 될겁니다. 만약 문제가 생기면 바로 댓글을 남겨주시면 되겠습니다. 진짜로 진짜로 진짜로 편하게 물어보셔도 됩니다. 절대 부담 갖지 마시고 진짜로 편하게 물어보세요. 질문자님이 새벽에 비행기를 타고 수 천미터를 날아서 오라고 해도 가겠습니다. 감사합니다.

    수정

    <div style="text-align:center; width:480px;">
        <button onmousedown=controller.up>▲</button><br>
        <button onmousedown=controller.left>◀</button>
        <button onmousedown=controller.down>▼</button>
        <button onmousedown=controller.right>▶</button><br>
    </div>
    

    먼저 첫 번째로 질문자님께서 버튼을 구현하기 위해 이 div 태그를 삽입하셨습니다. 일단 button 태그 쪽을 살펴볼까요? onmousedown=controller.blabla 이렇게 되어있는데, 이것은 '마우스 버튼이 눌렸을 때' Javascript에서 controller.blabla라는 '함수'를 실행하게 만드는 것입니다.

    우리는 모바일에서 이 게임을 즐길 수 있게 해야하므로 마우스가 아니라 터치를 구현해야겠죠? 따라서 onmousedown 대신에 ontouchstart를 쓰시면 되겠습니다. (참고로 onclick으로 구현하시면 마우스 터치 상관 없이 공통적으로 작동하게 할 수 있습니다.) 그리고 HTML의 요소들이 가진 속성은 항상 string 형태로 기재해주셔야 됩니다. 따라서 고쳐보면,

    <div style="text-align:center; width:480px;">
        <button ontouchstart="controller.up">▲</button><br>
        <button ontouchstart="controller.left">◀</button>
        <button ontouchstart="controller.down">▼</button>
        <button ontouchstart="controller.right">▶</button><br>
    </div>
    

    이렇게 하시면 되겠습니다.

    물론 아직 작동하지 않습니다. 왜일까요? 왜냐하면 controller.blabla는 함수가 아니기 때문입니다. 자바스크립트 파일 가장 위에 있는 controller를 보면 알 수 있습니다.

      controller = {
    
        down:false, left:false, right:false, up:false,
    
        keyUpDown:function(event) {
    
          var key_state = (event.type == "keydown")?true:false;
    
          switch(event.keyCode) {
    
            case 37: controller.left = key_state; break;
            case 38: controller.up = key_state; break;
            case 39: controller.right = key_state; break;
            case 40: controller.down = key_state; break;
          }
        }
      };
    

    이 부분이 의미하는 것은 아주 간단합니다. 일단 controller 내부의 down, left, right, up은 현재 뱀이 어디로 이동할 지 나타내는 역할입니다. 그리고 keyUpDown이라는 함수가 있는데요, 이 함수가 호출되면 이 함수를 호출한 이벤트가 keydown(키를 누름)인 지 아닌 지 key_state라는 변수에 저장합니다. 그리고 switch 문을 통해 이벤트의 keyCode, 그러니까 키보드 키마다 번호가 정해져 있는데 그 번호가 keyCode입니다. keyCode에 따라서 controller의 left 또는 up 또는 right 또는 down을 key_state의 값으로 정해줍니다.

    근데 keydown인 지 왜 체크하고, 또 왜 이렇게 복잡하게 구현했을까요? 그것은 가장 밑을 확인해보면 파악해볼 수 있습니다.

      window.addEventListener("resize", display.resize);
      window.addEventListener("keydown", controller.keyUpDown);
      window.addEventListener("keyup", controller.keyUpDown);
    

    이 세 줄의 코드는 window, 그러니까 브라우저의 창한테 이벤트가 발생 시 실행할 내용을 정해주는 부분입니다. 두 번째 줄부터 보시면 keydown과 keyup이 발생했을 때 둘다 controller.keyUpDown를 호출하는 것을 보실 수 있습니다.

    그러니까 예시로 왼쪽 방향키을 눌렀을 때의 흐름을 읽어보자면

    1. 왼쪽 방향키가 눌린다.
    2. keydown 이벤트가 발생하고 controller.keyUpDown이 호출된다.
    3. 이벤트가 keydown이므로 key_state는 true가 된다.
    4. keyCode가 37(왼쪽 방향키의 번호)이므로 controller.left는 key_state 즉 true가 된다.
    5. (뒤에서 돌아가는 코드가 이 controller.left를 참고하여 뱀을 왼쪽으로 움직인다.)
    6. 왼쪽 방향키가 떼진다. (키를 누르는 것은 눌리고 떼지는 것이므로)
    7. keyup 이벤트가 발생하고 controller.keyUpDown이 호출된다.
    8. 이번엔 이벤트가 keydown이 아니므로 key_state는 false가 된다.
    9. keyCode가 37이므로 controller.left는 key_state 즉 false가 된다.

    가 되겠습니다. 굳이 keydown과 keyup의 경우를 분리하는 이유는, controller의 down, left, right, up이 초기화되지 않고 계속 값이 지속되는 것을 방지하기 위해서입니다. keydown 시에 설정된 값을 뒤에 코드에서 사용한 다음에는, 다시 원상태로 돌려놓아야겠죠? 그렇지 않으면 왼쪽 방향키를 눌렀다고 했을 때, 초기화가 되지 않아 계속 controller.left이 true로 유지되고, 그 후 위쪽 방향키를 누렀을 때 controller.left가 true로 변하긴 하지만 사실 뒤에서 돌아가는 코드는 down -> left -> right -> up의 순서로 확인하기 때문에 left가 true인 이상 right와 up에는 접근할 수 없게 됩니다. reset 함수 밑에 있는 loop 함수에서 확인하실 수 있습니다.

        loop:function(time_stamp) {
    
          /* Get controller input. Make sure that the vector on the opposite axis is
          set to 0 so the snake doesn't move on a diagonal. */
          if (controller.down) {
    
            game.snake.vector_x = 0;
            game.snake.vector_y = 1;
    
          } else if (controller.left) {
    
            game.snake.vector_x = -1;
            game.snake.vector_y = 0;
    
          } else if (controller.right) {
    
            game.snake.vector_x = 1;
            game.snake.vector_y = 0;
    
          } else if (controller.up) {
    
            game.snake.vector_x = 0;
            game.snake.vector_y = -1;
    
          }
    

    위의 내용을 종합해보았을 때, 최종적으로 모바일을 위한 구현을 하기 위해서는,

    1. button 태그의 onmousedown을 ontouchstart로 바꿔준다.
    2. button 태그에서 이벤트 발생 시 호출할 함수를 바꿔준다.
    3. controller의 keyUpDown에서 key_state 확인을 keyDown이 아니라 touchstart로 한다.
    4. 키보드 키를 사용하지 않을 것이므로 window에 keydown과 keyup 이벤트 리스너를 등록하지 않는다.
    <div style="text-align:center; width:480px;">
        <button ontouchstart='controller.keyUpDown'>▲</button><br>
        <button ontouchstart='controller.keyUpDown'>◀</button>
        <button ontouchstart='controller.keyUpDown'>▼</button>
        <button ontouchstart='controller.keyUpDown'>▶</button><br>
    </div>
    
      controller = {
    
        down:false, left:false, right:false, up:false,
    
        keyUpDown:function(event) {
    
          var key_state = (event.type == "touchstart")?true:false;
    
          switch(event.keyCode) {
    
            case 37: controller.left = key_state; break;
            case 38: controller.up = key_state; break;
            case 39: controller.right = key_state; break;
            case 40: controller.down = key_state; break;
          }
        }
      };
    
     window.addEventListener("resize", display.resize);
     - window.addEventListener("keydown", controller.keyUpDown);
     - window.addEventListener("keyup", controller.keyUpDown);
    
     -가 붙은 줄은 삭제해주세요.
    
    

    이 외에도 보지 않은 코드는 많습니다. 하나씩 연구해보시고 직접 뱀 게임보다 훌륭한 것을 만드시는 분이 되길 응원합니다. 모르는 것이 있으면 진짜 편하게 질문하셔도 됩니다. 또, 구글에 모르는 것을 찾아보는 것도 좋으니 한 번 해보시기를 바랍니다.

    • (•́ ✖ •̀)
      알 수 없는 사용자
    • 정말 감사합니다. 덕분에 정말 많은 부분을 이해할 수 있었고 제가 원하는대로 코드를 만질 수 있었습니다. 혹시 방향키 부분도 봐주실 수 있나요? 모바일로도 할 수 있게끔 하고싶다보니 계속 코드를 바꿔보고 하고있는데 잘 안 됩니다. 다르게 바꾼 방향키 부분을 답변으로 올려놓겠습니다. 안 된다 하더라도 정말 감사합니다. 햇치킨 2020.5.16 12:58
    • 감사합니다. 대부분 이해를 완료했습니다. 제가 어떤걸 몰랐는지도 이 글을 통해 많이 배웠습니다. 그런데 html에서 ontouchstart가 정의되어있지 않다고 노란줄이 뜹니다. 그래서 그런지 터치를 해도 아무런 반응이 없구요. 혹시 제가 새로 정의를 해줘야하는건가요? onmousedown처럼 원래 있는게 아닌가요? 햇치킨 2020.5.16 19:29
    • 한번에 이해를 못해서 죄송합니다... 햇치킨 2020.5.16 19:29
    • 아니요 ㅠㅠ 제가 실수했네요 버튼 태그의 ontouchstart 뒤에 오는 따옴표를 쌍따옴표(")로 바꿔서 해결이 되나요?? 알 수 없는 사용자 2020.5.16 22:12
    • 답변이 늦어 죄송합니다. 쌍따옴표로 바꿔도 ontouchstart가 정의되어 있지 않다고 노란줄이 뜹니다. 햇치킨 2020.5.17 19:43
    • 혹시 ontouchstart를 html에서 정의하지 않고 css나 자바스크립트에서 정의하셨나요? ontouchstart는 html 요소의 속성이기 때문에 style 안에 넣거나 css에서 정의하면 동작하지 않습니다. 자바스크립트를 통해 이벤트를 등록하시려면 ontouchstart가 아니라 touchstart를 쓰셔야 됩니다. 알 수 없는 사용자 2020.5.18 09:51
  • 방향키 부분을 다시 코드를 고쳐봤습니다

    이렇게 해도 안 되는건 마찬가지였습니다

    혹시 방법이 없을까요?

    reset:function() {
    
          this.score = 0;
    
          for (let index = this.snake.segment_indices.length - 1; index > -1; -- index) {
    
            this.world.map[this.snake.segment_indices[index]] = display.background_tile;
    
          }
    
          this.snake.segment_indices = [55, 56];
          this.snake.head_index = 55;
          this.snake.old_head_index = undefined;
          this.snake.vector_x = this.snake.vector_y = 0;
          this.world.map[game.apple.index] = display.apple;
          this.world.map[game.snake.segment_indices[0]] = display.segment;
          this.world.map[game.snake.segment_indices[1]] = display.segment;
    
          this.time_step = 250;
    
          this.move();
          this.loop();
          display.render();
    
        },
    
        move:function move(dir) {
            if(dir == "up") {
                game.snake.vector_x = 0;
                game.snake.vector_y = -1;
            } else if(dir == "down") {
                game.snake.vector_x = 0;
                game.snake.vector_y = 1;
            } else if(dir == "left") {
                game.snake.vector_x = -1;
                game.snake.vector_y = 0;
            } else if(dir == "right") {
                game.snake.vector_x = 1;
                game.snake.vector_y = 0;
            }
        },
    
        loop:function(time_stamp) {
    
          if (controller.down) {
              move("down");
          } else if (controller.left) {
              move("left");
          } else if (controller.right) {
              move("right");
          } else if (controller.up) {
              move("up");
          }
    
    
    <div style="text-align:center; width:390px;">
    <button onmousedown="moveup()">▲</button><br>
    <button onmousedown="moveleft()">◀</button>
    <button onmousedown="movedown()">▼</button>
    <button onmousedown="moveright()">▶</button><br>
    </div>
    
    

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)