【必赢】写一个斗地主记牌器

前言

最近一段时间,闲暇之余玩了几把斗地主,惋惜的是本身没钱买记牌器,脑子又记不住那么多牌,常常翻车,震怒!遂写记牌器,逆天改命!html

界面

不用多说,确定是模仿斗地主的记牌器最实用好看啦。
image.png
ps:这个是最终稿的截图,前几版还有一些按钮,为何去掉了能够看后面。数组

交互

首先,怎么设计这个记牌器的交互才是关键,由于咱们只能手动记牌,其余牌友出了什么牌,咱们就从一副牌里减去出掉的牌。app

  • 想法1:键盘输入,回车|按钮出牌ide

    • 若是是1-9,那确定是很快的,可是JQK大小王这个输入起来太麻烦,若是换成其余键盘上连续的字母来代替JQK大小王那么又须要记忆的成本了,我tm记忆力好还要个🔨记牌器。🙅‍!
  • 想法2:点击选取,而后回车|按钮出牌flex

    • 这个实际上是比较符合咱们的斗地主的操做逻辑的,可是有一个问题若是我出的是飞机的话,就要点不少下,很是麻烦!不太行。
  • 想法3:点击+滑动直接出牌,去除回车或者按钮,右键撤回spa

    • 这个就是最终的交互逻辑了,若是对手只出了1张,那么咱们只须要点击就行,若是出连队,飞机,那咱们只须要滑几下而已。由于去除了出牌按钮,因此容易点错,这里加入了一个右键给某张牌撤回一张的功能。

实现

很容易就能够想出思路:设计

  1. 画出界面,13种牌(4张/种)+大小王(2张,这里并未区分大小王,由于通常我只是怕炸弹而已,大小王缺一张怕锤子,并且缺了一张之后,不论是大王仍是小王都是最大的,有区别吗?)
  2. 添加左键点击事件,以及左键按下滑动事件。
  3. 阻止默认右键事件,添加右键点击事件。
  4. 作一些细节的处理,好比说4张牌红色警告,0张牌,牌面变灰色等等。

实现1:画界面

这里实在太简单,不想说了。你能够手动写十几个div,也能够用js动态添加。3d

实现2:左键点击和滑动处理

咱们这里应该分红两布,第一步是选,第二步是出牌。因此咱们能够用一个数组来保存咱们已经选择的牌的序号。code

  • 左键点击orm

    • 直接将这个牌的序号添加进数组
    • 而后出牌
  • 滑动

    • 两种作法,一种是经过坐标定位,判断鼠标移动先后距离包含了哪几个牌来决定哪些牌应该被选取。第二种就是给每一个牌添加mouseenter,mouseleave事件,鼠标通过的时候,就会触发,就把出发的牌的序号添加进数组。
    • 而后出牌

实现3:右键增长牌数

这里惟一要注意的是下面这个,首先屏蔽默认的右键事件。

document.oncontextmenu = function (event) {
      event.preventDefault();
      if (event.button == 2) {
        addCardCount(event.target)
      }
    };

而后对event.target进行处理就行了。

targetcurrentTarget的区别是:前者多是绑定事件元素下的子元素,后者是绑定事件元素自己。注意使用区别。

实现4:状态改变

你看以前咱们的界面设计,当牌还有4个的时候是红色加粗的,说明可能有炸弹;当没有炸弹时是灰色的;当出完牌之后是带透明的淡灰色。
这里咱们只须要根据这个牌数来更改状态就行了。关键是咱们怎么改这个牌数会更方便呢?

你可能会使用innerHTML,innerText?

CSS中的伪元素中的beforeafter里面有个content属性,而这个属性是能够跟元素上的自定义属性绑定的。好比说

.card::after {
      content: attr(count);
      position: absolute;
      bottom: 2px;
      right: 5px;
      color: #999;
      font-size: 18px;
    }

那么这个content的值就会跟随元素的count属性。因此咱们出牌的操做其实只须要更改这个属性值就行了,而后根据值来作一些相应的类名添加和删除便可。

适用人群

  • 没钱买记牌器的
  • 记忆力差的
  • 开电脑玩的

后记

使用这个记牌器之后,胜率并无高多少阿,淦!
我发现是运气不行,别人把把超级加倍打🔨啊,天天登录就领几千豆,一把归西!

后续可能写个运气更改器

|
|
|
|
|
|

固然不可能啦。淦!

源码

