Przeglądaj źródła

Merge branch 'master' of http://git.mokasz.com/zouyong/mk_framework

# Conflicts:
#	mk_framework/assets/script/mk/system/MKSystem.ts
zouyong 5 lat temu
rodzic
commit
7ad00a454b
25 zmienionych plików z 1614 dodań i 60 usunięć
  1. 0 49
      mk_framework/assets/script/game/component/OpenWindow.ts
  2. 88 0
      mk_framework/assets/script/game/component/PageView.ts
  3. 1 1
      mk_framework/assets/script/game/component/PageView.ts.meta
  4. 136 0
      mk_framework/assets/script/game/component/SetGray.ts
  5. 9 0
      mk_framework/assets/script/game/component/SetGray.ts.meta
  6. 93 0
      mk_framework/assets/script/game/component/TabSwitching.ts
  7. 9 0
      mk_framework/assets/script/game/component/TabSwitching.ts.meta
  8. 497 0
      mk_framework/assets/script/game/component/TableView.ts
  9. 9 0
      mk_framework/assets/script/game/component/TableView.ts.meta
  10. 12 0
      mk_framework/assets/script/game/component/tween.meta
  11. 156 0
      mk_framework/assets/script/game/component/tween/FlyNode.ts
  12. 9 0
      mk_framework/assets/script/game/component/tween/FlyNode.ts.meta
  13. 45 0
      mk_framework/assets/script/game/component/tween/TweenEasing.ts
  14. 9 0
      mk_framework/assets/script/game/component/tween/TweenEasing.ts.meta
  15. 133 0
      mk_framework/assets/script/game/component/tween/UIOpenAndClose.ts
  16. 9 0
      mk_framework/assets/script/game/component/tween/UIOpenAndClose.ts.meta
  17. 153 0
      mk_framework/assets/script/game/component/tween/UITween.ts
  18. 9 0
      mk_framework/assets/script/game/component/tween/UITween.ts.meta
  19. 28 10
      mk_framework/assets/script/mk/system/MKSystem.ts
  20. 105 0
      mk_framework/assets/script/mk/system/UISystem.ts
  21. 9 0
      mk_framework/assets/script/mk/system/UISystem.ts.meta
  22. 51 0
      mk_framework/assets/script/mk/utils/GameUtil.ts
  23. 9 0
      mk_framework/assets/script/mk/utils/GameUtil.ts.meta
  24. 26 0
      mk_framework/assets/script/mk/utils/StorageUtil.ts
  25. 9 0
      mk_framework/assets/script/mk/utils/StorageUtil.ts.meta

+ 0 - 49
mk_framework/assets/script/game/component/OpenWindow.ts

@@ -1,49 +0,0 @@
-/**
- * 窗口打开模式
- */
-enum WindowOpenMode {
-    /**
-     * 对当前打开的窗口不作处理并添加新的窗口
-     */
-    NotCloseAndAdd,
-    /**
-     * 如果新的窗口和当前打开的窗口路径一致则传递参数且不打开,否则为NotCloseAndAdd模式
-     */
-    NotCloseAndCover,
-    /**
-     * 关闭当前打开的窗口并添加新的窗口
-     */
-    CloseAndAdd,
-    /**
-     * 如果新的窗口和当前打开的窗口路径一致则传递参数且不打开,否则为CloseAndCover模式
-     */
-    CloseAndCover
-}
-
-const { ccclass, property } = cc._decorator;
-/**
- * 打开窗口组件,定义窗口的参数、窗口的打开等
- * @author 薛鸿潇
- */
-@ccclass
-export default class OpenWindow extends cc.Component {
-
-    @property({ tooltip: "要加载的预制体对象相对于resources的路径" })
-    public prefabPath: string = '';
-    @property({ tooltip: "窗口打开的模式", type: cc.Enum(WindowOpenMode) })
-    public openMode: WindowOpenMode = WindowOpenMode.NotCloseAndAdd;
-    @property({ tooltip: "自定义参数" })
-    public params: string[] = [];
-    @property({ tooltip: "窗口打开触发的节点,不填则无触发", type: [cc.Node] })
-    public openFroms: cc.Node[] = [];
-    onLoad() {
-
-    }
-
-    start() {
-
-    }
-    private async open() {
-
-    }
-}

+ 88 - 0
mk_framework/assets/script/game/component/PageView.ts

@@ -0,0 +1,88 @@
+
+const { ccclass, property } = cc._decorator;
+/**
+ * 翻页组件类
+ * - 简单版 无动态加载功能
+ * - 已知bug,请注意规避:开启回弹后,首尾界面回弹没有考虑 setCurrentPageIndex 导致在setCurrentPageIndex设置之后的位置开始回弹。解决方法:关闭回弹
+ * @author 薛鸿潇
+ */
+@ccclass
+export default class PageView extends cc.Component {
+
+    /** 翻页组件 */
+    private comp_page_view: cc.PageView = null;
+    /** item 容器 */
+    private arr_node_item: Array<cc.Node> = [];
+    onLoad() {
+        this.comp_page_view = this.node.getComponent(cc.PageView);
+        this.node.on('ui-init', this.init, this);// 初始化列表
+        this.node.on('ui-clearItem', this.clearItem, this);// 清除页面
+        this.node.on('ui-backCurPage', this.backCurPage, this);// 返回到当前Index对应的界面【滑动后禁用滑动功能,再打开滑动功能,翻页组件不会自动返回,调用此接口】
+    }
+
+    start() {
+
+    }
+
+    /**
+     * 初始化列表
+     * @param list_data 数据列表
+     * @param page_item item预制体
+     */
+    private init(list_data: Array<any>, page_item: cc.Prefab, init_index: number = 0) {
+        const data_count = list_data.length;
+        if (!data_count) {
+            // 刷新时,数据列表是空的
+            const node_count = this.arr_node_item.length;
+            for (let i = 0; i < node_count; i++) {
+                this.comp_page_view.removePageAtIndex(i);
+                this.arr_node_item.splice(i, 1);
+            }
+            return;
+        }
+        for (let i = 0; i < data_count; i++) {
+            let node_item = this.arr_node_item[i];
+            if (!node_item) {
+                node_item = cc.instantiate(page_item);
+                this.arr_node_item.push(node_item);
+            }
+            // node_item.parent = this.content;
+            this.comp_page_view.addPage(node_item);
+            node_item.getComponent(node_item.name).setItemData(list_data[i]);
+        }
+        this.comp_page_view.setCurrentPageIndex(init_index);
+        // 清理多出来的item
+        const node_count = this.arr_node_item.length;
+        if (data_count > node_count) {
+            for (let i = data_count; i < node_count; i++) {
+                this.comp_page_view.removePageAtIndex(i);
+                this.arr_node_item.splice(i, 1);
+            }
+        }
+    }
+
+    /**
+     * 返回当前页
+     */
+    private backCurPage() {
+        let index = this.comp_page_view.getCurrentPageIndex();
+        this.comp_page_view.setCurrentPageIndex(index);
+    }
+    
+    /** 清理子节点 
+     * - need_destroy 销毁
+    */
+    private clearItem(need_destroy: boolean = false) {
+        // this.comp_page_view.removeAllPages();
+        // const n_count = this.arr_node_item.length;
+        // for (let i = 0; i < n_count; i++) {
+        //     if (need_destroy) {
+        //         let node_end = this.arr_node_item.pop();
+        //         node_end.destroy();
+        //     } else {
+        //         this.arr_node_item[i].removeFromParent();
+        //     }
+        // }
+    }
+    // update (dt) {}
+}

+ 1 - 1
mk_framework/assets/script/game/component/OpenWindow.ts.meta → mk_framework/assets/script/game/component/PageView.ts.meta

