利用原生的JavaScript实现简单拼图游戏


Posted in Javascript onNovember 18, 2018

前言

本篇主要讲解,如何利用原生的 JavaScript

来实现一个简单的拼图小游戏。

利用原生的JavaScript实现简单拼图游戏

一、游戏的基础逻辑

想用一门语言来开发游戏,必须先了解如何使用这门语言来实现一些基础逻辑,比如图像的绘制、交互的处理、定时器等。

1、图形绘制

图形绘制是一切的基础,这里使用 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() 的值为 8。

3、实现方块移动

方块移动的实现很简单,先将旧位置的图形清除,然后在新的位置绘制。

var refreshImagePositions = function(origin, target) {
var originRect = rectForPosition(origin);
context.clearRect(originRect[0], originRect[1], originRect[2], originRect[3]);
drawImageItem(imageIndexForPosition[target], target);
}

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 相关文章推荐
jQuery 名称冲突的解决方法
Apr 08 Javascript
javascript自适应宽度的瀑布流实现思路
Feb 20 Javascript
关闭浏览器时提示onbeforeunload事件
Dec 25 Javascript
javascript实现验证IP地址等相关信息代码
May 10 Javascript
JavaScript提升性能的常用技巧总结【经典】
Jun 20 Javascript
Vue与Node.js通过socket.io通信的示例代码
Jul 25 Javascript
PostgreSQL Node.js实现函数计算方法示例
Feb 12 Javascript
微信二次分享报错invalid signature问题及解决方法
Apr 01 Javascript
通过js给网页加上水印背景实例
Jun 17 Javascript
什么时候不能在 Node.js 中使用 Lock Files
Jun 24 Javascript
vue如何实现自定义底部菜单栏
Jul 01 Javascript
原生Js 实现的简单无缝滚动轮播图的示例代码
May 10 Javascript
Javascript实现动态时钟效果
Nov 17 #Javascript
使用Javascript简单计算器
Nov 17 #Javascript
JS实现图片切换效果
Nov 17 #Javascript
js实现导航跟随效果
Nov 17 #Javascript
JavaScript实现新年倒计时效果
Nov 17 #Javascript
JS实现倒计时图文效果
Nov 17 #Javascript
javaScript实现游戏倒计时功能
Nov 17 #Javascript
You might like
PHP.MVC的模板标签系统(五)
2006/09/05 PHP
Discuz! Passport 通行证整合
2008/03/27 PHP
PHP里的中文变量说明
2011/07/23 PHP
$_GET['goods_id']+0 的使用详解
2013/06/06 PHP
php打包压缩文件之ZipArchive方法用法分析
2016/04/30 PHP
php简单解析mysqli查询结果的方法(2种方法)
2016/06/29 PHP
php魔术方法功能与用法实例分析
2016/10/19 PHP
javascript 复杂的嵌套环境中输出单引号和双引号
2009/05/26 Javascript
js实现的跟随鼠标移动的时钟效果(中英文日期显示)
2011/01/17 Javascript
jqGrid jQuery 表格插件测试代码
2011/08/23 Javascript
当鼠标移动时出现特效的JQuery代码
2013/11/08 Javascript
给事件响应函数传参数的四种方式小结
2013/12/05 Javascript
JavaScript中Number.MIN_VALUE属性的使用示例
2015/06/04 Javascript
JavaScript中的原型prototype属性使用详解
2015/06/05 Javascript
深入解析JavaScript框架Backbone.js中的事件机制
2016/02/14 Javascript
浅谈JavaScript对象的创建方式
2016/06/13 Javascript
详解Node.js开发中的express-session
2017/05/19 Javascript
详解webpack介绍&amp;安装&amp;常用命令
2017/06/29 Javascript
node.js操作MongoDB的实例详解
2017/10/11 Javascript
js中的数组对象排序分析
2018/12/11 Javascript
Vue自定义属性实例分析
2019/02/23 Javascript
微信小程序 确认框的实现(附代码)
2019/07/23 Javascript
卸载vue2.0并升级vue_cli3.0的实例讲解
2020/02/16 Javascript
JavaScript进阶(二)词法作用域与作用域链实例分析
2020/05/09 Javascript
Python工程师面试题 与Python Web相关
2016/01/14 Python
利用python计算windows全盘文件md5值的脚本
2019/07/27 Python
深入理解Python 多线程
2020/06/16 Python
python GUI计算器的实现
2020/10/09 Python
草莓巧克力:Shari’s Berries
2017/02/07 全球购物
三万活动总结
2014/04/28 职场文书
简易版租房协议书范本
2014/10/13 职场文书
汇报材料怎么写
2014/12/30 职场文书
第二次离婚起诉书
2015/05/18 职场文书
2016新年晚会开场白
2015/12/03 职场文书
小学三年级数学教学反思
2016/02/16 职场文书
Python 避免字典和元组的多重嵌套问题
2022/07/15 Python