源码中已经添加诸多备注。复制粘贴便可,后续可能会放到博客上提供下载连接,不用复制那么辛苦啦。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>记牌器</title>
  <style>
    #box {
      display: flex;
      justify-content: center;
      align-items: stretch;
      user-select: none;
    }

    .card {
      position: relative;
      border-radius: 10px;
      width: 60px;
      margin-top: 20px;
      height: 100px;
      background-color: #f5f5f5;
      margin-right: 10px;
      box-shadow: 0 5px 5px 0 #c9c9c9;
      font-size: 28px;
      padding-left: 10px;
    }

    .card--empty {
      color: #c3c3c3;
      opacity: 0.8;
    }

    .card--chosen {
      margin-top: 0;
    }

    .card::after {
      content: attr(count);
      position: absolute;
      bottom: 2px;
      right: 5px;
      color: #999;
      font-size: 18px;
    }

    .card--warning::after {
      color: red;
      font-weight: bold;
    }

    #btn-box {
      text-align: center;
      margin-top: 30px;
    }

    button {
      padding: 10px 30px;
      border-radius: 60px;
      background-color: orangered;
      color: #fff;
      font-size: 32px;
      border: 0;
      cursor: pointer;
      transition: all ease .3s;
      margin-right: 20px;
      outline: none;
    }

    button:hover {
      background-color: red;
      transform: scale(1.1);
    }

    .info {
      font-size: 14px;
      margin-top: 70px;
      color: #999;
    }
  </style>
</head>

<body>
  <div id="box"></div>
  <div class="info">
    <p>做者: <a href="http://www.leelei.info">leelei</a></p>
    <p>用法: 鼠标【点击】直接出牌,或者【点击滑动】出牌,右键单击某张牌能够增长牌数(用于防止点错)</p>
    <p>适用于: 斗地主新手,而且没有钱买记牌器,而且常常开着电脑的时候顺便手机玩斗地主</p>
  </div>
</body>
<script>
  //常量
  const arr = [3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A', 2, '👻'];
  const nums = [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2];
  const TYPE_CHOSEN = ' card--chosen';
  const TYPE_WARNING = ' card--warning';
  const TYPE_EMPTY = ' card--empty';
  //储存已经选择
  let chosenArr = [];

  //添加类名
  function addClass(e, name) {
    if (e.className.indexOf(name) == -1) {
      e.className += name;
    }
  }
  //移除类名
  function removeClass(e, name) {
    e.className = e.className.replace(name, '')
  }
  //初始化卡片
  function initCards() {
    let box = document.getElementById('box');
    let frag = document.createDocumentFragment();
    for (let i = 0; i < 14; i++) {
      let ele = document.createElement('div');
      ele.className = 'card' + TYPE_WARNING;
      ele.innerText = arr[i];
      ele.setAttribute('count', nums[i]);
      ele.setAttribute('index', i);
      frag.append(ele)
    }
    box.append(frag);
  }

  //初始化输入
  function initSlideInput() {
    let cards = document.getElementsByClassName('card');
    //鼠标按下时注册
    box.addEventListener('mousedown', installSlideInput)
    //鼠标抬起卸载
    box.addEventListener('mouseup', uninstallSlideInput)
    box.addEventListener('mouseleave', uninstallSlideInput)
    //注册滑动输入
    function installSlideInput() {
      Array.from(cards).forEach((e) => {
        e.addEventListener('mouseenter', slideSelect)
        e.addEventListener('mouseleave', slideSelect)
      })
    }
    //卸载滑动输入
    function uninstallSlideInput() {
      Array.from(cards).forEach((e) => {
        e.removeEventListener('mouseenter', slideSelect)
        e.removeEventListener('mouseleave', slideSelect)
      })
      submit();
    }
    //点击输入,一直有效
    Array.from(cards).forEach((e) => {
      e.addEventListener('click', function (event) {
        slideSelect(event);
        submit();
      })
    })
    //滑动输入
    function slideSelect(event) {
      let idx = event.currentTarget.getAttribute('index');
      if (event.currentTarget.className.indexOf(TYPE_CHOSEN) == -1) {
        addClass(event.currentTarget,TYPE_CHOSEN)
        chosenArr.push(idx);
      }
    }
  }

  //重置所有牌的状态,凸起->对齐
  function reset() {
    chosenArr = [];
    let cards = document.getElementsByClassName('card');
    Array.from(cards).forEach((v, i) => {
      removeClass(v,TYPE_CHOSEN)
    });
  }

  //出牌 
  function submit() {
    let cards = document.getElementsByClassName('card');
    chosenArr.forEach((v, i) => {
      cards[v].setAttribute('count', cards[v].getAttribute('count') - 1);
      removeClass(cards[v],TYPE_WARNING);
      if (cards[v].getAttribute('count') < 1) {
        //最小为0,设置为空状态
        cards[v].setAttribute('count', 0);
        addClass(cards[v],TYPE_EMPTY)
      }
    });
    //重置状态
    reset();
  }
  //右键加牌,防止出错牌
  function addCardCount(e) {
    if (e.getAttribute('count') != undefined) {
      e.setAttribute('count', e.getAttribute('count') - 0 + 1);
    }
    if (e.getAttribute('count') >= nums[e.getAttribute('index')]) {
      e.setAttribute('count', nums[e.getAttribute('index')]);
      addClass(e,TYPE_WARNING)
    } else if (e.getAttribute('count') > 0) {
      removeClass(e,TYPE_EMPTY);
    }
  }

  window.onload = function () {
    document.oncontextmenu = function (event) {
      event.preventDefault();
      if (event.button == 2) {
        addCardCount(event.target)
      }
    };
    initCards();
    initSlideInput();
  }

</script>

</html>
相关文章
相关标签/搜索