day117:MoFang:宠物栏的功能实现&宠物道具的使用

目录

1.宠物栏的功能实现

2.宠物道具的使用

1.宠物栏的功能实现

1. 宠物的显示

2. 宠物的使用

3. 宠物的饱食度

4. 宠物的开锁

1.服务端提供显示宠物的api接口

orchard/socket.py代码:

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

    # 1.获取宠物列表
    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天
      },
    ]
    """
    # 2.从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
    )

2.数据库里设置宠物的相关参数

根据服务端前面添加的宠物的id主键,在配置参数中设置宠物的相关参数,

INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (11, 'pet_expire_2', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '1号宠物的有效期', '30');
INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (12, 'pet_skill_2', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '1号宠物的防御概率', '50');
INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (13, 'pet_expire_3', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '2号宠物的有效期', '30');
INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (14, 'pet_skill_3', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '2号宠物的防御概率', '20');
INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (15, 'pet_expire_4', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '3号宠物的有效期', '30');
INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (16, 'pet_skill_4', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '3号宠物的防御概率', '70');
INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (17, 'pet_expire_5', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '4号宠物的有效期', '30');
INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (18, 'pet_skill_5', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '4号宠物的防御概率', '30');

3.客户端中展示宠物栏和宠物列表以及饱食度

1.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();
          });
        },
        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
                        });
                    });
                },
                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);
                    })
                },
                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

2.my_orchard.html

<!DOCTYPE html>
<html>
<head>
    <title>用户中心</title>
    <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
    <meta charset="utf-8">
    <link rel="stylesheet" href="../static/css/main.css">
    <script src="../static/js/vue.js"></script>
    <script src="../static/js/axios.js"></script>
    <script src="../static/js/main.js"></script>
    <script src="../static/js/uuid.js"></script>
    <script src="../static/js/settings.js"></script>
    <script src="../static/js/socket.io.js"></script>
</head>
<body>
    <div class="app orchard orchard-frame" id="app">
    <div class="background">
      <img class="grassland2" src="../static/images/grassland2.png" alt="">
      <img class="mushroom1" src="../static/images/mushroom1.png" alt="">
      <img class="stake1" src="../static/images/stake1.png" alt="">
      <img class="stake2" src="../static/images/stake2.png" alt="">
    </div>
    <div class="pet-box">
      <div class="pet">
                <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">
          <img src="../static/images/tree4.png" alt="">
        </div>
        <div class="tree">
          <img src="../static/images/tree3.png" alt="">
        </div>
        <div class="tree">
          <img src="../static/images/tree4.png" alt="">
        </div>
      </div>
      <div class="tree-box">
        <div class="tree">
          <img src="../static/images/tree3.png" alt="">
        </div>
        <div class="tree">
          <img src="../static/images/tree2.png" alt="">
        </div>
        <div class="tree">
          <img src="../static/images/tree2.png" alt="">
        </div>
      </div>
      <div class="tree-box">
        <div class="tree">
          <img src="../static/images/tree1.png" alt="">
        </div>
        <div class="tree">
          <img src="../static/images/tree0.png" alt="">
        </div>
        <div class="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:[],
                    pet_number:[],
          timeout: 0,
                    prev:{name:"",url:"",params:{}},
                    current:{name:"orchard",url:"orchard.html",params:{}},
                }
            },
      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"));
                                this.game.print(this.pet_list);
                            }
                    });
                }
            }
        });
    }
    </script>
</body>
</html>
客户端展示宠物栏和宠物列表以及饱食度:my_orchard.html

2.宠物道具的使用

0.显示宠物道具&宠物道具的使用流程图

1.调整model类,增加道具类型选项

调整业务模型,为道具增加道具类型一项,orchard/models.py代码;

from application.utils.models import BaseModel,db
class Goods(BaseModel):
    """商品基本信息"""
    __tablename__ = "mf_goods"
    # 增加道具类型选项
    PROP_TYPE = (
        (0, "果树"),
        (1, "宠物"),
        (2, "植物生长道具"),
        (3, "宠物粮"),
    )
    remark = db.Column(db.String(255), comment="商品描述")
    price = db.Column(db.Numeric(7,2), comment="商品价格[余额]")
    prop_type = db.Column(db.Integer, default=0, comment="道具类型")
    credit = db.Column(db.Integer,     comment="商品价格[果子]")
    image = db.Column(db.String(255),  comment="商品图片")

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: ['确定', '取消']
                    }, function(ret, err){
                        if( ret.buttonIndex == 1 ){
                                api.sendEvent({
                                     name: 'use_prop',
                                     extra: {
                                             pid: pid,
                                     }
                             });

                        }
                    });


                    api.addEventListener({
                        name: 'pet_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.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">
          <img src="../static/images/tree4.png" alt="">
        </div>
        <div class="tree">
          <img src="../static/images/tree3.png" alt="">
        </div>
        <div class="tree">
          <img src="../static/images/tree4.png" alt="">
        </div>
      </div>
      <div class="tree-box">
        <div class="tree">
          <img src="../static/images/tree3.png" alt="">
        </div>
        <div class="tree">
          <img src="../static/images/tree2.png" alt="">
        </div>
        <div class="tree">
          <img src="../static/images/tree2.png" alt="">
        </div>
      </div>
      <div class="tree-box">
        <div class="tree">
          <img src="../static/images/tree1.png" alt="">
        </div>
        <div class="tree">
          <img src="../static/images/tree0.png" alt="">
        </div>
        <div class="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:[],
                    pet_number:[],
          timeout: 0,
                    prev:{name:"",url:"",params:{}},
                    current:{name:"orchard",url:"orchard.html",params:{}},
                }
            },
      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.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
                        });
                    });
                },
                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

3.后端实现使用道具接口

服务端实现使用道具接口, socket.py 代码:

from datetime import datetime
@socketio.on("use_prop", namespace="/mofang")
def use_prop(pid):
    """使用宠物"""
    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:a
        socketio.emit("pet_use_response", {"errno":status.CODE_NO_USER,"errmsg":errmsg.user_not_exists}, namespace="/mofang", room=room)
        return

    # 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. 初始化当前宠物信息
    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

    # 4.获取有效期和防御值
    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

    # 5.在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()

    # 6.基本信息保存到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,
          }}})
    """

    # 7.扣除背包中的道具数量
    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)

 

 

posted @ 2021-01-11 09:37  iR-Poke  阅读(153)  评论(0编辑  收藏  举报