开源小程序精选-单词天天斗
我最近在做二人对战模式答题,体验了不少小程序,找到一个开源的,现推荐给大家
小程序代码地址
https://github.com/arleyGuoLei/wx-words-pk
单词天天斗
微信小程序云开发实现的单词PK小程序,支持好友对战、随机匹配、人机模式,完整代码 ~ UI可以披靡市场上所有同类型小程序,体验也是一流的哦 ~ 目前已经有同学在QQ小程序、阿里小程序部署;也有同学修改成了公务员题库 ~ 期待看到各类优秀产品上线哦 ~
上线说明: 源码开源,但上线需要经过作者许可哦 ~ 开发不易、创作不易。
在线体验
UI截图
需求概述
单词对战模式
对战业务需求解析
单词对战的游戏核心为:随机生成一定数量的单词列表的单选题类型题目,题目文本为该单词,有 4 个随机中文释义的选项,其中仅有一个为正确释义,双方用户一起选择释义,正确率高且速度快的用户获得对战胜利。
单词对战游戏分为好友对战、随机匹配、人机对战三种对战的形式,均通过上述游戏核心的方式进行对战。
对战设置
用户还可以对以下对战信息进行自定义设置
- 对战的单词书,用户可以选择自己想要背诵的单词类型,包含四级核心词、四级大纲词、六级核心词、六级大纲词、考研真题核心词、考研大纲词、小学必备词、中考大纲词、高考大纲词、雅思大纲词、商务词汇等多种单词书,亦可以选择随机单词书模式,则将从所有的单词中进行随机抽取;
- 设置每一局对战的单词数目为以下任意一种:8、 10(默认)、 12、 15、 20
- 设置切换下一题是否自动播放单词发音
- 设置错词是否加入到生词本
- 开始和错词的时候是否震动
- 设置默认是否播放背景音乐,游戏中也可以随时关闭/开启背景音乐
其他细节优化
- 加入
正在对战过程中、对战已结束、房间已满等非正常类型房间,做出相应的交互提示,然后跳转至首页 - 在对战过程中任意用户退出游戏或掉线,则结束本局游戏,进行对战结算
- 对战结束后,房主可以选择再来一局,当房主创建好再来一局的房间后,另外一个用户可以选择再来一局,加入继续对战
- 在对战过程中,选择错误的单词或使用提示卡选择的单词,自动加入到用户生词本,用户可以在生词本中进行复习
- 加入倒计时机制,每一个单词的对战周期为 10s,超时则判断为错选
完整对战流程图
词汇挑战模式
词汇挑战模式业务解析
词汇挑战的核心为:获取随机的一个单词作为单选题题目文本,包含四个中文释义选项,其中一个为正确答案,选择错误则失败,选择正确再获取随机单词,循环下去。
挑战复活机制
在词汇挑战的过程中,如果选择错误,可以有两次复活机会
- 首次复活:通过分享小程序获得复活机会
- 第二次复活:通过观看一个 15s 之内的广告获得复活机会
- 当第三次选择错误,显示再来一局,从零开始记录分数
其他
- 词汇挑战每正确一个词,得分增加 100 分
- 当挑战失败的时候,如果挑战分数高于历史最高分数,则修改历史最高分数为当前分数,用于排行榜排行
- 可以使用提示卡进行选择
完整挑战流程图
其他功能
生词本
- 用户可以在生词本中查看在单词对战模式、词汇挑战模式中选择错误的单词
- 可以查看单词及单词释义、播放单词发音、删词生词
- 在设置中可以一键清空所有生词
学习打卡
- 当在单词对战模式中,当天对战局数超过 5 局且胜利局数超过 2 局,则打卡成功
- 可以在在打卡页面查看当日进度,可以查看历史的打卡日历
排行榜
- 排行榜包含词力值、词汇挑战分数、签到天数等排名信息
- 每类排行版显示前 20 名的排名头像和昵称以及分数
- 显示自己当前类目下的排名以及分数
用户相关
- 数据库应记录的用户数据包含:昵称、头像、对战局数、胜利局数、选择的单词本、词力值
- 词力值机制:在单词对战模式、单词挑战模式中,每局对战都可以获得相应的词力值分数,作为用户的经验值
其他
- 建议反馈:用户可以在小程序中,反馈意见,然后再后台可以查看用户留言
- 打赏作者:用户可以在小程序中,通过扫码的形式,对小程序进行打赏
- 小程序友情链接:可通过当前小程序跳转至作者的其他小程序中
- 小程序中加入部分广告,不影响用户体验
团队组成
整个项目的产品方案、UI 设计、开发、测试、上线运营等皆一个人独立完成。
技术方案
设计
设置使用sketch完成,设计稿上传至蓝湖,作为数据标注。
蓝湖链接
链接:https://lanhuapp.com/url/qe2Dl 密码: ydIX
设计图源文件
下载链接: https://pan.baidu.com/s/1KsZjvlTUbtyYFDcVCy91lg 密码:vylm
开发技术栈
- 前端:原生微信小程序
- 服务端:微信小程序云开发
其他工具
- ESLint
- Git + Github
- vscode
- Electron
- NodeJS
- Python
系统架构
项目文件简介
├── cloudfunctions # 云开发_云函数目录
| ├── model_auto_sign_trigger # 自动签到定时触发器
| ├── model_book_changeBook # 改变单词书
| ├── model_userWords_clear # 清除用户生词
| ├── model_userWords_get # 获取用户生词
| └── model_user_getInfo # 获取用户信息
├── db # 数据整理的脚本
├── design # 设计稿文件、素材文件
| └── words-pk-re.sketch # 设计稿
├── docs # 项目文档
├── miniprogram # 小程序前端目录
| ├── app.js # 小程序全局入口
| ├── app.json # 全局配置
| ├── app.wxss # 全局样式
| ├── audios # 选词正确错误的发音
| | ├── correct.mp3
| | └── wrong.mp3
| ├── components # 全局组件
| | ├── header # header组件
| | ├── loading # 全局loading
| | └── message # 全局弹窗
| ├── images
| | ├── ... 图片素材
| ├── miniprogram_npm # 小程序npm目录
| | └── wxapp-animate # 动画库
| ├── model # 所有的数据库操作
| | ├── base.js # 基类,所有集合继承该基类
| | ├── book.js # 单词书集合
| | ├── index.js # 导出所有数据库操作
| | ├── room.js # 房间集合
| | ├── sign.js # 签到集合
| | ├── user.js # 用户集合
| | ├── userWord.js # 生词表集合
| | └── word.js # 单词集合
| ├── pages # 页面
| | ├── combat # 对战页
| | ├── home # 首页
| | ├── ranking # 排行榜
| | ├── setting # 设置页
| | ├── sign # 签到页
| | ├── userWords # 生词表页
| | └── wordChallenge # 单词挑战
| └── utils
| ├── Tool.js # 全局工具类,放了加载、全局store等
| ├── ad.js # 广告
| ├── log.js # 日志上报
| ├── router.js # 全局路由
| ├── setting.js # 全局设置
| └── util.js # 全局工具函数
├── package.json
└── project.config.json # IDE设置、开发设置
云开发数据交互的 Model 层设计
在该项目中,将所有的服务端交互、数据库的读取、云函数的调用都放到了 model 目录下,对该目录结构深入解析。
(1) Base.js
base 基类,所有其他数据集合都继承该类,在构造函数中,用来做数据集合初始化和生命一些可能所需用到的变量。
import $ from './../utils/Tool'
const DB_PREFIX = 'pk_'
export default class {
constructor(collectionName) {
const env = $.store.get('env')
const db = wx.cloud.database({ env })
this.model = db.collection(`${DB_PREFIX}${collectionName}`)
this._ = db.command
this.db = db
this.env = env
}
get date() {
return wx.cloud.database({ env: this.env }).serverDate()
}
/**
* 取服务器偏移量后的时间
* @param {Number} offset 时间偏移,单位为ms 可+可-
*/
serverDate(offset = 0) {
return wx.cloud.database({ env: this.env }).serverDate({ offset })
}
}
(2)其他集合文件 (model 目录下,除了 base 和 index 之外的文件)
在这些文件中,对应和文件名同名的集合的所有数据操作,比如 book.js 中,包含了所有对 pk_book 集合的所有数据增删改查操作。
import Base from './base'
import $ from './../utils/Tool'
const collectionName = 'book'
/**
* 权限: 所有用户可读
*/
class BookModel extends Base {
constructor() {
super(collectionName)
}
async getInfo() {
const { data } = await this.model.get()
return data
}
async changeBook(bookId, oldBookId, bookName, bookDesc) {
if (bookId !== oldBookId) {
const { result: bookList } = await $.callCloud('model_book_changeBook', { bookId, oldBookId, bookName, bookDesc })
return bookList
}
}
}
export default new BookModel()
(3)index.js
在该文件中,对所有的数据集合操作文件进行引入,然后又导出,之后在其他文件中的的调用,就只需要引入该文件即可,就可以实现调用不同的集合操作。
import userModel from './user'
import bookModel from './book'
import wordModel from './word'
import roomModel from './room'
import userWordModel from './userWord'
import signModel from './sign'
export {
userModel,
bookModel,
wordModel,
roomModel,
userWordModel,
signModel
}
环境区分
在小程序初始化的时候,对云开发环境进行了全局的初始化,区别开发环境和正式环境。
// app.js
initEnv() {
const envVersion = __wxConfig.envVersion
const env = envVersion === 'develop' ? 'dev-lkupx' : 'prod-words-pk' // 'prod-words-pk' // ['develop', 'trial', 'release']
wx.cloud.init({
env,
traceUser: true
})
this.store.env = env
},
onLaunch() {
this.initEnv()
this.initUiGlobal()
},
难点解析
难点 1:单词数据
1. 抓包分析和代码实现
本课题中使用 MacOS 系统、Charles 抓包软件、安卓手机作为抓包的基本环境。首先在电脑上安装 Charles,然后开启 Proxy 抓包代理,同局域网下配置手机 WiFi 代理实现抓取手机包。
2. 单词数据整理
通过爬虫下来的单词数据如下,对于该课题的项目单词数据相对复杂,所以我们对单词数据结构进行简化,只提取项目中需要的字段,以单词 yum 为例:
优化前:
{"wordRank":63,"headWord":"yum","content":{"word":{"wordHead":"yum","wordId":"PEPXiaoXue4_2_63","content":{"usphone":"jʌm","ukphone":"jʌm","ukspeech":"yum&type=1","usspeech":"yum&type=2","trans":[{"tranCn":"味道好","descCn":"中释"}]}}},"bookId":"PEPXiaoXue4_2"}
优化后:
{"rank":286,"word":"yum","bookId":"primary","_id":"primary_286","usphone":"jʌm","trans":[{"tranCn":"味道好"}]}
通过 NodeJS 编写批量格式整理的程序,整理后导出 JSON 文件
3. 数据文件批量导入(传入数据库)
由于微信小程序云开发控制台不支持数据文件的批量导入数据库,所以开发了一个支持云
...

