CocosCreator-【微信小游戏】小游戏从零开发到上线全过
一周时间,从无到上线的所有开发过程记录如下。小游戏上线由于时间关系,没有接广告(调用微信的API,看完笔记就会了)。小游戏游戏上线3天的流量是4万人左右,端午节的时候哦(没有集大力推广,上线试水),后期用户流失较大(运营的事),小游戏不涉及自己的服务器,只有排行榜是利用的微信的服务器。
主域(主工程)
子域(子工程)
一、游戏内容
1.开发工具
CocosCreator 1.9.1、微信开发工具(最新)、Sublime
2.游戏本身玩法:游戏玩法逻辑,不作介绍,根据游戏自身写逻辑
3.排行榜:微信统计,只有“分数”一个数据,所有游戏本身的围绕一个分数来展开哦
4.分享:分享到微信好友或者微信朋友圈
5.需要创建2个工程,主域和子域
二、上线准备工作
三、开发核心点(坑点)
1.主域
1)游戏主工程(排行榜脚本和排行榜资源不能在这里):游戏玩法逻辑,subCanvas渲染,分数提交,分析等逻辑
2)主域的ui结构:需要创建一个subCanvas
image.png
GameMain.js
var UIHelper = require("UIHelper")
var SHARE_TITLE = "分享标题"
var SHARE_IMAGE_URL = "http://47.106.91.153/wechatgame/game_share_icon.png"
cc.Class({
extends: cc.Component,
gameWebSokcet: null,
properties: {
subCanvas: cc.Sprite,
},
onLoad: function () {
cc.Client = {}
cc.Client.UIHelper = new UIHelper()
cc.Client.GameMain = this
this.updateFlag = false
},
start: function()
{
if (window.wx != undefined) {
window.wx.showShareMenu({withShareTicket: true});
this.tex = new cc.Texture2D();
}
},
shareToFriends: function()
{
if(cc.sys.platform === cc.sys.WECHAT_GAME){
wx.shareAppMessage(
{
title: "端午大作战",
imageUrl: "http://47.106.91.153/wechatgame/game_share_icon.png"
});
}
},
// 刷新子域的纹理
_updateSubDomainCanvas: function() {
if (window.sharedCanvas != undefined) {
this.tex.initWithElement(window.sharedCanvas);
this.tex.handleLoadedTexture();
this.subCanvas.spriteFrame = new cc.SpriteFrame(this.tex);
}
},
setUpdateFlag:function(bOn){
this.updateFlag = bOn
},
update: function(dt) {
if(this.updateFlag){
this._updateSubDomainCanvas();
}
},
})
this._updateSubDomainCanvas(); 必须刷新,这了我用的标记去控制,就是在打开排行的时候去刷新,关闭排行的时候就不刷新,为什么? 因为,这个东西一直刷新非常非常消耗性能,FPS直接掉30帧,所以在玩游戏的就关闭下,游戏结束,打开排行榜再刷新。
2)发布设置:
image.png
黄色框为资源工程发布的游戏名字(特殊的,子工程发布的时候是发布在主工程发布所有在目录,即主工程的build目录下),对应了主域的子工程名字,发布路径必须是主域的build目录下
2.子域:只有排行榜脚本和资源在这里
1)子域设置:
image.png
排行数据相关类WXStorageMgr.js
cc.Class({
extends: cc.Component,
ctor: function()
{
this.RankListData = undefined
this.ScoreTag = "x1"//"WXStorage_Score"
},
SubmitScore: function(score)
{
if (window.wx == undefined)
{
return
}
var self = this
//获取云端的历史数据
wx.getUserCloudStorage({
keyList: [self.ScoreTag],
success: function(res)
{
console.log("云端读取成功")
var last_score = 0
//判断当前分数是否大于历史分数
if (res.KVDataList.length != 0)
{
let val = res.KVDataList[0].value
val = parseInt(val)
if (typeof val == "number")
{
last_score = val
}
}
console.log("----历史分数:" + last_score + "----当前分数:" + score)
if (last_score >= score)
{
console.log("当前分数没有历史分数高,不用记录")
return
}
//开始记录
wx.setUserCloudStorage({
KVDataList: [{key: self.ScoreTag, value: "" + score}],
success: function(res)
{
console.log("云端记录成功")
},
fail: function(res)
{
console.log("云端记录失败")
},
})
},
fail: function(res)
{
console.log("云端读取失败")
},
})
},
GetRankingData: function(call_back)
{
if (window.wx == undefined)
{
return
}
var self = this
//获取自己的信息
wx.getUserInfo({
openIdList: ["selfOpenId"],
success: function(res){
console.log(res)
//取出自己的user_info
if (res.data.length <= 0)
{
console.log("用户信息读取失败")
}
let mine_info = res.data[0]
//openid
//获取朋友的信息
wx.getFriendCloudStorage({
keyList: [self.ScoreTag],
success: function(res)
{
self.RankListData = new Array()
res.data.forEach(function(item,index,array){
let new_item = {}
new_item.avatarUrl = item.avatarUrl
new_item.isMine = item.avatarUrl == mine_info.avatarUrl
new_item.nickName = item.nickname
if (item.KVDataList.length > 0)
{
new_item.score = parseInt(item.KVDataList[0].value)
}else
{
new_item.score = 0
}
self.RankListData[index] = new_item
});
if (typeof call_back == "function")
{
call_back(self.RankListData)
}
console.log(self.RankListData)
},
fail: function(res)
{
console.log("朋友信息获取失败")
},
})
},
fail: function(res){
console.log("用户信息读取失败")
}
})
},
});
排行数据调用过程代码:
UIRank.js部分代码:
var WXStorageMgr = require("WXStorageMgr")
var MAX_SHOW_RANK = 100
var sort = function(ranks){
ranks.sort(function(a, b){
return b.score - a.score
})
}
// 用法:AddClickEvent(this.testBtn, this.node, "BtnFunctionTest", this.__classname__)
var AddClickEvent = function(node, target, handler, component){
if(!component){
log.error("<unknown component>")
return
}
console.log(node.name + ":" + component + ":" + handler)
var eventHandler = new cc.Component.EventHandler()
eventHandler.target = target
eventHandler.component = component
eventHandler.handler = handler
var clickEvents = node.getComponent(cc.Button).clickEvents;
clickEvents.push(eventHandler)
}
// 加载该玩家头像
var loadWechatHead = function(node, headSprite, head_url){
let image = wx.createImage()
image.onload = function () {
let texture = new cc.Texture2D()
texture.initWithElement(image)
texture.handleLoadedTexture()
headSprite.spriteFrame = new cc.SpriteFrame(texture)
}
image.src = head_url
}
cc.Class({
extends: cc.Component,
properties: {
btnChallenge:cc.Node,
btnReplay:cc.Node,
btnReturn:cc.Node,
btnViewAllRank:cc.Node,
rankListView:cc.ScrollView,
content:cc.Node,
rankItem:cc.Prefab,
curGetScore:cc.Label,
top4Node:cc.Node,
selfItem:cc.Node,
maxItem:cc.Node,
subRank:cc.Node,
allRank:cc.Node,
uiRank:cc.Node,
allRankBtnReturn :cc.Node,
btnShareToFriends :cc.Node,
},
onLoad () {
AddClickEvent(this.btnChallenge, this.node, "onBtnChallenge", this.__classname__)
AddClickEvent(this.btnReplay, this.node, "onBtnReplay", this.__classname__)
AddClickEvent(this.btnReturn, this.node, "onBtnReturn", this.__classname__)
AddClickEvent(this.btnViewAllRank, this.node, "onBtnViewAllRank", this.__classname__)
AddClickEvent(this.allRankBtnReturn, this.node, "onAllRankBtnReturn", this.__classname__)
AddClickEvent(this.btnShareToFriends, this.node, "shareToFriends", this.__classname__)
this.storageMgr = new WXStorageMgr()
console.log("rank on load finish")
},
shareToFriends: function()
{
if (window.wx == undefined)
{
return
}
wx.shareAppMessage(
{
title: "粽子大作战",
imageUrl: "http://47.106.91.153/wechatgame/duanwugame/res/raw-assets/resources/png/login/l_01.849db.png"
});
},
start: function()
{
console.log("rank on start")
var self = this
if (window.wx != undefined)
{
window.wx.onMessage(function(data)
{
//1:设置分数 2:获取排行数据
if (data.type == 1)
{
console.log("设置分数")
self.storageMgr.SubmitScore(data.score)
}else if (data.type == 2)
{
console.log("获取排行数据")
var that = self
self.storageMgr.GetRankingData(function(rank_datas)
{
console.log("-----排行数据获取成功-----")
that.onWechatCallback(rank_datas)
})
} else if (data.type == 4){
self.closeRankUI()
}
})
}
console.log("rank on start finish")
},
onAllRankBtnReturn:function(){
this.viewSubRank()
},
onWechatCallback:function(data){
for (var i = 0; i < data.length; i++) {
data[i]
}
this.uiRank.active = true
this.ranks = data
sort(this.ranks)
this.viewTop4PlayerRank(this.ranks)
// 自己
if(this.getMineInfo(this.ranks)){
var infos = this.getMineInfo(this.ranks)
this.setItemInfo(this.selfItem, infos.info, infos.rank)
} else {
console.log("error self info")
}
// 最大
if(this.ranks[0]){
console.log(" max info")
this.setItemInfo(this.maxItem, this.ranks[0], 1)
} else {
console.log("error max info")
}
this.viewSubRank()
},
3.分享:坑的是,在pc上的微信开发工具,调试期间没有转发功能,然后我在mac上的微信开发工具调试有转发功能!不知道后期是否修复了。
分析代码:
wx.shareAppMessage(
{
title: "粽子大作战",
imageUrl: "http://47.106.91.153/wechatgame/duanwugame/res/raw-assets/resources/png/login/l_01.849db.png"
});
4..ui制作规范:
由于子域不能和主域通信(主域能和子域通信),所有我把排行相关的ui按钮做到了主工程里面,然后按钮发送消息给子工程(这里基本思路,通信的内容用微信的api进行)
通信代码例子:
returnBegin:function(){
this.uiRankTemp.active = false
this.uiBegin.active = true
if(cc.sys.platform === cc.sys.WECHAT_GAME){
window.wx.postMessage({
type: 4,
});
}
var self = this
this.schedule(function(){
self.canvas.getComponent("GameMain").setUpdateFlag(false)
}, 0.1, 1)
},
image.png
4.远程资源下载
5.发布开发版本
6.发布体验版本
7.发布正式版
四、后记