一、新建一个quick start项目看看结构
在微信开发工具点击添加项目,选择 无appid,勾上"在当前目录中创建quick start 项目"。
可以看到一共有两个目录 pages和utils,和根目录下的3个app文件。pages存放的是小程序的页面,每个也面都有自己独立的文件夹。 一个页面由4文件构成,js文件是程序逻辑;wxss是微信定义的样式文件,语法跟css一样,支持的样式要少一些;wxml文件用来定义小程序的界面,作用类似于html,但是只能用微信自定义的一些标签,而且页面元素不能直接用js操作,只能通过绑定数据来修改;json是页面的配置文件一般用不着。根目录下的app.js,app.json,app.wxml作用和pages下面的作用类似,只不过pages下面的是页面级的,根目录下的是成个应用级的>。utils下面定义了一个转换时间格式工具函数,然后通过module.exports将函数暴露出去,再在logs.js中通过require引入。
二、改造index页面
知道了小程序的结构就可以动手开始做了,首先把index页面改造一下,把用户头像上的点击事件去掉,然后再新增两个按钮,用来跳转到游戏主界面和游戏成绩界面。
1.界面,bindtap相当于html的onclick
<!--index.wxml-->2.index.js 文件的Page中增加两个处理点击事件的函数,用wx.navigateTo来跳转的目标页
<view class="container">
<view class="userinfo">
<text class="userinfo-nickname"></text>
<image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
<text class="userinfo-nickname">你好</text>
</view>
<view class="usermotto" >
<text class="user-motto" bindtap="startGame">{{motto}}</text>
</view>
<view style="margin-top:30rpx; ">
<text class="user-motto" bindtap="viewScore" >查看排名</text>
</view>
</view>
//index.js//获取应用实例var app = getApp()Page({ data: { motto: '开始游戏', userInfo: {}, welcome:'你好' }, //事件处理函数 startGame: function() { wx.navigateTo({ url: '../game/game' }) },viewScore: function() { wx.navigateTo({ url: '../logs/logs' }) }, onLoad: function () { console.log('onLoad') var that = this //调用应用实例的方法获取全局数据 app.getUserInfo(function(userInfo){ //更新数据 that.setData({ userInfo:userInfo }) }) }})
3.index.wxss中增加游戏背景图
page{background: url('../images/gamebg.jpg') center top; }
在pages下新建一个images目录存照片
图片下载地址
http://pan.baidu.com/share/link?shareid=1434710849&uk=3758963053
http://pan.baidu.com/share/link?shareid=1434710849&uk=3758963053
三、游戏主界面和逻辑
在pages目录下新建一个game目录,然后再照着index页面新建game.js、game.json、game.wxml、game.wxss4个文件。
然后在app.json中增加game页的配置,顺便改下游戏标题.
{
"pages":[
"pages/index/index",
"pages/logs/logs",
"pages/game/game"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor":"white",
"navigationBarTitleText": "微信翻牌小程序",
"navigationBarTextStyle":"black"
}
}
1.game.js 游戏的逻辑
游戏的界面元素不能直接用js操作,只能用page的setData方法通过重新绑定数据来修改.界面上要用的变量都要定义在page的data中,界面有变化时必须要通过this.setData方法修改变量的值,直接修改变量界面不会变.
data: {游戏初始化时随机从牌堆中挑出一些,打乱显示在界面上几秒,然后翻回去游戏正式开始.
clickNum:0, // 点击次数
useTime:0, // 游戏时间
checked:0, // 已匹配牌数
allCard:allCard, // 全部卡牌数组
backImage:backCardImage, // 牌背面 图片地址
modalHidden: true, // 游戏完成提示是否显示
firstX:-1, // 点击的第一张卡牌的坐标
firstY:-1,
cards:[], // 随机挑选出来的牌
size:8 , // 界面显示的牌数=size*2
clickable:false, // 当前是否可点击
timer:'' // 游戏计时的定时器
}
startGame:function(){ // 开始游戏 var data = this.data; var that = this; console.log('startGame'); var tmp = this.data.allCard.sort( function(a,b){ return Math.random()>.5 ? -1 : 1;}).splice(0,Math.floor(data.size)); // 打乱牌堆,挑出size/2张牌 tmp = tmp.concat(tmp).sort(function(a,b){ return Math.random()>.5 ? -1 : 1;}); // 牌*2,再打乱 // 添加图片src和卡牌翻转状态state,存在二维数组方便展示 var cards = []; var ix = -1; var iy = 0; for(var i in tmp){ if( i%4 == 0){ cards.push([]); ix++; iy = 0; } cards[ix].push({ src:'../images/' +tmp[i]+ '.jpg', state:1 // 为1时显示图片,为0时显示牌背面 }); } this.data.cards = cards; this.setData({ cards:cards, clickNum:0, useTime:0, checked:0, modalHidden:true, firstX:-1, clickable:false }); var that = this; setTimeout(function(){ that.turnAllBack(); // 所有的牌翻到背面 console.log('turn all back'); data.clickable = true; if(data.timer === ''){ data.timer = setInterval(function(){ data.useTime++; that.setData({useTime:data.useTime}); },1000); // 游戏开始计时 }else{ that.setData({useTime:0}); } },5000); // 游戏开始前先让玩家记忆几秒钟 }响应点击事件
onTap: function(event){把所有牌翻到反面
var that = this;
var data = this.data;
var ix = event.currentTarget.dataset.ix; // 获取点击对象的坐标
var iy = event.currentTarget.dataset.iy;
console.log('onTap ' + ix + ' ' + iy);
if(data.cards[ix][iy].state != 0 || !data.clickable) // 点击的不是未翻过来的牌或者现在不让点直接pass
return;
that.setData({clickNum:++data.clickNum}); //点击数加1
// 1. 检测是翻过来的第几张牌
if(data.firstX == -1){
// 1.1 第一张修改状态为 1
data.cards[ix][iy].state = 1;
data.firstX = ix; data.firstY = iy; // 记下坐标
that.setData({cards:data.cards}); // 通过setData让界面变化
}else{
// 1.2 前面已经有张牌翻过来了,先翻到正面然后看是不是一样
data.cards[ix][iy].state = 1;
that.setData({cards:data.cards});
if(data.cards[data.firstX][data.firstY].src === data.cards[ix][iy].src){
// 1.2.1.1 两张牌相同, 修改两张牌的state为2完成配对
data.cards[data.firstX][data.firstY].state = 2;
data.cards[ix][iy].state = 2;
data.checked += 1; // 完成配对数++
data.firstX = -1; // 准备下一轮匹配
// 1.2.1.2 检查是否所有牌都已经翻过来,都已翻过来提示游戏结束
if(data.checked == data.size){ // 所有牌都配对成功了!
this.setData({ modalHidden: false});
clearInterval(this.data.timer); // 暂停计时
this.data.timer = '';
this.saveScore({'time':data.useTime,'click':data.clickNum}) // 保存成绩
}
}else{ // 1.2.2 两张牌不同, 修改两张牌的state为 0
data.cards[data.firstX][data.firstY].state = 0;
data.cards[ix][iy].state = 0;
data.firstX = -1;
data.clickable = false;
setTimeout(function(){
that.setData({cards:data.cards,clickable:true});
},500); //过半秒再翻回去
}
}
console.log(this.data.cards);
}
turnAllBack:function(){ for(var ix in this.data.cards) for(var iy in this.data.cards[ix]) this.data.cards[ix][iy].state = 0; this.setData({ cards:this.data.cards }); }游戏结束时,对游戏成绩进行排名然后通过wx.getStorageSync保存到本地
saveScore:function(score){ // 保存分数进入页面时记得调用startGame
var maxscore = wx.getStorageSync('maxscore');
if(maxscore == undefined || maxscore == '')
maxscore = [];
maxscore.push(score);
maxscore = maxscore.sort(function(a,b){
if(a.time < b.time )
return -1;
else if( a.time == b.time && a.click < b.click)
return -1;
else return 1;
});
wx.setStorageSync( 'maxscore',maxscore);
}
onLoad: function () { this.startGame(); console.log(this.data.cards); }2.界面布局
用view标签建立游戏的主界面
首先在顶部新建两个view 来显示时间和点击次数, 时间和点击次数是动态变化的所以要用两个大括号包住变量名这种格式
<view class="score">
<view class="scoredetail">
<view class="scoredesc">时间</view>
<view class="scorenumber">{{useTime}}</view>
</view>
<view class="scoredetail">
<view class="scoredesc">点击次数</view>
<view class="scorenumber">{{clickNum}}</view>
</view>
</view>
然后是卡牌,游戏的卡牌保存在二维数组中,用view标签for方法把二维数组展开.for-index 是当前元素索引值, for-item表示当前元素的引用,.同时通过state的值来控制牌的display样式是none还是block
<view class=""> <view class="board" > <view class="rows" wx:for="{{cards}}" wx:for-index="idx" wx:for-item="row"> <view wx:for="{{row}}" class="cols" wx:for-index="idy" wx:for-item="card" > <view class="" data-ix="{{idx}}" data-iy="{{idy}}" bindtap="onTap" > <image class="card" style="display:{{card.state == 0 ? 'none' : 'block'}}" mode="scaleToFill" src= "{{card.src}}" data-card="{{card}}"></image> <!--牌正面--> <image class="card back" style="display:{{card.state != 0 ? 'none' : 'block'}}" mode="scaleToFill" src= "{{backImage}}" ></image> <!--牌背面--> </view> </view> </view> </view></view>
相当于 javascript的
for(row in cards){ for(card in row){ <image>...</image><image>...</image>}}最后用model标签来弹出游戏结束时的提示, hidden属性用来控制modal是否显示,bindconfirm是点击确认时调用的方法, bindcancel是点取消时的方法, 这里点取消时我们让游戏跳转到排名页.<modal class="modal" hidden="{{modalHidden}}" bindconfirm="modalComfirm" bindcancel="modalCancle" cancelText="查看排名">在game.js中加两个响应函数
<view> 游戏结束 ,重新开始吗? </view>
</modal>modalComfirm:function(){3.样式文件
this.startGame();
},
modalCancle:function(){
this.setData({
modalHidden: true,
})
wx.navigateTo({
url: '../logs/logs'
})
}.score {
display: flex;
font-size: 1vh;
}
.scoredetail{
flex: 1;
height: 150rpx;
background:rgba(185, 65, 189, 0.8);
/*opacity: 0.6; */
margin: 50rpx 20rpx 40rpx 20rpx;
text-align: center;
border-radius: 11rpx;
}
.scoredetail:last-child{
margin-right: 40rpx;
}
.scoredesc{
font-size: 0.9rem;
line-height: 50rpx;
margin-top: 10rpx;
color:yellow;
}
.scorenumber{
line-height: 60rpx;
font-size: 1.1rem;
margin-top: 5rpx;
color:yellow;
}
.board{
margin-left: 5rpx;
margin-bottom: 5rpx;
}
.rows{
margin-bottom:1rpx ;
padding:0rpx;
text-algin:center;
flex-direction:row;
display:flex;
}
.cols{
margin: 5rpx;
}
.card{
width: 175rpx;
height: 237rpx;
padding:1rpx;
magrin: 2rpx;
}
page{background: url('../images/gamebg.jpg') center top; }四、最后把logs页面改造成游戏成绩页
在进入log页时用wx.getStorageSync 读取之前保存在游戏成绩信息//logs.js
Page({
data: {
logs: []
},
onLoad: function () {
this.setData({
logs: (wx.getStorageSync('maxscore') || [])
})
}
})游戏成绩读取出来是一个已经排好序的数组, 所以直接用wx:for按顺序显示出来就行<!--logs.wxml--><view class="container log-list"> <text class="log-item"> 用时 点击</text> <block wx:for="{{logs}}" wx:for-item="log" wx:key="*this"> <text class="log-item">{{index + 1}}. {{log.time}}秒 {{log.click}}次</text> </block></view>
游戏完整代码
https://github.com/kwdhd/wxFpgame
开发时参考了这个版本
http://blog.csdn.net/fdipzone/article/details/8630427