一镜到底,围观一个周边猜猜看是如何实现的【玩转Web小游戏】

举报
叶一一 发表于 2023/07/27 12:35:52 2023/07/27
【摘要】 之前获得了许多有趣的周边,又好看又好玩,在周边体验的过程中,突然奇想的做一个猜猜看到小游戏。灵感有了,剩下的就交给代码了。接下来分享一下实现的完整过程,以及对web小游戏的开发心得一并奉上。

星光坠心

一切还要从我收到拍拍灯说起。

我之前收到一份神秘的周边,打开发现竟然是期待已经的拍拍灯,实物如下,造型蛮特别的。

我看着这昏黄的光,似遥远星球闪耀的星光,一下子来了灵感。

新年 FLAG,当然是拥有更多掘金周边。拍拍灯算一个,再加上几款新年限定,可以在练练看中组合「出道」。这样一来新年愿望就达成了一半(另一半靠接下来的努力)。

有些路,想着想着就走通了。

我用了52秒决定做一个功能,又用了10分钟想清楚实现过程。

接下来,和我一起围观,如何实现一个网页游戏,一个遮挡版的掘金周边连连看

试玩一刻

周边解锁

如果出现如下的界面,恭喜,已解锁小游戏中的全部周边图片。


细听分说

一句话介绍

12张头像图片遮挡了6组掘金周边,每次的点击可以掀开被隐藏的掘金周边,确定两个一样的周边,直到六组全部被找到,游戏通关。

一表格演示

规则

规则内容

展示规则

1、遮挡头像图片每次会随机展示一张运营大佬的头像。

2、6组周边的展示位置是随机的,每次刷新或者重开游戏,会重排位置。

遮挡规则

1、每次点击查看一个周边。

2、两次是否相同

  • 相同,则取消遮挡;
  • 不相同,则继续遮挡。

通关规则

1、找到全部6组周边,游戏成功。

2、成功之后

  • 给出弹窗提示;
  • 可以重开游戏。

重开规则

1、游戏通关弹窗中,有重开按钮;

2、游戏中,可以点击游戏机底部按钮,进行重开。

解锁规则

1、根据当前游戏玩家的id判断是否有解锁功能;

2、待开发功能。

一镜到底

那日的夜幕下,连连看的实现过程,在我的脑海里,像一部短片,镜头从头到尾,没有一刻的晃动。

我带着奇妙的观影感,一镜到底,丝滑的实现了整个游戏的开发。

从造型开始

我想一个有趣的内在,也应该拥有一个有趣的外在,换了几次装,想到之前实现过一个游戏机的功能,于是给连连看增加了一个游戏机的外型。

<div class="game"></div>

变化的乐趣

我曾经玩过的游戏,印象有些模糊了,但是这次我想遮挡的图案是变化的,会更有趣。

我在想遮盖图案的随机和周边图案摆放的随机时,意外的发现,可以用相同的方式,即都是从一组图片中随机取一张

只不过,遮盖图案全部都是同一个,周边图片每组是同一个。

获取随机值

  • 设置一个随机空数组;
  • 进行循环操作,从目标数组中,每次随机得到索引值;
  • 通过索引得到对应的元素,存入新数组中,而目标数组去掉该元素;
  • 直到目标数组的值为空,此时就得到了完整的随机之后的新数组。
// 数组随机排序
function getListRandom(list) {
  let randomList = [];
  let listInit = [].concat(list);
  while (listInit.length > 0) {
    // 获取随机数索引值
    let numIndex = Math.floor(Math.random() * listInit.length);
    randomList.push(listInit[numIndex]);
    // 将当前索引对应的元素去除
    listInit.splice(numIndex, 1);
  }
  return randomList;
}

随机,遮盖图案

1、定义一组图案。

var itemImageSrcListInit = ['https://p3-passport.byteimg.com/img/user-avatar/0779dd287afeb3e6a983deb0ff79d724~180x180.awebp', 'https://p3-passport.byteimg.com/img/user-avatar/8db3fdff9a85ee60ad0e6706b6632064~180x180.awebp', 'https://p3-passport.byteimg.com/img/user-avatar/ed03b70fe4ab1ce93c74ff5cf4ae82d0~180x180.awebp', 'https://p3-passport.byteimg.com/img/user-avatar/5d08c09da9bffd1331bc6220b884a466~180x180.awebp', 'https://p3-passport.byteimg.com/img/user-avatar/b72e991ee9b1c9bdca7b2bd4c8dc78a8~180x180.awebp', 'https://p3-passport.byteimg.com/img/user-avatar/7e4a7c01e7022917f7242419f19a6c03~180x180.awebp', 'https://p3-passport.byteimg.com/img/user-avatar/e3a142ceef01d6d640ac417a16f127f6~180x180.awebp', 'https://p3-passport.byteimg.com/img/user-avatar/8378ae90f38c97148d85582b480fd3ad~180x180.awebp'];

2、得到随机图案数组,页面遮挡元素进行循环,将得到的图案,按照索引值,一一进行回显。

// 遮挡图片随机
function initItemImageList(itemImageSrcListInit, itemImageList) {
  let itemImageSrcList = getListRandom(itemImageSrcListInit);
  for (let i = 0; i < itemImageList.length; i++) {
    itemImageList[i].src = itemImageSrcList[0];
    itemImageList[i].style.display = 'block';
    itemImageList[i].classList.remove('hidden');
    // vip不遮挡
    if (vipFlag) {
      itemImageList[i].style.display = 'none';
    }
  }
}

3、还有一个特殊处理,初始化遮挡图案的展示样式,后续会用到。

随机,周边图案

1、定义一组周边图案。

