슬라이딩 퍼즐 게임 만들기 #2/4 (타일 이동)
천둥상어
·2023. 12. 25. 10:56
비어 있는 타일 표시
마지막 타일은 비어 있는 타일이므로 모습을 보이지 않도록 처리 합니다.
tile.js의 Tile 클래스에 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.js의 InteractionManager를 사용합니다.
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문으로 모든 타일을 재배치 하고 있지만 사실 교체되는 두 타일의 위치만 변경해도 됩니다.
이런 부분은 기능 구현을 우선적으로 하고 나중에 리팩토링을 하면서 개선하도록 합니다.
'프로그래밍 > JavaScript 게임 개발' 카테고리의 다른 글
슬라이딩 퍼즐 게임 만들기 #4/4 (완성 및 리팩토링) (0) | 2024.01.12 |
---|---|
슬라이딩 퍼즐 게임 만들기 #3/4 (타일 섞기) (3) | 2024.01.05 |
슬라이딩 퍼즐 게임 만들기 #1/4 (타일 배치) (0) | 2023.12.15 |
자바스크립트로 게임 만들기 (1) | 2023.12.09 |