@@ -1,6 +1,6 @@
 {
   "ver": "1.0.8",
-  "uuid": "7d3b9a5b-f60e-4981-aec4-dcf0abc9bc65",
+  "uuid": "bf07ca26-2764-4a4c-8abe-9ee317678fe6",
   "isPlugin": false,
   "loadPluginInWeb": true,
   "loadPluginInNative": true,

+ 136 - 0
mk_framework/assets/script/game/component/SetGray.ts

@@ -0,0 +1,136 @@
+/**
+ * 节点置灰组件
+ * @date 20210514
+ * @author kaka
+ * @description 暂时不包括spine动画
+ */
+
+const { ccclass, property } = cc._decorator;
+
+@ccclass
+export default class SetGray extends cc.Component {
+    @property(cc.Material)
+    private normal: cc.Material = null;   //内置正常材质
+
+    @property(cc.Material)
+    private gray: cc.Material = null;   //内置灰色材质
+
+    @property({ type: false, displayName: "是否置灰" })
+    public grayState: boolean = false;   //默认置灰状态
+
+    //上次置灰状态
+    private lastState = false;
+    private spArr = null;
+    private btnArr = null;
+    private labArr = null;
+    private labArrC = [];
+    private outLineArr = null;
+    private outLineArrC = [];
+    private labRichArr = null;
+    private labRichArrC = [];
+    private grayColor = new cc.Color(166, 166, 166, 255);
+    private grayOutLineColor = new cc.Color(230, 230, 230, 255);
+
+    private skeArr = null;
+
+    onLoad() {
+        this.spArr = this.node.getComponentsInChildren(cc.Sprite);
+        this.btnArr = this.node.getComponentsInChildren(cc.Button);
+        this.labArr = this.node.getComponentsInChildren(cc.Label);
+        this.outLineArr = this.node.getComponentsInChildren(cc.LabelOutline);
+        this.labRichArr = this.node.getComponentsInChildren(cc.RichText);
+        this.skeArr = this.node.getComponentsInChildren(sp.Skeleton);
+
+        this.setGray(this.grayState);
+    }
+
+    /**
+     * 设置颜色
+     * @param isGray true 置灰 false 还原正常 
+     */
+    setGray(isGray: boolean) {
+        if (this.lastState == isGray) {
+            console.log('和上次设置相同')
+            return
+        }
+        this.lastState = isGray;
+        //置灰
+        if (isGray) {
+            //内建材质
+            let len = this.spArr.length;
+            for (var i = 0; i < len; i++) {
+                this.spArr[i].setMaterial(0, this.gray);
+            }
+
+            let btnLen = this.btnArr.length;
+            for (var n = 0; n < btnLen; n++) {
+                (this.btnArr[n] as cc.Button).enableAutoGrayEffect = true;
+                (this.btnArr[n] as cc.Button).grayMaterial = this.gray;
+                (this.btnArr[n] as cc.Button).interactable = false;
+            }
+
+            //设置所有文本颜色
+            let labLen = this.labArr.length;
+            for (var j = 0; j < labLen; j++) {
+                this.labArrC[j] = this.labArr[j].node.color;
+                this.labArr[j].node.color = this.grayColor;
+            }
+
+            //设置所有描边颜色
+            let outLineLen = this.outLineArr.length;
+            for (var k = 0; k < outLineLen; k++) {
+                this.outLineArrC[k] = this.outLineArr[k].color;
+                this.outLineArr[k].color = this.grayOutLineColor;
+            }
+
+            //设置所有富文本颜色
+            let labRichLen = this.labRichArr.length;
+            for (var m = 0; m < labRichLen; m++) {
+                this.labRichArrC[m] = this.labRichArr[m].node.color;
+                this.labRichArr[m].node.color = this.grayColor;
+            }
+
+            // let skeLen = this.skeArr.length;
+            // for (var p = 0; p < skeLen; p++) {
+            //     this.skeArr[p].setMaterial(0, this.gray);
+            //     (this.skeArr[p] as any).markForRender(true);
+            // }
+        }
+        else {
+            //内建材质
+            let len = this.spArr.length;
+            for (var i = 0; i < len; i++) {
+                this.spArr[i].setMaterial(0, this.normal);
+            }
+
+            let btnLen = this.btnArr.length;
+            for (var n = 0; n < btnLen; n++) {
+                (this.btnArr[n] as cc.Button).interactable = true;
+            }
+
+            //设置所有文本颜色
+            let labLen = this.labArr.length;
+            for (var j = 0; j < labLen; j++) {
+                this.labArr[j].node.color = this.labArrC[j];
+            }
+
+            //设置所有描边颜色
+            let outLineLen = this.outLineArr.length;
+            for (var k = 0; k < outLineLen; k++) {
+                this.outLineArr[k].color = this.outLineArrC[k];
+            }
+
+            //设置所有富文本颜色
+            let labRichLen = this.labRichArr.length;
+            for (var m = 0; m < labRichLen; m++) {
+                this.labRichArr[m].node.color = this.labRichArrC[m];
+            }
+
+            // let skeLen = this.skeArr.length;
+            // for (var p = 0; p < skeLen; p++) {
+            //     this.skeArr[p].setMaterial(0, this.normal);
+            //     (this.skeArr[p] as any).markForRender(true);
+            // }
+        }
+    }
+}

+ 9 - 0
mk_framework/assets/script/game/component/SetGray.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.0.8",
+  "uuid": "f67a9484-3e50-4bf2-b1c7-a555fa835656",
+  "isPlugin": false,
+  "loadPluginInWeb": true,
+  "loadPluginInNative": true,
+  "loadPluginInEditor": false,
+  "subMetas": {}
+}

+ 93 - 0
mk_framework/assets/script/game/component/TabSwitching.ts

@@ -0,0 +1,93 @@
+
+const { ccclass, property } = cc._decorator;
+
+@ccclass
+/** 页签切换组件 
+ * - 只对样式进行处理
+ * - 可注册其他回调,通过'comp-cur-click'事件
+ * - 可初始化页签,通过'comp-cur-tab'事件
+ * @author 薛鸿潇
+*/
+export default class TabSwitching extends cc.Component {
+    /** 页签组 */
+    @property({ type: cc.Button, displayName: '页签组', tooltip: '按钮target需要有值' })
+    private arr_btn_tab: cc.Button[] = [];
+    /** 页签数量 */
+    private tab_count = 0;
+    /** 界面点击页签的回调 */
+    private func = null;
+    onLoad() {
+        this.tab_count = this.arr_btn_tab.length;
+        this.initTabState();
+        this.initBtnEvent();
+        /** 页签切换 */
+        this.node.on('comp-cur-tab', this.curTabType, this);
+        // 注册界面触摸回调。参数1:函数,参数2:target
+        this.node.on('comp-cur-click', this.onTabBtnClick, this);
+
+    }
+
+    start() {
+    }
+
+    /**
+     * 初始化按钮事件
+     */
+    private initBtnEvent() {
+        for (let i = 0; i < this.tab_count; i++) {
+            this.arr_btn_tab[i].node.on('click', this.onClockTabCall, this);
+        }
+    }
+
+    /**
+     * 页签切换回调
+     * @param comp_btn 按钮组件
+     * @param params 参数
+     */
+    private onClockTabCall(comp_btn, params?) {
+        this.initTabState();
+
+        let btn_node = comp_btn.node;
+        let img_style_1 = btn_node.getChildByName('img_style_1');
+        img_style_1.active = true;
+
+        let img_style_2 = btn_node.getChildByName('img_style_2');
+        img_style_2.active = false;
+        this.func && this.func(comp_btn, params);
+    }
+
+    /**
+     * ui界面注册的按钮事件
+     * @param func 事件
+     * @param target 目标类
+     */
+    private onTabBtnClick(func: Function, target) {
+        this.func = func.bind(target);
+    }
+
+    /**
+     * 初始化页签状态
+     */
+    private initTabState() {
+        for (let i = 0; i < this.tab_count; i++) {
+            let img_style_1 = this.arr_btn_tab[i].node.getChildByName('img_style_1');
+            img_style_1.active = false;
+            let img_style_2 = this.arr_btn_tab[i].node.getChildByName('img_style_2');
+            img_style_2.active = true;
+        }
+    }
+    
+    /**
+     * 切换到指定页签
+     * @param tab 页签下标
+     * @returns 
+     */
+    private curTabType(tab: number) {
+        for (let i = 0; i < this.tab_count; i++) {
+            if (i === tab) {
+                this.onClockTabCall(this.arr_btn_tab[i], i);
+                return;
+            }
+        }
+    }
+}

