种植园

修复宠物喂食时出现的饱食度没有增加的bug

在feed方法中监听是否喂食成功的pet_feed_success通知中, 保存更新后的hp_time.
my_orchard.html代码:

<!DOCTYPE html>
<html>
<head><title>用户中心</title><meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"><meta charset="utf-8"><link rel="stylesheet" href="../static/css/main.css"><script src="../static/js/vue.js"></script><script src="../static/js/axios.js"></script><script src="../static/js/main.js"></script><script src="../static/js/uuid.js"></script><script src="../static/js/settings.js"></script><script src="../static/js/socket.io.js"></script>
</head>
<body><div class="app orchard orchard-frame" id="app"><div class="background"><img class="grassland2" src="../static/images/grassland2.png" alt=""><img class="mushroom1" src="../static/images/mushroom1.png" alt=""><img class="stake1" src="../static/images/stake1.png" alt=""><img class="stake2" src="../static/images/stake2.png" alt=""></div><div class="pet-box"><div class="pet"><span @click='feed(0)' class="popped" v-if='pet_list[0] && pet_list[0].hp<90 && pet_list[0].hp>0 && pet_food_num > 0'><img class='pet-prop' src="../static/images/prop4.png" alt=""></span><img v-if='pet_list.length > 0' class="pet-item" :src="settings.static_url+pet_list[0].image" alt=""></div><div class="pet" v-if='pet_number > 1'><span @click='feed(1)' class="popped" v-if='pet_list[1] && pet_list[1].hp<90 && pet_list[1].hp>0 && pet_food_num > 0'><img class='pet-prop' src="../static/images/prop4.png" alt=""></span><img v-if='pet_list.length > 1' class='pet-item' :src="settings.static_url+pet_list[1].image" alt=""></div><div class="pet turned_off" v-if='pet_number == 1'><img class="turned_image" src="../static/images/turned_off.png" alt=""><p>请购买宠物</p></div></div><div class="tree-list"><div class="tree-box"><div class="tree" v-for='tree in user_tree_data.user_tree_list'><img :src="tree_img(tree.status)" alt=""></div><!-- 已激活但是未种植的树桩列表 --><div class="tree" v-for='i in active_tree'><img src="../static/images/tree1.png" alt=""></div><!-- 未激活树桩列表 --><div @click='unlock_tree' class="tree" v-for='i in lock_tree'><img src="../static/images/tree0.png" alt=""></div></div></div><div class="prop-list"><div class="prop"><img src="../static/images/prop1.png" alt=""><span>{{fertilizer_num}}</span><p>化肥</p></div><div class="prop"><img src="../static/images/prop2.png" alt=""><span>{{shears}}</span><p>修剪</p></div><div class="prop"><img src="../static/images/prop3.png" alt=""><span>{{waters}}</span><p>浇水</p></div><div class="prop"><img src="../static/images/prop4.png" alt=""><span>{{pet_food_num}}</span><p>宠物粮</p></div></div><div class="pet-hp-list"><div class="pet-hp" v-for='pet in pet_list'><p>宠物1 饱食度</p><div class="hp"><div :style="{width: pet.hp+'%', backgroundColor: bg(pet.hp)}" class="process">{{pet.hp}}%</div></div></div></div></div><script>apiready = function(){init();new Vue({el:"#app",data(){return {namespace: '/mofang',token:"",socket: null,pet_food_num: 0,  // 宠物粮数量fertilizer_num: 0,  // 化肥数量waters: 0,  // 浇水次数shears: 0,  // 剪刀次数pet_list: [],user_tree_data:{'total_tree': 9,  // 总树桩数量'user_tree_number': 0,  // 当前用户激活树桩数量'user_tree_list': [  // 当前种植的树桩列表状态],},tree_status:{},// user_tree_data:{//   'total_tree': 9,  // 总树桩数量//  'user_tree_number': 5,  // 当前用户激活树桩数量//   'user_tree_list': [  // 当前种植的树桩列表状态//         {  // 树桩状态//            'time': 1609808084,  // 种植时间//            'status': 4,  // 植物状态//           'has_time': 300,  // 状态时间//       },//    ],// },// pet_number: [],// tree_status:{//     'tree_status_0': 'tree0.png',  // 树桩//  'tree_status_1': 'tree1.png',  // 空桩//  'tree_status_2': 'tree2.png',  // 幼苗//  'tree_status_3': 'tree3.png',  // 成长//  'tree_status_4': 'tree4.png',  // 成熟// },pet_number: [],timeout: 0,prev:{name:"",url:"",params:{}},current:{name:"orchard",url:"orchard.html",params:{}},}},computed:{// 已激活但是未使用的树桩active_tree(){return parseInt(this.user_tree_data.user_tree_number - this.user_tree_data.user_tree_list.length);},// 未激活的剩余树桩lock_tree(){return parseInt(this.user_tree_data.total_tree - this.user_tree_data.user_tree_number);},},created(){this.show_pet_list();this.show_tree_list();this.get_prop_list();},methods:{feed(pet_key){// 我的背包this.game.save({'pet_key': pet_key});  // 记录本次喂养的宠物下标this.game.goFrame('package', 'package.html', this.current, null, {type: 'push',subType: 'from_top',duration: 300});api.addEventListener({name: 'pet_feed_success'}, (ret, err)=>{if( ret ){this.pet_list[ret.value.pet_key].hp = Math.ceil(ret.value.hp_time / this.pet_list[ret.value.pet_key].pet_hp_max * 100)this.pet_list[ret.value.pet_key].hp_time = ret.value.hp_time;this.game.save({'pet_list': this.pet_list})}});},bg(hp){if(hp>90){return '#f00';}else if(hp>60){return '#a00';}else if(hp>30){return '#600';}else {return '#300';}},get_prop_list(){// 更新道具列表信息api.addEventListener({name: 'update_prop_data'}, (ret, err)=>{if( ret ){this.pet_food_num = this.game.get('pet_food_num');this.fertilizer_num = this.game.get('fertilizer_num');}});},tree_img(status){return '../static/images/'+this.tree_status[status];},show_pet_list(){api.addEventListener({name: 'pet_show_success'}, (ret, err)=>{if( ret ){// 显示宠物相关this.pet_list = this.game.get('pet_list');this.pet_number = parseInt(this.game.get('pet_number'));var last_timer = null;for(let i in this.pet_list){this.pet_list[i].timer = setInterval(()=>{// 保证定时器中每次读取的都是最新的宠物信息this.pet_list = this.game.get('pet_list');if(this.pet_list.length<1){clearInterval(last_timer);return}if(this.pet_list[i].hp_time<1){// 宠物挂了api.sendEvent({name: 'pet_die',extra: {}});last_timer = this.pet_list[i].timer;clearInterval(this.pet_list[i].timer);}this.pet_list[i].hp_time -= 0.5;this.pet_list[i].hp = Math.ceil(this.pet_list[i].hp_time / this.pet_list[i].pet_hp_max * 100)this.game.save({'pet_list': this.pet_list});}, 500);}}});},show_tree_list(){api.addEventListener({name: 'user_tree_data'}, (ret, err)=>{if( ret ){// 用户种植植物信息this.user_tree_data.tree_total = parseInt(this.game.get('tree_total'));this.user_tree_data.user_tree_number = parseInt(this.game.get('user_tree_number'));this.user_tree_data.user_tree_list = this.game.get('user_tree_list');this.tree_status = this.game.get('tree_status');this.pet_food_num = this.game.get('pet_food_num');this.fertilizer_num = this.game.get('fertilizer_num');this.waters = this.game.get('waters');this.shears = this.game.get('shears');}});},unlock_tree(){// 激活树桩通知api.confirm({title: '提示',msg: '是否激活树桩?',buttons: ['确定', '取消']}, (ret, err)=>{if( ret.buttonIndex == 1 ){api.sendEvent({name: 'active_tree',extra: {}});}});// 激活成功!api.addEventListener({name: 'active_tree_success'}, (ret, err)=>{if( ret ){// 新增树桩的数量this.user_tree_data.user_tree_number+=1;this.game.save({'user_tree_number': this.user_tree_data.user_tree_number});}});}}});}</script>
</body>
</html>

宠物挂了的bug问题

修复当用户拥有2个宠物时,如果第1个宠物挂了,会出现第二个宠物变成第1个宠物的情况,会导致数据发生混乱出现bug

解决:

  1. 在第一个宠物挂了以后, 因为当初保存宠物数据的时候使用列表保存,所以在第一个成员被清理的时候,肯定会出现数据成员往前调整的现象
    所以可以把保存宠物的数据格式从列表改成字典.

  2. 如果当前用户有2个宠物,而第1个宠物挂了以后,则不直接删除第一个宠物,而是暂时保留数据并对数据进行状态改动.
    2.1 在宠物死亡的时候,判断如果是第一个宠物,则添加一个is_die=true的标记
    2.2 在宠物显示的时候,如果当前宠物出现is_die的标记,则不显示.
    2.3 用户在背包使用宠物道具时, 判断第一个宠物是否有is_die的标记,如果有,则进行替换

socket.py, 代码;


from application import socketio
from flask import request
from application.apps.users.models import User
from flask_socketio import join_room, leave_room
from application import mongo
from .models import Goods, Setting, db
from status import APIStatus as status
from message import ErrorMessage as errmsg# 建立socket通信
# @socketio.on('connect', namespace='/mofang')
# def user_connect():
#     """用户连接"""
#     print('用户%s连接过来了!' % request.sid)
#     # 主动响应数据给客户端
#     socketio.emit('server_response', 'hello', namespace='/mofang')# 断开socket通信
@socketio.on('disconnect', namespace='/mofang')
def user_disconnect():print('用户%s退出了种植园' % request.sid)@socketio.on('login', namespace='/mofang')
def user_login(data):# 分配房间room = data['uid']join_room(room)# 保存当前用户和sid的绑定关系# 判断当前用户是否在mongo中有记录query = {'_id': data['uid']}ret = mongo.db.user_info_list.find_one(query)if ret:mongo.db.user_info_list.update_one(query, {'$set': {'sid': request.sid}})else:mongo.db.user_info_list.insert_one({'_id': data['uid'],'sid': request.sid,})# 返回种植园的相关配置参数orchard_settings = {}setting_list = Setting.query.filter(Setting.is_deleted==False, Setting.status==True).all()"""现在的格式:[<Setting package_number_base>, <Setting package_number_max>, <Setting package_unlock_price_1>...]需要返回的格式:{package_number_base:4,package_number_max: 32,...}"""for item in setting_list:orchard_settings[item.name] = item.value# 返回当前用户相关的配置参数user_settings = {}# 从mongo中查找用户信息,判断用户是否激活了背包格子user_dict = mongo.db.user_info_list.find_one({'sid': request.sid})# 背包格子if user_dict.get('package_number') is None:user_settings['package_number'] = orchard_settings.get('package_number_base', 4)mongo.db.user_info_list.update_one({'sid': request.sid}, {'$set': {'package_number': user_settings['package_number']}})else:user_settings['package_number'] = user_dict.get('package_number')"""种植园植物信息"""# 总树桩数量setting = Setting.query.filter(Setting.name == 'user_total_tree').first()if setting is None:tree_total = 9else:tree_total = int(setting.value)# 用户已经激活的树桩setting = Setting.query.filter(Setting.name == 'user_active_tree').first()if setting is None:user_tree_number = 3else:user_tree_number = int(setting.value)user_tree_number = user_dict.get('user_tree_number', user_tree_number)# 种植的植物列表user_tree_list = user_dict.get('user_tree_list', [])key = 0for tree_item in user_tree_list:tree_item['status'] = 'tree_status_%s' % int(tree_item['status'])  # 植物状态tree_item['water_time'] = redis.ttl('user_tree_water_%s_%s' % (data['uid'], key))tree_item['growup_time'] = redis.ttl('user_tree_growup_%s_%s' % (data['uid'], key))key+=1# 植物状态信息status_list = ['tree_status_0','tree_status_1','tree_status_2','tree_status_3','tree_status_4',]setting_list = Setting.query.filter(Setting.name.in_(status_list)).all()tree_status = {}for item in setting_list:tree_status[item.name] = item.value"""显示植物相关道具"""# 获取背包中的化肥和宠物粮fertilizer_num, pet_food_num = get_package_prop_list(user_dict)# 获取剪刀和浇水# 只有植物处于成长期才会允许裁剪# 只有植物处于幼苗期才会允许浇水waters = 0shears = 0user_tree_list = user_dict.get('user_tree_list', [])if len(user_tree_list) > 0:key = 0for tree in user_tree_list:if(tree['status'] == 'tree_status_%s' % 2) and int(tree.get('waters', 0)) == 0:"""处于幼苗期"""# 判断只有种植指定时间以后的幼苗才可以浇水interval_time = redis.ttl('user_tree_water_%s_%s' % (user_dict.get('_id'), key))if interval_time == -2:waters+=1elif(tree['status'] == 'tree_status_%s' % 3) and int(tree.get('shears', 0)) == 0:"""处于成长期"""interval_time = redis.ttl('user_tree_shears_%s_%s' % (user_dict.get('_id'), key))if interval_time == -2:shears += 1key+=1message = {'errno': status.CODE_OK,'errmsg': errmsg.ok,'orchard_settings': orchard_settings,'user_settings': user_settings,'tree_total': tree_total,'user_tree_number': user_tree_number,'user_tree_list': user_tree_list,'fertilizer_num': fertilizer_num,'pet_food_num': pet_food_num,'tree_status': tree_status,'waters': waters,'shears': shears,}socketio.emit('login_response', message, namespace='/mofang', room=room)def get_package_prop_list(user_dict):fertilizer_num = 0pet_food_num = 0prop_list = user_dict.get('prop_list', {})for prop_item, num in prop_list.items():pid = prop_item.split('_')[-1]num = int(num)prop_obj = Goods.query.get(pid)if prop_obj.prop_type == 2:# 提取化肥fertilizer_num += numelif prop_obj.prop_type == 3:# 提取宠物粮pet_food_num += numreturn fertilizer_num, pet_food_num@socketio.on('user_buy_prop', namespace='/mofang')
def user_buy_prop(data):"""用户购买道具"""room = request.sid# 从mongo中获取当前用户信息user_info = mongo.db.user_info_list.find_one({'sid': request.sid})user = User.query.get(user_info.get('_id'))if user is None:socketio.emit('user_buy_prop_response', {'errno': status.CODE_NO_USER, 'errmsg': errmsg.user_not_exists}, namespace='/mofang', room=room)return# 判断背包物品存储是否达到上限use_package_number = int(user_info.get('use_package_number', 0))  # 当前已经使用的格子数量package_number = int(user_info.get('package_number', 0))  # 当前用户已经解锁的格子数量# 本次购买道具需要使用的格子数量setting = Setting.query.filter(Setting.name == 'td_prop_max').first()if setting is None:td_prop_max = 10else:td_prop_max = int(setting.value)# 计算购买道具以后需要额外占用的格子数量if('prop_%s' % data['pid']) in user_info.get('prop_list', {}):"""曾经购买过当前道具"""prop_num = int(user_info.get('prop_list')['prop_%s' % data['pid']])  # 购买前的道具数量new_prop_num = prop_num + int(data['num'])  # 如果成功购买道具以后的数量old_td_num = prop_num // td_prop_maxif prop_num % td_prop_max > 0:old_td_num += 1new_td_num = new_prop_num // td_prop_maxif new_prop_num % td_prop_max > 0:new_td_num += 1td_num = new_td_num - old_td_numelse:"""新增购买的道具"""# 计算本次购买道具需要占用的格子数量if int(data['num']) > td_prop_max:"""需要多个格子"""td_num = int(data['num']) // td_prop_maxif int(data['num']) % td_prop_max > 0:td_num += 1else:"""需要一个格子"""td_num = 1if use_package_number + td_num > package_number:"""超出存储上限"""socketio.emit('user_buy_prop_response', {'errno': status.CODE_NO_PACKAGE, 'errmsg': errmsg.no_package}, namespace='/mofang', room=room)return# 从mysql中获取商品价格prop = Goods.query.get(data['pid'])if user.money > 0:  # 当前商品需要通过RMB购买if float(user.money) < float(prop.price) * int(data['num']):socketio.emit('user_buy_prop_response', {'errno': status.CODE_NO_MONEY, 'errmsg': errmsg.money_no_enough}, namespace='/mofang', room=room)returnelse:"""当前通过果子进行购买"""if int(user.credit) < int(prop.credit) * int(data['num']):socketio.emit('user_buy_prop_response', {'errno': status.CODE_NO_CREDIT, 'errmsg': errmsg.credit_no_enough}, namespace='/mofang', room=room)return# 从mongo中获取用户列表信息,提取购买的商品数量进行累加和余额query = {'sid': request.sid}if user_info.get('prop_list') is None:"""此前没有购买任何道具"""message = {'$set': {'prop_list': {'prop_%s' % prop.id: int(data['num'])}}}mongo.db.user_info_list.update_one(query, message)else:"""此前有购买了道具"""prop_list = user_info.get('prop_list')  # 道具列表if('prop_%s' % prop.id) in prop_list:"""如果再次同一款道具"""prop_list[('prop_%s' % prop.id)] = prop_list[('prop_%s' % prop.id)] + int(data['num'])else:"""此前没有购买过这种道具"""prop_list[('prop_%s' % prop.id)] = int(data['num'])mongo.db.user_info_list.update_one(query, {'$set': {'prop_list': prop_list}})# 扣除余额或果子if prop.price > 0:user.money = float(user.money) - float(prop.price) * int(data['num'])else:user.credit = int(user.credit) - int(prop.credit) * int(data['num'])db.session.commit()# 返回购买成功的信息socketio.emit('user_buy_prop_response', {'errno': status.CODE_OK, 'errmsg': errmsg.ok}, namespace='/mofang', room=room)# 返回最新的用户道具列表user_prop()@socketio.on('user_prop', namespace='/mofang')
def user_prop():"""用户道具"""userinfo = mongo.db.user_info_list.find_one({'sid': request.sid})prop_list = userinfo.get('prop_list', {})prop_id_list = []for prop_str, num in prop_list.items():pid = int(prop_str[5:])prop_id_list.append(pid)data = []prop_list_data = Goods.query.filter(Goods.id.in_(prop_id_list)).all()setting = Setting.query.filter(Setting.name == 'td_prop_max').first()if setting is None:td_prop_max = 10else:td_prop_max = int(setting.value)for prop_data in prop_list_data:num = int(prop_list[('prop_%s' % prop_data.id)])if td_prop_max > num:data.append({'num': num,'image': prop_data.image,'pid': prop_data.id,'pty': prop_data.prop_type,})else:padding_time = num // td_prop_maxpadding_last = num % td_prop_maxarr = [{'num': td_prop_max,'image': prop_data.image,'pid': prop_data.id,'pty': prop_data.prop_type,}] * padding_timeif padding_last != 0:arr.append({'num': padding_last,'image': prop_data.image,'pid': prop_data.id,'pty': prop_data.prop_type,})data = data + arr# 保存当前用户已经使用的格子数量mongo.db.user_info_list.update_one({'sid':request.sid}, {'$set': {'use_package_number': len(data)}})room = request.sidfertilizer_num, pet_food_num = get_package_prop_list(userinfo)socketio.emit('user_prop_response', {'errno': status.CODE_OK,'errmsg': errmsg.ok,'data': data,'fertilizer_num': fertilizer_num,'pet_food_num': pet_food_num,}, namespace='/mofang', room=room)@socketio.on('unlock_package', namespace='/mofang')
def unlock_package():"""解锁背包"""room = request.sid# 从mongo获取当前用户解锁的格子数量user_info = mongo.db.user_info_list.find_one({'sid': request.sid})user = User.query.get(user_info.get('_id'))if user is None:socketio.emit('unlock_package_response', {'errno': status.CODE_NO_USER, 'errmsg': errmsg.user_not_exists}, namespace='/mofang', room=room)returnpackage_number = int(user_info.get('package_number'))num = 7 - (32 - package_number) // 4  # 没有解锁的格子# 从数据库中获取解锁背包的价格setting = Setting.query.filter(Setting.name == 'package_unlock_price_%s' % num).first()if setting is None:unlock_price = 0else:unlock_price = int(setting.value)# 判断是否有足够的积分或者价格room = request.sidif user.money < unlock_price:socketio.emit('unlock_package_response', {'errno': status.CODE_NO_MONEY, 'errmsg': errmsg.money_no_enough}, namespace='/mofang', room=room)return# 解锁成功user.money = float(user.money) - float(unlock_price)db.session.commit()# mongo中调整数量mongo.db.user_info_list.update_one({'sid': request.sid}, {'$set': {'package_number': package_number + 1}})# 返回解锁的结果socketio.emit('unlock_package_response', {'errno': status.CODE_OK,'errmsg': errmsg.ok}, namespace='/mofang', room=room)import math
from application import redis
@socketio.on('pet_show', namespace='/mofang')
def pet_show():"""显示宠物"""room = request.siduser_info = mongo.db.user_info_list.find_one({'sid': request.sid})user = User.query.get(user_info.get('_id'))if user is None:socketio.emit('pet_show_response', {'errno': status.CODE_NO_USER, 'errmsg': errmsg.user_not_exists}, namespace='/mofang', room=room)return# 获取宠物列表pet_list = user_info.get('pet_list', [])"""pet_list: [{ "pid":11,"image":"pet.png","hp":100%,"created_time":xxxx-xx-xx xx:xx:xx,"skill":"70%","has_time":30天},]"""# 从redis中提取当前宠物的饱食度和有效期# 初始化宠物的生命周期pet_hp_max = 10000for key, pet in enumerate(pet_list):setting = Setting.query.filter(Setting.name == 'pet_hp_max_%s' % pet['pid']).first()if setting is None:pet_hp_max = 7200else:pet_hp_max = int(setting.value)pet['hp'] = math.ceil(redis.ttl('pet_%s_%s_hp' % (user.id, key + 1)) / pet_hp_max * 100)pet['has_time'] = redis.ttl('pet_%s_%s_expire' % (user.id, key + 1))pet['hp_time'] = redis.ttl('pet_%s_%s_hp' % (user.id, key + 1))pet['pet_hp_max'] = pet_hp_max# 在饱食度低于0时,给当前宠物进行标记if pet['hp'] <=0:pet['is_die'] = 1redis.delete('pet_%s_%s_expire' % (user.id, key + 1))mongo.db.user_info_list.update_one({'sid': room}, {'$set': {'pet_list': pet_list}})pet_number = user_info.get('pet_number', 1)print(pet_list)socketio.emit('pet_show_response',{'errno': status.CODE_OK,'errmsg': errmsg.ok,'pet_list': pet_list,'pet_number': pet_number,},namespace='/mofang',room=room)from datetime import datetime
@socketio.on('use_prop', namespace='/mofang')
def use_prop(data):"""使用道具"""pid = data.get('pid')pet_key = data.get('pet_key', 0)room = request.sid# 获取mongo中的用户信息user_info = mongo.db.user_info_list.find_one({'sid': request.sid})# 获取mysql中的用户信息user = User.query.get(user_info.get('_id'))if user is None:socketio.emit('pet_use_response', {'errno': status.CODE_NO_USER, 'errmsg': errmsg.user_not_exists}, namespace='/mofang', room=room)return# 获取道具prop_data = Goods.query.get(pid)if prop_data is None:socketio.emit('pet_use_response', {'errno': status.CODE_NO_SUCH_PROP, 'errmsg': errmsg.not_such_prop}, namespace='/mofang', room=room)returnif int(prop_data.prop_type) == 0:"""使用植物道具"""# 1.判断当前的植物数量是否有空余tree_list = user_info.get('user_tree_list', [])# 当前用户最多可种植的数量setting = Setting.query.filter(Setting.name == 'user_active_tree').first()if setting is None:user_tree_number = 3else:user_tree_number = int(setting.value)user_tree_number = user_info.get('user_tree_number', user_tree_number)if len(tree_list) >= user_tree_number:socketio.emit('prop_use_response', {'errno': status.CODE_NO_EMPTY, 'errmsg': errmsg.prop_not_empty}, namespace='/mofang', room=room)return# 使用道具mongo.db.user_info_list.update_one({'sid': room}, {'$push': {'user_tree_list':{  # 植物状态"time": int(datetime.now().timestamp()),  # 种植时间"status": 2,  # 植物状态,2表示幼苗状态"waters": 0,  # 浇水次数'shears': 0,  # 使用剪刀次数}}})# 从种下去到浇水的时间pipe = redis.pipeline()pipe.multi()setting = Setting.query.filter(Setting.name == 'tree_water_time').first()if setting is None:tree_water_time = 3600else:tree_water_time = int(setting.value)# 必须等时间到了才可以浇水pipe.setex('user_tree_water_%s_%s' % (user.id, len(tree_list)), int(tree_water_time), '_')# 必须等时间到了才可以到成长期setting = Setting.query.filter(Setting.name == 'tree_growup_time').first()if setting is None:tree_growup_time = 3600else:tree_growup_time = int(setting.value)pipe.setex('user_tree_growup_%s_%s' % (user.id, len(tree_list)), tree_growup_time, '_')pipe.execute()user_login({'uid': user.id})if int(prop_data.prop_type) == 1:"""使用宠物道具"""# 1. 判断当前的宠物数量# 获取宠物列表pet_list = user_info.get('pet_list', [])if len(pet_list) > 1 and pet_list[0]['is_die'] == 0 and pet_list[1]['is_die'] == 0:socketio.emit('pet_use_response', {'errno': status.CODE_NO_EMPTY, 'errmsg': errmsg.prop_not_empty}, namespace='/mofang', room=room)return# 2. 是否有空余的宠物栏位pet_number = user_info.get('pet_number', 1)length = len(pet_list)if length == 2:live_leng = 0if pet_list[0]['is_die'] == 0:live_leng += 1if pet_list[1]['is_die'] == 0:live_leng += 1elif length == 1 and pet_list[0]['is_die'] == 0:live_leng = 1else:live_leng = 0if live_leng >= pet_number:socketio.emit('pet_use_response', {'errno': status.CODE_NO_EMPTY, 'errmsg': errmsg.prop_not_empty}, namespace='/mofang', room=room)return# 3. 初始化当前宠物信息# 获取有效期和防御值exp_data = Setting.query.filter(Setting.name == 'pet_expire_%s' % pid).first()ski_data = Setting.query.filter(Setting.name == 'pet_skill_%s' % pid).first()if exp_data is None:# 默认7天有效期expire = 7else:expire = exp_data.valueif ski_data is None:skill = 10else:skill = ski_data.value# 在redis中设置当前宠物的饱食度pipe = redis.pipeline()pipe.multi()setting = Setting.query.filter(Setting.name == ('pet_hp_max_%s' % pid)).first()if setting is None:pet_hp_max = 7200else:pet_hp_max = int(setting.value)# 保存到mongo# 判断是否有挂了的宠物在列表中pet_data = {'pid': pid,'image': prop_data.image,'created_time': int(datetime.now().timestamp()),'skill': skill,'is_die': 0,}# 如果第一个宠物是挂了的if len(pet_list) == 0:mongo.db.user_info_list.update_one({'sid': room}, {'$set': {'pet_list': [pet_data]}})pipe.setex('pet_%s_%s_hp' % (user.id, 1), pet_hp_max, '_')pipe.setex('pet_%s_%s_expire' % (user.id, 1), int(expire) * 24 * 60 * 60, '_')elif len(pet_list) == 1 and int(pet_list[0]['is_die']) == 1:"""只有一个挂了的宠物"""mongo.db.user_info_list.update_one({'sid': room}, {'$set': {'pet_list': [pet_data]}})pipe.setex('pet_%s_%s_hp' % (user.id, 1), pet_hp_max, '_')pipe.setex('pet_%s_%s_expire' % (user.id, 1), int(expire) * 24 * 60 * 60, '_')elif len(pet_list) == 1 and int(pet_list[0]['is_die']) == 0:"""只有一个活着的宠物"""mongo.db.user_info_list.update_one({'sid': room}, {'$push': {'pet_list': pet_data}})pipe.setex('pet_%s_%s_hp' % (user.id, 2), pet_hp_max, '_')pipe.setex('pet_%s_%s_expire' % (user.id, 2), int(expire) * 24 * 60 * 60, '_')elif len(pet_list) == 2 and int(pet_list[0]['is_die']) == 1:"""有2个宠物,但是第1个挂了"""pet_list[0] = pet_datamongo.db.user_info_list.update_one({'sid': room}, {'$set': {'pet_list': pet_list}})pipe.setex('pet_%s_%s_hp' % (user.id, 1), pet_hp_max, '_')pipe.setex('pet_%s_%s_expire' % (user.id, 1), int(expire) * 24 * 60 * 60, '_')elif len(pet_list) == 2 and int(pet_list[1]['is_die']) == 1:"""有2个宠物,但是第2个挂了"""pet_list[1] = pet_datapipe.setex('pet_%s_%s_hp' % (user.id, 2), pet_hp_max, '_')pipe.setex('pet_%s_%s_expire' % (user.id, 2), int(expire) * 24 * 60 * 60, '_')mongo.db.user_info_list.update_one({'sid': room}, {'$set': {'pet_list': pet_list}})pipe.execute()pet_show()if int(prop_data.prop_type) == 3:"""宠物喂食"""pet_list = user_info.get('pet_list')if len(pet_list) < 1:socketio.emit('pet_use_response', {'errno': status.CODE_NO_PET, 'errmsg': errmsg.not_pet}, namespace='/mofang', room=room)returncurrent_hp_time = redis.ttl('pet_%s_%s_hp' % (user.id, pet_key + 1))setting = Setting.query.filter(Setting.name == ('pet_hp_max_%s' % (pet_list[pet_key]['pid']))).first()if setting is None:pet_hp_max = 7200else:pet_hp_max = int(setting.value)current_pet_hp = math.ceil(current_hp_time / pet_hp_max * 100)if current_pet_hp > 90:"""饱食度高于90%无法喂养"""socketio.emit('pet_use_response', {'errno': status.CODE_NO_FEED, 'errmsg': errmsg.no_feed}, namespace='/mofang', room=room)returnif current_pet_hp <= 0:socketio.emit('pet_use_response', {'errno': status.CODE_NO_PET, 'errmsg': errmsg.not_pet}, namespace='/mofang', room=room)returnsetting = Setting.query.filter(Setting.name == 'pet_feed_number').first()if setting is None:pet_feed_number = 0.1else:pet_feed_number = float(setting.value)prop_time = pet_hp_max * pet_feed_numbertime = int(current_hp_time + prop_time)redis.expire('pet_%s_%s_hp' % (user.id, pet_key + 1), time)socketio.emit('pet_feed_response', {'errno': status.CODE_OK, 'errmsg': errmsg.ok, 'pet_key': pet_key, 'hp_time': time}, namespace='/mofang', room=room)# 扣除背包中的道具数量prop_list = user_info.get('prop_list', {})for key, value in prop_list.items():if key == ('prop_%s' % pid):if int(value) > 1:prop_list[key] = int(value) - 1else:prop_list.pop(key)breakmongo.db.user_info_list.update_one({'sid': room}, {'$set': {'prop_list': prop_list}})user_prop()socketio.emit('prop_use_response', {'errno': status.CODE_OK, 'errmsg': errmsg.ok}, namespace='/mofang', room=room)@socketio.on('active_tree', namespace='/mofang')
def active_tree():"""激活树桩"""room = request.sid# 获取mongo中的用户信息user_info = mongo.db.user_info_list.find_one({'sid': request.sid})# 获取mysql中的用户信息user = User.query.get(user_info.get('_id'))if user is None:socketio.emit('active_tree_response', {'errno': status.CODE_NO_USER, 'errmsg': errmsg.user_not_exists}, namespace='/mofang', room=room)return# 判断树桩是否达到上限tree_number_data = Setting.query.filter(Setting.name == 'user_active_tree').first()total_tree_data = Setting.query.filter(Setting.name == 'user_total_tree').first()if tree_number_data is None:tree_number = 1else:tree_number = tree_number_data.valueif total_tree_data is None:total_tree = 9else:total_tree = int(total_tree_data.value)user_tree_number = int(user_info.get('user_tree_number', tree_number))if user_tree_number >= total_tree:socketio.emit('active_tree_response', {'errno': status.CODE_NO_EMPTY, 'errmsg': errmsg.prop_not_empty}, namespace='/mofang', room=room)return# 扣除激活的果子数量ret = Setting.query.filter(Setting.name == 'active_tree_price').first()if ret is None:active_tree_price = 100 * user_tree_numberelse:active_tree_price = int(ret.value) * user_tree_numberif active_tree_price > int(user.credit):socketio.emit('active_tree_response', {'errno': status.CODE_NO_CREDIT, 'errmsg': errmsg.credit_no_enough}, namespace='/mofang', room=room)returnuser.credit = int(user.credit) - active_tree_pricedb.session.commit()mongo.db.user_info_list.update_one({'sid': room}, {'$set': {'user_tree_number': user_tree_number+1}})socketio.emit('active_tree_response', {'errno': status.CODE_OK, 'errmsg': errmsg.ok}, namespace='/mofang', room=room)return

客户端代码my_orchard.html:

<!DOCTYPE html>
<html>
<head><title>用户中心</title><meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"><meta charset="utf-8"><link rel="stylesheet" href="../static/css/main.css"><script src="../static/js/vue.js"></script><script src="../static/js/axios.js"></script><script src="../static/js/main.js"></script><script src="../static/js/uuid.js"></script><script src="../static/js/settings.js"></script><script src="../static/js/socket.io.js"></script>
</head>
<body><div class="app orchard orchard-frame" id="app"><div class="background"><img class="grassland2" src="../static/images/grassland2.png" alt=""><img class="mushroom1" src="../static/images/mushroom1.png" alt=""><img class="stake1" src="../static/images/stake1.png" alt=""><img class="stake2" src="../static/images/stake2.png" alt=""></div><div class="pet-box"><div class="pet"><span @click='feed(0)' class="popped" v-if='pet_list[0] && pet_list[0].hp<90 && pet_list[0].hp>0 && pet_food_num > 0'><img class='pet-prop' src="../static/images/prop4.png" alt=""></span><img v-if='pet_list.length > 0 && pet_list[0].hp>0' class="pet-item" :src="settings.static_url+pet_list[0].image" alt=""></div><div class="pet" v-if='pet_number > 1'><span @click='feed(1)' class="popped" v-if='pet_list[1] && pet_list[1].hp<90 && pet_list[1].hp>0 && pet_food_num > 0'><img class='pet-prop' src="../static/images/prop4.png" alt=""></span><img v-if='pet_list.length > 1 && pet_list[1].hp>0' class='pet-item' :src="settings.static_url+pet_list[1].image" alt=""></div><div class="pet turned_off" v-if='pet_number == 1'><img class="turned_image" src="../static/images/turned_off.png" alt=""><p>请购买宠物</p></div></div><div class="tree-list"><div class="tree-box"><div class="tree" v-for='tree in user_tree_data.user_tree_list'><img :src="tree_img(tree.status)" alt=""></div><!-- 已激活但是未种植的树桩列表 --><div class="tree" v-for='i in active_tree'><img src="../static/images/tree1.png" alt=""></div><!-- 未激活树桩列表 --><div @click='unlock_tree' class="tree" v-for='i in lock_tree'><img src="../static/images/tree0.png" alt=""></div></div></div><div class="prop-list"><div class="prop"><img src="../static/images/prop1.png" alt=""><span>{{fertilizer_num}}</span><p>化肥</p></div><div class="prop"><img src="../static/images/prop2.png" alt=""><span>{{shears}}</span><p>修剪</p></div><div class="prop"><img src="../static/images/prop3.png" alt=""><span>{{waters}}</span><p>浇水</p></div><div class="prop"><img src="../static/images/prop4.png" alt=""><span>{{pet_food_num}}</span><p>宠物粮</p></div></div><div class="pet-hp-list"><div class="pet-hp" v-for='pet, key in pet_list'><p>宠物{{key+1}} 饱食度</p><div class="hp"><div :style="{width: pet.hp+'%', backgroundColor: bg(pet.hp)}" class="process">{{pet.hp}}%</div></div></div></div></div><script>apiready = function(){init();new Vue({el:"#app",data(){return {namespace: '/mofang',token:"",socket: null,pet_food_num: 0,  // 宠物粮数量fertilizer_num: 0,  // 化肥数量waters: 0,  // 浇水次数shears: 0,  // 剪刀次数pet_list: [],user_tree_data:{'total_tree': 9,  // 总树桩数量'user_tree_number': 0,  // 当前用户激活树桩数量'user_tree_list': [  // 当前种植的树桩列表状态],},tree_status:{},// user_tree_data:{//   'total_tree': 9,  // 总树桩数量//  'user_tree_number': 5,  // 当前用户激活树桩数量//   'user_tree_list': [  // 当前种植的树桩列表状态//         {  // 树桩状态//            'time': 1609808084,  // 种植时间//            'status': 4,  // 植物状态//           'has_time': 300,  // 状态时间//       },//    ],// },// pet_number: [],// tree_status:{//     'tree_status_0': 'tree0.png',  // 树桩//  'tree_status_1': 'tree1.png',  // 空桩//  'tree_status_2': 'tree2.png',  // 幼苗//  'tree_status_3': 'tree3.png',  // 成长//  'tree_status_4': 'tree4.png',  // 成熟// },pet_number: [],timeout: 0,prev:{name:"",url:"",params:{}},current:{name:"orchard",url:"orchard.html",params:{}},}},computed:{// 已激活但是未使用的树桩active_tree(){return parseInt(this.user_tree_data.user_tree_number - this.user_tree_data.user_tree_list.length);},// 未激活的剩余树桩lock_tree(){return parseInt(this.user_tree_data.total_tree - this.user_tree_data.user_tree_number);},},created(){this.show_pet_list();this.show_tree_list();this.get_prop_list();},methods:{feed(pet_key){// 我的背包this.game.save({'pet_key': pet_key});  // 记录本次喂养的宠物下标this.game.goFrame('package', 'package.html', this.current, null, {type: 'push',subType: 'from_top',duration: 300});api.addEventListener({name: 'pet_feed_success'}, (ret, err)=>{if( ret ){this.pet_list[ret.value.pet_key].hp = Math.ceil(ret.value.hp_time / this.pet_list[ret.value.pet_key].pet_hp_max * 100)this.pet_list[ret.value.pet_key].hp_time = ret.value.hp_time;this.game.save({'pet_list': this.pet_list})}});},bg(hp){if(hp>90){return '#f00';}else if(hp>60){return '#a00';}else if(hp>30){return '#600';}else {return '#300';}},get_prop_list(){// 更新道具列表信息api.addEventListener({name: 'update_prop_data'}, (ret, err)=>{if( ret ){this.pet_food_num = this.game.get('pet_food_num');this.fertilizer_num = this.game.get('fertilizer_num');}});},tree_img(status){return '../static/images/'+this.tree_status[status];},show_pet_list(){api.addEventListener({name: 'pet_show_success'}, (ret, err)=>{if( ret ){// 显示宠物相关this.pet_list = this.game.get('pet_list');this.pet_number = parseInt(this.game.get('pet_number'));var timer = null;setInterval(()=>{// 保证定时器中每次读取的都是最新的宠物信息this.pet_list = this.game.get('pet_list');for(let i in this.pet_list){if(this.pet_list[i].hp_time<1 && this.pet_list[i].is_die==0){// 宠物挂了api.sendEvent({name: 'pet_die',extra: {}});}if(this.pet_list[i].hp_time>0){this.pet_list[i].hp_time -= 0.5;this.pet_list[i].hp = Math.ceil(this.pet_list[i].hp_time / this.pet_list[i].pet_hp_max * 100)}}this.game.save({'pet_list': this.pet_list});}, 500);}});},show_tree_list(){api.addEventListener({name: 'user_tree_data'}, (ret, err)=>{if( ret ){// 用户种植植物信息this.user_tree_data.tree_total = parseInt(this.game.get('tree_total'));this.user_tree_data.user_tree_number = parseInt(this.game.get('user_tree_number'));this.user_tree_data.user_tree_list = this.game.get('user_tree_list');this.tree_status = this.game.get('tree_status');this.pet_food_num = this.game.get('pet_food_num');this.fertilizer_num = this.game.get('fertilizer_num');this.waters = this.game.get('waters');this.shears = this.game.get('shears');}});},unlock_tree(){// 激活树桩通知api.confirm({title: '提示',msg: '是否激活树桩?',buttons: ['确定', '取消']}, (ret, err)=>{if( ret.buttonIndex == 1 ){api.sendEvent({name: 'active_tree',extra: {}});}});// 激活成功!api.addEventListener({name: 'active_tree_success'}, (ret, err)=>{if( ret ){// 新增树桩的数量this.user_tree_data.user_tree_number+=1;this.game.save({'user_tree_number': this.user_tree_data.user_tree_number});}});}}});}</script>
</body>
</html>

魔坊APP项目-24-种植园,修复宠物喂食时出现的饱食度没有增加的bug、宠物挂了的bug问题相关推荐

  1. 魔坊APP项目-23-种植园,宠物和种植物的状态改变、宠物的状态改动

    种植园 宠物和种植物的状态改变 1. 宠物的状态改动 2. 种植物的状态改动 3. 道具的使用 宠物的状态改动 因为宠物有多个,每个宠物会有不同的初始生命的饥饿时间,所以我们提前在mysql中进行配置 ...

  2. 魔坊APP项目-16-种植园、websocket协议、服务端基于socket提供服务(基于房间管理分发信息)、种植园页面展示

    种植园 我们需要完成的种植园,是一个互动频繁,并且要求有一定即时性的模块,所以如果继续基于http协议开发,那么需要通过ajax发送大量http请求,同时因为http本身属于单向通讯,所以服务端无法主 ...

  3. 魔坊APP项目-21-种植园,宠物栏的功能实现、服务端提供显示宠物的api接口、客户端中展示宠物栏和宠物列表以及饱食度、宠物道具的使用

    种植园 一.宠物栏的功能实现 1. 宠物的显示 2. 宠物的使用 3. 宠物的饱食度 4. 宠物的开锁 1.服务端提供显示宠物的api接口 socket.py,代码 ... import math f ...

  4. 魔坊APP项目-19-种植园,我的背包、道具购买

    种植园 一.我的背包 打开背包,orchard.html,代码: <!DOCTYPE html> <html> <head><title>用户中心< ...

  5. 魔坊APP项目-17-种植园,商城页面、服务端提供商品api,解决App打包编译以后的跨域限制、客户端获取商品列表并进行展示,集成Alipayplus模块完成支付

    种植园 一.商城页面 orchard.html,代码: <!DOCTYPE html> <html> <head><title>用户中心</tit ...

  6. 魔坊APP项目-25-种植园,植物的状态改动、当果树种植以后在celery的异步任务中调整浇水的状态、客户端通过倒计时判断时间,显示浇水道具

    种植园 植物的状态改动 一.当果树种植以后在celery的异步任务中调整浇水的状态 在进行果树种植的时候, 在服务端设置当前果树到等待浇水的redis变量中.通过celery不断进行周期任务的处理, ...

  7. 魔坊APP项目-22-种植园,种植栏的功能实现,客户端根据激活状态和未激活状态分别显示树桩、服务端提供种植植物的相关数据、解锁树桩、植物相关道具使用

    种植园 一.种植栏的功能实现 1. 客户端需要的植物相关参数: 总树桩数量, 当前用户激活树桩数量, 当前种植的树桩数量, 树桩列表状态 2. 客户端根据激活状态和未激活状态分别显示树桩 3. 服务端 ...

  8. 魔坊APP项目-18-种植园,基于支付宝提供的沙箱测试环境开发支付接口、服务端, 处理支付结果的同步通知和异步通知、修复页面底部菜单无法被点击的BUG

    种植园 一.基于支付宝提供的沙箱测试环境开发支付接口 沙箱环境: https://openhome.alipay.com/platform/appDaily.htm?tab=info 开发文档: ht ...

  9. 魔坊APP项目-20-种植园,背包显示道具、用户购买道具的时候,判断背包存储是否达到上限、背包解锁

    种植园 一.背包显示道具 在背包中显示道具,会涉及到用户的背包格子的显示以及解锁问题,所以我们需要在服务端准备一个参数信息, 用于保存种植园中用户的业务参数,例如: 格子的初始化数量, 每次解锁背包格 ...

最新文章

  1. Unity与C#创建一个3D平台游戏 Learn to Create a 3D Platformer Game with Unity C#
  2. 全局变量和局部变量的区别_值得收藏!8大技巧,带你了解菜鸟和高手的区别!...
  3. 智能制造深度报告发布:工业机器人、视觉与工业物联/互联网新方向
  4. datagrid出现相同两组数据_stata 数据操作基础知识:以一篇论文数据操作为例
  5. 钉钉轻松顶住信息洪流的原因,竟然是它
  6. JS正则判断输入框是否仅仅含有汉字、字母和数字
  7. 谈PC安全经验:杀毒八大错误观念
  8. 打了断点为直接运行完_黑社会行为?男子驾校身亡,家属看现场被保安围殴,手臂被打断...
  9. DCMTK3.6.0 安装失败的说明
  10. Flume的开发之 自定义 source 自定义 sink 自定义拦截器
  11. CCF201612-1 中间数(100分)【序列处理+排序】
  12. python怎么读取csv文件-使用Python读写csv文件的三种方法
  13. 三因子两水平doe_温故而知新 | DOE实验设计学习系列之(三):多因子DOE的魅力 (附视频)...
  14. CG100---13年金牛星 调表 型号HA48
  15. 如何在阿里云免费 SSL 证书到期后更新证书操作步骤
  16. 编写一个java_Java入门篇(一)——如何编写一个简单的Java程序
  17. 微信小程序 nodejs+vue校园学生社团管理系统
  18. 简单并查集-加边的无向图
  19. AntV G6 的坑之——从卡掉渣到满帧需要几步
  20. Excel数据分析从入门到精通(十)28个图表之对比分析

热门文章

  1. CSS复仇者联盟立体盒子
  2. DDR2/3的进阶之创建MIG
  3. Processing编程学习指南3.4 鼠标点击和键盘操作
  4. 北大ACM原创题目:母牛的故事(距离推理)
  5. JS 实现别踩白块功能
  6. 8个字符即可令Skype崩溃而且再也打不开
  7. 阿里云学生服务器配置及免费学生机领取攻略
  8. Excel中如何获取汉字拼音首字母
  9. 15:Named Entity Recognition without Labelled Data: A Weak Supervision Approach
  10. 带有示例的Python datetime weekday()方法