var positionImageList = ['https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1c27f38b3f5746e5b368385504af2d0c~tplv-k3u1fbpfcp-no-mark:0:0:0:0.image?', 'https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/59eb9d261a9f487a9674a2bc9049bea7~tplv-k3u1fbpfcp-no-mark:0:0:0:0.image?', 'https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/31198c6444a94f129caaf4d5eecb667b~tplv-k3u1fbpfcp-no-mark:0:0:0:0.image?', 'https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c918c454e0ae4e5da06f08fc3b597c9c~tplv-k3u1fbpfcp-no-mark:0:0:0:0.image?', 'https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b9ec814cb7c143f7a271ebda55f85819~tplv-k3u1fbpfcp-no-mark:0:0:0:0.image?', 'https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d9694d784a75485b943f152ff3a88c2d~tplv-k3u1fbpfcp-no-mark:0:0:0:0.image?'];

2、再定义一组位置索引值。

var positionListInit = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5];

3、得到位置索引的随机数组,页面周边元素进行循环,将索引随机数组得到周边图案,回显到页面对应的元素中。

// 位置随机
function initPositionList(positionListInit, coverImageList) {
  let positionList = getListRandom(positionListInit);
  for (let i = 0; i < coverImageList.length; i++) {
    let positionListIndex = positionList[i];
    coverImageList[i].src = positionImageList[positionListIndex];
    setTimeout(function () {
      coverImageList[i].style.display = 'block';
    }, 500);
  }
}

4、因为遮挡图案也是随机获取的,两个随机一起进行,可能图案会出现交错,所以我将周边图案的回显延迟了500毫秒。

追逐与嬉戏

前期的背景、走位已布置分配妥当,接下来就开始点击进行玩耍了。

1、监听每个元素的点击事件。

for (let i = 0; i < itemList.length; i++) {
  // 监听点击事件
  itemList[i].onclick = function () {
    ......
  };
}

2、设置一个接收点击位置的数组,后面的相同判断和重组都是通过它进行判断的。

// 接收每次点击的位置 当长度等于2的时候情况
var receivePositionList = [];

每次点击之后,将点击元素的索引放入接收数组中。

receivePositionList.push(i);

3、点击时,对应的遮挡元素添加隐藏样式

itemImageList[i].classList.add('hidden');
// 一段时间之后因此动画
setTimeout(function () {
  itemImageList[i].style.display = 'none';
}, 500);

4、当接收数组的长度等于2时,开始判断两个位置的周边是否相同。

  • 如果不同,则继续进行遮挡,并移除遮挡的动画。
  • 如果相同,成功的数量增加1。

最后将接收数组的值清空。

// 当点击的位置的数量是两个的时候 判断是否一致
if (receivePositionList.length === 2) {
  let positionIndex1 = receivePositionList[0];
  let positionIndex2 = receivePositionList[1];
  // 两个一致则连连看成功的数量加1
  if (coverImageList[positionIndex1].src === coverImageList[positionIndex2].src) {
    receiveCount += 1;
  } else {
    if (!vipFlag) {
      // 两个不一致则关闭
      setTimeout(function () {
        itemImageList[positionIndex1].style.display = 'block';
        itemImageList[positionIndex1].classList.remove('hidden');
        itemImageList[positionIndex2].style.display = 'block';
        itemImageList[positionIndex2].classList.remove('hidden');
      }, 800);
    }
  }
  // 清空接受的位置
  receivePositionList = [];
}

5、当所有的周边都被连成功之后,给出成功提示。

let positionListLen = positionListInit.length;
if (receiveCount === positionListLen / 2) {
  setTimeout(function () {
    openModal('restart');
  }, 800);
}

倒带重来

既然是游戏,肯定想多玩几次,所以我设计了游戏重开的功能,有两个入口。

1、成功提示弹层上面增加了「重新开始」的按钮。

点击「重新开始」,重置周边连接成功的数据和接收位置的值,重新计算遮挡和周边的位置,并关闭弹窗。

// 弹窗重开
modalBtn.onclick = function () {
  if (modalType === 'restart') {
    initData();
    receivePositionList = [];
    receiveCount = 0;
  }
  closeModal();
};

这里有一个需要注意的点,就是成功连接所有周边,遮挡图片被添加了样式,重开的时候需要进行一次初始化处理,否则样式会有问题,所以前面提到了特殊处理。

2、在游戏机底部有「重开」的按钮。

点击「重开」,重置数据。

// 按钮重开
btnRestart.onclick = function () {
  initData();
  receivePositionList = [];
  receiveCount = 0;
};

未完待续

一个基础版的连连看小游戏,从游戏规则到游戏实现的全过程,到这就基本结束了。

接下来是收获时刻,简单总结一下:

小游戏的基本特点

  • 简单有趣又解压。
  • 麻雀虽小,五脏俱全。有开始的功能,也要有重新开始的功能。

猜猜看的基本特点

  • 多组相同的图案。
  • 图案的随机摆放。
  • 相连的两次操作中,相同与不同的处理。

提升之处

除去编程实现功能的快乐等收获,逻辑思维的训练,创意思路的繁衍,也在每一次的创作中,增强、加快、演化。

创作心得

除去功能实现过程的分享,还想跟大家分享一下我的心得:

遇见它,了解它,实现它。

因为这样的创作理念,除去过去的这一年,我实现了多个小游戏。

后会有期

我还有多个待实现的创意想法,正在欢快的排队中。期待后面的相见。


作者:非职业「传道授业解惑」的开发者叶一一
简介:「趣学前端」、「CSS畅想」系列作者,华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。
如果看完文章有所收获,欢迎点赞👍 | 收藏⭐️ | 留言📝。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。