基于JavaScript编写一个翻卡游戏

目录
  • 前言
  • 翻卡动画
  • 生成随机分布数组
    • 均匀元素下的随机算法
    • 不均匀元素下的随机算法
    • 生成最终数组
  • 点击事件
  • 完整代码

前言

首先将这个游戏需求拆分成三个部分:

  • 翻卡动画
  • 生成随机分布数组
  • 点击事件

翻卡动画

假如我们的盒子模型不是个二维的平面,而是有个三维的体积,让它可以有正反两面,那我们在做的时候是不是只要将它真实的翻个面就可以了。让我们来想想将它变成三维的方法。 之后发现了这个属性:

transform: translateZ(1px);

使用了它,就可以把盒子内部的元素与盒子的底部撑出个高度。

<!-- html -->
<div class="card">
    <div class="top">我是正面哦~</div>
</div>

只用给叫做“top”的子盒子一个“距离父亲的距离”,再将叫做“card”的父盒子预先翻转180度rotateY(180deg),等到点击的时候给它翻回来transform: rotateY(0)就可以了。

.card{
  ...
  height: 100%;
  width: 100%;
  position: relative;
  transform-style: preserve-3d;
  transform: rotateY(180deg);
  transition: all 600ms;
  background: pink;
  &.select {
    transform: rotateY(0);
  }
  .top{
    ...
    height: 100%;
    width: 100%;
    position: absolute;
    top: 0;
    left: 0;
    box-sizing: border-box;
    background: white;
    border: 2px solid #b6a6dc;
    transform: translateZ(1px);
  }
}

生成随机分布数组

我们先来说下在理想环境中,每个元素都能匀均出现(次数相等)的情况。再来说下不能均匀出现的情况下,怎样最大限度的均匀。

均匀元素下的随机算法

此算法脑内模型由西塔(θ)先生友情提供

假设我们一共需要20个元素,有5个不同类型的格子,正好每个格子出现4次。我们就有了一个待分配元素的集合W:

const total = 20
const icons = ['a', 'b', 'c', 'd', 'e']
// => 得到集合W
const W = ['a', 'a', 'a', 'a',
           'b', 'b', 'b', 'b',
           'c', 'c', 'c', 'c',
           'd', 'd', 'd', 'd',
           'e', 'e', 'e', 'e']

混淆集合

有个指针p从下标0开始,在长度为20的数组格子里面负责填图案,填图案的规律是从集合w中随机取一个元素,取完后删除该元素,p移动到下一个格子里,迭代至完成。

function createRandomList(W: string[], total: number) {
    const list: any[] = []
    function it(time: number): any {
        if (time === 0) return list
        // 随机每次集合元素下标
        const randomNum = Math.floor(Math.random() * (W.length))
        list.push(W[randomNum]) // 新数组中加入随机到的元素
        W.splice(randomNum, 1) // 删除集合中的元素
        return it(--time)
    }
    return it(total)
}

我们再让这个方法灵活一点,使它的返回结果能够随便指定格式:

// fn非必传项,默认返回原数据
function createRandomList(W: string[], total: number, fn: (<T>(icon: string, index?: number) => T) = icon => icon) {
    const list: any[] = []
    // 迭代器
    function it(time: number): any {
        if (time === 0) return list
        // 随机每次集合元素下标
        const randomNum = Math.floor(Math.random() * (W.length))
        list.push(fn(W[randomNum], total-time)) // 将元素和下标传入fn中,将fn的计算结果加入到新数组中
        W.splice(randomNum, 1) // 删除集合中的元素
        return it(--time)
    }
    return it(total)
}

不均匀元素下的随机算法

const W = []

不均匀元素,其实就是集合W里的元素分布规则改变了,混淆算法仍然不受影响。之后,让我们来思考下怎么定义一个“不均匀中的最大程度均匀”的集合。 将集合W分为两个部分: 最大可均匀分布部分 + 随机部分

