前言
最近玩了一个小游戏,感觉挺有意思,打算放进我的小程序【自动化小助手】里面,“三张押一张,专押花姑娘!”,从三张卡牌,挑选一张,中奖后将奖励进行发放,并且创建下一期,不多说了,说做就做
分析
前端分析
前端设计出页面以后,从接口处获得参与次数,押中次数以及当前期数、开奖时间,开奖时间获取到以后和现在的时间进行对比获得倒计时,下面是我已经大致构建的画面
这是代码:
<template> <view> <view class="b-flex-x b-bg-white b-p-32"> <image src="@/static/guanjun.png" mode="aspectFit" class="logo b-radius-8"></image> <view class="b-flex-item b-ml-32"> <view class="b-text-B b-text-48 b-text-black">买定离手</view> <br> <view class="b-font-24 b-mt-8 b-text-black-dd">参与<span style="color: navajowhite;">2</span>次,押中<span style="color: yellowgreen;">23</span>次</view> </view> </view> <view class="b-pt-32 b-pr-32 b-pl-32 b-pb-24 b-text-black-dd" style="color: black;font-weight: 500;">第1期 开奖倒计时:<span style="color: red;">00:00</span></view> <view class="b-list-user b-bg-white" style="width: 700rpx;height: 300rpx;margin: auto;"> <text style="color: orange;">已选择卡牌,等待开奖</text> <text style="color: orange;">请选择</text> <view style="width: 680rpx;height: 250rpx;margin: auto;display: flex;flex-direction: row;align-items: center;justify-content: center;"> <image src="https://floor.huluxia.com/static/img/ya.png" mode="aspectFit" style="width: 200rpx;" v-if="select_card=='1'" ></image> <image src="https://floor.huluxia.com/static/img/1_normal.png" mode="aspectFit" style="width: 200rpx;" v-else @click="click_card('1')"></image> <image src="https://floor.huluxia.com/static/img/ya.png" mode="aspectFit" style="width: 200rpx;margin-left: 10rpx;" v-if="select_card=='2'"></image> <image src="https://floor.huluxia.com/static/img/2_normal.png" mode="aspectFit" style="width: 200rpx;margin-left: 10rpx;" v-else @click="click_card('2')"></image> <image src="https://floor.huluxia.com/static/img/ya.png" mode="aspectFit" style="width: 200rpx;margin-left: 10rpx;" v-if="select_card=='3'"></image> <image src="https://floor.huluxia.com/static/img/3_normal.png" mode="aspectFit" style="width: 200rpx;margin-left: 10rpx;" v-else @click="click_card('3')"></image> </view> </view> <view class="b-pt-32 b-pr-32 b-pl-32 b-pb-24 b-text-black-dd" style="color: black;font-weight: 500;">游戏规则:</view> <view class="b-list-user b-bg-white" style="width: 680rpx;height: 120rpx;margin:auto;"> <text>①三张卡牌中有一张是K,请选择一张卡牌。</text> <br> <text>②开奖后,选中的话可以获得相应的金币,反之会失去你的金币。</text> </view> <view class="b-pt-32 b-pr-32 b-pl-32 b-pb-24 b-text-black-dd" style="color: black;font-weight: 500;">最近开局记录</view> <view class="b-list-user b-bg-white"> </view> </view> </template> <script> export default { data() { return { select_card:'0' } }, onShow() { }, onLoad() { }, methods: { click_card(num){ this.select_card=num; }, } } </script> <style lang="scss"> .logo{ width: 140rpx; height: 140rpx; } </style>
后端分析
后端我这里用的是原生PHP,因为php简单,配合这次的项目能够发挥很大的效率,瘴气氨考虑用python,但是因为长连接不考虑,所以就
pass了
思路
新建一个php脚本,用来触发每一期的开盘
逻辑:查询数据库对应表,是否有最后一期,存在的话开奖,然后写入数据库,发放奖励,通过定时计划任务每几分钟触发,用户端在查到数据库信息后,换算开盘时间,进行押注
创建期数
新建game_system.php
<?php include '../api/conn.php'; require_once("../api/Message_push/mqtt_sender.php"); if ($_GET['password']!='iuweojsd8542637lk') { die( json_encode( array( 'code' => 200, 'msg' => '缺少参数' ),480) ); } // 获取当前时间戳 $currentTimestamp = time(); // 计算5分钟之后的时间戳 $fiveMinutesLaterTimestamp = $currentTimestamp + (5 * 60); //每多长时间开盘$fiveMinutesLaterTimestamp //先获取最后一期数 $sql = "SELECT * FROM game_periods ORDER BY period DESC LIMIT 1"; $result = $conn->query($sql); if ($result->num_rows > 0) { // 读取查询结果中的一行数据 $row = $result->fetch_assoc(); // 获取period字段的值 $period = $row['period']; //进行随机数计算,完成该期数据库写入 // 生成1、2或3的随机数 $randomNumber = mt_rand(1, 3); $sql_update="UPDATE `game_periods` SET `number` = '$randomNumber', `is_processed` = '1' WHERE `period` = '$period'"; $conn->query($sql_update); } else { //没有查询到任何记录 //创建第一期 $sql_insert="INSERT INTO `game_periods` (`id`, `period`, `number`, `next_draw_time`, `is_processed`) VALUES (NULL, '1', '','$fiveMinutesLaterTimestamp', '0')"; $conn->query($sql_insert); die("创建了第一期"); } //下一期创建 $nextPeriod = $period + 1; $sql_insert_ = "INSERT INTO game_periods (`id`, `period`, `number`, `next_draw_time`, `is_processed`) VALUES (NULL, '$nextPeriod', '', '$fiveMinutesLaterTimestamp', '0')"; $result = $conn->query($sql_insert_); // 匹配奖励结算(未中奖也要说) $reward = "SELECT price,openid,number FROM `periods_data` WHERE `period`='$period'"; $result = $conn->query($reward); if ($result->num_rows > 0) { // 循环读取查询结果中的所有行数据 while ($row = $result->fetch_assoc()) { $openid = $row['openid']; $price = $row['price']; $number_sonal = $row['number']; // 获得$price的两倍 $doublePrice = $price * 2; if ($number_sonal==$randomNumber) { // 金额到账 $price_update = "UPDATE `user` SET `price` = `price` + $doublePrice WHERE `openid` = '$openid'"; $conn->query($price_update); $msg="恭喜您,选中了K牌,奖励已到账"; } else { $msg="很遗憾,未选中K牌,再接再厉"; } $receiver = "$openid"; $content = $msg; send_mqtt_message($receiver, $content,$conn,'0'); // 通知消息 } } // 关闭数据库连接 $conn->close(); ?>
- 首先,代码通过include和require_once引入了一些依赖的文件,包括数据库连接文件和消息推送相关的文件。
- 接下来,代码检查传入的GET请求参数password是否等于iuweojsd8542637lk,如果不等于则返回一个JSON格式的错误信息,包含错误代码和错误消息。
- 然后,代码获取当前的时间戳,并计算出5分钟后的时间戳。代码通过数据库查询获取最后一期的信息,如果有查询结果,说明已经存在期数记录,就对该期进行更新操作:生成1、2或3的随机数,并将这个随机数以及标记为已处理的状态写入数据库。如果没有查询到任何记录,说明是第一期,代码将创建第一期的记录,并将下一期的信息也插入数据库,但这个记录的期数是当前期数加1,即第二期。
- 之后,代码会检查当前期数的数据记录,查询是否有用户参与,如果有参与,会根据用户选择的数字和随机生成的数字进行奖励结算。如果用户选择的数字与随机数一致,会将用户的账户余额增加两倍的奖励金额,否则用户得到一条未中奖的消息。
- 最后,代码通过消息推送的方式,将奖励结果发送给对应的用户。
- 最后关闭数据库连接。
定时计划
通过宝塔的定时计划任务,到点后触发URL,这个时候你可能会说程序会在创建过程中出现很多BUG,是的,当速度不匹配用户提交数据有很多不确定性,所以我们需要对下面的用户操作部分做一些调整,避免出现这些情况
买定离手操作
新建buy.php
<?php include '../api/conn.php'; if (!$_POST) { die( json_encode( array( 'code' => 200, 'msg' => '缺少参数' ),480) ); } $period=$_POST['period']; $openid=$_POST['openid']; $number=$_POST['number']; $price=$_POST['price']; //查询当前提交期数与系统最后期数一致吗(期数一致) $sql1="SELECT period,is_processed FROM game_periods ORDER BY period DESC LIMIT 1"; $result = $conn->query($sql1); if ($result->num_rows > 0) { // 读取查询结果中的一行数据 $row = $result->fetch_assoc(); // 获取id字段的值 $period_database = $row['period']; $is_processed = $row['is_processed']; if ($period_database==$period&&$is_processed=='0') { //防止写入两次 $query_sql="SELECT id FROM `periods_data` WHERE `period`='$period'and `openid`='$openid'"; $result = $conn->query($query_sql); if ($result->num_rows > 0) { die( json_encode( array( 'code' => 200, 'msg' => '已经押注过啦~' ),480) ); } else { // 余额支付 //我的余额查询 $cx_yue="SELECT `price` FROM `user` WHERE `openid`='$openid'"; $res=$conn->query($cx_yue); if ($rowss=$res->fetch_assoc()) { $my_money=$rowss['price'];//我的余额 } else { die( json_encode( array( 'code' => 200, 'msg' => '当前用户未注册' ),480) ); } $buy=$price;//真正需要付的钱 // var_dump($buy); //余额判断 if ($my_money>=$buy) { // 余额扣除 $residue_money=$my_money-$buy; $money_update="UPDATE `user` SET `price` = '$residue_money' WHERE `openid` = '$openid'"; $res2=$conn->query($money_update); //插入操作 $sql2="INSERT INTO `periods_data` (`id`, `period`, `number`, `openid`, `price`) VALUES (NULL, '$period_database', '$number', '$openid', '$price')"; $conn->query($sql2); die( json_encode( array( 'code' => 100, 'msg' => '押注成功' ),480) ); } else { die( json_encode( array( 'code' => 200, 'msg' => '余额不足' ),480) ); } // 余额支付 } } else { die( json_encode( array( 'code' => 200, 'msg' => '该局游戏不存在,请刷新后重试' ),480) ); } } else { die( json_encode( array( 'code' => 200, 'msg' => '游戏暂未开盘' ),480) ); } // 关闭数据库连接 $conn->close(); //放防止重复提交(同个用户一期只能提交一次)
- 代码首先通过include引入了数据库连接文件。
- 接下来,代码检查是否收到了POST请求,如果没有收到POST请求,返回一个JSON格式的错误信息,表示缺少参数。代码从POST请求中获取了期数p e r i o d 、用户标识 period、用户标识period、用户标识openid、用户选择的数字n u m b e r 以及押注金额 number以及押注金额number以及押注金额price。
- 代码查询数据库,获取系统中最后一期的信息,包括期数和是否已经处理的标记。
- 如果查询到最后一期的信息,代码会检查用户提交的期数p e r i o d 是否与系统最后一期的期数一致,并且检查该期是否未处理( period是否与系统最后一期的期数一致,并且检查该期是否未处理(period是否与系统最后一期的期数一致,并且检查该期是否未处理(is_processed为0)。如果期数一致且未处理,继续进行下面的操作。
- 代码查询数据库,检查该用户是否已经在当前期数下进行过押注,如果已经押注过,返回一个JSON格式的错误信息,表示已经押注过。
- 如果用户没有在当前期数下进行过押注,则继续进行余额支付判断。首先查询该用户的余额,并检查余额是否足够支付押注金额。
- 如果余额足够,进行余额扣除操作,更新用户余额,并将押注记录插入periods_data表中。
- 如果余额不足,返回一个JSON格式的错误信息,表示余额不足。
- 如果系统最后一期的期数与用户提交的期数不一致,或者该期已经处理过,返回相应的JSON格式错误信息,提示游戏状态或操作不合法。
- 最后,关闭数据库连接。
前端页面渲染接口
新建get_last_periods.php
<?php include '../api/conn.php'; header("Content-type:text/html;charset=utf-8");//字符编码设置 if (!$_POST) { die( json_encode( array( 'code' => 200, 'msg' => '缺少参数' ),480) ); } $sql = "SELECT * FROM game_periods ORDER BY period DESC LIMIT 1"; $result =$conn->query($sql); if (!$result) { die("fail"); } $jarr = array(); while ($rows=mysqli_fetch_array($result,MYSQLI_ASSOC)){ $count=count($rows);//不能在循环语句中,由于每次删除 row数组长度都减小 for($i=0;$i<$count;$i++){ unset($rows[$i]);//删除冗余数据 } array_push($jarr,$rows); } // $str=json_encode($jarr);//将数组进行json编码 // $info = json_decode(trim($jarr),true); die( json_encode( array( 'code' => 100, 'data' => $jarr, 'msg' => '获取成功' ),480) ); ?>
MQTT消息通知写入数据库
$receiver = "$openid"; $content = $msg; send_mqtt_message($receiver, $content,$conn,'0');
演示操作
可以去小程序【自动打卡小助手】里面体验,下面是演示视频
【uniapp】实现买定离手小游戏