Commit 4d911608 authored by limingzhe's avatar limingzhe

fix: debug

parent c71b356e
No preview for this file type
......@@ -2,8 +2,6 @@
cocos creator技术框架下的H5互动模板框架脚手架,基于cocos creator实现快速开发基于绘玩云的H5互动课件。
[视频教程传送门](https://www.bilibili.com/video/BV1Dq4y1t7n5/)
# 使用简介
## 前期准备
......@@ -51,30 +49,29 @@ npm start
```
* 打开浏览器:http://staging-teach.ireadabc.com/template_ci/debug
* [点击查看调试视频教程](https://www.bilibili.com/video/BV1Dq4y1t7n5?p=8)
### 真机调试
* 下载模板调试专用app
* 点击右上角齿轮,选择技术选型、调试模式选择“普通”
安卓下载:
http://download-iplayabc.oss-cn-beijing.aliyuncs.com/iDebugABC.apk
![avatar](http://staging-teach.cdn.ireadabc.com/084f2f95-8213-4c5a-8c46-b194819d7677.png)
### 互动模板
* 找到项目根路径下 index.html 文件
* 在引入JS的位置将air.js改为air_online_open.js
* 启动本地服务
iOS下载:
```
npm start
```
由于调试APP没有上架App Store 所以需要先获取手机的UDID 发送给我们的技术支持,加入后才可以扫码下载安装
获取UDID:https://www.pgyer.com/tools/udid
下载iOS: https://www.pgyer.com/gS0X
* 打开浏览器:http://staging-teach.ireadabc.com/template_ci/debug
* 点击右上角齿轮,选择技术选型、调试模式选择“互动”
* 左侧老师、右侧学生
### 真机调试
有时可能需要反复调试一些功能性的问题,与原生APP相关或者手上临时没有设备,我们提供了一个网页版的调试方式
* 下载模板调试专用app
http://staging-openapi.iteachabc.com/api/courseware/v1/middle/debug
http://download-iplayabc.oss-cn-beijing.aliyuncs.com/iDebugABC.apk
![avatar](http://staging-teach.cdn.ireadabc.com/084f2f95-8213-4c5a-8c46-b194819d7677.png)
* 启动本地服务
......@@ -84,12 +81,4 @@ npm start
* 手机和电脑连接同一个Wifi
* 打开调试app,根据提示输入IP地址,点击开始就可以在手机上预览模板了
* 使用 console.log("==调试信息=="); 可以打印日志进行必要的调试
* 点击左上角 “logcat” 可以查看运行日志,(logcat是可以按住拖动的, 所以不用考虑UI遮挡问题)
### 注意事项及常见问题
* 项目里所有文件及文件夹的命名方式要注意不能包含空格、汉字、减号
* 开发者新建的脚本文件(.js/.ts)的文件名必须包含项目名称,例如在 test_01 项目中添加一个脚本文件(如想命名为 hello.ts );则需要命名为 hello_test_01.ts
* 项目里尽量不要使用setTimeout、setInterval等定时器,如果使用了记得在onDestroy中释放掉(onDestroy 是指CocosCreator的生命周期钩子)
* 理论上禁止使用全局变量,因为模板到线上会进行组装,常见问题是一个模板使用多次造成全局变量被读脏
* 使用 this.log("==调试信息=="); 可以打印日志进行必要的调试
\ No newline at end of file
import { asyncDelay, onHomeworkFinish } from "../script/util";
import { MyCocosSceneComponent } from "../script/MyCocosSceneComponent";
const { ccclass, property } = cc._decorator;
@ccclass
export default class SceneComponent extends MyCocosSceneComponent {
addPreloadImage() {
// TODO 根据自己的配置预加载图片资源
this._imageResList.push({ url: this.data.pic_url });
this._imageResList.push({ url: this.data.pic_url_2 });
}
addPreloadAudio() {
// TODO 根据自己的配置预加载音频资源
this._audioResList.push({ url: this.data.audio_url });
}
addPreloadAnima() {
}
async onLoadEnd() {
// TODO 加载完成后的逻辑写在这里, 下面的代码仅供参考
this.initData();
this.initView();
this.initListener();
}
_cantouch = null;
initData() {
// 所有全局变量 默认都是null
this._cantouch = true;
}
initView() {
this.initBg();
this.initPic();
this.initBtn();
this.initIcon();
}
initBg() {
const bgNode = cc.find('Canvas/bg');
bgNode.scale = this._mapScaleMax;
}
pic1 = null;
pic2 = null;
initPic() {
const canvas = cc.find('Canvas');
const maxW = canvas.width * 0.7;
this.getSprNodeByUrl(this.data.pic_url, (sprNode) => {
const picNode1 = sprNode;
picNode1.scale = maxW / picNode1.width;
picNode1.baseX = picNode1.x;
canvas.addChild(picNode1);
this.pic1 = picNode1;
const labelNode = new cc.Node();
labelNode.color = cc.Color.YELLOW;
const label = labelNode.addComponent(cc.Label);
label.string = this.data.text;
label.fontSize = 60;
label.lineHeight = 60;
label.font = cc.find('Canvas/res/font/BRLNSDB').getComponent('cc.Label').font;
picNode1.addChild(labelNode);
});
this.getSprNodeByUrl(this.data.pic_url_2, (sprNode) => {
const picNode2 = sprNode;
picNode2.scale = maxW / picNode2.width;
canvas.addChild(picNode2);
picNode2.x = canvas.width;
picNode2.baseX = picNode2.x;
this.pic2 = picNode2;
const labelNode = new cc.Node();
const label = labelNode.addComponent(cc.RichText);
const size = 60
label.font = cc.find('Canvas/res/font/BRLNSDB').getComponent(cc.Label).font;
label.string = `<outline color=#751e00 width=4><size=${size}><color=#ffffff>${this.data.text}</color></size></outline>`
label.lineHeight = size;
picNode2.addChild(labelNode);
});
}
initIcon() {
const iconNode = this.getSprNode('icon');
iconNode.zIndex = 5;
iconNode.anchorX = 1;
iconNode.anchorY = 1;
iconNode.parent = cc.find('Canvas');
iconNode.x = iconNode.parent.width / 2 - 10;
iconNode.y = iconNode.parent.height / 2 - 10;
iconNode.on(cc.Node.EventType.TOUCH_START, () => {
this.playAudioByUrl(this.data.audio_url);
})
}
curPage = null;
initBtn() {
this.curPage = 0;
const bottomPart = cc.find('Canvas/bottomPart');
bottomPart.zIndex = 5; // 提高层级
bottomPart.x = bottomPart.parent.width / 2;
bottomPart.y = -bottomPart.parent.height / 2;
const leftBtnNode = bottomPart.getChildByName('btn_left');
//节点中添加了button组件 则可以添加click事件监听
leftBtnNode.on('click', () => {
if (!this._cantouch) {
return;
}
if (this.curPage == 0) {
return;
}
this.curPage = 0
this.leftMove();
this.playLocalAudio('btn');
})
const rightBtnNode = bottomPart.getChildByName('btn_right');
//节点中添加了button组件 则可以添加click事件监听
rightBtnNode.on('click', () => {
if (!this._cantouch) {
return;
}
if (this.curPage == 1) {
return;
}
this.curPage = 1
this.rightMove();
// 游戏结束时需要调用这个方法通知系统作业完成
onHomeworkFinish();
this.playLocalAudio('btn');
})
}
leftMove() {
this._cantouch = false;
const len = this.pic1.parent.width;
cc.tween(this.pic1)
.to(1, { x: this.pic1.baseX }, { easing: 'cubicInOut' })
.start();
cc.tween(this.pic2)
.to(1, { x: this.pic2.baseX }, { easing: 'cubicInOut' })
.call(() => {
this._cantouch = true;
})
.start();
}
rightMove() {
this._cantouch = false;
const len = this.pic1.parent.width;
cc.tween(this.pic1)
.to(1, { x: this.pic1.baseX - len }, { easing: 'cubicInOut' })
.start();
cc.tween(this.pic2)
.to(1, { x: this.pic2.baseX - len }, { easing: 'cubicInOut' })
.call(() => {
this._cantouch = true;
})
.start();
}
// update (dt) {},
initListener() {
}
playLocalAudio(audioName) {
const audio = cc.find(`Canvas/res/audio/${audioName}`).getComponent(cc.AudioSource);
return new Promise((resolve, reject) => {
const id = cc.audioEngine.playEffect(audio.clip, false);
cc.audioEngine.setFinishCallback(id, () => {
resolve(id);
});
})
}
}
import { defaultData } from "../script/defaultData";
export class MyCocosSceneComponent extends cc.Component {
// 生命周期 onLoad
onLoad() {
this.initSceneData();
this.initSize();
}
_imageResList = null;
_audioResList = null;
_animaResList = null;
initSceneData() {
this._imageResList = [];
this._audioResList = [];
this._animaResList = [];
}
_designSize = null; // 设计分辨率
_frameSize = null; // 屏幕分辨率
_mapScaleMin = null; // 场景中常用缩放(取大值)
_mapScaleMax = null; // 场景中常用缩放(取小值)
_cocosScale = null; // cocos 自缩放 (较少用到)
initSize() {
// 注意cc.winSize只有在适配后(修改fitHeight/fitWidth后)才能获取到正确的值,因此使用cc.getFrameSize()来获取初始的屏幕大小
let screen_size = cc.view.getFrameSize().width / cc.view.getFrameSize().height
let design_size = cc.Canvas.instance.designResolution.width / cc.Canvas.instance.designResolution.height
let f = screen_size >= design_size
cc.Canvas.instance.fitHeight = f
cc.Canvas.instance.fitWidth = !f
const frameSize = cc.view.getFrameSize();
this._frameSize = frameSize;
this._designSize = cc.view.getDesignResolutionSize();
let sx = cc.winSize.width / frameSize.width;
let sy = cc.winSize.height / frameSize.height;
this._cocosScale = Math.min(sx, sy);
sx = frameSize.width / this._designSize.width;
sy = frameSize.height / this._designSize.height;
this._mapScaleMin = Math.min(sx, sy) * this._cocosScale;
this._mapScaleMax = Math.max(sx, sy) * this._cocosScale;
cc.director['_scene'].width = frameSize.width;
cc.director['_scene'].height = frameSize.height;
}
data = null;
// 生命周期 start
start() {
if (window && (<any>window).courseware && (<any>window).courseware.getData) {
(<any>window).courseware.getData((data) => {
this.log('data:' + data);
this.data = data || this.getDefaultData();
this.data = JSON.parse(JSON.stringify(this.data));
this.preloadItem();
})
} else {
this.data = this.getDefaultData();
this.preloadItem();
}
}
getDefaultData() {
return defaultData;
}
preloadItem() {
this.addPreloadImage();
this.addPreloadAudio();
this.addPreloadAnima();
this.preload();
}
addPreloadImage() {
}
addPreloadAudio() {
}
addPreloadAnima() {
}
preload() {
const preloadArr = this._imageResList.concat(this._audioResList).concat(this._animaResList);
cc.assetManager.preloadAny(preloadArr, null, null, async (err, data) => {
if (window && window["air"]) {
// window["air"].onCourseInScreen = (next) => {
// window["air"].isCourseInScreen = true;
// this.onLoadEnd();
// next();
// };
await this.onLoadEnd();
window["air"].hideAirClassLoading();
} else {
await this.onLoadEnd();
}
cc.debug.setDisplayStats(false);
});
}
log (str) {
const node = cc.find('middleLayer');
if(node){
node.getComponent('middleLayer').log(str);
}else{
console.log(str);
}
}
async onLoadEnd() {
}
// ------------------------------------------------
getSprNode(resName) {
const sf = cc.find('Canvas/res/img/' + resName).getComponent(cc.Sprite).spriteFrame;
const node = new cc.Node();
node.addComponent(cc.Sprite).spriteFrame = sf;
return node;
}
getSpriteFrimeByUrl(url, cb) {
cc.loader.load({ url }, (err, img) => {
const spriteFrame = new cc.SpriteFrame(img)
if (cb) {
cb(spriteFrame);
}
})
}
getSprNodeByUrl(url, cb) {
const node = new cc.Node();
const spr = node.addComponent(cc.Sprite);
this.getSpriteFrimeByUrl(url, (sf) => {
spr.spriteFrame = sf;
if (cb) {
cb(node);
}
})
}
playAudioByUrl(audio_url, cb = null) {
if (audio_url) {
cc.assetManager.loadRemote(audio_url, (err, audioClip) => {
const audioId = cc.audioEngine.play(audioClip, false, 0.8);
if (cb) {
cc.audioEngine.setFinishCallback(audioId, () => {
cb();
});
}
});
}else{
cb && cb();
}
}
}
\ No newline at end of file
export const defaultData = {
"pic_url": "http://staging-teach.cdn.ireadabc.com/ed94332a503c31e0908bd4c6923a2665.png",
"pic_url_2": "http://staging-teach.cdn.ireadabc.com/5fb60317ade0195d35ad8034d5370a7f.png",
"text": "This is a test label.",
"audio_url": "http://staging-teach.cdn.ireadabc.com/f47f1d7b5c160fe1c59500d180346240.mp3"
}
\ No newline at end of file
{
"ver": "2.3.5",
"uuid": "18d07592-51a9-421e-8972-0f67b68d29e1",
"type": "sprite",
"wrapMode": "clamp",
"filterMode": "bilinear",
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"width": 144,
"height": 144,
"platformSettings": {},
"subMetas": {
"icon": {
"ver": "1.0.4",
"uuid": "6fbc30a8-3c49-44ae-8ba4-7f56f385b78a",
"rawTextureUuid": "18d07592-51a9-421e-8972-0f67b68d29e1",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": -0.5,
"trimX": 3,
"trimY": 2,
"width": 138,
"height": 141,
"rawWidth": 144,
"rawHeight": 144,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"subMetas": {}
}
}
}
\ No newline at end of file
{
"ver": "1.1.2",
"uuid": "8ae763a6-0f46-461c-af30-e4cb3ddb9ec1",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}
\ No newline at end of file
{
"ver": "1.1.0",
"uuid": "63b4e75f-857e-4577-9e2d-c86d4c05f53a",
"subMetas": {}
}
\ No newline at end of file
{
"ver": "1.0.1",
"uuid": "4251bacf-3f68-475f-b3b3-990fdbfc3991",
"subMetas": {}
}
\ No newline at end of file
{
"ver": "2.3.5",
"uuid": "9a79969a-0506-48d4-bc98-3c05d109b027",
"uuid": "60d9c614-a077-45c2-b078-eb1979cda77b",
"type": "sprite",
"wrapMode": "clamp",
"filterMode": "bilinear",
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"width": 61,
"height": 67,
"width": 68,
"height": 68,
"platformSettings": {},
"subMetas": {
"btn_left": {
"icon_back": {
"ver": "1.0.4",
"uuid": "ce19457d-e8f3-4c38-ae3e-d4b99208ddb5",
"rawTextureUuid": "9a79969a-0506-48d4-bc98-3c05d109b027",
"uuid": "b9b71493-4476-48a6-9440-a9e1c0c247ac",
"rawTextureUuid": "60d9c614-a077-45c2-b078-eb1979cda77b",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
......@@ -22,10 +22,10 @@
"offsetY": 0,
"trimX": 0,
"trimY": 0,
"width": 61,
"height": 67,
"rawWidth": 61,
"rawHeight": 67,
"width": 68,
"height": 68,
"rawWidth": 68,
"rawHeight": 68,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
......
{
"ver": "1.1.2",
"uuid": "3a7066b3-5a2a-4982-a364-47370eb0227b",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}
\ No newline at end of file
{
"ver": "1.1.2",
"uuid": "24910381-c329-4531-ad18-764b1cad9d6b",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}
\ No newline at end of file
This diff is collapsed.
{
"ver": "1.2.9",
"uuid": "782105f5-3081-436f-8651-71d5b076953a",
"asyncLoadAssets": false,
"autoReleaseAssets": false,
"subMetas": {}
}
\ No newline at end of file
// Learn TypeScript:
// - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
// Learn Attribute:
// - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
// - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html
const {ccclass, property} = cc._decorator;
@ccclass
export default class NewClass extends cc.Component {
// LIFE-CYCLE CALLBACKS:
// onLoad () {}
start () {
}
onRunGameCenter() {
cc.director.loadScene('middleLayer_for_jxw_demo');
}
// update (dt) {}
}
{
"ver": "1.0.8",
"uuid": "f8b451ff-857c-4ca8-9870-866bc5154a29",
"uuid": "3f255ebc-9ce5-4586-9131-8313973d7aae",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
......
{
"ver": "1.1.2",
"uuid": "07f21694-8cca-49b4-99a7-df4679af5e42",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}
\ No newline at end of file
# 游戏中心进度条功能说明
## 功能概述
为游戏中心页面添加了进度条功能,在调用`loadPageBundle`加载游戏资源时显示进度条,加载完成后自动隐藏。
## 主要特性
- 自动创建进度条UI组件
- 实时显示加载进度
- 支持通过属性面板自定义进度条样式
- 包含模拟进度功能作为备用方案
- 自动重写middleLayer组件的进度更新方法
## 使用方法
### 1. 自动创建进度条
进度条会在页面初始化时自动创建,无需手动配置。
### 2. 通过属性面板自定义
如果需要在编辑器中自定义进度条样式,可以在属性面板中设置以下属性:
- `progressBarContainer`: 进度条容器节点
- `progressBar`: 进度条组件
- `progressLabel`: 进度文本标签
### 3. 进度条显示时机
- 当用户点击游戏卡片时自动显示
-`loadPageBundle`调用期间保持显示
- 加载完成后自动隐藏
## 技术实现
### 进度条组件结构
```
progress_bar_container (容器)
├── bg_mask (背景遮罩)
├── loading_label (加载提示文本)
├── progress_bg (进度条背景)
├── progress_bar (进度条)
└── progress_label (进度百分比文本)
```
### 关键方法
- `showProgressBar()`: 显示进度条
- `hideProgressBar()`: 隐藏进度条
- `updateProgressBar(progress)`: 更新进度值
- `overrideProgressUpdate()`: 重写middleLayer的进度更新方法
- `startSimulatedProgress()`: 启动模拟进度更新
- `stopSimulatedProgress()`: 停止模拟进度更新
### 进度更新机制
1. **实际进度更新**: 通过重写middleLayer组件的`setLoadingProgressBar`方法
2. **模拟进度更新**: 作为备用方案,确保用户能看到进度变化
3. **自动隐藏**: 在`loadPageBundle`回调中自动隐藏进度条
## 样式配置
- 进度条容器尺寸: 400x120
- 进度条尺寸: 300x20
- 背景遮罩: 半透明黑色
- 进度条颜色: 蓝色
- 文本颜色: 白色
## 注意事项
1. 进度条会在页面初始化时自动创建
2. 模拟进度最多显示到90%,留10%给实际加载完成
3. 如果middleLayer组件没有正确调用进度更新,模拟进度会作为备用方案
4. 进度条会在加载完成后自动清理和隐藏
## 扩展功能
如需添加更多功能,可以考虑:
- 添加取消加载按钮
- 显示预计剩余时间
- 添加加载失败重试机制
- 自定义进度条动画效果
\ No newline at end of file
{
"ver": "2.0.0",
"uuid": "5952eb33-865c-4e39-b156-cd2f1c4ff5a0",
"subMetas": {}
}
\ No newline at end of file
# 游戏广场界面设置说明
## 概述
这个界面实现了一个游戏广场,显示8个游戏卡片的横滑列表,每个卡片包含游戏缩略图和标题。
## 节点结构
### 1. 主要节点层级
```
Canvas (1920x1080)
├── bg (背景 - 浅色背景)
├── back_btn (返回按钮 - 左上角)
├── header (标题栏)
│ └── title_label (游戏广场标题)
└── game_list_container (游戏列表容器)
└── scroll_view (滚动视图)
└── content (内容节点 - 包含所有游戏卡片)
```
### 2. 游戏卡片结构
```
game_card (300x400)
├── card_bg (卡片背景 - 白色圆角矩形)
├── game_thumbnail (游戏缩略图 - 260x280)
└── game_title (游戏标题 - 280x60)
```
## 在Cocos Creator中的设置步骤
### 步骤1: 创建主要节点
1. 在Canvas下创建以下节点:
- `bg` (Sprite) - 设置浅色背景
- `back_btn` (Button) - 返回按钮,已存在
- `header` (Node) - 标题栏容器
- `game_list_container` (Node) - 游戏列表容器
### 步骤2: 设置标题栏
1.`header`节点下创建:
- `title_label` (Label) - 设置文本为"游戏广场"
- 字体大小:32,颜色:黑色
- 位置:居中显示
### 步骤3: 设置滚动视图
1.`game_list_container`下创建:
- `scroll_view` (ScrollView组件)
- 设置ScrollView属性:
- Content: 创建content子节点
- Horizontal: true (允许水平滚动)
- Vertical: false (禁用垂直滚动)
- Elastic Top/Bottom: 0
- Elastic Left/Right: 0.1
### 步骤4: 设置内容节点
1.`scroll_view`下创建`content`节点
2. 设置content节点属性:
- Anchor Point: (0, 0.5)
- Position: (0, 0)
### 步骤5: 创建游戏卡片预制体(推荐)
1. 创建新的预制体文件:`game-card.prefab`
2. 在预制体中创建卡片结构:
- 根节点:300x400
- `card_bg`: 白色背景,300x400
- `game_thumbnail`: 缩略图容器,260x280,位置(0, 60)
- `game_title`: 标题标签,280x60,位置(0, -160)
3. 添加`GameCard`组件到根节点
4. 在组件中绑定对应的属性引用
### 步骤6: 配置脚本组件
1. 在Canvas节点上添加`GameCenter`脚本组件
2. 在脚本组件中设置属性:
- `gameListContainer`: 拖拽`game_list_container`节点
- `gameCardPrefab`: 拖拽`game-card.prefab`预制体
- `scrollView`: 拖拽`scroll_view`节点
## 样式设置
### 颜色方案
- 背景色:浅色 (#F8F6EF)
- 卡片背景:白色 (#FFFFFF)
- 标题文字:黑色 (#000000)
### 尺寸规格
- 卡片尺寸:300x400
- 卡片间距:30px
- 缩略图尺寸:260x280
- 标题区域:280x60
### 字体设置
- 标题字体:24px
- 行高:30px
- 对齐方式:居中对齐
## 功能特性
1. **自动加载游戏数据**:从API接口获取游戏列表
2. **动态创建卡片**:根据数据自动生成游戏卡片
3. **横滑滚动**:支持触摸滑动浏览所有游戏
4. **点击交互**:每个卡片都可以点击,触发相应事件
5. **响应式布局**:自动计算内容宽度,适配不同数量的游戏
## 注意事项
1. 确保网络接口正常工作,能够获取游戏数据
2. 游戏封面图片需要能够正常加载
3. 如果使用预制体,确保路径和引用正确
4. 滚动视图的content节点大小会根据游戏数量自动调整
5. 建议在真机上测试触摸滑动效果
## 扩展功能
1. **搜索功能**:可以添加搜索框过滤游戏
2. **分类功能**:按游戏类型分组显示
3. **收藏功能**:允许用户收藏喜欢的游戏
4. **最近游戏**:显示最近玩过的游戏
5. **游戏统计**:显示游戏完成度等信息
\ No newline at end of file
{
"ver": "2.0.0",
"uuid": "64657144-bd5a-48bd-ac6c-01f325f27087",
"subMetas": {}
}
\ No newline at end of file
{
"ver": "1.1.2",
"uuid": "312e0526-ac20-4b83-af6d-4e6be1ace098",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}
\ No newline at end of file
{
"ver": "2.3.5",
"uuid": "efa5fa09-a4dd-4bfc-ab7e-17c19f85408f",
"uuid": "53ca5daa-151f-4628-a00b-417e40e4b2dd",
"type": "sprite",
"wrapMode": "clamp",
"filterMode": "bilinear",
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"width": 366,
"height": 336,
"width": 360,
"height": 259,
"platformSettings": {},
"subMetas": {
"1orange": {
"bg_card": {
"ver": "1.0.4",
"uuid": "43d1e79d-6de8-4dcb-b8ce-d767df7913aa",
"rawTextureUuid": "efa5fa09-a4dd-4bfc-ab7e-17c19f85408f",
"uuid": "64a97fa2-f168-44f9-980f-080c929f6408",
"rawTextureUuid": "53ca5daa-151f-4628-a00b-417e40e4b2dd",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": -0.5,
"offsetY": 0,
"trimX": 0,
"trimY": 1,
"width": 366,
"height": 335,
"rawWidth": 366,
"rawHeight": 336,
"trimY": 0,
"width": 360,
"height": 259,
"rawWidth": 360,
"rawHeight": 259,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
......
{
"ver": "2.3.5",
"uuid": "d582359e-924e-4ee9-9964-1fc4bb417e71",
"uuid": "66a73419-c675-4d36-ab5d-a66348917e83",
"type": "sprite",
"wrapMode": "clamp",
"filterMode": "bilinear",
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"width": 61,
"height": 67,
"width": 68,
"height": 68,
"platformSettings": {},
"subMetas": {
"btn_right": {
"icon_back": {
"ver": "1.0.4",
"uuid": "e5a2dbaa-a677-4a32-90d7-a1b057d7fb59",
"rawTextureUuid": "d582359e-924e-4ee9-9964-1fc4bb417e71",
"uuid": "c45ab752-4f74-431a-addb-8f82a877e9d4",
"rawTextureUuid": "66a73419-c675-4d36-ab5d-a66348917e83",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": -0.5,
"offsetY": 0.5,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 0,
"width": 60,
"height": 66,
"rawWidth": 61,
"rawHeight": 67,
"width": 68,
"height": 68,
"rawWidth": 68,
"rawHeight": 68,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
......
const {ccclass, property} = cc._decorator;
interface GameCardData {
id: number;
uuid: string;
template_name: string;
template_description: string;
cover: string;
cw_cover: string;
data: string;
seq: number;
}
@ccclass
export default class GameCard extends cc.Component {
@property(cc.Sprite)
thumbnailSprite: cc.Sprite = null;
@property(cc.Label)
titleLabel: cc.Label = null;
@property(cc.Node)
cardBg: cc.Node = null;
private gameData: GameCardData = null;
onLoad() {
// 添加点击事件
this.node.on('click', this.onCardClick, this);
}
public init(data: GameCardData) {
this.gameData = data;
this.updateDisplay();
}
private updateDisplay() {
if (!this.gameData) return;
// 设置标题
if (this.titleLabel) {
this.titleLabel.string = this.gameData.template_description || '未知游戏';
}
// 加载并设置缩略图
if (this.thumbnailSprite && (this.gameData.cover || this.gameData.cw_cover)) {
const cv = this.gameData.cw_cover ? this.gameData.cw_cover : this.gameData.cover;
cc.loader.load(cv, (err, texture) => {
if (!err && texture) {
const spriteFrame = new cc.SpriteFrame(texture);
this.thumbnailSprite.spriteFrame = spriteFrame;
}
});
}
}
private onCardClick() {
if (this.gameData) {
console.log('点击游戏卡片:', this.gameData.template_description);
// 派发事件通知父节点
this.node.emit('onGameCardClick', this.gameData);
}
}
onDestroy() {
this.node.off('click', this.onCardClick, this);
}
}
\ No newline at end of file
{
"ver": "1.0.8",
"uuid": "c41b0e51-55d7-443c-af3a-b22c3dd9b9e5",
"uuid": "9ba24e00-4042-4aa2-b4b8-4bff0f316fbe",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
......
{
"ver": "1.2.9",
"uuid": "0737ce42-24f0-45c6-8e1a-8bdab4f74ba3",
"uuid": "867a2d96-17d5-47c7-96e9-5c29231a4af6",
"asyncLoadAssets": false,
"autoReleaseAssets": true,
"subMetas": {}
......
{
"ver": "1.0.8",
"uuid": "408a67f8-65fa-4cf1-8cf2-83e20e1a0fd5",
"uuid": "ee841466-ef92-49ad-84e7-c91048b6a896",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
......
{
"ver": "1.1.2",
"uuid": "bc2d8d9a-fe65-4d6b-b632-16fdb7292499",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}
\ No newline at end of file
[
{
"__type__": "cc.Prefab",
"_name": "",
"_objFlags": 0,
"_native": "",
"data": {
"__id__": 1
},
"optimizationPolicy": 0,
"asyncLoadAssets": false,
"readonly": false
},
{
"__type__": "cc.Node",
"_name": "game-card",
"_objFlags": 0,
"_parent": null,
"_children": [
{
"__id__": 2
},
{
"__id__": 5
},
{
"__id__": 8
}
],
"_active": true,
"_components": [
{
"__id__": 11
},
{
"__id__": 12
}
],
"_prefab": {
"__id__": 13
},
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 410,
"height": 259
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
0,
0,
0,
0,
0,
0,
1,
1,
1,
1
]
},
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
},
{
"__type__": "cc.Node",
"_name": " card_bg",
"_objFlags": 0,
"_parent": {
"__id__": 1
},
"_children": [],
"_active": false,
"_components": [
{
"__id__": 3
}
],
"_prefab": {
"__id__": 4
},
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 360,
"height": 259
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
0,
0,
0,
0,
0,
0,
1,
1,
1,
1
]
},
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 2
},
"_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": {
"__uuid__": "64a97fa2-f168-44f9-980f-080c929f6408"
},
"_type": 0,
"_sizeMode": 0,
"_fillType": 0,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_atlas": null,
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__uuid__": "3e0857f7-c988-4162-90e4-5e6c1887c3d6"
},
"fileId": "85oivK5FhAvZPML5eAXr4v",
"sync": false
},
{
"__type__": "cc.Node",
"_name": "game_thumbnail",
"_objFlags": 0,
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 6
}
],
"_prefab": {
"__id__": 7
},
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 410,
"height": 269
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
0,
21.754,
0,
0,
0,
0,
1,
1,
1,
1
]
},
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 5
},
"_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": null,
"_type": 1,
"_sizeMode": 0,
"_fillType": 0,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_atlas": null,
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__uuid__": "3e0857f7-c988-4162-90e4-5e6c1887c3d6"
},
"fileId": "e9n/ZFueBHlJMia+chDdd0",
"sync": false
},
{
"__type__": "cc.Node",
"_name": "game_title",
"_objFlags": 0,
"_parent": {
"__id__": 1
},
"_children": [],
"_active": false,
"_components": [
{
"__id__": 9
}
],
"_prefab": {
"__id__": 10
},
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 0,
"g": 0,
"b": 0,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 325,
"height": 40.32
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
-1.089,
-103.039,
0,
0,
0,
0,
1,
1,
1,
1
]
},
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
},
{
"__type__": "cc.Label",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 8
},
"_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_string": "",
"_N$string": "",
"_fontSize": 22,
"_lineHeight": 22,
"_enableWrapText": true,
"_N$file": null,
"_isSystemFontUsed": true,
"_spacingX": 0,
"_batchAsBitmap": false,
"_styleFlags": 0,
"_underlineHeight": 0,
"_N$horizontalAlign": 0,
"_N$verticalAlign": 0,
"_N$fontFamily": "Arial",
"_N$overflow": 1,
"_N$cacheMode": 0,
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__uuid__": "3e0857f7-c988-4162-90e4-5e6c1887c3d6"
},
"fileId": "baz8Zjv3ZPzbAiy2HWukQu",
"sync": false
},
{
"__type__": "9ba244AQEJKorS4S/8PMW++",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"thumbnailSprite": {
"__id__": 6
},
"titleLabel": {
"__id__": 9
},
"cardBg": {
"__id__": 2
},
"_id": ""
},
{
"__type__": "cc.Button",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"_normalMaterial": null,
"_grayMaterial": null,
"duration": 0.1,
"zoomScale": 1.2,
"clickEvents": [],
"_N$interactable": true,
"_N$enableAutoGrayEffect": false,
"_N$transition": 0,
"transition": 0,
"_N$normalColor": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_N$pressedColor": {
"__type__": "cc.Color",
"r": 211,
"g": 211,
"b": 211,
"a": 255
},
"pressedColor": {
"__type__": "cc.Color",
"r": 211,
"g": 211,
"b": 211,
"a": 255
},
"_N$hoverColor": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"hoverColor": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_N$disabledColor": {
"__type__": "cc.Color",
"r": 124,
"g": 124,
"b": 124,
"a": 255
},
"_N$normalSprite": null,
"_N$pressedSprite": null,
"pressedSprite": null,
"_N$hoverSprite": null,
"hoverSprite": null,
"_N$disabledSprite": null,
"_N$target": {
"__id__": 1
},
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__uuid__": "3e0857f7-c988-4162-90e4-5e6c1887c3d6"
},
"fileId": "",
"sync": false
}
]
\ No newline at end of file
{
"ver": "1.2.9",
"uuid": "3e0857f7-c988-4162-90e4-5e6c1887c3d6",
"optimizationPolicy": "AUTO",
"asyncLoadAssets": false,
"readonly": false,
"subMetas": {}
}
\ No newline at end of file
{
"ver": "1.2.9",
"uuid": "f0dfe8f4-e6c5-43c7-a94e-70cbf68bf300",
"asyncLoadAssets": false,
"autoReleaseAssets": true,
"subMetas": {}
}
\ No newline at end of file
// Learn TypeScript:
// - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
// Learn Attribute:
// - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
// - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html
const {ccclass, property} = cc._decorator;
@ccclass
export default class NewClass extends cc.Component {
// LIFE-CYCLE CALLBACKS:
// onLoad () {}
start () {
}
// update (dt) {}
}
{
"ver": "1.0.8",
"uuid": "9d11d90b-6323-43f3-833d-7c491761e70e",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}
\ No newline at end of file
cc.Class({
extends: cc.Component,
onDestroy() {
console.log('喵喵喵: destroyer onDestroy');
middleLayer.clearDragonDisplayAssetList();
}
});
{
"ver": "1.0.8",
"uuid": "9beec52f-4474-4135-b3f5-269e7020a53e",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}
\ No newline at end of file
This diff is collapsed.
{
"ver": "1.0.8",
"uuid": "28112492-beae-4e6a-a0f4-e7b31a14f575",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}
\ No newline at end of file
This diff is collapsed.
{
"ver": "1.0.8",
"uuid": "c7a121a7-92a9-440e-a7e9-d4f5141e3f45",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}
\ No newline at end of file
......@@ -177,85 +177,15 @@ export function playAudio(audioClip, cb = null) {
export async function asyncDelay(time) {
return new Promise((resolve, reject) => {
try {
cc.tween(cc.find('Canvas'))
.delay(time)
.call(()=>{
resolve(null);
})
.start();
setTimeout(() => {
resolve(null);
}, time * 1000);
} catch (e) {
reject(e);
}
})
}
export async function asyncLoadDragonBoneAnime(node, { skeJsonData: { url: skeJsonDataUrl }, texJsonData: { url: texJsonDataUrl }, texPngData: { url: texPngDataUrl } }) {
if (!texPngDataUrl || !texJsonDataUrl || !texPngDataUrl
|| texPngDataUrl == '' || texJsonDataUrl == '' || texPngDataUrl == '') {
return;
}
return new Promise((resolve, reject) => {
if (node.animaNode) {
node.animaNode.removeFromParent();
}
const animaNode = new cc.Node();
animaNode.name = 'animaNode';
animaNode.parent = node;
animaNode.active = true;
node.animaNode = animaNode;
const dragonDisplay = animaNode.addComponent(dragonBones.ArmatureDisplay);
const loadTexture = new Promise((resolve, reject) => {
cc.assetManager.loadRemote(texPngDataUrl, (error, texture) => {
if (error) {
reject(error);
}
resolve(texture);
});
});
const loadTexJsonData = new Promise((resolve, reject) => {
cc.assetManager.loadAny({ url: texJsonDataUrl }, (error, atlasJson) => {
if (error) {
reject(error);
}
resolve(atlasJson);
});
});
const loadSkeJsonData = new Promise((resolve, reject) => {
cc.assetManager.loadAny({ url: skeJsonDataUrl }, (error, dragonBonesJson) => {
if (error) {
reject(error);
}
resolve(dragonBonesJson);
});
});
Promise.all([loadTexture, loadTexJsonData, loadSkeJsonData]).then(([texture, atlasJson, dragonBonesJson]) => {
const atlas = new dragonBones.DragonBonesAtlasAsset();
atlas.atlasJson = JSON.stringify(atlasJson);
atlas.texture = texture;
const asset = new dragonBones.DragonBonesAsset();
asset.dragonBonesJson = JSON.stringify(dragonBonesJson);
dragonDisplay.dragonAtlasAsset = atlas;
dragonDisplay.dragonAsset = asset;
let armatureNames = dragonBonesJson.armature.map(data => data.name);
if (armatureNames.length > 0) {
dragonDisplay.armatureName = armatureNames[0];
}
resolve(animaNode);
});
});
}
export class FireworkSettings {
baseNode; // 父节点
nodeList; // 火花节点的array
......@@ -411,65 +341,14 @@ export function showTrebleFirework(baseNode, rabbonList) {
showFireworks(right);
}
export function httpHeadCall(requsetUrl: string, callback) {
let xhr = new XMLHttpRequest();
console.log("Status: Send Post Request to " + requsetUrl);
try {
xhr.onreadystatechange = () => {
try {
console.log('xhr.readyState: ', xhr.readyState);
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status < 400)) {
callback(true);
} else {
callback(false);
}
}
} catch (e) {
console.log(e)
}
};
xhr.open("HEAD", requsetUrl, true);
xhr.send();
xhr.timeout = 15000;
xhr.onerror = (e) => {
callback(false);
};
xhr.ontimeout = (e) => {
callback(false);
};
} catch (e) {
console.log("Send Get Request error: ", e);
}
}
export function onHomeworkFinish(data = "", callback = ()=>{}) {
const middleLayer = cc.find('middleLayer');
if (middleLayer) {
const middleLayerComponent = middleLayer.getComponent('middleLayer');
middleLayerComponent.onHomeworkFinish(callback, data);
} else {
console.log('onHomeworkFinish', JSON.stringify(data));
}
}
export function callMiddleLayerFunction(apiName: string, data: any, callback: Function) {
export function onHomeworkFinish() {
const middleLayer = cc.find('middleLayer');
if (middleLayer) {
const middleLayerComponent = middleLayer.getComponent('middleLayer');
middleLayerComponent.callMiddleLayerFunction(apiName, data, callback);
} else {
console.log('callMiddleLayerFunction: ' + apiName);
}
}
export function showTips(tips) {
const middleLayer = cc.find('middleLayer');
if (middleLayer) {
middleLayer.getComponent('middleLayer').showTips(tips);
if (middleLayerComponent.role == 'student') {
middleLayerComponent.onHomeworkFinish(() => { });
}
} else {
console.log(tips);
console.log('onHomeworkFinish');
}
}
}
\ No newline at end of file
{
"ver": "2.3.5",
"uuid": "e1b4d971-9876-4832-803a-5a321964a78b",
"uuid": "89e1cbbf-a096-4d31-b3a2-a5c84009d26b",
"type": "sprite",
"wrapMode": "clamp",
"filterMode": "bilinear",
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"width": 1280,
"height": 720,
"width": 416,
"height": 131,
"platformSettings": {},
"subMetas": {
"bg": {
"ver": "1.0.4",
"uuid": "8288e3d4-4c75-4b27-8f01-f7014417f4dd",
"rawTextureUuid": "e1b4d971-9876-4832-803a-5a321964a78b",
"uuid": "126a1b5a-3af8-498b-8d56-6afefeea3cb2",
"rawTextureUuid": "89e1cbbf-a096-4d31-b3a2-a5c84009d26b",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
......@@ -22,10 +22,10 @@
"offsetY": 0,
"trimX": 0,
"trimY": 0,
"width": 1280,
"height": 720,
"rawWidth": 1280,
"rawHeight": 720,
"width": 416,
"height": 131,
"rawWidth": 416,
"rawHeight": 131,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment