16 Star 143 Fork 52

Javen / Sunflower

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

小游戏爱上云开发

游戏简介

游戏名称: 娇娆向日葵

作者: Javen

版权: 深圳市紫石文化传播有限公司

开发语言: JavaScript

游戏引擎: Cocos Creator v2.1.2

注意事项: 允许免费用于学习交流,切勿商用否则后果自负

玩法:随着音乐节奏,点击左右按钮控制场景中人物形象播放速度,操作反应越快燃烧的卡路里越多、人物形象播放速度越快。

核心功能:

  1. 微信授权登录
  2. 好友排行榜
  3. 游戏个性化分享
  4. 小程序-云开发(获取用户信息、加载配置数据、上报成绩、排行榜)
  5. 资源动态加载(龙骨动画、预制资源)
  6. 资源远程加载(打包后将资源放在服务器首次启动时进行远程加载)
  7. 场景切换时显示加载进度

游戏场景介绍

该游戏比较简单,总共只使用到四个场景加微信开放域项目。

  • First 场景,此场景只有一张图片,此图片与游戏包一起发布。是为了解决 IOS 进行远程加载时会出现短暂黑屏的问题
  • Welcome 公司 IP 形象宣传页动画
  • Loading 加载数据的过渡场景。
    • 初始化云开发环境
    • 获取 openId
    • 获取用户信息
  • Home 游戏主场景
    • 初始化UI(各种 Node 节点、倒计时组件、异步加载龙骨动画、动态加载预制资源)
    • 判断是否授权,如果没有授权就动态创建button
    • 游戏逻辑实现
    • 游戏成绩上报
    • 好友排行榜

效果图

game1 game2 game3

云数据库

点击图三中的 云开发 根据流程开通即可使用 云函数云储存云数据库

wx_could wx_could

核心功能实现

参考文档:

微信 API 常用接口的封装

  • 初始化云环境
  • 封装调用云函数方法
  • 获取用户信息
  • 创建用户信息按钮
  • 调用云数据库将最新成绩上传至云端
  • 微信广告接口封装
# WxApi.js
/**
 * @author Javen 
 * @copyright 2019-03-07 19:22:21 javendev@126.com 
 * @description 微信接口
 */
let Global = require('../common/Global');

var WxApi = function() {

}
/**
 * 1、初始化云环境 
 * 2、显示分享菜单
 * 3、设置转发·小程序内容
 */
WxApi.prototype.initCloud = function(envId) {
    wx.cloud.init({
        env: envId,
        traceUser: true
    });

    //初始化数据库
    Global.wxDb = wx.cloud.database({
        env: envId
    });

    this.showShareMenu();
    this.onShareAppMessage();
}

/**
 * 封装调用云函数方法
 */
WxApi.prototype.callFunction = function(funcName, params) {
    return new Promise((resolve, reject) => {
        wx.cloud.callFunction({
            name: funcName,
            data: params || {},
            success: res => {
                resolve(res)
                console.log(`[云函数 ${funcName}] 调用成功: `, res);
            },
            fail: err => {
                resolve(null)
                console.log(`[云函数 ${funcName}] 调用失败: `, err);
            }
        })
    })
}
/**
 * 判断是否已授权
 */
WxApi.prototype.getSetting = function(scope) {
    return new Promise(function(resolve, reject) {
        wx.getSetting({
            success (res) {
                if (res.authSetting[scope]) {
                    resolve('已授权');
                } else {
                    reject('未授权');
                }
            }
        })
    });
}
/**
 * 获取用户信息
 */
WxApi.prototype.getUserInfo = function() {
    return new Promise(function(resolve, reject) {
        wx.getUserInfo({
            withCredentials: true,
            success (res) {
                resolve(res);
            },
            fail (error) {
                reject(error);
            }
        })
    });
}

WxApi.prototype.login = function() {
    return new Promise(function(resolve, reject) {
        if (cc.sys.platform == cc.sys.WECHAT_GAME) {
            wx.login({
                success (res) {
                    if (res.code) {
                        resolve(res.code);
                    } else {
                        reject(res.errMsg);
                    }
                }
            });
        } else {
            reject('非微信环境');
        }
    });
}

/**
 * 创建用户信息按钮
 */
