├── README.md ├── app.js ├── app.json ├── app.wxss ├── common └── net.js ├── mime └── mimeMap.js ├── pages ├── entry │ ├── entry.js │ ├── entry.wxml │ └── entry.wxss ├── gameover │ ├── gameover.js │ ├── gameover.wxml │ └── gameover.wxss └── index │ ├── index.js │ ├── index.wxml │ └── index.wxss ├── res ├── demo.jpg └── gameover.jpg └── websocket ├── connect.js └── msgHandler.js /README.md: -------------------------------------------------------------------------------- 1 | # wx-mime 2 | 微信小程序版的扫雷(挖金子),前端代码 3 |

4 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | 2 | App({ 3 | globalData:{ 4 | mimeMap: null, // [[1, 2, 3, 4, 5, 6, 8, 9], [1, 2, 3, 4, 5, 6, 8, 9], [1, 2, 3, 4, 5, 6, 8, 9]] 做测试用 5 | count: 0, 6 | roomNo: 0, 7 | score: 0 8 | }, 9 | updateMap: function(mimeMap) { // 更新应用的数据 10 | this.globalData.mimeMap = mimeMap; 11 | }, 12 | getMap: function() { 13 | return this.globalData.mimeMap; 14 | }, 15 | 16 | setCount: function(count) { 17 | this.globalData.count = count; 18 | }, 19 | decreaseCount: function() { 20 | if(this.globalData.count > 0) { 21 | this.globalData.count -= 1; 22 | } 23 | }, 24 | getCount: function() { 25 | return this.globalData.count 26 | }, 27 | 28 | getRoomNo: function() { 29 | return this.globalData.roomNo 30 | }, 31 | setRoomNo: function(no) { 32 | this.globalData.roomNo = no; 33 | }, 34 | 35 | setMyScore: function(score) { 36 | this.globalData.score = score; 37 | }, 38 | getMyScore: function() { 39 | return this.globalData.score; 40 | } 41 | }) -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages":[ 3 | "pages/entry/entry", 4 | "pages/gameover/gameover", 5 | "pages/index/index" 6 | ], 7 | "window":{ 8 | "backgroundTextStyle":"light", 9 | "navigationBarBackgroundColor": "#2a292e", 10 | "navigationBarTitleText": "掘金", 11 | "navigationBarTextStyle":"white" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | .container { 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | justify-content: space-between; 8 | padding: 200rpx 0; 9 | box-sizing: border-box; 10 | } 11 | -------------------------------------------------------------------------------- /common/net.js: -------------------------------------------------------------------------------- 1 | 2 | var app = getApp(); 3 | function post(url, data, successCallback, failCallback, completeCallback) { 4 | if(typeof(url) === 'object') { // 兼容json格式的参数 5 | opt = url; 6 | url = opt.url; 7 | data = opt.data; 8 | successCallback = opt.success; 9 | failCallback = opt.fail; 10 | completeCallback = opt.complete; 11 | } 12 | wx.request({ 13 | url: url, 14 | data: data, 15 | method: 'POST', 16 | header: { 17 | 'Content-Type': 'application/json' 18 | }, 19 | success: function(res) { 20 | console.log(res.data); 21 | successCallback && successCallback.call(null, res.data); 22 | }, 23 | fail: function(err) { 24 | console.log('fail'); 25 | failCallback && failCallback.call(err); 26 | }, 27 | complete: function(data) { 28 | completeCallback && completeCallback.call(data); 29 | } 30 | }); 31 | } 32 | 33 | module.exports = { 34 | post: post 35 | }; -------------------------------------------------------------------------------- /mime/mimeMap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 这只是一个示例,真正用到地图场景生成的是在后台 3 | */ 4 | 5 | var mimeCnt = 10; 6 | var col = row = 6; 7 | // 地图场景数据 8 | var data = []; 9 | 10 | // 生成雷的主入口 11 | function genMimeArr() { 12 | var tmpCnt = mimeCnt, 13 | mimeMap = {}; // 辅助判断各格子的状态 14 | 15 | // 初始化数据 16 | for (var r = 0; r < row; r ++) { 17 | data[r] = []; // 每一行都是一个数组 18 | for (var c = 0; c < col; c ++) { 19 | data[r][c] = 0; 20 | } 21 | } 22 | // 生成雷 23 | while(tmpCnt > 0) { 24 | var randX = getRandPos(col), // x => col 25 | randY = getRandPos(row), // y => row 26 | key = randY+'-'+randX; 27 | if(!mimeMap[key]) { 28 | mimeMap[key] = 1; 29 | data[randY][randX] = -1; // 用负数来表示这里是雷 30 | tmpCnt --; 31 | } 32 | } 33 | // 扫描雷附近的格子 34 | for (var r = 0; r < row; r ++) { 35 | for (var c = 0; c < col; c ++) { 36 | if(data[r][c] < 0) { 37 | increaseArround(r,c); 38 | } 39 | } 40 | } 41 | console.log(data); 42 | return data; 43 | } 44 | function getRandPos(max) { 45 | return Math.floor(Math.random()*10000)%max; 46 | } 47 | 48 | function increaseArround(r, c) { 49 | // upper row, current row, and the lower row 50 | for (var k = 1; k > -2; k --) { // 1, 0, -1 51 | var rr = r-k; // tmp row 52 | for (var i = c-1; i < c+2; i ++) { 53 | var cc = i; // tmp col 54 | if (cc >= 0 && cc < col // 约束列 55 | && rr >= 0 && rr < row // 约束行 56 | && !(rr===r&&cc===c) // 不是当前这一格 57 | && data[rr][cc] >= 0) { // 且不是雷 58 | data[rr][cc] ++; 59 | } 60 | } 61 | } 62 | } 63 | 64 | // genMimeArr(); 65 | 66 | module.exports = genMimeArr; -------------------------------------------------------------------------------- /pages/entry/entry.js: -------------------------------------------------------------------------------- 1 | var net = require('../../common/net.js'); 2 | // require('../../res/socket.io.js'); 3 | 4 | var app = getApp(); 5 | // console.log(io); 6 | 7 | Page({ 8 | data: { 9 | roomNo: 0 10 | }, 11 | startGame: function() { 12 | var roomNo = this.data.roomNo; 13 | if(!roomNo) { 14 | console.error('请填写房间号'); 15 | return; 16 | } 17 | app.setRoomNo(roomNo); // 房间号 18 | // 切换页面 19 | wx.navigateTo({ 20 | url: '../index/index' 21 | }); 22 | /*net.post({ 23 | url: 'http://localhost:8080/room', 24 | data: { 25 | no: roomNo, 26 | }, 27 | success: function(rsp) { 28 | // console.log(rsp, typeof(rsp)); 29 | if(rsp.errCode == 0) { 30 | var mimeMap = rsp.data.map; 31 | app.updateMap(mimeMap); // 地图场景 32 | app.setCount(rsp.data.count); // 金子的个数 33 | } 34 | }, 35 | fail: function(err) { 36 | console.error('fail: ' + err); 37 | } 38 | });*/ 39 | }, 40 | roomNoChanged: function(event) { 41 | this.setData({ 42 | roomNo: event.detail.value 43 | }); 44 | }, 45 | }); 46 | -------------------------------------------------------------------------------- /pages/entry/entry.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 请填入房间号开始游戏 5 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /pages/entry/entry.wxss: -------------------------------------------------------------------------------- 1 | .title { 2 | font-size: 16px; 3 | color: #333; 4 | } 5 | .start-game { 6 | font-size: 14px; 7 | margin-top: 30px; 8 | } 9 | .room-no { 10 | font-size: 14px; 11 | padding: 5px; 12 | text-align: center; 13 | border: 1px #ccc solid; 14 | margin: 10px auto; 15 | } -------------------------------------------------------------------------------- /pages/gameover/gameover.js: -------------------------------------------------------------------------------- 1 | var app = getApp(); 2 | 3 | Page({ 4 | data: { 5 | score: 0, 6 | roomNo: 0 7 | }, 8 | onLoad: function () { 9 | this.setData({ 10 | score: app.getMyScore(), 11 | roomNo: app.getRoomNo() 12 | }); 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /pages/gameover/gameover.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 我的得分:{{score}} 6 | 房间号:{{roomNo}} 7 | 8 | 9 | -------------------------------------------------------------------------------- /pages/gameover/gameover.wxss: -------------------------------------------------------------------------------- 1 | page { 2 | background: #010300; 3 | } 4 | .wrapper { 5 | width: 100%; 6 | padding: 5px 20px; 7 | } 8 | .banner { 9 | width: 100%; 10 | } 11 | .info { 12 | font-size: 16px; 13 | font-weight: bolder; 14 | color: #fcfbf9; 15 | padding: 10px 50px; 16 | } 17 | .info .item { 18 | line-height: 2em; 19 | } 20 | .info .item .data { 21 | color: #fff; 22 | } -------------------------------------------------------------------------------- /pages/index/index.js: -------------------------------------------------------------------------------- 1 | var websocket = require('../../websocket/connect.js'); 2 | var net = require('../../common/net.js'); 3 | var msgReceived = require('../../websocket/msgHandler.js'); 4 | 5 | var app = getApp(); 6 | 7 | Page({ 8 | data: { 9 | mimeMap: null, 10 | leftGolds: 0, // 总共有多少金子 11 | score: 0, // 我的得分 12 | roomNo: 0 // 房间号 13 | }, 14 | x: 0, // 用户点中的列 15 | y: 0, // 用户点中的行 16 | onLoad: function () { 17 | var roomNo = app.getRoomNo(); 18 | this.setData({ 19 | roomNo: roomNo 20 | }); 21 | // test 22 | // websocket.send('before connection'); 23 | 24 | if (!websocket.socketOpened) { 25 | // setMsgReceiveCallback 26 | websocket.setReceiveCallback(msgReceived, this); 27 | // connect to the websocket 28 | websocket.connect(); 29 | websocket.send({ 30 | type: 'create' 31 | }); 32 | } 33 | else { 34 | websocket.send({ 35 | type: 'create', 36 | no: roomNo 37 | }); 38 | } 39 | }, 40 | digGold: function(event) { // 不直接判断,而把坐标传给后台判断 41 | // 被开过的就不管了 42 | if (event.target.dataset.value < 9) { 43 | return; 44 | } 45 | 46 | // 取到这格的坐标 47 | this.x = parseInt(event.target.dataset.x); 48 | this.y = parseInt(event.target.dataset.y); 49 | console.log(this.x, this.y); 50 | // 上报坐标 51 | this.reportMyChoice(); 52 | }, 53 | 54 | reportMyChoice: function() { 55 | var roomNo = app.getRoomNo(); 56 | websocket.send({ 57 | type: 'dig', 58 | x: this.x, 59 | y: this.y, 60 | no: roomNo 61 | }); 62 | }, 63 | }); 64 | -------------------------------------------------------------------------------- /pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 我的得分:{{score}} 5 | 房间号:{{roomNo}} 6 | 剩余金子:{{leftGolds}} 7 | 8 | 10 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | /**index.wxss**/ 2 | .wrapper { 3 | padding: 5px; 4 | } 5 | .flex-container { 6 | padding: 0; 7 | margin: 0 auto; 8 | list-style: none; 9 | display: flex; 10 | flex-flow: row; 11 | justify-content: space-around; 12 | line-height:1em; 13 | width: 90%; 14 | } 15 | .flex-item { 16 | background: gray; 17 | margin: 1px; 18 | color: white; 19 | font-weight: bold; 20 | font-size: 14px; 21 | text-align: center; 22 | flex: 1 0 auto; 23 | height: auto; 24 | font-family: "Lucida Console", Monaco, monospace 25 | } 26 | .open { 27 | background: tomato; 28 | } 29 | .gold { 30 | background: #fdff37; 31 | color: #333; 32 | } 33 | .flex-item:before { 34 | content: ''; 35 | display: block; 36 | float: left; 37 | padding-top:100%; 38 | } 39 | .top { 40 | display: flex; 41 | font-size: 14px; 42 | line-height: 2.5em; 43 | text-align: center; 44 | } 45 | .top .label { 46 | flex: 1; 47 | } -------------------------------------------------------------------------------- /res/demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsongo/wx-mime/317b709383be570883a0dd1e664a3742ee77360c/res/demo.jpg -------------------------------------------------------------------------------- /res/gameover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsongo/wx-mime/317b709383be570883a0dd1e664a3742ee77360c/res/gameover.jpg -------------------------------------------------------------------------------- /websocket/connect.js: -------------------------------------------------------------------------------- 1 | module.exports = (function() { 2 | var webSocketUrl = 'ws://123.56.85.164:18080/websocket', 3 | socketOpened = false, // 标记websocket是否已经打开 4 | socketMsgQueue = [], 5 | connCallback = null, 6 | msgReceived = {}; 7 | 8 | function connect(callback) { // 发起链接 9 | var app = getApp(), 10 | roomNo = app.getRoomNo(); 11 | wx.connectSocket({ 12 | url: webSocketUrl + '?no=' + roomNo 13 | }); 14 | connCallback = callback; 15 | } 16 | 17 | function initEvent() { // 初始化一些webSocket事件 18 | wx.onSocketOpen(function(res){ // webSocket打开事件处理 19 | socketOpened = true; 20 | console.log('websocket opened.'); 21 | // 处理一下没发出去的消息 22 | while(socketMsgQueue.length > 0) { 23 | var msg = socketMsgQueue.pop(); 24 | sendSocketMessage(msg); 25 | } 26 | // sendSocketMessage('after'); 27 | 28 | // connection callback 29 | connCallback && connCallback.call(null); 30 | }); 31 | wx.onSocketMessage(function(res) { // 收到服务器消息时的处理 32 | console.log('received msg: ' + res.data); 33 | msgReceived.callback && msgReceived.callback.call(null, res.data, ...msgReceived.params); 34 | }); 35 | wx.onSocketError(function(res){ // 链接出错时的处理 36 | console.log('webSocket fail'); 37 | }); 38 | } 39 | 40 | function sendSocketMessage(msg) { 41 | if (typeof(msg) === 'object') { 42 | msg = JSON.stringify(msg); 43 | } 44 | if (socketOpened) { 45 | wx.sendSocketMessage({ 46 | data:msg 47 | }); 48 | } else { // 发送的时候,链接还没建立 49 | socketMsgQueue.push(msg); 50 | } 51 | } 52 | 53 | function setReceiveCallback(callback, ...params) { 54 | if (callback) { 55 | msgReceived.callback = callback; 56 | msgReceived.params = params; 57 | } 58 | } 59 | 60 | function init() { 61 | initEvent(); 62 | } 63 | 64 | init(); 65 | return { 66 | connect: connect, 67 | send: sendSocketMessage, 68 | setReceiveCallback: setReceiveCallback, 69 | socketOpened: socketOpened 70 | }; 71 | })(); 72 | -------------------------------------------------------------------------------- /websocket/msgHandler.js: -------------------------------------------------------------------------------- 1 | module.exports = function(msg, page) { // page -> index page 2 | var app = getApp(); 3 | 4 | msg = JSON.parse(msg); 5 | var type = msg.data && msg.data.type || 6 | msg.errMsg && msg.errMsg.type; 7 | if (type === 'dig') { // 挖金子操作 8 | if (msg.errCode == 0) { 9 | var result = msg.data.answer, 10 | x = msg.data.x, 11 | y = msg.data.y; 12 | if (result < 0) { // 挖到金子了 13 | app.decreaseCount(); 14 | var leftGolds = page.data.leftGolds, 15 | score = page.data.score; 16 | if (msg.data.isMe) { 17 | score ++; 18 | } 19 | page.setData({ 20 | leftGolds: --leftGolds, 21 | score: score 22 | }); 23 | } 24 | // 把相应的格子翻出来 25 | page.setData({ 26 | ['mimeMap[' + y + '][' + x + ']']: result, 27 | }); 28 | } 29 | } 30 | else if (type === 'create') { // 创建或进入房间 31 | if(msg.errCode == 0) { 32 | var mimeMap = msg.data.map; 33 | app.updateMap(mimeMap); // 地图场景 34 | app.setCount(msg.data.count); // 金子个数 35 | page.setData({ 36 | mimeMap: mimeMap, 37 | leftGolds: msg.data.count // app.getCount() 38 | }); 39 | } 40 | else { 41 | wx.navigateBack(); 42 | } 43 | } 44 | else if (type === 'over') { // 游戏结束 45 | if(msg.errCode == 0) { 46 | app.setMyScore(msg.data.score); 47 | wx.navigateTo({ 48 | url: '../gameover/gameover' 49 | }); 50 | } 51 | } 52 | } 53 | --------------------------------------------------------------------------------