目录

1.宠物的状态改动

2.宠物粮道具的使用

3.宠物死亡处理

1.宠物的状态改动

1.在setting表中为每个宠物配置生命周期时间

因为宠物有多个,每个宠物会有不同的初始生命的饥饿时间,所以我们提前在mysql中进行配置参数.

INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (29, 'pet_hp_max_2', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '1号宠物的最大生命周期时间', '86400');
INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (30, 'pet_hp_max_3', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '2号宠物的最大生命周期时间', '3600');
INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (31, 'pet_hp_max_4', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '3号宠物的最大生命周期时间', '86400');
INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (32, 'pet_hp_max_5', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '4号宠物的最大生命周期时间', '86400');

2.调整后端接口:使用宠物后的相关参数设置&用户进入种植园后显示宠物列表相关参数

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 = 9
else:
tree_total = int(setting.value) # 用户已经激活的树桩
setting = Setting.query.filter(Setting.name == "user_active_tree").first()
if setting is None:
user_tree_number = 3
else:
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 = 0
for 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 = 0
shears = 0
user_tree_list = user_dict.get("user_tree_list",[])
if len(user_tree_list) > 0:
key = 0
for 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+=1 elif (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+=1
key+=1
message = {
"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,
}
print(message)
socketio.emit("login_response", message, namespace="/mofang", room=room) def get_package_prop_list(user_dict):
fertilizer_num = 0
pet_food_num = 0
prop_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 += num
elif prop_obj.prop_type == 3:
# 提取宠物粮
pet_food_num += num return 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 = 10
else:
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_max
if prop_num % td_prop_max > 0:
old_td_num+=1
new_td_num = new_prop_num // td_prop_max
if new_prop_num % td_prop_max > 0:
new_td_num+=1
td_num = new_td_num - old_td_num
else:
"""新增购买的道具"""
# 计算本次购买道具需要占用的格子数量 if int(data["num"]) > td_prop_max:
"""需要多个格子"""
td_num = int(data["num"]) // td_prop_max
if int(data["num"]) % td_prop_max > 0:
td_num+=1
else:
"""需要一个格子"""
td_num = 1 if 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)
return
else:
"""当前通过果子进行购买"""
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 = 10
else:
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_max
padding_last = num % td_prop_max
arr = [{
"num": td_prop_max,
"image": prop_data.image,
"pid": prop_data.id,
"pty": prop_data.prop_type,
}] * padding_time
if 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.sid
fertilizer_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():
"""解锁背包"""
# 从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)
return package_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 = 0
else:
unlock_price = int(setting.value) # 判断是否有足够的积分或者价格
room = request.sid
if 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.sid
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("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 = 10000
for 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 = 7200
else:
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 pet_number = user_info.get("pet_number", 1)
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(pid):
"""使用道具"""
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)
return if 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 = 3
else:
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 = 3600
else:
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 = 3600
else:
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:
socketio.emit("pet_use_response", {"errno":status.CODE_NO_EMPTY,"errmsg":errmsg.pet_not_empty}, namespace="/mofang", room=room)
return # 2. 是否有空余的宠物栏位
pet_number = user_info.get("pet_number",1)
if pet_number <= len(pet_list):
socketio.emit("pet_use_response", {"errno":status.CODE_NO_EMPTY,"errmsg":errmsg.pet_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 = 7
else:
expire = exp_data.value if ski_data is None:
skill = 10
else:
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 = 7200
else:
pet_hp_max = int(setting.value) pipe.setex("pet_%s_%s_hp" % (user.id, len(pet_list)+1), pet_hp_max, "_")
pipe.setex("pet_%s_%s_expire" % (user.id, len(pet_list)+1), int(expire)*24*60*60, "_")
pipe.execute() # 基本保存到mongo
mongo.db.user_info_list.update_one({"sid":request.sid},{"$push":{"pet_list":{
"pid": pid,
"image": prop_data.image,
"created_time": int( datetime.now().timestamp() ),
"skill": skill,
}}}) """
db.user_info_list.updateOne({"_id":"52"},{"$push":{"pet_list":{
"pid": 2,
"image": "pet1.png",
"created_time": 1609727155,
"skill": 30,
}}})
""" pet_show() # 扣除背包中的道具数量
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) - 1
else:
prop_list.pop(key)
break mongo.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 = 1
else:
tree_number = tree_number_data.value if total_tree_data is None:
total_tree = 9
else:
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_number
else:
active_tree_price = int(ret.value) * user_tree_number if 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)
return user.credit = int(user.credit) - active_tree_price
db.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

使用宠物后的相关参数设置&用户进入种植园后显示宠物列表相关参数

3.前端:进行倒计时,对宠物的状态进行改动

