Cocos Creator 远程加载 plist 图集方法


Cocos Creator 远程加载 plist 图集方法

  1. 远程加载plist

  2. creator 安卓打包不支持 cc.loader.load 加载远程文本 plist 文件, 换 http get 方法获取

LoadRemotePlist.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

const BRACE_REGEX = /[\{\}]/g;

function parseSize (sizeStr) {
sizeStr = sizeStr.slice(1, -1);
let arr = sizeStr.split(',');
let width = parseFloat(arr[0]);
let height = parseFloat(arr[1]);
return new cc.Size(width, height);
}

function parseVec2 (vec2Str) {
vec2Str = vec2Str.slice(1, -1);
var arr = vec2Str.split(',');
var x = parseFloat(arr[0]);
var y = parseFloat(arr[1]);
return new cc.Vec2(x, y);
}

function parseTriangles (trianglesStr) {
return trianglesStr.split(' ').map(parseFloat);
}

function parseVertices (verticesStr) {
return verticesStr.split(' ').map(parseFloat);
}

function parseRect (rectStr) {
rectStr = rectStr.replace(BRACE_REGEX, '');
let arr = rectStr.split(',');
return new cc.Rect(
parseFloat(arr[0] || 0),
parseFloat(arr[1] || 0),
parseFloat(arr[2] || 0),
parseFloat(arr[3] || 0),
);
}

function parsePlist (plist, texture) {
let info = plist.metadata;
let frames = plist.frames;

let atlas = new cc.SpriteAtlas();
let spriteFrames = atlas._spriteFrames;

for (let key in frames) {
let frame = frames[key];
let rotated = false, sourceSize, offsetStr, textureRect;
// let trimmed = frame.trimmed;
if (info.format === 0) {
rotated = false;
// trimmed = frame.trimmed;
sourceSize = `{${frame.originalWidth},${frame.originalHeight}}`;
offsetStr = `{${frame.offsetX},${frame.offsetY}}`;
textureRect = `{{${frame.x},${frame.y}},{${frame.width},${frame.height}}}`;
}
else if (info.format === 1 || info.format === 2) {
rotated = frame.rotated;
// trimmed = frame.trimmed;
sourceSize = frame.sourceSize;
offsetStr = frame.offset;
textureRect = frame.frame;
}
else if (info.format === 3) {
rotated = frame.textureRotated;
// trimmed = frame.trimmed;
sourceSize = frame.spriteSourceSize;
offsetStr = frame.spriteOffset;
textureRect = frame.textureRect;
}

var sprite = new cc.SpriteFrame();

sprite.setTexture(texture, parseRect(textureRect), !!rotated, parseVec2(offsetStr), parseSize(sourceSize));
if (frame.triangles) {
let vertices = parseVertices(frame.vertices);
let verticesUV = parseVertices(frame.verticesUV);

sprite.vertices = {
triangles: parseTriangles(frame.triangles),
x: [],
y: [],
u: [],
v: []
};

for (let i = 0; i < vertices.length; i+=2) {
sprite.vertices.x.push(vertices[i]);
sprite.vertices.y.push(vertices[i+1]);
}
for (let i = 0; i < verticesUV.length; i+=2) {
sprite.vertices.u.push(verticesUV[i]);
sprite.vertices.v.push(verticesUV[i+1]);
}
}

let name = cc.path.mainFileName(key);
spriteFrames[name] = sprite;
}

return atlas;
}


module.exports = function (url, callback) {
// 发布 native 版需要下面的方法远程获取和解析plist文件
game.http.get(url, (data) => {
let plist = cc.plistParser.parse(data); // 用这个方法解析 plist 的 xml 格式文件
let texture = plist.metadata.realTextureFileName || plist.metadata.textureFileName;
texture = cc.path.join(cc.path.dirname(url), texture);
cc.loader.load(texture, function (err, tex) {
if (err) {
return callback(err);
}
let atlasSprite = parsePlist(plist, tex);
callback(null, atlasSprite);
});
},(status) => {
callback(status, null);
});

// 发布 web 版可以直接使用下面的方法
// cc.loader.load(url, function (err, plist) {
// if (err) {
// cc.log("plist err:" + JSON.stringify(err));
// return callback(err);
// }
// let texture = plist.metadata.realTextureFileName || plist.metadata.textureFileName;
// texture = cc.path.join(cc.path.dirname(url), texture);
// cc.loader.load(texture, function (err, tex) {
// if (err) {
// return callback(err);
// }
// let atlasSprite = parsePlist(plist, tex);
// callback(null, atlasSprite);
// });
// });
};

