네이티브 JavaScript를 사용하여 간단한 퍼즐 게임을 구현하는 방법

不言
풀어 주다: 2018-11-16 16:39:50
앞으로
2892명이 탐색했습니다.

이 기사의 내용은 간단한 퍼즐 게임을 구현하기 위해 기본 JavaScript를 사용하는 방법에 대한 것입니다. 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.

1. 게임의 기본 로직

언어를 사용하여 게임을 개발하려면 먼저 이 언어를 사용하여 이미지 그리기, 상호 작용 처리, 타이머, 등.

1. 그래픽 그리기

그래픽 그리기는 모든 것의 기본입니다. 여기서는 JavaScript를 사용하여 캔버스에 그립니다. 즉, 먼저 html에서 canvas 요소를 생성한 다음 JavaScript에서 이 요소를 ID로 가져오고 canvas code> 후속 그리기를 준비하기 위해 해당 컨텍스트 환경 <code>context를 가져옵니다. JavaScript 在 canvas 上进行绘制。即先在 html 中创建 canvas 元素,然后在 JavaScript 中,通过 id 拿到这个元素,并且通过 canvas 拿到对应的上下文环境 context ,为后续的绘图做好准备。

<canvas id="background" width="450px" height="450px"></canvas>
로그인 후 복사
var background = document.getElementById("background");
var context = background.getContext('2d');
로그인 후 복사

通过 context 的 drawImage 方法可以绘制图片,这里进行了相应的封装:

注:这里要等图片加载完毕后再进行绘制,即在 onload 中去调用 drawImage 方法,否则会绘制失败。

var drawImageItem = function(index, position) {
    var img = new Image();
    img.src = './image/dog_0' + String(index+1) + '.jpg';
    img.onload = () => {
        var rect = rectForPosition(position);
        context.drawImage(img, rect[0], rect[1], rect[2], rect[3]);
    }
}
로그인 후 복사

在绘制图片之后,我们还需要去动态刷新视图,否则 canvas 就只是一张静态的图片。如果是简单的图形刷新,只需在原来的位置重新绘制,进行覆盖即可。但有时候我们只需要将原来已存在的图形清除掉,而不需要绘制新图案。比如在拼图游戏中,将一个方块移动到另一个位置后,需要清空原来的位置。

通过 context 的 clearRect 方法可以达到清除的目的。以下是清除 canvas 的某个区域的代码:

var originRect = rectForPosition(origin);
context.clearRect(originRect[0], originRect[1], originRect[2], originRect[3]);
로그인 후 복사

2、事件处理

有了图形的绘制后,我们还需要处理玩家的输入事件,然后根据输入事件,来决定什么时候刷新视图。输入事件可以分为 3 种:在手机上有触屏事件;在 PC 上,有鼠标和键盘事件。

JavaScript 中对触屏和鼠标点击的监听是一样的,都是通过 canvas 的 onclick 事件进行回调,具体如下:

// 屏幕点击
background.onclick = function(e) {
};
로그인 후 복사

我们可以通过 e.offsetX 、 e.offsetY 来获取触控点在 canvas 中的位置。

注: canvas 的坐标原点在左上角,即左上角的坐标是 (0, 0) 。

键盘的按键点击则是通过 document 的 onkeyup 、 onkeydown 等事件进行回调。 onkeyup 是指按键的抬起事件, onkeydown 是指按键的按下事件。我们可以通过 keyCode 知道当前具体是哪一个按键,然后根据不同的按键去处理不同的逻辑,如下:

if (event.keyCode == '37') {  // 左
    // do something
} else if (event.keyCode == '38') { // 上
    // do something
} else if (event.keyCode == '39') { // 右
    // do something
} else if (event.keyCode == '40') { // 下
    // do something
}
로그인 후 복사

3、定时器

有时候,除了在玩家输入的时候需要去刷新视图,还需要每隔一段时间定时去刷新视图。比如在一个贪吃蛇游戏中,就需要每隔一段时间就去刷新蛇的位置。

这个时候我们就需要一个定时器,让它每隔一段时间去执行一段刷新视图的代码。我们通过 setInterval 方法来实现定时器功能:

setInterval("run()", 100);
로그인 후 복사

上面这段代码表示每隔 100 毫秒,去执行一次 run 方法。

二、拼图的基础逻辑

有了游戏的基础逻辑,下面来看一下如何实现拼图的逻辑。

1、生成随机序列

因为不是任意序列都可以通过平移的方式来还原,所以我们不能简单地生成一个随机序列。比如 1、0、2、3、4、5、6、7、8 这个序列,无论怎么平移,都不可能还原。

