中秋节马上就要来临,公司开发了一个h5小游戏叉月饼,其实就是游戏“见缝插针”的翻版。这个游戏的开发任务落到了我的头上。。。
一 游戏介绍
游戏场景基本如下所示:
二 所用工具
这次的开发还是用的公司原有的一些框架,其中包括处理图片预加载、处理音效的等,其中包含了creatJS的一些内容,暂时还没有研究。有时间要研究一下。
所用框架如下:
<script type="text/javascript" src="../Public/js/setviewport.js"></script> <script type="text/javascript" src="../Public/js/jweixin-1.0.0.js"></script> <script type="text/javascript" src="../Public/js/WeixinApi.js"></script> <script type="text/javascript" src="../Public/js/jquery-2.1.1.min.js"></script> <script type="text/javascript" src="../Public/js/hammer.min.js"></script> <script type="text/javascript" src="../Public/js/TweenMax.min.js"></script> <script type="text/javascript" src="../Public/js/preloadjs-0.6.0.min.js"></script> <script src="http://cdn.gbtags.com/EaselJS/0.7.1/easeljs.min.js"></script> <script src="http://cdn.gbtags.com/PreloadJS/0.4.1/preloadjs.min.js"></script> <script src="http://cdn.gbtags.com/SoundJS/0.5.2/soundjs.min.js"></script> <script type="text/javascript" src="../Public/js/main.js"></script> <script type="text/javascript" src="../Public/js/wScratchPad.min.js"></script>
其实主要用的是JQuery、TweenMAx、preload等。
三 页面布局
游戏的主要画面包括游戏初始页、规则、游戏、过关提示、抽奖、抽奖结果并提交信息、通关提交信息等。因为PSD图中游戏结束提示灯一些页面都是在初始页的基础上加了个半透明的遮罩,所以这些提示都写在了初始页里面,游戏画面是一个单独的快,抽奖是一个单纯的块,抽奖结果是一个单独的块,抽奖结束是一个单独的块,过关提示是一个单独的块。
四 游戏逻辑
首先第一个页面点击按钮查看游戏规则,游戏规则也点击开始游戏开始游戏,简单的点击事件暂且不提。
我们需要初始化一些全局变量用于游戏控制。
var tar = $(".point"); //旋转月饼1
var tar2 = $(".point2"); //旋转月饼2
var arrowIndex = 1; //针数
var rotateNum = 0; //旋转度数
var arrPos = [360]; //已有度数列表
var safeDistance = 8; //安全距离
var score = 0; //得分
var level=1; //关数
var levelmap=[0,2,4,6,8,9,10,11,12,13,14] //难度地图,设置初始针数
如图所示,月饼是旋转的,而在这里我们有两个旋转的月饼。原因是point这个月饼是一个空的div,而月饼图片是他的背景,而当我们把针射上去的时候,采用的方式是在point这个空div里面添加子元素,子元素就是针,而针子元素是相对于point定位的,结果就是针在月饼的上面,这样当然不好看,所以我在point后面加上了一个月饼point2,用它把第一个月饼盖住,两个月饼一起转动,这样针就乖乖的插在了月饼里面。
arrowIndex是表示插得针数,rotateNum是月饼旋转的角度,arrPos是月饼上已经有的针的角度,用于判断插针结果,safeDistance是安全距离,当两根针之间的角度差小于它是,游戏失败,score是得分,level是关数,levelmap是难度地图,用于初始化每关游戏开始时自带针数。
1、倒计时
点击开始游戏按钮时,游戏场景出现,开始倒计时3秒。倒计时的实现是采用setInterval每隔1000ms换一张图片。
function numCount(){
var flag=3;
var timer2=setInterval(function(){
if(flag>1){
flag--;
$('.count img').attr('src','../Public/images/a'+flag+'.png')
}else{
clearInterval(timer2);
can=true;
gameStart();
}
},1000)
}
其中can为点击事件的开关,初始为flase;当can为true时,方可点击。
2、难度设置
游戏刚开始时设置难度,同时每过一关都要重新设置难度,所以需要在这个函数中将arrowIndex重置为1,将arrPos重置为[360],之所以初始为360不为空,是因为0度肯定是存在的,而360等于0度,在计算是否插针成功的时候,没有360将会产生一些错误。
首先获得当前难度,然后根据当前难度在levelmap里面取数,取出的数字即为下一关初始针数,然后用360/针数取整,针旋转相应度数,将这些针循环写入point,同时将这些度数push进数组arrPos,表示已经存在上述度数的针。初始化页面下方球数,在调用这个函数的时候,需要传入一个参数,即每关有多少根针,然后将通过循环将底部小球写入相应div,并附上数字。
3、游戏开始
月饼旋转使用的是setInterval来控制,每隔相应时间月饼转动一度,同时全局变量rotateNum加1,当大于等于360的时候归0,这样月饼的角度一直在0到360之间变化。当发生点击事件的时候,可以通过rotateNum的值获取到当前月饼旋转的角度,然后在point中添加一个元素(针),并使它旋转到一定的角度。由于针是相对于月饼定位的,其top和left都为50%,通过调节margin使他出现在月饼正下方,所以如果月饼不转的话,新添加的针出现在月饼的正下方,此时月饼和针的旋转角度均为0,而当月饼旋转X度之后,针如果不旋转,也将出现在X度的方向,所以针需要旋转Y=360-X度,即让针从0度位置,先跟着月饼旋转到X,在旋转到Y,所以针相对于手机旋转360度等于不旋转,针将出现在月饼的最下方。然后将针旋转的度数Y push进数组arrPos。定义一个新数组,然后使用grep方式用Y减去数组arrPos的每一项,当结果小于安全距离safeDistance的时候,将arrPos的这一项写入新数组,如果新数组的长度大于等于2,说明存在两根针之间的距离小于安全距离,游戏结束。当这次插针成功时,将度数写入数组arrPos,将下方球第一个元素remove,同时分数加1,当分数大于等于10时,过关提示页出现,关数加1,同时初始化难度。当关数大于等于10时,通全关,游戏界面隐藏,清空计时器,出现奖励界面。若游戏失败且过关数大于等于3,游戏界面隐藏,清空计时器,出现抽奖页面。
4、抽奖
点击抽奖按钮,调ajax获取抽奖,若用户没有抽奖资格,转盘转动几圈,然后停在谢谢参与地方,弹窗提示用户,然后刷新页面。
若用户有抽奖资格且中奖,转盘转动,最后根据奖品ID停在相应位置,然后跳出获奖信息,并让用户填写信息。用户信息填写成功并提交后,跳到最后宣传页面。
若用户没有中奖,,转盘转动,最后停在谢谢参与位置,跳出没中奖,用户点击再次挑战重新开始游戏。
5、再次挑战,重新开始游戏
初始化各种全局变量,将页面该隐藏的隐藏,改显示的显示,然后重新调用倒计时函数。
五 遇到的各种BUG
1、iOS端点击延迟、闪屏:
愚蠢的我点击事件随便写了个click,当然是不可以啦,毕竟300ms延迟伤不起呀,怪我怪我~~~
我们是用这种方法封装的点击事件
var mobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);
var touchstart = mobile ? "touchstart" : "mousedown";
var touchend = mobile ? "touchend" : "mouseup";
var touchmove = mobile ? "touchmove" : "mousemove";
2、IOS端连续点击屏幕上移
这个问题很严重,快速双击是经常存在的,解决办法如下代码:
function initPreventPageDobuleTap(isPreventPageDobuleTap){
if(isPreventPageDobuleTap){
$('.main').on(touchstart,function(e){
e.preventDefault()
})
}else{
$('.main').off(touchstart);
$('.main').off(touchend);
}
}
意思就是当传入false的时候,把touch事件给解绑,传入true的时候,取消事件的默认动作。但是当有表单页的时候,要关闭阻止事件,否则不能输入文字了,请传入false值,再次运行即可。
即要阻止双击,就传true,取消事件的默认动作,但这样会阻止表单,因为触摸不会触发input,所以要关闭它。