WxApi.prototype.createUserInfoBtnByImg = function(left, top, imgUrl, width, height, callBack) {
    if (cc.sys.platform == cc.sys.WECHAT_GAME) {
        let button = wx.createUserInfoButton({
            type: 'image',
            image: imgUrl,
            style: {
                left: left,
                top: top,
                width: width,
                height: height,
            }
        });
        button.onTap((res) => {
            if (callBack) {
                callBack(res);
            }
        });
        button.show();
        return button;
    } else {
        console.log("createUserInfoBtnByImg 非微信环境...");
    }
}
/**
 * 创建打开意见反馈页面的按钮
 */
WxApi.prototype.createFeedbackButtonByImg = function(left, top, imgUrl, width, height, callBack) {
    if (cc.sys.platform == cc.sys.WECHAT_GAME) {

        let button = wx.createFeedbackButton({
            type: 'image',
            image: imgUrl,
            style: {
                left: left,
                top: top,
                width: width,
                height: height,
            }
        });
        button.onTap((res) => {
            if (callBack) {
                callBack(res);
            }
        });
        button.show();
        return button;
    } else {
        console.log("createFeedbackButtonByImg 非微信环境...");
    }
}

WxApi.prototype.getShareInfo = function(title, imageUrl, openId) {
    if (!title) {
        title = "前方高能";
    }
    if (!imageUrl) {
        imageUrl = "https://7072-pro-15ec75-1258808161.tcb.qcloud.la/static/share_01.png?sign=f246f9cc5f05eece2ae92bbd4444cc16&t=1552447069";
    }
    let query = "";
    if (!openId) {
        query = 'openId=' + openId;
    }
    return {
        title: title,
        imageUrl: imageUrl,
        query: query,
        success (res) {
            console.log("分享完成...", res);
        },
        fail (res) {
            console.log("分享失败...", res);
        }
    };
}

WxApi.prototype.showShareMenu = function() {
    if (cc.sys.platform == cc.sys.WECHAT_GAME) {
        wx.showShareMenu({
            withShareTicket: true
        });
    }
}

WxApi.prototype.onShareAppMessage = function(shareInfo) {
    if (!shareInfo) {
        shareInfo = this.getShareInfo();
    }
    if (cc.sys.platform == cc.sys.WECHAT_GAME) {
        //转发·小程序
        wx.onShareAppMessage(function() {
            return shareInfo;
        });
    } else {
        console.log("onShareAppMessage 非微信环境...");
    }
}

WxApi.prototype.shareAppMessage = function(shareInfo) {
    if (cc.sys.platform == cc.sys.WECHAT_GAME) {
        if (!shareInfo) {
            shareInfo = this.getShareInfo();
        }
        //主动分享
        wx.shareAppMessage(shareInfo);
    } else {
        console.log("shareAppMessage 非微信环境...");
    }
}

WxApi.prototype.showModal = function(title, content) {
    wx.showModal({
        title: title,
        content: content
    });
}

WxApi.prototype.showLoading = function(title) {
    return new Promise(function(resolve, reject) {
        if (cc.sys.platform == cc.sys.WECHAT_GAME) {
            wx.showLoading({
                title: title,
                mask: true,
                success (res) {
                    resolve(res);
                },
                fail (error) {
                    reject(error);
                }
            });
        } else {
            reject('非微信平台');
        }
    });
}

WxApi.prototype.hideLoading = function() {
    if (cc.sys.platform == cc.sys.WECHAT_GAME) {
        wx.hideLoading();
    }
}

WxApi.prototype.showToast = function(msg) {
    wx.showToast({
        title: msg,
        duration: 2000
    })
}



WxApi.prototype.loadVideoAd = function(adUnitId) {
    if (!Global.videoAd && cc.sys.platform == cc.sys.WECHAT_GAME) {
        let rewardedVideoAd = wx.createRewardedVideoAd({
            adUnitId: adUnitId
        });
        rewardedVideoAd.onLoad(() => {
            console.log('激励视频 广告加载成功');
            Global.videoAd = rewardedVideoAd;
            Global.videoAdLoadCount = 0;
        });
        rewardedVideoAd.onClose(res => {
            console.log('激励视频 广告关闭');
            Global.videoAd = undefined;
        });
        rewardedVideoAd.onError(err => {
            console.log('激励视频 广告加载失败');
            Global.viewAdLoadCount += 1;
            if (Global.viewAdLoadCount < 4) {
                rewardedVideoAd.load();
            }
        })
    }
}