最大可均匀分布的部分,它代表着icons中的每个元素都能出现相同的最多偶数次。可以这样得到它:

  • icons个数x2,得到完整一次配对需要多少格子
  • 总格子数 / 一次完整格子数,得到可以完整配对的最大次数n
  • 循环n次,每次循环往W里添加icons x 2
// 得到最大重复次数
const times = Math.floor(total / (icons.length * 2))
for (let index = 0; index < times; index++)
    W.push(...icons, ...icons)

剩下的是需要随机分布的部分,它代表着,某几个元素可以在这里出现2次,剩下的则不会出现。

  • 总格子数 % icons个数x2, 得到剩下未分配的格子
  • 未分配格子 / 2, 就是需要随机从icons中取出的元素个数n,这个n一定小于icons的个数
  • 从icons中随机取n个数,可以采用每取一个数,将该数从原集合删除,重复n次的方法
  • 将得到的n个数x2,往W里添加

第(3)条是不是听起来很耳熟,好像前面做过,没错就是前面写的createRandomList函数,W集合变成了icons,total变成了需要的个数n。

// 剩下未分配的格子个数
const lastCount = total % (icons.length * 2)
// 从icons中随机获取n个数
const lastList = createRandomList(icons, lastCount / 2)
W.push(...lastList, ...lastList)

合在一起就是就是创建W的方法:

function createW(icons: string[], total: number) {
    const times = Math.floor(total / (icons.length * 2))
    const lastCount = total % (icons.length * 2)
    const W = []
    for (let index = 0; index < times; index++)
        W.push(...icons, ...icons)
    const lastList = createRandomList(icons, lastCount / 2)
    W.push(...lastList, ...lastList)
    return W
}

生成最终数组

完整的生成随机数组代码:

function createW(icons: string[], total: number) {
    const times = Math.floor(total / (icons.length * 2))
    const lastCount = total % (icons.length * 2)
    const W = []
    for (let index = 0; index < times; index++)
        W.push(...icons, ...icons)
    const lastList = createRandomList(icons, lastCount / 2)
    W.push(...lastList, ...lastList)
    return W
}
function createRandomList(W: string[], total: number, fn: (<T>(icon: string, index?: number) => T) = icon => icon) {
    const list: any[] = []
    function it(time: number): any {
        if (time === 0) return list
        const randomNum = Math.floor(Math.random() * (W.length))
        list.push(fn(W[randomNum], total-time))
        W.splice(randomNum, 1)
        return it(--time)
    }
    return it(total)
}

// ['a', 'b', 'c', "d"] => ['c', 'd'...x15...'b', 'c', 'a']
createRandomList(createW(icons, total), total)

点击事件

乱序的随机数组有了,点一点还不简单吗! 先让生成的数组属性更丰富一些,来帮助我们展示内容。

type CardItem = { icon: string; isDel: boolean; isSelect: boolean, index: number }

let list: CardItem[] = []

// isSelect属性判断是否翻转,isDel属性判断是否已经消除,icon属性标注元素属性,index用来快速找到点击元素位于数组中的位置
list = createRandomList(createW(icons, total), total, (icon: string, index) => ({ icon, isDel: false, isSelect: false, index }))

这下可以用生成的数组去展示了。接下来我们写个点击事件,接收参数是点击的数组元素:

// isLock用来锁定动画完成前不能进行别的操作
function handlerTap(card: CardItem) {
    if (isLock) return
    list[card.index].isSelect = true
    const selectors = list.filter(item => item.isSelect && !item.isDel)
    // 假如选择元素<2,直接返回,不走之后流程
    if (selectors.length <= 1) return
    isLock = true
    const [item1, item2] = selectors
    // 翻转动画完成后进行操作
    setTimeout(() => {
        // 如果选择的元素相同,则消除属性等于true
        if (item1.icon === item2.icon) {
            list[item1.index].isDel = true
            list[item2.index].isDel = true
        }
        //将所有卡牌翻转过背面
        list = list.map(item => ({...item, isSelect: false}))
        isLock = false
        // 判断是否所有卡牌都已经翻转完成
        if (list.every(item => item.isDel)) console.log( "your win!")
    }, 800)
}

完整代码

100行整)。