+ 9 - 0
mk_framework/assets/script/game/component/TabSwitching.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.0.8",
+  "uuid": "3087d1f9-8168-427d-9364-b2a0330bec26",
+  "isPlugin": false,
+  "loadPluginInWeb": true,
+  "loadPluginInNative": true,
+  "loadPluginInEditor": false,
+  "subMetas": {}
+}

+ 497 - 0
mk_framework/assets/script/game/component/TableView.ts

@@ -0,0 +1,497 @@
+
+const { ccclass, property } = cc._decorator;
+
+/** 动态加载的滚动列表
+ * - 滑动列表动态加载
+ * - 支持多种类型预制体混合滚动 
+ * - item脚本需要有函数 setItemData 用于接收数据
+ * - 多个prefab混合时,要为每条item指定 pfbType
+ * - item、content锚点y需要为1其他为0.5
+ * @author 薛鸿潇
+*/
+@ccclass
+export default class TableView extends cc.Component {
+
+    @property({ type: [cc.Prefab] })
+    private pre_item: cc.Prefab[] = [];
+    /** 间距 */
+    @property({ displayName: '间距' })
+    private itemInterval: number = 0;
+
+    /** 数据 */
+    private itemData: any = null;
+    /** 滚动列表组件 */
+    private scrollView: cc.ScrollView = null;
+    /** item预制体组 */
+    private item: Array<any> = null;
+    /** 滑动列表的内容节点 */
+    private content: any = null;
+    /** 列表高 */
+    private layerHeight: any = null;
+    /** ? */
+    private firstItemIndex: number = 0;
+    private lastItemIndex: number = 0;
+    private firstItemData: any = {};
+    private lastItemData: any = {};
+    private itemArr: Array<any> = [];
+    private itemNode: Array<any> = [];
+    private itemPosMap: any = new Map();
+    private initItemData: boolean = true;
+    private count: number = 0;
+    private itemCanMoveDown: boolean = null;
+    private itemCanMoveUp: boolean = null;
+
+    onLoad() {
+        this.initPro();
+        // 测试
+        // let itemData = [];
+        // for (let i = 0; i < 20; i++) {
+        //     let test_data = {
+        //         pfbType: 0,
+        //     }
+        //     itemData.push(test_data);
+        // }
+        // this.init(itemData);
+    }
+
+    private initPro() {
+        this.scrollView = this.node.getComponent(cc.ScrollView);
+        this.content = this.scrollView.content;
+        this.item = this.pre_item;
+        this.layerHeight = this.node.height;
+        for (let i = 0; i < this.item.length; i++) {
+            this.itemNode[i] = cc.instantiate(this.item[i]);
+        }
+        this.node.on('srollview-init', this.init, this);
+    }
+    
+    /**
+     * @param itemData 列表数据
+     * @param isSkipInit 跳过初始化
+     * @returns 
+     */
+    public init(itemData: Array<any>, isSkipInit: boolean = false) {
+        if (!itemData[0]) {
+            return false;
+        }
+
+        this.itemData = itemData; //item数据
+        this.firstItemIndex = 0;
+        this.lastItemIndex = 0;
+        this.firstItemData = {};
+        this.lastItemData = {};
+        this.itemArr = [];
+        this.itemPosMap = new Map();
+        this.initItemData = true;
+        this.count = 0;
+        if (isSkipInit) return;
+        // this.itemNode = [];
+        // for (let i = 0; i < this.item.length; i++) {
+        //     this.itemNode[i] = cc.instantiate(this.item[i]);
+        // }
+        // cc.log(this.testTime(0));// 消耗计时
+        this.initItem();
+        this.getItemPos(0);
+        this.scrollView.node.on('scrolling', this.callback, this);
+        // cc.log('tableView结束:' + this.testTime());
+    }
+
+    /** 
+     * 刷新列表 
+     * 仅更新data数据
+    */
+    private updateList() {
+
+    }
+
+    private getItemPos(index: number) {
+        let item_data_count = this.itemData.length;
+        for (let i = index; i < item_data_count; i++) {
+            let obj: any = {}
+            let y;
+            if (i === 0) {
+                obj.startPos = 0;
+            } else {
+                obj.startPos = this.itemPosMap.get(i - 1).endPos;
+            }
+            let j = this.itemData[i].pfbType || 0;
+            obj.endPos = obj.startPos + this.itemNode[j].height + this.itemInterval;
+            this.itemPosMap.set(i, obj);
+        }
+        if (item_data_count > 0) {
+            this.updateContentHeigh(this.itemPosMap.get(item_data_count - 1).endPos);
+        }
+    }
+
+    /**
+     * 实例化所有用到的item,控制实例化item的数目,暂定超出两个
+     */
+    private initItem() {
+        let j = 0;
+        for (let i = 0; i < this.itemData.length; i++) {
+            if (this.content.height > this.layerHeight) {
+                j++
+                if (j > 2) {
+                    break;
+                }
+            }
+            let y = 0;
+            if (i > 0) {
+                y = this.itemArr[i - 1].y - this.itemArr[i - 1].height - this.itemInterval;// 下一条目纵坐标
+            }
+            this.addItemNode(i, y);
+            this.updateContentHeigh(this.itemArr[i].height - y);
+        }
+    }
+
+    /**
+     * 添加条目节点
+     * @param i 编号
+     * @param y 坐标y
+     */
+    private addItemNode(i: number, y: number) {
+        let pfbType = this.itemData[i].pfbType || 0;
+        let item = cc.instantiate(this.itemNode[pfbType]);
+        item.parent = this.content;
+        item.pfbType = pfbType;
+        item.index = i;
+        if (i === 0) {
+            item.y = 0;
+        } else {
+            item.y = y;
+        }
+        item.x = 0;
+        //对item赋值
+        let comp_script = item.getComponent(item.name);
+        comp_script && comp_script.setItemData(this.itemData[i], this);
+        this.itemArr.push(item);
+        // cc.log('生成itemNode' + i);
+    }
+    
+    /**
+     * 更新centent高
+     * @param num  
+     */
+    private updateContentHeigh(num: number) {
+        this.content.height = num > this.layerHeight ? num : this.layerHeight;
+        // cc.log('滚动条高度:', this.content.height);
+    }
+
+    /**
+     * 触摸滚动条的函数回调
+     * @param event 
+     * @param eventType 
+     * @returns 
+     */
+    private callback(event, eventType) {
+        // cc.log(event && event.type || eventType)
+        if (this.content.height > this.layerHeight) {
+            let firstItemPos = this.scrollView.getScrollOffset().y;
+            let lastItemPos = firstItemPos + this.layerHeight;
+            if (firstItemPos < 0) return;
+            if (this.initItemData) {
+                // cc.log('111:%o', this.itemPosMap)
+                this.initItemData = false;
+                this.updateFirstItemIndex();
+                this.itemCanMoveDown = true;
+                this.updateLastItemIndex();
+                this.itemCanMoveDown = false;
+            }
+
+            //超出边界直接返回.
+            //滚动条向上滑动可能会触发的函数
+            if (firstItemPos > this.firstItemData.endPos) {
+                if (this.lastItemIndex + 1 < this.itemData.length) {
+                    this.updateFirstItemIndex();
+                }
+                this.count++;
+            }
+            if (lastItemPos > this.lastItemData.endPos) {
+                if (this.lastItemIndex + 1 < this.itemData.length) {
+                    this.itemCanMoveDown = true;
+                    this.updateLastItemIndex();
+                    this.itemCanMoveDown = false;
+                }
+            }
+            //滚动条向下滑动可能会触发的函数
+            if (lastItemPos < this.lastItemData.startPos) {
+                this.updateLastItemIndex();
+                this.count--;
+            }
+            if (firstItemPos < this.firstItemData.startPos) {
+                this.itemCanMoveUp = true;
+                this.updateFirstItemIndex();
+                this.itemCanMoveUp = false;
+            }
+
+        }
+
+    }
+
+    private updateFirstItemIndex() {
+        let num = this.firstItemIndex;
+        if (this.itemCanMoveUp && num > this.getItemIndex()[0] && num > 0) {
+            this.itemMoveUp(this.firstItemIndex - 1);
+        }
+        this.updateItemIndex();
+    }
+    private updateLastItemIndex() {
+        let num = this.lastItemIndex;
+        if (this.itemCanMoveDown && num < this.getItemIndex()[1] && num + 1 < this.itemData.length) {
+            this.itemMoveDown(this.lastItemIndex + 1);
+        }
+        this.updateItemIndex();
+    }
+
+    private updateItemIndex() {
+        //cc.log(this.firstItemIndex, this.lastItemIndex, this.itemArr, this.itemData)
+    }
+
+    /**
+     * 得到滚动条此时状态下应有的itemNode元素,包括滚动条上方一个,滚动条下方一个
+     * @returns 
+     */
+    private getItemIndex() {
+        let firstItemPos = this.scrollView.getScrollOffset().y;
+        let lastItemPos = firstItemPos + this.layerHeight;
+        let arr = [];
+        this.itemPosMap.forEach((value, key) => {
+            let status1 = value.startPos <= firstItemPos && value.endPos > firstItemPos;
+            let status2 = value.startPos >= firstItemPos && value.endPos < lastItemPos;
+            let status3 = value.startPos <= lastItemPos && value.endPos > lastItemPos;
+            if (status1) {
+                this.firstItemData.startPos = value.startPos;
+                this.firstItemData.endPos = value.endPos;
+                this.firstItemIndex = key;
+                arr.push(key);
+            }
+            if (status3) {
+                this.lastItemData.startPos = value.startPos;
+                this.lastItemData.endPos = value.endPos;
+                this.lastItemIndex = key;
+                arr.push(key);
+            }
+        })
+        return arr;
+    }
+
+    /**
+     * 滚动到顶部【滚动条顺序是从上到下开始遍历】
+     * @param num 
+     * @returns 
+     */
+    private itemMoveUp(num: number) {
+        if (num < 0 || this.lastItemIndex + 1 < num || num + 1 > this.itemData.length) {
+            return;
+        }
+        if (!this.hasItem(num)) {
+            this.itemMove(num, -this.itemPosMap.get(num).startPos);
+        }
+        num++;
+        return this.itemMoveUp(num);
+    }
+
+    /** 滚动到底部 */
+    private itemMoveDown(num: number) {
+        if (num < 0 || this.firstItemIndex - 1 > num || num + 1 > this.itemData.length) {
+            return;
+        }
+        if (!this.hasItem(num)) {
+            this.itemMove(num, -this.itemPosMap.get(num).startPos);
+        }
+        num--;
+        return this.itemMoveDown(num);
+    }
+
+    /**
+     * 判断指定index位置是否存在itemNode
+     * @param index 节点下标
+     * @returns 
+     */
+    private hasItem(index: number) {
+        for (let i = 0; i < this.itemArr.length; i++) {
+            if (this.itemArr[i].index === index) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 移动条目
+     * 逻辑判断,第一种情况,修改itemArr数组的某个对象,第二种情况实例化一个新itemNode
+     * @param index 条目节点标记
+     * @param y 
+     * @returns 
+     */
+    private itemMove(index: number, y: number) {
+        for (let i = 0; i < this.itemArr.length; i++) {
+            //index存在-1的情况,类似于在缓存池里的item.
+            let status1 = this.itemArr[i].index < this.firstItemIndex - 1 ? true : false;
+            let status2 = this.itemArr[i].index > this.lastItemIndex + 1 ? true : false;
+            let status3 = this.itemArr[i].pfbType === this.itemData[index].pfbType;
+            //cc.log('item的索引', this.firstItemIndex, this.lastItemIndex)
+            if (status1 && status3 || status2 && status3) {
+                //cc.log(i, index, this.itemArr, this.content.height);
+                //给item赋值还有设置位置
+                this.itemArr[i].index = index;
+                this.itemArr[i].y = y;
+                let comp_script = this.itemArr[i].getComponent(this.itemArr[i].name);
+                comp_script && comp_script.setItemData(this.itemData[index], this);
+                return;
+            }
+        }
+        this.addItemNode(index, y);
+    }
+
+    /**
+     * 得到相关位置的排序index
+     * 方法待验证,可能有问题
+     * @param pos 坐标
+     * @returns 
+     */
+    public getPosIndex(pos: cc.Vec2) {
+        for (let [key, value] of this.itemPosMap.entries()) {
+            if (value.endPos > pos && value.startPos <= pos) {
+                return key;
+            }
+        }
+    }
+
+    /**
+     * 添加条目
+     * @param obj 数据对象
+     * @returns 
+     */
+    public addItem(obj: any) {
+        this.itemData.push(obj);
+        this.getItemPos(this.itemData.length - 1);
+        let endPos = this.itemPosMap.get(this.itemData.length - 1).endPos;
+        if (endPos - this.layerHeight > 0) {
+            let startPos = endPos - this.layerHeight;
+            //得到当前的firstItemIndex;
+            for (let i = this.itemData.length - 1; i >= 0; i--) {
+                if (this.itemPosMap.get(i).endPos > startPos && this.itemPosMap.get(i).startPos <= startPos) {
+                    this.firstItemIndex = i;
+                }
+            }
+            this.scrollView.scrollToBottom();
+            this.lastItemIndex = this.itemData.length - 1;
+            let num = this.firstItemIndex - 1 > 0 ? (this.firstItemIndex - 1) : 0;
+            this.itemMoveUp(num);
+            return true;
+        } else {
+            this.firstItemIndex = 0;
+            this.lastItemIndex = this.itemData.length - 1;
+            this.itemMoveUp(this.firstItemIndex);
+            return false;
+        }
+
+    }
+
+    /**
+     * 清理条目
+     */
+    public clearItem() {
+        this.itemData = [];
+        this.itemPosMap.clear();
+        this.scrollView.scrollToTop();
+        this.content.height = 0;
+        for (let i in this.itemArr) {
+            // this.itemArr[i].index = -1;
+            // this.itemArr[i].y = 3000;
+            this.itemArr[i].destroy();
+        }
+    }
+
+    /**
+     * 删除指定条目
+     * @param i 节点.index
+     * @returns 
+     */
+    public deleteItem(i: number) {
+        this.itemData.splice(i, 1);
+        const item_data_count = this.itemData.length;
+        if (item_data_count <= 0) return;
+        this.getItemPos(item_data_count - 1);
+
+        //改变this.itemArr的内容
+        for (let j = 0; j < this.itemArr.length; j++) {
+            if (this.itemArr[j].index === i) {
+                this.itemArr[j].index = -1;
+                this.itemArr[j].y = 3000;
+            }
+            if (this.itemArr[j].index > i) {
+                let num = this.itemArr[j].index;
+                this.itemArr[j].y = -this.itemPosMap.get(num - 1).startPos;
+                this.itemArr[j].index = num - 1;
+            }
+        }
+        this.updateContentHeigh(this.itemPosMap.get(this.itemData.length - 1).endPos);
+        if (!this.lastItemIndex) this.getItemIndex();// 初始化时没有初始化此值,会导致为0.不能创建新的item,此处校验
+        this.itemMoveUp(this.firstItemIndex);//
+    }
+
+    /**
+     * 重置指定item
+     * @param index 节点下标
+     * @param item_data 新的数据
+     */
+    public resetItemData(index: number, item_data?: any) {
+        for (let i = 0; i < this.itemArr.length; i++) {
+            if (this.itemArr[i].index === index) {
+                if (item_data) this.itemData[i] = item_data;
+                let comp_script = this.itemArr[i].getComponent(this.itemArr[i].name);
+                comp_script && comp_script.setItemData(this.itemData[index], this);
+                break;
+            }
+        }
+    }
+
+    private lastResetItemInfoHeight: any = null;
+    private lastResetItemIndex: any = null;
+    /**
+     * 重置条目大小
+     * @param index 节点下标
+     * @param infoHeight 新的高度
+     */
+    public resetItemSize(index: number, infoHeight: number) {
+        let func = (function (index, infoHeight) {
+
+            for (let i = 0; i < this.itemArr.length; i++) {
+                if (this.itemArr[i].index > index) {
+                    this.itemArr[i].y -= infoHeight;
+                }
+            }
+
+            for (let [key, value] of this.itemPosMap.entries()) {
+                if (key === index) {
+                    value.endPos += infoHeight;
+                }
+                if (key > index) {
+                    value.endPos += infoHeight;
+                    value.startPos += infoHeight;
+                }
+            }
+            this.lastResetItemInfoHeight = infoHeight;
+            this.lastResetItemIndex = index;
+        }).bind(this);
+        if (this.lastResetItemIndex !== null && this.lastResetItemInfoHeight) {
+            if (this.lastResetItemIndex === index) {
+                func(this.lastResetItemIndex, -this.lastResetItemInfoHeight);
+                this.lastResetItemIndex = null;
+                this.lastResetItemInfoHeight = 0;
+            } else {
+                func(this.lastResetItemIndex, -this.lastResetItemInfoHeight);
+
+                func(index, infoHeight);
+            }
+        } else {
+            func(index, infoHeight);
+        }
+        this.itemMoveUp(this.firstItemIndex);
+        this.updateContentHeigh(this.itemPosMap.get(this.itemData.length - 1).endPos);
+    }
+
+
+}

+ 9 - 0
mk_framework/assets/script/game/component/TableView.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.0.8",
+  "uuid": "9a31dad7-33ef-4d08-a624-17d0fbf33945",
+  "isPlugin": false,
+  "loadPluginInWeb": true,
+  "loadPluginInNative": true,
+  "loadPluginInEditor": false,
+  "subMetas": {}
+}

+ 12 - 0
mk_framework/assets/script/game/component/tween.meta

@@ -0,0 +1,12 @@
+{
+  "ver": "1.1.2",
+  "uuid": "0a129a35-b5bd-40c6-b7bc-987ad03bb1fc",
+  "isBundle": false,
+  "bundleName": "",
+  "priority": 1,
+  "compressionType": {},
+  "optimizeHotUpdate": {},
+  "inlineSpriteFrames": {},
+  "isRemoteBundle": {},
+  "subMetas": {}
+}

+ 156 - 0
mk_framework/assets/script/game/component/tween/FlyNode.ts

@@ -0,0 +1,156 @@
+
+const { ccclass, property } = cc._decorator;
+/**
+ * 飞item组件
+ * - item使用容器存储,可复用,组件的节点被销毁时,销毁所有item
+ * - 流程:
+ * - 把节点在范围内随机展开,移动到指定位置
+ * - 数值优先使用通过事件传递的值,没有则使用装饰器上的默认值
+ * @author 薛鸿潇
+ */
+@ccclass
+export default class FlyNode extends cc.Component {
+
+    @property({ displayName: '起始阶段消耗时间' })
+    private start_move_time: number = 0.1;
+    @property({ displayName: '结束阶段消耗时间' })
+    private end_move_time: number = 0.3;
+    // @property({ displayName: 'item缩放比率' })
+    // private item_scale: number = 0.2;
+    @property({ displayName: 'item默认数量' })
+    private item_count: number = 10;
+    /** 组件数据 */
+    private fly_data = {
+        /** 节点的父节点 */
+        node_p: null,
+        /** 节点数量 */
+        item_count: this.item_count,
+        /** 节点大小 */
+        item_scale: [0.3, 1],
+        /** 节点纹理 */
+        item_sf: null,
+        /** 起始位置 */
+        start_pos: cc.Vec2.ZERO,
+        /** 结束位置 */
+        end_pos: cc.Vec2.ZERO,
+        /** 完成回调 */
+        complete_call: null,
+    }
+    /** item父节点 */
+    private node_fly: cc.Node = null;
+    /** item容器 */
+    private arr_item: Array<cc.Node> = [];
+
+    onLoad() {
+        this.node.on('ui-fly-node', this.getNodeProgress, this);
+    }
+
+    /**
+     * 加载 小号图标组 
+     * @param _fly_data 数据内容
+     */
+    private getNodeProgress(_fly_data: any) {
+        // 数据整理node_p, item_sf: cc.SpriteFrame, item_count: number, start_pos: cc.Vec2 = cc.Vec2.ZERO, item_scale: number = 1
+        // this.fly_data = _fly_data;
+        if (_fly_data.node_p) this.fly_data.node_p = _fly_data.node_p;
+        if (_fly_data.item_count) this.fly_data.item_count = _fly_data.item_count;
+        if (_fly_data.item_scale) this.fly_data.item_scale = _fly_data.item_scale;
+        if (_fly_data.item_sf) this.fly_data.item_sf = _fly_data.item_sf;
+        if (_fly_data.start_pos) this.fly_data.start_pos = _fly_data.start_pos;
+        if (_fly_data.end_pos) this.fly_data.end_pos = _fly_data.end_pos;
+        if (_fly_data.complete_call) this.fly_data.complete_call = _fly_data.complete_call;
+        let node_p = this.fly_data.node_p;
+        const item_count = this.fly_data.item_count;
+        const item_scale = this.fly_data.item_scale;
+        let item_sf = this.fly_data.item_sf;
+        let start_pos = this.fly_data.start_pos;
+        // 创建节点
+        if (!this.node_fly) {
+            this.node_fly = new cc.Node('node_fly');
+            this.node_fly.parent = node_p;
+        }
+        for (let i = 0; i < item_count; i++) {
+            let node_item = this.arr_item.shift();
+            if (!node_item || (node_item && node_item.parent)) {
+                // 无item 或者item存在,但有父节点【表示正在运行中】
+                node_item = new cc.Node('node_item');
+                this.arr_item.push(node_item);
+            }
+            node_item.stopAllActions();
+            node_item.parent = this.node_fly;
+            node_item.setPosition(start_pos);
+            // // 创建位置
+            node_item.angle = this.Range(-45, 45, true);
+            let new_scale = this.Range(item_scale[0], item_scale[1], false);
+            node_item.scale = new_scale;
+            // 偏移位置计算-新
+            let dir = cc.v2(this.Range(-1, 1, false), this.Range(-1, 1, false));
+            dir = dir.normalize();
+            let deltaInit = cc.v2(this.Range(10, 80, false) * dir.x, this.Range(10, 80, false) * dir.y);
+            let initPos = start_pos.add(deltaInit); Range
+            // node_item.setPosition(initPos);
+
+            // 纹理
+            let spr_item = node_item.getComponent(cc.Sprite) || node_item.addComponent(cc.Sprite);
+            spr_item.spriteFrame = item_sf;
+            // 执行动画
+            this.movePos(node_item, initPos);
+        }
+    }
+
+    /**
+     * 移动到起始位置
+     * @param node_item 
+     * @param initPos 
+     */
+    private movePos(node_item, initPos) {
+        let new_start_move_time = this.Range(0.3, 1, false);
+        //this.start_move_time
+        let start_pos = cc.tween().to(new_start_move_time, { position: new cc.Vec2(initPos) }, { easing: 'sineOut' });
+        let dt1 = cc.tween().delay(this.start_move_time * 1.5);
+        // this.end_move_time
+        // 结束阶段效果
+        let end_pos = cc.tween().to(this.end_move_time, { position: this.fly_data.end_pos }, { easing: 'sineOut' })
+        let end_scale = cc.tween().to(this.end_move_time, { scale: 1 });
+        let end_angle = cc.tween().to(this.end_move_time, { angle: 0 });
+        let parallel1 = cc.tween().parallel(end_pos, end_scale, end_angle);
+        let call1 = cc.tween().call(() => {
+            this.fly_data.complete_call && this.fly_data.complete_call();
+            this.fly_data.complete_call = null;
+            this.arr_item.push(node_item);
+            node_item.removeFromParent();
+        });
+        cc.tween(node_item).then(start_pos).then(dt1).then(parallel1).then(call1).start();
+    }
+
+    /**
+     * 
+     * @param min 
+     * @param max 
+     * @param isInt 
+     * @returns 
+     */
+    private Range(min: number, max: number, isInt: boolean = true): number {
+        //return min + Math.ceil(Math.random() * 1000) % (max - min);         //不包含最大值
+        let del: number = max - min;
+        if (del > 0) {
+            let val: number = min + Math.random() * 0xffffff % del
+            if (isInt) {
+                return Math.floor(val);
+            }
+            return val
+        }
+        return min;
+    }
+
+    onDestroy() {
+        const item_count = this.arr_item.length
+        for (let i = 0; i < item_count; i++) {
+            if (cc.isValid(this.arr_item[0])) {
+                this.arr_item[0].destroy();
+                this.arr_item.shift();
+            }
+        }
+    }
+    // update (dt) {}
+}

+ 9 - 0
mk_framework/assets/script/game/component/tween/FlyNode.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.0.8",
+  "uuid": "fa8815e2-92ca-4897-bb17-ed809348e082",
+  "isPlugin": false,
+  "loadPluginInWeb": true,
+  "loadPluginInNative": true,
+  "loadPluginInEditor": false,
+  "subMetas": {}
+}

