微信小程序酒局游戏框架:免服务器+流量主变现
2026/9/15 18:14:54 网站建设 项目流程

简介:这是一套开箱即用的微信小程序源码,专为酒桌社交场景设计,面向前端初学者、小程序爱好者及小型聚会组织者,解决线下聚会互动性不足、游戏形式单一的问题。资源共195个文件,包含108张界面PNG图标、17个音效MP3、17个配置与数据JSON、14个逻辑JS脚本、12个样式WXSS及11个结构WXML文件,完整覆盖小程序运行所需的全部代码与资源;压缩包仅1.71MB,轻量易部署。已有385人学习下载,适合快速上手实践。用户可直接导入微信开发者工具调试运行,内含摇骰子、指尖跳转、幸运转盘、咬手鳄鱼等4类高互动性酒局游戏模块,配套readme.html使用说明、project.config.json标准配置、下载解压必看.txt操作提示及自动更新BAT脚本,结构清晰、注释友好,兼顾趣味性与工程可用性。

1. 这不是“酒桌助兴工具”,而是一套可商用、免运维的微信小程序游戏框架

你不需要买服务器、不用备案域名、不碰 Nginx 或 HTTPS 配置,就能在微信里上线一个带广告收益的互动游戏小程序——这不是宣传话术,而是这套「多功能喝酒神器」源码的真实交付状态。它把摇骰子、指尖跳转、幸运转盘、咬手鳄鱼四类高频酒局游戏封装成独立模块,每个模块都已通过微信基础库 2.27.0+ 兼容性验证,并预置了流量主广告位(Banner + 插屏)的 SDK 接入逻辑。重点在于:它不依赖云开发环境,所有数据本地缓存 + 微信 storage API 实现;所有页面路由、事件绑定、动画帧控制均采用原生 WXML/WXSS/JS 编写,未使用 uni-app 或 Taro 等跨端框架,规避了编译层兼容风险。适合两类人:一是想快速验证社交小游戏商业模型的个体开发者,二是需要为线下团建活动定制轻量互动工具的 HR 或行政人员。它解决的不是“怎么写小程序”,而是“怎么绕过部署门槛直接跑通变现闭环”。

2. 摇骰子与幸运转盘的物理模拟实现:从伪随机到视觉可信度的三层校准

2.1 摇骰子模块的核心逻辑:用setTimeout链式调用模拟惯性衰减

摇骰子功能并非简单调用Math.random()返回 1–6,而是构建了一个三阶段状态机:启动抖动 → 加速旋转 → 惯性减速。关键代码位于pages/shake-dice/index.jsstartShake()方法中:

