슬라이딩 퍼즐 게임 만들기 #2/4 (타일 이동)

천둥상어

·

2023. 12. 25. 10:56

반응형

슬라이딩퍼즐_썸네일

비어 있는 타일 표시

마지막 타일은 비어 있는 타일이므로 모습을 보이지 않도록 처리 합니다.

tile.jsTile 클래스setVisible() 함수를 추가 합니다.

해당 함수가 호출되면 타일의 숫자와, 사각형 그래픽을 감추도록 합니다.

  //tile.js
  setVisible(bVisible)
  {
    this.numberTxt.visible = bVisible;
    this.rect.visible = bVisible;
  }

init() 함수의 this.emptyIndex값을 할당하는 코드 아래에서 setVisible() 함수를 호출합니다.

    // 생략
    
    // 비어 있는 타일
    this.emptyIndex = this.TOTAL_CELL - 1;
    this["tile_" + this.emptyIndex].setVisible(false);
    
    // 생략

적용 결과

클릭 이벤트 만들기

이제 각 타일에 클릭 이벤트를 적용 합니다.

이벤트는 Pixi.jsInteractionManager를 사용합니다.

 

init() 함수에 아래와 같이 추가 합니다.

  • tile.eventMode = "static";  : 대상은 움직이지 않는 정적인 객체
  • tile.cursor = "pointer"; : 마우스 포인터 변경
  • tile.on("click", this.hnClick, this); : 클릭 이벤트 적용, 클릭시 hnClick 함수 호출, 스코프
      // 위 생략
      tile.setText(String(i));
      
      // 마우스 인터렉션 추가
      tile.eventMode = "static";
      tile.cursor = "pointer";
      tile.on("click", this.hnClick, this);

      tile.position.set(posX, posY);
      posX += 100;
      // 아래 생략

 

hnClick() 함수

hnClick 함수는 클릭시 호출되는 함수 입니다.

클릭시 해당 타일의 currentIndex 값이 호출된다면 잘 적용된 것입니다.

hnClick 함수에서는 해당 타일이 빈공간으로 움직일 수 있는지 비교, 판단을 하게 됩니다.

현재 타일의 위치(currentIndex) 와 비어있는 타일 위치 (emptyIndex)를 비교하여 판단하게 될 것입니다.

코드의 간결성을 위해 타일의 currentIndex 와 전역 변수인 emptyIndex를 지역 변수에 대입해 사용합니다.

  hnClick(evt)
  { 
    const tile = evt.currentTarget;
    const currentIndex = tile.currentIndex;
    const emptyIndex = this.emptyIndex;

    console.log(currentIndex);
    console.log(emptyIndex);
  }

조건문 구현

타일은 상, 하, 좌, 우의 방향성 있으며, 해당 방향 공간이 비어 있어야 이동이 가능합니다.

상, 하의 경우

상,하의 경우는 타일의 위치(currentIndex)에서 열(this.column)값을 더하거나 뺀 값이 비어있는 타일 위치(emptyIndex)라면 이동할 수 있습니다.

if(currentIndex - this.column === emptyIndex) console.log("위로 이동 가능");
if(currentIndex + this.column === emptyIndex) console.log("아래로 이동 가능");

 

좌, 우의 경우

좌,우의 경우는 자신의 위치(currentIndex)에서 1 증가하거나 1 감소한 값이 비어있는 타일 위치(emptyIndex)라면 이동이 가능합니다. 

여기서 선행 조건이 하나 더 있는데 같은 행(같은 줄)에서만 적용되어야 한다는 것입니다. 좌우 이동은 같은 줄에서만 가능하기 때문입니다.

타일의 행값은 타의 위치값(currentIndex)에서 행(this.row)값을 나눈 몫의 소수점 절사값이 됩니다.

아래 코드의 출력을 보면 알 수 있습니다.

console.log(0/4); //0
console.log(1/4); //0.25
console.log(2/4); //0.5
console.log(3/4); //0.75

console.log(4/4); //1
console.log(5/4); //1.25
console.log(6/4); //1.5
console.log(7/4); //1.75

console.log(8/4); //2
console.log(9/4); //2.25
console.log(10/4); //2.5
console.log(11/4); //2.75

console.log(12/4); //3
console.log(13/4); //3.25
console.log(14/4); //3.5
console.log(15/4); //3.75

모든 조건을 정리하면 코드는 다음과 같습니다.

    if(Math.trunc(currentIndex / this.row) === Math.trunc(emptyIndex / this.row))
    {
      console.log("같은 줄에 있음");
      if(currentIndex + 1 === emptyIndex) console.log("오른쪽 이동 가능");
      if(currentIndex - 1 === emptyIndex) console.log("왼쪽 이동 가능");
    }

전체 코드

조건문을 정리한 전체 코드는 아래와 같습니다.