+ 45 - 0
mk_framework/assets/script/game/component/tween/TweenEasing.ts

@@ -0,0 +1,45 @@
+export enum TweenEasing {
+    linear,
+    smooth,
+    fade,
+    quadIn,
+    quadOut,
+    quadInOut,
+    quadOutIn,
+    cubicIn,
+    cubicOut,
+    cubicInOut,
+    cubicOutIn,
+    quartIn,
+    quartOut,
+    quartInOut,
+    quartOutIn,
+    quintIn,
+    quintOut,
+    quintInOut,
+    quintOutIn,
+    sineIn,
+    sineOut,
+    sineInOut,
+    sineOutIn,
+    expoIn,
+    expoOut,
+    expoInOut,
+    expoOutIn,
+    circIn,
+    circOut,
+    circInOut,
+    circOutIn,
+    elasticIn,
+    elasticOut,
+    elasticInOut,
+    elasticOutIn,
+    backIn,
+    backOut,
+    backInOut,
+    backOutIn,
+    bounceIn,
+    bounceOut,
+    bounceInOut,
+    bounceOutIn
+}

+ 9 - 0
mk_framework/assets/script/game/component/tween/TweenEasing.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.0.8",
+  "uuid": "7d9391f6-5e6e-4aef-9213-43dc2ad2d153",
+  "isPlugin": false,
+  "loadPluginInWeb": true,
+  "loadPluginInNative": true,
+  "loadPluginInEditor": false,
+  "subMetas": {}
+}