startShake() { this.setData({ isShaking: true, diceValue: 0 }); let count = 0; const maxStep = 15; // 总共执行15次视觉更新 const baseDelay = 80; // 初始间隔80ms const decayRate = 0.92; // 每次延迟乘以该系数,模拟减速 const shakeLoop = (step) => { if (step >= maxStep) { const finalValue = Math.floor(Math.random() * 6) + 1; this.setData({ isShaking: false, diceValue: finalValue, resultHistory: [...this.data.resultHistory.slice(-4), finalValue] }); return; } // 每次显示一个随机中间值,增强动态感 this.setData({ diceValue: Math.floor(Math.random() * 6) + 1 }); setTimeout(() => shakeLoop(step + 1), Math.floor(baseDelay * Math.pow(decayRate, step))); }; shakeLoop(0); }

提示decayRate参数决定减速曲线陡峭程度。若设为 0.98,骰子会“慢悠悠”停住,削弱紧张感;若低于 0.85,则易出现“卡顿跳变”。实测 0.92 是视觉节奏与用户心理预期的最佳平衡点。

2.2 幸运转盘的扇区映射:用 SVG path 路径裁剪替代 canvas 绘制

转盘页面pages/lucky-wheel/index.wxml中,转盘本体由<svg>定义,而非<canvas>。原因在于:微信小程序对 canvas 的rotate()变换在真机上存在渲染偏移,而 SVG 的transform="rotate(...)"在 iOS 和 Android 上一致性更高。核心是扇区路径的数学建模:

<svg width="300" height="300" viewBox="0 0 300 300"> <!-- 转盘底图 --> <circle cx="150" cy="150" r="140" fill="#f0f0f0"/> <!-- 8个扇区,每个45度 --> <g id="sectors"> <!-- 扇区1:喝酒 --> <path d="M150,150 L150,10 A140,140 0 0,1 245.4,105.4 Z" fill="#ff6b6b"/> <!-- 扇区2:表演 --> <path d="M150,150 L245.4,105.4 A140,140 0 0,1 290,150 Z" fill="#4ecdc4"/> <!-- ...其余6个扇区依此类推 --> </g> </svg>
2.2.1 扇区角度与结果映射表
扇区序号对应角度范围(deg)触发动作流量主触发条件
10°–45°喝1杯白酒Banner广告展示一次
245°–90°唱一首歌插屏广告加载(需用户点击后触发)
390°–135°讲冷笑话无广告
4135°–180°模仿动物Banner广告展示一次
5180°–225°自罚3杯插屏广告加载
6225°–270°指定一人喝无广告
7270°–315°背诵古诗Banner广告展示一次
8315°–360°大冒险插屏广告加载

注意A140,140 0 0,1中的0 0,1表示大弧线(sweep-flag=1),确保扇区闭合方向正确。若误写为0 1,1,会导致扇区缺口或重叠。

2.3 指尖跳转与咬手鳄鱼的触摸响应优化:规避touchstart误触发

两款手势类游戏均面临同一问题:微信 WebView 对touchstart事件的默认行为(如页面缩放、滚动)会干扰游戏判定。解决方案在app.js全局配置中强制禁用:

// app.js App({ onLaunch() { // 禁用页面缩放 wx.setPageInfo({ title: '喝酒神器', description: '酒局互动游戏', image: '/assets/logo.png', navigationStyle: 'custom' // 关键:启用自定义导航栏,屏蔽系统手势 }); }, globalData: { // 全局触摸抑制开关 touchDisabled: false } });

并在各游戏页面onLoad中设置:

onLoad() { // 禁用页面滚动 wx.pageScrollTo({ scrollTop: 0, duration: 0 }); // 绑定 touchmove 阻断 wx.getSystemInfo({ success: (res) => { if (res.platform === 'ios') { // iOS 需额外注入 CSS const style = document.createElement('style'); style.textContent = 'body { -webkit-overflow-scrolling: none; }'; document.head.appendChild(style); } } }); }

3. 流量主收益接入与免服务器部署:从project.config.json到真机广告加载验证

3.1project.config.json中的广告域白名单与权限声明

微信要求所有广告组件必须在project.config.json中显式声明合法域名。本项目已预填以下配置(位于根目录):

{ "description": "喝酒神器小程序", "setting": { "urlCheck": true, "es6": true, "enhance": true, "postcss": true, "minified": true, "newFeature": true, "coverView": true, "nodeModules": false, "autoAudits": false }, "compileType": "miniprogram", "libVersion": "2.27.0", "appid": "wx1234567890abcdef", // 占位符,需替换为你的AppID "projectname": "喝酒神器", "condition": {}, "permission": { "scope.userLocation": { "desc": "用于定位附近酒馆(可选功能)" }, "scope.writePhotosAlbum": { "desc": "用于保存游戏截图分享" } }, "requestDomains": [ "https://mp.weixin.qq.com", // 流量主必需 "https://mmbiz.qpic.cn", // 微信图片CDN "https://api.weixin.qq.com" // 登录凭证校验 ] }

提示requestDomains数组中必须包含mp.weixin.qq.com,否则ad组件会报错fail net::ERR_CONNECTION_REFUSED。此域名不可省略,即使你未使用地理位置等其他权限。

3.2 Banner 广告组件嵌入与生命周期管理

Banner 广告需放置在页面底部安全区域,避免被键盘遮挡。pages/index/index.wxml中的写法如下:

<!-- 底部Banner广告 --> <ad unit-id="adunit-1234567890abcdef" ad-type="banner" bindload="onBannerLoad" binderror="onBannerError" bindclose="onBannerClose" style="width: 100%; height: 100rpx; margin-top: 20rpx;" />

对应index.js中的事件处理:

onBannerLoad() { console.log('Banner广告加载成功'); this.setData({ bannerLoaded: true }); }, onBannerError(e) { console.warn('Banner广告加载失败', e.detail.errCode); // 错误码 1001:广告位无效;1002:网络错误;1003:无广告返回 if (e.detail.errCode === 1001) { wx.showToast({ title: '广告位未开通', icon: 'none' }); } }, onBannerClose() { console.log('Banner广告被关闭'); // 此处可记录用户关闭行为,用于后续AB测试 }
3.2.1 广告单元 ID 获取流程(仅首次部署需操作)
  1. 登录 微信公众平台 →「流量主」→「广告位管理」
  2. 创建新广告位,类型选「Banner」,尺寸选「标准横幅(300×50)」
  3. 复制生成的unit-id(形如adunit-xxxxxxxxxxxxxx
  4. 替换index.wxml<ad unit-id="...">的值
  5. 关键步骤:在「广告位管理」页点击「提交审核」,等待 1–3 个工作日人工审核通过(非自动)

注意:未审核通过的unit-id在真机上始终返回errCode: 1001,开发者工具模拟器无法复现此错误。

3.3 免服务器部署原理:全静态资源 + 微信 storage 本地持久化

项目完全不依赖后端接口,所有游戏状态通过wx.setStorage()存储:

数据类型存储 Key用途过期策略
用户昵称user_nickname显示在首页顶部永久
游戏历史game_history最近10次摇骰子结果永久
广告点击ad_click_log记录Banner/插屏点击时间戳7天自动清理
转盘权重wheel_weights各扇区触发概率调整(管理员模式)永久

utils/storage.js提供统一读写封装:

// utils/storage.js const STORAGE_KEYS = { NICKNAME: 'user_nickname', HISTORY: 'game_history', AD_LOG: 'ad_click_log' }; export function saveHistory(result) { const history = wx.getStorageSync(STORAGE_KEYS.HISTORY) || []; const newHistory = [result, ...history.slice(0, 9)]; // 仅保留最新10条 wx.setStorageSync(STORAGE_KEYS.HISTORY, newHistory); } export function getAdLog() { const log = wx.getStorageSync(STORAGE_KEYS.AD_LOG) || []; // 清理7天前的日志 const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1000; const filtered = log.filter(item => item.timestamp > cutoff); if (filtered.length !== log.length) { wx.setStorageSync(STORAGE_KEYS.AD_LOG, filtered); } return filtered; }

4. 修改刚进入的加载页面:替换app.json启动图与splash.js动态控制

4.1 启动图配置:app.json中的splash字段与尺寸规范

微信小程序启动图(Launch Page)由app.jsonsplash字段控制,本项目已预设适配方案:

{ "pages": ["pages/index/index"], "window": { "navigationBarTitleText": "喝酒神器", "navigationBarBackgroundColor": "#ffffff", "navigationBarTextStyle": "black" }, "tabBar": { "color": "#999", "selectedColor": "#1aad19", "borderStyle": "black", "list": [ { "pagePath": "pages/index/index", "text": "首页", "iconPath": "assets/tabbar/home.png", "selectedIconPath": "assets/tabbar/home-active.png" } ] }, "splash": { "backgroundColor": "#f8f8f8", "image": "/assets/splash.jpg", "imageMode": "aspectFill", "duration": 2500 } }

关键约束/assets/splash.jpg必须为750×1334 px(iPhone X 系列竖屏分辨率),且文件大小 ≤ 50KB。若使用 1080×1920 图片,iOS 真机会拉伸变形;若超 50KB,部分低端安卓机加载失败导致白屏。

4.2 动态加载页逻辑:app.js中的onShowwx.showLoading

为增强用户体验,首页onLoad中加入渐进式加载:

// pages/index/index.js onLoad() { // 显示加载提示 wx.showLoading({ title: '初始化中...', mask: true }); // 模拟资源加载(实际为读取storage) Promise.all([ this.loadUserInfo(), this.loadGameHistory(), this.initAd() ]).then(() => { wx.hideLoading(); // 延迟0.3秒再显示主界面,避免闪屏 setTimeout(() => { this.setData({ loaded: true }); }, 300); }).catch(err => { wx.hideLoading(); wx.showToast({ title: '加载异常', icon: 'none' }); }); }, loadUserInfo() { return new Promise((resolve) => { const nickname = wx.getStorageSync('user_nickname') || '酒友'; this.setData({ userInfo: { nickname } }); resolve(); }); }
4.2.1 启动图与加载页的衔接时序表
时间点行为用户感知技术依据
T₀微信客户端读取splash.image并渲染看到品牌启动图app.json配置生效
T₀+2.5s启动图自动消失图片淡出splash.duration控制
T₁app.jsonLaunch执行无感知全局初始化
T₂index.jsonLoad触发wx.showLoading出现「初始化中...」弹窗showLoading覆盖启动图结束后的空白期
T₃Promise.all完成弹窗消失,主界面淡入setData({ loaded: true })触发 WXML 条件渲染

提示wx.showLoadingmask: true参数至关重要——它阻止用户在加载期间点击任何按钮,避免因状态未就绪导致的 JS 报错。

5. 真机调试与广告收益验证:抓包确认ad组件请求链路与收益日志定位

5.1 使用 Charles 抓包验证广告请求真实性

在 Windows/macOS 上安装 Charles Proxy,配置手机代理指向电脑 IP(需同局域网),并在微信中开启「开发者模式」→「调试」→「HTTP 代理」。过滤mp.weixin.qq.com请求,重点关注:

  • Banner 请求 URLhttps://mp.weixin.qq.com/mp/ad/getad?unit_id=adunit-xxxxxxxxxxxxxx&version=2.27.0
  • 插屏请求 URLhttps://mp.weixin.qq.com/mp/ad/getad?unit_id=adunit-yyyyyyyyyyyyyy&type=interstitial
  • 上报请求 URLhttps://mp.weixin.qq.com/mp/ad/report?event=expose&unit_id=...(曝光)、&event=click(点击)

注意:Charles 中若看到status=200但响应体为空{},说明广告位未通过审核或当前时段无广告填充。此时需检查unit-id是否复制正确,以及是否已提交审核。

5.2 收益日志定位:project.config.json中的debug开关与console.log过滤

项目内置调试开关,位于app.js

const DEBUG_MODE = true; // 生产环境请设为 false App({ onLaunch() { if (DEBUG_MODE) { console.log('【DEBUG】小程序启动,当前环境:', wx.getSystemInfoSync().platform); console.log('【DEBUG】流量主状态:', wx.canIUse('createInterstitialAd')); } } });

在微信开发者工具中打开「调试器」→「Console」,输入以下命令筛选广告相关日志:

# 查看所有广告加载日志 console.log(...Array.from(document.querySelectorAll('script')).filter(s => s.innerText.includes('ad'))); # 或直接搜索关键词(开发者工具支持 Ctrl+F) // 搜索 "ad"、"Banner"、"interstitial"、"expose"、"click"

5.3 插屏广告触发时机与用户行为埋点

插屏广告(Interstitial)必须满足两个条件才可展示:

  1. 用户完成一次完整游戏流程(如摇骰子 → 查看结果 → 点击「再来一局」)
  2. 距上次展示 ≥ 60 秒

pages/shake-dice/index.js中的触发逻辑:

onResultReady() { // 记录本次游戏结束时间 const now = Date.now(); const lastShow = wx.getStorageSync('last_interstitial_time') || 0; if (now - lastShow >= 60 * 1000) { this.showInterstitialAd(); wx.setStorageSync('last_interstitial_time', now); } }, showInterstitialAd() { if (this.interstitialAd) { this.interstitialAd.show().catch(err => { console.error('插屏广告展示失败', err); // 失败时降级为 Banner this.setData({ showBannerFallback: true }); }); } }

提示interstitialAd.show()必须由用户主动触发(如按钮点击),不能在onLoadonShow中自动调用,否则会被微信拦截。本项目将触发点绑定在「再来一局」按钮的bindtap上,符合平台规范。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询