这里采取的做法是:预先设置了 4 个可还原的序列,先从这 4 个序列中随机选取一个,然后再对序列进行模拟平移若干步骤。以此来尽可能地保证初始序列的多样性,也保证了序列的可还原性。具体代码如下:

var setupRandomPosition = function() {
    var list1 = [4, 3, 2, 8, 0, 7, 5, 6, 1];
    var list2 = [2, 0, 5, 6, 8, 7, 3, 1, 4];
    var list3 = [3, 7, 2, 4, 1, 6, 8, 0, 5];
    var list4 = [3, 2, 4, 1, 7, 6, 5, 0, 8];
    var lists = [list1, list2, list3, list4];

    imageIndexForPosition = lists[parseInt(Math.random() * 4)];

    // 获取空位位置
    var emptyPosition = 0;
    for (var i = imageIndexForPosition.length - 1; i >= 0; i--) {
        if (imageIndexForPosition[i] == lastIndex()) {
            emptyPosition = i;
            break;
        }
    }
    background.emptyPosition = emptyPosition;

    // 随机移动次数
    var times = 10;
    while (times--) {
        // 获取随机数,决定空位哪个位置进行移动
        var direction = parseInt(Math.random() * 4);

        var target = -1;
        if (direction == 0) {
            target = topOfPosition(emptyPosition);  // 上
        } else if (direction == 1) {
            target = leftOfPosition(emptyPosition);  // 左 
        } else if (direction == 2) {
            target = rightOfPosition(emptyPosition);  // 右
        } else if (direction == 3) {
            target = bottomOfPosition(emptyPosition);  // 下
        }
        if (target < 0 || target > lastIndex()) {  // 位置不合法,继续下一次循环
            continue;
        }
        var result = moveImageIfCanAtPosition(target);
        if (result >= 0) { // 如果移动成功,更新空位的位置
            emptyPosition = target;
        }
    }
}
로그인 후 복사

2、判断是否可以移动方块

在保存顺序的时候,是用 0~8 这 9 个数字来保存,而空白的方块是数字 8 的位置。所以判断可以移动的唯一条件是,目标位置的值是否为 8。代码如下:

var isPositionEmpty = function(position) {
    if (position < 0 || position > lastIndex()) {
        return false;
    } 
    if (imageIndexForPosition[position] == lastIndex()) {
        return true;
    } else {
        return false;
    }
}
로그인 후 복사

上面 lastIndex()

var refreshImagePositions = function(origin, target) {
    var originRect = rectForPosition(origin);
    context.clearRect(originRect[0], originRect[1], originRect[2], originRect[3]);
    drawImageItem(imageIndexForPosition[target], target);
}
로그인 후 복사
var checkIfFinish = function() {
    for (var index = 0; index < imageIndexForPosition.length; index++) {
        if (index != imageIndexForPosition[index]) {
            return false;
        }
    }
    return true;
}
로그인 후 복사
로그인 후 복사
contextdrawImage 메서드를 통해 그림을 그릴 수 있습니다. 해당 캡슐화는 여기에서 수행됩니다.

참고:

그림이 나타날 때까지 기다려야 합니다. 즉, onload에서 drawImage 메서드를 호출하세요. 그렇지 않으면 그리기가 실패합니다.

// 屏幕点击
background.onclick = function(e) {
    if (isFinish) {
        return;
    }

    // do something
};

// 键盘按钮事件
document.onkeyup = function(event) {
    if (isFinish) {
        return;
    }

    // do something
}
로그인 후 복사
로그인 후 복사

그림을 그린 후에는 뷰를 동적으로 새로 고쳐야 합니다. 그렇지 않으면 캔버스는 정적 그림일 뿐입니다. 단순한 그래픽 새로고침이라면 원래 위치에 다시 그려서 덮어쓰면 됩니다. 하지만 때로는 새로운 그래픽을 그리지 않고 기존 그래픽을 지워야 하는 경우도 있습니다. 예를 들어 직소 퍼즐의 경우 블록을 다른 위치로 이동한 후 원래 위치를 지워야 합니다.