HttpRequest.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/** 
* 游戏服务器管理
*/
let HttpRequest = {};
let urls = {}; // 当前请求地址集合
let remoteImages = {};
let remoteImageLoaded = true;

game.HttpEvent = {};
game.HttpEvent.NO_NETWORK = "http_request_no_network"; // 断网
game.HttpEvent.UNKNOWN_ERROR = "http_request_unknown_error"; // 未知错误

game.http = module.exports = {
get: function (url, completeCallback, errorCallback) {
this._sendRequest(url, null, false, completeCallback, errorCallback)
},

getByArraybuffer: function (url, completeCallback, errorCallback) {
this._sendRequest(url, null, false, completeCallback, errorCallback, 'arraybuffer');
},

getWithParams: function (url, params, completeCallback, errorCallback) {
this._sendRequest(url, params, false, completeCallback, errorCallback)
},

getWithParamsByArraybuffer: function (url, params, callback, errorCallback) {
this._sendRequest(url, params, false, completeCallback, errorCallback, 'arraybuffer');
},

post: function (url, params, completeCallback, errorCallback) {
this._sendRequest(url, params, true, completeCallback, errorCallback);
},

_getParamString: function (params) {
let result = "";
for (let name in params) {
result += name + "=" + params[name] + "&";
}
return result.substr(0, result.length - 1);
},

_sendRequest: function (url, params, isPost, completeCallback, errorCallback, responseType) {
if (url === null || url === '')
return;

let newUrl;
if (params) {
newUrl = url + "?" + this._getParamString(params);
}
else {
newUrl = url;
}

if (urls[newUrl]) {
cc.warn("地址不能重复请求:" + url);
return;
}

// 防重复请求功能
urls[newUrl] = true;

let xhr = cc.loader.getXMLHttpRequest();
if (isPost) {
xhr.open("POST", url);
// xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Accept","application/json");
}
else {
xhr.open("GET", newUrl, true);
}

if (responseType === 'arraybuffer') {
xhr.responseType = responseType;
}

xhr.onerror = function () {
delete urls[newUrl];
if (errorCallback === null) return;
if (xhr.readyState === 1 && xhr.status === 0) {
errorCallback(game.HttpEvent.NO_NETWORK); // 断网
}
else {
errorCallback(game.HttpEvent.UNKNOWN_ERROR); // 未知错误
}
};

xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) return;

delete urls[newUrl];
if (xhr.readyState === 4 && xhr.status === 200) {
if (completeCallback) {
if (responseType === 'arraybuffer') {
// xhr.responseType = responseType;
completeCallback(xhr.response); // 加载非文本格式
}
else {
completeCallback(xhr.responseText); // 加载文本格式
}
}
}
else {
if (errorCallback) errorCallback(xhr.status);
}
};

if (params === null || params === "") {
xhr.send();
}
else {
xhr.send(JSON.stringify(params));
//xhr.send(this._getParamString(params));
}
},
postH5: function (url, params, completeCallback, errorCallback) {
let baseurl = game.setting.api[game.setting.channel];
if(!baseurl) baseurl = game.setting.api.default;
let u = baseurl + url;
this._sendRequest(u, { h5: true, requestMsg: JSON.stringify(params) }, true, completeCallback, errorCallback);
},
postOp: function (url, params, completeCallback, errorCallback) {
if(!game.setting.opurl[game.setting.channel]) return;
this._sendRequest(game.setting.opurl[game.setting.channel] + url, params, true, completeCallback, errorCallback);
},
loadRemoteImage: function (params, callback) {
params.guid = game.utils.guid();
remoteImages[params.guid] = {params:params, callback:callback};
},
updateLoadRemoteImage: function () {
if(!remoteImageLoaded) return;
for(let guid in remoteImages){
let data = remoteImages[guid]
if(!data) continue;
remoteImageLoaded = false;
cc.loader.load(data.params, (err, tex) => {
if(err){ // 如果获取失败,则取消后面全部图片的加载,防止切换场景时的卡死问题
remoteImages = {};
}else{
if(data) data.callback(err, tex);
}
delete remoteImages[guid];
remoteImageLoaded = true;
});
break;
}
},
clearAllRemoteImage: function () {
remoteImages = {};
remoteImageLoaded = true;
},
};