├── .gitignore ├── English.md ├── LICENSE ├── README.md ├── ccc-components ├── Listview.js ├── Scrollview.js ├── button.js └── handcardPreview.js ├── ccc-plugin ├── AssetsExportor.js ├── builder │ ├── buildAnimation.js │ ├── buildCreator.js │ ├── buildOutline.js │ ├── buildRelationship.js │ ├── buildlua.js │ ├── sort.js │ ├── util.js │ └── writeFile.js ├── catcher │ ├── Button.js │ ├── Catcher.js │ ├── CustomComponent.js │ ├── EditBox.js │ ├── ExtraData.js │ ├── ImageSource.js │ ├── Label.js │ ├── Outline.js │ ├── ParticleSystem.js │ ├── ProgressBar.js │ ├── Sprite.js │ ├── Type.js │ ├── ValueStr.js │ └── Widget.js ├── components │ ├── AnimationRecorder.js │ └── ExportRule.js ├── main.js ├── package.json ├── panel │ ├── index.html │ └── index.js ├── sceneEnv.js └── sort.js ├── lua-interpret ├── BtnFactory.lua ├── RadioGroup.lua ├── createNode.lua └── outline.lua ├── work-quick.txt └── work.txt /.gitignore: -------------------------------------------------------------------------------- 1 | test_2dx/cocos2d 2 | test_2dx/proj.win32 3 | test_2dx/Resources 4 | test_2dx/.cocos-project.json 5 | test_2dx/CMakeLists.txt 6 | test_2dx/vcredist_x64.exe 7 | test_2dx/vcredist_x86.exe 8 | test_2dx/Classes/udpLog 9 | *.meta -------------------------------------------------------------------------------- /English.md: -------------------------------------------------------------------------------- 1 | Brief introduction 2 | ------------------ 3 | * **Plugin of creator:** Outline is a plugin working on the popular game editor cocos creator(we call it creator below).It can export any node or animation in the creator editor to a cocos2dx(we call it 2dx below) project. 4 | * **Features:** Outline is dedicated to bring 2dx a graphical and component-based industry,and simultaneously,making the work to maintain a high compatibility,high ease of use and migration.Outline is quite different from the official one .First ,it can support 2dx versions under 3.14(I am using the version 3.10,and it works well.The lowest version it can support is not tested).Second it can export any node individually. Finally,it can export your customized component. 5 | * **Export source files** Kind of the file outline exports is c++ source file.Each node(include its child nodes),or each animation clip will be exported in a single hpp file.The exported source file of a node will contain a template tree of the node and its child nodes.I call this tree the creator tree.Each creator instance in the creator tree can be one-to-one matched with a node in the exported node tree,and can also create instance of that matched node.Follow the code hints by IDE,you can get any instance in the creator tree quickly.There are some advantages of exporting source file solution,such as a faster speed in runtime,more prominent security and Extensibility ...The disadvantage is that the source file can not be hot updated. 6 | * **Design idea** As its name shown,outline will pay more attention on the outline of a node,because I find that,the biggest advantage of designing by Editor comparing with designing by manual is that it can be more intuitive to set the properties,such as the position,scale,rotation and so on,of a node.And these properties can be summarized as the outline of a node.Of cource the infomation of other components will be exported as key-value pairs in the standard map container. 7 | * **Design idea of animation** Outline use an solution that ,run the project and play the animation,at the same time record the state of the playing node in every frame.Finally export every animation clip. 8 | 9 | 10 | How to export node 11 | ------------------ 12 | Asserting you have installed outline in your project.When you open it by creator editor,you can find following changes.Firstly, a item shown as "outline" appears in the menu bar.If you click it , a child item shown as "export rule" will appear.Secondly,In the assets panel,four script files occur in the outline-components folder.They are "ExportRule.js","AnimationRecorder.js","AutoRecorder.js" and "Status.js".The ExportRule script is used to descript an export rule.Just add an export rule by dragging the "ExportRle.js" script into the property inspector of the Canvas node.Then set it in the property inspector and save the project after completing your setting. Finally,export what you want by clicking the "export node" item. 13 | 14 | 15 | How to add customized components 16 | -------------------------------- 17 | In creator,you can push some extra information to a node by adding your customized component script into the node.You can also export these information to a 2dx project through outline by just making a mark in the name of the component property.Outline provides two export schemes.A property taking "o_" as its prefix,will be exported as a member variable of its creator struct;And a property taking "o__" as its prefix,will be exported into the mapAble member variable of its creator struct,with the format "key:value%o__%",that is to say,the data of all such properties of one node will spell a string and be exported as the mapAble member of its creator struct.In the format above,the "key" symbol is the name of exported property,and the "value" is its value,the "%o__%" symbol is the separator between two properties.Currently,the data types of properties outline can export are int,float,string,bool and cc.SpriteFrame(the path string of its image file).The first scheme is suitable when the property has something about the project logic,such as defining some status of a node.The second scheme is suitale when the propery has nothing on logic,such as defining the node as a controller. 18 | 19 | 20 | How to export animation 21 | ----------------------- 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 limall 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | outline-lua · ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) 2 | ======= 3 | 特性 4 | ------- 5 | * **组件化:** outline-lua(以下简称outline)主要为cocos2d-x lua(以下简称2dx)项目设计ui,用户在cocos creator中设计ui,通过outline导出到2dx项目中;同时引入组件化工作流。组件化的主要依据在于,outline导出的是节点而非场景,并且支持导出creator中的自定义组件,这些都为程序员把节点封装成组件带来了便利。 6 | * **导出源码:** outline直接导出lua源码,配合BabelLua的代码提示,检索节点变得十分便利。导出源码还有个好处就是控件的适配更加灵活 7 | * **节点模板:** outline导出的是节点模板,除了直接由根模板生成一个页面外,程序员也可以索引到特定的某个节点模板,然后创建多个节点,甚至创建一批节点后,通过设置模板,还能再创建变了形状的节点。在保持整体性的同时,使用上更加灵活。 8 | 9 | 相关文章 10 | -------- 11 | * 思路及Hello,world,可参考文章[outline-组件化cocos2dx的插件](https://www.jianshu.com/p/aba7d1deebcd)   12 | * 关于如何导出节点,可参考文章[outline-导出节点](https://www.jianshu.com/p/2b1766662498) 13 | 14 | 15 | 注意 16 | --------- 17 | * 支持的creator版本为1.6至1.9 18 | * 使用前需取消cocos creator的自动裁剪功能,这在《outline-导出节点》中会介绍步骤 19 | * 导出node前须先要保存scene 20 | * 节点的名称的规范和lua代码变量名称规范一致,要求同一节点的子节点名称不可相同 21 | * 节点和图片名称除了"_"号,尽量不要出现其他符号 22 | * 在使用res_dst导出图片等资源时,由于windows文件不区分大小写,所以要避免资源或资源文件夹在不区分大小写时相同的情况。比较好的避免方法是资源文件或资源目录名称统一使用大写或小写。 23 | * 导出动画需要占用的网络端口为20383,确保没被其他程序占用 24 | 25 |         26 | -------------------------------------------------------------------------------- /ccc-components/Listview.js: -------------------------------------------------------------------------------- 1 | var Direction=cc.Enum({ 2 | ToBottom:1, 3 | ToRight:2/*, 4 | ToTop:3, 5 | ToLeft:4*/ 6 | }); 7 | 8 | 9 | var Gravity=cc.Enum({ 10 | Left:0, 11 | Right:1, 12 | Center_Horizontal:2, 13 | Top:3, 14 | Bottom:4, 15 | Center_Vertical:5 16 | }); 17 | 18 | cc.Class({ 19 | extends: cc.Component, 20 | properties: { 21 | o__isListview:{ 22 | default:true, 23 | visible:false 24 | }, 25 | o__listview_inertia:{ 26 | default:true, 27 | tooltip:"是否开启滚动惯性", 28 | displayName:'inertia' 29 | }, 30 | /*o__listview_brake:{ 31 | default:0.5, 32 | tooltip:"开启惯性后,在用户停止触摸后滚动多块停止,0表示永不停止,1表示立刻停止", 33 | displayName:'brake' 34 | },*/ 35 | o__listview_elastic:{ 36 | default:true, 37 | tooltip:"是否允许滚动内容超过边界,并在停止触摸后回弹", 38 | displayName:'elastic' 39 | }, 40 | /*o__listview_bounce_duration:{ 41 | default:1, 42 | tooltip:"回弹持续的时间,0表示将立即反弹", 43 | displayName:'bounce_duration' 44 | }, 45 | o__listview_horizontal_scroll_bar:{ 46 | default:null, 47 | type:cc.Scrollbar, 48 | tooltip:"水平滚动的Scrollbar", 49 | displayName:'horizontal_scroll_bar' 50 | }, 51 | o__listview_vertical_scroll_bar:{ 52 | default:null, 53 | type:cc.Scrollbar, 54 | tooltip:"垂直滚动的Scrollbar", 55 | displayName:'vertical_scroll_bar' 56 | }, 57 | o__listview_cancel_inner_events:{ 58 | default:true, 59 | tooltip:"滚动行为是否会取消子节点上注册的触摸事件", 60 | displayName:'cancel_inner_events' 61 | },*/ 62 | 63 | o__listview_hidebar:{ 64 | default:true, 65 | tooltip:"是否隐藏滚动条", 66 | displayName:"hidebar" 67 | }, 68 | 69 | o__listview_background:{ 70 | type:cc.SpriteFrame, 71 | default:null, 72 | tooltip:"背景", 73 | displayName:'background' 74 | }, 75 | 76 | o__listview_direction:{ 77 | default:Direction.ToBottom, 78 | type:Direction, 79 | tooltip:"listview的方向", 80 | displayName:'direction' 81 | }, 82 | 83 | o__listview_item_gravity:{ 84 | default:Gravity.Center_Horizontal, 85 | type:Gravity, 86 | displayName:'item_gravity' 87 | }, 88 | 89 | o__listview_item_margin:{ 90 | default:5, 91 | tooltip:"项距", 92 | displayName:'item_margin' 93 | }, 94 | 95 | o__listview_padding_left:{ 96 | default:0, 97 | tooltip:"listview的左边距", 98 | displayName:'padding_left' 99 | }, 100 | o__listview_padding_right:{ 101 | default:0, 102 | tooltip:"listview的右边距", 103 | displayName:'padding_right' 104 | }, 105 | o__listview_padding_top:{ 106 | default:0, 107 | tooltip:"listview的上边距", 108 | displayName:'padding_top' 109 | }, 110 | o__listview_padding_bottom:{ 111 | default:0, 112 | tooltip:"listview的下边距", 113 | displayName:'padding_bottom' 114 | } 115 | }, 116 | start:function(){ 117 | var listview=this.node; 118 | if(this.o__listview_background){ 119 | var node_background=this.node_background = new cc.Node(); 120 | var sp = node_background.addComponent(cc.Sprite); 121 | sp.type = cc.Sprite.Type.SLICED 122 | sp.spriteFrame = this.o__listview_background; 123 | node_background.parent = listview; 124 | node_background.width=listview.width; 125 | node_background.height=listview.height; 126 | } 127 | 128 | var contentWidth=listview.width-this.o__listview_padding_left-this.o__listview_padding_right; 129 | var left=-listview.width*listview.anchorX; 130 | var contentX=left+this.o__listview_padding_left+contentWidth/2; 131 | var contentHeight=listview.height-this.o__listview_padding_top-this.o__listview_padding_bottom; 132 | var bottom=-listview.height*listview.anchorY; 133 | var contentY=bottom+this.o__listview_padding_bottom+contentHeight/2; 134 | 135 | var contentMask=new cc.Node(); 136 | contentMask.x=contentX; 137 | contentMask.y=contentY; 138 | contentMask.width=contentWidth; 139 | contentMask.height=contentHeight; 140 | contentMask.parent=listview; 141 | 142 | var mask=contentMask.addComponent(cc.Mask); 143 | mask.type = cc.Mask.Type.RECT; 144 | 145 | var top=contentMask.height/2; 146 | var left=-contentMask.width/2; 147 | var bottom=-top; 148 | cc.log("b"+bottom); 149 | var right=-left; 150 | 151 | var item_sample=listview.getChildByName('item_sample'); 152 | if(item_sample){ 153 | if(this.o__listview_direction==Direction.ToBottom){ 154 | for(var i=0;i<10;i++){ 155 | var item=cc.instantiate(item_sample); 156 | item.x=0; 157 | if(this.o__listview_item_gravity==Gravity.Left){ 158 | item.x=left+item.width*item.anchorX; 159 | }else if(this.o__listview_item_gravity==Gravity.Right){ 160 | item.x=right-item.width*(1-item.anchorX); 161 | } 162 | item.y=top-item.height*i-this.o__listview_item_margin*i-item.height*(1-item.anchorY); 163 | item.parent=contentMask; 164 | } 165 | }else if(this.o__listview_direction==Direction.ToRight){ 166 | for(var i=0;i<10;i++){ 167 | var item=cc.instantiate(item_sample); 168 | item.x=left+item.width*i+this.o__listview_item_margin*i+item.width*item.anchorX; 169 | item.y=0; 170 | if(this.o__listview_item_gravity==Gravity.Bottom){ 171 | item.y=bottom+item.height*item.anchorY; 172 | }else if(this.o__listview_item_gravity==Gravity.Top){ 173 | item.y=top-item.height*(1-item.anchorY); 174 | } 175 | item.parent=contentMask; 176 | cc.log(item.y); 177 | } 178 | } 179 | } 180 | } 181 | }); 182 | -------------------------------------------------------------------------------- /ccc-components/Scrollview.js: -------------------------------------------------------------------------------- 1 | var Direction=cc.Enum({ 2 | VERTICAL:1, 3 | HORIZONTAL:2, 4 | BOTH:3 5 | }); 6 | cc.Class({ 7 | extends: cc.Component, 8 | properties: { 9 | o__isScrollview:{ 10 | default:true, 11 | visible:false 12 | }, 13 | o__scrollview_inertia:{ 14 | default:true, 15 | tooltip:"是否开启滚动惯性", 16 | displayName:'inertia' 17 | }, 18 | o__scrollview_direction:{ 19 | default:Direction.VERTICAL, 20 | type:Direction, 21 | tooltip:"scrollview的滚动方向", 22 | displayName:'direction' 23 | }, 24 | o__scrollview_hidebar:{ 25 | default:true, 26 | tooltip:"是否隐藏滚动条", 27 | displayName:"hidebar" 28 | } 29 | }, 30 | start () { 31 | var scrollview=this.node; 32 | var content=scrollview.getChildByName('content'); 33 | var viewsize=scrollview.getContentSize(); 34 | var contentsize=scrollview.getContentSize(); 35 | 36 | //先设置content到scroll的正中心(both情况) 37 | content.setAnchorPoint(0.5,0.5); 38 | var viewAnchor=scrollview.getAnchorPoint(); 39 | content.x=(0.5-viewAnchor.x)*viewsize.width; 40 | content.y=(0.5-viewAnchor.y)*viewsize.height; 41 | 42 | switch(this.o__scrollview_direction){ 43 | case Direction.VERTICAL: 44 | content.y-=(contentsize.height-viewsize.height)/2; 45 | break; 46 | case Direction.HORIZONTAL: 47 | content.x+=(contentsize.width-viewsize.width)/2; 48 | break; 49 | } 50 | 51 | var mask=scrollview.addComponent(cc.Mask); 52 | mask.type = cc.Mask.Type.RECT; 53 | }, 54 | }); 55 | -------------------------------------------------------------------------------- /ccc-components/button.js: -------------------------------------------------------------------------------- 1 | var ButtonType=cc.Enum({ 2 | ScaleButton:1, 3 | ColorButton:2, 4 | SpriteButton:3, 5 | SelectButton:4, 6 | NoTransition:5 7 | }); 8 | cc.Class({ 9 | extends: cc.Component, 10 | properties: { 11 | o__btn_enableAutoGrayEffect:{ 12 | displayName:'enable auto gray effect', 13 | default:false 14 | }, 15 | o__btn_buttonType:{ 16 | displayName:'buttonType', 17 | default:ButtonType.ScaleButton, 18 | type:ButtonType 19 | }, 20 | o__btn_needSwallowTouch:{ 21 | displayName:'needSwallowTouch', 22 | default:true 23 | }, 24 | o__btn_cancelWhenScroll:{ 25 | displayName:'cancelWhenScroll', 26 | default:false 27 | }, 28 | o__btn_image_normal:{ 29 | default:null, 30 | type:cc.SpriteFrame, 31 | displayName:'normal' 32 | }, 33 | o__btn_image_pressed:{ 34 | default:null, 35 | type:cc.SpriteFrame, 36 | displayName:'pressed' 37 | }, 38 | o__btn_image_disabled:{ 39 | default:null, 40 | type:cc.SpriteFrame, 41 | displayName:'disabled' 42 | } 43 | }, 44 | }); 45 | -------------------------------------------------------------------------------- /ccc-components/handcardPreview.js: -------------------------------------------------------------------------------- 1 | cc.Class({ 2 | extends: cc.Component, 3 | 4 | properties: { 5 | isMiddle:false, 6 | num:17, 7 | isX:true, 8 | increment:60 9 | }, 10 | 11 | onLoad(){ 12 | }, 13 | 14 | start () { 15 | var node=this.node; 16 | var num=this.num; 17 | var start=node.getPosition(); 18 | var isX=this.isX; 19 | var increment=this.increment; 20 | var addpos=isX?new cc.Vec2(increment,0):new cc.Vec2(0,increment); 21 | if(this.isMiddle){ 22 | for(var i=0;i0){ 19 | code_components+=creatorName+'._components={'; 20 | } 21 | userDatas.forEach(function(userData){ 22 | var code=creatorName+'.'+userData.UserDataName+'={\n'; 23 | for(var propName in userData){ 24 | if(propName!=='UserDataName'){ 25 | code+=' '+propName+'='+userData[propName]+',\n' 26 | } 27 | } 28 | code+='}\n' 29 | code_components+='"'+userData.UserDataName+'",'; 30 | luaCode+=code; 31 | }); 32 | if(code_components!==''){ 33 | code_components+='}\n'; 34 | } 35 | return luaCode+code_components; 36 | } 37 | 38 | /** 39 | * @method buildCreators 生成多个creator的lua代码 40 | * @param {"Array"} outline 多个outline 41 | * @returns {string} 多个creator的lua代码 42 | */ 43 | module.exports.buildCreators=function(outlines){ 44 | var luaCode=''; 45 | outlines.forEach(function(outline){ 46 | luaCode+=buildOneCreator(outline)+'\n'; 47 | }); 48 | return luaCode; 49 | } 50 | -------------------------------------------------------------------------------- /ccc-plugin/builder/buildOutline.js: -------------------------------------------------------------------------------- 1 | var util=require ('./util') 2 | 3 | var luaDefault={ 4 | name:'', 5 | x:0, 6 | y:0, 7 | scaleX:1, 8 | scaleY:1, 9 | width:0, 10 | height:0, 11 | anchorX:0.5, 12 | anchorY:0.5, 13 | rotation:0, 14 | skewX:0, 15 | skewY:0, 16 | opacity:255, 17 | visible:true, 18 | zOrder:0, 19 | colorR:255, 20 | colorG:255, 21 | colorB:255 22 | }; 23 | 24 | var exportProperties=[ 25 | 'x', 26 | 'y', 27 | 'width', 28 | 'height', 29 | 'anchorX', 30 | 'anchorY', 31 | 'scaleX', 32 | 'scaleY', 33 | 'rotation', 34 | 'skewX', 35 | 'skewY', 36 | 'opacity', 37 | 'visible', 38 | 'zOrder', 39 | 'key', 40 | 'value', 41 | 'colorR', 42 | 'colorG', 43 | 'colorB', 44 | 'name', 45 | 'extraData' 46 | ]; 47 | 48 | function isRightProp(propName){ 49 | for(var i=0;i0){ 9 | for(var i=0;i0){ 27 | var parentOutline=util.getPName(parent)+'.outline'; 28 | var code=parentOutline+'.children={'; 29 | for(var i=0;i0){ 6 | var thisLevel=[]; 7 | for(var i=0;i0) 32 | sorted.push(thisLevel); 33 | } 34 | return sorted; 35 | }; 36 | 37 | module.exports.sort=sort; 38 | 39 | module.exports.getArray=function(obj){ 40 | var sorted=sort(obj); 41 | var array=[]; 42 | sorted.forEach(function(outlines){ 43 | outlines.forEach(function(outline){ 44 | array.push(outline); 45 | }); 46 | }); 47 | return array; 48 | } 49 | 50 | module.exports.bottomUp=(sorted)=>{ 51 | var newSorted=[]; 52 | for(var i=sorted.length-1;i>=0;i--){ 53 | newSorted.push(sorted[i]); 54 | } 55 | return newSorted; 56 | }; -------------------------------------------------------------------------------- /ccc-plugin/builder/util.js: -------------------------------------------------------------------------------- 1 | var util={}; 2 | 3 | /** 4 | * @method util.getPath 由creator中的资源路径转为2dx的资源路径 5 | * @param {String} path creator中的资源路径 6 | * @returns {String} 适用于2dx的资源路径 7 | */ 8 | util.getPath=function(path){ 9 | return path.substring(path.indexOf('/assets/')+8) 10 | } 11 | 12 | /** 13 | * @method util.getPName 获取该节点自导出节点开始的节点路径,从而获得一个唯一的名称 14 | * @param {"Object"} nodeData 节点数据 15 | * @returns {String} 包含自导出节点的完整路径的节点名称 16 | */ 17 | util.getPName=function(nodeData){ 18 | var name=nodeData.name; 19 | while(nodeData.parent){ 20 | name=nodeData.parent.name+'_'+name; 21 | nodeData=nodeData.parent; 22 | } 23 | return name; 24 | } 25 | 26 | /** 27 | * @method util.firstCaseUp 将传入的字符串的首字母转换为大写 28 | * @param {String} name 需要修改的字符串 29 | * @returns {String} 转换后的字符串 30 | */ 31 | util.firstCaseUp=function(name){ 32 | return name.substring(0,1).toUpperCase()+name.substring(1); 33 | } 34 | 35 | module.exports=util -------------------------------------------------------------------------------- /ccc-plugin/builder/writeFile.js: -------------------------------------------------------------------------------- 1 | var fs=require('fs'); 2 | 3 | module.exports=function(content,path,name,suffix,isAnimation){ 4 | var filepath; 5 | if(path==='out'){ 6 | filepath=Editor.projectPath+'/out'; 7 | if(!fs.existsSync(filepath)) 8 | fs.mkdirSync(filepath); 9 | filepath+='/'+name+'.'+suffix; 10 | }else if(path===''){ 11 | Editor.log('please input your dst hpp path'); 12 | }else{ 13 | filepath=path; 14 | } 15 | if(filepath){ 16 | 17 | //保留文尾用户自定义的内容 18 | const isUpdate=fs.existsSync(filepath); 19 | if(isUpdate){ 20 | const oldText=fs.readFileSync(filepath).toString(); 21 | const customIndex=oldText.indexOf('--outline-custom'); 22 | if(customIndex>0){ 23 | const customText=oldText.substring(customIndex); 24 | content+='\n'+customText; 25 | } 26 | }else{ 27 | content+='\n--outline-custom'; 28 | } 29 | 30 | fs.writeFile(filepath,content,(err)=>{ 31 | if(err){ 32 | Editor.error('dst path is error\n'+err); 33 | }else{ 34 | if(isAnimation) 35 | Editor.success('export animation '+name+' successfully'); 36 | else 37 | Editor.success('export node '+name+' successfully'); 38 | } 39 | }); 40 | } 41 | } -------------------------------------------------------------------------------- /ccc-plugin/catcher/Button.js: -------------------------------------------------------------------------------- 1 | var imageSource=require('./ImageSource'); 2 | var getValueStr=require('./ValueStr'); 3 | 4 | module.exports=function(node,typeInfo){ 5 | var com_button=node.getComponent(cc.Button); 6 | var com_sprite=node.getComponent(cc.Sprite); 7 | 8 | var spf_normal=com_button.normalSprite; 9 | if(!spf_normal){ 10 | spf_normal=com_sprite.spriteFrame; 11 | } 12 | if(spf_normal){ 13 | typeInfo.add('image_normal',getValueStr(spf_normal)); 14 | }else 15 | return; 16 | 17 | var spf_pressed=com_button.pressedSprite; 18 | if(spf_pressed){ 19 | typeInfo.add('buttonType',getValueStr(3)); 20 | typeInfo.add('image_pressed',getValueStr(spf_pressed)); 21 | }else{ 22 | typeInfo.add('buttonType',getValueStr(1)); 23 | } 24 | 25 | var spf_disabled=com_button.disabledSprite; 26 | if(spf_disabled){ 27 | typeInfo.add('image_disabled',getValueStr(spf_disabled)); 28 | } 29 | 30 | var enableAutoGrayEffect=com_button.enableAutoGrayEffect; 31 | if(enableAutoGrayEffect) 32 | typeInfo.add('btn_enableAutoGrayEffect',getValueStr(enableAutoGrayEffect)); 33 | } -------------------------------------------------------------------------------- /ccc-plugin/catcher/Catcher.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 本文件着重于获取节点的数据 3 | * 包括如何获取单个节点的数据 4 | * 以及如何遍历整个节点树的数据(使用递归) 5 | */ 6 | 7 | var Outline=require('./Outline'); 8 | var imageSource=require('./ImageSource'); 9 | 10 | var excludeNodes=null; 11 | 12 | /** 13 | * 遍历节点树时,处理单个节点的函数 14 | * @param {cc.Node} node 待获取数据的节点 15 | * @param {function} catchOne 获取数据的函数(node,parentResult),其中node为待获取数据的节点,parentResult为从父节点获取的数据 16 | * @param {any} parentResult 从父节点获取的数据 17 | */ 18 | function walkOneNode(node,catchOne,parentResult){ 19 | var exclude=false; 20 | if(excludeNodes){ 21 | excludeNodes.forEach(function(excludeNode){ 22 | if(excludeNode===node) 23 | exclude=true; 24 | }); 25 | } 26 | if(node && !exclude){ 27 | var result=catchOne(node,parentResult); 28 | var children=node.children; 29 | for(var i=0;i=0&&name.indexOf('>')>1){ 44 | name=name.substring(name.indexOf('<')+1,name.indexOf('>')); 45 | } 46 | if(componentNames[name]!==undefined){ 47 | componentNames[name+'_userData'].setUserDataName(name+'0'); 48 | componentNames[name]++; 49 | name=name+componentNames[name]; 50 | userData.setUserDataName(name); 51 | }else{ 52 | componentNames[name]=0; 53 | componentNames[name+'_userData']=userData; 54 | userData.setUserDataName(name); 55 | } 56 | } 57 | } 58 | 59 | module.exports=function(node,typeInfo){ 60 | var components=node._components; 61 | 62 | //get typeInfo 63 | for(var i=0;i0){ 73 | component.o__listview_background_insetTop=insetTop; 74 | } 75 | if(insetBottom>0){ 76 | component.o__listview_background_insetBottom=insetBottom; 77 | } 78 | if(insetLeft>0){ 79 | component.o__listview_background_insetLeft=insetLeft; 80 | } 81 | if(insetRight>0){ 82 | component.o__listview_background_insetRight=insetRight; 83 | } 84 | } 85 | } 86 | for(var propName in component){ 87 | typeInfo.addCustom(propName,component[propName]); 88 | } 89 | } 90 | 91 | //get userData 92 | var userDatas=[]; 93 | for(var i=0;i0){ 52 | if(valueStr.indexOf('-')!==0||fuNum!==1) 53 | isNum=false; 54 | } 55 | 56 | if(isNum){ 57 | if(dotNum===0) 58 | return 'int'; 59 | else if(dotNum===1) 60 | return 'float'; 61 | } 62 | } 63 | 64 | function isInt(value){ 65 | var type=getNumberType(value); 66 | if(type==='int') 67 | return true; 68 | else 69 | return false; 70 | } 71 | 72 | function isFloat(value){ 73 | var type=getNumberType(value); 74 | if(type==='float') 75 | return true; 76 | else 77 | return false; 78 | } 79 | 80 | function isSpriteFrame(value){ 81 | var toReturn=value instanceof cc.SpriteFrame; 82 | if (!toReturn && value && value.isSpriteFrame){ 83 | toReturn=true; 84 | } 85 | return toReturn; 86 | } 87 | 88 | function isFont(value){ 89 | return value instanceof cc.Font; 90 | } 91 | 92 | function isArray(value){ 93 | return value instanceof Array; 94 | } 95 | 96 | 97 | module.exports = function(value){ 98 | if(isVec2(value)){ 99 | return 'vec2'; 100 | }else if(isBool(value)){ 101 | return 'bool'; 102 | }else if(isInt(value)){ 103 | return 'int'; 104 | }else if(isFloat(value)){ 105 | return 'float'; 106 | }else if(isSize(value)){ 107 | return 'size'; 108 | }else if(isSpriteFrame(value)){ 109 | return 'spriteFrame'; 110 | }else if(isColor(value)){ 111 | return 'color'; 112 | }else if(isFont(value)){ 113 | return 'font'; 114 | }else if(value===null){ 115 | return 'null' 116 | }else 117 | return 'string'; 118 | } 119 | -------------------------------------------------------------------------------- /ccc-plugin/catcher/ValueStr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 本文件用来根据值,来获取代表该值的用来生成源码的string 3 | */ 4 | 5 | var getType=require('./Type'); 6 | var assetsExportor=require('../AssetsExportor'); 7 | var imageSource=require('./ImageSource'); 8 | 9 | function getIntStr(value){ 10 | return ''+value; 11 | } 12 | 13 | function getFloatStr(value,precision){ 14 | precision = precision || 4; 15 | var valueStr=''+value; 16 | var dotIndex=valueStr.indexOf('.'); 17 | if(dotIndex>=0){ 18 | var totalLength=valueStr.length; 19 | if(totalLength-(dotIndex+1)>precision){ 20 | valueStr=valueStr.substring(0,dotIndex+1+precision); 21 | value=parseFloat(valueStr); 22 | } 23 | } 24 | return ''+value; 25 | } 26 | 27 | function getVec2Str(value){ 28 | return 'Vec2('+value.x+','+value.y+')'; 29 | } 30 | 31 | function getSizeStr(value){ 32 | return 'Size('+value.width+','+value.y+')'; 33 | } 34 | 35 | function getColorStr(value){ 36 | return 'Color('+value.r+','+value.g+','+value.b+','+value.a+')'; 37 | } 38 | 39 | function getBoolStr(value){ 40 | return ''+value; 41 | } 42 | 43 | function getStringStr(value){ 44 | return '"'+value+'"'; 45 | } 46 | 47 | function getSpriteFrameStr(value){ 48 | return '"'+imageSource.getSpriteFrame(value)+'"'; 49 | } 50 | 51 | function getFontStr(font){ 52 | var str='{fontType='; 53 | if(font instanceof cc.LabelAtlas){ 54 | str+='"atlas"'; 55 | 56 | var spriteFrame=font.spriteFrame; 57 | assetsExportor.addFile(imageSource.getImagePath(spriteFrame)); 58 | 59 | str+=',atlas='+getSpriteFrameStr(spriteFrame); 60 | var temp=font._fntConfig.fontDefDictionary; 61 | var isFirst=true; 62 | for(var propName in temp){ 63 | var prop=temp[propName]; 64 | if(prop.rect){ 65 | if(isFirst){ 66 | str+=',startChar='+getValueStr(propName); 67 | str+=',itemWidth='+getValueStr(prop.rect.width); 68 | str+=',itemHeight='+getValueStr(prop.rect.height); 69 | str+='}'; 70 | isFirst=false 71 | } 72 | } 73 | } 74 | }else{ 75 | str+='"ttf"'; 76 | str+=',path="'+font.fontPath+'"'; 77 | str+='}'; 78 | assetsExportor.addFile(font.fontPath); 79 | } 80 | return str; 81 | } 82 | 83 | function getValueStr(value){ 84 | var type=getType(value); 85 | var valueStr; 86 | switch(type){ 87 | case 'int': 88 | valueStr=getIntStr(value); 89 | break; 90 | case 'float': 91 | valueStr=getFloatStr(value); 92 | break; 93 | case 'vec2': 94 | valueStr=getVec2Str(value); 95 | break; 96 | case 'size': 97 | valueStr=getSizeStr(value); 98 | break; 99 | case 'bool': 100 | valueStr=getBoolStr(value); 101 | break; 102 | case 'string': 103 | valueStr=getStringStr(value); 104 | break; 105 | case 'spriteFrame': 106 | valueStr=getSpriteFrameStr(value); 107 | break; 108 | case 'color': 109 | valueStr=getColorStr(value); 110 | break; 111 | case 'font': 112 | valueStr=getFontStr(value); 113 | break; 114 | } 115 | return valueStr; 116 | } 117 | 118 | module.exports=getValueStr; -------------------------------------------------------------------------------- /ccc-plugin/catcher/Widget.js: -------------------------------------------------------------------------------- 1 | var getValueStr=require('./ValueStr'); 2 | 3 | var UNITTYPE_PX=1 4 | var UNITTYPE_RATE=2 5 | 6 | function cloneWidget(widget){ 7 | var newWidget=new cc.Widget(); 8 | for(var propName in widget){ 9 | newWidget[propName]=widget[propName]; 10 | } 11 | return newWidget; 12 | } 13 | 14 | module.exports=function(node,typeInfo){ 15 | var widget=node.getComponent(cc.Widget); 16 | 17 | //In order to get the origin size of this node,we need to change properties of its widget. 18 | //Before doing this,we have to clone the origin widget as a backup. 19 | //So after the size is got,we can restore the widget. 20 | var temp=cloneWidget(widget); 21 | 22 | if(widget){ 23 | typeInfo.add('hasWidget',getValueStr(true)); 24 | 25 | var isAlignLeft=widget.isAlignLeft; 26 | var isAlignRight=widget.isAlignRight; 27 | var isAlignTop=widget.isAlignTop; 28 | var isAlignBottom=widget.isAlignBottom; 29 | var isAlignHorizontalCenter=widget.isAlignHorizontalCenter; 30 | var horizontalCenter=widget.horizontalCenter; 31 | var isAbsoluteHorizontalCenter=widget.isAbsoluteHorizontalCenter; 32 | var verticalCenter=widget.verticalCenter; 33 | var isAbsoluteVerticalCenter=widget.isAbsoluteVerticalCenter; 34 | var isAlignVerticalCenter=widget.isAlignVerticalCenter; 35 | var left=widget.left; 36 | var right=widget.right; 37 | var top=widget.top; 38 | var bottom=widget.bottom; 39 | var isAbsoluteBottom=widget.isAbsoluteBottom; 40 | var isAbsoluteLeft=widget.isAbsoluteLeft; 41 | var isAbsoluteTop=widget.isAbsoluteTop; 42 | var isAbsoluteRight=widget.isAbsoluteRight; 43 | 44 | if(isAlignBottom&&isAlignTop){ 45 | var heightTemp=node.height; 46 | widget.isAlignBottom=false; 47 | typeInfo.add('widget_originHeight',getValueStr(node.height)); 48 | node.height=heightTemp; 49 | } 50 | 51 | if(isAlignLeft&&isAlignRight){ 52 | var widthTemp=node.width; 53 | widget.isAlignLeft=false; 54 | typeInfo.add('widget_originWidth',getValueStr(node.width)); 55 | node.width=widthTemp; 56 | } 57 | 58 | for(var propName in widget){ 59 | widget[propName]=temp[propName]; 60 | } 61 | 62 | if(isAlignHorizontalCenter){ 63 | typeInfo.add('widget_AHCenter',getValueStr(true)); 64 | typeInfo.add('widget_HCenter',getValueStr(horizontalCenter)); 65 | var unit_horizontalCenter=isAbsoluteHorizontalCenter?UNITTYPE_PX:UNITTYPE_RATE; 66 | typeInfo.add('widget_UHCenter',getValueStr(unit_horizontalCenter)); 67 | }else{ 68 | if(isAlignLeft){ 69 | typeInfo.add('widget_ALeft',getValueStr(true)); 70 | typeInfo.add('widget_left',getValueStr(left)); 71 | var unit_left=isAbsoluteLeft?UNITTYPE_PX:UNITTYPE_RATE; 72 | typeInfo.add('widget_unit_left',getValueStr(unit_left)); 73 | } 74 | 75 | if(isAlignRight){ 76 | typeInfo.add('widget_ARight',getValueStr(true)); 77 | typeInfo.add('widget_right',getValueStr(right)); 78 | var unit_right=isAbsoluteRight?UNITTYPE_PX:UNITTYPE_RATE; 79 | typeInfo.add('widget_unit_right',getValueStr(unit_right)); 80 | } 81 | } 82 | 83 | if(isAlignVerticalCenter){ 84 | typeInfo.add('widget_AVCenter',getValueStr(true)); 85 | typeInfo.add('widget_VCenter',getValueStr(verticalCenter)); 86 | var unit_verticalCenter=isAbsoluteVerticalCenter?UNITTYPE_PX:UNITTYPE_RATE; 87 | typeInfo.add('widget_UVCenter',getValueStr(unit_verticalCenter)); 88 | }else{ 89 | if(isAlignBottom){ 90 | typeInfo.add('widget_ABottom',getValueStr(true)); 91 | typeInfo.add('widget_bottom',getValueStr(bottom)); 92 | var unit_bottom=isAbsoluteBottom?UNITTYPE_PX:UNITTYPE_RATE; 93 | typeInfo.add('widget_unit_bottom',getValueStr(unit_bottom)); 94 | } 95 | 96 | if(isAlignTop){ 97 | typeInfo.add('widget_ATop',getValueStr(true)); 98 | typeInfo.add('widget_top',getValueStr(top)); 99 | var unit_top=isAbsoluteTop?UNITTYPE_PX:UNITTYPE_RATE; 100 | typeInfo.add('widget_unit_top',getValueStr(unit_top)); 101 | } 102 | } 103 | } 104 | } -------------------------------------------------------------------------------- /ccc-plugin/components/AnimationRecorder.js: -------------------------------------------------------------------------------- 1 | //用于记录node在每一帧的状态 2 | function Status(node){ 3 | this.x=node.x; 4 | this.y=node.y; 5 | this.scaleX=node.scaleX; 6 | this.scaleY=node.scaleY; 7 | this.rotation=node.rotation; 8 | this.width=node.width; 9 | this.height=node.height; 10 | this.colorR=node.color.getR(); 11 | this.colorG=node.color.getG(); 12 | this.colorB=node.color.getB(); 13 | this.opacity=node.opacity; 14 | this.anchorX=node.anchorX; 15 | this.anchorY=node.anchorY; 16 | this.skewX=node.skewX; 17 | this.skewY=node.skewY; 18 | var sprite=node.getComponent(cc.Sprite); 19 | if(sprite){ 20 | this.spriteFrame=sprite.spriteFrame; 21 | } 22 | } 23 | 24 | //用于对得到的increment进行校验修正 25 | function Proofread(){ 26 | this.keyIncrements=[]; 27 | this.add=function(incrementIndex,proofread){ 28 | this.keyIncrements.push({ 29 | keyIndex:incrementIndex, 30 | proofread:proofread 31 | }); 32 | }; 33 | this.proofread=function(increments,propName){ 34 | //先把静止帧定义为0 35 | for(var i=0;i0?1:-1; 108 | var absolute=totalOffset; 109 | if(absolute<0) 110 | absolute=-absolute; 111 | var reduce=numOfIncrement/absolute; 112 | var k=keyIndex; 113 | while(absolute>0){ 114 | var index=parseInt(k); 115 | increments[index][propName]=increments[index][propName]+eachOffset; 116 | k-=reduce; 117 | absolute--; 118 | } 119 | } 120 | j=i; 121 | } 122 | var increment=0; 123 | for(var i=0;i1){ 144 | rgb.forEach(function(suffix){ 145 | var proofreadobj=this.proofreads[propName+suffix.toUpperCase()]=new Proofread(); 146 | for(var i=1;i1){ 158 | var proofreadobjx=this.proofreads.x=new Proofread(); 159 | var proofreadobjy=this.proofreads.y=new Proofread(); 160 | for(var i=1;i1){ 173 | var proofreadobj=this.proofreads[propName]=new Proofread(); 174 | for(var i=1;i0){ 216 | this.clip=clips[0]; 217 | this.clipName=this.clip.name; 218 | this.startRecord(this.clip); 219 | } 220 | } 221 | }, 222 | getIncrements:function(){ 223 | for(var i=0;i0.000005) 246 | increment[propName]=value; 247 | } 248 | } 249 | } 250 | increments.push(increment); 251 | } 252 | 253 | //矫正帧数 254 | var numOfFrame=Math.round(this.clip.sample*this.clip._duration-1); 255 | cc.log(increments.length+','+numOfFrame); 256 | if(increments.length>numOfFrame){ 257 | var head=true; 258 | while(increments.length>numOfFrame){ 259 | if(head){ 260 | increments.shift(); 261 | head=false; 262 | }else{ 263 | increments.pop(); 264 | head=true; 265 | } 266 | } 267 | }else if(increments.length0){ 310 | for(var i=0;i{ 8 | ws.on('message',(msg)=>{ 9 | if(preMsg!=msg){ 10 | var anim=JSON.parse(msg); 11 | luaBuilder.buildAnimation(anim); 12 | preMsg=msg; 13 | } 14 | }); 15 | }); 16 | }, 17 | 18 | unload () { 19 | // 当 package 被正确卸载的时候执行 20 | }, 21 | messages: { 22 | //弹出选择export rule的界面 23 | 'start-export-node' () { 24 | Editor.Panel.open('outline'); 25 | }, 26 | 'export-all-rule' () { 27 | Editor.Scene.callSceneScript('outline', 'getNode','export-all-rule',Editor.projectPath,function (data) { 28 | var dataObj=JSON.parse(data); 29 | for(var i=0;i 2 | 3 | export setting 4 | 5 | 14 | 15 | 16 | 17 |

18 | 19 |    20 | 21 |

22 |
23 |
24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /ccc-plugin/panel/index.js: -------------------------------------------------------------------------------- 1 | var ids=[]; 2 | var ruleNames=[]; 3 | function getId(ruleName){ 4 | var id=ids.length; 5 | ids.push(id); 6 | ruleNames.push(ruleName); 7 | return id; 8 | } 9 | function getHtml(ruleName,src,dst){ 10 | var html='

'+ruleName+'  src='+src+'  dst='+dst+'

'; 11 | console.log(html); 12 | return html; 13 | } 14 | var rulesNode=document.getElementById('rules'); 15 | 16 | function initData(data){ 17 | ids=[]; 18 | ruleNames=[]; 19 | var html=''; 20 | for(var i=0;i { 45 | var selected=[]; 46 | for(var i=0;i0) 53 | Editor.Ipc.sendToMain('outline:export-node',JSON.stringify(selected)); 54 | else 55 | Editor.error('pelease select an export rule'); 56 | }); 57 | 58 | var btn_selectAll=document.getElementById('selectAll'); 59 | btn_selectAll.addEventListener('click', () => { 60 | for(var i=0;i{ 3 | var pre=[obj]; 4 | var sorted=[pre]; 5 | while(pre.length>0){ 6 | var thisLevel=[]; 7 | for(var i=0;i0) 30 | sorted.push(thisLevel); 31 | } 32 | return sorted; 33 | }; 34 | 35 | module.exports.bottomUp=(sorted)=>{ 36 | var newSorted=[]; 37 | for(var i=sorted.length-1;i>=0;i--){ 38 | newSorted.push(sorted[i]); 39 | } 40 | return newSorted; 41 | }; -------------------------------------------------------------------------------- /lua-interpret/BtnFactory.lua: -------------------------------------------------------------------------------- 1 | local function isTouchInSprite(node,touch,scaleX,scaleY) 2 | local x = touch:getLocation().x; 3 | local y = touch:getLocation().y; 4 | 5 | local size = node:getContentSize(); 6 | size.width = size.width * scaleX; 7 | size.height = size.height * scaleY; 8 | 9 | local anchorX = node:getAnchorPoint().x; 10 | local anchorY = node:getAnchorPoint().y; 11 | local pos = node:getParent():convertToWorldSpace(cc.p(node:getPositionX(),node:getPositionY())); 12 | 13 | local x1 = pos.x - size.width*anchorX; 14 | local x2 = pos.x + size.width*(1-anchorX); 15 | local y1 = pos.y - size.height*anchorY; 16 | local y2 = pos.y + size.height*(1-anchorY); 17 | return x >= x1 and x <= x2 and y >= y1 and y <= y2; 18 | end 19 | 20 | outlineprivate_btnFactory={} 21 | 22 | function outlineprivate_btnFactory.autoGray(node) 23 | local vsh= "attribute vec4 a_position;\n" 24 | .."attribute vec2 a_texCoord;\n" 25 | .."attribute vec4 a_color;\n" 26 | .."#ifdef GL_ES\n" 27 | .."varying lowp vec4 v_fragmentColor;\n" 28 | .."varying mediump vec2 v_texCoord;\n" 29 | .."#else\n" 30 | .."varying vec4 v_fragmentColor;\n" 31 | .."varying vec2 v_texCoord;\n" 32 | .."#endif\n" 33 | .."void main() {\n" 34 | .." gl_Position = CC_PMatrix* a_position;\n" 35 | .." v_fragmentColor= a_color;\n" 36 | .." v_texCoord = a_texCoord;\n" 37 | .."}" 38 | local fsh_gray= 39 | "varying vec4 v_fragmentColor;\n" 40 | .."varying vec2 v_texCoord;\n" 41 | .."void main() {\n" 42 | .." vec4 mycolor = v_fragmentColor*texture2D(CC_Texture0, v_texCoord);\n" 43 | .." float gray = dot(mycolor.rgb, vec3(0.2126, 0.7152, 0.0722));\n" 44 | .." gl_FragColor = vec4(gray);\n" 45 | .." gl_FragColor.a = mycolor.a;\n" 46 | .."}" 47 | local fsh_normal= 48 | "varying vec4 v_fragmentColor;\n" 49 | .."varying vec2 v_texCoord;\n" 50 | .."void main() {\n" 51 | .." gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);\n" 52 | .."}" 53 | local setEnabled=node.setEnabled 54 | node.setEnabled=function(self,enable) 55 | local fsh 56 | if(enable)then 57 | fsh=fsh_normal 58 | else 59 | fsh=fsh_gray 60 | end 61 | local prog = cc.GLProgram:createWithByteArrays(vsh,fsh) 62 | prog:link() 63 | prog:updateUniforms() 64 | local progStat= cc.GLProgramState:getOrCreateWithGLProgram(prog) 65 | self:setGLProgramState(progStat) 66 | if(setEnabled)then 67 | setEnabled(self,enable) 68 | end 69 | end 70 | end 71 | 72 | function outlineprivate_btnFactory.processBtn(node,onPressed,onPressEnd) 73 | if(not node)then 74 | return nil 75 | end 76 | 77 | local listener = cc.EventListenerTouchOneByOne:create() 78 | node.btn_status=outlineprivate_btnFactory.BTN_STATUS_NORMAL 79 | node.btn_isPressed=false 80 | node.btn_onClick=nil 81 | node.btn_originScaleX=node:getScaleX() 82 | node.btn_originScaleY=node:getScaleY() 83 | 84 | local function onTouchBegan(touch,event) 85 | if(not node:isVisible())then 86 | return false 87 | end 88 | if(node.btn_status==outlineprivate_btnFactory.BTN_STATUS_DISABLED or node.btn_isPressed)then 89 | return false 90 | else 91 | node.btn_realScaleX,node.btn_realScaleY=getScale(node) 92 | if(isTouchInSprite(node,touch,node.btn_realScaleX,node.btn_realScaleY))then 93 | if(node.needSwallowTouch)then 94 | listener:setSwallowTouches(true) 95 | end 96 | node.btn_isPressed=true 97 | 98 | --用于确定滑动 99 | local pos = node:getParent():convertToWorldSpace(cc.p(node:getPositionX(),node:getPositionY())); 100 | local beginX=pos.x--需要先转化坐标 101 | local beginY=pos.y--需要先转化坐标 102 | local beginSize=node:getContentSize() 103 | local beginAnchor=node:getAnchorPoint() 104 | local beginLeft=beginX-beginSize.width*beginAnchor.x 105 | local beginBottom=beginY-beginSize.height*beginAnchor.y 106 | node.touchBeginRect={ 107 | left=beginLeft, 108 | bottom=beginBottom, 109 | width=beginSize.width, 110 | height=beginSize.height 111 | } 112 | 113 | onPressed(node) 114 | if(node.onPressed)then 115 | node.btn_status=outlineprivate_btnFactory.BTN_STATUS_PRESSED 116 | node.onPressed(node.btn_para1,node.btn_para2) 117 | end 118 | end 119 | end 120 | return true; 121 | end 122 | 123 | local function onTouchCancelled(touch,event) 124 | listener:setSwallowTouches(false) 125 | if(not node:isVisible())then 126 | return 127 | end 128 | if(node.btn_isPressed)then 129 | onPressEnd(node) 130 | if(node.onPressUp)then 131 | node.btn_status=outlineprivate_btnFactory.BTN_STATUS_NORMAL 132 | node.onPressUp(node.btn_para1,node.btn_para2) 133 | end 134 | end 135 | end 136 | 137 | local function onTouchEnded(touch,event) 138 | listener:setSwallowTouches(false) 139 | if(not node:isVisible())then 140 | return 141 | end 142 | if(node.btn_isPressed)then 143 | onPressEnd(node) 144 | if(node.onPressUp)then 145 | node.btn_status=outlineprivate_btnFactory.BTN_STATUS_NORMAL 146 | node.onPressUp(node.btn_para1,node.btn_para2) 147 | end 148 | if(isTouchInSprite(node,touch,node.btn_realScaleX,node.btn_realScaleY))then 149 | if(node.btn_onClick)then 150 | node.btn_onClick(node.btn_para1,node.btn_para2) 151 | end 152 | end 153 | end 154 | end 155 | 156 | local function onTouchMoved(touch,event) 157 | if(not node:isVisible())then 158 | return 159 | end 160 | if(node.btn_isPressed)then 161 | local cancel=not isTouchInSprite(node,touch,node.btn_realScaleX,node.btn_realScaleY) 162 | if(node.cancelWhenScroll)then 163 | local x = touch:getLocation().x 164 | local y = touch:getLocation().y 165 | local r=node.touchBeginRect 166 | cancel=xr.left+r.width or yr.bottom+r.height 167 | end 168 | if(cancel)then 169 | listener:setSwallowTouches(false) 170 | onPressEnd(node) 171 | node.btn_isPressed=false 172 | if(node.onPressUp)then 173 | node.btn_status=outlineprivate_btnFactory.BTN_STATUS_NORMAL 174 | node.onPressUp(node.btn_para1,node.btn_para2) 175 | end 176 | end 177 | end 178 | end 179 | 180 | listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN) 181 | listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED) 182 | listener:registerScriptHandler(onTouchCancelled,cc.Handler.EVENT_TOUCH_CANCELLED) 183 | listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED) 184 | 185 | local eventDispatcher = node:getEventDispatcher() 186 | eventDispatcher:addEventListenerWithSceneGraphPriority(listener, node) 187 | 188 | function node:setOnClick(onClick,para1,para2) 189 | node.btn_onClick=onClick 190 | node.btn_para1=para1 191 | node.btn_para2=para2 192 | end 193 | 194 | function node:setEnable(enable) 195 | if not enable then 196 | node.btn_status=outlineprivate_btnFactory.BTN_STATUS_DISABLED 197 | if node.image_disabled then 198 | setSPF(node,node.image_disabled) 199 | end 200 | else 201 | node.btn_status=outlineprivate_btnFactory.BTN_STATUS_NORMAL 202 | if node.image_normal then 203 | setSPF(node,node.image_normal) 204 | end 205 | end 206 | end 207 | 208 | function node:setOnPressed(onPressed,para1,para2) 209 | node.onPressed=onPressed 210 | node.btn_para1=para1 211 | node.btn_para2=para2 212 | end 213 | 214 | function node:setOnPressUp(onPressUp,para1,para2) 215 | node.onPressUp=onPressUp 216 | node.btn_para1=para1 217 | node.btn_para2=para2 218 | end 219 | end 220 | 221 | function outlineprivate_btnFactory.processScaleBtn(node) 222 | local function onPressed(node) 223 | local action=cc.EaseExponentialInOut:create(cc.ScaleBy:create(0.06,0.75)) 224 | node:runAction(action) 225 | end 226 | 227 | local function callback(args) 228 | node.btn_isPressed=false 229 | node:setScaleX(node.btn_originScaleX) 230 | node:setScaleY(node.btn_originScaleY) 231 | end 232 | 233 | local function onPressEnd(node) 234 | local action=cc.Sequence:create( 235 | cc.EaseExponentialInOut:create(cc.ScaleTo:create(0.2,node.btn_originScaleX,node.btn_originScaleY)), 236 | cc.CallFunc:create(callback) 237 | ) 238 | node:runAction(action) 239 | end 240 | 241 | outlineprivate_btnFactory.processBtn(node, onPressed, onPressEnd); 242 | end 243 | 244 | function outlineprivate_btnFactory.processColorBtn(node) 245 | local function onPressed(node) 246 | node.btn_color=node:getColor() 247 | node:setColor(cc.c3b(102, 95, 75)); 248 | end 249 | local function onPressEnd(node) 250 | node:setColor(node.btn_color or cc.c3b(255, 255, 255)); 251 | node.btn_isPressed = false; 252 | end 253 | outlineprivate_btnFactory.processBtn(node, onPressed, onPressEnd); 254 | end 255 | 256 | function outlineprivate_btnFactory.processSpriteBtn(node) 257 | local function onPressed(node) 258 | setSPF(node,node.image_pressed) 259 | end 260 | 261 | local function onPressEnd(node) 262 | setSPF(node,node.image_normal) 263 | node.btn_isPressed=false 264 | end 265 | 266 | function node:resetSpriteSrc(normal,pressed,disable) 267 | if normal then 268 | node.image_normal=normal 269 | if node.btn_status==outlineprivate_btnFactory.BTN_STATUS_NORMAL then 270 | setSPF(node,node.image_normal) 271 | end 272 | end 273 | if pressed then 274 | node.image_pressed=pressed 275 | if node.btn_status==outlineprivate_btnFactory.BTN_STATUS_PRESSED then 276 | setSPF(node,node.image_pressed) 277 | end 278 | end 279 | if disable then 280 | node.image_disabled=disable 281 | if node.btn_status==outlineprivate_btnFactory.BTN_STATUS_DISABLED then 282 | setSPF(node,node.image_disabled) 283 | end 284 | end 285 | end 286 | 287 | outlineprivate_btnFactory.processBtn(node, onPressed, onPressEnd); 288 | end 289 | 290 | function outlineprivate_btnFactory.processSelectBtn(node) 291 | outlineprivate_btnFactory.processScaleBtn(node) 292 | 293 | function node:setOnSelect(onSelect) 294 | self.onSelect=onSelect 295 | return self 296 | end 297 | function node:setOnUnSelect(onUnSelect) 298 | self.onUnSelect=onUnSelect 299 | return self 300 | end 301 | 302 | node.isSelected=false 303 | function node:setSelect() 304 | self.isSelected=true 305 | local child=node:getChildByName('selected') 306 | if(child)then 307 | child:setVisible(true) 308 | end 309 | if(self.onSelect)then 310 | self.onSelect(self) 311 | end 312 | return self 313 | end 314 | function node:setUnSelect() 315 | self.isSelected=false 316 | local child=node:getChildByName('selected') 317 | if(child)then 318 | child:setVisible(false) 319 | end 320 | if(self.onUnSelect)then 321 | self.onUnSelect(self) 322 | end 323 | return self 324 | end 325 | 326 | function node:setSelected(selected) 327 | if(selected)then 328 | self:setSelect() 329 | else 330 | self:setUnSelect() 331 | end 332 | return self 333 | end 334 | 335 | node:setOnClick(function() 336 | if(node.isSelected)then 337 | node:setUnSelect() 338 | else 339 | node:setSelect() 340 | end 341 | end) 342 | end 343 | 344 | function outlineprivate_btnFactory.processNoneBtn(node) 345 | local function onPressed(node) 346 | end 347 | local function onPressEnd(node) 348 | node.btn_isPressed=false 349 | end 350 | outlineprivate_btnFactory.processBtn(node, onPressed, onPressEnd); 351 | end 352 | 353 | outlineprivate_btnFactory.BUTTONTYPE_SCALE=1 354 | outlineprivate_btnFactory.BUTTONTYPE_COLOR=2 355 | outlineprivate_btnFactory.BUTTONTYPE_SPRITE=3 356 | outlineprivate_btnFactory.BUTTONTYPE_SELECT=4 357 | outlineprivate_btnFactory.BUTTONTYPE_NONE=5 358 | 359 | outlineprivate_btnFactory.BTN_STATUS_NORMAL=6 360 | outlineprivate_btnFactory.BTN_STATUS_PRESSED=7 361 | outlineprivate_btnFactory.BTN_STATUS_DISABLED=8 362 | 363 | return outlineprivate_btnFactory 364 | -------------------------------------------------------------------------------- /lua-interpret/RadioGroup.lua: -------------------------------------------------------------------------------- 1 | --传入的btn类型只能为SpriteButton 2 | --ButtonGroup包括多选按钮组和单选按钮组,把button的pressed状态作为选中状态,normal状态为未选中状态 3 | local function newRadioGroup() 4 | local btnGroup={ 5 | _btns={}, 6 | _selectedBtn=nil 7 | } 8 | 9 | --如果addMember后再调用btn:setOnClick,btnGroup将失去效果 10 | function btnGroup:addMember(btn) 11 | local this=self 12 | table.insert(self._btns,btn) 13 | local oldOnClick=btn.btn_onClick 14 | local newOnClick=function(para1,para2) 15 | setSPF(btn,btn.image_pressed) 16 | if btn==this._selectedBtn then 17 | return 18 | end 19 | this:onClickMember(btn) 20 | oldOnClick(btn,para1,para2) 21 | end 22 | btn:setOnClick(newOnClick,btn.btn_para1,btn.btn_para2) 23 | return btnGroup 24 | end 25 | 26 | function btnGroup:onClickMember(btn) 27 | if self._selectedBtn then 28 | setSPF(self._selectedBtn,self._selectedBtn.image_normal) 29 | end 30 | self._selectedBtn=btn 31 | end 32 | 33 | function btnGroup:getSelect() 34 | return self._selectedBtn 35 | end 36 | 37 | return btnGroup 38 | end 39 | 40 | return newRadioGroup 41 | -------------------------------------------------------------------------------- /lua-interpret/createNode.lua: -------------------------------------------------------------------------------- 1 | local EMITTERMODE_GRAVITY=0 2 | local EMITTERMODE_RADIUS=1 3 | 4 | local function createEditBox(outline) 5 | local extraData=outline.extraData 6 | 7 | local back=extraData.editbox_backgroundImage 8 | if(back)then 9 | local backSprite=ccui.Scale9Sprite:createWithSpriteFrame(getFrame(back)) 10 | 11 | local width=extraData.editbox_width 12 | if(nil==width)then 13 | width=0 14 | end 15 | local height=extraData.editbox_height 16 | if(nil==height)then 17 | height=0 18 | end 19 | 20 | local editBox=ccui.EditBox:create(cc.size(width,height),backSprite) 21 | 22 | local inputMode=extraData.editbox_inputMode or cc.EDITBOX_INPUT_MODE_SINGLELINE 23 | editBox:setInputMode(inputMode) 24 | 25 | local fontSize=extraData.editbox_fontSize 26 | if(nil~=fontSize)then 27 | editBox:setFontSize(fontSize) 28 | end 29 | 30 | local color=extraData.editbox_fontColor 31 | if(nil ~=color )then 32 | editBox:setFontColor(color) 33 | end 34 | 35 | local str=extraData.editbox_string 36 | if(nil ~= str)then 37 | editBox:setText('' .. str) 38 | end 39 | 40 | local placeholder=extraData.editbox_placeholder 41 | if(nil~=placeholder)then 42 | editBox:setPlaceHolder('' .. placeholder) 43 | end 44 | 45 | local placeholderFontSize=extraData.editbox_placeholderFontSize 46 | if(nil~=placeholderFontSize)then 47 | editBox:setPlaceholderFontSize(placeholderFontSize) 48 | end 49 | 50 | local maxLength=extraData.editbox_maxLength 51 | if(nil~=maxLength)then 52 | editBox:setMaxLength(maxLength) 53 | end 54 | 55 | local inputFlag=extraData.editbox_inputFlag 56 | if(nil~=inputFlag)then 57 | editBox:setInputFlag(inputFlag) 58 | end 59 | 60 | return editBox 61 | end 62 | end 63 | 64 | local function createProgressBar(outline) 65 | local extraData=outline.extraData 66 | 67 | local horizontal=false 68 | if(extraData.progressbar_mode==0)then 69 | horizontal=true 70 | end 71 | 72 | local percent=extraData.progressbar_progress*100 73 | local reverse=extraData.progressbar_reverse 74 | local spriteFrame=extraData.progressbar_spriteFrame 75 | 76 | local sprite=cc.Sprite:createWithSpriteFrame(getFrame(spriteFrame)) 77 | local progressbar = cc.ProgressTimer:create(sprite) 78 | progressbar:setType(cc.PROGRESS_TIMER_TYPE_BAR) 79 | 80 | if(horizontal and not reverse)then 81 | progressbar:setMidpoint(cc.p(0,0.5)) 82 | progressbar:setBarChangeRate(cc.p(1,0)) 83 | elseif(not horizontal and not reverse)then 84 | progressbar:setMidpoint(cc.p(0.5,0)) 85 | progressbar:setBarChangeRate(cc.p(0,1)) 86 | elseif(horizontal and reverse)then 87 | progressbar:setMidpoint(cc.p(1,0.5)) 88 | progressbar:setBarChangeRate(cc.p(1,0)) 89 | else 90 | progressbar:setMidpoint(cc.p(0.5,1)) 91 | progressbar:setBarChangeRate(cc.p(0,1)) 92 | end 93 | 94 | progressbar:setPercentage(percent) 95 | 96 | return progressbar 97 | end 98 | 99 | local function createSprite(outline) 100 | 101 | local extraData=outline.extraData 102 | local spriteFrame=extraData.sprite_spriteFrame 103 | 104 | local index=string.find(spriteFrame,'splash.png') 105 | if(index)then 106 | return 107 | end 108 | 109 | local frame=getFrame(spriteFrame) 110 | if(not frame)then 111 | return 112 | end 113 | 114 | if(extraData.sprite_isSliced)then 115 | local scale9 116 | scale9=cc.Scale9Sprite:createWithSpriteFrame(frame) 117 | scale9:setInsetBottom(extraData.sprite_insetBottom) 118 | scale9:setInsetLeft(extraData.sprite_insetLeft) 119 | scale9:setInsetRight(extraData.sprite_insetRight) 120 | scale9:setInsetTop(extraData.sprite_insetTop) 121 | return scale9 122 | else 123 | return cc.Sprite:createWithSpriteFrame(frame) 124 | end 125 | end 126 | 127 | local function createLabel(outline) 128 | local extraData=outline.extraData 129 | local label 130 | local label_string 131 | if(nil~=extraData.label_string)then 132 | label_string='' .. extraData.label_string 133 | else 134 | label_string='' 135 | end 136 | local font=extraData.label_font 137 | if(font)then 138 | local fontType=font.fontType 139 | if(fontType=="atlas")then 140 | local startChar=font.startChar 141 | local atlas=font.atlas 142 | local width=font.itemWidth 143 | local height=font.itemHeight 144 | label=cc.LabelAtlas:_create(label_string,atlas,width,height,startChar) 145 | elseif(fontType=="ttf")then 146 | label=cc.Label:createWithTTF(label_string,font.path,extraData.label_fontSize) 147 | if(extraData.label_overflow==1)then 148 | label:setMaxLineWidth(outline.width) 149 | end 150 | end 151 | else 152 | if(nil~=extraData.label_overflow)then 153 | local dimession=cc.size(outline.width,outline.height) 154 | label = cc.Label:createWithSystemFont(label_string,'Arial',extraData.label_fontSize,dimession) 155 | else 156 | label = cc.Label:createWithSystemFont(label_string,'Arial',extraData.label_fontSize) 157 | end 158 | end 159 | 160 | local horizontalAlign=extraData.label_horizontalAlign or 1 161 | if label.setHorizontalAlignment then 162 | label:setHorizontalAlignment(horizontalAlign) 163 | end 164 | local verticalAlign=extraData.label_verticalAlign or 1 165 | if label.setVerticalAlignment then 166 | label:setVerticalAlignment(verticalAlign) 167 | end 168 | 169 | return label 170 | end 171 | 172 | local function createParticleSystem(outline) 173 | local extraData=outline.extraData 174 | 175 | local ps=cc.ParticleSystemQuad:create(extraData.ps_file) 176 | ps:setAutoRemoveOnFinish(true) 177 | if(extraData.ps_texture)then 178 | local temp=display.newSprite(extraData.ps_texture) 179 | ps:setTexture(temp:getTexture()) 180 | end 181 | if(extraData.ps_custom)then 182 | ps:setEmissionRate(extraData.ps_emissionRate) 183 | ps:setLife(extraData.ps_life) 184 | ps:setLifeVar(extraData.ps_lifeVar) 185 | ps:setDuration(extraData.ps_duration) 186 | ps:setTotalParticles(extraData.ps_totalParticles) 187 | ps:setStartColor(extraData.ps_startColor) 188 | ps:setStartColorVar(extraData.ps_startColorVar) 189 | ps:setEndColor(extraData.ps_endColor) 190 | ps:setEndColorVar(extraData.ps_endColorVar) 191 | ps:setAngle(extraData.ps_angle) 192 | ps:setStartSize(extraData.ps_startSize) 193 | ps:setEndSize(extraData.ps_endSize) 194 | ps:setStartSpin(extraData.ps_startSpin) 195 | ps:setEndSpin(extraData.ps_endSpin) 196 | ps:setAngleVar(extraData.ps_angleVar) 197 | ps:setStartSizeVar(extraData.ps_startSizeVar) 198 | ps:setEndSizeVar(extraData.ps_endSizeVar) 199 | ps:setStartSpinVar(extraData.ps_startSpinVar) 200 | ps:setEndSpinVar(extraData.ps_endSpinVar) 201 | ps:setLifeVar(extraData.ps_lifeVar) 202 | ps:setSourcePosition(extraData.ps_sourcePos) 203 | ps:setPosVar(extraData.ps_posVar) 204 | 205 | local temp=extraData.ps_positionType 206 | local positionType = cc.POSITION_TYPE_FREE 207 | if (temp == 2)then 208 | positionType = cc.POSITION_TYPE_RELATIVE; 209 | elseif (temp == 3)then 210 | positionType = cc.POSITION_TYPE_GROUPED; 211 | end 212 | ps:setPositionType(positionType) 213 | ps:setEmitterMode(extraData.ps_emitterMode); 214 | 215 | if(extraData.ps_emitterMode==EMITTERMODE_GRAVITY)then 216 | ps:setSpeed(extraData.ps_speed) 217 | ps:setSpeedVar(extraData.ps_speedVar) 218 | ps:setTangentialAccel(extraData.ps_tangentialAccel) 219 | ps:setTangentialAccelVar(extraData.ps_tangentialAccelVar) 220 | ps:setRadialAccel(extraData.ps_radialAccel) 221 | ps:setRotationIsDir(extraData.ps_rotationIsDir) 222 | ps:setGravity(extraData.ps_gravity) 223 | elseif(extraData.ps_emitterMode==EMITTERMODE_RADIUS)then 224 | ps:setStartRadius(extraData.ps_startRadius) 225 | ps:setStartRadiusVar(extraData.ps_startRadiusVar) 226 | ps:setEndRadius(extraData.ps_endRadius) 227 | ps:setEndRadiusVar(extraData.ps_endRadiusVar); 228 | ps:setRotatePerSecond(extraData.ps_rotatePerS); 229 | ps:setRotatePerSecondVar(extraData.ps_rotatePerSVar); 230 | end 231 | end 232 | return ps 233 | end 234 | 235 | local function createListview(creator) 236 | local outline=creator.outline 237 | local extraData=outline.extraData 238 | 239 | local listview=ccui.ListView:create() 240 | function listview:pushbackBySample(para) 241 | if(self.getItemBySample)then 242 | local item=self:getItemBySample(para) 243 | local size=item:getContentSize() 244 | local anchor=item:getAnchorPoint() 245 | item:move(cc.p(size.width*anchor.x,size.height*anchor.y)) 246 | local widget=ccui.Widget:create() 247 | widget:setContentSize(size) 248 | widget:addChild(item) 249 | self:pushBackCustomItem(widget) 250 | end 251 | end 252 | 253 | if(extraData.listview_background)then 254 | local sep=string.find(extraData.listview_background,'%:') 255 | if(sep and sep>0)then 256 | print("background of listview can not be plist") 257 | else 258 | listview:setBackGroundImage(extraData.listview_background) 259 | 260 | listview:setBackGroundImageScale9Enabled(true) 261 | local b_insetTop=extraData.listview_background_insetTop or 0 262 | local b_insetBottom=extraData.listview_background_insetBottom or 0 263 | local b_insetLeft=extraData.listview_background_insetLeft or 0 264 | local b_insetRight=extraData.listview_background_insetRight or 0 265 | local size=listview:getBackGroundImageTextureSize() 266 | local rect=cc.rect(b_insetLeft,b_insetBottom,size.width-b_insetRight-b_insetLeft,size.height-b_insetTop-b_insetBottom) 267 | listview:setBackGroundImageCapInsets(rect) 268 | end 269 | end 270 | 271 | listview:setScrollBarEnabled(not extraData.listview_hidebar) 272 | listview:setInertiaScrollEnabled(extraData.listview_inertia) 273 | listview:setBounceEnabled(extraData.listview_elastic) 274 | listview:setDirection(extraData.listview_direction) 275 | listview:setItemsMargin(extraData.listview_item_margin) 276 | listview:setGravity(extraData.listview_item_gravity) 277 | listview:setPadding(extraData.listview_padding_left,extraData.listview_padding_top,extraData.listview_padding_right,extraData.listview_padding_bottom) 278 | 279 | listview.isListview=true 280 | return listview 281 | end 282 | 283 | local function createScrollview(creator) 284 | local outline=creator.outline 285 | local extraData=outline.extraData 286 | 287 | local scroll=ccui.ScrollView:create() 288 | local viewsize = cc.size(outline.width, outline.height); 289 | scroll:setInertiaScrollEnabled(extraData.scrollview_inertia); 290 | scroll:setScrollBarEnabled(not extraData.scrollview_hidebar); 291 | scroll:setDirection(extraData.scrollview_direction); 292 | 293 | local addChild=scroll.addChild 294 | function scroll:addChild(content) 295 | local contentsize = content:getContentSize(); 296 | content:setAnchorPoint(cc.p(0.5,0.5)) 297 | content:setPosition(cc.p(contentsize.width / 2, contentsize.height / 2)); 298 | 299 | local container = self:getInnerContainer(); 300 | container:setContentSize(contentsize); 301 | 302 | local di=extraData.scrollview_direction 303 | if(di==1)then 304 | container:setPositionX((viewsize.width - contentsize.width) / 2); 305 | self:scrollToTop(0.8, true); 306 | elseif(di==2)then 307 | container:setPositionY((viewsize.height-contentsize.height)/2) 308 | self:scrollToLeft(0.8,true) 309 | elseif(di==3)then 310 | container:setPositionY((viewsize.height-contentsize.height)/2) 311 | container:setPositionX((viewsize.width - contentsize.width) / 2); 312 | end 313 | 314 | addChild(self,content) 315 | end 316 | 317 | return scroll 318 | end 319 | 320 | function outlineprivate_createNode(creator,parent) 321 | local outline=creator.outline 322 | local node 323 | local extraData=outline.extraData 324 | 325 | if(extraData)then 326 | if(extraData.isListview)then 327 | node=createListview(creator) 328 | end 329 | 330 | if(extraData.isScrollview)then 331 | node=createScrollview(creator) 332 | end 333 | 334 | if(extraData.isProgressBar)then 335 | node=createProgressBar(outline) 336 | end 337 | 338 | if(extraData.isSprite)then 339 | node=createSprite(outline) 340 | end 341 | 342 | if(extraData.isLabel)then 343 | node=createLabel(outline) 344 | end 345 | 346 | if(extraData.isEditBox)then 347 | node=createEditBox(outline) 348 | end 349 | 350 | if(extraData.isParticleSystem)then 351 | node=createParticleSystem(outline) 352 | end 353 | end 354 | 355 | if(not node)then 356 | node=display.newNode() 357 | end 358 | 359 | return node 360 | end 361 | 362 | 363 | -------------------------------------------------------------------------------- /lua-interpret/outline.lua: -------------------------------------------------------------------------------- 1 | outline_global={} 2 | 3 | function outline_global.init(src) 4 | local btnsrc=src..'BtnFactory' 5 | require (btnsrc) 6 | local createNodeSrc=src..'createNode' 7 | require (createNodeSrc) 8 | end 9 | 10 | local Outline={} 11 | 12 | function getFrame(framePath) 13 | local frame 14 | local sep=string.find(framePath,'%:') 15 | if(sep and sep>0)then 16 | local imageFile=string.sub(framePath,0,sep-1) 17 | local spriteFrameName=string.sub(framePath,sep+1) 18 | 19 | local cache=cc.SpriteFrameCache:getInstance() 20 | local dotIndex=string.find(imageFile,'%.') 21 | local plistFile=string.sub(imageFile,0,dotIndex)..'plist' 22 | 23 | frame=cache:getSpriteFrame(spriteFrameName) 24 | if(not frame)then 25 | if(string.find(spriteFrameName,'%.png')==nil)then 26 | spriteFrameName=spriteFrameName .. '.png' 27 | frame=cache:getSpriteFrame(spriteFrameName) 28 | end 29 | if(not frame)then 30 | cache:addSpriteFrames(plistFile) 31 | frame=cache:getSpriteFrame(spriteFrameName) 32 | end 33 | end 34 | else 35 | local texture=cc.Director:getInstance():getTextureCache():addImage(framePath) 36 | local rect=cc.rect(0,0,texture:getPixelsWide(),texture:getPixelsHigh()) 37 | frame=cc.SpriteFrame:createWithTexture(texture,rect) 38 | end 39 | return frame 40 | end 41 | 42 | local UNITTYPE_PX=1 43 | local UNITTYPE_RATE=2 44 | local function getApplyWidget(outline) 45 | if(not outline.extraData)then return end 46 | if(not outline.extraData.hasWidget)then return end 47 | 48 | local function applyWidget(self,cascade) 49 | local parent=self:getParent() 50 | local child=self 51 | 52 | local size_parent=parent:getContentSize() 53 | local size_child=child:getContentSize() 54 | local anchor_child=child:getAnchorPoint() 55 | 56 | local aLeft=outline.extraData.widget_ALeft 57 | local aRight=outline.extraData.widget_ARight 58 | local aBottom=outline.extraData.widget_ABottom 59 | local aTop=outline.extraData.widget_ATop 60 | 61 | local AHCenter=outline.extraData.widget_AHCenter 62 | local HCenter=outline.extraData.widget_HCenter 63 | local UHCenter=outline.extraData.widget_UHCenter 64 | 65 | local AVCenter=outline.extraData.widget_AVCenter 66 | local VCenter=outline.extraData.widget_VCenter 67 | local UVCenter=outline.extraData.widget_UVCenter 68 | 69 | if(AVCenter)then 70 | anchor_child.y=0.5 71 | child:setAnchorPoint(anchor_child) 72 | if(UVCenter==UNITTYPE_RATE)then 73 | VCenter=size_parent.height*VCenter 74 | end 75 | child:setPositionY(0.5*size_parent.height+VCenter) 76 | else 77 | local bottom=outline.extraData.widget_bottom 78 | local top=outline.extraData.widget_top 79 | local unit_bottom=outline.extraData.widget_unit_bottom 80 | if(unit_bottom==UNITTYPE_RATE)then 81 | bottom=size_parent.height*bottom 82 | end 83 | local unit_top=outline.extraData.widget_unit_top 84 | if(unit_top==UNITTYPE_RATE)then 85 | top=size_parent.height*top 86 | end 87 | 88 | if(aBottom and not aTop)then 89 | anchor_child.y=0 90 | child:setAnchorPoint(anchor_child) 91 | child:setPositionY(bottom) 92 | elseif(aBottom and aTop)then 93 | local newHeight=size_parent.height-top-bottom 94 | if(newHeight>0 and not outline.isLabel)then 95 | child:setPositionY(bottom+newHeight*anchor_child.y) 96 | if(outline.isSprite and not outline.extraData.slice)then 97 | size_child.height=outline.extraData.widget_originHeight 98 | child:setContentSize(size_child) 99 | child:setScaleY(newHeight/size_child.height) 100 | else 101 | size_child.height=newHeight 102 | child:setContentSize(size_child) 103 | end 104 | end 105 | elseif(not aBottom and aTop)then 106 | anchor_child.y=1 107 | child:setAnchorPoint(anchor_child) 108 | child:setPositionY(size_parent.height-top) 109 | end 110 | end 111 | 112 | if(HCenter)then 113 | anchor_child.x=0.5 114 | child:setAnchorPoint(anchor_child) 115 | if(UHCenter==UNITTYPE_RATE)then 116 | HCenter=size_parent.height*HCenter 117 | end 118 | child:setPositionX(0.5*size_parent.width+HCenter) 119 | else 120 | local left=outline.extraData.widget_left 121 | local right=outline.extraData.widget_right 122 | local unit_left=outline.extraData.widget_unit_left 123 | if(unit_left==UNITTYPE_RATE)then 124 | left=size_parent.width*left 125 | end 126 | local unit_right=outline.extraData.widget_unit_right 127 | if(unit_right==UNITTYPE_RATE)then 128 | right=size_parent.width*right 129 | end 130 | if(aLeft and (not aRight))then 131 | anchor_child.x=0 132 | child:setAnchorPoint(anchor_child) 133 | child:setPositionX(left) 134 | elseif(aLeft and aRight)then 135 | local newWidth=size_parent.width-left-right 136 | if(newWidth>0 and not outline.isLabel)then 137 | child:setPositionX(left+newWidth*anchor_child.x) 138 | if(outline.isSprite and not outline.extraData.slice)then 139 | size_child.width=outline.extraData.widget_originWidth 140 | child:setContentSize(size_child) 141 | child:setScaleX(newWidth/size_child.width) 142 | else 143 | size_child.width=newWidth 144 | child:setContentSize(size_child) 145 | end 146 | end 147 | elseif(not aLeft and aRight)then 148 | anchor_child.x=1 149 | child:setAnchorPoint(anchor_child) 150 | child:setPositionX(size_parent.width-right) 151 | end 152 | end 153 | 154 | if(cascade)then 155 | local children=self:getChildren() 156 | for k,v in pairs(children)do 157 | if(v.applyWidget)then 158 | v:applyWidget(true) 159 | end 160 | end 161 | end 162 | end 163 | return applyWidget 164 | end 165 | 166 | local function processBtn(node,extraData) 167 | node.needSwallowTouch=extraData.btn_needSwallowTouch 168 | node.cancelWhenScroll=extraData.btn_cancelWhenScroll 169 | 170 | local buttonType=extraData.btn_buttonType 171 | 172 | local image_disabled=extraData.btn_image_disabled 173 | if(image_disabled)then 174 | node.image_disabled=image_disabled 175 | end 176 | 177 | local image_normal=extraData.btn_image_normal 178 | if(image_normal)then 179 | node.image_normal=image_normal 180 | end 181 | 182 | local image_pressed=extraData.btn_image_pressed 183 | if(image_pressed)then 184 | node.image_pressed=image_pressed 185 | end 186 | 187 | function node:setEnabled(enable) 188 | if(enable)then 189 | self.btn_isDisabled=false 190 | if(self.image_normal)then 191 | setSPF(self,self.image_normal) 192 | end 193 | else 194 | self.btn_isDisabled=true 195 | if(self.image_disabled)then 196 | setSPF(self,self.image_disabled) 197 | end 198 | end 199 | return self 200 | end 201 | 202 | if(buttonType==outlineprivate_btnFactory.BUTTONTYPE_SCALE)then 203 | outlineprivate_btnFactory.processScaleBtn(node) 204 | elseif(buttonType==outlineprivate_btnFactory.BUTTONTYPE_COLOR)then 205 | outlineprivate_btnFactory.processColorBtn(node) 206 | elseif(buttonType==outlineprivate_btnFactory.BUTTONTYPE_SPRITE)then 207 | outlineprivate_btnFactory.processSpriteBtn(node) 208 | elseif(buttonType==outlineprivate_btnFactory.BUTTONTYPE_SELECT)then 209 | outlineprivate_btnFactory.processSelectBtn(node) 210 | elseif(buttonType==outlineprivate_btnFactory.BUTTONTYPE_NONE)then 211 | outlineprivate_btnFactory.processNoneBtn(node) 212 | end 213 | 214 | if(extraData.btn_enableAutoGrayEffect)then 215 | outlineprivate_btnFactory.autoGray(node) 216 | end 217 | end 218 | 219 | function Outline:create( parent ) 220 | local node=self.createNode(self.creator,parent) 221 | node:setName(self.name) 222 | self:reset(node) 223 | if(parent)then 224 | parent:addChild(node) 225 | end 226 | 227 | node.applyWidget=getApplyWidget(self) 228 | if(node.applyWidget)then 229 | node:applyWidget() 230 | end 231 | 232 | if(self.extraData and self.extraData.btn_buttonType)then 233 | processBtn(node,self.extraData) 234 | end 235 | 236 | if(self.children and not node.isListview)then 237 | for index,child in pairs(self.children)do 238 | child:create(node) 239 | end 240 | end 241 | self.lastNode=node 242 | 243 | return node 244 | end 245 | 246 | function Outline:reset( node , cascade ) 247 | node:setPosition(self.x,self.y) 248 | if (self.width>0 and self.height>0)then 249 | node:setContentSize(self.width,self.height); 250 | end 251 | node:setAnchorPoint(cc.p(self.anchorX, self.anchorY)); 252 | node:setScaleX(self.scaleX); 253 | node:setScaleY(self.scaleY); 254 | node:setRotation(self.rotation); 255 | node:setOpacity(self.opacity); 256 | node:setVisible(self.visible); 257 | node:setLocalZOrder(self.zOrder); 258 | node:setSkewX(self.skewX) 259 | node:setSkewY(self.skewY) 260 | node:setColor(cc.c3b(self.colorR, self.colorG, self.colorB)); 261 | if(cascade)then 262 | if(self.children)then 263 | for index,child in pairs(self.children)do 264 | if(child.lastNode)then 265 | child:reset(child.lastNode,cascade) 266 | end 267 | end 268 | end 269 | end 270 | end 271 | 272 | 273 | outline_global.createOutline=function(nodeInfo) 274 | local outline={ 275 | name="undefine", 276 | x=0, 277 | y=0, 278 | scaleX=1, 279 | scaleY=1, 280 | width=0, 281 | height=0, 282 | anchorX=0.5, 283 | anchorY=0.5, 284 | rotation=0, 285 | skewX=0, 286 | skewY=0, 287 | opacity=255, 288 | visible=true, 289 | zOrder=0, 290 | colorR=255, 291 | colorG=255, 292 | colorB=255 293 | } 294 | 295 | outline.lastNode=nil 296 | outline.createNode=outlineprivate_createNode 297 | outline.create=Outline.create 298 | outline.reset=Outline.reset 299 | outline.applyWidget=Outline.applyWidget 300 | 301 | if(nodeInfo) then 302 | for k,v in pairs(nodeInfo)do 303 | outline[k]=v 304 | end 305 | end 306 | 307 | return outline 308 | end 309 | 310 | local Creator={} 311 | 312 | function Creator:create(parent,withComponents) 313 | local node=self.outline:create(parent) 314 | if(withComponents)then 315 | if(self._components)then 316 | for k,v in pairs(self._components)do 317 | node[v]={} 318 | for key,value in pairs(self[v])do 319 | node[v][key]=value 320 | end 321 | end 322 | end 323 | end 324 | return node 325 | end 326 | function Creator:lastNode() 327 | return self.outline.lastNode 328 | end 329 | outline_global.createCreator=function(outline,creator) 330 | creator.outline=outline 331 | outline.creator=creator 332 | creator.create=Creator.create 333 | creator.lastNode=Creator.lastNode 334 | end 335 | 336 | function addX(node,addx) 337 | if(node)then 338 | node:setPositionX(node:getPositionX()+addx) 339 | end 340 | end 341 | 342 | function addY(node,addy) 343 | if(node)then 344 | node:setPositionY(node:getPositionY()+addy) 345 | end 346 | end 347 | 348 | function addScaleX(node,addscalex) 349 | if(node)then 350 | node:setScaleX(node:getScaleX()+addscalex) 351 | end 352 | end 353 | 354 | function addScaleY(node,addscaley) 355 | if(node)then 356 | node:setScaleY(node:getScaleY()+addscaley) 357 | end 358 | end 359 | 360 | function addSize(node,addwidth,addheight) 361 | if(node)then 362 | local size=node:getContentSize() 363 | size.width=size.width+addwidth 364 | size.height=size.height+addheight 365 | node:setContentSize(size) 366 | end 367 | end 368 | 369 | function addAnchor(node,x,y) 370 | if(node)then 371 | local anchor=node:getAnchorPoint() 372 | anchor.x=anchor.x+x 373 | anchor.y=anchor.y+y 374 | node:setAnchorPoint(anchor) 375 | end 376 | end 377 | 378 | function addRotation(node,addrotation) 379 | if(node)then 380 | node:setRotation(node:getRotation()+addrotation) 381 | end 382 | end 383 | 384 | function addColor(node,r,g,b) 385 | if(node)then 386 | local color=node:getColor() 387 | color.r=color.r+r 388 | color.g=color.g+g 389 | color.b=color.b+b 390 | node:setColor(color) 391 | end 392 | end 393 | 394 | function setSpriteFrame(node,frame) 395 | if(node)then 396 | setSPF(node,frame) 397 | end 398 | end 399 | 400 | function addOpacity(node,addOpacity) 401 | local newOpacity=node:getOpacity()+addOpacity 402 | if(newOpacity>255)then 403 | newOpacity=255 404 | elseif(newOpacity<0)then 405 | newOpacity=0 406 | end 407 | if(node) then node:setOpacity(newOpacity) end 408 | end 409 | 410 | --private 411 | local function getChild(parent,...) 412 | local child=parent 413 | for index,name in ipairs{...}do 414 | child=child:getChildByName(name) 415 | end 416 | return child 417 | end 418 | 419 | local function pause(self) 420 | cc.Director:getInstance():getScheduler():unscheduleScriptEntry(self.scheduleId) 421 | end 422 | 423 | local function stop(self) 424 | self:pause() 425 | self=nil 426 | end 427 | 428 | --private 429 | local function play(self,node,loop,callback,key) 430 | self.callback=callback 431 | self.node=node 432 | self.loop=loop 433 | self.frameIndex=0 434 | self.key=key 435 | if(node)then 436 | self.played=true 437 | self:resume() 438 | end 439 | end 440 | 441 | local function whenFrameEnd(self) 442 | if(self.loop)then 443 | self.frameIndex=0 444 | else 445 | self:pause() 446 | end 447 | if(self.callback)then 448 | self.callback(self.key) 449 | if(not self.loop)then 450 | self.callback=nil 451 | end 452 | end 453 | end 454 | 455 | outline_global.createAnim=function() 456 | local anim={} 457 | anim.frameIndex=0 458 | anim.getChild=getChild 459 | anim.whenFrameEnd=whenFrameEnd; 460 | anim.pause=pause 461 | anim.play=play 462 | anim.stop=stop 463 | return anim 464 | end 465 | 466 | function getScale(node) 467 | local scaleX=1 468 | local scaleY=1 469 | local parent=node 470 | while(parent)do 471 | scaleX = scaleX * parent:getScaleX() 472 | scaleY = scaleY * parent:getScaleY() 473 | parent = parent:getParent() 474 | end 475 | return scaleX,scaleY 476 | end 477 | 478 | function setSPF(sp,spf) 479 | local spType=tolua.type(sp) 480 | if(spType=="ccui.Scale9Sprite")then 481 | sp:setSpriteFrame(getFrame(spf),sp:getCapInsets()) 482 | else 483 | sp:setSpriteFrame(getFrame(spf)) 484 | end 485 | end 486 | 487 | Vec2=cc.p; 488 | Color=cc.c4b; 489 | Size=cc.size; 490 | -------------------------------------------------------------------------------- /work-quick.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limall/outline/c74bb533df9f32a9b58b0cc92103d8de30e168ce/work-quick.txt -------------------------------------------------------------------------------- /work.txt: -------------------------------------------------------------------------------- 1 | label字体查找 2 | 编写文档 3 | 讨论交流 4 | 依照讨论交流的结果决定是否进行下面的工作 5 | layout、scrollview、listview、pageview 6 | phaser.js 7 | 英文注释和英文Readme 8 | 9 | 重做动画 10 | 首先以Bezier为核心,不需弄懂算法,翻译成lua,制定测试策略,确保翻译无误 11 | cardano算法移植 12 | 在c++端运行时,记录10组输入输出,若在lua端的输出差距很小,就算移植成功 13 | 暂不重做,主要以提高原来的精度为主 14 | 一次只能录制一个动画 15 | 提供bool值判断这个动画是否需要录制,录制时自动寻找场景中录制为true的第一个动画 16 | --------------------------------------------------------------------------------