如何用JS做一个老虎机抽奖,由服务端控制得奖几率

6,599 阅读3分钟

近期热文(感谢掘友的鼓励与支持🌹🌹🌹)


前言

最近看到一篇文章 JS-VUE-老虎机抽奖,想起来我之前用JS游戏引擎做过一个,所以我也分享下心得体会吧。

先看最终效果

游戏引擎介绍

这里我用了一个可能大家不太熟悉的引擎,叫 annie2x,这个游戏引擎由一个js的2d引擎FLASH插件组成。

怎么还有FLASH!!

你没看错,annie2x通过插件的形式让熟练掌握FLASH软件的开发者更容易的生产和组织美术资源。比如将FLASH里的MovieClip直接转成2d引擎里可使用的代码文件。FLASH仅仅作为美术资源,动画制作的工具而存在,代码并不在FLASH里编写。如果你熟练掌握FLASHannie2x可以将H5的开发效率大大提升,在时间就是金钱的广告圈里,这个框架用户还是挺多的。

开发思路

虽然使用的是游戏引擎,但思路和逻辑是一样的。

循环滚动

首先将所有元素按相同尺寸排列在一张图片上,排列顺序是1234561。通过控制图片的y轴坐标来进行滚动,当最后一个元素显示完时,瞬间将图片的y轴归零,就可以循环滚动起来了。

我在这里建立了一个独立的对象RollingMC,让一个纵列作为整体去管理自己的运动逻辑。

AnnieRoot.game=AnnieRoot.game||{};
game.RollingMC=function(){
	var s = this;
	annie.Sprite.call(s);
	/*_a2x_need_start*/s.content_mc=null;/*_a2x_need_end*/
	annie.initRes(s,"game","RollingMC");

	var isRolling = false;
	var speed;
	var speedVal;

	var timer;
	var loopCount;
	var curLoop;
	var tposY;
	s.startRoll=function(index,tpos) {
    	//index指示当前是第几纵列,主要用于控制一个圈数差
        //tpos为最后落点的位置序号
		isRolling = true;
		curLoop=0;
		speed = 0;
		speedVal=1;

		//每次都转10圈打底,按第几纵列的顺序+2圈
		loopCount=10+index*2;
        //将tpos换算为y轴坐标
		tposY = tpos*-204;

		// console.log("最后将落在Y:",tposY);

		timer=window.requestAnimationFrame(loop);
	}
	function stopRolling() {
		window.cancelAnimationFrame(timer);
		isRolling = false;
	}

	function loop() {
		timer=window.requestAnimationFrame(loop);
		if (!isRolling) return;

		speed += speedVal;
		if (speed > 50) speed = 50;
		else if (speed < 1) speed = 1;
		s.content_mc.y -= speed;
		if (s.content_mc.y < -1428) {
			curLoop+=1;
			s.content_mc.y = -speed;
		}
		
		if(curLoop>=loopCount){
			if(s.content_mc.y<=tposY){
				s.content_mc.y = tposY;
				stopRolling();
			}
		}
	}
};
A2xExtend(game.RollingMC,annie.Sprite);

停止

如上面的代码所示,在启动滚动时,我传入了一个index参数用于让第123列的滚动次数上产生差异。另外还传入了一个tpos,代表targetPosition,用来控制最终停止位。

//如果当滚动圈数达到预计滚动圈数时
if(curLoop>=loopCount){
    //当图片的y轴坐标达到指定坐标时停止滚动
    if(s.content_mc.y<=tposY){
        s.content_mc.y = tposY;
        stopRolling();
    }
}

控制三个纵列的滚动,让启动的时间相隔500毫秒

function startRollingContent(index){
    s.main_mc["rolling_" + index].startRoll(index,pos_arr[index]);
    s.main_mc["rolling_" + index].didRollingStop = function () {
        rollingCount+=1;
        if (rollingCount>=3){
            rollingFinished();
        }
    }
}

setTimeout(function () { startRollingContent(0) }, 0);
setTimeout(function () { startRollingContent(1) }, 500);
setTimeout(function () { startRollingContent(2) }, 1000);

几率控制

  • 抽奖游戏就没有真随机的!
  • 抽奖游戏就没有真随机的!
  • 抽奖游戏就没有真随机的!

重要的事情说三遍!!!

在每次启动前会通过接口去获取最终要停止的位置

//前端代码片段
utils.RequestApi("luckyroll",{},function(res){
    loading.hide();
    if(res.err==0){
        pos_arr = res.result.posarr;
        award=res.result.award;
        realStart();
    }else{
        weui.alert(res.msg);
    }
});

服务端也是我写的,在服务端我首先是真的通过随机获得三个纵列的最终停止位。

//后端代码片段
function getRandomPosCheckInventory(){
	global $db;
	global $openid;
	$pos_arr = getRandomPos();

	$pos_str = join(",",$pos_arr);
    
    //这里我们会获得一个真正的随机的位置,值是0,0,0这种格式,代表最终三个纵列停止位的序号

可恨的是,我会通过查询数据库里奖品表的库存项来决定要不要给你发奖。如果有库存,那就给你。如果没库存,即使你随机中奖了,也会被我强行变为没奖。

//后端代码片段
if ($pos_str === "0,0,0") {
    //三个水杯
    $award=isEnoughInventory("水杯");
    if (!isset($award))return array("posarr"=>getNoAwardPos());
}else if (substr_count($pos_str,'0')==2&&(substr_count($pos_str,'2')==1 || substr_count($pos_str,'3')==1 || substr_count($pos_str,'4')==1 || substr_count($pos_str,'5')==1)) {
    //两个水杯+一个宠物
    $award=isEnoughInventory("玩偶");
    if (!isset($award))return array("posarr"=>getNoAwardPos());

是的,为了服务器效率,我并不会去找一个有库存的小奖给你,而是直接判定为无奖。

可恨

可恨

可恨

运气被白白浪费了呢~

体验地址

打开DEMO

在电脑上打开记得开启手机浏览模式

关注大帅搞全栈

感谢大家点赞,我挖到的金子一定全部分给大家