+ 133 - 0
mk_framework/assets/script/game/component/tween/UIOpenAndClose.ts

@@ -0,0 +1,133 @@
+
+const { ccclass, property, executeInEditMode, playOnFocus } = cc._decorator;
+/** 效果类型 */
+enum EffectType {
+    None = 0,   //无
+    Scale = 1,  //缩放
+    ScaleToPoint = 2,    //缩放到某点
+    CenterUnfolding = 3,   //从中部展开
+}
+/**
+ * 界面打开 和 关闭效果
+ * 组件请挂载到对应ui界面上
+ * @author 薛鸿潇
+ */
+@ccclass
+@executeInEditMode()
+@playOnFocus()
+export default class UIOpenAndClose extends cc.Component {
+
+    @property({ type: cc.Node, displayName: '动画节点' })
+    private effect_par: cc.Node = null
+
+    @property({ type: cc.Enum(EffectType), displayName: '打开动画节点效果', visible() { return this.effect_par } })
+    private open_effect: EffectType = EffectType.None;
+
+    @property({ type: cc.Enum(EffectType), displayName: '关闭动画节点效果', visible() { return this.effect_par } })
+    private close_effect: EffectType = EffectType.None;
+
+    @property({ displayName: '关闭节点缩小到此节点坐标', visible() { return this.close_effect == EffectType.ScaleToPoint } })
+    private close_toPoint: string = "";
+
+    private _play_open: boolean = false;
+    @property({ displayName: "预览开" })
+    get play_open(): boolean {
+        if (this._play_open) {
+            this.showEffect();
+            this._play_open = false;
+        }
+        return this._play_open;
+    }
+    set play_open(v: boolean) {
+        this._play_open = v;
+    }
+    private _play_close: boolean = false;
+    @property({ displayName: "预览开" })
+    get play_close(): boolean {
+        if (this._play_close) {
+            this.hideEffect();
+            this._play_close = false;
+        }
+        return this._play_close;
+    }
+    set play_close(v: boolean) {
+        this._play_close = v;
+    }
+
+    onLoad() {
+        // this.node.on('ui-close', this.hideEffect, this);// 界面关闭事件
+    }
+
+    start() {
+        this.showEffect();
+    }
+
+    /**
+     * 界面打开效果
+     */
+    private showEffect() {
+        if (this.effect_par) {
+            switch (this.open_effect) {
+                case EffectType.None:
+                    break;
+                case EffectType.Scale:
+                    this.effect_par.scale = 0;
+                    cc.tween(this.effect_par)
+                        .to(0.15, { scale: 1 })
+                        .start()
+                    break;
+                case EffectType.CenterUnfolding:
+                    this.effect_par.scaleX = 0;
+                    cc.tween(this.effect_par)
+                        .to(0.15, { scaleX: 1 })
+                        .start()
+                    break;
+            }
+        }
+    }
+
+    /**
+     * 关闭打开效果
+     * @param cb 结束回调
+     */
+    private hideEffect(cb: Function = null) {
+        if (this.effect_par) {
+            switch (this.close_effect) {
+                case EffectType.None:
+                    cb && cb();
+                    break;
+                case EffectType.Scale:
+                    cc.tween(this.effect_par)
+                        .to(0.15, { scale: 0 })
+                        .call(() => {
+                            cb && cb();
+                        })
+                        .start()
+                    break;
+                case EffectType.ScaleToPoint:
+                    if (this.close_toPoint == "") {
+                        console.error('需要配置缩小到终点节点路径')
+                    } else {
+                        let path = this.close_toPoint;
+                        let node = cc.find(path);
+                        if (node) {
+                            let world_pos = node.parent.convertToWorldSpaceAR(node.getPosition());
+                            let node_pos = this.effect_par.parent.convertToNodeSpaceAR(world_pos);
+                            cc.tween(this.effect_par)
+                                .to(0.3, { scale: 0, position: new cc.Vec3(node_pos.x, node_pos.y, 0) })
+                                .call(() => {
+                                    cb && cb();
+                                })
+                                .start()
+                        } else {
+                            cb && cb();
+                            cc.error('关闭时动画节点未找到,请检查!!!!!')
+                        }
+                    }
+                    break;
+            }
+        } else {
+            cb && cb();
+        }
+    }
+}