WxApi.prototype.loadBannerAd = function(adUnitId) {
    if (!Global.bannerAd && cc.sys.platform == cc.sys.WECHAT_GAME) {

        let bannerAd = wx.createBannerAd({
            adUnitId: adUnitId,
            style: {
                left: 10,
                top: Global.windowHeight - 180,
                width: Global.windowWidth - 20,
            }
        });
        bannerAd.onError(err => {
            console.log('Banner 广告加载失败', err);
            Global.bannerAdLoadCount += 1;
            if (Global.bannerAdLoadCount < 4) {
                loadBannerAd();
            }
        });
        bannerAd.onLoad(() => {
            console.log('banner 广告加载成功');
            Global.bannerAd = bannerAd;
            Global.viewAdLoadCount = 0;
        });
    }
}

WxApi.prototype.showBannerAd = function() {
    if (Global.bannerAd) {
        Global.bannerAd.show();
    } else {
        loadBannerAd();
    }
}

WxApi.prototype.hideBannerAd = function() {
    if (Global.bannerAd) {
        // Global.bannerAd.hide();
        Global.bannerAd.destroy();
        Global.bannerAd = undefined;
        loadBannerAd();
    } else {
        console.log('不存在资源,无需关闭');
    }
}

WxApi.prototype.post = function(postUrl, params) {
    return new Promise(function(resolve, reject) {
        wx.request({
            url: postUrl,
            method: 'POST',
            header: {
                'content-type': 'application/x-www-form-urlencoded'
            },
            data: params || {},
            success: function(res) {
                resolve(res)
                console.log(`[post ${postUrl}] 调用成功: `, res);
            },
            fail: function(error) {
                reject(error);
                console.log(`[post ${postUrl}] 调用失败: `, error);
            }
        });
    });
}
/**
 * 设置用户云端数据
 */
WxApi.prototype.setUserCloudStorage = function(score) {
    return new Promise(function(resolve, reject) {
        wx.setUserCloudStorage({
            KVDataList: [{
                key: "score",
                value: score + ""
            }],
            success (res) {
                console.log("数据上报成功:", res);
                resolve(res);
            },
            fail (err) {
                console.log("数据上报失败:", err);
                reject(err);
            },
            complete () {
                console.log("数据上报完成");
            }
        });
    });
}
/**
 * 调用云函数将最新成绩上传至云端
 */
WxApi.prototype.uploadScore = function(score) {
    let that = this;
    // 1、查询成绩 
    // 2、如果没有数据就添加
    // 3、如果有数据判断是否是新纪录
    return new Promise(function(resolve, reject) {
        Global.wxDb.collection('scores').where({
            _openid: Global.openId,
        }).get({
            success (res) {
                if (res.data.length > 0) {
                    let data = res.data[0];
                    let oldScore = data.score;

                    if (oldScore < score) {
                        // 新纪录 更新
                        Global.wxDb.collection('scores').doc(data._id).update({
                            data: {
                                score: score,
                                updateDate: Global.wxDb.serverDate()
                            },
                            success (res) {
                                that.setUserCloudStorage(score);
                                // 新纪录
                                resolve(1);
                            },
                            fail (err) {
                                reject(err);
                            }
                        })
                    } else {
                        resolve(-1);
                    }
                } else {
                    // 无纪录添加数据
                    Global.wxDb.collection('scores').add({
                        data: {
                            score: score,
                            createDate: Global.wxDb.serverDate(),
                            updateDate: Global.wxDb.serverDate()
                        },
                        success (res) {
                            that.setUserCloudStorage(score);
                            // 新纪录
                            resolve(1);
                        },
                        fail (err) {
                            reject(err);
                        }
                    })
                }
            },
            fail (err) {
                reject(err);
            }
        })
    });
}

module.exports = WxApi;

适配不同平台

思路: 使用 cc.sys.platform 获取平台信息再做接口适配,目前只实现了 cc.sys.WECHAT_GAME 的接口如下:

const WxApi = require('./WxApi');

var wxApi = new WxApi();

function initCloud () {
    wxApi.initCloud('pro-15ec75');
}

function callFunction (funcName, params) {
    return wxApi.callFunction(funcName, params)
}

// 获取设置,判断是否授权
function getSetting (scope) {
    return wxApi.getSetting(scope);
}
// 登录获取code
function login () {
    return wxApi.login();
}

function getUserInfo () {
    return wxApi.getUserInfo();
}

// 显示准发按钮
function showShareMenu () {
    wxApi.showShareMenu();
}

// 转发·小程序
function onShareAppMessage () {
    wxApi.onShareAppMessage();
}
// 主动拉起转发
function shareAppMessage () {
    wxApi.shareAppMessage();
}

function showModal (title, content) {
    wxApi.showModal(title, content);
}

