创意闹新春,我正在参加「春节创意投稿大赛」,详情请看:春节创意投稿大赛
游戏地址:yain-tls.netlify.app/
开发框架:vue3+vite 运行平台:浏览器、适配移动端(横屏体验更佳)
gitee地址:gitee.com/yan_yin/mah…
欢迎大家体验
前言
又是新的一年,先给各位hxd和dl萌拜个早年,祝大家虎虎生威,如虎添翼,虎年大吉。
事物都有两面性,有的人认为打麻将不是一件好事,是赌博,但我觉得麻将只是个休闲游戏,是个社交活动,过年和朋友打一下午麻将,然后谁赢了请吃饭岂不快哉。做这个小教程的灵感来自于我朋友,因为他不会打麻将,但是过年很多朋友都要玩,他不玩就很不合群,于是在公司肝了两天便有了它,胡了有彩蛋哦!
yain-tls.netlify.app/ 快去转给不会麻将的小伙伴,让他学会,过年便多了一份快乐。做的简单,不喜勿喷。
游戏规则
先上公式 :n*ABC + m*DDD + 1*EE
ABC:顺子 、DDD:三个相同 、EE:对子 | n>=0 、m>=0
由于对川麻较熟悉,所以只有大众和四川
两种模式
大众模式就是满足上面的公式即可,川麻则是必须在缺一个花色的前提下满足公式
菜单及全局配置
目前有模式切换,是否自动摸牌和是否开启BGM,默认是大众、否、否。改变后用localStorage保存了状态。
模式切换
<div class="container">
<da-zhong v-if="!model" />
<si-chuan v-else />
</div>
没必要用路由,直接就通过一个变量切换两个组件
自动摸牌
在打出一张麻将之后再去调摸牌的函数即可
const delMj = (index)=> {
if([1,4,7,10,13].includes(data.handMj.length)){
window.alert('请先摸牌')
}else{
data.handMj.splice(index,1)
//摸牌的时候不排序 打出去的时候在排
handMjSort()
}
}
const handMjSort = ()=> {
setTimeout(()=> {
data.handMj.sort((a,b )=>a-b)
//自动摸牌
if(Number(localStorage.getItem('model2'))==1)getNewMj()
},1000)
}
const getNewMj = ()=> {
//摸牌后排序
data.handMj.push(...data.remainMj.splice(0,1))
checkMj()
//手牌麻将重复数最多的麻将
let max = findNum(data.handMj)
//是否有杠
if(max[0]==4){
//有杠
data.isGang = true
data.gangId = max[1]
}else{
data.isGang = false
}
}
声音
由于只有一个BGM,所以直接写在了appDom上,点击开关的时候直接调方法
<audio hidden="true" ref="audio" loop controls>
<source src="./assets/woop.mp3" type="audio/mpeg" />
</audio>
const audio = ref();
audio.value.volume = 0.1
audio.value.play()
audio.value.pause()
思路
麻将ID
最先想的是一个对象{type:x,num:y},一个是花色,一个是数字,但发现在排序和验证是否胡的时候很麻烦,于是想着就1-27个数字,每个数字有4个,在验证胡牌的时候9,10,11会通过验证,但是因为花色不一样,是不能成顺子,所以最简单的ID应该就是1-9,11-19,21-29。生成108张之后再用random乱序。
for (let i = 1; i <28;i++) {
for (let j = 0; j <4;j++) {
//将 筒 条 万不同花色的隔开
if(i<=9){
mjArr.push(i)
}else if(i<=18){
mjArr.push(i+1)
}else if(i<=27){
mjArr.push(i+2)
}
}
}
mjArr = mjArr.sort(()=>0.5 - Math.random())
流程
初始化先从108张中取13,排序摸一张牌
const data = reactive({
mjArr,
selectMj:[], //获取随机的13个
remainMj:[], //除去13个剩余的无序麻将
handMj:[],//手牌,除去杠的牌
footMj:[],//碰或者杠的牌,
isGang:false, //是否可以杠
gangId:'', //杠的id
isCheck:false, //是否胡牌
isNone:'none',//是否展示胡了图片
})
onMounted(()=> {
data.selectMj = mjArr.slice(0, 13)
data.remainMj = mjArr.slice(13)
data.handMj = [...data.selectMj]
data.handMj.sort((a,b )=>a-b)
getNewMj()
})
摸牌后先进行胡牌检测,再是否有杠的检测,按理来说如果有多个杠,是可以进行选择哪一个杠,但是由于时间原因没弄
const getNewMj = ()=> {
data.handMj.push(...data.remainMj.splice(0,1))
checkMj()
//手牌麻将重复数最多的麻将
let max = findNum(data.handMj)
//是否有杠
if(max[0]==4){
//有杠
data.isGang = true
data.gangId = max[1]
}else{
data.isGang = false
}
}
打一张牌再排序,在牌数量不正确时不让打出并提示
//打出一张
const delMj = (index)=> {
if([1,4,7,10,13].includes(data.handMj.length)){
window.alert('请先摸牌')
}else{
data.handMj.splice(index,1)
//摸牌的时候不排序 打出去的时候在排a
handMjSort()
}
}
//判断是否胡牌
const checkMj = ()=> {
let arr = [...data.handMj].sort((a,b )=>a-b)
data.isCheck = isHu(arr)
}
川麻
两种模式其实差别不是很大,可以通过变量判断写到一个页面,但是嫌麻烦所以直接分开写了,川麻不同之处是首先在进入的时候有个蒙层然后选择定缺,之后在胡牌检测前先进行检测是否有花猪,之后的流程基本一样。
//判断是否胡牌(四川模式)
const checkMj = ()=> {
if(checkPig()){
let arr = [...data.handMj].sort((a,b )=>a-b)
data.isCheck = isHu(arr)
}
}
胡
1.先判断是否7对
2.去除一个对牌,将剩余的牌进行ABC/DDD检测,成功后将ABC/DDD删除再进行检测
3.还原牌后去除下一个不同的对牌在进行ABC/DDD
代码太多了就不放上面了。gitee.com/yan_yin/mah… ,参考了 https://gitee.com/w_xd/mahjong-utils ,里面还有各种情况,感兴趣的可以去看看
最后
本是四人游戏却只有一个人自娱自乐,但是初衷就是想让不会的xdm能学会。
做的随意,有什么问题敬请指出
既然都看到这儿了,不妨点个赞再走~