<script lang="ts">
    type CardItem = { icon: string; isDel: boolean; isSelect: boolean, index: number }
    const icons = ['a', 'b', 'c', "d"]
    const total = 20
    let list: CardItem[] = []
    let isLock = false

    function handlerTap(card: CardItem) {
        if (isLock) return
        list[card.index].isSelect = true
        const selectors = list.filter(item => item.isSelect && !item.isDel)
        if (selectors.length <= 1) return
        isLock = true
        const [item1, item2] = selectors
        setTimeout(() => {
            if (item1.icon === item2.icon) {
                list[item1.index].isDel = true
                list[item2.index].isDel = true
            }
            list = list.map(item => ({...item, isSelect: false}))
            isLock = false
            if (list.every(item => item.isDel)) console.log( "your win!")
        }, 800)
    }
    function createW(icons: string[], total: number) {
        const times = Math.floor(total / (icons.length * 2))
        const lastCount = total % (icons.length * 2)
        const W = []
        for (let index = 0; index < times; index++)
            W.push(...icons, ...icons)
        const lastList = createRandomList(icons, lastCount / 2)
        W.push(...lastList, ...lastList)
        return W
    }
    function createRandomList(W: string[], total: number, fn: (<T>(icon: string, index?: number) => T) = icon => icon) {
        const list: any[] = []
        function it(time: number): any {
            if (time === 0) return list
            const randomNum = Math.floor(Math.random() * (W.length))
            list.push(fn(W[randomNum], total-time))
            W.splice(randomNum, 1)
            return it(--time)
        }
        return it(total)
    }

    list = createRandomList(createW(icons, total),
            total,
            (icon: string, index) => ({ icon, isDel: false, isSelect: false, index }))