function showLoading (title) {
    wxApi.showLoading(title)
}

function hideLoading () {
    wxApi.hideLoading();
}

// 动态创建获取用户信息按钮
function createUserInfoBtnByImg (left, top, imgUrl, width, height, callBack) {
    return wxApi.createUserInfoBtnByImg(left, top, imgUrl, width, height, callBack);
}

// 动态创建反馈按钮
function createFeedbackButtonByImg (left, top, imgUrl, width, height, callBack) {
    return wxApi.createFeedbackButtonByImg(left, top, imgUrl, width, height, callBack);
}

function loadVideoAd () {
    wxApi.loadVideoAd('adunit-5b6b4a914e14b53e');
}

function loadBannerAd () {
    wxApi.loadBannerAd('adunit-0ebd781de8250e17');
}

function showBannerAd () {
    wxApi.showBannerAd();
}

function hideBannerAd () {
    wxApi.hideBannerAd();
}

function post (postUrl, params) {
    return wxApi.post(postUrl, params);
}

function uploadScore (score) {
    return wxApi.uploadScore(score);
}

module.exports = {
    initCloud: initCloud,
    getSetting: getSetting,
    login: login,
    getUserInfo: getUserInfo,
    showShareMenu: showShareMenu,
    onShareAppMessage: onShareAppMessage,
    shareAppMessage: shareAppMessage,
    createUserInfoBtnByImg: createUserInfoBtnByImg,
    createFeedbackButtonByImg: createFeedbackButtonByImg,
    loadVideoAd: loadVideoAd,
    loadBannerAd: loadBannerAd,
    showBannerAd: showBannerAd,
    hideBannerAd: hideBannerAd,
    showModal: showModal,
    showLoading: showLoading,
    hideLoading: hideLoading,
    post: post,
    callFunction: callFunction,
    uploadScore: uploadScore,
}

微信开放域

微信小游戏开放数据域使用的是旧版本实现 参考文档