+ 9 - 0
mk_framework/assets/script/game/component/tween/UIOpenAndClose.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.0.8",
+  "uuid": "ac053cf0-a9a4-43e8-8266-4e541699e7d9",
+  "isPlugin": false,
+  "loadPluginInWeb": true,
+  "loadPluginInNative": true,
+  "loadPluginInEditor": false,
+  "subMetas": {}
+}

+ 153 - 0
mk_framework/assets/script/game/component/tween/UITween.ts

@@ -0,0 +1,153 @@
+
+import { TweenEasing } from "./TweenEasing";
+const { ccclass, property, executeInEditMode, playOnFocus } = cc._decorator;
+/**
+ * 缓动数据
+ * @author 
+ */
+@ccclass("PropsData")
+export class PropsData {
+    @property({ tooltip: "坐标" })
+    public position: cc.Vec2 = cc.Vec2.ZERO;
+    @property({ tooltip: "旋转" })
+    public angle: number = 0;
+    @property({ tooltip: "缩放" })
+    public scale: number = 1;
+}
+/**
+ * 缓动数据
+ * @author 
+ */
+@ccclass//("TweenData")
+export class TweenData {
+    // @property({ tooltip: "属性数据", type: PropsData })
+    // public propsData: PropsData = new PropsData();
+    @property({ tooltip: "坐标" })
+    public position: cc.Vec2 = cc.Vec2.ZERO;
+    @property({ tooltip: "旋转" })
+    public angle: number = 0;
+    @property({ tooltip: "缩放" })
+    public scale: number = 1;
+
+    @property({ tooltip: "持续时间,单位为秒" })
+    public duration: number = 0.3;
+    @property({ tooltip: "延迟时间,单位为秒" })
+    public delay: number = 0;
+    @property({ tooltip: "是否为差值" })
+    public isOffset: boolean = false;
+    @property({ tooltip: "当缓动动作完成时触发", type: cc.Component.EventHandler })
+    public onComplete: cc.Component.EventHandler = null;
+    @property({ tooltip: "当缓动动作启动时触发", type: cc.Component.EventHandler })
+    public onStart: cc.Component.EventHandler = null;
+    @property({ tooltip: "当缓动动作更新时触发", type: cc.Component.EventHandler })
+    public onUpdate: cc.Component.EventHandler = null;
+}
+/**
+ * 缓动组件,目前只支持节点的三个基础属性
+ * 目前改动类后会导致编辑器内的属性记录丢失,请不要使用
+ * @author 
+ */
+@ccclass//('UITween')
+@executeInEditMode()
+@playOnFocus()
+export class UITween extends cc.Component {
+    @property
+    private err = '属性记录会丢失,请不要使用'
+    @property({ tooltip: "节点初始属性", type: PropsData })
+    public fromData: PropsData = new PropsData();
+    @property({ tooltip: "节点目标属性", type: TweenData, serializable: false })//, serializable: false
+    public targetData: TweenData[] = [];//new TweenData()
+    @property({ tooltip: "要播放缓动动画的目标,不填则是当前节点", type: cc.Node })
+    public target: cc.Node = null;
+    @property({ tooltip: "缓动效果", type: cc.Enum(TweenEasing) })
+    public tweenEasing: TweenEasing = TweenEasing.linear;
+    @property({ tooltip: "执行次数,为0则一直重复执行" })
+    public repeat: number = 1;
+    @property({ tooltip: "单次缓动序列执行完毕时触发", type: cc.Component.EventHandler })
+    public onOneRepeatComplete: cc.Component.EventHandler = null;
+    @property({ tooltip: "是否在缓动组件运行时自动播放缓动动画" })
+    public playOnLoad: boolean = false;
+    @property({ displayName: "编辑器预览" })
+    public _playOnEdit: boolean = false;
+    @property({ displayName: "编辑器预览" })//, editorOnly: true
+    get playOnEdit(): boolean {
+        if (this._playOnEdit) {
+            this.play()
+        }
+        return this._playOnEdit;
+    }
+    set playOnEdit(v: boolean) {
+        this._playOnEdit = v;
+    }
+    public start() {
+        // if (CC_EDITOR && !this._playOnEdit) return;
+        !this.target && (this.target = this.node);
+        this.target = this.target || this.node;
+        this.currentRepeat = this.repeat;
+        this.playOnLoad && this.play();
+    }
+    private t: cc.Tween<any>;
+    private currentRepeat: number;
+    public play() {
+        if (CC_EDITOR && !this._playOnEdit) return;
+        if (this.repeat == 0) {
+            this.t = cc.tween(this.target);
+            this.readyPlay();
+            this.t = this.t.call(this.play.bind(this));
+            this.t.start();
+        }
+        else if (this.currentRepeat) {
+            this.t = cc.tween(this.target);
+            this.readyPlay();
+            this.t = this.t.call(this.play.bind(this));
+            this.currentRepeat--;
+            this.t.start();
+        }
+        else {
+            this.t = null;
+        }
+    }
+    public readyPlay() {
+        let self = this;
+        if (this.fromData) {
+            this.node.setPosition(this.fromData.position.clone());
+            this.node.scale = this.fromData.scale;
+            this.node.angle = this.fromData.angle;
+        }
+        if (this.targetData.length) {
+            for (let i = 0; i < this.targetData.length; i++) {
+                const targetData = this.targetData[i];
+                if (targetData.delay != 0) {
+                    this.t = this.t.delay(targetData.delay);
+                }
+                let toData = {
+                    position: targetData.position,
+                    scale: targetData.scale,
+                    angle: targetData.angle
+                }
+                if (targetData.isOffset) {
+                    toData.position = this.node.getPosition().add(targetData.position);
+                    toData.scale = this.node.scale + targetData.scale;
+                    toData.angle = this.node.angle + targetData.angle;
+                }
+                this.t = this.t.to(
+                    targetData.duration,
+                    toData,
+                    {
+                        easing: TweenEasing[this.tweenEasing] as any,
+                        onComplete: (target: cc.Node) => {
+                            targetData.onComplete && targetData.onComplete.emit([target]);
+                        },
+                        onStart: (target: cc.Node) => { targetData.onStart && targetData.onStart.emit([target]) },
+                        onUpdate: (target: cc.Node, ratio: number) => { targetData.onUpdate && targetData.onUpdate.emit([target, ratio]) }
+                    }
+                );
+            }
+        }
+        if (this.onOneRepeatComplete) {
+            this.t = this.t.call(() => {
+                self.onOneRepeatComplete.emit([this, this.t])
+            });
+        }
+    }
+}