</script>
<div class="game-box">
    {#each list as item}
        <div class="grid">
            {#if !item.isDel}
                <div class="card {item.isSelect && 'select'}" on:click="{() => handlerTap(item)}">
                    <div class="top">{item.icon}</div>
                </div>
            {/if}
        </div>
    {/each}
</div>
<style lang="less">
    .game-box{
      margin: 10px auto 0;
      width: 90vw;
      height: 80vh;
      display: grid;
      grid-template-columns: repeat(4, calc(100% / 4 - 3px));
      grid-template-rows: repeat(5, calc(100% / 5 - 3px));
      grid-row-gap:3px;
      grid-column-gap: 3px;
      .card{
        height: 100%;
        width: 100%;
        box-sizing: border-box;
        position: relative;
        transform-style: preserve-3d;
        transform: rotateY(180deg);
        transition: all 600ms;
        background: pink;
        &.select {
          transform: rotateY(0);
        }
        .top{
          height: 100%;
          width: 100%;
          position: absolute;
          top: 0;
          left: 0;
          box-sizing: border-box;
          display: flex;
          justify-content: center;
          align-items: center;
          background: white;
          border: 2px solid #b6a6dc;
          transform: translateZ(1px);
        }
      }
    }
</style>

以上就是基于JavaScript编写一个翻卡游戏的详细内容,更多关于JavaScript翻卡游戏的资料请关注我们其它相关文章!

(0)

相关推荐

  • js实现翻牌小游戏

    本文实例为大家分享了js实现翻牌小游戏的具体代码,供大家参考,具体内容如下 效果图 需求分析 1.生成两组顺序随机的1-8数据 2.卡片需要有翻转效果 3.两次翻转数据不相等,回复原状 4.两次翻转数据相等,卡片相等,不能再被点击 5.当所有卡片不能被点击游戏结束 6.限制最大点击次数50次 HTML结构 <div class="wrap"> <div> <p class="top"></p> <p class=

  • js实现简单翻牌小游戏

    本文实例为大家分享了js实现简单翻牌小游戏的具体代码,供大家参考,具体内容如下 1.简介 非常简单的一个网络消消乐翻牌小游戏的实现,代码量较少,不过遇到的bug和自行开发的步骤十分有纪念意义. 2.核心代码块 生成随机数列,确定图片随机分布 function getImgIndex(is){    var index = parseInt(Math.random()*8)+1;          if(is[index] < 2){              is[index]++;      

  • 基于HTML+CSS+JS实现纸牌记忆游戏

    目录 知识点 HTML 用户界面 CSS 部分 一些基本样式 纸牌的样式 分数面板的样式 祝贺面板的样式 动画 媒体查询 JavaScript 部分 洗牌功能 开始新游戏的功能 显示卡片的功能 当卡片匹配时的功能 当卡片不匹配时的功能 暂时禁用卡片的功能 启用卡片并禁用匹配的卡片的功能 计算玩家的动作的功能 显示游戏的时间 再次游戏功能 总结 这节实验我们将使用 HTML.CSS 和 JavaScript 制作纸牌记忆游戏. 让我们开始吧! 在线演示戳这里 知识点 animation-durat

  • 原生JS实现记忆翻牌游戏

    本文实例为大家分享了JS实现记忆翻牌游戏的具体代码,供大家参考,具体内容如下 html代码 <div id="game"> <!-- div.block*16>div.pic --> </div> css代码 * { padding: 0; margin: 0; } #game { width: 600px; height: 600px; margin: 0 auto; } .block { float: left; box-sizing: b

  • JS实现纸牌发牌动画

    本文实例为大家分享了JS实现纸牌发牌动画的具体代码,供大家参考,具体内容如下 先看演示 游戏构建准备 1.准备52张纸牌 2.一张桌布 3.编辑工具为 Visual Code 技术概要 1.对象操作 2.数据操作 3.JS animation动画 4.全局变量 function desen_x(){ let that = this; var desen=["h_1","h_2","h_3","h_4","h_5&qu

  • 基于JavaScript编写一个翻卡游戏

    目录 前言 翻卡动画 生成随机分布数组 均匀元素下的随机算法 不均匀元素下的随机算法 生成最终数组 点击事件 完整代码 前言 首先将这个游戏需求拆分成三个部分: 翻卡动画 生成随机分布数组 点击事件 翻卡动画 假如我们的盒子模型不是个二维的平面,而是有个三维的体积,让它可以有正反两面,那我们在做的时候是不是只要将它真实的翻个面就可以了.让我们来想想将它变成三维的方法. 之后发现了这个属性: transform: translateZ(1px); 使用了它,就可以把盒子内部的元素与盒子的底部撑出个

  • 如何利用JavaScript编写一个格斗小游戏

    拖延症晚期的我原本计划趁着周末写个年终总结,但是一直没有什么思路,想来想去也没想到要写啥就胡乱写了这么一个小东西. 一直比较痴迷游戏行业,可能我不太适合做前端,应该去学C++.... 首先当然是选择一张背景图,作为整个场景中的地图,而且要大要高清.布局到页面中. 然后通过可视区值展示这张图片的一小部分.我这里用的是宽600,高420的,超出直接隐藏掉. width: 600px; height: 420px; 这样一个简单的场景就写好了,接着我们需要在这个场景中加入我们的人物.也就是游戏中的角色

  • 基于JavaScript编写一个图片转PDF转换器

    目录 JavaScript 实现图片转 PDF 第一步: PDF Converter的基本结构 第二步: 图片预览框 第 3 步: 图像到 PDF 转换器的按钮 第 4 步: 在 JavaScript 中实现图片转换到 PDF 这是一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件.你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件.但是除了图片之外,其他文件不可以在此处转换为 PDF.我使用 HTML 添加了不同的元素并创建了一个输入框来选择图像. 我们

  • JavaScript编写一个贪吃蛇游戏

    写的比较乱,有个逻辑错误:蛇吃了果果后应该是蛇尾加一节,写成了蛇头部增加一节- -. 可用键盘的上下左右键操作: 效果图: 代码如下: <html> <head> <title> 贪吃蛇 </title> <style type="text/css"> body{margin:0;padding:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:n

  • 基于Python编写一个宝石消消乐小游戏

    目录 开发工具 环境搭建 原理简介 开发工具 python版本:3.6.4 相关模块: pygame:以及一些python自带的模块. 环境搭建 安装python并添加到环境变量,pip安装需要的相关模块即可. 原理简介 游戏规则: 玩家通过鼠标交换相邻的拼图,若交换后水平/竖直方向存在连续三个相同的拼图,则这些拼图消失,玩家得分,同时生成新的拼图以补充消失的部分,否则,交换失败,玩家不得分.玩家需要在规定时间内获取尽可能高的得分. 实现过程: 首先加载一些必要的游戏素材: 加载背景音乐: py

  • 基于JavaScript制作一个骰子游戏

    目录 知识点 HTML 部分 CSS 部分 JavaScript 部分 总结 游戏可以通过这个链接进入 完整源码我已经放在GitHub上了 这节实验我们将使用 HTML.CSS 和 JavaScript 构建一个骰子游戏.设置两名玩家(一个人玩也行)然后掷骰子,获得更高点数的玩家将赢得游戏. 知识点 :hover 选择器 querySelector() 方法 setAttribute() 方法 骰子 1-6 点的图片都放在这里了,大家可以将这些图片保存在本地的文件夹中然后用相对地址引用,或者也可

  • 基于Python编写一个中秋节嫦娥投食小游戏

    目录 游戏设计 1.游戏背景 2.功能设计 效果展示 代码素材 代码 素材 山河远阔,烟火人间,又一年,千里婵娟~ 今天给大家带来的是给玉兔投喂月饼的小游戏.八月十五中秋夜晚,让我们对着月亮许愿:希望我们在意和在意我们的人,诸邪避退.百事无忌.平安喜乐.万事胜意.提前祝大家中秋节快乐. 中秋节的起源 中秋节起源于上古时代,普及于汉代,定型于唐朝初年,盛行于宋朝以后.中秋节是秋季时令习俗的综合,其所包含的节俗因素,大都有古老的渊源.中秋节以月之圆兆人之团圆,为寄托思念故乡,思念亲人之情,祈盼丰收.

  • 基于JavaScript+HTML5 实现打地鼠小游戏逻辑流程图文详解(附完整代码)

    随着html5的兴起,那些公司对大型游戏的开发正在慢慢疏远,一.开发周期长:二.运营花费高:他们正找一些能够克服这些缺点的替代品.正好,html5的出现可以改变这些现状,在淘宝.京东等一些大型电商网站.QQ.微信等聊天软件都出现了html5的小游戏,这说明html5越来越受到大家的青睐.接下来我用javascript实现一个小型游戏---打地鼠. 一.游戏简介 打地鼠这个游戏相信大家都不陌生,也是童年时候一款经典的游戏.本次游戏的编写是以html文件形式完成的,并且使用HBulider软件进行编

  • 利用Python编写一个记忆翻牌游戏

    目录 导语 开发工具 环境搭建 先睹为快 原理简介 导语 昨天看到有留言竟然说我是月更博主,我明明更新地这么勤快(心虚.jpg).看吧,昨天刚更新过,今天又来更新了. 今天还是带大家写个小游戏吧,不过老是用pygame也没啥意思,这次我们换点新花样,用python自带的tkinter包写一个记忆翻牌小游戏呗. 废话不多说,让我们愉快地开始吧~ 开发工具 Python版本:3.7.4 相关模块: pygame模块: tkinter模块: pillow模块: 以及一些python自带的模块. 环境搭

  • 基于Unity编写一个九宫格抽奖软件

    目录 一.前言 二.效果图 三.案例制作 1.界面搭建 2.代码编写 3.效果演示 四.后言 一.前言 本博文标题和内容参考:基于原生JS实现H5转盘游戏 博主将改编成Unity版本. 二.效果图 三.案例制作 1.界面搭建 使用了9个图片作为奖品栏,然后一个chooseBox作为蒙版,一个StartBtn开始按钮放在中间 2.代码编写 新建脚本goLuckyDraw.cs 使用DoTween插件做动画,没有导入这个插件的下载导入一下 实现抽奖,主要有两个方面,一个是概率的设置,一个是动画 动画

随机推荐