<!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">
<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">
<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, // 状态时间
// },
// ],
// },
// 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:{
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"));
for( let pet of this.pet_list){
setInterval(()=>{
pet.hp_time-=0.5;
pet.hp = Math.ceil( pet.hp_time / pet.pet_hp_max * 100 )
},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>

前端:进行倒计时,对宠物的状态进行改动-my_orchard.html

4.前端:在倒计时中阻止宠物饱食度进入负数状态

<!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 class="popped">
<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">
<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, // 状态时间
// },
// ],
// },
// 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:{
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"));
for( let pet of this.pet_list){
pet.timer = setInterval(()=>{
if(pet.hp<=0){
// 宠物挂了
clearInterval(pet.timer);
}
pet.hp_time-=0.5;
pet.hp = Math.ceil( pet.hp_time / pet.pet_hp_max * 100 )
},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>

在倒计时中阻止宠物饱食度进入负数状态-my_orchard.html

2.宠物粮道具的使用

1.宠物喂养的半透明图标

添加道具样式, my_orchard.html

      <div class="pet">
<span class="popped">
<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>

css样式, main.css, 代码;

.popped {
transform: translate(-50%, -50%);
border-radius: 5rem;
height: 5rem;
width: 5rem;
display: block;
position: absolute;
opacity: 1;
transition: box-shadow .5s ease-in-out, transform .07s ease-out, opacity .04s ease-in;
top: 6rem;
right: 0rem;
box-shadow: rgb(255, 200, 200) 0px 0px 3rem inset;
z-index: 100;
}
.popped:after {
content: '';
position: absolute;
top: 18%;
left: 18%;
background-color: rgba(191, 255, 255, 0.6);
width: 1.2rem;
height: 1.5rem;
border-radius: 50%;
transform: rotate(45deg) scale(0.8);
}
.popped img{
width: 4rem;
height: 4rem;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}

2.前端:根据宠物的饱食度和道具数量来控制是否显示喂食的图标-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 class="popped" v-if="pet_list[0] && pet_list[0].hp<50 && 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 class="popped" v-if="pet_list[1] && pet_list[1].hp<50 && 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, // 状态时间
// },
// ],
// },
// 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:{
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"));
for( let pet of this.pet_list){
pet.timer = setInterval(()=>{
if(pet.hp<=0){
// 宠物挂了
clearInterval(pet.timer);
}
pet.hp_time-=0.5;
pet.hp = Math.ceil( pet.hp_time / pet.pet_hp_max * 100 )
},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>

根据宠物的饱食度和道具数量来控制是否显示喂食的图标-my_orchard.html

3.后端:实现使用宠物粮道具的逻辑

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 = 9
else:
tree_total = int(setting.value) # 用户已经激活的树桩
setting = Setting.query.filter(Setting.name == "user_active_tree").first()
if setting is None:
user_tree_number = 3
else:
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 = 0
for 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 = 0
shears = 0
user_tree_list = user_dict.get("user_tree_list",[])
if len(user_tree_list) > 0:
key = 0
for 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+=1 elif (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+=1
key+=1
message = {
"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,
}
print(message)
socketio.emit("login_response", message, namespace="/mofang", room=room) def get_package_prop_list(user_dict):
fertilizer_num = 0
pet_food_num = 0
prop_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 += num
elif prop_obj.prop_type == 3:
# 提取宠物粮
pet_food_num += num return 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 = 10
else:
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_max
if prop_num % td_prop_max > 0:
old_td_num+=1
new_td_num = new_prop_num // td_prop_max
if new_prop_num % td_prop_max > 0:
new_td_num+=1
td_num = new_td_num - old_td_num
else:
"""新增购买的道具"""
# 计算本次购买道具需要占用的格子数量 if int(data["num"]) > td_prop_max:
"""需要多个格子"""
td_num = int(data["num"]) // td_prop_max
if int(data["num"]) % td_prop_max > 0:
td_num+=1
else:
"""需要一个格子"""
td_num = 1 if 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)
return
else:
"""当前通过果子进行购买"""
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 = 10
else:
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_max
padding_last = num % td_prop_max
arr = [{
"num": td_prop_max,
"image": prop_data.image,
"pid": prop_data.id,
"pty": prop_data.prop_type,
}] * padding_time
if 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.sid
fertilizer_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():
"""解锁背包"""
# 从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)
return package_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 = 0
else:
unlock_price = int(setting.value) # 判断是否有足够的积分或者价格
room = request.sid
if 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.sid
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("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 = 10000
for 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 = 7200
else:
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 pet_number = user_info.get("pet_number", 1)
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)
return if 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 = 3
else:
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 = 3600
else:
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 = 3600
else:
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:
socketio.emit("pet_use_response", {"errno":status.CODE_NO_EMPTY,"errmsg":errmsg.pet_not_empty}, namespace="/mofang", room=room)
return # 2. 是否有空余的宠物栏位
pet_number = user_info.get("pet_number",1)
if pet_number <= len(pet_list):
socketio.emit("pet_use_response", {"errno":status.CODE_NO_EMPTY,"errmsg":errmsg.pet_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 = 7
else:
expire = exp_data.value if ski_data is None:
skill = 10
else:
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 = 7200
else:
pet_hp_max = int(setting.value) pipe.setex("pet_%s_%s_hp" % (user.id, len(pet_list)+1), pet_hp_max, "_")
pipe.setex("pet_%s_%s_expire" % (user.id, len(pet_list)+1), int(expire)*24*60*60, "_")
pipe.execute() # 基本保存到mongo
mongo.db.user_info_list.update_one({"sid":request.sid},{"$push":{"pet_list":{
"pid": pid,
"image": prop_data.image,
"created_time": int( datetime.now().timestamp() ),
"skill": skill,
}}}) """
db.user_info_list.updateOne({"_id":"52"},{"$push":{"pet_list":{
"pid": 2,
"image": "pet1.png",
"created_time": 1609727155,
"skill": 30,
}}})
""" 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)
return current_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 = 7200
else:
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)
return if current_pet_hp <= 0:
socketio.emit("pet_use_response", {"errno": status.CODE_NO_PET, "errmsg": errmsg.not_pet},
namespace="/mofang", room=room)
return
setting = Setting.query.filter(Setting.name == "pet_feed_number").first()
if setting is None:
pet_feed_number = 0.1
else:
pet_feed_number = float(setting.value)
prop_time = pet_hp_max * pet_feed_number
time = int( current_hp_time + prop_time )
redis.expire("pet_%s_%s_hp" % (user.id,pet_key+1),time)
print({"pet_key":pet_key,"hp_time":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) - 1
else:
prop_list.pop(key)
break mongo.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 = 1
else:
tree_number = tree_number_data.value if total_tree_data is None:
total_tree = 9
else:
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_number
else:
active_tree_price = int(ret.value) * user_tree_number if 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)
return user.credit = int(user.credit) - active_tree_price
db.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

使用宠物粮道具的后端接口

4.前端:点击宠物粮道具,向后端发起通知-package.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>
</head>
<body>
<div class="app frame avatar add_friend package" id="app">
<div class="box">
<p class="title">我的背包</p>
<img class="close" @click="close_frame" src="../static/images/close_btn1.png" alt="">
<div class="prop_list">
<div class="item" v-for="prop in user_package" @click="use_prop(prop.pid)">
<img :src="settings.static_url+prop.image" alt="">
<span>{{prop.num}}</span>
</div>
<div class="item" v-for="number in unlock_td_number"></div>
<div class="item lock" @click="unlock_package()" v-for="number in lock_td_number"></div>
</div>
</div>
</div>
<script>
apiready = function(){
init();
new Vue({
el:"#app",
data(){
return {
td: 36, // 背包格子总数量
user_id: "", // 当前登陆用户Id
orchard_settings:{}, // 种植园相关公共参数
user_settings:{}, // 用户相关私有参数
user_package:[], // 用户背包信息
prev:{name:"",url:"",params:{}},
current:{name:"package",url:"package.html",params:{}},
}
},
computed:{// 计算属性
lock_td_number(){
// 未解锁的格子
return parseInt(this.orchard_settings.package_number_max-this.user_settings.package_number);
},
unlock_td_number(){
// 解锁的格子
return parseInt( this.user_settings.package_number - this.user_package.length);
}
},
created(){
this.user_id = this.game.get("id") || this.game.fget("id");
this.orchard_settings = JSON.parse(this.game.fget("orchard_settings"));
this.user_settings = JSON.parse(this.game.fget("user_settings"));
this.user_package = JSON.parse(this.game.fget("user_package"));
},
methods:{
use_prop(pid){
// 发起使用道具的通知
api.confirm({
title: '提示',
msg: '确认使用当前道具吗?',
buttons: ['确定', '取消']
}, (ret, err)=>{
if( ret.buttonIndex == 1 ){
api.sendEvent({
name: "use_prop",
extra: {
pid: pid,
}
}); }
}); api.addEventListener({
name: 'prop_use_success'
}, (ret, err)=>{
if( ret ){
// 扣除指定道具
var pid = parseInt(ret.value.pid);
for(var i in this.user_package){
if(parseInt(this.user_package[i].pid) == pid){
this.user_package[i].num-=1;
if(this.user_package[i].num == 0){
this.user_package.splice(i,1);
}
}
}
this.game.fsave({"user_package":this.user_package});
}else{
alert( JSON.stringify( err ) );
}
}); },
unlock_package(){
// 解锁格子上限
api.confirm({
title: '提示',
msg: '解锁背包上限',
buttons: ['确定', '取消']
}, (ret, err)=>{
if( ret.buttonIndex == 1 ){ api.sendEvent({
name: 'unlock_package_number',
extra: {}
}); api.addEventListener({
name: 'unlock_package_success'
}, (ret, err)=>{
this.user_settings.package_number=parseInt(this.user_settings.package_number)+1;
this.game.fsave({"user_settings":this.user_settings});
});
}
}); },
close_frame(){
this.game.outFrame("package");
},
}
});
}
</script>
</body>
</html>

前端点击宠物粮道具向后端发起通知-package.html

5.前端:接收道具使用成功的通知-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" id="app">
<img class="music" :class="music_play?'music2':''" @click="music_play=!music_play" src="../static/images/player.png">
<div class="orchard-bg">
<img src="../static/images/bg2.png">
<img class="board_bg2" src="../static/images/board_bg2.png">
</div>
<img class="back" @click="go_index" src="../static/images/user_back.png" alt="">
<div class="header">
<div class="info" @click="go_home">
<div class="avatar">
<img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
<img class="user_avatar" src="../static/images/avatar.png" alt="">
<img class="avatar_border" src="../static/images/avatar_border.png" alt="">
</div>
<p class="user_name">好听的昵称</p>
</div>
<div class="wallet">
<div class="balance" @click="user_recharge">
<p class="title"><img src="../static/images/money.png" alt="">钱包</p>
<p class="num">{{money}}</p>
</div>
<div class="balance">
<p class="title"><img src="../static/images/integral.png" alt="">果子</p>
<p class="num">99,999.00</p>
</div>
</div>
<div class="menu-list">
<div class="menu">
<img src="../static/images/menu1.png" alt="">
排行榜
</div>
<div class="menu">
<img src="../static/images/menu2.png" alt="">
签到有礼
</div>
<div class="menu" @click="go_orchard_shop">
<img src="../static/images/menu3.png" alt="">
道具商城
</div>
<div class="menu">
<img src="../static/images/menu4.png" alt="">
邮件中心
</div>
</div>
</div>
<div class="footer" >
<ul class="menu-list">
<li class="menu">新手</li>
<li class="menu" @click="go_my_package">背包</li>
<li class="menu-center" @click="go_orchard_shop">商店</li>
<li class="menu">消息</li>
<li class="menu">好友</li>
</ul>
</div>
</div>
<script>
apiready = function(){
init();
new Vue({
el:"#app",
data(){
return {
music_play:true,
namespace: '/mofang',
token:"",
money:"",
settings_info:{
orchard: {}, // 种植园公共参数
user:{}, // 用户私有相关参数
},
socket: null,
recharge_list: ['10','20','50','100','200','500','1000'],
timeout: 0,
prev:{name:"",url:"",params:{}},
current:{name:"orchard",url:"orchard.html",params:{}},
}
},
beforeCreate(){
this.game.goFrame("orchard","my_orchard.html", this.current,{
x: 0,
y: 180,
w: 'auto',
h: 410,
},null);
},
created(){
this.checkout();
this.money = this.game.fget("money");
},
methods:{
user_recharge(){
// 发起充值请求
api.actionSheet({
title: '余额充值',
cancelTitle: '取消',
buttons: this.recharge_list
}, (ret, err)=>{
if( ret ){
if(ret.buttonIndex <= this.recharge_list.length){
// 充值金额
money = this.recharge_list[ret.buttonIndex-1];
// 调用支付宝充值
this.create_recharge(money);
}
}else{ }
}); },
create_recharge(money){
// 获取历史信息记录
var token = this.game.get("access_token") || this.game.fget("access_token");
this.game.checkout(this, token, (new_access_token)=>{
this.axios.post("",{
"jsonrpc": "2.0",
"id": this.uuid(),
"method": "Recharge.create",
"params": {
"money": money,
}
},{
headers:{
Authorization: "jwt " + token,
}
}).then(response=>{
if(parseInt(response.data.result.errno)==1000){
// 前往支付宝
var aliPayPlus = api.require('aliPayPlus');
aliPayPlus.payOrder({
orderInfo: response.data.result.order_string,
sandbox: response.data.result.sandbox, // 将来APP上线需要修改成false
}, (ret, err)=>{
pay_result = {
9000:"支付成功",
8000:"正在处理中",
4000:"订单支付失败",
5000:"重复请求",
6001:"取消支付",
6002:"网络连接出错",
6004:"支付结果未知",
}
api.alert({
title: '支付结果',
msg: pay_result[ret.code],
buttons: ['确定']
});
// 通知服务端, 修改充值结果
this.return_recharge(response.data.result.order_number,token);
});
}else{
this.game.print(response.data);
}
}).catch(error=>{
// 网络等异常
this.game.print(error);
});
})
},
return_recharge(out_trade_number,token){
this.axios.post("",{
"jsonrpc": "2.0",
"id": this.uuid(),
"method": "Recharge.return",
"params": {
"out_trade_number": out_trade_number,
}
},{
headers:{
Authorization: "jwt " + token,
}
}).then(response=>{
if(parseInt(response.data.result.errno)==1000){
this.money = response.data.result.money.toFixed(2);
}
})
},
checkout(){
var token = this.game.get("access_token") || this.game.fget("access_token");
this.game.checkout(this,token,(new_access_token)=>{
this.connect();
this.login();
this.user_package();
this.buy_prop();
this.unlock_package_number();
this.show_pet();
this.use_prop();
this.active_tree();
});
},
connect(){
// socket连接
this.socket = io.connect(this.settings.socket_server + this.namespace, {transports: ['websocket']});
this.socket.on('connect', ()=>{
this.game.print("开始连接服务端");
var id = this.game.fget("id");
this.socket.emit("login",{"uid":id});
this.socket.emit("user_prop");
});
},
login(){
this.socket.on("login_response",(message)=>{
this.settings_info.orchard = message.orchard_settings;
this.settings_info.user=message.user_settings;
this.game.fsave({
"orchard_settings":message.orchard_settings,
"user_settings":message.user_settings,
});
this.game.save({
"tree_total":message.tree_total,
"user_tree_number":message.user_tree_number,
"user_tree_list":message.user_tree_list,
"tree_status":message.tree_status,
"pet_food_num":message.pet_food_num,
"fertilizer_num":message.fertilizer_num,
"waters":message.waters,
"shears":message.shears,
});
setTimeout(()=>{
// 通知种植园页面获取到了当前用户的种植信息
api.sendEvent({
name: 'user_tree_data',
extra: {}
});
},500);
});
},
user_package(){
// 用户背包道具列表
this.socket.on("user_prop_response",(message)=>{
this.game.fsave({
"user_package":message.data,
});
// 界面中的道具信息
this.game.save({
"pet_food_num":message.pet_food_num,
"fertilizer_num":message.fertilizer_num,
});
api.sendEvent({
name: 'update_prop_data',
extra: { }
}); })
},
go_index(){
this.game.goWin("root");
},
go_friends(){
this.game.goFrame("friends","friends.html",this.current);
this.game.goFrame("friend_list","friend_list.html",this.current,{
x: 0,
y: 190,
w: 'auto',
h: 'auto',
},null,true);
},
go_home(){
this.game.goWin("user","user.html", this.current);
},
go_orchard_shop(){
// 种植园商店
this.game.goFrame("orchard_shop","shop.html", this.current,null,{
type:"push",
subType:"from_top",
duration:300
});
},
go_my_package(){
// 我的背包
this.game.goFrame("package","package.html", this.current,null,{
type:"push",
subType:"from_top",
duration:300
});
},
buy_prop(){
api.addEventListener({
name: 'buy_prop'
}, (ret, err)=>{
if( ret ){
// 用户购买道具
this.socket.emit("user_buy_prop",ret.value);
}
});
this.socket.on("user_buy_prop_response",(message)=>{
alert(message.errmsg); })
},
use_prop(){
// 使用道具
var pid = 0;
api.addEventListener({
name: 'use_prop'
}, (ret, err)=>{
if( ret ){
// 用户使用道具
pid = ret.value.pid;
var pet_key = this.game.get("pet_key");
if(pet_key<1){
pet_key = 0;
}
this.socket.emit("use_prop",{pid:ret.value.pid,pet_key:pet_key});
}
}); this.socket.on("prop_use_response",(message)=>{
if(parseInt(message.errno) === 1000){
api.sendEvent({
name: 'prop_use_success',
extra: {
pid: pid
}
});
}else{
api.alert({
title: '提示',
msg: message.errmsg,
}); }
}); this.socket.on("pet_feed_response",(message)=>{
if(parseInt(message.errno) === 1000){
api.sendEvent({
name: 'pet_feed_success',
extra: {
pet_key: message.pet_key,
hp_time: message.hp_time
}
});
}else{
api.alert({
title: '提示',
msg: message.errmsg,
}); }
}) },
unlock_package_number(){
api.addEventListener({
name: 'unlock_package_number'
}, (ret, err)=>{
if( ret ){
// 用户购买道具
this.socket.emit("unlock_package");
}
}); this.socket.on("unlock_package_response",(message)=>{
if(parseInt(message.errno) === 1000){
api.sendEvent({
name: 'unlock_package_success',
extra: {
}
});
}else{
api.alert({
title: '提示',
msg: message.errmsg,
}); } })
},
show_pet(){
// 显示宠物
this.socket.emit("pet_show");
this.socket.on("pet_show_response",(message)=>{
if(parseInt(message.errno) === 1000){
// 把宠物信息保存到本地
this.game.save({"pet_list":message.pet_list})
this.game.save({"pet_number":message.pet_number})
setTimeout(()=>{
api.sendEvent({
name: 'pet_show_success',
extra: {}
});
},500);
}else{
api.alert({
title: '提示',
msg: message.errmsg,
});
} })
},
active_tree(){
// 激活树桩
api.addEventListener({
name: 'active_tree'
}, (ret, err)=>{
if( ret ){
this.socket.emit("active_tree");
}
}); this.socket.on("active_tree_response",(message)=>{
if(parseInt(message.errno) === 1000){
// 更新数据到本地
api.sendEvent({
name: 'active_tree_success',
extra: {}
});
}else{
api.alert({
title: '提示',
msg: message.errmsg,
});
} })
}
}
});
}
</script>
</body>
</html>

接收道具使用成功的通知-orchard.html

6.前端:点击宠物喂养小透明图标,也可以进行喂养-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, // 状态时间
// },
// ],
// },
// 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.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"));
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[i].hp<=0){
// 宠物挂了
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 )
},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>

点击喂养透明图标,也可以进行喂养-my_orchard.html

3.宠物死亡处理

1.后端读取宠物信息,若死亡,则清除宠物信息

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 = 9
else:
tree_total = int(setting.value) # 用户已经激活的树桩
setting = Setting.query.filter(Setting.name == "user_active_tree").first()
if setting is None:
user_tree_number = 3
else:
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 = 0
for 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 = 0
shears = 0
user_tree_list = user_dict.get("user_tree_list",[])
if len(user_tree_list) > 0:
key = 0
for 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+=1 elif (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+=1
key+=1
message = {
"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 = 0
pet_food_num = 0
prop_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 += num
elif prop_obj.prop_type == 3:
# 提取宠物粮
pet_food_num += num return 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 = 10
else:
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_max
if prop_num % td_prop_max > 0:
old_td_num+=1
new_td_num = new_prop_num // td_prop_max
if new_prop_num % td_prop_max > 0:
new_td_num+=1
td_num = new_td_num - old_td_num
else:
"""新增购买的道具"""
# 计算本次购买道具需要占用的格子数量 if int(data["num"]) > td_prop_max:
"""需要多个格子"""
td_num = int(data["num"]) // td_prop_max
if int(data["num"]) % td_prop_max > 0:
td_num+=1
else:
"""需要一个格子"""
td_num = 1 if 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)
return
else:
"""当前通过果子进行购买"""
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 = 10
else:
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_max
padding_last = num % td_prop_max
arr = [{
"num": td_prop_max,
"image": prop_data.image,
"pid": prop_data.id,
"pty": prop_data.prop_type,
}] * padding_time
if 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.sid
fertilizer_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():
"""解锁背包"""
# 从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)
return package_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 = 0
else:
unlock_price = int(setting.value) # 判断是否有足够的积分或者价格
room = request.sid
if 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.sid
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("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 = 10000
die_pet = []
for 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 = 7200
else:
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
if pet["hp"] <=0:
die_pet.append(pet)
redis.delete("pet_%s_%s_expire" % (user.id,key+1)) # 清除死亡的宠物信息
if len(die_pet)>0:
for del_pet in die_pet:
pet_list.remove(del_pet)
mongo.db.user_info_list.update_one({"sid":room},{"$set":{"pet_list":pet_list}}) pet_number = user_info.get("pet_number", 1)
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)
return if 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 = 3
else:
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 = 3600
else:
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 = 3600
else:
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:
socketio.emit("pet_use_response", {"errno":status.CODE_NO_EMPTY,"errmsg":errmsg.pet_not_empty}, namespace="/mofang", room=room)
return # 2. 是否有空余的宠物栏位
pet_number = user_info.get("pet_number",1)
if pet_number <= len(pet_list):
socketio.emit("pet_use_response", {"errno":status.CODE_NO_EMPTY,"errmsg":errmsg.pet_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 = 7
else:
expire = exp_data.value if ski_data is None:
skill = 10
else:
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 = 7200
else:
pet_hp_max = int(setting.value) pipe.setex("pet_%s_%s_hp" % (user.id, len(pet_list)+1), pet_hp_max, "_")
pipe.setex("pet_%s_%s_expire" % (user.id, len(pet_list)+1), int(expire)*24*60*60, "_")
pipe.execute() # 基本保存到mongo
mongo.db.user_info_list.update_one({"sid":request.sid},{"$push":{"pet_list":{
"pid": pid,
"image": prop_data.image,
"created_time": int( datetime.now().timestamp() ),
"skill": skill,
}}}) """
db.user_info_list.updateOne({"_id":"52"},{"$push":{"pet_list":{
"pid": 2,
"image": "pet1.png",
"created_time": 1609727155,
"skill": 30,
}}})
""" 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)
return current_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 = 7200
else:
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)
return if current_pet_hp <= 0:
socketio.emit("pet_use_response", {"errno": status.CODE_NO_PET, "errmsg": errmsg.not_pet},
namespace="/mofang", room=room)
return
setting = Setting.query.filter(Setting.name == "pet_feed_number").first()
if setting is None:
pet_feed_number = 0.1
else:
pet_feed_number = float(setting.value)
prop_time = pet_hp_max * pet_feed_number
time = int( current_hp_time + prop_time )
redis.expire("pet_%s_%s_hp" % (user.id,pet_key+1),time)
print({"pet_key":pet_key,"hp_time":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) - 1
else:
prop_list.pop(key)
break mongo.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 = 1
else:
tree_number = tree_number_data.value if total_tree_data is None:
total_tree = 9
else:
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_number
else:
active_tree_price = int(ret.value) * user_tree_number if 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)
return user.credit = int(user.credit) - active_tree_price
db.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

宠物死亡则清除宠物信息

2.前端:宠物饱食度消耗完之后,发起宠物死亡的通知

<!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, // 状态时间
// },
// ],
// },
// 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.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>

客户端在饱食度消耗完以后, 发起宠物死亡的通知-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" id="app">
<img class="music" :class="music_play?'music2':''" @click="music_play=!music_play" src="../static/images/player.png">
<div class="orchard-bg">
<img src="../static/images/bg2.png">
<img class="board_bg2" src="../static/images/board_bg2.png">
</div>
<img class="back" @click="go_index" src="../static/images/user_back.png" alt="">
<div class="header">
<div class="info" @click="go_home">
<div class="avatar">
<img class="avatar_bf" src="../static/images/avatar_bf.png" alt="">
<img class="user_avatar" src="../static/images/avatar.png" alt="">
<img class="avatar_border" src="../static/images/avatar_border.png" alt="">
</div>
<p class="user_name">好听的昵称</p>
</div>
<div class="wallet">
<div class="balance" @click="user_recharge">
<p class="title"><img src="../static/images/money.png" alt="">钱包</p>
<p class="num">{{money}}</p>
</div>
<div class="balance">
<p class="title"><img src="../static/images/integral.png" alt="">果子</p>
<p class="num">99,999.00</p>
</div>
</div>
<div class="menu-list">
<div class="menu">
<img src="../static/images/menu1.png" alt="">
排行榜
</div>
<div class="menu">
<img src="../static/images/menu2.png" alt="">
签到有礼
</div>
<div class="menu" @click="go_orchard_shop">
<img src="../static/images/menu3.png" alt="">
道具商城
</div>
<div class="menu">
<img src="../static/images/menu4.png" alt="">
邮件中心
</div>
</div>
</div>
<div class="footer" >
<ul class="menu-list">
<li class="menu">新手</li>
<li class="menu" @click="go_my_package">背包</li>
<li class="menu-center" @click="go_orchard_shop">商店</li>
<li class="menu">消息</li>
<li class="menu">好友</li>
</ul>
</div>
</div>
<script>
apiready = function(){
init();
new Vue({
el:"#app",
data(){
return {
music_play:true,
namespace: '/mofang',
token:"",
money:"",
settings_info:{
orchard: {}, // 种植园公共参数
user:{}, // 用户私有相关参数
},
socket: null,
recharge_list: ['10','20','50','100','200','500','1000'],
timeout: 0,
prev:{name:"",url:"",params:{}},
current:{name:"orchard",url:"orchard.html",params:{}},
}
},
beforeCreate(){
this.game.goFrame("orchard","my_orchard.html", this.current,{
x: 0,
y: 180,
w: 'auto',
h: 410,
},null);
},
created(){
this.checkout();
this.money = this.game.fget("money");
},
methods:{
user_recharge(){
// 发起充值请求
api.actionSheet({
title: '余额充值',
cancelTitle: '取消',
buttons: this.recharge_list
}, (ret, err)=>{
if( ret ){
if(ret.buttonIndex <= this.recharge_list.length){
// 充值金额
money = this.recharge_list[ret.buttonIndex-1];
// 调用支付宝充值
this.create_recharge(money);
}
}else{ }
}); },
create_recharge(money){
// 获取历史信息记录
var token = this.game.get("access_token") || this.game.fget("access_token");
this.game.checkout(this, token, (new_access_token)=>{
this.axios.post("",{
"jsonrpc": "2.0",
"id": this.uuid(),
"method": "Recharge.create",
"params": {
"money": money,
}
},{
headers:{
Authorization: "jwt " + token,
}
}).then(response=>{
if(parseInt(response.data.result.errno)==1000){
// 前往支付宝
var aliPayPlus = api.require('aliPayPlus');
aliPayPlus.payOrder({
orderInfo: response.data.result.order_string,
sandbox: response.data.result.sandbox, // 将来APP上线需要修改成false
}, (ret, err)=>{
pay_result = {
9000:"支付成功",
8000:"正在处理中",
4000:"订单支付失败",
5000:"重复请求",
6001:"取消支付",
6002:"网络连接出错",
6004:"支付结果未知",
}
api.alert({
title: '支付结果',
msg: pay_result[ret.code],
buttons: ['确定']
});
// 通知服务端, 修改充值结果
this.return_recharge(response.data.result.order_number,token);
});
}else{
this.game.print(response.data);
}
}).catch(error=>{
// 网络等异常
this.game.print(error);
});
})
},
return_recharge(out_trade_number,token){
this.axios.post("",{
"jsonrpc": "2.0",
"id": this.uuid(),
"method": "Recharge.return",
"params": {
"out_trade_number": out_trade_number,
}
},{
headers:{
Authorization: "jwt " + token,
}
}).then(response=>{
if(parseInt(response.data.result.errno)==1000){
this.money = response.data.result.money.toFixed(2);
}
})
},
checkout(){
var token = this.game.get("access_token") || this.game.fget("access_token");
this.game.checkout(this,token,(new_access_token)=>{
this.connect();
this.login();
this.user_package();
this.buy_prop();
this.unlock_package_number();
this.show_pet();
this.use_prop();
this.active_tree();
});
},
connect(){
// socket连接
this.socket = io.connect(this.settings.socket_server + this.namespace, {transports: ['websocket']});
this.socket.on('connect', ()=>{
this.game.print("开始连接服务端");
var id = this.game.fget("id");
this.socket.emit("login",{"uid":id});
this.socket.emit("user_prop");
});
},
login(){
this.socket.on("login_response",(message)=>{
this.settings_info.orchard = message.orchard_settings;
this.settings_info.user=message.user_settings;
this.game.fsave({
"orchard_settings":message.orchard_settings,
"user_settings":message.user_settings,
});
this.game.save({
"tree_total":message.tree_total,
"user_tree_number":message.user_tree_number,
"user_tree_list":message.user_tree_list,
"tree_status":message.tree_status,
"pet_food_num":message.pet_food_num,
"fertilizer_num":message.fertilizer_num,
"waters":message.waters,
"shears":message.shears,
});
setTimeout(()=>{
// 通知种植园页面获取到了当前用户的种植信息
api.sendEvent({
name: 'user_tree_data',
extra: {}
});
},500);
});
},
user_package(){
// 用户背包道具列表
this.socket.on("user_prop_response",(message)=>{
this.game.fsave({
"user_package":message.data,
});
// 界面中的道具信息
this.game.save({
"pet_food_num":message.pet_food_num,
"fertilizer_num":message.fertilizer_num,
});
api.sendEvent({
name: 'update_prop_data',
extra: { }
}); })
},
go_index(){
this.game.goWin("root");
},
go_friends(){
this.game.goFrame("friends","friends.html",this.current);
this.game.goFrame("friend_list","friend_list.html",this.current,{
x: 0,
y: 190,
w: 'auto',
h: 'auto',
},null,true);
},
go_home(){
this.game.goWin("user","user.html", this.current);
},
go_orchard_shop(){
// 种植园商店
this.game.goFrame("orchard_shop","shop.html", this.current,null,{
type:"push",
subType:"from_top",
duration:300
});
},
go_my_package(){
// 我的背包
this.game.goFrame("package","package.html", this.current,null,{
type:"push",
subType:"from_top",
duration:300
});
},
buy_prop(){
api.addEventListener({
name: 'buy_prop'
}, (ret, err)=>{
if( ret ){
// 用户购买道具
this.socket.emit("user_buy_prop",ret.value);
}
});
this.socket.on("user_buy_prop_response",(message)=>{
alert(message.errmsg); }); },
use_prop(){
// 使用道具
var pid = 0;
api.addEventListener({
name: 'use_prop'
}, (ret, err)=>{
if( ret ){
// 用户使用道具
pid = ret.value.pid;
var pet_key = this.game.get("pet_key");
if(pet_key<1){
pet_key = 0;
}
this.socket.emit("use_prop",{pid:ret.value.pid,pet_key:pet_key});
}
}); this.socket.on("prop_use_response",(message)=>{
if(parseInt(message.errno) === 1000){
api.sendEvent({
name: 'prop_use_success',
extra: {
pid: pid
}
});
}else{
api.alert({
title: '提示',
msg: message.errmsg,
}); }
}); this.socket.on("pet_feed_response",(message)=>{
if(parseInt(message.errno) === 1000){
api.sendEvent({
name: 'pet_feed_success',
extra: {
pet_key: message.pet_key,
hp_time: message.hp_time
}
});
}else{
api.alert({
title: '提示',
msg: message.errmsg,
}); }
}) },
unlock_package_number(){
api.addEventListener({
name: 'unlock_package_number'
}, (ret, err)=>{
if( ret ){
// 用户购买道具
this.socket.emit("unlock_package");
}
}); this.socket.on("unlock_package_response",(message)=>{
if(parseInt(message.errno) === 1000){
api.sendEvent({
name: 'unlock_package_success',
extra: {
}
});
}else{
api.alert({
title: '提示',
msg: message.errmsg,
}); } })
},
show_pet(){
// 显示宠物
this.socket.emit("pet_show");
this.socket.on("pet_show_response",(message)=>{
if(parseInt(message.errno) === 1000){
// 把宠物信息保存到本地
this.game.save({"pet_list":message.pet_list})
this.game.save({"pet_number":message.pet_number})
setTimeout(()=>{
api.sendEvent({
name: 'pet_show_success',
extra: {}
});
},500);
}else{
api.alert({
title: '提示',
msg: message.errmsg,
});
} }); api.addEventListener({
name: 'pet_die'
}, (ret, err)=>{
if( ret ){
this.socket.emit("pet_show");
}
}); },
active_tree(){
// 激活树桩
api.addEventListener({
name: 'active_tree'
}, (ret, err)=>{
if( ret ){
this.socket.emit("active_tree");
}
}); this.socket.on("active_tree_response",(message)=>{
if(parseInt(message.errno) === 1000){
// 更新数据到本地
api.sendEvent({
name: 'active_tree_success',
extra: {}
});
}else{
api.alert({
title: '提示',
msg: message.errmsg,
});
} })
}
}
});
}
</script>
</body>
</html>

客户端在饱食度消耗完以后, 发起宠物死亡的通知-orchard.html

day119:MoFang:宠物的状态改动&宠物粮道具的使用&宠物死亡处理的更多相关文章

  1. day121:MoFang:植物的状态改动(幼苗→成长期)&植物的浇水功能

    目录 1.当果树种植以后在celery的异步任务中调整浇水的状态 2.客户端通过倒计时判断时间,显示浇水道具 3.客户端判断当前种植物状态控制图标的显示和隐藏 4.当用户单击浇水图标, 则根据当前果树 ...

  2. 【转载】在Linux下,一个文件也有三种时间,分别是:访问时间、修改时间、状态改动时间

    在windows下,一个文件有:创建时间.修改时间.访问时间.而在Linux下,一个文件也有三种时间,分别是:访问时间.修改时间.状态改动时间. 两者有此不同,在Linux下没有创建时间的概念,也就是 ...

  3. Linux下文件的三种时间标记:访问时间、修改时间、状态改动时间 (转载)

    在windows下,一个文件有:创建时间.修改时间.访问时间. 而在Linux下,一个文件也有三种时间,分别是:访问时间.修改时间.状态改动时间. 两者有此不同,在Linux下没有创建时间的概念,也就 ...

  4. Bzoj1208 [HNOI2004]宠物收养所

    Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 7457  Solved: 2960 Description 最近,阿Q开了一间宠物收养所.收养所提供两 ...

  5. BZOJ 1208: [HNOI2004]宠物收养所

    1208: [HNOI2004]宠物收养所 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 7514  Solved: 2982[Submit][Sta ...

  6. 宠物收养所(bzoj1208)

    Description 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物.每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的一个特 ...

  7. 【BZOJ1208】[HNOI2004]宠物收养所 Splay

    还是模板题,两颗splay,找点删即可. #include <iostream> #include <cstdio> #include <cstdlib> #def ...

  8. 【BZOJ-1208】宠物收养所 Splay

    1208: [HNOI2004]宠物收养所 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 6638  Solved: 2601[Submit][Sta ...

  9. BZOJ1208 宠物收养所

    Description 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物.每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的一个特 ...

随机推荐

  1. Project Lombok——带给你简洁、清晰的代码

    相信但凡有一点Java编程经历的人,都见过或者写过下面这种代码.这是一个简单的POJO,只有4个fields,加上构造器.equals.hash.toString以及各种getter setter,前 ...

  2. Scrum 冲刺 第五篇

    Scrum 冲刺 第五篇 每日会议照片 昨天已完成工作 队员 昨日完成任务 黄梓浩 初步完成app项目架构搭建 黄清山 完成部分个人界面模块数据库的接口 邓富荣 完成后台首页模块数据库的接口 钟俊豪 ...

  3. CSS基础-字体

    字体变化设置 改变字体颜色 color 改变字体大小 font-size 改变字体粗细 font-weight 改变字体样式 font-family 改变字间距 letter-spacing 改变字体 ...

  4. 一个小时学会用 Go 编写命令行工具

    前言 最近因为项目需要写了一段时间的 Go ,相对于 Java 来说语法简单同时又有着一些 Python 之类的语法糖,让人大呼"真香". 但现阶段相对来说还是 Python 写的 ...

  5. 【科技】位运算(bitset)优化最长公共子序列算法

    最长公共子序列(LCS)问题 你有两个字符串 \(A,B\),字符集为 \(\Sigma\),求 \(A, B\) 的最长公共子序列. 简单动态规划 首先有一个广为人知的 dp:\(f_{i,j}\) ...

  6. BIOS、UEFI、Boot Loader都是些什么

    BIOS.UEFI.Boot Loader都是些什么 目录 BIOS.UEFI.Boot Loader都是些什么 什么是BIOS 基本的输入输出是什么 自检程序"检"了什么 系统自 ...

  7. 使用Swiper快速实现3D效果轮播

    最近经常接到轮播图3D效果的需求, 特在此记录一下以备之后使用. 具体实现效果如下: 在这里介绍两种使用方式, 一种原生的html+php后端渲染, 一种是使用vue. 原生实现 引入 首先我们介绍原 ...

  8. 事件修饰符 阻止冒泡 .stop 阻止默认事件 .prevent

    stop修饰符 阻止冒泡行为 可以在函数中利用$event传参通过stopPropagation()阻止冒泡 通过直接在元素中的指令中添加 .stop prevent修饰符 阻止默认行为 可以在函数中 ...

  9. react第十二单元(react路由-使用react-router-dom-认识相关的组件以及组件属性)

    第十二单元(react路由-使用react-router-dom-认识相关的组件以及组件属性) #课程目标 理解路由的原理及应运 理解react-router-dom以及内置的一些组件 合理应用内置组 ...

  10. WinForm引用ActiveX组件,对Com组件的学习

    1.WinForm引用Adobe PDF Reader 工作中写WinForm程序经常会引用第三方的组件,包括引用Com组件,做了一个桌面程序需要展示PDF,看了些其它的开源组件对PDF的兼容性都不是 ...