+ 9 - 0
mk_framework/assets/script/game/component/tween/UITween.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.0.8",
+  "uuid": "a20d913e-37b1-4188-857b-cf5c21b93e89",
+  "isPlugin": false,
+  "loadPluginInWeb": true,
+  "loadPluginInNative": true,
+  "loadPluginInEditor": false,
+  "subMetas": {}
+}

+ 28 - 10
mk_framework/assets/script/mk/system/MKSystem.ts

@@ -7,6 +7,12 @@ import HttpSystem from "./HttpSystem";
 import LoadResUtil from "../utils/LoadResUtil";
 import LogUtil from "../utils/LogUtil";
 import { EncryptUtil } from "../utils/EncryptUtil";
+import GameUtil from "../utils/GameUtil";
+import UISystem from "./UISystem";
+import StorageUtil from "../utils/StorageUtil";
+import TimerSystem from "./TimerSystem";
+import EventSystem from "./EventSystem";
+import MathUtil from "../utils/MathUtil";
 
 /**
  * @description mk系统
@@ -18,21 +24,26 @@ class MKSystem {
     }
 
     /** 工具 */
-    public time: TimeUtil;
-    public file: FileUtil;
-    public loadRes: LoadResUtil;
-    public encrypt: EncryptUtil;
-    public log: LogUtil;
+    time: TimeUtil;
+    file: FileUtil;
+    encrypt: EncryptUtil;
+    log: LogUtil;
+    game: GameUtil;
+    loader: LoadResUtil;
+    storage: StorageUtil;
+    math: MathUtil;
 
     /** SDK */