11번 타일을 클릭하면 "아래로 이동 가능"이 출력되고 14번 타일을 클릭하면 "오른쪽 이동 가능"이 출력 됩니다.

  hnClick(evt)
  { 
    const tile = evt.currentTarget;
    const currentIndex = tile.currentIndex;
    const emptyIndex = this.emptyIndex;

    if(currentIndex + this.column === emptyIndex)
    {
      console.log("아래로 이동 가능");
    } 
    else if(currentIndex - this.column === emptyIndex)
    {
      console.log("위로 이동 가능");
    }
    else if(Math.trunc(currentIndex / this.row) === Math.trunc(emptyIndex / this.row))
    {
      console.log("같은 줄에 있음");
      if(currentIndex + 1 === emptyIndex)
      {
        console.log("오른쪽 이동 가능");
      }
      else if(currentIndex - 1 === emptyIndex)
      {
        console.log("왼쪽 이동 가능");
      } 
    }
  }
}

 

타일을 교체하는 moveTile() 함수 정의

이제 클릭시 타일의 위치를 교체하는  moveTile() 함수를 작성합니다.

hnClick() 함수에서 이동이 가능한 경우 currentIndex 와 emptyIndex를 인자로 전달하고 moveTile에서 해당 인자들로 로직을 구현합니다.

 

moveTile() 함수 정의

main.js의 Main 클래스에 정의 합니다.

 moveTile(currentIndex, emptyIndex)
  {
  	//
  }

 

hnClick() 함수에 moveTile() 함수 호출 추가

이동이 가능한 경우 moveTile() 함수를 호출합니다

currentIndex와 emptyIndex를 인자값으로 전달 합니다.

// 생략

   if(currentIndex + this.column === emptyIndex)
    {
      console.log("아래로 이동 가능");
      this.moveTile(currentIndex, emptyIndex);
    } 
    else if(currentIndex - this.column === emptyIndex)
    {
      console.log("위로 이동 가능");
      this.moveTile(currentIndex, emptyIndex);
    }
    else if(Math.trunc(currentIndex / this.row) === Math.trunc(emptyIndex / this.row))
    {
      console.log("같은 줄에 있음");
      if(currentIndex + 1 === emptyIndex)
      {
        console.log("오른쪽 이동 가능");
        this.moveTile(currentIndex, emptyIndex);
      }
      else if(currentIndex - 1 === emptyIndex)
      {
        console.log("왼쪽 이동 가능");
        this.moveTile(currentIndex, emptyIndex);
      } 
    }

//생략

moveTile() 함수 로직 구현

moveTile() 함수 기능은 클릭한 타일과 비어 있는 타일을 교체하는 것입니다.

다음과 같이 진행 됩니다.

  • 교체되는 타일의 currentIndex값 변경
  • 전역 변수 this.emptyIndex값 변경
  • 타일을 담고 있는 배열 this.tileArr 의 요소 변경
  • 갱신된 this.tileArr의 순서대로 타일 재배치
  moveTile(currentIndex, emptyIndex)
  {
    // 클릭한 타일이 비어 있는 타일 위치로 이동하고
    // 비어 있는 타일은 클릭한 타일 위치로 이동해야 된다.
    // 그러므로 둘의 currentIndex값이 교환되어야 한다.
    this.tileArr[currentIndex].currentIndex = emptyIndex;
    this.tileArr[emptyIndex].currentIndex = currentIndex;

    // currentIndex값을 교환했으면 배열에서의 위치도 서로 바꿔준다.
    const temp = this.tileArr[currentIndex];
    this.tileArr[currentIndex] = this.tileArr[emptyIndex];
    this.tileArr[emptyIndex] = temp;

    // 비어 있는 타일 인덱스를 갱신한다
    this.emptyIndex = currentIndex;

    // 변경된 배열순으로 타일을 재배치 한다.
    let posX = 0; //타일 x값
    let posY = 0; //타일 y값

    for (let i = 0; i < this.TOTAL_CELL; i++) {
      const tile = this.tileArr[i];
      tile.position.set(posX, posY);
      posX += 100;

      if ((i + 1) % this.row == 0) {
        posX = 0;
        posY += 100;
      }
    }
  }

실행 결과

여기까지 코드를 적용하고 실행하면 타일 클릭시 타일 위치가 교체되는 것을 확인할 수 있습니다.

참고로 동작은 동일해도 로직은 다양하게 작성할 수 있습니다.

이동 조건도 더 간결할 수 있고,  타일의 위치 변경도 더 효율적으로 구현이 가능할 것입니다.

지금은 for문으로 모든 타일을 재배치 하고 있지만 사실 교체되는 두 타일의 위치만 변경해도 됩니다.

이런 부분은 기능 구현을 우선적으로 하고 나중에 리팩토링을 하면서 개선하도록 합니다.

실행 결과

반응형