let ITEM_TYPE = cc.Enum({
    TOP3: 0,
    OTHERS: 1,
    SELF: 2,
});
cc.Class({
    extends: cc.Component,
 
    properties: {
        content: cc.Node,
        selfNode: cc.Node,
        prefab: cc.Prefab,
        itemBgs: {
            default: [],
            type: cc.SpriteFrame
        },
        itemNumberTop3: {
            default: [],
            type: cc.SpriteFrame
        },
        _dataArray: [],
    },
 
    start() {
        let _self = this;
 
        if (cc.sys.platform == cc.sys.WECHAT_GAME) {
            wx.onMessage(data => {
                console.log("onMessage..", data);
                if (data.message == 'getFriendRank') {
 
                    let selfOpenId = data.openId;
                    console.log("selfOpenId:", selfOpenId);
                    //清理之前的数据
                    _self.content.children.forEach(element => {
                        element.destroy();
                    });
                    _self._dataArray = [];
                    //清理之前的数据End
                    //获取好友排行榜数据
                    wx.getFriendCloudStorage({
                        keyList: ['score'],
                        success: function (res) {
                            console.log('friend success', res);
                            let length = res.data.length;
                            if (length > 0) {
                                for (let i = 0; i < res.data.length; i++) {
                                    let friendInfo = res.data[i];
                                    if (friendInfo) {
                                        let openId = friendInfo.openid;
                                        let nickName = friendInfo.nickname;
                                        let avatarUrl = friendInfo.avatarUrl;
                                        let score = friendInfo.KVDataList[0].value;
                                        _self._dataArray.push(_self._itemObj(0, openId, avatarUrl, nickName, score));
                                    }
                                }
                                //排序
                                _self._dataArray.sort(function (m, n) {
                                    if (parseInt(m.score) < parseInt(n.score)) return 1
                                    else if (parseInt(m.score) > parseInt(n.score)) return -1
                                    else return 0
                                });
                                console.log("排序后的数据:", _self._dataArray);
                                let temp = _self._dataArray.length > 10 ? 10 : _self._dataArray.length;
                                for (let index = 0; index < temp; index++) {
                                    let node = _self.createPrefab();
                                    let itemData = _self._dataArray[index];
                                    itemData.id = index + 1;
                                    _self._setItemNode(node, itemData.id < 4 ? ITEM_TYPE.TOP3 : ITEM_TYPE.OTHERS,
                                        itemData);
                                }
 
                                _self.selfNode.active = false;
                                //设置自己排名
                                for (let index = 0; index < _self._dataArray.length; index++) {
                                    let tempData = _self._dataArray[index];
                                    tempData.id = index + 1;
                                    if (selfOpenId == tempData.openId) {
                                        console.log("selfData:", tempData);
                                        _self._setItemNode(_self.createPrefab(), ITEM_TYPE.SELF, tempData);
                                        _self.selfNode.active = true;
                                        break;
                                    }
                                }
                            }
                        },
                        fail: function (res) {
                            console.error(res);
                        }
                    });
                }
            });
        } else {
            //非微信环境下的测试数据
            console.log('非微信环境...');
            for (let index = 1; index < 11; index++) {
                let node = this.createPrefab();
                let itemData = new this._itemObj(index, "", "http://192.168.1.134:12888/img/head.png",
                    "Javen", 100 + index);
                this._setItemNode(node, index < 4 ? ITEM_TYPE.TOP3 : ITEM_TYPE.OTHERS, itemData);
            }
            let itemData = new this._itemObj(100, "", "http://192.168.1.134:12888/img/head.png",
                "Javen001", 100);
            this._setItemNode(this.createPrefab(), ITEM_TYPE.SELF, itemData);
        }
    },
 
    _setItemNode(newNode, type, itemObj) {
        // 设置成绩
        newNode.getChildByName("score").getComponent(cc.Label).string = itemObj.score;
        // 设置图像
        let headNode = newNode.getChildByName("head").getChildByName("head");
        this.loadImgByUrl(headNode, itemObj.avatarUrl);
        // 设置 item 背景
        newNode.getComponent(cc.Sprite).spriteFrame = this.itemBgs[type];
        // 设置玩家昵称 
        newNode.getChildByName("bannerId").getChildByName("name").
        getComponent(cc.Label).string = this.stringTodo(itemObj.nickName, 8);
        // 设置排名
        let noNode = newNode.getChildByName("no");
        let numberNode = newNode.getChildByName("number");
        let numImgNode = newNode.getChildByName("numImg");
        noNode.active = false;
        numberNode.active = false;
        numImgNode.active = false;
 
        if (type == ITEM_TYPE.TOP3) {
            numImgNode.getComponent(cc.Sprite).spriteFrame = this.itemNumberTop3[itemObj.id - 1];
            numImgNode.active = true;
        } else if (type == ITEM_TYPE.OTHERS) {
            numberNode.getComponent(cc.Label).string = itemObj.id;
            numberNode.active = true;
        } else if (type == ITEM_TYPE.SELF) {
            if (itemObj.id <= 0) {
                noNode.active = true;
            } else {
                numberNode.getComponent(cc.Label).string = itemObj.id;
                numberNode.active = true;
            }
        }
 
        if (type == ITEM_TYPE.SELF) {
            newNode.parent = this.selfNode;
        }
    },
 
    _itemObj(id, openId, avatarUrl, nickName, score) {
        return {
            id: id,
            openId: openId,
            nickName: nickName,
            score: score,
            avatarUrl: avatarUrl,
        }
    },
 
    createPrefab() {
        let node = cc.instantiate(this.prefab);
        node.parent = this.content;
        return node;
    },
    loadImgByUrl(imgNode, remoteUrl, imageType) {
        let _self = this;
        if (!imageType) {
            imageType = "png";
        }
        cc.loader.load({
            url: remoteUrl,
            type: imageType
        }, function (err, texture) {
            if (err) {
                return;
            }
            _self.setImg(imgNode, new cc.SpriteFrame(texture));
        });
    },
    setImg(imgNode, spriteFrame) {
        imgNode.getComponent(cc.Sprite).spriteFrame = spriteFrame;
    },
    stringTodo(str, len) {
        let reg = /[\u4e00-\u9fa5]/g,
            slice = str.substring(0, len),
            chineseCharNum = (~~(slice.match(reg) && slice.match(reg).length)),
            realen = slice.length * 2 - chineseCharNum;
        return str.substr(0, realen) + (realen < str.length ? "..." : "");
    }
 
});

资源远程加载

参考文章:

广而告知

空文件

简介

微信小游戏-妖娆向日葵,随着音乐节奏,点击左右按钮控制场景中人物形象播放速度,操作反应越快燃烧的卡路里越多、人物形象播放速度越快。 展开 收起
JavaScript
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
JavaScript
1
https://gitee.com/javen205/Sunflower.git
git@gitee.com:javen205/Sunflower.git
javen205
Sunflower
Sunflower
master

搜索帮助