-    public bugly: BuglySDK;
+    bugly: BuglySDK;
 
 
     /** 系统管理 */
-    public loader: LoadResUtil;
-    public data: DataSystem;
-    public http: HttpSystem;
-    public audio: AudioSystem;
+    data: DataSystem;
+    http: HttpSystem;
+    audio: AudioSystem;
+    ui: UISystem;
+    timer: TimerSystem;
+    event: EventSystem;
 
     init() {
         //工具
@@ -49,6 +60,13 @@ class MKSystem {
         this.audio = new AudioSystem();
         this.data = new DataSystem();
         this.http = new HttpSystem();
+
+        let a = 1;
+        let b = "a";
+        let c = { a: 1 };
+        console.log(JSON.stringify(a));
+        console.log(JSON.stringify(b));
+        console.log(JSON.stringify(c));
     }
 }
 

+ 105 - 0
mk_framework/assets/script/mk/system/UISystem.ts

@@ -0,0 +1,105 @@
+
+/**
+ * UI管理类
+ * @author 冯聪
+ */
+export default class UISystem {
+
+    /**panel父节点 */
+    public panelParent: cc.Node = null;
+
+    /**界面预制体路径 */
+    private panelPrefanbUrl: string = './prefab/uiPanel/'
+    /**是否正在打开界面 */
+    private isPanelOpening: boolean = false;
+    /**是否界面正在关闭 */
+    private isPanelClosing: boolean = false;
+    /**当前打开的UIPanel */
+    private curOnPanelDic: { [key: string]: cc.Node } = {};
+    /**上一个打开的界面名称 */
+    private lastOpenPanelName: string = "";
+
+    /**
+     * 打开panel界面
+     * @param panelName 界面名称
+     * @param callBack  打开之后的回调
+     * @param openAction 打开之后的操(需不需要关闭其他界面)
+     */
+    onPanel(panelName: string, callBack: Function = null, openAction: OpenActionType = OpenActionType.normal) {
+
+        if (this.isPanelOpening || this.getCurOnPanel(panelName)) {
+            return;
+        }
+
+        this.isPanelOpening = true;
+
+        mk.loader.load(`${this.panelPrefanbUrl}` + panelName, cc.Prefab).then((prefab) => {
+
+            this.isPanelOpening = false;
+
+            let node_panel = cc.instantiate(prefab);
+            this.curOnPanelDic[panelName] = node_panel;
+            //如果父节点不存在,就默认把该节点定为panel的父节点
+            if (!this.panelParent) {
+                mk.console.log("[UISystem] UI的父节点panelParent为null,需指定UI打开的父节点");
+                return;
+            }
+            this.panelParent.addChild(node_panel);
+            
+            callBack && callBack();
+
+            switch (openAction) {
+                case OpenActionType.normal:
+                    break;
+                case OpenActionType.closeLast:
+                    if (this.lastOpenPanelName) {
+                        this.offPanel(this.lastOpenPanelName);
+                    }
+                    break;
+                case OpenActionType.closeOther:
+                    let keys = Object.keys(this.curOnPanelDic).filter((key) => { key != panelName });
+                    for (var i = 0; i < keys.length; i++) {
+                        let key = keys[i];
+                        this.offPanel(key);
+                    }
+                    break;
+            }
+            this.lastOpenPanelName = panelName;
+        })
+    }
+
+    /**获取当前打开的panel界面
+     * @param panelName 界面名称
+     */
+    getCurOnPanel(panelName: string): cc.Node {
+        return this.curOnPanelDic[panelName];
+    }
+
+    /**
+     * 关闭panel界面
+     * @param panelName 界面名称
+     * @param callBack  关闭之后回调
+     */
+    offPanel(panelName: string, callBack: Function = null) {
+        if (this.isPanelClosing || !this.getCurOnPanel(panelName)) {
+            return;
+        }
+        this.isPanelClosing = true;
+
+        let node_panel = this.getCurOnPanel(panelName);
+        node_panel.removeFromParent();
+        delete this.curOnPanelDic[panelName];
+
+        this.isPanelClosing = false;
+    }
+}
+
+/**界面打开操作 */
+export enum OpenActionType {
+    /**普通不操作 */
+    normal = 0,
+    /**关闭其他 */
+    closeOther = 1,
+    /**关闭上一个 */
+    closeLast = 2
+}

+ 9 - 0
mk_framework/assets/script/mk/system/UISystem.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.0.8",
+  "uuid": "d0ea1f88-3b40-4a26-864c-2274ba77d772",
+  "isPlugin": false,
+  "loadPluginInWeb": true,
+  "loadPluginInNative": true,
+  "loadPluginInEditor": false,
+  "subMetas": {}
+}

+ 51 - 0
mk_framework/assets/script/mk/utils/GameUtil.ts

@@ -0,0 +1,51 @@
+
+/**
+ * 游戏工具类
+ * @description 
+ * @author 冯聪
+ */
+export default class GameUtil {
+
+    /**获取屏幕尺寸 */
+    public getWinSize(): cc.Size {
+        return cc.winSize;
+    }
+
+    /**激活物理系统 */
+    public enablePhysics() {
+        cc.director.getPhysicsManager().enabled = true;
+    }
+
+    /**绘制物理信息 */
+    public debugDrawPhysicsFlag(ifDraw: boolean = false) {
+        if (ifDraw) {
+            cc.director.getPhysicsManager().debugDrawFlags =
+                cc.PhysicsManager.DrawBits.e_aabbBit |
+                cc.PhysicsManager.DrawBits.e_jointBit |
+                cc.PhysicsManager.DrawBits.e_shapeBit;
+        }
+        else {
+            cc.director.getPhysicsManager().debugDrawFlags = 0;
+        }
+    }
+
+    /**获取世界坐标
+     * @param 需要获取的节点
+     */
+    public static getWorldPos(node: cc.Node): cc.Vec2 {
+        let originX = node.x;
+        let originY = node.y;
+        let curNode = node;
+
+        while (curNode.parent) {
+            let parent = curNode.parent;
+            if (parent.name == 'Canvas') {
+                break;
+            }
+            originX += parent.x;
+            originY += parent.y;
+            curNode = parent;
+        }
+        return new cc.Vec2(originX, originY);
+    }
+}

+ 9 - 0
mk_framework/assets/script/mk/utils/GameUtil.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.0.8",
+  "uuid": "78449f73-4199-44e4-b190-fc0380599a91",
+  "isPlugin": false,
+  "loadPluginInWeb": true,
+  "loadPluginInNative": true,
+  "loadPluginInEditor": false,
+  "subMetas": {}
+}

+ 26 - 0
mk_framework/assets/script/mk/utils/StorageUtil.ts

@@ -0,0 +1,26 @@
+/**
+ * 本地存储工具类 
+ * @author 冯聪
+ */
+export default class StorageUtil {
+
+    /**获取存储
+     * @param:key key值
+     */
+    public getStorage(key: string): any {
+        if (cc.sys.localStorage.getItem(key)) {
+            return JSON.parse(cc.sys.localStorage.getItem(key));
+        }
+        else {
+            return null;
+        }
+    }
+
+    /**存储
+     * @param: key key值
+     * @param: value 要存储的value值
+     */
+    public setStorage(key: string, value: any) {
+        cc.sys.localStorage.setItem(key, JSON.stringify(value));
+    }
+}

+ 9 - 0
mk_framework/assets/script/mk/utils/StorageUtil.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.0.8",
+  "uuid": "897f9fce-4dee-482e-9091-7f385d550522",
+  "isPlugin": false,
+  "loadPluginInWeb": true,
+  "loadPluginInNative": true,
+  "loadPluginInEditor": false,
+  "subMetas": {}
+}