day118:MoFang:根据激活/未激活的状态分别显示树桩&种植植物&解锁树桩&化肥/修剪/浇水/宠物粮小图标数字的显示
登录
种植栏的功能实现
1. 客户端需要的植物相关参数: 总树桩数量, 当前用户激活树桩数量, 当前种植的树桩数量, 树桩列表状态
2. 客户端根据激活状态和未激活状态分别显示树桩
3. 服务端在用户进入种植园时提供上面的数据
4. 用户如果第一次进入种植园需要初始化参数
5. 数据库中必须预设树桩的相关参数
6. 用户可以使用道具对树桩进行响应的操作
7. 用户可以在背包里面进行果树的种植
1.根据激活状态和未激活状态分别显示树桩
1.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">
- <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="i in active_tree">
- <img src="../static/images/tree1.png" alt="">
- </div>
- <!-- 未激活树桩列表 -->
- <div 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>1</span>
- <p>化肥</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop2.png" alt="">
- <span>0</span>
- <p>修剪</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop3.png" alt="">
- <span>1</span>
- <p>浇水</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop4.png" alt="">
- <span>1</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+'%'}" 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_list:[],
- user_tree_data:{
- "total_tree":9, // 总树桩数量
- "user_tree_number": 5, // 当前用户激活树桩数量
- "user_tree_list":[ // 当前种植的树桩列表状态
- ],
- },
- 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();
- },
- methods:{
- 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"));
- }
- });
- }
- }
- });
- }
- </script>
- </body>
- </html>
my_orchard.html-先确定前端需要哪些数据
2.my_orchard.html-确定当前种植的树桩状态列表的数据结构
- user_tree_data:{
- "total_tree":9, // 总树桩数量
- "user_tree_number": 5, // 当前用户激活树桩数量
- "user_tree_list":[ // 当前种植的树桩列表状态
- { // 树桩状态
- "time":1609808084, // 种植时间
- "status":4, // 状态
- "has_time": 300, // 状态时间
- },
- ],
- },
- pet_number:[],
- tree_status:{
- "tree0": "../static/images/tree0.png", // 树桩
- "tree1": "../static/images/tree1.png", // 空桩
- "tree2": "../static/images/tree2.png", // 幼苗
- "tree3": "../static/images/tree3.png", // 成长
- "tree4": "../static/images/tree4.png", // 成熟
- },
客户端显示种植植物相关的参数,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">
- <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 v-if="tree.status==2" src="../static/images/tree2.png" alt="">
- <img v-if="tree.status==3" src="../static/images/tree3.png" alt="">
- <img v-if="tree.status==4" src="../static/images/tree4.png" alt="">
- </div>
- <!-- 已激活但是未种植的树桩列表 -->
- <div class="tree" v-for="i in active_tree">
- <img src="../static/images/tree1.png" alt="">
- </div>
- <!-- 未激活树桩列表 -->
- <div 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>1</span>
- <p>化肥</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop2.png" alt="">
- <span>0</span>
- <p>修剪</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop3.png" alt="">
- <span>1</span>
- <p>浇水</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop4.png" alt="">
- <span>1</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+'%'}" 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_list:[],
- user_tree_data:{
- "total_tree":9, // 总树桩数量
- "user_tree_number": 5, // 当前用户激活树桩数量
- "user_tree_list":[ // 当前种植的树桩列表状态
- { // 树桩状态
- "time":1609808084, // 种植时间
- "status":4, // 状态
- "has_time": 300, // 状态时间
- },
- ],
- },
- pet_number:[],
- tree_status:{
- "tree0": "../static/images/tree0.png", // 树桩
- "tree1": "../static/images/tree1.png", // 空桩
- "tree2": "../static/images/tree2.png", // 幼苗
- "tree3": "../static/images/tree3.png", // 成长
- "tree4": "../static/images/tree4.png", // 成熟
- },
- 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();
- },
- methods:{
- 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"));
- }
- });
- }
- }
- });
- }
- </script>
- </body>
- </html>
my_orchard.html-确定当前种植的树桩状态列表的数据结构
3.服务端提供种植植物的相关数据
1.在setting表中添加种植植物的参数数据
添加参数数据,SQL代码:
- INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (19, 'tree_status_0', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '树桩状态-未解锁', 'tree0.png');
- INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (20, 'tree_status_1', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '树桩状态-未种植', 'tree1.png');
- INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (21, 'tree_status_2', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '树桩状态-幼苗', 'tree2.png');
- INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (22, 'tree_status_3', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '树桩状态-成长', 'tree3.png');
- INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (23, 'tree_status_4', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '树桩状态-成熟', 'tree4.png');
2.后端返回当前用户种植的植物信息
服务端返回当前用户种植的植物信息,socket.py, 代码:


- from application import socketio
- from flask import request
- from application.apps.users.models import User
- from flask_socketio import join_room, leave_room
- from application import mongo
- from .models import Goods,Setting,db
- from status import APIStatus as status
- from message import ErrorMessage as errmsg
- # 断开socket通信
- @socketio.on("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", [])
- socketio.emit("login_response", {
- "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,
- }, namespace="/mofang", room=room)
- @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
- })
- 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
- }] * padding_time
- if padding_last != 0:
- arr.append({
- "num": padding_last,
- "image": prop_data.image,
- "pid": prop_data.id
- })
- data = data + arr
- mongo.db.user_info_list.update_one({"sid":request.sid},{"$set":{"use_package_number":len(data)}})
- room = request.sid
- socketio.emit("user_prop_response", {
- "errno": status.CODE_OK,
- "errmsg": errmsg.ok,
- "data":data,
- }, 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中提取当前宠物的饱食度和有效期
- for key,pet in enumerate(pet_list):
- pet["hp"] = math.ceil( redis.ttl("pet_%s_%s_hp" % (user.id,key+1)) / 86400 * 100 )
- pet["has_time"] = redis.ttl("pet_%s_%s_expire" % (user.id,key+1))
- 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):
- """使用宠物"""
- # 1. 判断当前的宠物数量
- 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_use_response", {"errno":status.CODE_NO_USER,"errmsg":errmsg.user_not_exists}, namespace="/mofang", room=room)
- return
- # 获取宠物列表
- 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. 初始化当前宠物信息
- pet = Goods.query.get(pid)
- if pet is None:
- socketio.emit("pet_use_response", {"errno":status.CODE_NO_SUCH_PET,"errmsg":errmsg.not_such_pet}, namespace="/mofang", room=room)
- return
- # 获取有效期和防御值
- 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()
- pipe.setex("pet_%s_%s_hp" % (user.id, len(pet_list)+1), 24*60*60, "_")
- 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": pet.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,
- }}})
- """
- # 扣除背包中的道具数量
- 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()
- pet_show()
- socketio.emit("pet_use_response", {"errno": status.CODE_OK, "errmsg": errmsg.ok},
- namespace="/mofang", room=room)
用户登录种植园成功后,后端返回当前用户种植的植物信息
4.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();
- });
- },
- 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,
- });
- 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,
- })
- })
- },
- 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;
- this.socket.emit("use_prop",ret.value.pid);
- }
- });
- this.socket.on("pet_use_response",(message)=>{
- if(parseInt(message.errno) === 1000){
- api.sendEvent({
- name: 'pet_use_success',
- extra: {
- pid: pid
- }
- });
- }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,
- });
- }
- })
- }
- }
- });
- }
- </script>
- </body>
- </html>
orchard.html-登陆种植园成功后将植物相关信息获取并保存在前端,并发送事件
5.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">
- <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 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>1</span>
- <p>化肥</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop2.png" alt="">
- <span>0</span>
- <p>修剪</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop3.png" alt="">
- <span>1</span>
- <p>浇水</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop4.png" alt="">
- <span>1</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+'%'}" 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_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();
- },
- methods:{
- 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"));
- }
- });
- },
- 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");
- }
- });
- }
- }
- });
- }
- </script>
- </body>
- </html>
my_orchard.html-监听事件,并获取前端已经保存好的植物数据
2.用户使用植物道具进行果树种植
1.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 = ret.value.pid;
- for(var i in this.user_package){
- if(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-用户点击背包中的道具,前端发起使用道具的请求
2.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();
- });
- },
- 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,
- });
- 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,
- })
- })
- },
- 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;
- this.socket.emit("use_prop",ret.value.pid);
- }
- });
- 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,
- });
- }
- });
- },
- 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,
- });
- }
- })
- }
- }
- });
- }
- </script>
- </body>
- </html>
orchard.html-监听使用道具事件
3.my_orchard.html-增加tree_img方法,前端根据后端传过来的status显示植物的不同形态


- <!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 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>1</span>
- <p>化肥</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop2.png" alt="">
- <span>0</span>
- <p>修剪</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop3.png" alt="">
- <span>1</span>
- <p>浇水</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop4.png" alt="">
- <span>1</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+'%'}" 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_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();
- },
- methods:{
- 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"));
- }
- });
- },
- 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");
- }
- });
- }
- }
- });
- }
- </script>
- </body>
- </html>
my_orchard.html-增加tree_img方法,前端根据后端传过来的status显示植物的不同形态
4.服务端调整使用道具的后端接口和进入种植园的登录接口


- 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" % 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
- 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,
- "tree_status":tree_status,
- }
- socketio.emit("login_response", message, namespace="/mofang", room=room)
- @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
- socketio.emit("user_prop_response", {
- "errno": status.CODE_OK,
- "errmsg": errmsg.ok,
- "data":data,
- }, 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中提取当前宠物的饱食度和有效期
- for key,pet in enumerate(pet_list):
- pet["hp"] = math.ceil( redis.ttl("pet_%s_%s_hp" % (user.id,key+1)) / 86400 * 100 )
- pet["has_time"] = redis.ttl("pet_%s_%s_expire" % (user.id,key+1))
- 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表示幼苗状态
- "water_time": 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()
- pipe.setex("pet_%s_%s_hp" % (user.id, len(pet_list)+1), 24*60*60, "_")
- 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)
服务端调整使用道具后端接口&种植园登录接口
3.解锁树桩
1.在Setting表中添加解锁树桩的费用
- INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (28, 'active_tree_price', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '激活树桩的递增果子费用', '1000');
2.后端提供解锁树桩的接口
- @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.前端发起请求解锁树桩
1.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">
- <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>1</span>
- <p>化肥</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop2.png" alt="">
- <span>0</span>
- <p>修剪</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop3.png" alt="">
- <span>1</span>
- <p>浇水</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop4.png" alt="">
- <span>1</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+'%'}" 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_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();
- },
- methods:{
- 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"));
- }
- });
- },
- 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");
- }
- });
- },
- 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.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,
- });
- 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,
- })
- })
- },
- 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;
- this.socket.emit("use_prop",ret.value.pid);
- }
- });
- 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,
- });
- }
- });
- },
- 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
4.化肥/修剪/浇水/宠物粮小图标显示
1.显示化肥和宠物粮的道具数量
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" % 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_orchard_prop_list(user_dict)
- 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,
- }
- socketio.emit("login_response", message, namespace="/mofang", room=room)
- def get_orchard_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_orchard_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中提取当前宠物的饱食度和有效期
- for key,pet in enumerate(pet_list):
- pet["hp"] = math.ceil( redis.ttl("pet_%s_%s_hp" % (user.id,key+1)) / 86400 * 100 )
- pet["has_time"] = redis.ttl("pet_%s_%s_expire" % (user.id,key+1))
- 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表示幼苗状态
- "water_time": 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()
- pipe.setex("pet_%s_%s_hp" % (user.id, len(pet_list)+1), 24*60*60, "_")
- 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
服务端提供化肥和宠物粮的道具数量
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" 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,
- });
- 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;
- this.socket.emit("use_prop",ret.value.pid);
- }
- });
- 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,
- });
- }
- });
- },
- 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


- <!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>0</span>
- <p>修剪</p>
- </div>
- <div class="prop">
- <img src="../static/images/prop3.png" alt="">
- <span>1</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+'%'}" 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, // 化肥数量
- 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:{
- 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"));
- }
- });
- },
- 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");
- }
- });
- },
- 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.后端:根据植物计算剪刀和浇水的数量


- 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中提取当前宠物的饱食度和有效期
- for key,pet in enumerate(pet_list):
- pet["hp"] = math.ceil( redis.ttl("pet_%s_%s_hp" % (user.id,key+1)) / 86400 * 100 )
- pet["has_time"] = redis.ttl("pet_%s_%s_expire" % (user.id,key+1))
- 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()
- pipe.setex("pet_%s_%s_hp" % (user.id, len(pet_list)+1), 24*60*60, "_")
- 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
服务端根据植物的状态计算剪刀和浇水的数量
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" 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;
- this.socket.emit("use_prop",ret.value.pid);
- }
- });
- 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,
- });
- }
- });
- },
- 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


- <!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+'%'}" 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:{
- 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"));
- }
- });
- },
- 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
day118:MoFang:根据激活/未激活的状态分别显示树桩&种植植物&解锁树桩&化肥/修剪/浇水/宠物粮小图标数字的显示的更多相关文章
- CentOS 6.x启动时网卡eth0未激活
简述 安装CentOS 6.x操作系统后,开机时发现没有网络,最后发现系统启动时未激活网卡 - 因为只有在激活状态的网卡才能去连接网络,进行网络通讯. 简述 激活网卡eth0 激活网卡eth0 执行& ...
- ecshop后台"云提醒未激活 点击激活" 补丁删除方法
ecshop后台"云提醒未激活 点击激活" 补丁删除方法 ECSHOP教程/ ecshop教程网(www.ecshop119.com) 2015-01-15 ecshop后台提 ...
- firebug调试js时提示调试器未激活处理办法
firebug是web开发中最常用的分析调试软件,不过我今天使用在调试百度在线编辑器UEditor时一直提示调试器未激活. 从使用经验来看不应该啊,我都下了断点了为什么会提示调试器未激活呢!多次载入网 ...
- 打开phpmyadmin显示高级功能尚未完全设置部分功能未激活
问题:老师,打开phpmyadmin显示高级功能尚未完全设置部分功能未激活,应该如何解决? 这是前一阵子学生问过我的一个问题,今天我就在博客里解答你的疑问吧. 总共三步可以搞定 1.导入相关文件到数据 ...
- Ribbon Workbench 与此流程相关的流程操作未激活
问题描述:使用Ribbon Workbench 打开解决方案时报 :与此流程相关的流程操作未激活 解决方法 :ribbon 导航--系统定置--流程中心--流程--CustomiseRibbon -- ...
- 优步uber司机申请了为什么一直没有通过审核,帐号也显示未激活
优步uber现在是越来越火,申请注册成为优步uber司机的人数也日剧增多,申请了的车主都知道,申请后要等待审核,审核通过才可以激活帐号,快的运气好的,三五天不到一个星期就激活了,慢点的得大半个月,还有 ...
- phpMyAdmin 高级功能尚未完全设置,部分功能未激活(转载)
phpMyAdmin 高级功能尚未完全设置,部分功能未激活.请点击这里查看原因. 第一步: 使用Mysql管理员帐号通过phpmyadmin登陆,然后点击“导入”,然后点击“浏览”按钮,找到phpmy ...
- day119:MoFang:宠物的状态改动&宠物粮道具的使用&宠物死亡处理
目录 1.宠物的状态改动 2.宠物粮道具的使用 3.宠物死亡处理 1.宠物的状态改动 1.在setting表中为每个宠物配置生命周期时间 因为宠物有多个,每个宠物会有不同的初始生命的饥饿时间,所以我们 ...
- 产品激活 比如Windows激活 , office激活 等激活的原理是什么? KMS等激活工具安全吗?
什么是密钥管理服务 (KMS)? 密钥管理服务 (KMS) 允许在本地网络上激活产品.这样,单台计算机不必连接至 Microsoft 便可激活产品.需要将一台计算机配置为 KMS 主机.管理员必须为 ...
- SpringBoot实现网站注册,邮件激活码激活功能
项目源码:https://gitee.com/smfx1314/springbootemail 上一篇文章已经讲到如何springboot如何实现邮件的发送,趁热打铁,这篇文章实现如下功能. 很多网站 ...
随机推荐
- Alibaba Cloud Linux 3.2104 64位安装nginx-1.16.1
1 下载nginx 从nginx官网 http://nginx.org/ 下载新的稳定版本nginx 并上传到linux服务器 2 安装nginx 所需要的扩展 yum -y install ...
- 简单了解promise
promise是什么: JavaScript中存在很多异步操作, Promise将异步操作队列化,按照期望的顺序执行,返回 符合预期的结果.可以通过链式调用多个 Promise达到我们的目的. Pro ...
- 20193314白晨阳 实验一《Python程序设计》实验报告
实验一 20193314 2020-2021-2 <Python程序设计>实验1报告 课程:<Python程序设计> 班级: 201933 姓名: 白晨阳 学号:2019331 ...
- MySQL分库分表原理
转自https://www.jianshu.com/p/7aec260ca1a2 前言 在互联网还未崛起的时代,我们的传统应用都有这样一个特点:访问量.数据量都比较小,单库单表都完全可以支撑整个业务. ...
- MP逻辑删除
在实体类中加上@TableLogic注解 在配置类中加入逻辑删除插件
- antd动态tree 自定义样式
import React, { useEffect, useState } from 'react';import { Tree } from 'antd';import './index.less' ...
- Spring整合Redis学习笔记
1 Spring-Data-Redis 1.1 Spring-Data-Redis简介 Spring-Data-Redis(简称SDR)对Redis的Key-Value数据存储操作提供了更高层次的 ...
- springboot项目导出excel实现
参见:https://blog.csdn.net/duli_0105/article/details/102809936
- WSL/Ubutun安装GCC
1.更新升级软件包 $ sudo apt-get update && sudo apt-get upgrade -y 2.清理关联软件包 $ sudo apt autoremove - ...
- Winform 应用DotnetBar
Winform 使用NotNetBar namespace WindowsFormExample { public partial class FrmMain : Office2007Form { p ...