삭제 목적은 contextclearRect 메서드를 통해 달성할 수 있습니다. 다음은 ​​캔버스의 특정 영역을 지우는 코드입니다: 🎜rrreee🎜2.이벤트 처리🎜🎜그래픽을 그린 후 플레이어의 입력 이벤트도 처리한 다음 이를 기반으로 결정해야 합니다. 입력 이벤트에서 보기를 새로 고칠 시기입니다. 입력 이벤트는 휴대폰의 터치스크린 이벤트, PC의 마우스 및 키보드 이벤트의 세 가지 유형으로 나눌 수 있습니다. 🎜🎜JavaScript는 터치 스크린과 마우스 클릭을 동일한 방식으로 모니터링하며, 둘 다 다음과 같이 canvasonclick 이벤트를 통해 호출됩니다. 🎜 rrreee🎜e.offsetXe.offsetY를 사용하여 캔버스에서 터치 포인트의 위치를 ​​가져올 수 있습니다. 🎜🎜참고: 캔버스의 좌표 원점은 왼쪽 상단에 있습니다. 즉, 왼쪽 상단의 좌표는 (0, 0)입니다. 🎜🎜키보드 키 클릭은 documentonkeyuponkeydown과 같은 이벤트를 통해 다시 호출됩니다. onkeyup은 키 리프트 이벤트를 나타내고, onkeydown은 키 누름 이벤트를 나타냅니다. keyCode를 사용하여 현재 어떤 키가 눌러져 있는지 알 수 있으며 다음과 같이 다른 키에 따라 다른 논리를 처리할 수 있습니다. 🎜rrreee🎜3. Timer🎜🎜때때로 플레이어가 입력할 때를 제외하고 새로 고쳐지려면 뷰를 주기적으로 새로 고쳐야 합니다. 예를 들어, 뱀 게임에서는 뱀의 위치를 ​​가끔씩 새로 고쳐야 합니다. 🎜🎜이때 가끔씩 뷰를 새로 고치는 코드를 실행하는 타이머가 필요합니다. setInterval 메소드를 통해 타이머 기능을 구현합니다. 🎜rrreee🎜위 코드는 run 메소드가 100밀리초마다 실행된다는 의미입니다. 🎜

2. 퍼즐의 기본 논리

🎜게임의 기본 논리와 함께 퍼즐의 논리를 어떻게 구현하는지 살펴보겠습니다. 🎜🎜1. 무작위 시퀀스 생성🎜🎜 어떤 시퀀스도 번역으로 복원할 수 없기 때문에 단순히 무작위 시퀀스를 생성할 수는 없습니다. 예를 들어 1, 0, 2, 3, 4, 5, 6, 7, 8 시퀀스는 어떻게 번역하더라도 복원할 수 없습니다. 🎜🎜여기에서 취한 접근 방식은 4개의 축소 가능 시퀀스를 미리 설정하고, 먼저 이 4개의 시퀀스 중 하나를 무작위로 선택한 다음 해당 시퀀스에서 여러 단계의 번역을 시뮬레이션하는 것입니다. 이런 방식으로 초기 서열의 다양성이 최대한 보장되고, 서열의 환원성도 보장됩니다. 구체적인 코드는 다음과 같습니다. 🎜rrreee🎜2. 사각형을 이동할 수 있는지 여부를 결정합니다🎜🎜순서를 저장할 때 0부터 8까지 9개의 숫자를 사용하여 저장하며, 빈 사각형은 숫자 8의 위치입니다. 따라서 이동 가능 여부를 판단하는 유일한 조건은 목표 위치의 값이 8인지 여부입니다. 코드는 다음과 같습니다. 🎜rrreee🎜위의 lastIndex() 값은 8입니다. 🎜🎜3. 블록 이동 실현🎜🎜블록 이동 구현은 매우 간단합니다. 먼저 이전 위치에서 그래픽을 지우고 새 위치에 그립니다. 🎜rrreee🎜4. 완료되었는지 확인🎜🎜패턴이 복원되었는지 확인하려면 배열을 한 번만 순회하여 순서대로 확인하면 됩니다. 🎜
var checkIfFinish = function() {
    for (var index = 0; index < imageIndexForPosition.length; index++) {
        if (index != imageIndexForPosition[index]) {
            return false;
        }
    }
    return true;
}
로그인 후 복사
로그인 후 복사

5、交互事件屏蔽

当图案还原之后,我们不希望玩家还能通过键盘或鼠标来移动方块,这个时候就需要对交互事件进行屏蔽。

只需要一个标志位就可以达到这个目的:

// 屏幕点击
background.onclick = function(e) {
    if (isFinish) {
        return;
    }

    // do something
};

// 键盘按钮事件
document.onkeyup = function(event) {
    if (isFinish) {
        return;
    }

    // do something
}
로그인 후 복사
로그인 후 복사

当图案还原之后,标志位 isFinish 会被置为 true ,然后在屏幕点击和键盘按钮响应事件的开始处添加判断,如果已经结束,则不继续走方块移动的逻辑。

위 내용은 네이티브 JavaScript를 사용하여 간단한 퍼즐 게임을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:segmentfault.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