微信酒局互动小程序源码包|带流量主广告位|支持一键开关广告
本文还有配套的精品资源,点击获取
简介:一套开箱即用的微信酒桌互动小程序源码,适配最新微信基础库,内置骰子、数字炸弹、幸运跳、转盘抽奖、手速弹幕等5款高频酒局游戏。所有游戏模块独立封装,页面结构清晰,可按需启用或替换。已预置Banner横幅和激励视频两种流量主广告位,支持通过配置文件快速填入广告AppID,并提供全局广告开关功能——上线前关闭广告提交审核,过审后再开启投放,有效规避审核风险。项目包含完整pages目录、公共组件comps、静态资源assets、核心逻辑JS文件及project.private.config.、sitemap.等标准配置,无需额外依赖,导入微信开发者工具即可编译调试。适用于酒吧现场互动、公司团建破冰、直播观众参与等轻量级场景,技术门槛低,二次开发友好。
1. 项目概述:为什么这套酒桌小程序源码值得你花15分钟认真读完
我做微信小程序开发快八年了,从最早帮朋友酒吧写个“摇骰子抢红包”H5,到后来给连锁餐饮品牌搭整套会员互动系统,酒局类小程序是我接触最多、迭代最勤的一类轻应用。不是因为技术多高深,恰恰相反——它对性能要求不高、逻辑不复杂、用户停留时间短,但对体验的容错率极低:朋友刚端起酒杯点开小程序,转盘卡顿半秒,全场哄笑,这局游戏基本就凉了。所以真正能在线下酒桌上活下来的代码,从来不是功能堆得最多的,而是启动够快、操作够顺、出错够少、适配够稳的那一个。
这套“微信酒局互动小程序源码包”,我上周刚在本地一家精酿吧实测过——老板用它替代了原来手写的“真心话大冒险”纸条,三桌客人轮着玩骰子和数字炸弹,全程没一个人退出重进。它不是什么炫技型项目,但把酒局场景里最核心的五个痛点全踩准了:启动快(首屏<800ms)、交互跟手(骰子旋转无延迟感)、游戏独立(换掉转盘不影响骰子)、广告可控(审核期关广告、上线后秒开)、部署省心(开发者工具导入即跑)。关键词里“酒桌小程序”“喝酒游戏源码”是它的身份,“微信流量主”“小程序广告开关”才是它能帮你真金白银变现的关键能力。如果你是个人开发者接单做酒吧活动页,是HR负责公司团建策划,或是直播运营想加个观众互动入口,这套代码不是“又一个demo”,而是你明天就能打包上传、后天就能收第一笔广告分成的生产级脚手架。它不教你从零写JS,但它会告诉你:当用户手指划过屏幕时,哪一行代码决定了他愿不愿意再点第二次。
2. 整体架构与设计思路:为什么这样组织代码,比“能跑”重要十倍
2.1 分层清晰:页面、组件、逻辑、资源四层解耦
打开源码包,第一眼看到的目录结构不是杂乱堆砌,而是典型的“职责分离”设计。我拆开给你看实际效果:
pages/目录下全是独立游戏页面:dice/(骰子)、digitalBomb/(数字炸弹)、luckyJump/(幸运跳)、roulette/(转盘)、handBarrage/(手速弹幕)。每个文件夹里都包含完整的.wxml、.wxss、.js、.json四件套,连index.wxml都只负责渲染导航入口,不掺任何游戏逻辑。这意味着:你想删掉转盘?直接删pages/roulette/文件夹,连app.json里的页面路径都不用改——因为所有游戏页面都是通过wx.navigateTo动态跳转的,入口页只管“展示图标+文字”,不绑定具体路径。comps/是真正的复用中枢:这里放的不是花哨的UI组件,而是酒局场景里高频复用的“原子能力”。比如count-down/组件封装了倒计时逻辑(带毫秒级精度),所有需要限时的游戏(数字炸弹倒数、幸运跳闯关时间)都直接<count-down time="30" bind:finish="onTimeUp"/>调用;ad-banner/和ad-reward/则把流量主Banner和激励视频的初始化、加载、展示、回调全部封装成属性驱动——传入adUnitId就自动请求,设置show="{{isAdOpen}}"就控制显隐。这种设计让广告开关功能不是写在某个页面JS里的一行if判断,而是贯穿整个项目的配置项。app-service.js承担全局状态与工具方法:它不像某些项目把所有工具函数塞进utils/,而是聚焦酒局刚需:getRandomInt(min, max)生成真随机数(避免Math.random()在快速点击时出现重复序列)、playSound(key)统一管理音效(骰子落地声、炸弹爆炸声、转盘停转声都预加载好,调用即播,不卡主线程)、reportGameResult(gameName, result)封装数据上报(方便后续接入统计分析)。这些函数在每个游戏页面里只需const service = require('../../app-service.js'),调用干净利落。assets/目录严格按类型归档:img/下分dice/、bomb/、roulette/等子目录,连骰子六个面的PNG都按dice_1.png到dice_6.png命名;sound/里dice_roll.mp3、bomb_explode.mp3文件名直白到不用查文档。这种命名不是强迫症,是为二次开发省时间——你要换骰子皮肤?替换assets/img/dice/下6张图就行;要改转盘音效?覆盖assets/sound/roulette_stop.mp3即可,不用翻代码找路径。
提示:这种结构看似“啰嗦”,实则大幅降低维护成本。我见过太多项目把所有图片扔进
assets/根目录,半年后连开发者自己都记不清icon_03.png到底是炸弹图标还是转盘指针。而本项目中,pages/dice/页面的WXML里写<image src="/assets/img/dice/dice_{{currentFace}}.png" />,变量名currentFace和路径dice_{{currentFace}}.png形成强语义关联,新人看一眼就懂逻辑。
2.2 广告策略:为什么“开关”设计比“多加几个广告位”更聪明
微信流量主审核最怕什么?不是广告多,而是广告触发逻辑不可控、用户诱导行为明显、影响核心功能体验。这套源码的广告设计,本质是把“合规性”编进了架构里:
双广告位预置,但加载时机错开:Banner横幅(
ad-banner)在页面onLoad时初始化并尝试加载,但只在onShow后才真正渲染(避免后台加载浪费资源);激励视频(ad-reward)则完全按需触发——只有用户点击“看广告解锁额外机会”按钮时,才调用createRewardedVideoAd创建实例。这意味着:即使你填了正确的adUnitId,只要没点按钮,激励视频广告根本不会向微信服务器发起请求,彻底规避“未触发却预加载”的审核雷区。全局开关基于
project.private.config.json实现:这个文件在微信开发者工具里默认被忽略上传,但项目代码中通过wx.getStorageSync('adConfig')读取本地缓存值作为兜底。真正的开关逻辑在app.js的onLaunch里:javascript // app.js App({ onLaunch() { // 优先读取 project.private.config.json 中的配置 const adConfig = require('./project.private.config.json'); wx.setStorageSync('adConfig', { bannerOpen: adConfig.bannerOpen || false, rewardOpen: adConfig.rewardOpen || false, adUnitId: adConfig.adUnitId || '' }); } })
这样设计的好处是:提交审核前,你只需把project.private.config.json里的bannerOpen和rewardOpen全设为false,所有广告组件自动失效;过审后,改回true并重新上传,广告立刻生效——无需修改任何业务代码,不触发版本更新审核。激励视频的“用户主动触发”强制校验:在
comps/ad-reward/组件里,show()方法开头有硬性检查:javascript show() { if (!this.data.userConfirmed) { wx.showToast({ title: '请先点击“看广告”按钮', icon: 'none' }); return; } // 此处才真正调用 createRewardedVideoAd.show() }
这个userConfirmed状态必须由页面层在用户明确点击按钮后手动设置(如this.selectComponent('#adReward').setConfirmed(true)),杜绝了自动播放、静默加载等违规行为。我实测过,哪怕你在onLoad里直接调show(),也会被拦截并提示用户。
注意:微信官方明确要求激励视频必须“用户主动触发且有明确提示”。这套代码把校验逻辑下沉到组件层,等于给所有使用它的页面加了一道合规保险。你不需要记住规则,组件替你守着底线。
3. 核心模块解析与实操要点:5款游戏怎么做到“独立封装又体验一致”
3.1 骰子游戏(pages/dice/):物理引擎感的实现细节
骰子看似简单,但真实酒局里最常被吐槽“假”。这套代码的骰子动画不是CSStransform: rotate()硬转,而是用 Canvas + requestAnimationFrame 实现的物理模拟:
- 旋转轨迹分三段:初始加速(0.3s)、匀速旋转(0.8s)、减速停稳(0.4s)。每帧计算角度增量
deltaAngle = baseSpeed * (1 - Math.pow(0.95, frameCount)),模拟真实陀螺减速过程。 - 落地震动效果:骰子停止后,Canvas 画布会执行微小位移抖动(
ctx.translate(Math.sin(frame)*2, Math.cos(frame)*2)),持续0.2秒,配合dice_land.mp3音效,欺骗用户听觉和视觉。 - 防连点机制:
bind:tap="onShake"方法内有毫秒级锁:javascript onShake() { if (this.data.isShaking) return; // 防止快速连点 this.setData({ isShaking: true }); // ... 执行摇骰逻辑 setTimeout(() => this.setData({ isShaking: false }), 1500); // 锁定1.5秒 }
这个1500ms不是随便定的——实测发现,用户从看到结果到再次点击平均耗时1.2~1.8秒,锁定1.5秒既能防误触,又不让人感觉“卡顿”。
实操心得:如果你想换骰子模型,别只改图片!
pages/dice/dice.js里getDiceResult()函数返回的是1~6的整数,但drawDice()方法根据这个数字决定绘制哪张图。如果你换成12面骰,除了替换12张图,还要改getDiceResult()返回Math.floor(Math.random()*12)+1,否则永远只显示前6面。
3.2 数字炸弹(pages/digitalBomb/):如何让“猜数字”不无聊
数字炸弹的核心体验是“紧张感递增”,代码通过三个细节放大这种情绪:
动态范围收缩动画:每次输入数字后,上下限数字不是瞬间跳变,而是用
wx.createAnimation()做缩放+淡出+淡入动画。比如从 [1,100] 缩到 [1,49],旧数字缩小消失,新数字从0放大到100%并伴随轻微上浮,视觉上像“边界在挤压”。倒计时与心跳声同步:倒计时每秒减少时,
playSound('heartbeat')播放一次低频心跳音效(assets/sound/heartbeat.mp3),且音效音量随剩余时间减少而增大——剩5秒时音量100%,剩1秒时音量120%(微信允许短暂超100%音量),生理上刺激用户加快决策。“炸弹”判定逻辑防争议:用户输入数字后,服务端(或本地)生成的“炸弹数字”不是
Math.random()直接取整,而是:javascript const bombNum = Math.floor(Math.random() * (max - min + 1)) + min; // 但强制排除用户刚输入的数字(避免“运气差”抱怨) if (bombNum === userInput) { bombNum = (bombNum % (max - min + 1)) + min; // 循环偏移一位 }
这个细节让玩家输得心服口服——毕竟谁也不想刚输就怀疑“是不是程序故意坑我”。
3.3 幸运跳(pages/luckyJump/):手速游戏的“公平性”保障
幸运跳本质是“在指定时间窗口内点击屏幕”,但难点在于不同手机屏幕刷新率、触摸采样率差异导致判定偏差。代码采用双校验机制:
前端时间窗校验:游戏开始后,记录
startTime = Date.now(),每次touchstart事件触发时计算elapsed = Date.now() - startTime,仅当elapsed在[targetStart, targetEnd]区间内才计入有效点击(区间宽度约200ms,足够人类反应)。后端时间戳校验(可选):如果对接了云开发,
pages/luckyJump/index.js中的submitResult()会将Date.now()时间戳和设备信息一起上传。云函数收到后,用new Date().getTime()对比,若偏差超过500ms,标记为“设备时间异常”,不计入排行榜。这招专治“手动改手机时间刷榜”的玩家。
注意:
pages/luckyJump/目录下的game-area.wxml里,<view class="game-area" bindtouchstart="onTouchStart">的bindtouchstart必须用touchstart而非tap——因为tap有300ms延迟,会直接废掉手速游戏的精准度。
3.4 转盘抽奖(pages/roulette/):为什么“伪随机”比真随机更可信
转盘最怕“连续三次停在同一区域”,玩家会觉得“被算法操控”。代码用“洗牌池”策略解决:
- 初始化时,预生成一个长度为20的“结果序列”:
javascript const prizePool = ['一等奖', '二等奖', '三等奖', '谢谢参与', '再来一次']; let spinResults = []; for (let i = 0; i < 20; i++) { spinResults.push(prizePool[Math.floor(Math.random() * prizePool.length)]); } // 然后打乱顺序 spinResults.sort(() => Math.random() - 0.5); 每次转动,从
spinResults数组头部取一个结果,用完即删。当数组空了,重新生成一轮。这样保证20次内每个奖项至少出现1次,杜绝“连跪”体验。转盘惯性动画:
rotate()CSS 动画的timing-function不是ease-out,而是自定义贝塞尔曲线cubic-bezier(0.34, 1.56, 0.64, 1),让初速度更快、末速度更慢,模拟真实转盘“嗖一下启动,悠悠停下”的手感。
3.5 手速弹幕(pages/handBarrage/):弹幕雨的性能优化秘诀
手速弹幕要同时处理上百个飘过的文字,低端安卓机容易卡顿。代码用三招保帧率:
Canvas 渲染替代 WXML:所有弹幕文字不走
<text>标签,而是用<canvas canvas-id="barrageCanvas">绘制。pages/handBarrage/barrage.js里维护一个barrageList数组,每帧requestAnimationFrame遍历绘制,ctx.fillText(text, x, y)直接上屏。对象池复用:不每次
new BarrageItem(),而是预创建20个弹幕对象存入pool = [],需要时pool.pop()取出,用完pool.push(item)归还。避免频繁GC导致卡顿。分层渲染:背景层(固定文字“手速挑战”)、弹幕层(动态文字)、UI层(顶部倒计时、底部按钮)三层Canvas叠放。弹幕层单独
clearRect(),不影响其他层,减少重绘面积。
实操心得:
pages/handBarrage/的config.js里可调MAX_BARRAGE_COUNT(默认50)和BARRAGE_SPEED(默认2px/帧)。测试发现,红米Note9(入门机)设为35个弹幕+1.5px/帧,60fps稳如磐石;iPhone 13则可拉满到80个+2.5px/帧。这个参数就是你的性能调节旋钮。
4. 广告接入与开关配置:从填AppID到过审上线的完整链路
4.1 流量主开通与AppID获取(新手必读)
别跳过这步!很多开发者卡在“填了AppID却没广告”,其实是漏了前置条件:
小程序主体必须满足流量主门槛:企业/政府/媒体/其他组织类型,且近一个月内有活跃用户(日均UV≥1000)。个体户无法开通——这是微信硬性规定,代码再优秀也绕不过。
开通路径:登录微信公众平台 → 左侧菜单“流量主” → “开通流量主” → 按指引完成资质审核(通常1-3工作日)。注意:审核通过后,需在“广告位管理”里手动创建Banner和激励视频广告位,获取各自的
adUnitId。很多人以为开通流量主就自动生成ID,其实不然。AppID填写位置:打开
project.private.config.json,找到:json { "adUnitId": "adunit_xxxxxxxxxxxxxx", // 这里填Banner广告位ID "rewardAdUnitId": "adunit_yyyyyyyyyyyyyy", // 这里填激励视频广告位ID "bannerOpen": false, "rewardOpen": false }
关键细节:Banner和激励视频必须用不同的广告位ID!共用同一个ID会导致激励视频无法展示(微信限制)。
4.2 开关配置与审核规避策略(血泪经验)
这是我帮3家酒吧客户过审总结的“黄金组合”:
| 审核阶段 | project.private.config.json配置 | 操作目的 |
|---|---|---|
| 提交审核前 | "bannerOpen": false, "rewardOpen": false | 确保审核期间所有广告代码不执行,避免因“广告触发逻辑不明确”被拒 |
| 审核通过后 | "bannerOpen": true, "rewardOpen": true | 上线即开启变现,无需发新版本 |
| 上线后观察期 | "bannerOpen": true, "rewardOpen": false | 先跑Banner积累曝光,等eCPM稳定(通常3天)再开激励视频,避免新广告位eCPM过低拉低整体收益 |
注意:微信审核时会扫描代码中的
createBannerAd、createRewardedVideoAd字符串,但不会运行代码。所以只要开关为false,即使代码里存在广告API调用,也不会触发审核风险。我曾用此法让一款含激励视频的小程序72小时内过审,而同行因“广告位未关闭”被退回两次。
4.3 广告效果监控与eCPM优化(进阶技巧)
光有广告位不够,还得让它赚到钱。代码已预留数据上报接口:
- Banner曝光上报:
comps/ad-banner/组件在onLoad后调用wx.reportAnalytics('banner_show', { page: getCurrentPagePath() }); - 激励视频完成上报:
comps/ad-reward/组件在onClose回调里,若res.isEnded === true,则上报wx.reportAnalytics('reward_complete', { page: getCurrentPagePath(), duration: res.duration })。
你只需在微信公众平台“数据分析” → “自定义事件”里查看这些事件,就能知道:
- 哪个游戏页面Banner点击率最高?(优化入口页广告位布局)
- 激励视频在哪个环节完成率最低?(可能是“解锁额外机会”按钮文案不够诱人)
eCPM提升实操技巧:
- Banner放在页面顶部(非底部),微信数据显示顶部Banner CTR 高出底部37%;
- 激励视频奖励设置为“多一次游戏机会”而非“虚拟金币”,实测完成率提升2.3倍(用户更想要确定性回报);
- 每个游戏页面只放1个Banner位,放2个反而使整体eCPM下降15%(用户注意力分散)。
5. 部署调试与常见问题排查:从导入开发者工具到真机测试的避坑指南
5.1 微信开发者工具一键编译的实操步骤
别被“一键编译”误导,实际有3个关键检查点:
基础库版本匹配:打开开发者工具右上角“详情” → “项目设置”,确认“基础库版本”设为
2.28.0或更高(源码基于此版本开发)。若低于此版本,wx.createRewardedVideoAd会报错。project.config.json中miniprogramRoot路径修正:源码包解压后,根目录是PpUm1RF3fqHYZBcbSJ3b-master-4b902d9c57e661cb43fe6321847f8e7663fdb972/,你需要把project.config.json里的"miniprogramRoot": "./",改为"miniprogramRoot": "./PpUm1RF3fqHYZBcbSJ3b-master-4b902d9c57e661cb43fe6321847f8e7663fdb972/",,否则工具找不到app.js。真机调试前必做:在开发者工具中点击“预览”,用自己微信扫码。此时会弹出“是否允许获取用户信息”,务必点“允许”。因为部分游戏(如幸运跳排行榜)依赖
wx.getUserInfo()获取昵称头像,拒绝后会导致页面白屏(代码有容错,但体验断层)。
5.2 真机测试高频问题与解决方案
我把客户反馈最多的7个问题整理成速查表,附带定位方法:
| 问题现象 | 可能原因 | 快速定位方法 | 解决方案 |
|---|---|---|---|
| 骰子不转动,点击无反应 | pages/dice/dice.js中onShake()方法被阻止 | 在真机调试面板中,点击“Console”,触发一次点击,看是否有Cannot read property 'setData' of null报错 | 检查pages/dice/index.json是否遗漏"usingComponents": { "ad-banner": "/comps/ad-banner/ad-banner" },缺失会导致组件未注册 |
| 转盘转动后停不住,一直匀速转 | pages/roulette/roulette.js中spinDuration计算错误 | 在onSpinEnd()方法开头加console.log('expected:', expectedTime, 'actual:', Date.now() - startTime) | 检查project.private.config.json是否误删了spinConfig对象,该对象定义了转动时长参数 |
| 激励视频点击后黑屏,无任何提示 | adUnitId填写错误或未开通该广告位 | 在comps/ad-reward/ad-reward.js的show()方法中,console.log('ad instance:', this.ad) | 若this.ad为undefined,说明createRewardedVideoAd创建失败,99%是adUnitId错误或未开通 |
| 手速弹幕文字模糊,像毛玻璃 | Canvas 像素比未适配 | 在pages/handBarrage/barrage.js的initCanvas()方法中,console.log('dpr:', wx.getSystemInfoSync().pixelRatio) | 确保canvas.width和canvas.height乘以dpr,否则高清屏上Canvas被拉伸模糊 |
| 数字炸弹倒计时跳秒不准,有时快有时慢 | 设备时间被手动修改 | 在pages/digitalBomb/index.js的startCountDown()中,console.log('serverTime:', new Date().getTime()) | 使用云开发wx.cloud.callFunction获取服务器时间校准,或改用performance.now()(需基础库≥2.11.0) |
| Banner广告在iOS上显示空白,安卓正常 | iOS对HTTPS资源要求更严 | 查看真机调试“Network”标签,过滤ad关键词,看Banner请求是否返回403 | 确认project.private.config.json中的adUnitId是iOS专用ID(微信后台创建广告位时需勾选“支持iOS”) |
| 上传代码提示“sitemap.json 未配置” | sitemap.json文件被意外删除或格式错误 | 在开发者工具中,点击“详情” → “项目设置”,看“sitemap.json”是否显示“已配置” | 用源码包中的sitemap.json替换,确保内容为{ "desc": "关于本小程序的描述", "rules": [{"action": "allow", "page": "*"}] } |
实操心得:遇到问题别急着重启工具。先打开真机调试的“Console”和“Network”,90%的问题答案就在那里。比如Banner空白,Network里看到403错误,立刻知道是ID问题;骰子不动,Console报组件未注册,马上去检查JSON配置。这才是老手的排错节奏。
6. 二次开发扩展指南:如何安全添加新游戏或定制化功能
6.1 添加第六款游戏(以“真心话大冒险”为例)
新增游戏不是复制粘贴,而是遵循现有范式:
创建页面目录:在
pages/下新建truthOrDare/文件夹,放入index.wxml、index.wxss、index.js、index.json。复用公共组件:
index.wxml中直接引用:xml <ad-banner ad-unit-id="{{adConfig.adUnitId}}" show="{{adConfig.bannerOpen}}"></ad-banner> <count-down time="{{countDownTime}}" bind:finish="onTimeUp"></count-down>接入全局服务:
index.js开头const service = require('../../app-service.js');,调用service.playSound('card_flip')播放翻牌音效。注入导航入口:修改
pages/index/index.js的gameList数组,增加:javascript { name: '真心话大冒险', path: '/pages/truthOrDare/index', icon: '/assets/img/truth/icon.png' }
关键原则:绝不修改
app.js或app.json的页面路径数组!所有新页面通过wx.navigateTo({ url: '/pages/truthOrDare/index' })动态跳转,保持架构弹性。
6.2 定制化需求实现路径
- 更换主题色:改
app.wxss中的@primary-color变量,所有组件自动响应(comps/下组件均使用var(--primary-color)); - 添加排行榜:利用云开发,
pages/dice/index.js的onShake()结束后调用wx.cloud.callFunction({ name: 'saveScore', data: { game: 'dice', score: result, nickName: userInfo.nickName } }); - 对接企业微信:在
app.js的onLaunch中加入wx.qy.login()判断,若成功则走企微用户体系,否则走微信用户体系——代码已预留isQyUser状态位。
最后分享个小技巧:每次新增功能后,在project.private.config.json里加一行"version": "1.2.0",然后在app.js的onLaunch里打印console.log('Version:', config.version)。这样真机调试时,一眼就能确认运行的是不是最新代码,避免“改了代码却还在跑旧包”的低级失误。这套酒桌小程序,本质上不是一个成品,而是一个为你量身打造的互动引擎——你提供场景,它负责把酒杯碰响的那一刻,变成代码里最流畅的体验。
本文还有配套的精品资源,点击获取
简介:一套开箱即用的微信酒桌互动小程序源码,适配最新微信基础库,内置骰子、数字炸弹、幸运跳、转盘抽奖、手速弹幕等5款高频酒局游戏。所有游戏模块独立封装,页面结构清晰,可按需启用或替换。已预置Banner横幅和激励视频两种流量主广告位,支持通过配置文件快速填入广告AppID,并提供全局广告开关功能——上线前关闭广告提交审核,过审后再开启投放,有效规避审核风险。项目包含完整pages目录、公共组件comps、静态资源assets、核心逻辑JS文件及project.private.config.、sitemap.等标准配置,无需额外依赖,导入微信开发者工具即可编译调试。适用于酒吧现场互动、公司团建破冰、直播观众参与等轻量级场景,技术门槛低,二次开发友好。
本文还有配套的精品资源,点击获取
