种植园
植物的状态改动
一、当果树种植以后在celery的异步任务中调整浇水的状态
在进行果树种植的时候, 在服务端设置当前果树到等待浇水的redis变量中.通过celery不断进行周期任务的处理, 改动果树的浇水状态
socket.py
...
from datetime import datetime
@socketio.on('use_prop', namespace='/mofang')
def use_prop(data):
"""使用道具"""
pid = data.get('pid')
pet_key = data.get('pet_key', 0)
room = request.sid
# 获取mongo中的用户信息
user_info = mongo.db.user_info_list.find_one({'sid': request.sid})
# 获取mysql中的用户信息
user = User.query.get(user_info.get('_id'))
if user is None:
socketio.emit('pet_use_response', {'errno': status.CODE_NO_USER, 'errmsg': errmsg.user_not_exists}, namespace='/mofang', room=room)
return
# 获取道具
prop_data = Goods.query.get(pid)
if prop_data is None:
socketio.emit('pet_use_response', {'errno': status.CODE_NO_SUCH_PROP, 'errmsg': errmsg.not_such_prop}, namespace='/mofang', room=room)
return
if int(prop_data.prop_type) == 0:
"""使用植物道具"""
# 1.判断当前的植物数量是否有空余
tree_list = user_info.get('user_tree_list', [])
# 当前用户最多可种植的数量
setting = Setting.query.filter(Setting.name == 'user_active_tree').first()
if setting is None:
user_tree_number = 3
else:
user_tree_number = int(setting.value)
user_tree_number = user_info.get('user_tree_number', user_tree_number)
if len(tree_list) >= user_tree_number:
socketio.emit('prop_use_response', {'errno': status.CODE_NO_EMPTY, 'errmsg': errmsg.prop_not_empty}, namespace='/mofang', room=room)
return
# 使用道具
mongo.db.user_info_list.update_one({'sid': room}, {'$push': {'user_tree_list':
{ # 植物状态
"time": int(datetime.now().timestamp()), # 种植时间
"status": 2, # 植物状态,2表示幼苗状态
'allow_water': False, # 是否允许浇水
"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()
# 设置定时任务进行浇水
redis.append('tree_list_water', '%s_%s,' % (user.id, len(tree_list)))
user_login({'uid': user.id})
if int(prop_data.prop_type) == 1:
"""使用宠物道具"""
# 1. 判断当前的宠物数量
# 获取宠物列表
pet_list = user_info.get('pet_list', [])
if len(pet_list) > 1 and pet_list[0]['is_die'] == 0 and pet_list[1]['is_die'] == 0:
socketio.emit('pet_use_response', {'errno': status.CODE_NO_EMPTY, 'errmsg': errmsg.prop_not_empty}, namespace='/mofang', room=room)
return
# 2. 是否有空余的宠物栏位
pet_number = user_info.get('pet_number', 1)
length = len(pet_list)
if length == 2:
live_leng = 0
if pet_list[0]['is_die'] == 0:
live_leng += 1
if pet_list[1]['is_die'] == 0:
live_leng += 1
elif length == 1 and pet_list[0]['is_die'] == 0:
live_leng = 1
else:
live_leng = 0
if live_leng >= pet_number:
socketio.emit('pet_use_response', {'errno': status.CODE_NO_EMPTY, 'errmsg': errmsg.prop_not_empty}, namespace='/mofang', room=room)
return
# 3. 初始化当前宠物信息
# 获取有效期和防御值
exp_data = Setting.query.filter(Setting.name == 'pet_expire_%s' % pid).first()
ski_data = Setting.query.filter(Setting.name == 'pet_skill_%s' % pid).first()
if exp_data is None:
# 默认7天有效期
expire = 7
else:
expire = exp_data.value
if ski_data is None:
skill = 10
else:
skill = ski_data.value
# 在redis中设置当前宠物的饱食度
pipe = redis.pipeline()
pipe.multi()
setting = Setting.query.filter(Setting.name == ('pet_hp_max_%s' % pid)).first()
if setting is None:
pet_hp_max = 7200
else:
pet_hp_max = int(setting.value)
# 保存到mongo
# 判断是否有挂了的宠物在列表中
pet_data = {
'pid': pid,
'image': prop_data.image,
'created_time': int(datetime.now().timestamp()),
'skill': skill,
'is_die': 0,
}
# 如果第一个宠物是挂了的
if len(pet_list) == 0:
mongo.db.user_info_list.update_one({'sid': room}, {'$set': {'pet_list': [pet_data]}})
pipe.setex('pet_%s_%s_hp' % (user.id, 1), pet_hp_max, '_')
pipe.setex('pet_%s_%s_expire' % (user.id, 1), int(expire) * 24 * 60 * 60, '_')
elif len(pet_list) == 1 and int(pet_list[0]['is_die']) == 1:
"""只有一个挂了的宠物"""
mongo.db.user_info_list.update_one({'sid': room}, {'$set': {'pet_list': [pet_data]}})
pipe.setex('pet_%s_%s_hp' % (user.id, 1), pet_hp_max, '_')
pipe.setex('pet_%s_%s_expire' % (user.id, 1), int(expire) * 24 * 60 * 60, '_')
elif len(pet_list) == 1 and int(pet_list[0]['is_die']) == 0:
"""只有一个活着的宠物"""
mongo.db.user_info_list.update_one({'sid': room}, {'$push': {'pet_list': pet_data}})
pipe.setex('pet_%s_%s_hp' % (user.id, 2), pet_hp_max, '_')
pipe.setex('pet_%s_%s_expire' % (user.id, 2), int(expire) * 24 * 60 * 60, '_')
elif len(pet_list) == 2 and int(pet_list[0]['is_die']) == 1:
"""有2个宠物,但是第1个挂了"""
pet_list[0] = pet_data
mongo.db.user_info_list.update_one({'sid': room}, {'$set': {'pet_list': pet_list}})
pipe.setex('pet_%s_%s_hp' % (user.id, 1), pet_hp_max, '_')
pipe.setex('pet_%s_%s_expire' % (user.id, 1), int(expire) * 24 * 60 * 60, '_')
elif len(pet_list) == 2 and int(pet_list[1]['is_die']) == 1:
"""有2个宠物,但是第2个挂了"""
pet_list[1] = pet_data
pipe.setex('pet_%s_%s_hp' % (user.id, 2), pet_hp_max, '_')
pipe.setex('pet_%s_%s_expire' % (user.id, 2), int(expire) * 24 * 60 * 60, '_')
mongo.db.user_info_list.update_one({'sid': room}, {'$set': {'pet_list': pet_list}})
pipe.execute()
pet_show()
if int(prop_data.prop_type) == 3:
"""宠物喂食"""
pet_list = user_info.get('pet_list')
if len(pet_list) < 1:
socketio.emit('pet_use_response', {'errno': status.CODE_NO_PET, 'errmsg': errmsg.not_pet}, namespace='/mofang', room=room)
return
current_hp_time = redis.ttl('pet_%s_%s_hp' % (user.id, pet_key + 1))
setting = Setting.query.filter(Setting.name == ('pet_hp_max_%s' % (pet_list[pet_key]['pid']))).first()
if setting is None:
pet_hp_max = 7200
else:
pet_hp_max = int(setting.value)
current_pet_hp = math.ceil(current_hp_time / pet_hp_max * 100)
if current_pet_hp > 90:
"""饱食度高于90%无法喂养"""
socketio.emit('pet_use_response', {'errno': status.CODE_NO_FEED, 'errmsg': errmsg.no_feed}, namespace='/mofang', room=room)
return
if current_pet_hp <= 0:
socketio.emit('pet_use_response', {'errno': status.CODE_NO_PET, 'errmsg': errmsg.not_pet}, namespace='/mofang', room=room)
return
setting = Setting.query.filter(Setting.name == 'pet_feed_number').first()
if setting is None:
pet_feed_number = 0.1
else:
pet_feed_number = float(setting.value)
prop_time = pet_hp_max * pet_feed_number
time = int(current_hp_time + prop_time)
redis.expire('pet_%s_%s_hp' % (user.id, pet_key + 1), time)
socketio.emit('pet_feed_response', {'errno': status.CODE_OK, 'errmsg': errmsg.ok, 'pet_key': pet_key, 'hp_time': time}, namespace='/mofang', room=room)
# 扣除背包中的道具数量
prop_list = user_info.get('prop_list', {})
for key, value in prop_list.items():
if key == ('prop_%s' % pid):
if int(value) > 1:
prop_list[key] = int(value) - 1
else:
prop_list.pop(key)
break
mongo.db.user_info_list.update_one({'sid': room}, {'$set': {'prop_list': prop_list}})
user_prop()
socketio.emit('prop_use_response', {'errno': status.CODE_OK, 'errmsg': errmsg.ok}, namespace='/mofang', room=room)
@socketio.on('active_tree', namespace='/mofang')
def active_tree():
"""激活树桩"""
room = request.sid
# 获取mongo中的用户信息
user_info = mongo.db.user_info_list.find_one({'sid': request.sid})
# 获取mysql中的用户信息
user = User.query.get(user_info.get('_id'))
if user is None:
socketio.emit('active_tree_response', {'errno': status.CODE_NO_USER, 'errmsg': errmsg.user_not_exists}, namespace='/mofang', room=room)
return
# 判断树桩是否达到上限
tree_number_data = Setting.query.filter(Setting.name == 'user_active_tree').first()
total_tree_data = Setting.query.filter(Setting.name == 'user_total_tree').first()
if tree_number_data is None:
tree_number = 1
else:
tree_number = tree_number_data.value
if total_tree_data is None:
total_tree = 9
else:
total_tree = int(total_tree_data.value)
user_tree_number = int(user_info.get('user_tree_number', tree_number))
if user_tree_number >= total_tree:
socketio.emit('active_tree_response', {'errno': status.CODE_NO_EMPTY, 'errmsg': errmsg.prop_not_empty}, namespace='/mofang', room=room)
return
# 扣除激活的果子数量
ret = Setting.query.filter(Setting.name == 'active_tree_price').first()
if ret is None:
active_tree_price = 100 * user_tree_number
else:
active_tree_price = int(ret.value) * user_tree_number
if active_tree_price > int(user.credit):
socketio.emit('active_tree_response', {'errno': status.CODE_NO_CREDIT, 'errmsg': errmsg.credit_no_enough}, namespace='/mofang', room=room)
return
user.credit = int(user.credit) - active_tree_price
db.session.commit()
mongo.db.user_info_list.update_one({'sid': room}, {'$set': {'user_tree_number': user_tree_number+1}})
socketio.emit('active_tree_response', {'errno': status.CODE_OK, 'errmsg': errmsg.ok}, namespace='/mofang', room=room)
return
mycelery/tree/tasks.py
代码:
from application import redis
from mycelery.main import app, flask_app
from application import mongo
@app.task(name='tree_write', bind=True)
def tree_write(self):
"""允许浇水"""
try:
tree_list_water = redis.get('tree_list_water')
if tree_list_water is None:
return
tree_list_water = tree_list_water.decode()
tree_list = tree_list_water.split(',')[:-1]
for tree in tree_list:
timer = redis.ttl('user_tree_water_%s' % tree)
if timer == -2:
print('%s可以浇水了' % tree)
treeinfo = tree.split('_')
query = {'_id': treeinfo[0]}
user_info = mongo.db.user_info_list.find_one(query)
user_tree_list = user_info.get('user_tree_list', [])
user_tree_list[int(treeinfo[1])]['allow_water'] = True
mongo.db.user_info_list.update_one(query, {'$set': {'user_tree_list': user_tree_list}})
tree_list_water_str = ''.join(tree_list_water.split(tree+','))
redis.set('tree_list_water', tree_list_water_str)
except Exception as exc:
print(exc)
mycelery/main.py
,代码:
from celery import Celery
from application import init_app
# 初始化celery对象
app = Celery("flask")
# 初始化flask
flask_app = init_app("application.settings.dev").app
# 加载配置
app.config_from_object("mycelery.config")
# 自动注册任务
app.autodiscover_tasks(["mycelery.sms", 'mycelery.tree'])
# 运行celery
# 主程序终端下启动: celery -A mycelery.main worker -l info
# 调度器终端下启动: celery -A mycelery.main beat
mycelery/config.py
,代码:
# 任务队列地址
broker_url = 'redis://127.0.0.1:6379/15'
# 结果队列地址
result_backend = "redis://127.0.0.1:6379/14"
# 周期任务
from mycelery.main import app
app.conf.beat_schedule = {
'tree_write_task': {
'task': 'tree_write',
'schedule': 5,
},
}
接下来在终端下运行celery
celery -A mycelery.main worker -l info
celery -A mycelery.main beat
二、客户端通过倒计时判断时间,显示浇水道具
客户端显示浇水图标, main.css
,代码:
...
.tree-popped{
top: 4rem;
right: 3rem;
height: 3.4rem;
width: 3.4rem;
border-radius: 3.4rem;
}
.popped:after {
content: '';
position: absolute;
top: 18%;
left: 18%;
background-color: rgba(191, 255, 255, 0.6);
width: 1.2rem;
height: 1.5rem;
border-radius: 50%;
transform: rotate(45deg) scale(0.8);
}
.popped img{
width: 3rem!important;
height: 3rem!important;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
.tree-popped img{
width: 2.2rem!important;
height: 2.2rem!important;
}
.orchard-frame .pet-box .turned_off .turned_image{
width: 5.14rem;
height: 6.83rem;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
.orchard-frame .pet-box .turned_off p{
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
border: 1px solid #fff;
border-radius: 1rem;
width: 8rem;
height: 3rem;
line-height: 3rem;
font-size: 1.5rem;
word-wrap: break-word;
padding: 1rem;
color: #000;
text-align: center;
background: rgba(255,255,255,.6);
}
.orchard-frame .pet-box .pet-item{
width: 10rem;
height: 10rem;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
.orchard-frame .tree-list{
position: absolute;
top: 9rem;
width: 100%;
}
.orchard-frame .tree-box{
margin-left: 3rem;
margin-right: 3rem;
}
.orchard-frame .tree-box .tree{
width: 9rem;
height: 4rem;
margin-bottom: 2rem;
float: left;
position: relative;
}
...
my_orchard.html
<!DOCTYPE html>
<html>
<head>
<title>用户中心</title>
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta charset="utf-8">
<link rel="stylesheet" href="../static/css/main.css">
<script src="../static/js/vue.js"></script>
<script src="../static/js/axios.js"></script>
<script src="../static/js/main.js"></script>
<script src="../static/js/uuid.js"></script>
<script src="../static/js/settings.js"></script>
<script src="../static/js/socket.io.js"></script>
</head>
<body>
<div class="app orchard orchard-frame" id="app">
<div class="background">
<img class="grassland2" src="../static/images/grassland2.png" alt="">
<img class="mushroom1" src="../static/images/mushroom1.png" alt="">
<img class="stake1" src="../static/images/stake1.png" alt="">
<img class="stake2" src="../static/images/stake2.png" alt="">
</div>
<div class="pet-box">
<div class="pet">
<span @click='feed(0)' class="popped" v-if='pet_list[0] && pet_list[0].hp<90 && pet_list[0].hp>0 && pet_food_num > 0'>
<img class='pet-prop' src="../static/images/prop4.png" alt="">
</span>
<img v-if='pet_list.length > 0 && pet_list[0].hp>0' class="pet-item" :src="settings.static_url+pet_list[0].image" alt="">
</div>
<div class="pet" v-if='pet_number > 1'>
<span @click='feed(1)' class="popped" v-if='pet_list[1] && pet_list[1].hp<90 && pet_list[1].hp>0 && pet_food_num > 0'>
<img class='pet-prop' src="../static/images/prop4.png" alt="">
</span>
<img v-if='pet_list.length > 1 && pet_list[1].hp>0' class='pet-item' :src="settings.static_url+pet_list[1].image" alt="">
</div>
<div class="pet turned_off" v-if='pet_number == 1'>
<img class="turned_image" src="../static/images/turned_off.png" alt="">
<p>请购买宠物</p>
</div>
</div>
<div class="tree-list">
<div class="tree-box">
<div class="tree" v-for='tree in user_tree_data.user_tree_list'>
<span class="popped tree-popped">
<img src="../static/images/prop3.png" alt="">
</span>
<img :src="tree_img(tree.status)" alt="">
</div>
<!-- 已激活但是未种植的树桩列表 -->
<div class="tree" v-for='i in active_tree'>
<img src="../static/images/tree1.png" alt="">
</div>
<!-- 未激活树桩列表 -->
<div @click='unlock_tree' class="tree" v-for='i in lock_tree'>
<img src="../static/images/tree0.png" alt="">
</div>
</div>
</div>
<div class="prop-list">
<div class="prop">
<img src="../static/images/prop1.png" alt="">
<span>{{fertilizer_num}}</span>
<p>化肥</p>
</div>
<div class="prop">
<img src="../static/images/prop2.png" alt="">
<span>{{shears}}</span>
<p>修剪</p>
</div>
<div class="prop">
<img src="../static/images/prop3.png" alt="">
<span>{{waters}}</span>
<p>浇水</p>
</div>
<div class="prop">
<img src="../static/images/prop4.png" alt="">
<span>{{pet_food_num}}</span>
<p>宠物粮</p>
</div>
</div>
<div class="pet-hp-list">
<div class="pet-hp" v-for='pet, key in pet_list'>
<p>宠物{{key+1}} 饱食度</p>
<div class="hp">
<div :style="{width: pet.hp+'%', backgroundColor: bg(pet.hp)}" class="process">{{pet.hp}}%</div>
</div>
</div>
</div>
</div>
<script>
apiready = function(){
init();
new Vue({
el:"#app",
data(){
return {
namespace: '/mofang',
token:"",
socket: null,
pet_food_num: 0, // 宠物粮数量
fertilizer_num: 0, // 化肥数量
waters: 0, // 浇水次数
shears: 0, // 剪刀次数
pet_list: [],
user_tree_data:{
'total_tree': 9, // 总树桩数量
'user_tree_number': 0, // 当前用户激活树桩数量
'user_tree_list': [ // 当前种植的树桩列表状态
],
},
tree_status:{
},
// user_tree_data:{
// 'total_tree': 9, // 总树桩数量
// 'user_tree_number': 5, // 当前用户激活树桩数量
// 'user_tree_list': [ // 当前种植的树桩列表状态
// { // 树桩状态
// 'time': 1609808084, // 种植时间
// 'status': 4, // 植物状态
// 'has_time': 300, // 状态时间
// },
// ],
// },
// pet_number: [],
// tree_status:{
// 'tree_status_0': 'tree0.png', // 树桩
// 'tree_status_1': 'tree1.png', // 空桩
// 'tree_status_2': 'tree2.png', // 幼苗
// 'tree_status_3': 'tree3.png', // 成长
// 'tree_status_4': 'tree4.png', // 成熟
// },
pet_number: [],
timeout: 0,
prev:{name:"",url:"",params:{}},
current:{name:"orchard",url:"orchard.html",params:{}},
}
},
computed:{
// 已激活但是未使用的树桩
active_tree(){
return parseInt(this.user_tree_data.user_tree_number - this.user_tree_data.user_tree_list.length);
},
// 未激活的剩余树桩
lock_tree(){
return parseInt(this.user_tree_data.total_tree - this.user_tree_data.user_tree_number);
},
},
created(){
this.show_pet_list();
this.show_tree_list();
this.get_prop_list();
},
methods:{
feed(pet_key){
// 我的背包
this.game.save({'pet_key': pet_key}); // 记录本次喂养的宠物下标
this.game.goFrame('package', 'package.html', this.current, null, {
type: 'push',
subType: 'from_top',
duration: 300
});
api.addEventListener({
name: 'pet_feed_success'
}, (ret, err)=>{
if( ret ){
this.pet_list[ret.value.pet_key].hp = Math.ceil(ret.value.hp_time / this.pet_list[ret.value.pet_key].pet_hp_max * 100)
this.pet_list[ret.value.pet_key].hp_time = ret.value.hp_time;
this.game.save({'pet_list': this.pet_list})
}
});
},
bg(hp){
if(hp>90){
return '#f00';
}else if(hp>60){
return '#a00';
}else if(hp>30){
return '#600';
}else {
return '#300';
}
},
get_prop_list(){
// 更新道具列表信息
api.addEventListener({
name: 'update_prop_data'
}, (ret, err)=>{
if( ret ){
this.pet_food_num = this.game.get('pet_food_num');
this.fertilizer_num = this.game.get('fertilizer_num');
}
});
},
tree_img(status){
return '../static/images/'+this.tree_status[status];
},
show_pet_list(){
api.addEventListener({
name: 'pet_show_success'
}, (ret, err)=>{
if( ret ){
// 显示宠物相关
this.pet_list = this.game.get('pet_list');
this.pet_number = parseInt(this.game.get('pet_number'));
var timer = null;
setInterval(()=>{
// 保证定时器中每次读取的都是最新的宠物信息
this.pet_list = this.game.get('pet_list');
for(let i in this.pet_list){
if(this.pet_list[i].hp_time<1 && this.pet_list[i].is_die==0){
// 宠物挂了
api.sendEvent({
name: 'pet_die',
extra: {
}
});
}
if(this.pet_list[i].hp_time>0){
this.pet_list[i].hp_time -= 0.5;
this.pet_list[i].hp = Math.ceil(this.pet_list[i].hp_time / this.pet_list[i].pet_hp_max * 100)
}
}
this.game.save({'pet_list': this.pet_list});
}, 500);
}
});
},
show_tree_list(){
api.addEventListener({
name: 'user_tree_data'
}, (ret, err)=>{
if( ret ){
// 用户种植植物信息
this.user_tree_data.tree_total = parseInt(this.game.get('tree_total'));
this.user_tree_data.user_tree_number = parseInt(this.game.get('user_tree_number'));
this.user_tree_data.user_tree_list = this.game.get('user_tree_list');
this.tree_status = this.game.get('tree_status');
this.pet_food_num = this.game.get('pet_food_num');
this.fertilizer_num = this.game.get('fertilizer_num');
this.waters = this.game.get('waters');
this.shears = this.game.get('shears');
}
});
},
unlock_tree(){
// 激活树桩通知
api.confirm({
title: '提示',
msg: '是否激活树桩?',
buttons: ['确定', '取消']
}, (ret, err)=>{
if( ret.buttonIndex == 1 ){
api.sendEvent({
name: 'active_tree',
extra: {
}
});
}
});
// 激活成功!
api.addEventListener({
name: 'active_tree_success'
}, (ret, err)=>{
if( ret ){
// 新增树桩的数量
this.user_tree_data.user_tree_number+=1;
this.game.save({'user_tree_number': this.user_tree_data.user_tree_number});
}
});
}
}
});
}
</script>
</body>
</html>
客户端判断当前种植物状态控制图标的显示和隐藏
my_orhcard.html
<!DOCTYPE html>
<html>
<head>
<title>用户中心</title>
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta charset="utf-8">
<link rel="stylesheet" href="../static/css/main.css">
<script src="../static/js/vue.js"></script>
<script src="../static/js/axios.js"></script>
<script src="../static/js/main.js"></script>
<script src="../static/js/uuid.js"></script>
<script src="../static/js/settings.js"></script>
<script src="../static/js/socket.io.js"></script>
</head>
<body>
<div class="app orchard orchard-frame" id="app">
<div class="background">
<img class="grassland2" src="../static/images/grassland2.png" alt="">
<img class="mushroom1" src="../static/images/mushroom1.png" alt="">
<img class="stake1" src="../static/images/stake1.png" alt="">
<img class="stake2" src="../static/images/stake2.png" alt="">
</div>
<div class="pet-box">
<div class="pet">
<span @click='feed(0)' class="popped" v-if='pet_list[0] && pet_list[0].hp<90 && pet_list[0].hp>0 && pet_food_num > 0'>
<img class='pet-prop' src="../static/images/prop4.png" alt="">
</span>
<img v-if='pet_list.length > 0 && pet_list[0].hp>0' class="pet-item" :src="settings.static_url+pet_list[0].image" alt="">
</div>
<div class="pet" v-if='pet_number > 1'>
<span @click='feed(1)' class="popped" v-if='pet_list[1] && pet_list[1].hp<90 && pet_list[1].hp>0 && pet_food_num > 0'>
<img class='pet-prop' src="../static/images/prop4.png" alt="">
</span>
<img v-if='pet_list.length > 1 && pet_list[1].hp>0' class='pet-item' :src="settings.static_url+pet_list[1].image" alt="">
</div>
<div class="pet turned_off" v-if='pet_number == 1'>
<img class="turned_image" src="../static/images/turned_off.png" alt="">
<p>请购买宠物</p>
</div>
</div>
<div class="tree-list">
<div class="tree-box">
<div class="tree" v-for='tree in user_tree_data.user_tree_list'>
<span class="popped tree-popped" v-if='tree.allow_water && tree.waters<1'>
<img src="../static/images/prop3.png" alt="">
</span>
<img :src="tree_img(tree.status)" alt="">
</div>
<!-- 已激活但是未种植的树桩列表 -->
<div class="tree" v-for='i in active_tree'>
<img src="../static/images/tree1.png" alt="">
</div>
<!-- 未激活树桩列表 -->
<div @click='unlock_tree' class="tree" v-for='i in lock_tree'>
<img src="../static/images/tree0.png" alt="">
</div>
</div>
</div>
<div class="prop-list">
<div class="prop">
<img src="../static/images/prop1.png" alt="">
<span>{{fertilizer_num}}</span>
<p>化肥</p>
</div>
<div class="prop">
<img src="../static/images/prop2.png" alt="">
<span>{{shears}}</span>
<p>修剪</p>
</div>
<div class="prop">
<img src="../static/images/prop3.png" alt="">
<span>{{waters}}</span>
<p>浇水</p>
</div>
<div class="prop">
<img src="../static/images/prop4.png" alt="">
<span>{{pet_food_num}}</span>
<p>宠物粮</p>
</div>
</div>
<div class="pet-hp-list">
<div class="pet-hp" v-for='pet, key in pet_list'>
<p>宠物{{key+1}} 饱食度</p>
<div class="hp">
<div :style="{width: pet.hp+'%', backgroundColor: bg(pet.hp)}" class="process">{{pet.hp}}%</div>
</div>
</div>
</div>
</div>
<script>
apiready = function(){
init();
new Vue({
el:"#app",
data(){
return {
namespace: '/mofang',
token:"",
socket: null,
pet_food_num: 0, // 宠物粮数量
fertilizer_num: 0, // 化肥数量
waters: 0, // 浇水次数
shears: 0, // 剪刀次数
pet_list: [],
user_tree_data:{
'total_tree': 9, // 总树桩数量
'user_tree_number': 0, // 当前用户激活树桩数量
'user_tree_list': [ // 当前种植的树桩列表状态
],
},
tree_status:{
},
// user_tree_data:{
// 'total_tree': 9, // 总树桩数量
// 'user_tree_number': 5, // 当前用户激活树桩数量
// 'user_tree_list': [ // 当前种植的树桩列表状态
// { // 树桩状态
// 'time': 1609808084, // 种植时间
// 'status': 4, // 植物状态
// 'has_time': 300, // 状态时间
// },
// ],
// },
// pet_number: [],
// tree_status:{
// 'tree_status_0': 'tree0.png', // 树桩
// 'tree_status_1': 'tree1.png', // 空桩
// 'tree_status_2': 'tree2.png', // 幼苗
// 'tree_status_3': 'tree3.png', // 成长
// 'tree_status_4': 'tree4.png', // 成熟
// },
pet_number: [],
timeout: 0,
prev:{name:"",url:"",params:{}},
current:{name:"orchard",url:"orchard.html",params:{}},
}
},
computed:{
// 已激活但是未使用的树桩
active_tree(){
return parseInt(this.user_tree_data.user_tree_number - this.user_tree_data.user_tree_list.length);
},
// 未激活的剩余树桩
lock_tree(){
return parseInt(this.user_tree_data.total_tree - this.user_tree_data.user_tree_number);
},
},
created(){
this.show_pet_list();
this.show_tree_list();
this.get_prop_list();
},
methods:{
feed(pet_key){
// 我的背包
this.game.save({'pet_key': pet_key}); // 记录本次喂养的宠物下标
this.game.goFrame('package', 'package.html', this.current, null, {
type: 'push',
subType: 'from_top',
duration: 300
});
api.addEventListener({
name: 'pet_feed_success'
}, (ret, err)=>{
if( ret ){
this.pet_list[ret.value.pet_key].hp = Math.ceil(ret.value.hp_time / this.pet_list[ret.value.pet_key].pet_hp_max * 100)
this.pet_list[ret.value.pet_key].hp_time = ret.value.hp_time;
this.game.save({'pet_list': this.pet_list})
}
});
},
bg(hp){
if(hp>90){
return '#f00';
}else if(hp>60){
return '#a00';
}else if(hp>30){
return '#600';
}else {
return '#300';
}
},
get_prop_list(){
// 更新道具列表信息
api.addEventListener({
name: 'update_prop_data'
}, (ret, err)=>{
if( ret ){
this.pet_food_num = this.game.get('pet_food_num');
this.fertilizer_num = this.game.get('fertilizer_num');
}
});
},
tree_img(status){
return '../static/images/'+this.tree_status[status];
},
show_pet_list(){
var pet_timer = null;
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'));
clearInterval(pet_timer);
pet_timer = setInterval(()=>{
// 保证定时器中每次读取的都是最新的宠物信息
this.pet_list = this.game.get('pet_list');
for(let i in this.pet_list){
if(this.pet_list[i].hp_time<1 && this.pet_list[i].is_die==0){
// 宠物挂了
api.sendEvent({
name: 'pet_die',
extra: {
}
});
}
if(this.pet_list[i].hp_time>0){
this.pet_list[i].hp_time -= 0.5;
this.pet_list[i].hp = Math.ceil(this.pet_list[i].hp_time / this.pet_list[i].pet_hp_max * 100)
}
}
this.game.save({'pet_list': this.pet_list});
}, 500);
}
});
},
show_tree_list(){
var tree_timer = null; // 定时器标记符
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');
clearInterval(tree_timer);
tree_timer = setInterval(()=>{
var user_tree_list = this.game.get('user_tree_list');
for(let tree of user_tree_list){
if(tree.water_time>-2){
tree.water_time-=1;
}
if(tree.water_time<=-2 && tree.allow_water==false){
// 通知服务端允许用户浇水
tree.allow_water = true;
this.waters+=1;
}
}
this.user_tree_data.user_tree_list = user_tree_list;
this.game.save({'user_tree_list': user_tree_list});
},1000);
}
});
},
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>
当用户单击浇水图标, 则根据当前果树的种植时间和状态确定是否进入成长期
socket.py
,代码:
...
@socketio.on('water_tree', namespace='/mofang')
def water_tree(key):
"""浇水"""
room = request.sid
# 获取mongo中的用户信息
query = {'sid': request.sid}
user_info = mongo.db.user_info_list.find_one(query)
# 获取mysql中的用户信息
user = User.query.get(user_info.get('_id'))
if user is None:
socketio.emit('water_tree_response', {'errno': status.CODE_NO_USER, 'errmsg': errmsg.user_not_exists}, namespace='/mofang', room=room)
return
print('给%s的植物%s' % (user.id, key))
user_tree_list = user_info.get('user_tree_list', [])
try:
tree_data = user_tree_list[key]
except Exception as e:
socketio.emit('water_tree_response', {'errno': status.CODE_NO_SUCH_TREE, 'errmsg': errmsg.tree_not_exists}, namespace='/mofang', room=room)
return
if tree_data.get('allow_water', False) and int(tree_data.get('waters', 1)) == 0:
"""允许浇水"""
tree_data['waters'] = 1
# 如果种植物的种植时间达到成长期,则修改种植物的成长状态
growup = redis.ttl('user_tree_growup_%s_%s' % (user.id, key))
if growup == -2:
tree_data['status'] = 3
mongo.db.user_info_list.update_one(query, {'$set': {'user_tree_list': user_tree_list}})
socketio.emit('water_tree_response', {'errno': status.CODE_OK, 'errmsg': errmsg.ok}, namespace='/mofang', room=room)
user_login({'uid': user.id})
status.py
...
CODE_NO_SUCH_TREE = 1021 # 没有对应的种植物
message.py
...
tree_not_exists = "没有对应的种植物"
mycelery/tree/tasks.py
,代码:
from application import redis
from mycelery.main import app, flask_app
from application import mongo
@app.task(name='tree_write', bind=True)
def tree_write(self):
"""允许浇水"""
try:
tree_list_water = redis.get('tree_list_water')
if tree_list_water is None:
return
tree_list_water = tree_list_water.decode()
tree_list = tree_list_water.split(',')[:-1]
print(tree_list)
for tree in tree_list:
treeinfo = tree.split('_')
query = {'_id': treeinfo[0]}
user_info = mongo.db.user_info_list.find_one(query)
user_tree_list = user_info.get('user_tree_list', [])
# 是否允许浇水
timer = redis.ttl('user_tree_water_%s' % tree)
if timer == -2 and user_tree_list[int(treeinfo[1])]['allow_water'] == False:
user_tree_list[int(treeinfo[1])]['allow_water'] = True
# 是否进入成长期
timer = redis.ttl('user_tree_growup_%s' % tree)
if timer == -2 and user_tree_list[int(treeinfo[1])]['status'] == 2:
if user_tree_list[int(treeinfo[1])]['waters'] > 0:
user_tree_list[int(treeinfo[1])]['status'] = 3
# tree_list_water_str = ''.join(tree_list_water.split(tree + ','))
# redis.set('tree_list_water', tree_list_water_str)
mongo.db.user_info_list.update_one(query, {'$set': {'user_tree_list': user_tree_list}})
except Exception as exc:
# 重新尝试执行失败任务
print(exc)
客户端发起浇水通知,my_orchard.html
,代码;
<!DOCTYPE html>
<html>
<head>
<title>用户中心</title>
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta charset="utf-8">
<link rel="stylesheet" href="../static/css/main.css">
<script src="../static/js/vue.js"></script>
<script src="../static/js/axios.js"></script>
<script src="../static/js/main.js"></script>
<script src="../static/js/uuid.js"></script>
<script src="../static/js/settings.js"></script>
<script src="../static/js/socket.io.js"></script>
</head>
<body>
<div class="app orchard orchard-frame" id="app">
<div class="background">
<img class="grassland2" src="../static/images/grassland2.png" alt="">
<img class="mushroom1" src="../static/images/mushroom1.png" alt="">
<img class="stake1" src="../static/images/stake1.png" alt="">
<img class="stake2" src="../static/images/stake2.png" alt="">
</div>
<div class="pet-box">
<div class="pet">
<span @click='feed(0)' class="popped" v-if='pet_list[0] && pet_list[0].hp<90 && pet_list[0].hp>0 && pet_food_num > 0'>
<img class='pet-prop' src="../static/images/prop4.png" alt="">
</span>
<img v-if='pet_list.length > 0 && pet_list[0].hp>0' class="pet-item" :src="settings.static_url+pet_list[0].image" alt="">
</div>
<div class="pet" v-if='pet_number > 1'>
<span @click='feed(1)' class="popped" v-if='pet_list[1] && pet_list[1].hp<90 && pet_list[1].hp>0 && pet_food_num > 0'>
<img class='pet-prop' src="../static/images/prop4.png" alt="">
</span>
<img v-if='pet_list.length > 1 && pet_list[1].hp>0' class='pet-item' :src="settings.static_url+pet_list[1].image" alt="">
</div>
<div class="pet turned_off" v-if='pet_number == 1'>
<img class="turned_image" src="../static/images/turned_off.png" alt="">
<p>请购买宠物</p>
</div>
</div>
<div class="tree-list">
<div class="tree-box">
<div class="tree" v-for='tree, key in user_tree_data.user_tree_list'>
<span @click='water_tree(key)' class="popped tree-popped" v-if='tree.allow_water && tree.waters<1'>
<img src="../static/images/prop3.png" alt="">
</span>
<img :src="tree_img(tree.status)" alt="">
</div>
<!-- 已激活但是未种植的树桩列表 -->
<div class="tree" v-for='i in active_tree'>
<img src="../static/images/tree1.png" alt="">
</div>
<!-- 未激活树桩列表 -->
<div @click='unlock_tree' class="tree" v-for='i in lock_tree'>
<img src="../static/images/tree0.png" alt="">
</div>
</div>
</div>
<div class="prop-list">
<div class="prop">
<img src="../static/images/prop1.png" alt="">
<span>{{fertilizer_num}}</span>
<p>化肥</p>
</div>
<div class="prop">
<img src="../static/images/prop2.png" alt="">
<span>{{shears}}</span>
<p>修剪</p>
</div>
<div class="prop">
<img src="../static/images/prop3.png" alt="">
<span>{{waters}}</span>
<p>浇水</p>
</div>
<div class="prop">
<img src="../static/images/prop4.png" alt="">
<span>{{pet_food_num}}</span>
<p>宠物粮</p>
</div>
</div>
<div class="pet-hp-list">
<div class="pet-hp" v-for='pet, key in pet_list'>
<p>宠物{{key+1}} 饱食度</p>
<div class="hp">
<div :style="{width: pet.hp+'%', backgroundColor: bg(pet.hp)}" class="process">{{pet.hp}}%</div>
</div>
</div>
</div>
</div>
<script>
apiready = function(){
init();
new Vue({
el:"#app",
data(){
return {
namespace: '/mofang',
token:"",
socket: null,
pet_food_num: 0, // 宠物粮数量
fertilizer_num: 0, // 化肥数量
waters: 0, // 浇水次数
shears: 0, // 剪刀次数
pet_list: [],
user_tree_data:{
'total_tree': 9, // 总树桩数量
'user_tree_number': 0, // 当前用户激活树桩数量
'user_tree_list': [ // 当前种植的树桩列表状态
],
},
tree_status:{
},
// user_tree_data:{
// 'total_tree': 9, // 总树桩数量
// 'user_tree_number': 5, // 当前用户激活树桩数量
// 'user_tree_list': [ // 当前种植的树桩列表状态
// { // 树桩状态
// 'time': 1609808084, // 种植时间
// 'status': 4, // 植物状态
// 'has_time': 300, // 状态时间
// },
// ],
// },
// pet_number: [],
// tree_status:{
// 'tree_status_0': 'tree0.png', // 树桩
// 'tree_status_1': 'tree1.png', // 空桩
// 'tree_status_2': 'tree2.png', // 幼苗
// 'tree_status_3': 'tree3.png', // 成长
// 'tree_status_4': 'tree4.png', // 成熟
// },
pet_number: [],
timeout: 0,
prev:{name:"",url:"",params:{}},
current:{name:"orchard",url:"orchard.html",params:{}},
}
},
computed:{
// 已激活但是未使用的树桩
active_tree(){
return parseInt(this.user_tree_data.user_tree_number - this.user_tree_data.user_tree_list.length);
},
// 未激活的剩余树桩
lock_tree(){
return parseInt(this.user_tree_data.total_tree - this.user_tree_data.user_tree_number);
},
},
created(){
this.show_pet_list();
this.show_tree_list();
this.get_prop_list();
},
methods:{
water_tree(tree_key){
// 给种植物浇水
api.sendEvent({
name: 'water_tree',
extra: {
key: tree_key,
}
});
api.addEventListener({
name: 'water_tree_success'
}, (ret, err)=>{
if( ret ){
this.user_tree_data.user_tree_list[ret.value.key]['waters'] = 1;
this.waters-=1;
this.game.save({'user_tree_list': this.user_tree_data.user_tree_list});
}
});
},
feed(pet_key){
// 我的背包
this.game.save({'pet_key': pet_key}); // 记录本次喂养的宠物下标
this.game.goFrame('package', 'package.html', this.current, null, {
type: 'push',
subType: 'from_top',
duration: 300
});
api.addEventListener({
name: 'pet_feed_success'
}, (ret, err)=>{
if( ret ){
this.pet_list[ret.value.pet_key].hp = Math.ceil(ret.value.hp_time / this.pet_list[ret.value.pet_key].pet_hp_max * 100)
this.pet_list[ret.value.pet_key].hp_time = ret.value.hp_time;
this.game.save({'pet_list': this.pet_list})
}
});
},
bg(hp){
if(hp>90){
return '#f00';
}else if(hp>60){
return '#a00';
}else if(hp>30){
return '#600';
}else {
return '#300';
}
},
get_prop_list(){
// 更新道具列表信息
api.addEventListener({
name: 'update_prop_data'
}, (ret, err)=>{
if( ret ){
this.pet_food_num = this.game.get('pet_food_num');
this.fertilizer_num = this.game.get('fertilizer_num');
}
});
},
tree_img(status){
return '../static/images/'+this.tree_status[status];
},
show_pet_list(){
var pet_timer = null;
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'));
clearInterval(pet_timer);
pet_timer = setInterval(()=>{
// 保证定时器中每次读取的都是最新的宠物信息
this.pet_list = this.game.get('pet_list');
for(let i in this.pet_list){
if(this.pet_list[i].hp_time<1 && this.pet_list[i].is_die==0){
// 宠物挂了
api.sendEvent({
name: 'pet_die',
extra: {
}
});
}
if(this.pet_list[i].hp_time>0){
this.pet_list[i].hp_time -= 0.5;
this.pet_list[i].hp = Math.ceil(this.pet_list[i].hp_time / this.pet_list[i].pet_hp_max * 100)
}
}
this.game.save({'pet_list': this.pet_list});
}, 500);
}
});
},
show_tree_list(){
var tree_timer = null; // 定时器标记符
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');
clearInterval(tree_timer);
tree_timer = setInterval(()=>{
var user_tree_list = this.game.get('user_tree_list');
for(let tree of user_tree_list){
if(tree.water_time>-2){
tree.water_time-=1;
}
if(tree.water_time<=-2 && tree.allow_water==false){
// 通知服务端允许用户浇水
tree.allow_water = true;
this.waters+=1;
}
if(tree.growup_time>=-2){
tree.growup_time-=1;
}
if(tree.growup_time<=-2 && tree.waters>0 && tree.status=='tree_status_2'){
// 通知服务端植物成长了
tree.status='tree_status_3';
}
}
this.user_tree_data.user_tree_list = user_tree_list;
this.game.print(this.user_tree_data.user_tree_list)
this.game.save({'user_tree_list': user_tree_list});
},1000);
}
});
},
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>
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" @click='go_friends'>好友</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=>{
// this.game.print(response.data);
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();
this.water_tree();
});
},
connect(){
// socket连接
this.socket = io.connect(this.settings.socket_server + this.namespace, {transports: ['websocket']});
this.socket.on('connect', ()=>{
this.game.print("开始连接服务端");
var id = this.game.fget('id');
this.socket.emit('login', {'uid': id});
this.socket.emit('user_prop');
});
},
login(){
this.socket.on('login_response', (message)=>{
this.settings_info.orchard = message.orchard_settings;
this.settings_info.user = message.user_settings;
this.game.fsave({
'orchard_settings': message.orchard_settings,
'user_settings': message.user_settings,
});
this.game.save({
'tree_total': message.tree_total,
'user_tree_number': message.user_tree_number,
'user_tree_list': message.user_tree_list,
'tree_status': message.tree_status,
'pet_food_num': message.pet_food_num,
'fertilizer_num': message.fertilizer_num,
'waters': message.waters,
'shears': message.shears,
});
setTimeout(()=>{
// 通知种植园页面获取到了当前用户的种植信息
api.sendEvent({
name: 'user_tree_data',
extra: {}
});
}, 500);
});
},
user_package(){
// 用户背包道具列表
this.socket.on('user_prop_response', (message)=>{
this.game.fsave({
'user_package': message.data,
});
// 界面中的道具信息
this.game.save({
'pet_food_num': message.pet_food_num,
'fertilizer_num': message.fertilizer_num,
});
api.sendEvent({
name: 'update_prop_data',
extra: {
}
});
})
},
go_index(){
this.game.goWin("root");
},
go_friends(){
this.game.goFrame('friends', 'friends.html', this.current);
this.game.goFrame('friend_list', 'friend_list.html', this.current, {
x: 0,
y: 190,
w: 'auto',
h: 'auto',
}, null, true);
},
go_home(){
this.game.goWin('user', 'user.html', this.current);
},
go_orchard_shop(){
// 种植园商店
this.game.goFrame('orchard_shop', 'shop.html', this.current, null, {
type: 'push',
subType: 'from_top',
duration: 300
});
},
go_my_package(){
// 我的背包
this.game.goFrame('package', 'package.html', this.current, null, {
type: 'push',
subType: 'from_top',
duration: 300
});
},
buy_prop(){
api.addEventListener({
name: 'buy_prop'
}, (ret, err)=>{
if( ret ){
// 用户购买道具
this.socket.emit('user_buy_prop', ret.value);
}
});
this.socket.on('user_buy_prop_response', (message)=>{
alert(message.errmsg);
})
},
use_prop(){
// 使用道具
var pid = 0;
api.addEventListener({
name: 'use_prop'
}, (ret, err)=>{
if( ret ){
// 用户使用道具
pid = ret.value.pid;
var pet_key = this.game.get('pet_key');
if(pet_key<1){
pet_key = 0;
}
this.socket.emit('use_prop', {pid: ret.value.pid, pet_key: pet_key});
}
});
this.socket.on('prop_use_response', (message)=>{
if(parseInt(message.errno) === 1000){
api.sendEvent({
name: 'prop_use_success',
extra: {
pid: pid
}
});
}else{
api.alert({
title: '提示',
msg: message.errmsg,
});
}
});
this.socket.on('pet_feed_response', (message)=>{
if(parseInt(message.errno) === 1000){
api.sendEvent({
name: 'pet_feed_success',
extra: {
pet_key: message.pet_key,
hp_time: message.hp_time
}
});
}else{
api.alert({
title: '提示',
msg: message.errmsg,
});
}
});
},
unlock_package_number(){
api.addEventListener({
name: 'unlock_package_number'
}, (ret, err)=>{
if( ret ){
// 用户购买道具
this.socket.emit('unlock_package');
}
});
this.socket.on('unlock_package_response', (message)=>{
if(parseInt(message.errno) === 1000){
api.sendEvent({
name: 'unlock_package_success',
extra: {
}
});
}else {
api.alert({
title: '提示',
msg: message.errmsg,
});
}
})
},
show_pet(){
// 显示宠物
this.socket.emit('pet_show');
this.socket.on('pet_show_response', (message)=>{
if(parseInt(message.errno) === 1000){
// 把宠物信息保存到本地
this.game.save({'pet_list': message.pet_list})
this.game.save({'pet_number': message.pet_number})
setTimeout(()=>{
api.sendEvent({
name: 'pet_show_success',
extra: {}
});
}, 500);
}else {
api.alert({
title: '提示',
msg: message.errmsg,
});
}
});
api.addEventListener({
name: 'pet_die'
}, (ret, err)=>{
if( ret ){
this.socket.emit('pet_show');
}
});
},
active_tree(){
// 激活树桩
api.addEventListener({
name: 'active_tree'
}, (ret, err)=>{
if( ret ){
this.socket.emit('active_tree');
}
});
this.socket.on('active_tree_response', (message)=>{
if(parseInt(message.errno) === 1000){
// 更新数据到本地
api.sendEvent({
name: 'active_tree_success',
extra: {}
});
}else {
api.alert({
title: '提示',
msg: message.errmsg,
});
}
})
},
water_tree(){
var key = null;
api.addEventListener({
name: 'water_tree'
}, (ret, err)=>{
if( ret ){
key = ret.value.key;
this.socket.emit('water_tree', key=key);
}
});
this.socket.on('water_tree_response', (message)=>{
if(parseInt(message.errno) == 1000){
// 更新数据到本地
api.sendEvent({
name: 'water_tree_success',
extra: {key: key}
});
}else {
api.alert({
title: '提示',
msg: 'message.errmsg',
});
}
})
}
}
});
}
</script>
</body>
</html>