我是HullQin,公众号线下聚会游戏的作者(欢迎关注公众号,发送加微信,交个朋友),转发本文前需获得作者HullQin授权。我独立开发了《联机桌游合集》,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋等游戏,不收费没广告。还开发了《Dice Crush》参加Game Jam 2022。喜欢可以关注我 HullQin 噢~我有空了会分享做游戏的相关技术。
问题描述
我们想做一个斗地主游戏,其中最重要的一点是,把扑克牌展示出来。
一副牌有54张,我们给每张牌1个编号(id),取值1-54。如果涉及到2副牌,就取id为1-108。
展示牌,其实就是给你一个id列表,按需展示列表中的牌即可。
而展示牌有3种排序方式:
- 不排序,列表是什么,就展示什么。(发牌、底牌常用)
- 按照大小排序。(手牌常用)
- 按照出牌规则排序。(出牌常用,规则比如顺子、连对、飞机、四带二、炸弹等)
今天,我们就来实现它们!
第1步,展示1张牌
准备素材
牌有54种,加上牌背面,有55种图案。我们先准备好素材:
如果要展示1张牌,以它为背景,使用background-position
和width
、height
对整个大图片裁剪即可。
不要拆开这个大图,让用户一次性下载55张图片,那样速度会肉眼可见的慢。因为大多数浏览器不能并发55个请求下载图片,它可能一次最多建立8个TCP连接来下载,你可能需要8次RTT才能下载完。(55除以8向上取整=8)
所以,做Web开发,一定要尽量拼接多个小素材成为一个大图片,再去裁剪它展示素材。
写好css做裁剪
我们利用class,定义一个.poker
写所有扑克牌共用的样式,再给每个扑克牌定义一个background-position
(裁剪位置)即可。
.poker {
position: absolute;
background-image: url('./card.png');
background-clip: content-box;
background-repeat: no-repeat;
width: 116px;
height: 159px;
transform-origin: 0 0 0;
transition: left .2s ease-out, top .2s ease-out;
}
例如,这是id为1的扑克牌的样式。每个扑克牌单独的样式很简单,只有1行,定义background-position
即可。因为其它样式都是一模一样的,用.poker
复用即可。
.poker-1 {
background-position: -238px -646px;
}
不再罗列了,可以参考style.css源码: github.com/HullQin/poker_fe
定义 扑克牌ID->图片ID 的映射
开头我们提到,可能有2幅牌,而他们的图片样式应该是一样的。所以需要通过取余数,把108个ID映射到54个值。
const mapPokerIdToCardId = (id) => {
// 映射扑克id(可能有多幅牌)至卡片id(只有0-54)
return (id - 1) % 54 + 1;
};
代码中,我用id = 0
表示扑克牌的背面。
封装一个组件
你可以封装为React组件或Vue组件,或其它你采用框架支持的组件。
我代码使用了React,所以封装为React组件。
import cn from 'classnames';
const Poker = (props) => {
const {
id, className, ...otherProps } = props;
if (typeof id !== 'number') return;
const cardId = mapPokerIdToCardId(id);
return (
<div
className={
cn(