├── 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 |
--------------------------------------------------------------------------------