├── .gitignore ├── .idea ├── .name └── jsLibraryMappings.xml ├── LICENSE ├── README.md ├── bin ├── flax-lite.min.js └── flax.min.js ├── build.xml ├── graph.xmind ├── helloWorld ├── .cocos-project.json ├── flash │ ├── flaxAnim.fla │ └── flaxAnim.swf ├── index.html ├── main.js ├── project.json ├── res │ ├── flaxAnim.plist │ ├── flaxAnim.png │ ├── logo.png │ └── rotate.png └── src │ ├── HelloWorld.js │ └── resource.js ├── logs ├── v1.8_cn.txt └── v1.8_en.txt └── src └── flax ├── Flax.js ├── core ├── Animator.js ├── AssetsManager.js ├── Button.js ├── DebugDraw.js ├── FlaxLoader.js ├── FlaxSprite.js ├── Image.js ├── InputManager.js ├── Label.js ├── MovieClip.js ├── Physics.js └── ProgressBar.js ├── game ├── Color.js ├── Gun.js ├── Gunner.js ├── LinkFinder.js ├── ObjectPool.js ├── Preloader.js ├── ScrollPane.js ├── ScrollingBG.js ├── SoundButton.js ├── TileMap.js ├── TiledImage.js └── UserData.js ├── module ├── EnemyWaveModule.js ├── HealthModule.js ├── MoveModule.js ├── PhysicsModule.js ├── ScreenLayoutModule.js └── TileMapModule.js └── signal ├── Signal.js ├── SignalBinding.js └── wrapper.js /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .idea/encodings.xml 3 | 4 | .idea/Flax-js.iml 5 | 6 | .idea/misc.xml 7 | 8 | .idea/modules.xml 9 | 10 | .idea/scopes/scope_settings.xml 11 | 12 | .idea/vcs.xml 13 | 14 | .idea/workspace.xml -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | Flax-js -------------------------------------------------------------------------------- /.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 yangxi 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | What is Flax? 2 | ============ 3 | Flax is a game develop tool based on Flash Professional (Later we called it Flash), which is a well-known multimedia creation platform. For the past few years, Flash has even become a powerful game develop tool. 4 | 5 | Flax is just to use the power of the Flash to create animation/UI/scene/font etc. Convert a created SWF to texture to be used by other game develop platform, such as Cocos2d-js, Cocos2d-x, Unity, Starling, maybe more. 6 | 7 | Video 8 | ======== 9 | http://v.qq.com/page/d/a/4/d0148a7pma4.html 10 | 11 | Pros 12 | ==== 13 | 1. For Mac and Windows both 14 | 2. Based on powerful Flash, what you see in flash is what you get in game 15 | 3. Easy to use and extendable 16 | 4. It’s free 17 | 18 | Key Features 19 | ============ 20 | 1. Key frame animation create 21 | 2. Skeletal animation create 22 | 3. UI edit 23 | 4. Scene edit 24 | 5. Font create 25 | 6. Anchor edit 26 | 7. Physic edit 27 | 28 | Who need Flax 29 | ============= 30 | If you or your team member especially the artist are familiar with the Flash, you should enjoy it. If you were a Flash game developer, Flax will make you feel so familiar to develop games with other platform like Cocos2d/Unity etc. 31 | 32 | Examples 33 | ======== 34 | https://github.com/longyangxi/Flax-js-examples 35 | 36 | Online Demo 37 | =========== 38 | http://longames.com/h5/example/ 39 | 40 | Home 41 | ==== 42 | http://flax.longames.com 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /graph.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longyangxi/Flax-js/2c40fb7b825168b83eb0f2f981e65ca8fb177428/graph.xmind -------------------------------------------------------------------------------- /helloWorld/.cocos-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "has_native": true, 3 | "project_type": "js" 4 | } -------------------------------------------------------------------------------- /helloWorld/flash/flaxAnim.fla: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longyangxi/Flax-js/2c40fb7b825168b83eb0f2f981e65ca8fb177428/helloWorld/flash/flaxAnim.fla -------------------------------------------------------------------------------- /helloWorld/flash/flaxAnim.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longyangxi/Flax-js/2c40fb7b825168b83eb0f2f981e65ca8fb177428/helloWorld/flash/flaxAnim.swf -------------------------------------------------------------------------------- /helloWorld/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Cocos2d-html5 Hello World test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /helloWorld/main.js: -------------------------------------------------------------------------------- 1 | cc.game.onStart = function(){ 2 | if(!cc.sys.isNative && document.getElementById("cocosLoading")) //If referenced loading.js, please remove it 3 | document.body.removeChild(document.getElementById("cocosLoading")); 4 | // Pass true to enable retina display, disabled by default to improve performance 5 | cc.view.enableRetina(false); 6 | //初始化引擎 7 | flax.init(cc.ResolutionPolicy.SHOW_ALL); 8 | //注册场景(参数:场景名字,场景,所需素材) 9 | flax.registerScene("helloWorld", HelloWorld, res_helloWorld); 10 | //根据场景名字切换场景 11 | flax.replaceScene("helloWorld"); 12 | }; 13 | cc.game.run(); -------------------------------------------------------------------------------- /helloWorld/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version":1.0, 3 | "gameId":"helloWorld", 4 | "width":640, 5 | "height":960, 6 | "landscape":false, 7 | "rotateImg":"res/rotate.png", 8 | "language":"zh", 9 | "languageJson":false, 10 | "loading":"res/logo.png", 11 | "preloader":"flax.Preloader", 12 | "domainAllowed":[ 13 | 14 | ], 15 | "project_type":"javascript", 16 | "debugMode":1, 17 | "showFPS":false, 18 | "frameRate":60, 19 | "id":"gameCanvas", 20 | "renderMode":0, 21 | "engineDir":"frameworks/cocos2d-html5", 22 | "modules":[ 23 | "cocos2d" 24 | ], 25 | "jsList":[ 26 | "src/flax/Flax.js", 27 | "src/flax/signal/SignalBinding.js", 28 | "src/flax/signal/Signal.js", 29 | "src/flax/signal/wrapper.js", 30 | "src/flax/core/DebugDraw.js", 31 | "src/flax/core/InputManager.js", 32 | "src/flax/core/FlaxLoader.js", 33 | "src/flax/core/AssetsManager.js", 34 | "src/flax/core/Physics.js", 35 | "src/flax/module/TileMapModule.js", 36 | "src/flax/module/ScreenLayoutModule.js", 37 | "src/flax/module/PhysicsModule.js", 38 | "src/flax/module/MoveModule.js", 39 | "src/flax/core/FlaxSprite.js", 40 | "src/flax/core/Animator.js", 41 | "src/flax/core/Image.js", 42 | "src/flax/core/MovieClip.js", 43 | "src/flax/core/ProgressBar.js", 44 | "src/flax/core/Label.js", 45 | "src/flax/core/Button.js", 46 | "src/flax/game/Preloader.js", 47 | "src/flax/game/TileMap.js", 48 | "src/flax/game/UserData.js", 49 | "src/flax/game/ObjectPool.js", 50 | "src/flax/module/HealthModule.js", 51 | "src/flax/module/EnemyWaveModule.js", 52 | "src/flax/game/SoundButton.js", 53 | "src/flax/game/Gun.js", 54 | "src/flax/game/Gunner.js", 55 | "src/flax/game/ScrollingBG.js", 56 | "src/flax/game/ScrollPane.js", 57 | "src/flax/game/TiledImage.js", 58 | "src/flax/game/LinkFinder.js", 59 | "src/flax/game/Color.js", 60 | "src/resource.js", 61 | "src/HelloWorld.js" 62 | ] 63 | 64 | } 65 | -------------------------------------------------------------------------------- /helloWorld/res/flaxAnim.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | frames 4 | 5 | flaxAnim_000000 6 | 7 | frame 8 | {{0,27},{140,145}} 9 | offset 10 | {0.00,0.00} 11 | rotated 12 | 13 | sourceSize 14 | {138,143} 15 | 16 | flaxAnim_000001 17 | 18 | frame 19 | {{0,0},{169,27}} 20 | offset 21 | {0.00,0.00} 22 | rotated 23 | 24 | sourceSize 25 | {167,25} 26 | 27 | 28 | metadata 29 | 30 | flaxVersion 31 | 2.11 32 | fps 33 | 24 34 | format 35 | 2 36 | realTextureFileName 37 | flaxAnim.png 38 | size 39 | {170,246} 40 | textureFileName 41 | flaxAnim.png 42 | 43 | displays 44 | 45 | asset1 46 | 47 | type 48 | null 49 | anchorX 50 | 0.5072463768115942 51 | anchorY 52 | 0.4965034965034965 53 | start 54 | 0 55 | end 56 | 0 57 | 58 | asset3 59 | 60 | type 61 | null 62 | anchorX 63 | 0.5053892215568863 64 | anchorY 65 | 0.604 66 | start 67 | 1 68 | end 69 | 1 70 | 71 | 72 | mcs 73 | 74 | helloWorld 75 | 76 | type 77 | null 78 | totalFrames 79 | 35 80 | rect 81 | 0,0,400.00,400.00 82 | anchorX 83 | 0.5 84 | anchorY 85 | 0.5 86 | children 87 | 88 | instance617 89 | 90 | class 91 | asset3 92 | zIndex 93 | 1 94 | frames 95 | null|||||||||||||||||||199.20,152.05,0.00,1,1,0.21,1,0,0|199.20,152.05,0.00,1,1,0.26,1,0,0|199.20,152.05,0.00,1,1,0.32,1,0,0|199.20,152.05,0.00,1,1,0.37,1,0,0|199.20,152.05,0.00,1,1,0.42,1,0,0|199.20,152.05,0.00,1,1,0.47,1,0,0|199.20,152.05,0.00,1,1,0.53,1,0,0|199.20,152.05,0.00,1,1,0.58,1,0,0|199.20,152.05,0.00,1,1,0.63,1,0,0|199.20,152.05,0.00,1,1,0.68,1,0,0|199.20,152.05,0.00,1,1,0.74,1,0,0|199.20,152.05,0.00,1,1,0.79,1,0,0|199.20,152.05,0.00,1,1,0.84,1,0,0|199.20,152.05,0.00,1,1,0.89,1,0,0|199.20,152.05,0.00,1,1,0.95,1,0,0|199.20,152.05,0.00,1,1,1.00,1,0,0 96 | 97 | instance583 98 | 99 | class 100 | asset1 101 | zIndex 102 | 0 103 | frames 104 | 200.00,200.00,0.00,6.25,6.25,0.37,0,0,0|200.00,200.00,0.00,6.1465301513671875,6.1465301513671875,0.38,0,0,0|200.00,200.00,0.00,6.0237884521484375,6.0237884521484375,0.40,0,0,0|200.00,200.00,0.00,5.8819732666015625,5.8819732666015625,0.41,0,0,0|200.00,200.00,0.00,5.7208099365234375,5.7208099365234375,0.43,0,0,0|200.00,200.00,0.00,5.54046630859375,5.54046630859375,0.46,0,0,0|200.00,200.00,0.00,5.3407745361328125,5.3407745361328125,0.48,0,0,0|200.00,200.00,0.00,5.1221923828125,5.1221923828125,0.51,0,0,0|200.00,200.00,0.00,4.884246826171875,4.884246826171875,0.54,0,0,0|200.00,200.00,0.00,4.62713623046875,4.62713623046875,0.57,0,0,0|200.00,200.00,0.00,4.350860595703125,4.350860595703125,0.60,0,0,0|200.00,200.00,0.00,4.0553131103515625,4.0553131103515625,0.63,0,0,0|200.00,200.00,0.00,3.740509033203125,3.740509033203125,0.67,0,0,0|200.00,200.00,0.00,3.4067230224609375,3.4067230224609375,0.71,0,0,0|200.00,200.00,0.00,3.0535736083984375,3.0535736083984375,0.75,0,0,0|200.00,200.00,0.00,2.6812591552734375,2.6812591552734375,0.80,0,0,0|200.00,200.00,0.00,2.2897796630859375,2.2897796630859375,0.84,0,0,0|200.00,200.00,0.00,1.879119873046875,1.879119873046875,0.89,0,0,0|200.00,200.00,0.00,1.4491119384765625,1.4491119384765625,0.95,0,0,0|200.00,200.00,0.00,1,1,1.00,0,0,0||||||||||||||| 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /helloWorld/res/flaxAnim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longyangxi/Flax-js/2c40fb7b825168b83eb0f2f981e65ca8fb177428/helloWorld/res/flaxAnim.png -------------------------------------------------------------------------------- /helloWorld/res/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longyangxi/Flax-js/2c40fb7b825168b83eb0f2f981e65ca8fb177428/helloWorld/res/logo.png -------------------------------------------------------------------------------- /helloWorld/res/rotate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longyangxi/Flax-js/2c40fb7b825168b83eb0f2f981e65ca8fb177428/helloWorld/res/rotate.png -------------------------------------------------------------------------------- /helloWorld/src/HelloWorld.js: -------------------------------------------------------------------------------- 1 | var HelloWorld = cc.Scene.extend({ 2 | onEnter:function(){ 3 | this._super(); 4 | var winSize = cc.visibleRect; 5 | //从flax输出的素材文件中,创建id为anim的动画,对应flash库中链接名为mc.anim的动画 6 | //添加到this中,并设置位置为舞台中心 7 | var anim = flax.assetsManager.createDisplay(res.anim, "helloWorld", {parent: this, x: winSize.width/2, y: winSize.height/2}); 8 | //在最后一帧停住 9 | anim.autoStopWhenOver = true; 10 | //从当前帧就是第1帧开始播放 11 | anim.play(); 12 | } 13 | }); -------------------------------------------------------------------------------- /helloWorld/src/resource.js: -------------------------------------------------------------------------------- 1 | var res = { 2 | anim:"res/flaxAnim.plist", 3 | anim_png:"res/flaxAnim.png" 4 | }; 5 | 6 | var res_helloWorld = [ 7 | res.anim, 8 | res.anim_png 9 | ]; 10 | -------------------------------------------------------------------------------- /logs/v1.8_cn.txt: -------------------------------------------------------------------------------- 1 | 1. flax.FlaxSprite可以播放帧声音了,并且可以自动播放从Flash中导出的帧声音 2 | 2. flax.FlaxSprite添加了MoveTo和MoveToBySpeed方法,替代Cocos的MoveTo来避免JSB中出现bug 3 | 3. flax.AssetsManager增加了获取资源类型的函数getAssetType 4 | 4. flax.AssetsManager.createDisplay现在添加了batch参数来产生MovieClipBatch以提高骨骼动画的效率 5 | 5. 改进了flax.MovieClip.eplaceChild方法,可以从不同的assetsFile中替换child 6 | 6. 修正了Label里的一些特殊符号引起JSB报错 7 | 7. 修正了LinkFinder里没有shuffle的bug 8 | 8. 修正了JSB下flax.Gun中invalid native object的bug 9 | -------------------------------------------------------------------------------- /logs/v1.8_en.txt: -------------------------------------------------------------------------------- 1 | 1. Add frame sound for flax.FlaxSprite and now can auto play frame sound
 exported from Flash 2 | 2. Add MoveTo and MoveToBySpeed functions for flax.FlaxSprite to avoid MoveTo action bug in JSb 3 | 3. Add getAssetType function for flax.AssetsManager 4 | 4. Add batch option to create MovieClipBatch in createDisplay for flax.AssetsManager 5 | 5. Improved the replaceChild in flax.MovieClip 6 | 6. Fixed some special chars bug in Label’s text in JSB 7 | 7. Fixed shuffle bug in LinkFinder 8 | 8. Fixed invalid native object bug of flax.Gun in JSB 9 | -------------------------------------------------------------------------------- /src/flax/core/Animator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-2-1. 3 | */ 4 | 5 | flax.Animator = flax.FlaxSprite.extend({ 6 | frameNames:null, 7 | clsName:"flax.Animator", 8 | onNewSource:function() 9 | { 10 | var startFrame = this.define['start']; 11 | var endFrame = this.define['end']; 12 | 13 | this.frameNames = flax.assetsManager.getFrameNames(this.assetsFile, startFrame, endFrame); 14 | this.totalFrames = this.frameNames.length; 15 | if(this.totalFrames == 0) 16 | { 17 | cc.log("There is no frame for display: "+this.assetID); 18 | return; 19 | } 20 | }, 21 | doRenderFrame:function(frame) 22 | { 23 | this.setSpriteFrame(this.frameNames[frame]); 24 | }, 25 | getDefine:function() 26 | { 27 | var define = flax.assetsManager.getDisplayDefine(this.assetsFile, this.assetID); 28 | if(define == null) throw "There is no Animator named: " + this.assetID + " in assets: " + this.assetsFile + ", or make sure this class extends from the proper class!"; 29 | return define; 30 | } 31 | }); 32 | 33 | flax.Animator.create = function(assetsFile, assetID) 34 | { 35 | var mc = new flax.Animator(assetsFile, assetID); 36 | mc.clsName = "flax.Animator"; 37 | return mc; 38 | }; 39 | 40 | //Avoid to advanced compile mode 41 | window['flax']['Animator'] = flax.Animator; -------------------------------------------------------------------------------- /src/flax/core/AssetsManager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-1-31. 3 | */ 4 | 5 | flax._assetsClassMap = 6 | { 7 | "btn":"flax.SimpleButton", 8 | "button":"flax.SimpleButton", 9 | "progress":"flax.ProgressBar", 10 | "jpg":"flax.Image", 11 | "png":"flax.Image", 12 | "scrollPane":"flax.ScrollPane", 13 | "gun":"flax.Gunner", 14 | "soundBtn":"flax.SimpleSoundButton" 15 | }; 16 | 17 | flax._assetsMcClassMap = 18 | { 19 | "button":"flax.Button", 20 | "scrollPane":"flax.MCScrollPane", 21 | "gun":"flax.MCGunner", 22 | "gun1":"flax.MCGunner", 23 | "soundBtn":"flax.SoundButton" 24 | }; 25 | /** 26 | * Asset type in flax 27 | * */ 28 | flax.ASSET_NONE = 0; 29 | flax.ASSET_ANIMATOR = 1; 30 | flax.ASSET_MOVIE_CLIP = 2; 31 | flax.ASSET_IMAGE = 3; 32 | /** 33 | * Register a className for Animator 34 | * */ 35 | flax.registerClass = function(key, className){ 36 | flax._assetsClassMap[key] = className; 37 | }; 38 | /** 39 | * Register a className for MovieClip 40 | * */ 41 | flax.registerMcClass = function(key, className){ 42 | flax._assetsMcClassMap[key] = className; 43 | }; 44 | 45 | flax.AssetsManager = cc.Class.extend({ 46 | framesCache:null, 47 | displaysCache:null, 48 | displayDefineCache:null, 49 | mcsCache:null, 50 | subAnimsCache:null, 51 | fontsCache:null, 52 | toolsVersion:null, 53 | 54 | init:function() 55 | { 56 | this.framesCache = {}; 57 | this.displaysCache = {}; 58 | this.displayDefineCache = {}; 59 | this.mcsCache = {}; 60 | this.subAnimsCache = {}; 61 | this.fontsCache = {}; 62 | this.toolsVersion = {}; 63 | }, 64 | getAssetType:function(assetsFile, assetID) 65 | { 66 | if(this.getMc(assetsFile, assetID)) return flax.ASSET_MOVIE_CLIP; 67 | var define = this.getDisplayDefine(assetsFile, assetID); 68 | if(define) { 69 | if(define.type == "jpg" || define.type == "png") return flax.ASSET_IMAGE; 70 | if(define.type == "share"){ 71 | return this.getAssetType(this._getSharedPlist(assetsFile, define), assetID) 72 | } 73 | return flax.ASSET_ANIMATOR; 74 | } 75 | return flax.ASSET_NONE; 76 | }, 77 | /** 78 | * Create a display from a assetsFile with assetID 79 | * @param {String} assetsFile the assetsFile 80 | * @param {String} assetID the asset id in the assetsFile 81 | * @param {Object} params params could be set to the target with attr function 82 | * the special param is: 83 | * parent, if set parent, the display will be auto added to it 84 | * class, if set class, the display will be created with the class 85 | * batch, if set true and it is MovieClip then create flax.MovieClipBatch instance 86 | * @param {Boolean} fromPool if the display should fetch from the pool 87 | * @param {String} clsName the class name to create the display, if null, it'll be automatically set according by the assets file 88 | * Deprecated: createDisplay:function(assetsFile, assetID, clsName, fromPool, parent, params) 89 | * */ 90 | createDisplay:function(assetsFile, assetID, params, fromPool, clsName) 91 | { 92 | if(assetsFile == null || assetID == null){ 93 | throw "Please give me assetsFile and assetID!"; 94 | } 95 | if(clsName == null && params) clsName = params["class"]; 96 | if((params && typeof params === "string") || (clsName && typeof clsName !== "string")) { 97 | throw "Params error: maybe you are using the old api, please use the latest!"; 98 | } 99 | this.addAssets(assetsFile); 100 | 101 | var subAnims = this.getSubAnims(assetsFile, assetID); 102 | if(subAnims.length) { 103 | assetID = assetID + "$" + subAnims[0]; 104 | } 105 | var define = this.getDisplayDefine(assetsFile, assetID); 106 | //if it's a shared object, then fetch its source assetsFile 107 | if(define && define.type == "share"){ 108 | return this.createDisplay(this._getSharedPlist(assetsFile, define), assetID, params, fromPool, clsName); 109 | } 110 | 111 | var mcCls = null; 112 | if(clsName) { 113 | mcCls = flax.nameToObject(clsName); 114 | if(mcCls == null){ 115 | throw "The class: "+clsName+" doesn't exist!" 116 | } 117 | } 118 | 119 | if(mcCls == null) { 120 | var isMC = false; 121 | if(define == null) { 122 | define = this.getMc(assetsFile, assetID); 123 | isMC = true; 124 | } 125 | if(define){ 126 | clsName = define.type; 127 | if(clsName == "null" && assetID != "jpg" && assetID != "png"){ 128 | clsName = assetID; 129 | } 130 | mcCls = flax.nameToObject(clsName); 131 | if(mcCls == null){ 132 | clsName = isMC ? flax._assetsMcClassMap[clsName] : flax._assetsClassMap[clsName]; 133 | //Handle the scale9Image 134 | if(clsName == "flax.Image" && define['scale9']){ 135 | clsName = "flax.Scale9Image"; 136 | if(flax.Scale9Image == null) throw "Please add module of 'gui' or 'ccui'(cocos 3.10 later) into project.json if you want to use Scale9Image!"; 137 | } 138 | mcCls = flax.nameToObject(clsName); 139 | } 140 | if(mcCls == null) 141 | { 142 | mcCls = isMC ? flax.MovieClip : flax.Animator; 143 | clsName = isMC ? "flax.MovieClip" : "flax.Animator"; 144 | if(isMC && params && params.batch === true){ 145 | mcCls = flax.MovieClipBatch; 146 | clsName = "flax.MovieClipBatch"; 147 | } 148 | } 149 | }else{ 150 | throw "There is no display with assetID: "+assetID+" in assets file: "+assetsFile+", or make sure the display is not a BLANK symbol!"; 151 | } 152 | } 153 | if(params == null) params = {}; 154 | var mc = null; 155 | var parent = params.parent; 156 | delete params.parent; 157 | if(fromPool === true) { 158 | mc = flax.ObjectPool.get(assetsFile,clsName,assetID).fetch(assetID, parent, params); 159 | }else{ 160 | if(mcCls.create) mc = mcCls.create(assetsFile, assetID); 161 | else mc = new mcCls(assetsFile, assetID); 162 | mc.attr(params); 163 | if(parent) parent.addChild(mc); 164 | mc.clsName = clsName; 165 | } 166 | return mc; 167 | }, 168 | /** 169 | * Clone a new display from the target, if fromPool = true, it'll be fetched from the pool 170 | * It only supports flax.FlaxSprite or its sub classes 171 | * */ 172 | cloneDisplay:function(target, fromPool, autoAdd) 173 | { 174 | if(!flax.isFlaxDisplay(target)) { 175 | throw "cloneDisplay only support flax type display!" 176 | } 177 | var obj = this.createDisplay(target.assetsFile, target.assetID, {parent: (autoAdd ? target.parent : null)}, fromPool, target.clsName); 178 | if(autoAdd) obj.setPosition(target.getPosition()); 179 | obj.setScale(target.getScale()); 180 | obj.setRotation(target.rotation); 181 | obj.zIndex = target.zIndex; 182 | return obj; 183 | }, 184 | removeAssets:function(assetsFile) 185 | { 186 | delete this.framesCache[assetsFile]; 187 | delete this.displaysCache[assetsFile]; 188 | delete this.displayDefineCache[assetsFile]; 189 | delete this.mcsCache[assetsFile]; 190 | delete this.subAnimsCache[assetsFile]; 191 | delete this.fontsCache[assetsFile]; 192 | 193 | var assetsFile1 = assetsFile; 194 | var ext = cc.path.extname(assetsFile); 195 | if(ext == ".flax") assetsFile1 = cc.path.changeBasename(assetsFile1, ".plist"); 196 | 197 | cc.spriteFrameCache.removeSpriteFramesFromFile(assetsFile1); 198 | cc.loader.release(assetsFile1); 199 | cc.loader.release(cc.path.changeBasename(assetsFile1, ".png")); 200 | }, 201 | removeAllAssets:function() 202 | { 203 | for(var file in this.framesCache){ 204 | this.removeAssets(file); 205 | } 206 | }, 207 | addAssets:function(assetsFile) 208 | { 209 | if(typeof this.framesCache[assetsFile] !== "undefined") return false; 210 | 211 | var assetsFile1 = assetsFile; 212 | var ext = cc.path.extname(assetsFile); 213 | if(ext == ".flax") assetsFile1 = cc.path.changeBasename(assetsFile1, ".plist"); 214 | var dict = cc.loader.getRes(assetsFile1); 215 | if(dict == null){ 216 | throw "Make sure you have pre-loaded the resource: "+assetsFile; 217 | } 218 | //the min tool version this API needed 219 | var toolVersion = dict["metadata"]["version"] || dict["metadata"]["flaxVersion"]; 220 | this.toolsVersion[assetsFile] = toolVersion || 0; 221 | if(!toolVersion || toolVersion < flax.minToolVersion){ 222 | throw "The resource: " + assetsFile + " was exported with the old version of Flax, please do it with current version!"; 223 | } 224 | //get the fps from flash 225 | var fps = dict["metadata"]["fps"]; 226 | 227 | cc.spriteFrameCache.addSpriteFrames(assetsFile1); 228 | //Note: the plist will be released by cocos when addSpriteFrames 229 | //We want it to be there to check the resource if loaded 230 | cc.loader.cache[assetsFile1] = "loaded!"; 231 | 232 | //parse the frames 233 | var frames = []; 234 | var frameDict = dict["frames"]; 235 | for(var key in frameDict) 236 | { 237 | frames.push(key); 238 | } 239 | //sort ascending 240 | frames.sort(); 241 | 242 | this.framesCache[assetsFile] = frames; 243 | 244 | //parse the displays defined in the assets 245 | if(dict["displays"]) 246 | { 247 | this._parseDisplays(assetsFile, dict["displays"], fps); 248 | } 249 | //parse the movieClipgs 250 | if(dict["mcs"]) 251 | { 252 | this._parseMovieClips(assetsFile, dict["mcs"], fps); 253 | } 254 | //parse the fonts 255 | if(dict["fonts"]) 256 | { 257 | this._parseFonts(assetsFile, dict["fonts"]); 258 | } 259 | return true; 260 | }, 261 | _parseDisplays:function(assetsFile, displays, fps){ 262 | var displayNames = []; 263 | var dDefine = null; 264 | for(var dName in displays) 265 | { 266 | displayNames.push(dName); 267 | dDefine = displays[dName]; 268 | if(dDefine['anchors']) dDefine['anchors'] = this._parseFrames(dDefine['anchors']); 269 | if(dDefine['colliders']) dDefine['colliders'] = this._parseFrames(dDefine['colliders']); 270 | if(dDefine['scale9']) dDefine['scale9'] = flax._strToRect(dDefine['scale9']); 271 | dDefine['fps'] = fps || cc.game.config["frameRate"]; 272 | this.displayDefineCache[assetsFile + dName] = dDefine; 273 | this._parseSubAnims(assetsFile, dName); 274 | } 275 | this.displaysCache[assetsFile] = displayNames; 276 | }, 277 | _parseMovieClips:function(assetsFile, mcs, fps){ 278 | for(var sName in mcs) 279 | { 280 | var mcDefine = mcs[sName]; 281 | if(mcDefine['anchors']) mcDefine['anchors'] = this._parseFrames(mcDefine['anchors']); 282 | if(mcDefine['colliders']) mcDefine['colliders'] = this._parseFrames(mcDefine['colliders']); 283 | var childDefine; 284 | var childrenDefine = mcDefine['children']; 285 | for(var childName in childrenDefine) 286 | { 287 | childDefine = childrenDefine[childName]; 288 | childDefine.frames = this._strToArray(childDefine.frames); 289 | } 290 | mcDefine['fps'] = fps || cc.game.config["frameRate"]; 291 | this.mcsCache[assetsFile + sName] = mcDefine; 292 | //see if there is a '$' sign which present sub animation of the mc 293 | this._parseSubAnims(assetsFile, sName); 294 | } 295 | }, 296 | _parseFonts:function(assetsFile, fonts){ 297 | for(var fName in fonts) 298 | { 299 | this.fontsCache[assetsFile + fName] = fonts[fName]; 300 | } 301 | }, 302 | _parseSubAnims:function(assetsFile, assetID) 303 | { 304 | var aarr = assetID.split("$"); 305 | var rname = aarr[0]; 306 | var aname = aarr[1]; 307 | if(rname && aname && rname != '' && aname != ''){ 308 | var akey = assetsFile + rname; 309 | var anims = this.subAnimsCache[akey]; 310 | if(anims == null) { 311 | anims = []; 312 | this.subAnimsCache[akey] = anims; 313 | } 314 | anims.push(aname); 315 | } 316 | }, 317 | _parseFrames:function(data){ 318 | var dict = {}; 319 | for(var name in data) 320 | { 321 | dict[name] = this._strToArray(data[name]); 322 | } 323 | return dict; 324 | }, 325 | _strToArray:function(str){ 326 | var frames = str.split("|"); 327 | var i = -1; 328 | var arr = []; 329 | while(++i < frames.length) 330 | { 331 | var frame = frames[i]; 332 | if(frame === "null") arr.push(null); 333 | //"" means the params is the same as prev frame 334 | else if(frame === "") arr.push(arr[i - 1]); 335 | else arr.push(frame); 336 | } 337 | return arr; 338 | }, 339 | _getSharedPlist:function(assetsFile, define) 340 | { 341 | //get the resource root folder, the share library must be in the root folder 342 | var dir = assetsFile.slice(0, assetsFile.indexOf("/")); 343 | return dir + "/" + define.url + ".plist"; 344 | }, 345 | getFrameNames:function(assetsFile, startFrame, endFrame) 346 | { 347 | this.addAssets(assetsFile); 348 | var frames = this.framesCache[assetsFile]; 349 | if(frames == null) return []; 350 | if(startFrame == -1) startFrame = 0; 351 | if(endFrame == -1) endFrame = frames.length - 1; 352 | return frames.slice(parseInt(startFrame), parseInt(endFrame) + 1); 353 | }, 354 | getFrameNamesOfDisplay:function(assetsFile, assetID) 355 | { 356 | var define = this.getDisplayDefine(assetsFile, assetID); 357 | if(define == null) throw "There is no display named: " + assetID + " in assetsFile: " + assetsFile; 358 | return this.getFrameNames(assetsFile, define.start, define.end); 359 | }, 360 | getDisplayDefine:function(assetsFile, assetID) 361 | { 362 | this.addAssets(assetsFile); 363 | var key = assetsFile + assetID; 364 | return this.displayDefineCache[key]; 365 | }, 366 | getDisplayNames:function(assetsFile) 367 | { 368 | this.addAssets(assetsFile); 369 | return this.displaysCache[assetsFile] || []; 370 | }, 371 | getRandomDisplayName:function(assetsFile) 372 | { 373 | var names = this.getDisplayNames(assetsFile); 374 | var i = Math.floor(Math.random()*names.length); 375 | return names[i]; 376 | }, 377 | getMc:function(assetsFile, assetID) 378 | { 379 | this.addAssets(assetsFile); 380 | var key = assetsFile + assetID; 381 | return this.mcsCache[key]; 382 | }, 383 | getSubAnims:function(assetsFile, theName) 384 | { 385 | this.addAssets(assetsFile); 386 | var akey = assetsFile + theName; 387 | return this.subAnimsCache[akey] || []; 388 | }, 389 | getFont:function(assetsFile, fontName) 390 | { 391 | this.addAssets(assetsFile); 392 | var key = assetsFile + fontName; 393 | return this.fontsCache[key]; 394 | }, 395 | getToolVersion:function(assetsFile) 396 | { 397 | var v = this.toolsVersion[assetsFile]; 398 | return v || 0; 399 | } 400 | }); 401 | 402 | 403 | 404 | flax.AssetsManager.create = function() 405 | { 406 | var am = new flax.AssetsManager(); 407 | am.init(); 408 | return am; 409 | }; -------------------------------------------------------------------------------- /src/flax/core/Button.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-4-25. 3 | */ 4 | 5 | var ButtonState = { 6 | UP:"up", 7 | OVER:"over", 8 | DOWN:"down", 9 | SELECTED:"selected", 10 | SELECTED_OVER:"selected_over", 11 | SELECTED_DOWN:"selected_down", 12 | DISABLED:"disabled", 13 | LOCKED:"locked" 14 | }; 15 | 16 | MOUSE_DOWN_SCALE = 0.95; 17 | 18 | flax._buttonDefine = { 19 | clickSound:null,//The sound will play when click 20 | group:null,//the button group it belongs to 21 | _playChildrenOnState:false,//If auto play children's animation when change state 22 | _state:null, 23 | _initScaleX:1.0, 24 | _initScaleY:1.0, 25 | _inScaleDown:false, 26 | _inDisabledGray:true, 27 | __isButton:true, 28 | 29 | onEnter:function(){ 30 | this._super(); 31 | // this._state = null 32 | this._initScaleX = this.scaleX; 33 | this._initScaleY = this.scaleY; 34 | flax.inputManager.addListener(this, this._onPress, InputType.press); 35 | flax.inputManager.addListener(this, this._onClick, InputType.click); 36 | //listen the mouse drag event on PC and mobile 37 | flax.inputManager.addListener(this, this._onMove, InputType.move); 38 | //listen the mouse move event on PC 39 | if(!cc.sys.isMobile){ 40 | var self = this; 41 | var mouseListener = cc.EventListener.create({ 42 | event: cc.EventListener.MOUSE, 43 | onMouseMove:function(event){ 44 | if(event.getButton() != 0){ 45 | var evt = {target:self, currentTarget:self}; 46 | if(self.isMouseEnabled()) self._onMove(event, evt); 47 | } 48 | } 49 | }) 50 | cc.eventManager.addListener(mouseListener, this); 51 | } 52 | }, 53 | onExit:function(){ 54 | if(this.group){ 55 | this.group.removeButton(this); 56 | this.group = null; 57 | } 58 | cc.eventManager.removeListener(this); 59 | this._super(); 60 | }, 61 | onRecycle:function(){ 62 | this._super(); 63 | this._playChildrenOnState = false; 64 | this._state = null; 65 | this._inScaleDown = false; 66 | if(this._inDisabledGray) { 67 | // this.setColor(COLOR_WHITE); 68 | } 69 | if(this['disabledCover']) this['disabledCover'].visible = true; 70 | this._inDisabledGray = true; 71 | }, 72 | setState:function(state) 73 | { 74 | // if(this._state == state) return; 75 | var oldSelected = this.isSelected(); 76 | this._state = state; 77 | if(!this.gotoAndStop(this._state)) 78 | { 79 | var optionState = this.isSelected() ? ButtonState.SELECTED : ButtonState.UP; 80 | if(!this.gotoAndStop(optionState)){ 81 | this.gotoAndStop(0); 82 | if(this._state.indexOf("down") > -1) { 83 | this._inScaleDown = true; 84 | this.setScale(this._initScaleX*MOUSE_DOWN_SCALE, this._initScaleY*MOUSE_DOWN_SCALE); 85 | } 86 | if(this._state == ButtonState.DISABLED){ 87 | this._inDisabledGray = true; 88 | // this.setColor(COLOR_GRAY); 89 | if(this['disabledCover']) this['disabledCover'].visible = true; 90 | } 91 | } 92 | } 93 | if(this._state.indexOf("down") == -1 && this._inScaleDown) 94 | { 95 | this.setScale(this._initScaleX, this._initScaleY); 96 | } 97 | if(this._state != ButtonState.DISABLED && this._inDisabledGray) 98 | { 99 | this._inDisabledGray = false; 100 | if(this['disabledCover']) this['disabledCover'].visible = false; 101 | // this.setColor(COLOR_WHITE); 102 | } 103 | this._playOrPauseChildren(); 104 | if(this.isSelected() && !oldSelected && this.group){ 105 | this.group.updateButtons(this); 106 | } 107 | this.handleStateChange(); 108 | }, 109 | handleStateChange:function() 110 | { 111 | //to be override 112 | }, 113 | getState:function() 114 | { 115 | return this._state; 116 | }, 117 | isSelected:function() 118 | { 119 | return this._state && (this._state.indexOf("selected") == 0); 120 | }, 121 | setSelected:function(value) 122 | { 123 | if(this.isSelected() == value || !this.isSelectable() || !this.isMouseEnabled() || this.isLocked()) return; 124 | this.setState(value ? ButtonState.SELECTED : ButtonState.UP); 125 | }, 126 | isSelectable:function() 127 | { 128 | return this.hasLabel(ButtonState.SELECTED); 129 | }, 130 | setMouseEnabled:function(enable) 131 | { 132 | // if(this.isMouseEnabled() == enable) return false; 133 | this.setState(enable ? ButtonState.UP : ButtonState.DISABLED); 134 | return true; 135 | }, 136 | isMouseEnabled:function() 137 | { 138 | return this._state != ButtonState.DISABLED; 139 | }, 140 | setLocked:function(locked) 141 | { 142 | // if(this.isLocked() == locked) return; 143 | this.setState(locked ? ButtonState.LOCKED : ButtonState.UP); 144 | }, 145 | isLocked:function() 146 | { 147 | return this._state == ButtonState.LOCKED; 148 | }, 149 | setPlayChildrenOnState:function(play) 150 | { 151 | if(this._playChildrenOnState == play) return; 152 | this._playChildrenOnState = play; 153 | this._playOrPauseChildren(); 154 | }, 155 | getPlayChildrenOnState:function() 156 | { 157 | return this._playChildrenOnState; 158 | }, 159 | _onPress:function(touch, event) 160 | { 161 | if(this._state == ButtonState.LOCKED || this._state == ButtonState.DISABLED) return; 162 | var sound = this.clickSound || flax.buttonSound; 163 | if(sound) flax.playSound(sound); 164 | this._toSetState(ButtonState.DOWN); 165 | }, 166 | _onClick:function(touch, event) 167 | { 168 | if(this._state == ButtonState.LOCKED || this._state == ButtonState.DISABLED) return; 169 | if(this.isSelectable()) 170 | { 171 | if (!this.isSelected() || this.group){ 172 | this.setState(ButtonState.SELECTED); 173 | }else { 174 | this.setState(ButtonState.UP); 175 | } 176 | }else{ 177 | this.setState(ButtonState.UP); 178 | } 179 | }, 180 | _onMove:function(touch, event) 181 | { 182 | if(this._state == ButtonState.DISABLED || this._state == ButtonState.LOCKED) return; 183 | if(flax.ifTouched(this, touch.getLocation())){ 184 | this._toSetState(cc.sys.isMobile ? ButtonState.DOWN : ButtonState.OVER); 185 | }else{ 186 | this._toSetState(ButtonState.UP); 187 | } 188 | }, 189 | _toSetState:function(state) 190 | { 191 | if(this.isSelectable() && this.isSelected()) 192 | { 193 | if(state == ButtonState.UP) state = ButtonState.SELECTED; 194 | else state = "selected_"+state; 195 | } 196 | this.setState(state); 197 | }, 198 | /** 199 | * Auto play the children's animation on new state if _playChildrenOnState = true 200 | * */ 201 | _playOrPauseChildren:function() 202 | { 203 | var i = this.childrenCount; 204 | while(i--){ 205 | var child = this.children[i]; 206 | if(!flax.isFlaxSprite(child)) continue; 207 | if(this._playChildrenOnState) { 208 | child.autoPlayChildren = true; 209 | child.play(); 210 | }else{ 211 | child.autoPlayChildren = false; 212 | child.stop(); 213 | } 214 | } 215 | } 216 | }; 217 | 218 | flax.SimpleButton = flax.Animator.extend(flax._buttonDefine); 219 | flax.SimpleButton.create = function(assetsFile, assetID) 220 | { 221 | var btn = new flax.SimpleButton(assetsFile, assetID); 222 | btn.clsName = "flax.SimpleButton"; 223 | btn.setState(ButtonState.UP); 224 | return btn; 225 | }; 226 | 227 | //Avoid to advanced compile mode 228 | window['flax']['SimpleButton'] = flax.SimpleButton; 229 | 230 | var _p = flax.SimpleButton.prototype; 231 | /** @expose */ 232 | _p.state; 233 | cc.defineGetterSetter(_p, "state", _p.getState, _p.setState); 234 | /** @expose */ 235 | _p.playChildrenOnState; 236 | cc.defineGetterSetter(_p, "playChildrenOnState", _p.getPlayChildrenOnState, _p.setPlayChildrenOnState); 237 | /** @expose */ 238 | _p.selected; 239 | cc.defineGetterSetter(_p, "selected", _p.isSelected, _p.setSelected); 240 | 241 | flax.Button = flax.MovieClip.extend(flax._buttonDefine); 242 | flax.Button.create = function(assetsFile, assetID) 243 | { 244 | var btn = new flax.Button(assetsFile, assetID); 245 | btn.clsName = "flax.Button"; 246 | btn.setState(ButtonState.UP); 247 | return btn; 248 | }; 249 | 250 | //Avoid to advanced compile mode 251 | window['flax']['Button'] = flax.Button; 252 | 253 | _p = flax.Button.prototype; 254 | /** @expose */ 255 | _p.state; 256 | cc.defineGetterSetter(_p, "state", _p.getState, _p.setState); 257 | /** @expose */ 258 | _p.playChildrenOnState; 259 | cc.defineGetterSetter(_p, "playChildrenOnState", _p.getPlayChildrenOnState, _p.setPlayChildrenOnState); 260 | /** @expose */ 261 | _p.selected; 262 | cc.defineGetterSetter(_p, "selected", _p.isSelected, _p.setSelected); 263 | 264 | flax.ButtonGroup = cc.Class.extend({ 265 | buttons:null, 266 | selectedButton:null, 267 | onSelected:null, 268 | ctor:function() 269 | { 270 | this.buttons = []; 271 | this.onSelected = new signals.Signal(); 272 | }, 273 | addButton:function(buttons) 274 | { 275 | if(!(buttons instanceof Array)) { 276 | buttons = Array.prototype.slice.call(arguments); 277 | } 278 | for(var i = 0; i < buttons.length; i++){ 279 | var btn = buttons[i]; 280 | var btn = buttons[i]; 281 | if(!flax.isButton(btn)) continue; 282 | if(this.buttons.indexOf(btn) > -1) continue; 283 | this.buttons.push(btn); 284 | btn.group = this; 285 | } 286 | }, 287 | removeButton:function(button) 288 | { 289 | var i = this.buttons.indexOf(button); 290 | if(i > -1){ 291 | this.buttons.splice(i, 1); 292 | button.group = null; 293 | if(this.selectedButton == button){ 294 | // this.selectedButton = this.buttons[0]; 295 | // if(this.selectedButton) this.selectedButton.setState(ButtonState.SELECTED); 296 | } 297 | } 298 | if(this.buttons.length == 0){ 299 | this.onSelected.removeAll(); 300 | this.onSelected = null; 301 | } 302 | }, 303 | updateButtons:function(newSelected) 304 | { 305 | for(var i = 0; i < this.buttons.length; i++){ 306 | var btn = this.buttons[i]; 307 | if(btn != newSelected && btn.isMouseEnabled() && !btn.isLocked()){ 308 | btn.setState(ButtonState.UP); 309 | } 310 | } 311 | this.selectedButton = newSelected; 312 | //If touched or just call setSelected 313 | var ifTouch = flax.mousePos && flax.ifTouched(newSelected, flax.mousePos); 314 | this.onSelected.dispatch(newSelected, ifTouch); 315 | } 316 | }); -------------------------------------------------------------------------------- /src/flax/core/DebugDraw.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-8-19. 3 | */ 4 | 5 | flax.__drawNode = null; 6 | 7 | flax.createDrawNode = function(parent, zIndex){ 8 | 9 | if(flax.__drawNode && flax.__drawNode.parent && !parent) return; 10 | 11 | if(flax.__drawNode == null) { 12 | flax.__drawNode = cc.DrawNode.create(); 13 | } 14 | if(flax.currentScene) { 15 | if(!parent) parent = flax.currentScene; 16 | if(flax.__drawNode.parent && flax.__drawNode.parent != parent){ 17 | flax.__drawNode.removeFromParent(); 18 | flax.__drawNode.clear(); 19 | } 20 | if(flax.__drawNode.parent == null) parent.addChild(flax.__drawNode); 21 | flax.__drawNode.zIndex = zIndex || 99999; 22 | } 23 | }; 24 | 25 | flax.clearDraw = function(destroy) 26 | { 27 | if(flax.__drawNode == null) return; 28 | flax.__drawNode.clear(); 29 | if(destroy === true) { 30 | flax.__drawNode.removeFromParent(); 31 | flax.__drawNode = null; 32 | } 33 | }; 34 | 35 | flax.drawLine = function(from, to, lineWidth, lineColor) 36 | { 37 | flax.createDrawNode(); 38 | if(lineWidth == null) lineWidth = 1; 39 | if(lineColor == null) lineColor = cc.color(255, 0, 0, 255); 40 | flax.__drawNode.drawSegment(from, to, lineWidth, lineColor); 41 | }; 42 | flax.drawRay = function(from, rotation, length, lineWidth, lineColor) 43 | { 44 | flax.drawLine(from, flax.getPointOnCircle(from, length, rotation), lineWidth, lineColor); 45 | }; 46 | flax.drawRect = function(rect, lineWidth, lineColor, fillColor) 47 | { 48 | flax.createDrawNode(); 49 | if(lineWidth == null) lineWidth = 1; 50 | if(lineColor == null) lineColor = cc.color(255, 0, 0, 255); 51 | var dp = cc.pAdd(cc.p(rect.x, rect.y), cc.p(rect.width, rect.height)); 52 | flax.__drawNode.drawRect(cc.p(rect.x, rect.y), dp, fillColor, lineWidth, lineColor); 53 | }; 54 | flax.drawStageRect = function() 55 | { 56 | var w = h = 2; 57 | flax.drawRect(cc.rect(flax.stageRect.x + w, flax.stageRect.y + h, flax.stageRect.width - 2*w, flax.stageRect.height - 2*h)); 58 | } 59 | flax.drawCircle = function(center, radius, lineWidth, lineColor) 60 | { 61 | flax.createDrawNode(); 62 | if(lineWidth == null) lineWidth = 1; 63 | if(lineColor == null) lineColor = cc.color(255, 0, 0, 255); 64 | flax.__drawNode.drawCircle(center, radius, 360, 360, false, lineWidth, lineColor); 65 | }; 66 | flax.drawDot = function(center, radius, color) 67 | { 68 | flax.createDrawNode(); 69 | if(radius == null) radius = 3; 70 | if(color == null) color = cc.color(255, 0, 0, 255); 71 | flax.__drawNode.drawDot(center, radius,color); 72 | }; -------------------------------------------------------------------------------- /src/flax/core/FlaxLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-12-29. 3 | */ 4 | 5 | /** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ 6 | /**rawinflate*/ 7 | (function() {'use strict';var l=this;function p(b,e){var a=b.split("."),c=l;!(a[0]in c)&&c.execScript&&c.execScript("var "+a[0]);for(var d;a.length&&(d=a.shift());)!a.length&&void 0!==e?c[d]=e:c=c[d]?c[d]:c[d]={}};var q="undefined"!==typeof Uint8Array&&"undefined"!==typeof Uint16Array&&"undefined"!==typeof Uint32Array&&"undefined"!==typeof DataView;function t(b){var e=b.length,a=0,c=Number.POSITIVE_INFINITY,d,f,g,h,k,m,r,n,s,J;for(n=0;na&&(a=b[n]),b[n]>=1;J=g<<16|n;for(s=m;s>>=1;switch(b){case 0:var e=this.input,a=this.d,c=this.b,d=this.a,f=e.length,g=void 0,h=void 0,k=c.length,m=void 0;this.c=this.f=0;if(a+1>=f)throw Error("invalid uncompressed block header: LEN");g=e[a++]|e[a++]<<8;if(a+1>=f)throw Error("invalid uncompressed block header: NLEN");h=e[a++]|e[a++]<<8;if(g===~h)throw Error("invalid uncompressed block header: length verify");if(a+g>e.length)throw Error("input buffer is broken");switch(this.i){case w:for(;d+ 10 | g>c.length;){m=k-d;g-=m;if(q)c.set(e.subarray(a,a+m),d),d+=m,a+=m;else for(;m--;)c[d++]=e[a++];this.a=d;c=this.e();d=this.a}break;case v:for(;d+g>c.length;)c=this.e({o:2});break;default:throw Error("invalid inflate mode");}if(q)c.set(e.subarray(a,a+g),d),d+=g,a+=g;else for(;g--;)c[d++]=e[a++];this.d=a;this.a=d;this.b=c;break;case 1:this.j(y,z);break;case 2:A(this);break;default:throw Error("unknown BTYPE: "+b);}}return this.m()}; 11 | var B=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],C=q?new Uint16Array(B):B,D=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],E=q?new Uint16Array(D):D,F=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],G=q?new Uint8Array(F):F,H=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],I=q?new Uint16Array(H):H,K=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13, 12 | 13],L=q?new Uint8Array(K):K,M=new (q?Uint8Array:Array)(288),N,O;N=0;for(O=M.length;N=N?8:255>=N?9:279>=N?7:8;var y=t(M),P=new (q?Uint8Array:Array)(30),Q,R;Q=0;for(R=P.length;Q=g)throw Error("input buffer is broken");a|=d[f++]<>>e;b.c=c-e;b.d=f;return h} 13 | function S(b,e){for(var a=b.f,c=b.c,d=b.input,f=b.d,g=d.length,h=e[0],k=e[1],m,r;c=g);)a|=d[f++]<>>16;b.f=a>>r;b.c=c-r;b.d=f;return m&65535} 14 | function A(b){function e(a,b,c){var e,d=this.p,f,g;for(g=0;gf)c>=d&&(this.a=c,a=this.e(),c=this.a),a[c++]=f;else{g=f-257;k=E[g];0=d&&(this.a=c,a=this.e(),c=this.a);for(;k--;)a[c]=a[c++-h]}for(;8<=this.c;)this.c-=8,this.d--;this.a=c}; 16 | u.prototype.t=function(b,e){var a=this.b,c=this.a;this.n=b;for(var d=a.length,f,g,h,k;256!==(f=S(this,b));)if(256>f)c>=d&&(a=this.e(),d=a.length),a[c++]=f;else{g=f-257;k=E[g];0d&&(a=this.e(),d=a.length);for(;k--;)a[c]=a[c++-h]}for(;8<=this.c;)this.c-=8,this.d--;this.a=c}; 17 | u.prototype.e=function(){var b=new (q?Uint8Array:Array)(this.a-32768),e=this.a-32768,a,c,d=this.b;if(q)b.set(d.subarray(32768,b.length));else{a=0;for(c=b.length;aa;++a)d[a]=d[e+a];this.a=32768;return d}; 18 | u.prototype.v=function(b){var e,a=this.input.length/this.d+1|0,c,d,f,g=this.input,h=this.b;b&&("number"===typeof b.o&&(a=b.o),"number"===typeof b.r&&(a+=b.r));2>a?(c=(g.length-this.d)/this.n[2],f=258*(c/2)|0,d=fe&&(this.b.length=e),b=this.b);return this.buffer=b};p("Zlib.RawInflate",u);p("Zlib.RawInflate.prototype.decompress",u.prototype.u);var T={ADAPTIVE:v,BLOCK:w},U,V,W,X;if(Object.keys)U=Object.keys(T);else for(V in U=[],W=0,T)U[W++]=V;W=0;for(X=U.length;W -1) { 141 | cc.log(this.assetID+": anchor has been bound, "+anchorName); 142 | return false; 143 | } 144 | if(alwaysBind !== false) this._anchorBindings.push(node); 145 | node.__anchor__ = anchorName; 146 | this._updateAnchorNode(node, this.getAnchor(anchorName)); 147 | if(node.parent != this){ 148 | node.removeFromParent(false); 149 | this.addChild(node); 150 | } 151 | return true; 152 | }, 153 | _updateAnchorNode:function(node, anchor) 154 | { 155 | if(anchor == null) return; 156 | node.x = anchor.x; 157 | node.y = anchor.y; 158 | node.zIndex = anchor.zIndex; 159 | node.rotation = anchor.rotation; 160 | }, 161 | //todo, setScale has issue in JSB 162 | // setScale:function(sx, sy) 163 | // { 164 | // if(flax.Scale9Image && target instanceof flax.Scale9Image){ 165 | // if(sy == null){ 166 | // this._sx = sx.x; 167 | // this._sy = sx.y; 168 | // }else{ 169 | // this._sx = sx; 170 | // this._sy = sy; 171 | // } 172 | // this._updateSize(sx, sy); 173 | // }else{ 174 | // this._super(sx, sy); 175 | // } 176 | // }, 177 | setScaleX:function(sx) 178 | { 179 | if(flax.Scale9Image && this instanceof flax.Scale9Image){ 180 | this._sx = sx; 181 | this._updateSize(sx, this._sy); 182 | }else{ 183 | cc.Node.prototype.setScaleX.call(this, sx); 184 | } 185 | }, 186 | setScaleY:function(sy) 187 | { 188 | if(flax.Scale9Image && this instanceof flax.Scale9Image){ 189 | this._sy = sy; 190 | this._updateSize(this._sx, sy); 191 | }else{ 192 | cc.Node.prototype.setScaleY.call(this, sy); 193 | } 194 | }, 195 | _updateSize:function(sx, sy) 196 | { 197 | if(this._imgSize == null) return; 198 | this.width = this._imgSize.width*sx; 199 | this.height = this._imgSize.height*sy; 200 | }, 201 | onNewSource:function() 202 | { 203 | 204 | } 205 | }; 206 | 207 | flax.Image = cc.Sprite.extend(flax._image); 208 | 209 | if(cc.Scale9Sprite) { 210 | flax.Scale9Image = cc.Scale9Sprite.extend(flax._image); 211 | 212 | var _p = flax.Image.prototype; 213 | //cc.defineGetterSetter(_p, "scale", _p.getScale, _p.setScale); 214 | cc.defineGetterSetter(_p, "scaleX", _p.getScaleX, _p.setScaleX); 215 | cc.defineGetterSetter(_p, "scaleY", _p.getScaleY, _p.setScaleY); 216 | 217 | _p = flax.Scale9Image.prototype; 218 | //cc.defineGetterSetter(_p, "scale", _p.getScale, _p.setScale); 219 | cc.defineGetterSetter(_p, "scaleX", _p.getScaleX, _p.setScaleX); 220 | cc.defineGetterSetter(_p, "scaleY", _p.getScaleY, _p.setScaleY); 221 | 222 | //Avoid to advanced compile mode 223 | window['flax']['Image'] = flax.Image; 224 | window['flax']['Scale9Image'] = flax.Scale9Image; 225 | } 226 | 227 | flax.Image.create = function(assetsFile, assetID) 228 | { 229 | var define = flax.assetsManager.getDisplayDefine(assetsFile, assetID); 230 | if(define['scale9']) { 231 | if(flax.Scale9Image == null) throw "Please add module of 'gui' into project.json if you want to use Scale9Image!"; 232 | var img = new flax.Scale9Image(assetsFile, assetID); 233 | }else{ 234 | img = new flax.Image(assetsFile, assetID); 235 | } 236 | return img; 237 | } -------------------------------------------------------------------------------- /src/flax/core/InputManager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-2-5. 3 | */ 4 | var InputType = { 5 | press:"onPress", 6 | up:"onUp",//The touch position maybe not within the press target 7 | click:"onClick", 8 | move:"onMouseMove",//The touch position maybe not within the press target 9 | keyPress:"onKeyPress", 10 | keyUp:"onKeyUp" 11 | }; 12 | 13 | flax.InputManager = cc.Node.extend({ 14 | enabled:true, 15 | nullEnabled:false, 16 | inTouching:false, 17 | inDragging:false, 18 | justDragged:false, 19 | justDragDist:0, 20 | _masks:[], 21 | _callbacks:{}, 22 | _keyboardCallbacks:{}, 23 | _keyboardListener:null, 24 | _touchListeners:null, 25 | 26 | ctor:function() 27 | { 28 | cc.Node.prototype.ctor.call(this); 29 | this._masks = []; 30 | this.inTouching = false; 31 | this._callbacks = {}; 32 | this._keyboardCallbacks = {}; 33 | this._keyboardListener = null; 34 | this._touchListeners = {}; 35 | }, 36 | onEnter:function() 37 | { 38 | this._super(); 39 | 40 | var self = this; 41 | 42 | //listen the mouse move event on PC 43 | if(!cc.sys.isMobile){ 44 | var mouseListener = cc.EventListener.create({ 45 | event: cc.EventListener.MOUSE, 46 | onMouseMove:function(event){ 47 | //event.getButton() == 0 means left mouse is in pressing 48 | self.inDragging = event.getButton() == 0; 49 | self.justDragged = self.inDragging; 50 | if(self.inDragging) { 51 | self.justDragDist += cc.pLength(event.getDelta()); 52 | } 53 | //dispatch mouse hover event 54 | if(!self.inDragging){ 55 | var evt = {target:self, currentTarget:self}; 56 | self._dispatchOne(self, event, evt, InputType.move); 57 | //todo, dispatch for every single target 58 | // self._dispatch(self, event, evt, InputType.move); 59 | } 60 | flax.mousePos = event.getLocation(); 61 | } 62 | }) 63 | cc.eventManager.addListener(mouseListener, this); 64 | } 65 | 66 | var touchListener = cc.EventListener.create({ 67 | event: cc.EventListener.TOUCH_ONE_BY_ONE, 68 | swallowTouches: false, 69 | onTouchBegan:function(touch, event) 70 | { 71 | flax.mousePos = touch.getLocation(); 72 | if(!self.nullEnabled) return false; 73 | if (!self.enabled) return false; 74 | self.inDragging = false; 75 | self.justDragged = false; 76 | self.justDragDist = 0; 77 | self.inTouching = true; 78 | self._dispatchOne(self, touch, event, InputType.press); 79 | return true; 80 | }, 81 | onTouchEnded:function(touch, event) 82 | { 83 | if(!self.nullEnabled) return; 84 | self.inDragging = false; 85 | self.inTouching = false; 86 | self._dispatchOne(self, touch, event, InputType.up); 87 | self._dispatchOne(self, touch, event, InputType.click); 88 | }, 89 | onTouchMoved:function(touch, event) 90 | { 91 | flax.mousePos = touch.getLocation(); 92 | if(!self.nullEnabled) return; 93 | self.inDragging = true; 94 | self.justDragged = true; 95 | self.justDragDist += cc.pLength(touch.getDelta()); 96 | self._dispatchOne(self, touch, event, InputType.move); 97 | } 98 | }); 99 | cc.eventManager.addListener(touchListener, this); 100 | }, 101 | onExit:function(){ 102 | this._super(); 103 | this.removeAllTouchListeners(); 104 | this.removeAllKeyboardListeners(); 105 | this.removeAllMasks(); 106 | // cc.eventManager.removeAllListeners(); 107 | }, 108 | /** 109 | * Add a Sprite node which will permitted the lower sprite to get touch event callback 110 | * */ 111 | addMask:function(mask){ 112 | if(this._masks.indexOf(mask) > -1) return; 113 | this._masks.push(mask); 114 | mask.__isInputMask = true; 115 | }, 116 | removeMask:function(mask){ 117 | var i = this._masks.indexOf(mask); 118 | if(i > -1) { 119 | this._masks.splice(i, 1); 120 | mask.__isInputMask = false; 121 | } 122 | }, 123 | removeAllMasks:function(){ 124 | var i = this._masks.length; 125 | while(i--){ 126 | this._masks[i].__isInputMask = false; 127 | this._masks.splice(i, 1); 128 | } 129 | this._masks.length = 0; 130 | }, 131 | _compareRealZIndex:function(node0, node1){ 132 | if(!node0.parent || !node1.parent) return 1; 133 | if(node0.parent == node1.parent) return this._childIsOnFront(node0, node1); 134 | 135 | var theSameParent = null; 136 | var theSameIndex = 0; 137 | 138 | var parents0 = []; 139 | var node = node0.parent; 140 | while(node){ 141 | parents0.push(node); 142 | node = node.parent; 143 | } 144 | 145 | var parents1 = []; 146 | node = node1.parent; 147 | while(node){ 148 | theSameIndex = parents0.indexOf(node); 149 | if(theSameIndex > -1) { 150 | theSameParent = node; 151 | break; 152 | } 153 | parents1.push(node); 154 | node = node.parent; 155 | } 156 | parents0 = parents0.slice(0, theSameIndex); 157 | var front = this._childIsOnFront(parents0[parents0.length - 1] || node0, parents1[parents1.length - 1] || node1, theSameParent); 158 | return front ? 1 : -1; 159 | }, 160 | _childIsOnFront:function(child0, child1, parent){ 161 | if(parent == null) parent = child0.parent; 162 | return parent.children.indexOf(child0) > parent.children.indexOf(child1); 163 | }, 164 | /** 165 | * @param{cc.Node} target the target want to receive the touch event, if target is null, then global event will be triggered 166 | * for keyboard event, the target will be the context if the real context is null 167 | * @param{function} func function to call back, for touch event: func(touch, event),{event.currentTarget, event.target} 168 | * for keyboard event: func(key){}; 169 | * @param{string} type event type as InputType said 170 | * @param{cc.Node} context the callback context of "THIS", if null, use target as the context 171 | * Note: If the target is null, then listen the global event, in this instance, be sure to REMOVE the listener manually 172 | * on the sprite exit, otherwise, a new sprite will not receive the event again! 173 | * */ 174 | addListener:function(target, func, type, context) 175 | { 176 | if(func == null) { 177 | throw "Event callback can not be null!" 178 | } 179 | var isKeyboardEvent = (type == InputType.keyPress || type == InputType.keyUp); 180 | if(target == null) { 181 | target = this; 182 | if(!isKeyboardEvent) { 183 | cc.log("Listening target is null, make sure you want to listen to the full screen input!"); 184 | } 185 | } 186 | 187 | if(isKeyboardEvent) { 188 | var arr = this._keyboardCallbacks[type]; 189 | if(arr == null) { 190 | arr = []; 191 | this._keyboardCallbacks[type] = arr; 192 | } 193 | //Make sure no duplicated listener 194 | var i = arr.length; 195 | while(i--){ 196 | if(arr[i].func == func) return; 197 | } 198 | arr.push({func:func, context:context || target}); 199 | if(!this._keyboardListener) { 200 | this._createKeyboardListener(); 201 | } 202 | return; 203 | } 204 | 205 | type = (type == null) ? InputType.click : type; 206 | if(target.__instanceId == null) target.__instanceId = ClassManager.getNewInstanceId(); 207 | var arr = this._callbacks[target.__instanceId]; 208 | if(arr == null){ 209 | arr = []; 210 | this._callbacks[target.__instanceId] = arr; 211 | if(target != this) { 212 | var listener = this._createListener(target, true); 213 | this._touchListeners[target.__instanceId] = listener; 214 | } 215 | } 216 | //Make sure no duplicated listener 217 | var i = arr.length; 218 | while(i--){ 219 | if(arr[i].type == type && arr[i].func == func) return; 220 | } 221 | var callback = {type:type, func:func, context:context || target}; 222 | arr.push(callback); 223 | }, 224 | removeListener:function(target, func, type) 225 | { 226 | if(target == null) target = this; 227 | var calls = this._callbacks[target.__instanceId]; 228 | if(calls && (type == null || (type != InputType.keyPress && type != InputType.keyUp))) { 229 | // this.scheduleOnce(function(){ 230 | var call = null; 231 | var i = calls.length; 232 | if(func || type) { 233 | while(i--){ 234 | call = calls[i]; 235 | if((!type || call.type == type) && (!func || call.func == func)) { 236 | calls.splice(i, 1); 237 | } 238 | } 239 | } 240 | if(calls.length == 0 || (!func && !type)){ 241 | delete this._callbacks[target.__instanceId]; 242 | var listener = this._touchListeners[target.__instanceId]; 243 | if(listener){ 244 | //todo,3.5 cause Invalid native object error! 245 | // cc.eventManager.removeListener(listener); 246 | delete this._touchListeners[target.__instanceId]; 247 | } 248 | } 249 | // },0.01); 250 | } 251 | if(func && (type == null || type == InputType.keyPress || type == InputType.keyUp)){ 252 | if(type == null) { 253 | calls = this._keyboardCallbacks[InputType.keyPress] || []; 254 | calls = calls.concat(this._keyboardCallbacks[InputType.keyUp] || []); 255 | }else{ 256 | calls = this._keyboardCallbacks[type]; 257 | } 258 | if(calls && calls.length){ 259 | // this.scheduleOnce(function(){ 260 | var call = null; 261 | var i = calls.length; 262 | while(i--){ 263 | call = calls[i]; 264 | if(call.func == func) calls.splice(i, 1); 265 | } 266 | // },0.01); 267 | } 268 | } 269 | }, 270 | removeAllTouchListeners:function() 271 | { 272 | this._callbacks = {}; 273 | for(var id in this._touchListeners){ 274 | var listener = this._touchListeners[id]; 275 | cc.eventManager.removeListener(listener); 276 | delete this._touchListeners[id]; 277 | 278 | } 279 | }, 280 | removeAllKeyboardListeners:function() 281 | { 282 | this._keyboardCallbacks = {}; 283 | if(this._keyboardListener) { 284 | //todo,3.5 cause Invalid native object error! 285 | // cc.eventManager.removeListener(this._keyboardListener); 286 | this._keyboardListener = null; 287 | } 288 | }, 289 | handleTouchBegan:function(touch, event) 290 | { 291 | if (!this.enabled) return false; 292 | 293 | var target = event.getCurrentTarget(); 294 | 295 | if(this._ifTargetIgnore(target, touch)) return false; 296 | var pos = touch.getLocation(); 297 | 298 | //handle the masks 299 | if(!this._ifNotMasked(target, pos)) return false; 300 | 301 | event.currentTarget = target; 302 | event.target = this._findRealTarget(target, pos) || target; 303 | //if currentTarget is cc.Layer or flax.MovieClip and hasn't touch any of it's child, then ignore! 304 | if((target instanceof cc.Layer || target instanceof flax.MovieClip) && event.target == target) { 305 | return false; 306 | } 307 | this._dispatch(target, touch, event, InputType.press); 308 | // cc.log("touch begin result: "+target.name+", "+target.assetID); 309 | return true; 310 | }, 311 | handleTouchEnded:function(touch, event) 312 | { 313 | var target = event.getCurrentTarget(); 314 | 315 | event.currentTarget = target; 316 | event.target = this._findRealTarget(target, touch.getLocation()) || target; 317 | 318 | this._dispatch(target, touch, event, InputType.up); 319 | // cc.log("touch end: "+this.name+", "+this.type+", "+this._itemTouched); 320 | var onTarget = flax.ifTouched(target, touch.getLocation()); 321 | if(onTarget) this._dispatch(target, touch, event, InputType.click); 322 | }, 323 | handleTouchMoved:function(touch, event) 324 | { 325 | var target = event.getCurrentTarget(); 326 | // cc.log("moving: "+target.clsName); 327 | this._dispatch(target, touch, event, InputType.move); 328 | }, 329 | _createListener:function(target, swallow) 330 | { 331 | var self = this; 332 | var listener = cc.EventListener.create({ 333 | event: cc.EventListener.TOUCH_ONE_BY_ONE, 334 | swallowTouches: swallow, 335 | onTouchBegan:function(touch, event) 336 | { 337 | return self.handleTouchBegan(touch, event); 338 | }, 339 | onTouchEnded:function(touch, event) 340 | { 341 | self.handleTouchEnded(touch, event); 342 | }, 343 | onTouchMoved:function(touch, event) 344 | { 345 | self.handleTouchMoved(touch, event); 346 | }, 347 | onTouchCancelled:function(touch, event){ 348 | self.handleTouchEnded(touch, event); 349 | } 350 | }); 351 | cc.eventManager.addListener(listener, target); 352 | return listener; 353 | }, 354 | _createKeyboardListener:function() 355 | { 356 | var self = this; 357 | this._keyboardListener = { 358 | event: cc.EventListener.KEYBOARD, 359 | onKeyPressed: function(keyCode, event){ 360 | self._dispatchKeyboardEvent(keyCode, InputType.keyPress); 361 | }, 362 | onKeyReleased: function(keyCode, event){ 363 | self._dispatchKeyboardEvent(keyCode, InputType.keyUp); 364 | } 365 | }; 366 | cc.eventManager.addListener(this._keyboardListener, this); 367 | }, 368 | _ifNotMasked:function(target, pos) 369 | { 370 | var i = this._masks.length; 371 | var mask = null; 372 | var maskTouchedItem = null; 373 | while(i--){ 374 | mask = this._masks[i]; 375 | if(target == mask || flax.isChildOf(target, mask) || flax.isChildOf(mask, target)) continue; 376 | if(this._ifTargetIgnore(mask)) continue; 377 | if(this._compareRealZIndex(mask, target) == 1){ 378 | maskTouchedItem = this._findRealTarget(mask, pos); 379 | if(maskTouchedItem) return false; 380 | } 381 | } 382 | return true; 383 | }, 384 | /** 385 | * Find the real target that clicked, the basic element in the targets... 386 | * */ 387 | _findRealTarget:function(targets, pos) 388 | { 389 | if(!(targets instanceof Array)) targets = [targets]; 390 | var target = null; 391 | var i = targets.length; 392 | while(i--){ 393 | target = targets[i]; 394 | if(this._ifTargetIgnore(target)) continue; 395 | if(target.children.length > 0){ 396 | this._temp = this._findRealTarget(target.children, pos); 397 | if(this._temp) { 398 | return this._temp; 399 | } 400 | } 401 | if(flax.ifTouched(target, pos)){ 402 | return target; 403 | } 404 | } 405 | return null; 406 | }, 407 | _ifTargetIgnore:function(target, touch) 408 | { 409 | if(target == null) return true; 410 | if(!(target instanceof cc.Scene) && !target.parent) return true; 411 | if(!this._ifTargetVisible(target)) return true; 412 | if(target.isMouseEnabled && target.isMouseEnabled() === false) return true; 413 | if(touch && !flax.ifTouched(target, touch.getLocation())) return true; 414 | return false; 415 | }, 416 | _ifTargetVisible:function(target){ 417 | while(target){ 418 | if(!target.visible) return false; 419 | target = target.parent; 420 | } 421 | return true; 422 | }, 423 | _dispatch:function(target, touch, event, type){ 424 | //If the target is button, then don't handle its parent's event 425 | // if(target.__isButton) { 426 | // this._dispatchOne(target, touch, event, type); 427 | // return; 428 | // } 429 | var p = target; 430 | //if the child triggered some event, then its parent should also be informed 431 | var ps = []; 432 | while(p){ 433 | //Fixed the bug when addListener on the callback 434 | var calls = this._callbacks[p.__instanceId]; 435 | if(calls && calls.length){ 436 | ps.push(p); 437 | } 438 | p = p.parent; 439 | } 440 | for(var i = 0; i < ps.length; i++){ 441 | p = ps[i]; 442 | this._dispatchOne(p, touch, event, type); 443 | } 444 | }, 445 | _dispatchOne:function(target, touch, event, type) 446 | { 447 | var calls = this._callbacks[target.__instanceId]; 448 | if(!calls || !calls.length) return; 449 | event.currentTarget = target; 450 | event.inputType = type; 451 | var call = null; 452 | var dispatches = []; 453 | var i = calls.length; 454 | while(i--){ 455 | call = calls[i]; 456 | if(call.type == type) { 457 | dispatches.push(call); 458 | } 459 | } 460 | //handle object according by the time it addListener 461 | i = dispatches.length; 462 | while(i--){ 463 | call = dispatches[i]; 464 | call.func.apply(call.context, [touch, event]); 465 | } 466 | }, 467 | _dispatchKeyboardEvent:function(keyCode, type) 468 | { 469 | var calls = this._keyboardCallbacks[type]; 470 | if(!calls || !calls.length) return; 471 | var key = this._getNativeKeyName(keyCode); 472 | var call = null; 473 | var dispatches = []; 474 | var i = calls.length; 475 | while(i--){ 476 | call = calls[i]; 477 | dispatches.push(call); 478 | } 479 | //handle object according by the time it addListener 480 | i = dispatches.length; 481 | while(i--){ 482 | call = dispatches[i]; 483 | call.func.apply(call.context, [key]); 484 | } 485 | }, 486 | _getNativeKeyName:function(keyCode) { 487 | var allCode = Object.getOwnPropertyNames(flax.KEY); 488 | var keyName = ""; 489 | for(var x in allCode){ 490 | if(flax.KEY[allCode[x]] == keyCode){ 491 | keyName = allCode[x]; 492 | break; 493 | } 494 | } 495 | return keyName; 496 | } 497 | }); 498 | //Fixed bug in advanced mode compile when use cc.KEY 499 | flax.KEY = { 500 | 'none':0, 501 | 502 | // android 503 | 'back':6, 504 | 'menu':18, 505 | 506 | 'backspace':8, 507 | 'tab':9, 508 | 509 | 'enter':13, 510 | 511 | 'shift':16, //should use shiftkey instead 512 | 'ctrl':17, //should use ctrlkey 513 | 'alt':18, //should use altkey 514 | 'pause':19, 515 | 'capslock':20, 516 | 517 | 'escape':27, 518 | 'space':32, 519 | 'pageup':33, 520 | 'pagedown':34, 521 | 'end':35, 522 | 'home':36, 523 | 'left':37, 524 | 'up':38, 525 | 'right':39, 526 | 'down':40, 527 | 'select':41, 528 | 529 | 'insert':45, 530 | 'Delete':46, 531 | '0':48, 532 | '1':49, 533 | '2':50, 534 | '3':51, 535 | '4':52, 536 | '5':53, 537 | '6':54, 538 | '7':55, 539 | '8':56, 540 | '9':57, 541 | 'a':65, 542 | 'b':66, 543 | 'c':67, 544 | 'd':68, 545 | 'e':69, 546 | 'f':70, 547 | 'g':71, 548 | 'h':72, 549 | 'i':73, 550 | 'j':74, 551 | 'k':75, 552 | 'l':76, 553 | 'm':77, 554 | 'n':78, 555 | 'o':79, 556 | 'p':80, 557 | 'q':81, 558 | 'r':82, 559 | 's':83, 560 | 't':84, 561 | 'u':85, 562 | 'v':86, 563 | 'w':87, 564 | 'x':88, 565 | 'y':89, 566 | 'z':90, 567 | //todo for advanced cimpile 568 | num0:96, 569 | num1:97, 570 | num2:98, 571 | num3:99, 572 | num4:100, 573 | num5:101, 574 | num6:102, 575 | num7:103, 576 | num8:104, 577 | num9:105, 578 | '*':106, 579 | '+':107, 580 | '-':109, 581 | 'numdel':110, 582 | '/':111, 583 | f1:112, //f1-f12 dont work on ie 584 | f2:113, 585 | f3:114, 586 | f4:115, 587 | f5:116, 588 | f6:117, 589 | f7:118, 590 | f8:119, 591 | f9:120, 592 | f10:121, 593 | f11:122, 594 | f12:123, 595 | 596 | numlock:144, 597 | scrolllock:145, 598 | 599 | ';':186, 600 | semicolon:186, 601 | equal:187, 602 | '=':187, 603 | ',':188, 604 | comma:188, 605 | dash:189, 606 | '.':190, 607 | period:190, 608 | forwardslash:191, 609 | grave:192, 610 | '[':219, 611 | openbracket:219, 612 | backslash:220, 613 | ']':221, 614 | closebracket:221, 615 | quote:222, 616 | 617 | // gamepad controll 618 | dpadLeft:1000, 619 | dpadRight:1001, 620 | dpadUp:1003, 621 | dpadDown:1004, 622 | dpadCenter:1005 623 | } -------------------------------------------------------------------------------- /src/flax/core/Label.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-2-3. 3 | */ 4 | 5 | flax.Label = cc.Sprite.extend({ 6 | mlWidth:0.0, 7 | mlHeight:0.0, 8 | fontName:null, 9 | fontSize:20, 10 | frames:[], 11 | chars:[], 12 | assetsFile:null, 13 | name:null, 14 | params:null, 15 | _str:null, 16 | _gap:0, 17 | _spaceGap:10, 18 | _charCanvas:null, 19 | _fontDefine:null, 20 | 21 | getString:function() 22 | { 23 | return this._str; 24 | }, 25 | setString:function(str) 26 | { 27 | if(str === this._str) return; 28 | this._str = ""+str; 29 | this._updateStr(); 30 | }, 31 | getSpaceGap:function() 32 | { 33 | return this._spaceGap; 34 | }, 35 | setSpaceGap:function(gap) 36 | { 37 | if(this._spaceGap == gap) return; 38 | this._spaceGap = gap; 39 | if(this._str && this._str.indexOf(" ") > -1){ 40 | this._updateStr(); 41 | } 42 | }, 43 | getGap:function() 44 | { 45 | return this._gap; 46 | }, 47 | setGap:function(gap) 48 | { 49 | if(gap == this._gap) return; 50 | this._gap = gap; 51 | if(this._str) 52 | { 53 | this._updateStr(); 54 | } 55 | }, 56 | setFontName:function(font) 57 | { 58 | if(font == null) return; 59 | if(this.fontName != null && this.fontName == font) return; 60 | this.fontName = font; 61 | this._fontDefine = flax.assetsManager.getFont(this.assetsFile, this.fontName); 62 | if(this._fontDefine == null){ 63 | throw "Can't find the font named: " + this.fontName; 64 | } 65 | this.frames = flax.assetsManager.getFrameNames(this.assetsFile, parseInt(this._fontDefine['start']), parseInt(this._fontDefine['end'])); 66 | this.chars = this._fontDefine['chars']; 67 | this.fontSize = parseInt(this._fontDefine['size']); 68 | }, 69 | tweenInt:function(from, to, time){ 70 | this.setString(from); 71 | var sign = flax.numberSign(to - from); 72 | if(sign == 0) return; 73 | 74 | var num = Math.abs(to - from); 75 | var interval = Math.max(time/num, flax.frameInterval); 76 | num = Math.round(time/interval); 77 | sign *= Math.round(Math.abs(to - from)/num); 78 | //todo, num + 10 maybe cause bug! 79 | this.schedule(function(delta){ 80 | var ct = parseInt(this._str); 81 | var ci = ct + sign; 82 | if(sign > 0 && ci > to) ci = to; 83 | else if(sign < 0 && ci < to) ci = to; 84 | if(ci != ct) this.setString(ci); 85 | },interval, num + 10); 86 | }, 87 | _updateStr:function() 88 | { 89 | if(this._charCanvas == null) { 90 | var imgFile = cc.path.changeBasename(this.assetsFile, ".png"); 91 | this._charCanvas = new cc.SpriteBatchNode(imgFile, this._str.length); 92 | this.addChild(this._charCanvas); 93 | } 94 | this._charCanvas.removeAllChildren(); 95 | 96 | this.mlWidth = 0; 97 | this.mlHeight = 0; 98 | for(i = 0; i < this._str.length ; i++) 99 | { 100 | var ch = this._str[i]; 101 | //if it's a break char or other special char, ignore it for now! 102 | if(ch == "\n") 103 | { 104 | continue; 105 | } 106 | if(ch == " ") 107 | { 108 | this.mlWidth += this._spaceGap; 109 | continue; 110 | } 111 | var charIndex = -1; 112 | for(var j = 0; j < this.chars.length; j++) 113 | { 114 | if(this.chars[j] == ch) 115 | { 116 | charIndex = j; 117 | break; 118 | } 119 | } 120 | if(charIndex == -1) 121 | { 122 | cc.log("Not found the char: "+ch + " in the fonts: "+ this.fontName); 123 | continue; 124 | } 125 | 126 | sprite = new cc.Sprite(cc.spriteFrameCache.getSpriteFrame(this.frames[charIndex])); 127 | sprite.anchorX = this._fontDefine.anchorX; 128 | sprite.anchorY = this._fontDefine.anchorY; 129 | // calculate the position of the sprite; 130 | var size = sprite.getContentSize(); 131 | sprite.x = this.mlWidth; 132 | sprite.y = 0; 133 | this.mlWidth += size.width; 134 | if(i != this._str.length -1) this.mlWidth += this._gap; 135 | this.mlHeight = size.height > this.mlHeight ? size.height : this.mlHeight; 136 | this._charCanvas.addChild(sprite); 137 | } 138 | if(this.params){ 139 | //restrain the text within the rectangle 140 | var rx = this.mlWidth/this.params.textWidth; 141 | var ry = this.mlHeight/this.params.textHeight; 142 | var r = Math.max(rx, ry); 143 | var deltaY = 0; 144 | if(r > 1){ 145 | var rscale = 1/r; 146 | this._charCanvas.scale = rscale; 147 | deltaY = this.mlHeight*(1 - 1/r)*r; 148 | this.mlWidth *= rscale; 149 | this.mlHeight *= rscale; 150 | 151 | } 152 | //enable the center align 153 | var deltaX = (this.params.textWidth - this.mlWidth)/2; 154 | i = this._charCanvas.childrenCount; 155 | while(i--){ 156 | charChild = this._charCanvas.children[i]; 157 | if(H_ALIGHS[this.params.textAlign] == "center") charChild.x += deltaX; 158 | else if(H_ALIGHS[this.params.textAlign] == "right") charChild.x += 2*deltaX; 159 | charChild.y -= deltaY; 160 | } 161 | } 162 | this._charCanvas.setContentSize(this.mlWidth, this.mlHeight); 163 | this.setContentSize(this.mlWidth, this.mlHeight); 164 | }, 165 | getRect:function(coordinate) 166 | { 167 | if(coordinate == null) coordinate = true; 168 | var border = 2; 169 | var rect = cc.rect(0.5*this.width/this._str.length, -this.params.textHeight, this.width, this.height + border); 170 | rect.y += (this.params.textHeight - this.height)/2 - border/2; 171 | if(!coordinate) return rect; 172 | var w = rect.width; 173 | var h = rect.height; 174 | var origin = cc.p(rect.x, rect.y); 175 | origin = this.convertToWorldSpace(origin); 176 | if(coordinate instanceof cc.Node) origin = coordinate.convertToNodeSpace(origin); 177 | return cc.rect(origin.x, origin.y, w, h); 178 | }, 179 | destroy:function() 180 | { 181 | this.removeFromParent(); 182 | } 183 | }); 184 | 185 | var _p = flax.Label.prototype; 186 | /** @expose */ 187 | _p.gap; 188 | cc.defineGetterSetter(_p, "gap", _p.getGap, _p.setGap); 189 | /** @expose */ 190 | _p.spaceGap; 191 | cc.defineGetterSetter(_p, "spaceGap", _p.getSpaceGap, _p.setSpaceGap); 192 | /** @expose */ 193 | _p.text; 194 | cc.defineGetterSetter(_p, "text", _p.getString, _p.setString); 195 | 196 | _p = cc.LabelTTF.prototype; 197 | /** @expose */ 198 | _p.text; 199 | cc.defineGetterSetter(_p, "text", _p.getString, _p.setString); 200 | 201 | flax.Label.create = function(assetsFile, data, define) 202 | { 203 | //if the plist was exported by the older version, give a tip 204 | if(data._isText === false){ 205 | throw "The assetsFile: " + assetsFile + " was exported with old version of Flax tool, re-export it to fix the Text issue!"; 206 | } 207 | //Remove all the \ chars in the text in Web 208 | if(!cc.sys.isNative) define.text = define.text.split("\\").join(""); 209 | var lbl = null; 210 | var txtCls = define["class"]; 211 | var bmpFontName = flax.assetsManager.getFont(assetsFile, txtCls); 212 | //input text 213 | if(define.input == true){ 214 | if(cc.EditBox == null){ 215 | throw "If you want to use input text, please add module of 'editbox' into project.json!"; 216 | } 217 | var frames = flax.assetsManager.getFrameNamesOfDisplay(assetsFile, txtCls); 218 | //todo, the size of the edit box is the background's size, not the text 219 | if(flax.Scale9Image == null) throw "Please add module of 'gui' or 'ccui'(cocos 3.10 later) into project.json if you want to use EditBox!"; 220 | lbl = new cc.EditBox(cc.size(data.textWidth, data.textHeight), new cc.Scale9Sprite(frames[0]), 221 | frames[1] ? new cc.Scale9Sprite(frames[1]) : null, 222 | frames[2] ? new cc.Scale9Sprite(frames[2]) : null); 223 | lbl.setFontColor(data.fontColor); 224 | lbl.setFontName(data.font); 225 | lbl.setFontSize(data.fontSize); 226 | //the placeholder text will be cleared when begin to edit 227 | lbl.setPlaceHolder(define.text); 228 | lbl.setPlaceholderFontName(data.font); 229 | lbl.setPlaceholderFontSize(data.fontSize); 230 | // lbl.setPlaceholderFontColor(cc.hexToColor(define.color)); 231 | //set the anchor 232 | var d = flax.assetsManager.getDisplayDefine(assetsFile, txtCls); 233 | lbl.setAnchorPoint(d.anchorX, d.anchorY); 234 | 235 | // lbl.setInputFlag(cc.EDITBOX_INPUT_FLAG_PASSWORD); 236 | // lbl.setMaxLength(20); 237 | // lbl.setDelegate(this); 238 | } 239 | //If it is ttf label(has font and the bitmap font is null, other wise use bitmap label 240 | else if(data.font && bmpFontName == null){ 241 | //todo, if setFontSize bug occur in JSB, pls don't use cc.FontDefinition to create labelTTF 242 | var labelDef = new cc.FontDefinition(); 243 | labelDef.fontName = data.font; 244 | labelDef.fontSize = data.fontSize; 245 | labelDef.textAlign = data.textAlign; 246 | labelDef.verticalAlign = cc.VERTICAL_TEXT_ALIGNMENT_CENTER; 247 | labelDef.fillStyle = data.fontColor; 248 | labelDef.fontDimensions = true; 249 | labelDef.boundingWidth = data.textWidth; 250 | labelDef.boundingHeight = data.textHeight; 251 | //text, fontName, fontSize, dimensions, hAlignment, vAlignment 252 | if(txtCls == "null") { 253 | lbl = new cc.LabelTTF(define.text, labelDef); 254 | }else if(flax.getLanguageStr){ 255 | lbl = new cc.LabelTTF(flax.getLanguageStr(txtCls) || define.text, labelDef); 256 | } 257 | //enable stroke 258 | //lbl.enableStroke(cc.color(255, 0, 0, 255), 5); 259 | //enable shadow 260 | //lbl.enableShadow(cc.color(255,255,255,255),2,5); 261 | //bitmap font text 262 | }else{ 263 | lbl = new flax.Label(); 264 | flax.assetsManager.addAssets(assetsFile); 265 | lbl.assetsFile = assetsFile; 266 | lbl.params = data; 267 | lbl.setFontName(txtCls); 268 | lbl.setAnchorPoint(0, 0); 269 | lbl.setString(define.text); 270 | } 271 | return lbl; 272 | }; 273 | 274 | flax._fontResources = null; 275 | flax.registerFont = function(name, urls) 276 | { 277 | if(!name || !urls) return; 278 | if(typeof urls == "string") urls = [urls]; 279 | if(flax._fontResources == null) flax._fontResources = {}; 280 | flax._fontResources[name] = urls; 281 | }; 282 | -------------------------------------------------------------------------------- /src/flax/core/MovieClip.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-2-14. 3 | */ 4 | 5 | flax.FrameData = cc.Class.extend({ 6 | x:0, 7 | y:0, 8 | rotation:0, 9 | scaleX:1, 10 | scaleY:1, 11 | opacity:255, 12 | zIndex:-1, 13 | skewX:0, 14 | skewY:0, 15 | //ttf text properties 16 | font:null, 17 | fontSize:12, 18 | fontColor:"", 19 | textAlign:"", 20 | textWidth:40, 21 | textHeight:20, 22 | 23 | _isText:false, 24 | _data:null, 25 | _hasSkew:false, 26 | 27 | ctor:function(data){ 28 | this._data = data; 29 | this.x = parseFloat(data[0]); 30 | this.y = parseFloat(data[1]); 31 | this.rotation = parseFloat(data[2]); 32 | this.scaleX = parseFloat(data[3]); 33 | this.scaleY = parseFloat(data[4]); 34 | this.opacity = Math.round(255*parseFloat(data[5])); 35 | if(data.length > 6) this.zIndex = parseInt(data[6]); 36 | if(data.length > 7) this.skewX = parseFloat(data[7]); 37 | if(data.length > 8) this.skewY = parseFloat(data[8]); 38 | this._hasSkew = (data.length > 7); 39 | //the ttf text info 40 | if(data.length > 9) { 41 | this._isText = true; 42 | this.font = data[9]; 43 | this.fontSize = parseInt(data[10]); 44 | this.fontColor = cc.hexToColor(data[11]); 45 | this.textAlign = H_ALIGHS.indexOf(data[12]); 46 | this.textWidth = parseFloat(data[13]); 47 | this.textHeight = parseFloat(data[14]); 48 | } 49 | }, 50 | setForChild:function(child) 51 | { 52 | if(!this._hasSkew) child.setRotation(this.rotation); 53 | child.setScaleX(this.scaleX); 54 | child.setScaleY(this.scaleY); 55 | 56 | if(this._hasSkew){ 57 | child.setRotationX(this.skewX); 58 | child.setRotationY(this.skewY); 59 | } 60 | 61 | if(child.setOpacity) child.setOpacity(this.opacity); 62 | 63 | var x = this.x; 64 | var y = this.y; 65 | //set the ttf text properties 66 | if(this.font && child instanceof cc.LabelTTF) 67 | { 68 | child.setFontName(this.font); 69 | child.setFontFillColor(this.fontColor); 70 | child.setHorizontalAlignment(this.textAlign); 71 | child.setDimensions({width: this.textWidth, height:this.textHeight}); 72 | //todo: fix the bug of cocos: no update when the font color changed 73 | child.setFontSize(this.fontSize - 1); 74 | child.setFontSize(this.fontSize); 75 | //ttf position offset 76 | x += this.textWidth/2; 77 | y -= this.textHeight/2; 78 | } 79 | 80 | child.setPositionX(x); 81 | child.setPositionY(y); 82 | }, 83 | clone:function(){ 84 | return new flax.FrameData(this._data); 85 | } 86 | }); 87 | 88 | flax._movieClip = { 89 | clsName:"flax.MovieClip", 90 | sameFpsForChildren:true,//all children use the same fps with this 91 | createChildFromPool:true, 92 | _autoPlayChildren:false,//auto play children when play 93 | namedChildren:null, 94 | // _stoppingChildren:null, 95 | _theRect:null, 96 | _frameDatas:null, 97 | __isMovieClip:true, 98 | /** 99 | * Replace a child with name of childName by an asset of assetID in assetsFile 100 | * @param {String} childName the child to be replaced 101 | * @param {String} assetID the new assetID 102 | * @param {String} assetsFile the new asset's assetsFile, if null, use this.assetsFile 103 | * */ 104 | replaceChild:function(childName, assetID, assetsFile) 105 | { 106 | var childDefine = this.define['children'][childName]; 107 | if(childDefine == null){ 108 | cc.log("There is no child with named: "+childName +" in MovieClip: "+this.assetID); 109 | return; 110 | } 111 | var child = this.namedChildren[childName]; 112 | if(child) 113 | { 114 | if(!assetsFile) assetsFile = this.assetsFile; 115 | var assetType = flax.assetsManager.getAssetType(assetsFile, assetID); 116 | if(!assetType){ 117 | throw "There is no display with assetID: " + assetID + " in assets: " + assetsFile; 118 | } 119 | if(flax.assetsManager.getAssetType(child.assetsFile, child.assetID) == assetType){ 120 | child.setSource(assetsFile, assetID); 121 | } else { 122 | var autoPlay = child._autoPlayChildren; 123 | child.destroy(); 124 | child = flax.assetsManager.createDisplay(assetsFile, assetID, null, this.createChildFromPool); 125 | child.name = childName; 126 | this.namedChildren[childName] = child; 127 | if(child.__isMovieClip === true && !autoPlay) child.autoPlayChildren = this._autoPlayChildren; 128 | if(this._autoPlayChildren && child.__isFlaxSprite === true) { 129 | this.playing ? child.gotoAndPlay(0) : child.gotoAndStop(0); 130 | } 131 | this[childName] = child; 132 | this.addChild(child); 133 | } 134 | }else{ 135 | childDefine["class"] = assetID; 136 | childDefine.assetsFile = assetsFile; 137 | } 138 | }, 139 | getFrameData:function(childName, frame) 140 | { 141 | if(this._frameDatas[childName] == null) return null; 142 | var frameData = this._frameDatas[childName][frame]; 143 | return frameData; 144 | }, 145 | setOpacity: function (opacity) { 146 | cc.Node.prototype.setOpacity.call(this, opacity); 147 | for(var k in this.namedChildren){ 148 | var child = this.namedChildren[k]; 149 | if(child.setOpacity) child.setOpacity(opacity); 150 | } 151 | }, 152 | setColor: function (color) { 153 | cc.Node.prototype.setColor.call(this, color); 154 | for(var k in this.namedChildren){ 155 | var child = this.namedChildren[k]; 156 | if(child.setColor) child.setColor(color); 157 | } 158 | }, 159 | /** 160 | * Stop the child with name at some frame or label on all frames, if just child.gotAndStop(frameOrLabel), it maybe 161 | * only take effect on some frames instead all frames especially in $ animation 162 | * @param {String|Sprite} nameOrInstance The child or its name 163 | * @param {String|Integer} frameOrLabel The frame or label to stop, if null, set random frame 164 | * */ 165 | // stopChildAt:function(nameOrInstance, frameOrLabel) 166 | // { 167 | // var child = null; 168 | // if(typeof nameOrInstance === "string") { 169 | // child = this.namedChildren[nameOrInstance]; 170 | // if(child == null){ 171 | // cc.log("***Warning--There is no child with name: " + nameOrInstance); 172 | // return; 173 | // } 174 | // }else if(nameOrInstance.__isFlaxSprite === true) { 175 | // child = nameOrInstance; 176 | // if(child.parent != this){ 177 | // cc.log("***Warning--The target is not a child of this!"); 178 | // return; 179 | // } 180 | // }else throw 'Invalid child name of instance!' 181 | // if(frameOrLabel == null) frameOrLabel = flax.randInt(0, child.totalFrames); 182 | // if(child.gotoAndStop(frameOrLabel)){ 183 | // if(this._stoppingChildren == null) this._stoppingChildren = {}; 184 | // this._stoppingChildren[child.name] = frameOrLabel; 185 | // } 186 | // }, 187 | // updateStoppingChildren:function() 188 | // { 189 | // if(this._stoppingChildren){ 190 | // for(var childName in this._stoppingChildren){ 191 | // var child = this.namedChildren[childName]; 192 | // if(child){ 193 | // child.gotoAndStop(this._stoppingChildren[childName]); 194 | // } 195 | // } 196 | // } 197 | // }, 198 | onNewSource:function() 199 | { 200 | for(var childName in this.namedChildren){ 201 | this.namedChildren[childName].destroy(); 202 | delete this.namedChildren[childName]; 203 | delete this[childName]; 204 | } 205 | this.namedChildren = {}; 206 | this.totalFrames = this.define['totalFrames']; 207 | this._theRect = flax._strToRect(this.define['rect']); 208 | this.setContentSize(this._theRect.width, this._theRect.height); 209 | this._initFrameDatas(); 210 | }, 211 | _initFrameDatas:function() 212 | { 213 | this._frameDatas = {}; 214 | for(var childName in this.define['children']) 215 | { 216 | var frames = []; 217 | var fs = this.define['children'][childName].frames; 218 | var i = -1; 219 | while(++i < fs.length){ 220 | var fd = fs[i]; 221 | if(fd){ 222 | fd = fd.split(","); 223 | frames[i] = new flax.FrameData(fd); 224 | } 225 | } 226 | this._frameDatas[childName] = frames; 227 | } 228 | }, 229 | onEnter:function() 230 | { 231 | this._super(); 232 | this.setContentSize(this._theRect.width, this._theRect.height); 233 | }, 234 | doRenderFrame:function(frame) 235 | { 236 | var child; 237 | var childDefine; 238 | var frameData; 239 | for(var childName in this.define['children']) 240 | { 241 | childDefine = this.define['children'][childName]; 242 | frameData = this._frameDatas[childName][frame]; 243 | child = this.namedChildren[childName]; 244 | if(frameData) { 245 | if(child == null){ 246 | //hadle the label text 247 | if(childDefine.text != null){ 248 | child = flax.Label.create(this.assetsFile, frameData, childDefine); 249 | }else{ 250 | child = flax.assetsManager.createDisplay(childDefine.assetsFile || this.assetsFile, childDefine["class"], null, this.createChildFromPool); 251 | } 252 | 253 | child.name = childName; 254 | this.namedChildren[childName] = child; 255 | this[childName] = child; 256 | this.onNewChild(child); 257 | } 258 | frameData.setForChild(child); 259 | //all children use the same fps with this 260 | if(this.sameFpsForChildren) child.fps = this.fps; 261 | // if(child.__isMovieClip === true && !child.getAutoPlayChildren()) child._autoPlayChildren = this._autoPlayChildren; 262 | // if(this._autoPlayChildren && flax.isFlaxSprite(child)) { 263 | // this.playing ? child.play() : child.stop(); 264 | // } 265 | //To fix the zIndex bug when use the old version tool 266 | var zIndex = (frameData.zIndex == -1) ? childDefine['zIndex'] : frameData.zIndex; 267 | if(child.parent != this){ 268 | child.removeFromParent(false); 269 | this.addChild(child, zIndex); 270 | }else if(child.zIndex != zIndex){ 271 | child.zIndex = zIndex; 272 | } 273 | }else if(child) { 274 | if(child.destroy) child.destroy(); 275 | else child.removeFromParent(true); 276 | delete this.namedChildren[childName]; 277 | delete this[childName]; 278 | } 279 | } 280 | }, 281 | stop:function() 282 | { 283 | this._super(); 284 | if(this._autoPlayChildren) { 285 | for(var key in this.namedChildren) { 286 | var child = this.namedChildren[key]; 287 | if(child.__isFlaxSprite === true) { 288 | child.stop(); 289 | } 290 | } 291 | } 292 | }, 293 | play:function() 294 | { 295 | this._super(); 296 | if(this._autoPlayChildren) { 297 | for(var key in this.namedChildren) { 298 | var child = this.namedChildren[key]; 299 | if(child.__isFlaxSprite === true) { 300 | child.play(); 301 | } 302 | } 303 | } 304 | }, 305 | getAutoPlayChildren:function() 306 | { 307 | return this._autoPlayChildren; 308 | }, 309 | setAutoPlayChildren:function(v) 310 | { 311 | if(this._autoPlayChildren == v) return; 312 | this._autoPlayChildren = v; 313 | for(var key in this.namedChildren) { 314 | var child = this.namedChildren[key]; 315 | if(child.__isMovieClip === true) { 316 | child.setAutoPlayChildren(v); 317 | } 318 | if(child.__isFlaxSprite) { 319 | v ? child.play() : child.stop(); 320 | } 321 | } 322 | }, 323 | onNewChild:function(child) 324 | { 325 | if(child.__isMovieClip === true) child.autoPlayChildren = this._autoPlayChildren; 326 | if(this._autoPlayChildren && child.__isFlaxSprite === true) { 327 | this.playing ? child.gotoAndPlay(0) : child.gotoAndStop(0); 328 | } 329 | // if(this._stoppingChildren && child.__isFlaxSprite === true){ 330 | // var frameOrLabel = this._stoppingChildren[child.name]; 331 | // if(frameOrLabel != null) child.gotoAndStop(frameOrLabel); 332 | // } 333 | // if(child.__isMovieClip === true && child._stoppingChildren){ 334 | // child.updateStoppingChildren(); 335 | // } 336 | }, 337 | getDefine:function() 338 | { 339 | var define = flax.assetsManager.getMc(this.assetsFile, this.assetID); 340 | if(define == null) throw "There is no MovieClip named: " + this.assetID + " in assets: " + this.assetsFile + ", or make sure this class extends from the proper class!"; 341 | return define; 342 | }, 343 | getChild:function(name, nest) 344 | { 345 | if(nest === undefined) nest = true; 346 | var child = this.namedChildren[name]; 347 | if(child) return child; 348 | if(!nest) return null; 349 | for(var key in this.namedChildren) { 350 | child = this.namedChildren[key]; 351 | if(child.getChild) { 352 | child = child.getChild(name, nest); 353 | if(child) return child; 354 | } 355 | } 356 | return null; 357 | }, 358 | getChildByAssetID:function(id) 359 | { 360 | var child = null; 361 | for(var key in this.namedChildren) { 362 | child = this.namedChildren[key]; 363 | if(child.assetID == id){ 364 | return child; 365 | } 366 | } 367 | return null; 368 | }, 369 | getLabelText:function(labelName, ifNest) 370 | { 371 | var label = this.getChild(labelName, ifNest === undefined ? true : ifNest); 372 | if(label && (label instanceof flax.Label || label instanceof cc.LabelTTF)) return label.getString(); 373 | return null; 374 | }, 375 | setLabelText:function(labelName, text, ifNest) 376 | { 377 | var label = this.getChild(labelName, ifNest === undefined ? true : ifNest); 378 | if(label && (label instanceof flax.Label || label instanceof cc.LabelTTF)) { 379 | label.setString(text); 380 | return label; 381 | } 382 | return null; 383 | }, 384 | setFPS:function(f) 385 | { 386 | if(this._fps == f) return; 387 | this._fps = f; 388 | this.updateSchedule(); 389 | if(!this.sameFpsForChildren) return; 390 | var child = null; 391 | for(var key in this.namedChildren) { 392 | child = this.namedChildren[key]; 393 | child.fps = this._fps; 394 | } 395 | }, 396 | //todo, not verified yet 397 | // getRect:function(coordinate) 398 | // { 399 | // var rect = null; 400 | // for (var i = 0; i < this.children.length; i++) { 401 | // var child = this.children[i]; 402 | // var r = flax.getRect(child, coordinate); 403 | // if(rect) rect = cc.rectUnion(r, rect); 404 | // else rect = r; 405 | // } 406 | // return rect; 407 | // }, 408 | onRecycle:function() 409 | { 410 | this._super(); 411 | this.sameFpsForChildren = true; 412 | this.createChildFromPool = true; 413 | this._autoPlayChildren = false; 414 | if(RESET_FRAME_ON_RECYCLE){ 415 | for(var key in this.namedChildren) { 416 | var child = this.namedChildren[key]; 417 | if(child.__isFlaxSprite === true) { 418 | child.gotoAndStop(0); 419 | } 420 | } 421 | } 422 | }, 423 | onExit: function () { 424 | this._super(); 425 | for(var childName in this.namedChildren){ 426 | delete this.namedChildren[childName]; 427 | delete this[childName]; 428 | } 429 | //this._childrenDefine = null; 430 | } 431 | }; 432 | 433 | flax.MovieClip = flax.FlaxSprite.extend(flax._movieClip); 434 | flax.MovieClip.create = function(assetsFile, assetID) 435 | { 436 | var mc = new flax.MovieClip(assetsFile, assetID); 437 | mc.clsName = "flax.MovieClip"; 438 | return mc; 439 | }; 440 | 441 | var _p = flax.MovieClip.prototype; 442 | /** @expose */ 443 | _p.autoPlayChildren; 444 | cc.defineGetterSetter(_p, "autoPlayChildren", _p.getAutoPlayChildren, _p.setAutoPlayChildren); 445 | cc.defineGetterSetter(_p, "opacity", _p.getOpacity, _p.setOpacity); 446 | 447 | //Avoid to advanced compile mode 448 | window['flax']['MovieClip'] = flax.MovieClip; 449 | 450 | flax.MovieClipBatch = flax.FlaxSpriteBatch.extend(flax._movieClip); 451 | flax.MovieClipBatch.create = function(assetsFile, assetID) 452 | { 453 | var mc = new flax.MovieClipBatch(assetsFile, assetID); 454 | mc.clsName = "flax.MovieClipBatch"; 455 | return mc; 456 | }; 457 | 458 | _p = flax.MovieClipBatch.prototype; 459 | /** @expose */ 460 | _p.autoPlayChildren; 461 | cc.defineGetterSetter(_p, "autoPlayChildren", _p.getAutoPlayChildren, _p.setAutoPlayChildren); 462 | cc.defineGetterSetter(_p, "opacity", _p.getOpacity, _p.setOpacity); 463 | 464 | //Avoid to advanced compile mode 465 | window['flax']['MovieClipBatch'] = flax.MovieClipBatch; -------------------------------------------------------------------------------- /src/flax/core/ProgressBar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-5-7. 3 | */ 4 | flax.ProgressBarType = { 5 | HORIZONTAL:"horizontal", 6 | VERTICAL:"vertical", 7 | RADIAL:"radial" 8 | }; 9 | flax.ProgressBar = flax.Animator.extend({ 10 | pBar:null, 11 | _type:flax.ProgressBarType.HORIZONTAL, 12 | _reversed:false, 13 | _tween:null, 14 | onEnter:function() 15 | { 16 | this._super(); 17 | }, 18 | getPercentage:function() 19 | { 20 | if(this.pBar) return this.pBar.percentage; 21 | return 0; 22 | }, 23 | setPercentage:function(p) 24 | { 25 | if(this.pBar) this.pBar.percentage = p; 26 | }, 27 | getType:function() 28 | { 29 | return this._type; 30 | }, 31 | setType:function(type) 32 | { 33 | if(this._type == type) return; 34 | this._type = type; 35 | this._updatePBar(); 36 | }, 37 | getReversed:function() 38 | { 39 | return this._reversed; 40 | }, 41 | setReversed:function(r) 42 | { 43 | if(this._reversed == r) return; 44 | this._reversed = r; 45 | this._updatePBar(); 46 | //to fix the setReverse bug 47 | this.percentage += 0.1; 48 | this.percentage -= 0.1; 49 | }, 50 | tween:function(from, to, duration) 51 | { 52 | if(this.pBar == null) return; 53 | if(this._tween) { 54 | this.pBar.stopAction(this._tween); 55 | this._tween.release(); 56 | } 57 | this._tween = cc.progressFromTo(duration, from, to); 58 | this._tween.retain(); 59 | this.pBar.runAction(this._tween); 60 | }, 61 | stopTween:function() 62 | { 63 | if(this._tween && this.pBar) { 64 | this.pBar.stopAction(this._tween); 65 | this._tween.release(); 66 | this._tween = null; 67 | } 68 | }, 69 | doRenderFrame:function(frame) 70 | { 71 | var sFrame = cc.spriteFrameCache.getSpriteFrame(this.frameNames[frame]); 72 | if(sFrame) { 73 | //todo, is there some performance issue? pool? 74 | var frameSprite = new cc.Sprite(sFrame); 75 | if(this.pBar == null){ 76 | this.width = frameSprite.width; 77 | this.height = frameSprite.height; 78 | 79 | this.pBar = cc.ProgressTimer.create(frameSprite); 80 | 81 | this._updatePBar(); 82 | 83 | this.pBar.setAnchorPoint(this.getAnchorPoint()); 84 | this.pBar.setPosition(this.getAnchorPointInPoints()); 85 | this.addChild(this.pBar); 86 | }else{ 87 | this.pBar.setSprite(frameSprite); 88 | } 89 | } 90 | }, 91 | _updatePBar:function() 92 | { 93 | if(this.pBar == null) return; 94 | if(this._type == flax.ProgressBarType.RADIAL) { 95 | //In version 3.0 alpha called cc.PROGRESS_TIMER_TYPE_RADIAL, 3.0 rc1 called cc.ProgressTimer.TYPE_RADIAL 96 | this.pBar.type = 0; 97 | this.pBar.setReverseDirection(this._reversed); 98 | this.pBar.midPoint = cc.p(0.5, 0.5); 99 | }else{ 100 | //In version 3.0 alpha called cc.PROGRESS_TIMER_TYPE_BAR, 3.0 rc1 called cc.ProgressTimer.TYPE_BAR 101 | this.pBar.type = 1; 102 | var isHorizontal = this._type == flax.ProgressBarType.HORIZONTAL; 103 | var mid = cc.p(0, 0); 104 | var cRate = cc.p(isHorizontal ? 1: 0, isHorizontal ? 0 : 1); 105 | if(this._reversed){ 106 | if(isHorizontal) mid.x = 1; 107 | else mid.y = 1; 108 | } 109 | this.pBar.midPoint = mid; 110 | this.pBar.barChangeRate = cRate; 111 | } 112 | } 113 | }); 114 | flax.ProgressBar.create = function(assetsFile, assetID) 115 | { 116 | var p = new flax.ProgressBar(assetsFile, assetID); 117 | p.clsName = "flax.ProgressBar"; 118 | return p; 119 | }; 120 | 121 | //Avoid to advanced compile mode 122 | window['flax']['ProgressBar'] = flax.ProgressBar; 123 | 124 | var _p = flax.ProgressBar.prototype; 125 | 126 | /** @expose */ 127 | _p.percentage; 128 | cc.defineGetterSetter(_p, "percentage", _p.getPercentage, _p.setPercentage); 129 | /** @expose */ 130 | _p.type; 131 | cc.defineGetterSetter(_p, "type", _p.getType, _p.setType); 132 | /** @expose */ 133 | _p.reversed; 134 | cc.defineGetterSetter(_p, "reversed", _p.getReversed, _p.setReversed); -------------------------------------------------------------------------------- /src/flax/game/Color.js: -------------------------------------------------------------------------------- 1 | var HEX_NUM = "0123456789ABCDEF"; 2 | var COLOR_WHITE = cc.color(255, 255, 255); 3 | var COLOR_BLACK = cc.color(0, 0, 0); 4 | var COLOR_RED = cc.color(255, 0, 0); 5 | var COLOR_GREEN = cc.color(0, 255, 0); 6 | var COLOR_BLUE = cc.color(0, 0, 255); 7 | var COLOR_GRAY = cc.color(128, 128, 128); 8 | 9 | function hexToRgb(hex) 10 | { 11 | var h = (hex.charAt(0)=="#") ? hex.substring(1,7) : hex; 12 | var r = parseInt(h.substring(0,2),16); 13 | var g = parseInt(h.substring(2,4),16); 14 | var b = parseInt(h.substring(4,6),16); 15 | return [r, g, b]; 16 | } 17 | 18 | function randomColor() 19 | { 20 | var rgb = hsvToRgb(Math.random(), 0.9725, 1.0); 21 | return rgbToHex(rgb[0], rgb[1], rgb[2]).toUpperCase(); 22 | } 23 | 24 | function rgbToHex(r, g, b) { 25 | return _toHex(r) + _toHex(g) + _toHex(b); 26 | } 27 | /** 28 | * Converts an RGB color value to HSL. Conversion formula 29 | * adapted from http://en.wikipedia.org/wiki/HSL_color_space. 30 | * Assumes r, g, and b are contained in the set [0, 255] and 31 | * returns h, s, and l in the set [0, 1]. 32 | * 33 | * @param Number r The red color value 34 | * @param Number g The green color value 35 | * @param Number b The blue color value 36 | * @return Array The HSL representation 37 | */ 38 | function rgbToHsl(r, g, b){ 39 | r /= 255, g /= 255, b /= 255; 40 | var max = Math.max(r, g, b), min = Math.min(r, g, b); 41 | var h, s, l = (max + min) / 2; 42 | 43 | if(max == min){ 44 | h = s = 0; // achromatic 45 | }else{ 46 | var d = max - min; 47 | s = l > 0.5 ? d / (2 - max - min) : d / (max + min); 48 | switch(max){ 49 | case r: h = (g - b) / d + (g < b ? 6 : 0); break; 50 | case g: h = (b - r) / d + 2; break; 51 | case b: h = (r - g) / d + 4; break; 52 | } 53 | h /= 6; 54 | } 55 | 56 | return [h, s, l]; 57 | } 58 | 59 | /** 60 | * Converts an HSL color value to RGB. Conversion formula 61 | * adapted from http://en.wikipedia.org/wiki/HSL_color_space. 62 | * Assumes h, s, and l are contained in the set [0, 1] and 63 | * returns r, g, and b in the set [0, 255]. 64 | * 65 | * @param Number h The hue 66 | * @param Number s The saturation 67 | * @param Number l The lightness 68 | * @return Array The RGB representation 69 | */ 70 | function hslToRgb(h, s, l){ 71 | var r, g, b; 72 | 73 | if(s == 0){ 74 | r = g = b = l; // achromatic 75 | }else{ 76 | function hue2rgb(p, q, t){ 77 | if(t < 0) t += 1; 78 | if(t > 1) t -= 1; 79 | if(t < 1/6) return p + (q - p) * 6 * t; 80 | if(t < 1/2) return q; 81 | if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; 82 | return p; 83 | } 84 | 85 | var q = l < 0.5 ? l * (1 + s) : l + s - l * s; 86 | var p = 2 * l - q; 87 | r = hue2rgb(p, q, h + 1/3); 88 | g = hue2rgb(p, q, h); 89 | b = hue2rgb(p, q, h - 1/3); 90 | } 91 | 92 | return [r * 255, g * 255, b * 255]; 93 | } 94 | 95 | /** 96 | * Converts an RGB color value to HSV. Conversion formula 97 | * adapted from http://en.wikipedia.org/wiki/HSV_color_space. 98 | * Assumes r, g, and b are contained in the set [0, 255] and 99 | * returns h, s, and v in the set [0, 1]. 100 | * 101 | * @param Number r The red color value 102 | * @param Number g The green color value 103 | * @param Number b The blue color value 104 | * @return Array The HSV representation 105 | */ 106 | function rgbToHsv(r, g, b){ 107 | r = r/255, g = g/255, b = b/255; 108 | var max = Math.max(r, g, b), min = Math.min(r, g, b); 109 | var h, s, v = max; 110 | 111 | var d = max - min; 112 | s = max == 0 ? 0 : d / max; 113 | 114 | if(max == min){ 115 | h = 0; // achromatic 116 | }else{ 117 | switch(max){ 118 | case r: h = (g - b) / d + (g < b ? 6 : 0); break; 119 | case g: h = (b - r) / d + 2; break; 120 | case b: h = (r - g) / d + 4; break; 121 | } 122 | h /= 6; 123 | } 124 | 125 | return [h, s, v]; 126 | } 127 | 128 | /** 129 | * Converts an HSV color value to RGB. Conversion formula 130 | * adapted from http://en.wikipedia.org/wiki/HSV_color_space. 131 | * Assumes h, s, and v are contained in the set [0, 1] and 132 | * returns r, g, and b in the set [0, 255]. 133 | * 134 | * @param Number h The hue 135 | * @param Number s The saturation 136 | * @param Number v The value 137 | * @return Array The RGB representation 138 | */ 139 | function hsvToRgb(h, s, v){ 140 | var r, g, b; 141 | 142 | var i = Math.floor(h * 6); 143 | var f = h * 6 - i; 144 | var p = v * (1 - s); 145 | var q = v * (1 - f * s); 146 | var t = v * (1 - (1 - f) * s); 147 | 148 | switch(i % 6){ 149 | case 0: r = v, g = t, b = p; break; 150 | case 1: r = q, g = v, b = p; break; 151 | case 2: r = p, g = v, b = t; break; 152 | case 3: r = p, g = q, b = v; break; 153 | case 4: r = t, g = p, b = v; break; 154 | case 5: r = v, g = p, b = q; break; 155 | } 156 | 157 | return [r * 255, g * 255, b * 255]; 158 | } 159 | /** 160 | * Darken the hex color by amount ,amout is from 0 to 1 161 | * */ 162 | function darkenHexColor(color, amount) { 163 | 164 | var rgb = hexToRgb(color); 165 | var hsl = rgbToHsl(rgb[0], rgb[1], rgb[2]); 166 | hsl[2] -= amount; 167 | rgb = hslToRgb(hsl[0], hsl[1], hsl[2]); 168 | return rgbToHex(rgb[0], rgb[1], rgb[2]); 169 | } 170 | 171 | function _toHex(num) { 172 | num = parseInt(num, 10); 173 | if (isNaN(num)) return "00"; 174 | num = Math.max(0, Math.min(num, 255)); 175 | return HEX_NUM.charAt((num - num%16) / 16) 176 | + HEX_NUM.charAt(num % 16); 177 | } -------------------------------------------------------------------------------- /src/flax/game/Gun.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-2-22. 3 | */ 4 | 5 | flax.GunParam = cc.Class.extend({ 6 | bulletAssets:null,//the assets file of the bullet 7 | bulletID:null,//the id of the bullet asset 8 | targetMap:null,//the TileMap name of the target to shoot 9 | selfMap:null,//the TileMap the bullet itself to be added to 10 | damage:1,//the damage of the bullet, if it's Array with two elements, set a random value between them 11 | damageRadius:0,//if damageRadius > 1, bullet will make splash damage to the enemies around it 12 | speed:600,//the move speed of the bullet per second 13 | interval:0.15,//the interval time between two launch 14 | count:1,//the bullet count in one launch 15 | angleGap:5,//if count > 1, angle gap between two bullets at one launch 16 | angleOffset:0,//the bullet move angle offset according to the gun itself 17 | waveInterval:0,//the seconds interval between two wave launch, if <= 0 then no wave mode 18 | countInWave:6,//launch times in one wave 19 | gravityX:0,//gravity on x 20 | gravityY:0,//gravity on y 21 | fireSound:null,//the sound when fire 22 | fireEffectID:null,//the id of fire effect, it must be packed with the bullet asset id together 23 | hitEffectID:null,//the id of hit effect, it must be packed with the bullet assets id together 24 | alwaysLive:false,//if true, when the bullet hurt target, it'll not disappear, continue to hurt next enemy on the path 25 | bulletPlayOnce:false,//if true, the bullet will play only once after fire, otherwise always play again and again 26 | fps:0,//if the bullet has animation, then set the fps, or use the default fps in the fla 27 | isMissle:false//todo, if it's missile 28 | }); 29 | 30 | flax.GunParam.create = function(param) 31 | { 32 | var gp = new flax.GunParam(); 33 | //fixed the speed == 0 bug 34 | if(param.speed == 0) param.speed = 0.001; 35 | flax.copyProperties(param, gp); 36 | return gp; 37 | }; 38 | 39 | flax.Gun = cc.Node.extend({ 40 | owner:null, 41 | param:null, 42 | aimTarget:null, 43 | _firing:false, 44 | _targetMap:null, 45 | _canvas:null, 46 | 47 | start:function() 48 | { 49 | if(this._firing) return; 50 | this._firing = true; 51 | 52 | this._canvas = flax.BulletCanvas.fetch(this.param.bulletAssets); 53 | 54 | if(this.param.waveInterval <= 0 || this.param.countInWave < 1) { 55 | this.schedule(this.shootOnce, this.param.interval); 56 | this.shootOnce(); 57 | }else{ 58 | this._waveFire(); 59 | } 60 | }, 61 | end:function() 62 | { 63 | if(!this._firing) return; 64 | this._firing = false; 65 | this.unschedule(this.shootOnce); 66 | this.unschedule(this._createWave); 67 | }, 68 | updateParam:function(param) 69 | { 70 | if(param == null) return; 71 | flax.copyProperties(param, this.param); 72 | this.end(); 73 | this.start(); 74 | }, 75 | isFiring:function() 76 | { 77 | return this._firing; 78 | }, 79 | _waveFire:function() 80 | { 81 | if(!this._firing) return; 82 | this._createWave(); 83 | var t = this.param.interval*this.param.countInWave + this.param.waveInterval; 84 | this.schedule(this._createWave, t, cc.REPEAT_FOREVER); 85 | }, 86 | shootOnce:function() 87 | { 88 | if(this.parent == null) return; 89 | 90 | var pos = this.parent.convertToWorldSpace(this.getPosition()); 91 | if(this.aimTarget && this.aimTarget.parent && this.aimTarget.visible){ 92 | var angle = flax.getAngle(flax.getPosition(this, true), this.aimTarget.center); 93 | this.owner.onAimingTarget(angle); 94 | this.rotation = angle - this.param.angleOffset - this.parent.rotation; 95 | } 96 | pos = this._canvas.convertToNodeSpace(pos); 97 | var rot = flax.getRotation(this, true); 98 | var i = -1; 99 | var r = 0; 100 | var d = 0; 101 | var ints = flax.createDInts(this.param.count); 102 | while(++i < this.param.count) 103 | { 104 | d = ints[i]; 105 | r = rot + d*this.param.angleGap; 106 | this._canvas.addBullet(r, pos, this.param, this.owner); 107 | } 108 | this._showFireEffect(pos, r); 109 | if(this.param.fireSound) flax.playSound(this.param.fireSound); 110 | }, 111 | _createWave:function() 112 | { 113 | if(this.param.countInWave > 1) this.schedule(this.shootOnce, this.param.interval, this.param.countInWave - 1); 114 | else this.shootOnce(); 115 | }, 116 | _showFireEffect:function(pos, rot) 117 | { 118 | if(this.param.fireEffectID == null || this.param.fireEffectID == "") return; 119 | var fireEffect = flax.assetsManager.createDisplay(this.param.bulletAssets, this.param.fireEffectID, {parent: this._canvas}, true); 120 | fireEffect.zIndex = 999; 121 | fireEffect.autoDestroyWhenOver = true; 122 | fireEffect.setPosition(pos); 123 | fireEffect.setRotation(rot); 124 | fireEffect.gotoAndPlay(0); 125 | } 126 | }); 127 | flax.BulletCanvas = cc.SpriteBatchNode.extend({ 128 | assetsFile:null, 129 | onBulletHit:null, 130 | onBulletOut:null, 131 | _bullets:null, 132 | onEnter:function(){ 133 | this._super(); 134 | this._bullets = []; 135 | this.onBulletHit = new signals.Signal(); 136 | this.onBulletOut = new signals.Signal(); 137 | this.scheduleUpdate(); 138 | }, 139 | onExit:function(){ 140 | this._super(); 141 | this.onBulletHit.removeAll(); 142 | this.onBulletOut.removeAll(); 143 | }, 144 | addBullet:function(rotation, position, param, owner){ 145 | if(this.parent == null) { 146 | cc.log("Please create a bullet canvas: flax.BulletCanvas.create('"+this.assetsFile+"', container, zIndex);"); 147 | return; 148 | } 149 | if(!(param instanceof flax.GunParam)) param = flax.GunParam.create(param); 150 | var b = flax.assetsManager.createDisplay(param.bulletAssets, param.bulletID, {parent: this}, true); 151 | b.owner = owner; 152 | b.param = param; 153 | if(owner && owner.targets) b.targets = owner.targets; 154 | if(param.targetMap) b.targetMap = flax.getTileMap(param.targetMap); 155 | if(param.fps) b.fps = param.fps; 156 | b.__physicalShooted = false; 157 | //if it's MovieClip 158 | if(b instanceof flax.MovieClip){ 159 | b.__isMovieClip = true; 160 | b.autoPlayChildren = true; 161 | b.autoDestroyWhenOver = true; 162 | var i = b.children.length; 163 | var cb; 164 | while(i--){ 165 | cb = b.children[i]; 166 | if(param.selfMap) { 167 | cb.setTileMap(param.selfMap); 168 | } 169 | cb.__isBullet = true; 170 | cb.__canvas = this; 171 | cb.__body = b; 172 | } 173 | }else if(param.selfMap) { 174 | b.setTileMap(param.selfMap); 175 | b.__isBullet = true; 176 | b.__canvas = this; 177 | b.__body = b; 178 | } 179 | b.play(); 180 | b.autoStopWhenOver = param.bulletPlayOnce; 181 | b.setPosition(position); 182 | b.setRotation(rotation); 183 | 184 | var dmg = param.damage; 185 | if(dmg instanceof Array){ 186 | if(dmg.length == 1) dmg = dmg[0]; 187 | else if(dmg.length >= 2) dmg = flax.randInt(dmg[0], dmg[1]); 188 | } 189 | b.damage = dmg; 190 | 191 | var r1 = DEGREE_TO_RADIAN*(90 - (rotation + param.angleOffset)); 192 | b.__vx = param.speed*Math.cos(r1); 193 | b.__vy = param.speed*Math.sin(r1); 194 | 195 | this._bullets.push(b); 196 | return b; 197 | }, 198 | destroyBullet:function(b, i, doDestroy){ 199 | if(i === undefined) i = this._bullets.indexOf(b); 200 | if(i < 0) return; 201 | if(doDestroy !== false) b.destroy(); 202 | this._bullets.splice(i, 1); 203 | }, 204 | update:function(delta) 205 | { 206 | var i = this._bullets.length; 207 | if(i == 0) return; 208 | var b = null; 209 | var targets = null; 210 | var j = -1; 211 | var rect = null; 212 | var hitted = false; 213 | var pos = null; 214 | var rot = null; 215 | //Note: how to delete item of an Array in a loop, this is a template! 216 | while(i--) { 217 | b = this._bullets[i]; 218 | //if the bullet controlled by physics, then don't move it here 219 | if(b.physicsBody){ 220 | if(!b.__physicalShooted){ 221 | b.physicsBody.SetLinearVelocity({x:b.__vx/PTM_RATIO, y:b.__vy/PTM_RATIO}); 222 | b.__physicalShooted = true; 223 | } 224 | // continue; 225 | }else{ 226 | b.__vx = b.__vx + b.param.gravityX*delta; 227 | b.__vy = b.__vy + b.param.gravityY*delta; 228 | b.x += b.__vx*delta; 229 | b.y += b.__vy*delta; 230 | b.rotation = flax.getAngle1(b.__vx, b.__vy, true) - b.param.angleOffset; 231 | } 232 | rect = flax.getRect(b, true); 233 | hitted = false; 234 | targets = null; 235 | var outOfBounds = !cc.rectIntersectsRect(flax.stageRect, rect); 236 | if(!outOfBounds){ 237 | targets = this._checkHittedTarget(b, rect, false); 238 | if(targets && targets.length){ 239 | pos = flax.getPosition(b, true); 240 | var radius = b.param.damageRadius; 241 | if(radius > 0){ 242 | rect = cc.rect(pos.x - radius/2, pos.y - radius/2, radius, radius); 243 | targets = this._checkHittedTarget(b, rect, true); 244 | } 245 | hitted = true; 246 | } 247 | } 248 | if(outOfBounds) { 249 | this.onBulletOut.dispatch(b); 250 | this.destroyBullet(b, i); 251 | }else if(hitted){ 252 | this.onBulletHit.dispatch(b); 253 | if(!b.param.alwaysLive) this.destroyBullet(b, i); 254 | } 255 | } 256 | }, 257 | _checkHittedTarget:function(b, rect, multiple){ 258 | var hittedTargets = []; 259 | var targets = null; 260 | if(b.targets) targets = b.targets; 261 | else if(b.targetMap) targets = b.targetMap.getCoveredTiles1(rect, true); 262 | if(!targets || !targets.length) return hittedTargets; 263 | 264 | var rot = flax.getRotation(b, true); 265 | var i = -1; 266 | while(++i < targets.length) { 267 | target = targets[i]; 268 | if(!target || !target.parent || !target.visible) continue; 269 | if(b.owner && (target == b.owner || flax.isChildOf(b.owner, target) || target.dead === true || (b.owner.camp != null && target.camp == b.owner.camp))) continue; 270 | //hit the target 271 | if(b.__isMovieClip){ 272 | var children = b.children; 273 | var num = children.length; 274 | while(num--){ 275 | var cb = children[num]; 276 | rot = flax.getRotation(cb, true); 277 | if(cb.mainCollider.checkCollision(target.mainCollider)) { 278 | // if(target.onHit) target.dead = target.onHit(b); 279 | flax.callModuleFunction(target, "onHit", b); 280 | if(target.hurtable !== false) this._showHitEffect(b, rot, b.convertToWorldSpace(cb.getPosition())); 281 | if(target.__isBullet) { 282 | var ii = target.__canvas._bullets.indexOf(target); 283 | if(ii > -1) target.__canvas._bullets.splice(ii, 1); 284 | target.__body.destroy(); 285 | } 286 | if(!multiple) return [target]; 287 | hittedTargets.push(target); 288 | } 289 | } 290 | }else{ 291 | if(b.mainCollider.checkCollision(target.mainCollider)) { 292 | // if(target.onHit) target.dead = target.onHit(b); 293 | flax.callModuleFunction(target, "onHit", b); 294 | if(target.hurtable !== false) this._showHitEffect(b, rot, b.getPosition()); 295 | if(target.__isBullet) { 296 | var ii = target.__canvas._bullets.indexOf(target); 297 | if(ii > -1) target.__canvas._bullets.splice(ii, 1); 298 | target.__body.destroy(); 299 | } 300 | if(!multiple) return [target]; 301 | hittedTargets.push(target); 302 | } 303 | } 304 | } 305 | return hittedTargets; 306 | }, 307 | _showHitEffect:function(bullet, rot, pos) 308 | { 309 | if(bullet.param.hitEffectID == null || bullet.param.hitEffectID == "") return; 310 | var hitEffect = flax.assetsManager.createDisplay(bullet.param.bulletAssets, bullet.param.hitEffectID, {parent: this}, true); 311 | hitEffect.zIndex = 999; 312 | hitEffect.autoDestroyWhenOver = true; 313 | hitEffect.setPosition(pos || bullet.getPosition()); 314 | hitEffect.setRotation(rot); 315 | hitEffect.gotoAndPlay(0); 316 | } 317 | }); 318 | flax.BulletCanvas.create = function(assetsFile, container, zIndex) { 319 | var canvas = flax.BulletCanvas.fetch(assetsFile); 320 | if(canvas.parent != container){ 321 | canvas.removeFromParent(); 322 | container.addChild(canvas, zIndex || 999); 323 | } 324 | }; 325 | flax.BulletCanvas.fetch = function (assetsFile) { 326 | if(flax._bulletCanvases[assetsFile]) return flax._bulletCanvases[assetsFile]; 327 | var texturePath = cc.path.changeBasename(assetsFile, ".png"); 328 | var c = new flax.BulletCanvas(texturePath, 100); 329 | c.assetsFile = assetsFile; 330 | flax._bulletCanvases[assetsFile] = c; 331 | return c; 332 | }; 333 | flax._bulletCanvases = {}; 334 | flax.BulletCanvas.release = function(){ 335 | flax._bulletCanvases = {}; 336 | }; 337 | 338 | flax.Gun.create = function(param) 339 | { 340 | if(param == null) { 341 | cc.log("Please give me a param defiled like: flax.GunParam!"); 342 | return null; 343 | } 344 | param = flax.GunParam.create(param); 345 | var gun = new flax.Gun(); 346 | gun.param = param; 347 | gun.init(); 348 | return gun; 349 | }; -------------------------------------------------------------------------------- /src/flax/game/Gunner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-4-24. 3 | */ 4 | 5 | flax._gunnerDefine = { 6 | camp:null,//Player or Enemy? 7 | _gunParam:null,//see flax.GunParam, remember the anchors, ["weapon1","weapon2"] 8 | targets:null,//the targets array of the enemy 9 | alwaysBind:true,//if the gun always bind to the anchor every frame 10 | _guns:null, 11 | _autoShooting:false, 12 | _waitingShoot:false, 13 | _auto:false,//if true, will auto shoot according to the gunParam 14 | 15 | onEnter:function() 16 | { 17 | this._super(); 18 | this._guns = []; 19 | if(this._gunParam) this.setGunParam(this._gunParam); 20 | }, 21 | onRecycle:function() 22 | { 23 | this._super(); 24 | this.camp = null; 25 | this._gunParam = null; 26 | this.targets = null; 27 | this._guns = null; 28 | this._autoShooting = this._waitingShoot = this._auto = false; 29 | this.stopShoot(); 30 | }, 31 | getGunParam:function(){ 32 | return this._gunParam; 33 | }, 34 | setGunParam:function(param, gunAnchors) 35 | { 36 | this._gunParam = param; 37 | if(this.parent == null) return; 38 | if(!gunAnchors) gunAnchors = param.gunAnchors; 39 | if(gunAnchors == null){ 40 | cc.log("Please set the gunAnchors param!"); 41 | return; 42 | } 43 | var i = -1; 44 | var n = gunAnchors.length; 45 | var gunAnchor = null; 46 | var gun = null; 47 | while(++i < n) 48 | { 49 | gunAnchor = gunAnchors[i]; 50 | gun = flax.Gun.create(this._gunParam); 51 | if(this.bindAnchor(gunAnchor, gun, this.alwaysBind)) { 52 | gun.owner = this; 53 | gun.name = gunAnchor; 54 | this[gunAnchor] = gun; 55 | this._guns.push(gun); 56 | } 57 | } 58 | if(this._waitingShoot){ 59 | this.scheduleOnce(this.autoShoot, 0.1); 60 | } 61 | }, 62 | shoot:function(){ 63 | this._auto = false; 64 | this._doBeginShoot(); 65 | }, 66 | autoShoot:function(delay) 67 | { 68 | this._auto = true; 69 | if(this.parent == null || this._guns == null || this._guns.length == 0) { 70 | this._waitingShoot = true; 71 | return; 72 | } 73 | if(delay > 0){ 74 | this.scheduleOnce(this._doBeginShoot, delay); 75 | }else{ 76 | this._doBeginShoot(); 77 | } 78 | this._autoShooting = true; 79 | this._waitingShoot = false; 80 | }, 81 | /** 82 | * Set a target to aim to 83 | * */ 84 | aimToTarget:function(target){ 85 | if(!target || !target.parent || !target.visible) return; 86 | if(this.targets == null) this.targets = [target]; 87 | else if(this.targets.indexOf(target) == -1) this.targets.push(target); 88 | var i = -1; 89 | var n = this._guns.length; 90 | var gun = null; 91 | while(++i < n) 92 | { 93 | gun = this._guns[i]; 94 | gun.aimTarget = target; 95 | } 96 | }, 97 | onAimingTarget:function(angle){ 98 | //to be override 99 | }, 100 | _doBeginShoot:function() 101 | { 102 | var i = -1; 103 | var n = this._guns.length; 104 | while(++i < n) 105 | { 106 | if(this._auto) this._guns[i].start(); 107 | else this._guns[i].shootOnce(); 108 | } 109 | }, 110 | stopShoot:function() 111 | { 112 | this._autoShooting = false; 113 | if(this._guns == null || this._guns.length == 0) return; 114 | var i = -1; 115 | var n = this._guns.length; 116 | while(++i < n) 117 | { 118 | this._guns[i].end(); 119 | } 120 | }, 121 | upgradeGun:function(deltaParam, time) 122 | { 123 | var delta = this._deltaGunParam(deltaParam); 124 | if(!isNaN(time) && time > 0){ 125 | this.scheduleOnce(function(){ 126 | this._deltaGunParam(delta); 127 | }, time); 128 | }else{ 129 | this._deltaGunParam(delta); 130 | } 131 | }, 132 | _deltaGunParam:function(param) 133 | { 134 | if(this._guns.length == 0) return; 135 | var delta = {}; 136 | var newValue = 0; 137 | for(var k in param){ 138 | newValue = this._guns[0].param[k] + param[k]; 139 | if(newValue <= 0) { 140 | delete param[k]; 141 | continue; 142 | } 143 | delta[k] = -param[k]; 144 | param[k] = newValue; 145 | } 146 | var i = this._guns.length; 147 | var gun = null; 148 | while(i--) 149 | { 150 | gun = this._guns[i]; 151 | gun.updateParam(param); 152 | } 153 | return delta; 154 | }, 155 | onDie:function() 156 | { 157 | this.stopShoot(); 158 | flax.callModuleFunction(this, "onDie"); 159 | if(this.ownerBody) this.ownerBody.destroy(); 160 | else this.destroy(); 161 | } 162 | }; 163 | 164 | flax.Gunner = flax.Animator.extend(flax._gunnerDefine); 165 | //Avoid to advanced compile mode 166 | window['flax']['Gunner'] = flax.Gunner; 167 | 168 | flax.MCGunner = flax.MovieClip.extend(flax._gunnerDefine); 169 | //Avoid to advanced compile mode 170 | window['flax']['MCGunner'] = flax.MCGunner; 171 | 172 | flax.addModule(flax.Gunner, flax.HealthModule, false); 173 | flax.addModule(flax.MCGunner, flax.HealthModule, false); 174 | 175 | var _p = flax.Gunner.prototype; 176 | /** @expose */ 177 | _p.onHit; 178 | /** @expose */ 179 | _p.onDie; 180 | /** @expose */ 181 | _p.gunParam; 182 | cc.defineGetterSetter(_p, "gunParam", _p.getGunParam, _p.setGunParam); 183 | 184 | _p = flax.MCGunner.prototype; 185 | /** @expose */ 186 | _p.onHit; 187 | /** @expose */ 188 | _p.onDie; 189 | /** @expose */ 190 | _p.gunParam; 191 | cc.defineGetterSetter(_p, "gunParam", _p.getGunParam, _p.setGunParam); 192 | 193 | flax.Gunner.create = function(assetsFile, assetID) 194 | { 195 | var h = new flax.Gunner(assetsFile, assetID); 196 | h.clsName = "flax.Gunner"; 197 | return h; 198 | }; 199 | 200 | flax.MCGunner.create = function(assetsFile, assetID) 201 | { 202 | var h = new flax.MCGunner(assetsFile, assetID); 203 | h.clsName = "flax.MCGunner"; 204 | return h; 205 | }; 206 | 207 | 208 | 209 | -------------------------------------------------------------------------------- /src/flax/game/LinkFinder.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-2-15. 3 | */ 4 | EIGHT_DIRECT_VALUE = [[0,1],[0,-1],[-1,0],[1,0],[-1,1],[1,1],[1,-1],[-1,-1]]; 5 | var LinkFinder = {}; 6 | window['LinkFinder'] = LinkFinder; 7 | //the flax.TileMap to manage all the objects to link together 8 | LinkFinder.map = null; 9 | //an objects array, the linkage with these objects are unavailable 10 | LinkFinder.blocks = null; 11 | /** 12 | * Check if tx0,ty0 and tx1,ty1 are linked 13 | * */ 14 | LinkFinder.findLink = function(tx0, ty0, tx1, ty1) 15 | { 16 | var link = null; 17 | if(tx0 == tx1 || ty0 == ty1) { 18 | link = LinkFinder._checkDirectLink(tx0, ty0, tx1, ty1); 19 | }else{ 20 | link = LinkFinder._checkOneLink(tx0, ty0, tx1, ty1); 21 | } 22 | if(link == null) 23 | { 24 | link = LinkFinder._checkTwoLink(tx0, ty0, tx1, ty1); 25 | } 26 | return link; 27 | }; 28 | LinkFinder.shuffle = function(useTween){ 29 | var all = this.map.getAllObjects(); 30 | var tiles = all.concat(); 31 | var i = -1; 32 | if(this.blocks && this.blocks.length){ 33 | tiles = []; 34 | while(++i < all.length){ 35 | var a = all[i]; 36 | if(this.blocks.indexOf(a) == -1){ 37 | tiles.push(a); 38 | } 39 | } 40 | } 41 | flax.shuffleArray(tiles); 42 | i = -1; 43 | var halfCount = tiles.length/2; 44 | while(++i < halfCount){ 45 | var a0 = tiles[i]; 46 | var a1 = tiles[i + halfCount]; 47 | // var tempPos = cc.p(a0.getPosition()); 48 | var tempPos = a0.getPosition(); 49 | if(useTween !== false){ 50 | a0.runAction(cc.MoveTo.create(0.2, a1.getPosition())); 51 | a1.runAction(cc.MoveTo.create(0.2, tempPos)); 52 | }else{ 53 | a0.setPosition(a1.getPosition()); 54 | a1.setPosition(tempPos); 55 | } 56 | } 57 | }; 58 | /** 59 | * Check if the map is dead, dead means there is no link anymore, then tried to fix it 60 | * Return a available linked pair, null result means there is no link anymore and can't be fixed 61 | * */ 62 | LinkFinder.findAvailableLink = function(useTween) 63 | { 64 | var tiles = this.map.getAllObjects(); 65 | var count = tiles.length; 66 | if(count == 0) return null; 67 | var f0; 68 | var f1; 69 | var link = null; 70 | var sameTypes = []; 71 | var first = null; 72 | for(var i = 0; i< count -1; i++) 73 | { 74 | f0 = tiles[i]; 75 | if(this.blocks && this.blocks.indexOf(f0) > -1) continue; 76 | var checkSameType = (sameTypes.length == 0); 77 | if(first == null) first = f0; 78 | for(var j = i + 1; j < count; j++) 79 | { 80 | f1 = tiles[j]; 81 | if(this.blocks && this.blocks.indexOf(f1) > -1) continue; 82 | if(f1.assetID == f0.assetID) { 83 | if(LinkFinder.findLink(f0.tx, f0.ty, f1.tx, f1.ty)){ 84 | return [f0, f1]; 85 | } 86 | if(checkSameType) sameTypes.push(f1); 87 | }else if(checkSameType && link == null && LinkFinder.findLink(f0.tx, f0.ty, f1.tx, f1.ty)){ 88 | link = f1; 89 | } 90 | } 91 | } 92 | if(sameTypes.length == 0) return null; 93 | var theLink = sameTypes[Math.floor(sameTypes.length*Math.random())]; 94 | var tempPos = cc.p(theLink.getPosition()); 95 | if(link == null) { 96 | var empty = this._findEmptyNeighbor(first.tx, first.ty); 97 | if(empty == null) throw "Dead map!!!!"; 98 | tempPos = this.map.getTiledPosition(empty.x, empty.y); 99 | if(theLink.parent) tempPos = theLink.parent.convertToNodeSpace(tempPos); 100 | if(useTween === true){ 101 | theLink.runAction(cc.MoveTo.create(0.2, tempPos)); 102 | }else{ 103 | theLink.setPosition(tempPos); 104 | } 105 | }else{ 106 | if(useTween === true){ 107 | theLink.runAction(cc.MoveTo.create(0.2, link.getPosition())); 108 | link.runAction(cc.MoveTo.create(0.2, tempPos)); 109 | }else{ 110 | theLink.setPosition(link.getPosition()); 111 | link.setPosition(tempPos); 112 | } 113 | } 114 | return [first, theLink]; 115 | }; 116 | LinkFinder._findEmptyNeighbor = function(tx, ty){ 117 | var result = null; 118 | for(var i = 0; i < 4; i++){ 119 | var ds = EIGHT_DIRECT_VALUE[i]; 120 | result = cc.p(tx + ds[0], ty + ds[1]); 121 | if(this.map.isEmptyTile(result.x, result.y)) return result; 122 | } 123 | return result; 124 | }; 125 | LinkFinder._checkDirectLink = function(tx0, ty0, tx1, ty1) 126 | { 127 | if(tx0 == tx1 && ty0 == ty1) return null; 128 | if(tx0 == tx1) 129 | { 130 | var linked = true; 131 | var d = (ty1 - ty0 > 0) ? 1 : -1; 132 | var ty = ty0 + d; 133 | while(ty != ty1) 134 | { 135 | if(!this.map.isEmptyTile(tx0, ty)){ 136 | linked = false; 137 | break; 138 | } 139 | ty += d; 140 | } 141 | if(linked) return [new cc.p(tx0, ty0), new cc.p(tx1, ty1)]; 142 | } 143 | if(ty0 == ty1) 144 | { 145 | var linked = true; 146 | var d = (tx1 - tx0 > 0) ? 1 : -1; 147 | var tx = tx0 + d; 148 | while(tx != tx1) 149 | { 150 | if(!this.map.isEmptyTile(tx, ty0)){ 151 | linked = false; 152 | break; 153 | } 154 | tx += d; 155 | } 156 | if(linked) return [new cc.p(tx0, ty0), new cc.p(tx1, ty1)]; 157 | } 158 | return null; 159 | }; 160 | LinkFinder._checkOneLink = function(tx0, ty0, tx1, ty1) 161 | { 162 | if(tx0 == tx1 || ty0 == ty1) return null; 163 | //corner1: tx0, ty1 164 | if(this.map.isEmptyTile(tx0, ty1)){ 165 | var linked0 = LinkFinder._checkDirectLink(tx0, ty0, tx0, ty1); 166 | if(linked0) { 167 | var linked1 = LinkFinder._checkDirectLink(tx0, ty1, tx1, ty1); 168 | if(linked1) return [new cc.p(tx0, ty0), new cc.p(tx0, ty1), new cc.p(tx1, ty1)]; 169 | } 170 | } 171 | //corner2: tx1, ty0 172 | if(this.map.isEmptyTile(tx1, ty0)) 173 | { 174 | var linked0 = LinkFinder._checkDirectLink(tx0, ty0, tx1, ty0); 175 | if(linked0) { 176 | var linked1 = LinkFinder._checkDirectLink(tx1, ty0, tx1, ty1); 177 | if(linked1) { 178 | return [new cc.p(tx0, ty0), new cc.p(tx1, ty0), new cc.p(tx1, ty1)]; 179 | } 180 | } 181 | } 182 | return null; 183 | }; 184 | LinkFinder._checkTwoLink = function(tx0, ty0, tx1, ty1) 185 | { 186 | if(tx0 == tx1 && ty0 == ty1) return null; 187 | var dx = (tx1 - tx0) >= 0 ? 1 : -1; 188 | var dy = (ty1 - ty0) >= 0 ? 1 : -1; 189 | var link = LinkFinder._twoLinkSearch(tx0, ty0, tx1, ty1, dx, dy); 190 | if(link == null) link = LinkFinder._twoLinkSearch(tx0, ty0, tx1, ty1, -dx, -dy); 191 | if(link != null) link.unshift(new cc.p(tx0, ty0)); 192 | return link; 193 | }; 194 | LinkFinder._twoLinkSearch = function(tx0, ty0, tx1, ty1, dx, dy) 195 | { 196 | var link = null; 197 | var tx = tx0 + dx; 198 | var ty = ty0 + dy; 199 | var xOver = false; 200 | var yOver = false; 201 | while(!xOver || !yOver) 202 | { 203 | if(!xOver) 204 | { 205 | xOver = !this.map.isEmptyTile(tx, ty0); 206 | if(!xOver){ 207 | link = LinkFinder._checkOneLink(tx, ty0, tx1, ty1); 208 | if(link != null) break; 209 | tx += dx; 210 | } 211 | } 212 | if(!yOver) 213 | { 214 | yOver = !this.map.isEmptyTile(tx0, ty); 215 | if(!yOver){ 216 | link = LinkFinder._checkOneLink(tx0, ty, tx1, ty1); 217 | if(link != null) break; 218 | ty += dy; 219 | } 220 | } 221 | } 222 | return link; 223 | }; -------------------------------------------------------------------------------- /src/flax/game/ObjectPool.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-2-22. 3 | */ 4 | 5 | flax.ObjectPool = cc.Class.extend({ 6 | maxCount:100, 7 | _clsName:null, 8 | _cls:null, 9 | _assetsFile:null, 10 | _pool:null, 11 | _extraID:"", 12 | 13 | init:function(assetsFile, clsName, maxCount) 14 | { 15 | if(this._assetsFile && this._cls){ 16 | cc.log("The pool has been inited with cls: "+this._cls); 17 | return false; 18 | } 19 | this._clsName = clsName; 20 | this._cls = flax.nameToObject(clsName); 21 | if(this._cls == null){ 22 | cc.log("There is no class named: "+clsName); 23 | return false; 24 | } 25 | this._assetsFile = assetsFile; 26 | this._pool = []; 27 | if(maxCount !== undefined) this.maxCount = maxCount; 28 | return true; 29 | }, 30 | fetch:function(assetID, parent, params) 31 | { 32 | if(assetID == null){ 33 | cc.log("Please give me a assetID to fetch a object!"); 34 | return null; 35 | } 36 | var obj = null; 37 | if(this._pool.length > 0){ 38 | obj = this._pool.shift(); 39 | obj.__fromPool = true; 40 | obj.setSource(this._assetsFile, assetID); 41 | }else{ 42 | if(this._cls.create) obj = this._cls.create(this._assetsFile, assetID); 43 | else obj = new this._cls(this._assetsFile, assetID); 44 | } 45 | 46 | obj.__pool__id__ = this._extraID; 47 | obj.clsName = this._clsName; 48 | obj._destroyed = false; 49 | obj.autoRecycle = true; 50 | obj.visible = true; 51 | 52 | //to fix the zIndex bug 53 | if(params){ 54 | if(typeof params.zIndex === "undefined") params.zIndex = 0; 55 | }else{ 56 | params = {zIndex:0}; 57 | } 58 | obj.attr(params); 59 | if(parent) parent.addChild(obj); 60 | // cc.log("fetch: "+obj.assetID); 61 | return obj; 62 | }, 63 | recycle:function(object) 64 | { 65 | if(!(object instanceof this._cls)){ 66 | cc.log("The object to recycle is not the same type with this pool: "+this._clsName); 67 | return; 68 | } 69 | if(this._pool.length < this.maxCount){ 70 | // cc.log("recycle: "+object.assetID); 71 | object.onRecycle&&object.onRecycle(); 72 | object.retain&&object.retain(); 73 | this._pool.push(object); 74 | } 75 | }, 76 | release:function() 77 | { 78 | var i = this._pool.length; 79 | while(i--){ 80 | this._pool[i].release&&this._pool[i].release(); 81 | } 82 | this._pool.length = 0; 83 | } 84 | }); 85 | 86 | flax.ObjectPool.all = {}; 87 | 88 | flax.ObjectPool.create = function(assetsFile, clsName, maxCount) 89 | { 90 | var pool = new flax.ObjectPool(); 91 | if(pool.init(assetsFile, clsName, maxCount)) { 92 | return pool; 93 | } 94 | return null; 95 | }; 96 | flax.ObjectPool.get = function(assetsFile, clsName, id) 97 | { 98 | if(clsName == null) clsName = "flax.Animator"; 99 | if(id == null) id = ""; 100 | var key = assetsFile+clsName+id; 101 | var pool = flax.ObjectPool.all[key]; 102 | if(pool == null){ 103 | pool = flax.ObjectPool.create(assetsFile, clsName); 104 | pool._extraID = id; 105 | flax.ObjectPool.all[key] = pool; 106 | } 107 | return pool; 108 | }; 109 | 110 | flax.ObjectPool.release = function() 111 | { 112 | for(var k in flax.ObjectPool.all){ 113 | flax.ObjectPool.all[k].release(); 114 | delete flax.ObjectPool.all[k]; 115 | } 116 | }; 117 | 118 | -------------------------------------------------------------------------------- /src/flax/game/Preloader.js: -------------------------------------------------------------------------------- 1 | 2 | flax._preloader = { 3 | resources:null, 4 | _label : null, 5 | _logo:null, 6 | _inited:false, 7 | /** 8 | * init with resources 9 | * @param {Array} resources 10 | * @param {Function|String} cb 11 | */ 12 | initWithResources: function (resources, cb) { 13 | this.init(); 14 | if(typeof resources == "string") 15 | resources = [resources]; 16 | this.resources = resources || []; 17 | this.cb = cb; 18 | }, 19 | init : function(){ 20 | if(this._inited) return; 21 | this._inited = true; 22 | 23 | var self = this; 24 | var winSize = cc.director.getWinSize(); 25 | 26 | if(this instanceof cc.Layer){ 27 | var back = new cc.LayerColor(cc.color(0, 0, 0, 100)); 28 | this.addChild(back, 0); 29 | } 30 | //logo 31 | var centerPos = cc.p(winSize.width / 2, winSize.height / 2); 32 | 33 | //logo 34 | var loadingImg = cc.game.config["loading"]; 35 | if(loadingImg && flax.isImageFile(loadingImg)){ 36 | cc.loader.load(loadingImg, function(){ 37 | self._logo = new cc.Sprite(loadingImg); 38 | self._logo.setPosition(centerPos); 39 | self.addChild(self._logo, 10); 40 | if(!cc.sys.isNative){ 41 | var fontSize = 16*(1 + self._logo.width/200); 42 | self.createLabel(cc.pSub(centerPos, cc.p(0, self._logo.height/2 + fontSize*0.6)), fontSize); 43 | self.logoClick(); 44 | } 45 | }) 46 | }else{ 47 | self.createLabel(centerPos); 48 | } 49 | }, 50 | createLabel:function(pos, fontSize){ 51 | var label = this._label = new cc.LabelTTF("Loading...", "Arial", fontSize || 18); 52 | label.enableStroke(cc.color(51, 51, 51), 2); 53 | label.setColor(cc.color(255, 255, 255)); 54 | label.setPosition(pos); 55 | this.addChild(label, 10); 56 | }, 57 | logoClick:function(){ 58 | //click logo to go 59 | var logo = this._logo; 60 | var listener = cc.EventListener.create({ 61 | event: cc.EventListener.TOUCH_ONE_BY_ONE, 62 | swallowTouches: false, 63 | onTouchBegan:function(touch, event) 64 | { 65 | if(cc.rectContainsPoint(flax.getRect(logo, true), touch.getLocation())){ 66 | flax.goHomeUrl(); 67 | return true; 68 | } 69 | return false; 70 | } 71 | }); 72 | cc.eventManager.addListener(listener, this._logo); 73 | }, 74 | onEnter: function () { 75 | var self = this; 76 | cc.Node.prototype.onEnter.call(self); 77 | if(this.resources) self.schedule(self._startLoading, 0.3); 78 | }, 79 | _startLoading: function () { 80 | var self = this; 81 | self.unschedule(self._startLoading); 82 | var res = self.resources; 83 | cc.loader.load(res, 84 | function (result, count, loadedCount) { 85 | if(self._label == null) return; 86 | self._showProgress("Loading: ", count, loadedCount); 87 | }, function () { 88 | if (self.cb) 89 | self.cb(); 90 | }); 91 | }, 92 | _showProgress:function(text, count, loadedCount) 93 | { 94 | if(!this._label) return; 95 | if(loadedCount != null) this._label.setString(text + (loadedCount + 1) + "/" + count); 96 | else { 97 | // var percent = (loadedCount / count * 100) | 0; 98 | // percent = Math.min(percent, 100); 99 | this._label.setString(text + count + "%"); 100 | } 101 | } 102 | }; 103 | 104 | flax.Preloader = cc.Scene.extend(flax._preloader); 105 | flax.ResPreloader = cc.Layer.extend(flax._preloader); 106 | //Avoid to advanced compile mode 107 | window['flax']['Preloader'] = flax.Preloader; 108 | window['flax']['ResPreloader'] = flax.ResPreloader; 109 | -------------------------------------------------------------------------------- /src/flax/game/ScrollPane.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-6-6. 3 | */ 4 | 5 | flax._scrollPaneDefine = { 6 | _viewRect:null, 7 | onEnter:function(){ 8 | this._super(); 9 | //todo, maybe true 10 | this._viewRect = this.getCollider("view").getRect(true); 11 | if(!this._viewRect) { 12 | cc.log("If you want me scrollable, please set collider__view for me!"); 13 | return; 14 | } 15 | flax.inputManager.addListener(null, this._startDrag, InputType.press, this); 16 | //todo, mask the content 17 | // var stencil = cc.DrawNode.create(); 18 | // var rectangle = [cc.p(0, 0),cc.p(this._viewRect.width, 0),cc.p(this._viewRect.width, this._viewRect.height),cc.p(0, this._viewRect.height)]; 19 | // var color = cc.color(255, 255, 255, 100); 20 | // stencil.drawPoly(rectangle, color, 1, color); 21 | //// this.parent.addChild(stencil, 10000); 22 | // stencil.setPosition(this._viewRect.x, this._viewRect.y); 23 | // var mask = cc.ClippingNode.create(stencil); 24 | // mask.addChild(this); 25 | }, 26 | /** 27 | * Scroll the pane to make the target in the screen center 28 | * @param {sprite || point} target the sprite or the position in this pane 29 | * @param {number} time the duration to scroll to 30 | * */ 31 | scrollToCenter:function(target, time){ 32 | var pos0 = cc.visibleRect.center; 33 | pos0 = this.parent.convertToNodeSpace(pos0); 34 | var pos = this.convertToWorldSpace( target.getPosition ? target.getPosition() : target); 35 | pos = this.parent.convertToNodeSpace(pos); 36 | var delta = cc.pSub(pos0, pos); 37 | var x = this.x + delta.x; 38 | var y = this.y + delta.y; 39 | var newPos = this._validatePos(x, y); 40 | if(time > 0){ 41 | this.runAction(cc.MoveTo.create(time, newPos)); 42 | }else{ 43 | this.setPosition(newPos); 44 | } 45 | }, 46 | _startDrag:function(touch, event){ 47 | this.scheduleOnce(function(){ 48 | flax.inputManager.addListener(null, this._drag, InputType.move,this); 49 | flax.inputManager.addListener(null, this._stopDrag, InputType.up, this); 50 | },0.01); 51 | }, 52 | _drag:function(touch, event){ 53 | var delta = touch.getDelta(); 54 | //if the viewRect is larger than the content itself, then do nothing 55 | if(this._viewRect.width >= this.width) delta.x = 0; 56 | if(this._viewRect.height >= this.height) delta.y = 0; 57 | 58 | var x = this.x + delta.x; 59 | var y = this.y + delta.y; 60 | var newPos = this._validatePos(x, y); 61 | this.x = newPos.x; 62 | this.y = newPos.y; 63 | }, 64 | _stopDrag:function(touch, event){ 65 | flax.inputManager.removeListener(null, this._drag, InputType.move); 66 | flax.inputManager.removeListener(null, this._stopDrag, InputType.up); 67 | }, 68 | _validatePos:function(x, y){ 69 | x = Math.max(this._viewRect.x + this._viewRect.width - this.width, x); 70 | x = Math.min(this._viewRect.x, x); 71 | 72 | y = Math.max(this._viewRect.y + this._viewRect.height - this.height, y); 73 | y = Math.min(this._viewRect.y, y); 74 | 75 | return cc.p(x, y); 76 | } 77 | }; 78 | 79 | flax.ScrollPane = flax.Animator.extend(flax._scrollPaneDefine); 80 | flax.ScrollPane.create = function(assetsFile, assetID){ 81 | var s = new flax.ScrollPane(assetsFile, assetID); 82 | return s; 83 | }; 84 | 85 | //Avoid to advanced compile mode 86 | window['flax']['ScrollPane'] = flax.ScrollPane; 87 | 88 | flax.MCScrollPane = flax.MovieClip.extend(flax._scrollPaneDefine); 89 | flax.MCScrollPane.create = function(assetsFile, assetID){ 90 | var s = new flax.MCScrollPane(assetsFile, assetID); 91 | return s; 92 | }; 93 | 94 | //Avoid to advanced compile mode 95 | window['flax']['MCScrollPane'] = flax.MCScrollPane; 96 | -------------------------------------------------------------------------------- /src/flax/game/ScrollingBG.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-2-27. 3 | */ 4 | 5 | flax.ScrollingBG = cc.Node.extend({ 6 | name:null, 7 | onScrolledOver:null, 8 | _loop:true, 9 | _bg0:null, 10 | _bg1:null, 11 | _sources:null, 12 | _scrollingIndex:0, 13 | _scrolling:false, 14 | _paused:false, 15 | _speedX:0, 16 | _speedY:0, 17 | _d:1, 18 | _size:null, 19 | _x0:0, 20 | _y0:0, 21 | ctor:function(source, assetID, isTiled) 22 | { 23 | this._super(); 24 | this._sources = []; 25 | this.onScrolledOver = new signals.Signal(); 26 | if(source){ 27 | this.addSource(source, assetID, isTiled); 28 | } 29 | }, 30 | onExit:function() 31 | { 32 | this._super(); 33 | this.onScrolledOver.removeAll(); 34 | }, 35 | addSource:function(source, assetID, isTile) 36 | { 37 | this._sources.push({source: source, assetID: assetID, isTile:isTile}); 38 | if(this._bg0 == null){ 39 | this._bg0 = this._createNextBG(); 40 | } 41 | }, 42 | _createNextBG:function() 43 | { 44 | if(this._scrollingIndex > this._sources.length - 1){ 45 | this._scrollingIndex = 0; 46 | } 47 | var bgData = this._sources[this._scrollingIndex]; 48 | this._scrollingIndex ++; 49 | 50 | var bg = null; 51 | //If it's a custom display 52 | if(bgData.assetID != null){ 53 | if(bgData.isTile !== true){ 54 | bg = flax.assetsManager.createDisplay(bgData.source, bgData.assetID, null, true); 55 | }else{ 56 | bg = new flax.TiledImage(bgData.source, bgData.assetID); 57 | } 58 | }else if(bgData.source){ 59 | //if it's a FlaxSprite 60 | if(flax.isFlaxDisplay(bgData.source)){ 61 | //todo, JSB Invalid native object error! 62 | if(bgData.source.parent) bgData.source.parent.addChild(this, bgData.source.zIndex); 63 | this.name = bgData.source.name; 64 | if(this.parent) this.parent[this.name] = this; 65 | this.setPosition(bgData.source.getPosition()); 66 | bg = flax.assetsManager.cloneDisplay(bgData.source); 67 | bgData.source.removeFromParent(); 68 | } 69 | //If it's a image 70 | else if(flax.isImageFile(bgData.source)){ 71 | bg = new cc.Sprite(bgData.source); 72 | }else { 73 | throw "Not supported source type!"; 74 | } 75 | }else{ 76 | throw "Arguments is not valid!" 77 | } 78 | bg.setAnchorPoint(0, 0); 79 | this.addChild(bg); 80 | 81 | if(this._size == null){ 82 | this._size = bg.getContentSize(); 83 | this.setContentSize(this._size); 84 | } 85 | 86 | return bg; 87 | }, 88 | reset:function() 89 | { 90 | this._paused = false; 91 | if(!this._scrolling) return; 92 | this._scrolling = false; 93 | this._speedX = this._speedY = 0; 94 | 95 | if(this._bg0.destroy) this._bg0.destroy(); 96 | else this._bg0.removeFromParent(); 97 | this._bg0 = null; 98 | 99 | if(this._bg1.destroy) this._bg1.destroy(); 100 | else this._bg1.removeFromParent(); 101 | this._bg1 = null; 102 | 103 | this._scrollingIndex = 0; 104 | if(this._bg0 == null) this._bg0 = this._createNextBG(); 105 | this._bg0.setPosition(this._x0, this._y0); 106 | this.unscheduleUpdate(); 107 | }, 108 | startXScroll:function(speed, loop) 109 | { 110 | if(speed == 0 || this._bg0 == null) return; 111 | if(this._scrolling) return; 112 | this._scrolling = true; 113 | this._loop = loop !== false; 114 | this._speedX = speed; 115 | this._speedY = 0; 116 | this._d = (this._speedX > 0) ? 1: -1; 117 | this._resetScroll(); 118 | this.scheduleUpdate(); 119 | }, 120 | startYScroll:function(speed, loop) 121 | { 122 | if(speed == 0 || this._bg0 == null) return; 123 | if(this._scrolling) return; 124 | this._scrolling = true; 125 | this._loop = loop !== false; 126 | this._speedY = speed; 127 | this._speedX = 0; 128 | this._d = (this._speedY > 0) ? 1: -1; 129 | this._resetScroll(); 130 | this.scheduleUpdate(); 131 | }, 132 | pauseScroll:function() 133 | { 134 | if(!this._scrolling) return; 135 | if(this._paused) return; 136 | this._paused = true; 137 | this.unscheduleUpdate(); 138 | }, 139 | resumeScroll:function() 140 | { 141 | if(!this._scrolling) return; 142 | if(!this._paused) return; 143 | this._paused = false; 144 | this.scheduleUpdate(); 145 | }, 146 | _resetScroll:function() 147 | { 148 | this._bg0.setPosition(this._x0, this._y0); 149 | if(this._bg1 == null) this._bg1 = this._createNextBG(); 150 | (this._speedX != 0) ? this._bg1.x = -this._d*(this._size.width - 1) : this._bg1.y = -this._d*(this._size.height - 1); 151 | }, 152 | update:function(delta) 153 | { 154 | if(this._size.width*this._size.height == 0) { 155 | this._size = this._bg0.getContentSize(); 156 | if(this._size.width*this._size.height != 0){ 157 | this.setContentSize(this._size); 158 | this._resetScroll(); 159 | } 160 | return; 161 | } 162 | var needReset = false; 163 | if(this._speedX != 0){ 164 | var dx = this._speedX*delta; 165 | this._bg0.x += dx; 166 | this._bg1.x += dx; 167 | var dist = this._size.width - this._bg0.x*this._d; 168 | if(dist <= 0){ 169 | this._bg0.x += this._d*dist; 170 | this._bg1.x += this._d*dist; 171 | needReset = true; 172 | } 173 | }else if(this._speedY != 0){ 174 | var dy = this._speedY*delta; 175 | this._bg0.y += dy; 176 | this._bg1.y += dy; 177 | var dist = this._size.height - this._bg0.y*this._d; 178 | if(dist <= 0){ 179 | this._bg0.y += this._d*dist; 180 | this._bg1.y += this._d*dist; 181 | needReset = true; 182 | } 183 | } 184 | if(needReset){ 185 | if(!this._loop && this._scrollingIndex > this._sources.length - 1){ 186 | this.onScrolledOver.dispatch(); 187 | this.pauseScroll(); 188 | return; 189 | } 190 | //todo, performance improve by reuse the bg? 191 | if(this._bg0.destroy) this._bg0.destroy(); 192 | else this._bg0.removeFromParent(); 193 | this._bg0 = this._bg1; 194 | this._bg1 = this._createNextBG(); 195 | this._resetScroll(); 196 | } 197 | }, 198 | getRect:function(){ 199 | if(this._size.width*this._size.height == 0) { 200 | this._size = this._bg0.getContentSize(); 201 | if(this._size.width*this._size.height != 0){ 202 | this.setContentSize(this._size); 203 | } 204 | } 205 | return cc.rect(0, 0, this._size.width, this._size.height); 206 | } 207 | }); 208 | 209 | flax.ScrollingBG.create = function(source, assetID, isTiled) 210 | { 211 | var bg = new flax.ScrollingBG(source, assetID, isTiled); 212 | return bg; 213 | }; -------------------------------------------------------------------------------- /src/flax/game/SoundButton.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 15-5-7. 3 | */ 4 | 5 | flax._soundButton = { 6 | onEnter:function() 7 | { 8 | this._super(); 9 | this.setState(flax.getSoundEnabled() ? ButtonState.UP : ButtonState.SELECTED); 10 | }, 11 | _onClick:function(touch, event) 12 | { 13 | this._super(touch, event); 14 | flax.setSoundEnabled(!this.isSelected()); 15 | } 16 | } 17 | 18 | flax.SimpleSoundButton = flax.SimpleButton.extend(flax._soundButton); 19 | 20 | flax.SoundButton = flax.Button.extend(flax._soundButton); -------------------------------------------------------------------------------- /src/flax/game/TiledImage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-2-21. 3 | */ 4 | /** 5 | * Layer.bake maybe a choice for good performance 6 | * */ 7 | flax.TiledImage = cc.SpriteBatchNode.extend({ 8 | tileMap:null, 9 | tileWidthOffset: 0, 10 | tileHeightOffset:0, 11 | assetsFile:null, 12 | assetID:null, 13 | _mapWidth:0, 14 | _mapHeight:0, 15 | 16 | ctor:function(assetsFile, assetID, minWidth, minHeight) 17 | { 18 | var imgFile = cc.path.changeBasename(assetsFile, ".png"); 19 | cc.SpriteBatchNode.prototype.ctor.call(this, imgFile); 20 | this.tileMap = new flax.TileMap(); 21 | this.setTileSource(assetsFile, assetID); 22 | if(!minWidth) minWidth = cc.visibleRect.width; 23 | if(!minHeight) minHeight = cc.visibleRect.height; 24 | this.setSize(minWidth, minHeight); 25 | }, 26 | setTileSource:function(assetsFile, assetID) 27 | { 28 | if(this.assetsFile == assetsFile && this.assetID == assetID) return; 29 | this.assetsFile = assetsFile; 30 | this.assetID = assetID; 31 | 32 | var tile = flax.assetsManager.createDisplay(this.assetsFile, this.assetID); 33 | var size = tile.getContentSize(); 34 | this.tileMap.init(size.width + this.tileWidthOffset, size.height + this.tileHeightOffset); 35 | 36 | if(this._mapWidth * this._mapHeight > 0) { 37 | if(this.getChildrenCount() > 0){ 38 | this._updateTileImg(); 39 | } 40 | this._updateSize(); 41 | } 42 | }, 43 | /** 44 | * todo, there is issue when randomly change the size 45 | * */ 46 | setSize:function(w, h) 47 | { 48 | if(w == this._mapWidth && h == this._mapHeight) return; 49 | this._mapWidth = w; 50 | this._mapHeight = h; 51 | if(this.assetsFile) { 52 | this._updateSize(); 53 | } 54 | }, 55 | _updateTileImg:function() 56 | { 57 | var child = null; 58 | var num = this.getChildrenCount(); 59 | var i = -1; 60 | while(++i < num) 61 | { 62 | child = this.children[i]; 63 | child.setSource(this.assetsFile, this.assetID); 64 | this.tileMap.snapToTile(child, child.tx, child.ty); 65 | } 66 | }, 67 | _updateSize:function() 68 | { 69 | var objs = this.tileMap.setMapSize(this._mapWidth, this._mapHeight, true); 70 | var i; 71 | var n = objs[0].length; 72 | if(n > 0) { 73 | var tile; 74 | i = -1; 75 | while(++i < n){ 76 | //remove the tiles 77 | tile = objs[0][i]; 78 | if(tile.destroy) tile.destroy(); 79 | else tile.removeFromParent(); 80 | } 81 | } 82 | n = objs[1].length; 83 | if(n > 0) { 84 | i = -1; 85 | while(++i < n){ 86 | this._createTile(objs[1][i][0], objs[1][i][1]); 87 | } 88 | } 89 | this.setContentSize(this.tileMap.getMapSizePixel()); 90 | }, 91 | _createTile:function(i, j) 92 | { 93 | var tile = flax.assetsManager.createDisplay(this.assetsFile, this.assetID, {parent: this}, true); 94 | tile.setAnchorPoint(0.5, 0.5); 95 | this.tileMap.snapToTile(tile, i, j, true); 96 | return tile; 97 | } 98 | }); -------------------------------------------------------------------------------- /src/flax/game/UserData.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-11-19. 3 | */ 4 | flax.userData = { 5 | // gold:100, 6 | // levelStars:[], 7 | // powerups:[0,0,0,0] 8 | }; 9 | 10 | flax.fetchUserData = function(defaultValue) { 11 | if(defaultValue) flax.userData = defaultValue; 12 | var data = null; 13 | try{ 14 | data = cc.sys.localStorage.getItem(cc.game.config["gameId"]); 15 | if(data) data = JSON.parse(data); 16 | }catch(e){ 17 | cc.log("Fetch UserData Error: "+ e.name); 18 | } 19 | if(data) flax.copyProperties(data, flax.userData); 20 | // else if(defaultValue) flax.userData = defaultValue; 21 | if(!flax.userData) flax.userData = {}; 22 | }; 23 | 24 | flax.saveUserData = function() { 25 | if(!flax.userData) flax.userData = {}; 26 | try{ 27 | cc.sys.localStorage.setItem(cc.game.config["gameId"], JSON.stringify(flax.userData)); 28 | }catch (e){ 29 | cc.log("Save UserData Error: "+ e.name); 30 | } 31 | }; -------------------------------------------------------------------------------- /src/flax/module/EnemyWaveModule.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-7-11. 3 | */ 4 | /** 5 | * var waves = [{types:["enemy1","enemy2"],count:5,interval:[3,5],gap:5}, 6 | * {types:["enemy1","enemy2"],count:5,interval:[3,5],gap:5}, 7 | * {types:["enemy1","enemy2"],count:5,interval:[3,5],gap:5} 8 | * ...] 9 | * Set waves and waveAssetJson, if need, override the _doCreateEnemy function 10 | * */ 11 | flax.EnemyWaveModule = { 12 | waveAssetJson:null, 13 | waves:null, 14 | onWaveBegin:null, 15 | onEnemyIn:null, 16 | onWaveOver:null, 17 | batchCanvas:null, 18 | currentWave:-1, 19 | totalWaves:0, 20 | wavePaused:true, 21 | waveOver:false, 22 | _waveDefine:null, 23 | _enemyCount:0, 24 | _firstRun:true, 25 | onEnter:function() 26 | { 27 | this.totalWaves = this.waves.length; 28 | this.onWaveBegin = new signals.Signal(); 29 | this.onEnemyIn = new signals.Signal(); 30 | this.onWaveOver = new signals.Signal(); 31 | if(!this.wavePaused){ 32 | this.nextWave(); 33 | } 34 | }, 35 | onExit:function(){ 36 | this.onWaveBegin.removeAll(); 37 | this.onEnemyIn.removeAll(); 38 | this.onWaveOver.removeAll(); 39 | }, 40 | startWave:function() 41 | { 42 | if(!this.wavePaused) return; 43 | this.wavePaused = false; 44 | if(this._firstRun) this.nextWave(); 45 | else this._createWaveEnemy(); 46 | this._firstRun = false; 47 | }, 48 | stopWave:function() 49 | { 50 | if(this.wavePaused) return; 51 | this.wavePaused = true; 52 | }, 53 | nextWave:function() 54 | { 55 | if(this.waveOver || this.wavePaused) return; 56 | this._enemyCount = 0; 57 | this.currentWave++; 58 | this._waveDefine = this.waves[this.currentWave]; 59 | this._createWaveEnemy(); 60 | this.onWaveBegin.dispatch(); 61 | }, 62 | _createWaveEnemy:function() 63 | { 64 | if(this.waveOver || this.wavePaused) return; 65 | var assetID = flax.getRandomInArray(this._waveDefine.types); 66 | var enemy = this._doCreateEnemy(assetID); 67 | this.onEnemyIn.dispatch(enemy); 68 | if(++this._enemyCount < this._waveDefine.count){ 69 | var interval = flax.randInt(parseInt(this._waveDefine.interval[0]), parseInt(this._waveDefine.interval[1])); 70 | this.scheduleOnce(function(){ 71 | this._createWaveEnemy(); 72 | },interval); 73 | }else if(this.currentWave == this.totalWaves - 1){ 74 | this.waveOver = true; 75 | this.onWaveOver.dispatch(); 76 | }else{ 77 | this.nextWave(); 78 | } 79 | }, 80 | _doCreateEnemy:function(assetID){ 81 | if(this.waveAssetJson) flax.assetsManager.createDisplay(this.waveAssetJson, assetID, {parent: this.batchCanvas, x: this.x, y: this.y}, true); 82 | //override this function yourself 83 | } 84 | }; -------------------------------------------------------------------------------- /src/flax/module/HealthModule.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 14-7-10. 3 | */ 4 | flax.HealthModule = { 5 | maxHealth:100, 6 | health:100, 7 | hurtable:true, 8 | dead:false, 9 | ownerBody:null,//the body to be hurted, when health == 0, the body will disappear, default body is the gunner itself 10 | onEnter:function(){ 11 | this.health = this.maxHealth; 12 | this.dead = false; 13 | }, 14 | onExit:function(){ 15 | }, 16 | onHit:function(bullet) 17 | { 18 | if(!this.hurtable) return false; 19 | if(this.dead) return true; 20 | this.health -= bullet.damage; 21 | if(this.health <= 0) { 22 | this.dead = true; 23 | this.health = 0; 24 | this.onDie(); 25 | return true; 26 | } 27 | return false; 28 | }, 29 | onDie:function() 30 | { 31 | if(this.ownerBody) this.ownerBody.destroy(); 32 | else this.destroy(); 33 | } 34 | }; -------------------------------------------------------------------------------- /src/flax/module/MoveModule.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 15-4-17. 3 | */ 4 | 5 | flax.MoveModule = { 6 | gravityOnMove:null, 7 | destroyWhenReach:false, 8 | destroyWhenOutofStage:false, 9 | moveSpeed:null, 10 | moveAcc:null, 11 | restrainRect:null, 12 | inRandom:false, 13 | _moveSpeedLen:0, 14 | _targetPos:null, 15 | _inMoving:false, 16 | _callBack:null, 17 | _callContext:null, 18 | 19 | onEnter:function(){ 20 | }, 21 | onExit:function(){ 22 | this.destroyWhenReach = false; 23 | this.destroyWhenOutofStage = false; 24 | this.gravityOnMove = null; 25 | this.restrainRect = null; 26 | this.inRandom = false; 27 | this._inMoving = false; 28 | }, 29 | /** 30 | * Move to a new position within duration time 31 | * Note: If you use cc.moveTo in JSB, the setPosition function in js can not be called, use this instead of 32 | * */ 33 | moveTo:function(pos, duration, callBack, callContext) { 34 | this.inRandom = false; 35 | this._targetPos = pos; 36 | this._callBack = callBack; 37 | this._callContext = callContext; 38 | var dis = cc.pSub(pos, this.getPosition()); 39 | if(cc.pLength(dis) < 1 || !duration || duration <= 0){ 40 | this.scheduleOnce(this._moveOver, 0.01); 41 | return; 42 | } 43 | this.moveSpeed = cc.pMult(dis, 1.0 / duration); 44 | this._moveSpeedLen = cc.pLength(this.moveSpeed); 45 | this.resumeMove(); 46 | }, 47 | /** 48 | * Move to a new position with speed 49 | * Note: If you use cc.moveTo in JSB, the setPosition function in js can not be called, use this instead of 50 | * */ 51 | moveToBySpeed:function(pos, speed, callBack, callContext) { 52 | this.inRandom = false; 53 | this._targetPos = pos; 54 | this._callBack = callBack; 55 | this._callContext = callContext; 56 | var dis = cc.pSub(pos, this.getPosition()); 57 | var len = cc.pLength(dis); 58 | if(len < 1){ 59 | this.scheduleOnce(this._moveOver, 0.01); 60 | return; 61 | } 62 | this.moveSpeed = cc.pMult(dis, speed / len); 63 | this._moveSpeedLen = cc.pLength(this.moveSpeed); 64 | this.resumeMove(); 65 | }, 66 | /** 67 | * Just move forward with the speed (and the direction) 68 | * @speed {Point|Number} speed If its point, then move on x direction on .x speed and y direction on .y speed 69 | * @direction {Number} direction If speed is a number, then move on this direction(degree angle) 70 | * */ 71 | moveBySpeed:function(speed, direction) 72 | { 73 | this._targetPos = null; 74 | this._callBack = null; 75 | this.inRandom = false; 76 | 77 | if(typeof speed === "object"){ 78 | this.moveSpeed = speed; 79 | }else{ 80 | this.moveSpeed = flax.getPointOnCircle(cc.p(), speed, direction); 81 | } 82 | this.resumeMove(); 83 | }, 84 | moveRandomly:function(speed, direction, restrainRect) 85 | { 86 | this.restrainRect = restrainRect || flax.stageRect; 87 | this.moveBySpeed(speed, direction || 360*Math.random()); 88 | this.inRandom = direction == null; 89 | }, 90 | pauseMove:function() 91 | { 92 | if(this._inMoving){ 93 | this.unschedule(this._doMove); 94 | this._inMoving = false; 95 | } 96 | }, 97 | resumeMove:function() 98 | { 99 | if(this._inMoving) return; 100 | this._inMoving = true; 101 | this.schedule(this._doMove, flax.frameInterval, cc.REPEAT_FOREVER); 102 | }, 103 | stopMove:function() 104 | { 105 | if(this._inMoving){ 106 | this._targetPos = this.moveSpeed = null; 107 | this._inMoving = false; 108 | this._callBack = null; 109 | this.restrainRect = null; 110 | this.inRandom = false; 111 | this.unschedule(this._doMove); 112 | } 113 | }, 114 | _doMove:function(delta) 115 | { 116 | var pos = this.getPosition(); 117 | var dis = this._targetPos ? cc.pDistance(pos, this._targetPos) : Number.maxValue; 118 | var deltaDis = this._moveSpeedLen*delta; 119 | if(dis < deltaDis || (this.destroyWhenOutofStage && !cc.rectContainsRect(flax.stageRect, flax.getRect(this, true)))){ 120 | this._moveOver(); 121 | this.stopMove(); 122 | }else{ 123 | var rect = flax.getRect(this, this.parent); 124 | //when collide with the bounder, bounce back 125 | if(this.restrainRect){ 126 | var dx = 0; 127 | var dy = 0; 128 | if(rect.x < this.restrainRect.x){ 129 | dx = 1.0; 130 | }else if(rect.x > this.restrainRect.x + this.restrainRect.width - rect.width) { 131 | dx = -1.0; 132 | } 133 | if(rect.y < this.restrainRect.y){ 134 | dy = 1.0; 135 | }else if(rect.y > this.restrainRect.y + this.restrainRect.height - rect.height) { 136 | dy = -1.0; 137 | } 138 | if(this.inRandom){ 139 | if(dx) this.moveSpeed.x = dx*Math.abs(this.moveSpeed.x); 140 | if(dy) this.moveSpeed.y = dy*Math.abs(this.moveSpeed.y); 141 | }else if(dx || dy){ 142 | //todo 143 | // this.moveSpeed = cc.p(); 144 | // this.stopMove(); 145 | } 146 | } 147 | var acc = this.moveAcc; 148 | if(this.gravityOnMove) acc = cc.pAdd(acc || cc.p(), this.gravityOnMove); 149 | if(acc) { 150 | this.moveSpeed = cc.pAdd(this.moveSpeed, cc.pMult(acc, delta)); 151 | } 152 | this.setPosition(cc.pAdd(pos, cc.pMult(this.moveSpeed, delta))); 153 | } 154 | }, 155 | _moveOver:function() 156 | { 157 | if(this._targetPos) this.setPosition(this._targetPos); 158 | if(this._callBack){ 159 | this._callBack.apply(this._callContext || this); 160 | this._callBack = null; 161 | } 162 | if(this.destroyWhenReach){ 163 | this.destroy(); 164 | } 165 | } 166 | } -------------------------------------------------------------------------------- /src/flax/module/PhysicsModule.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 15-9-17. 3 | */ 4 | 5 | flax.PhysicsModule = { 6 | _physicsBody:null, 7 | _physicsToBeSet:null, 8 | _physicsBodyParam:null, 9 | _physicsColliders:null, 10 | onEnter:function() 11 | { 12 | if(this._physicsColliders == null) this._physicsColliders = []; 13 | if(this._physicsBodyParam) { 14 | this.createPhysics(this._physicsBodyParam.type, this._physicsBodyParam.fixedRotation, this._physicsBodyParam.bullet); 15 | } 16 | if(this._physicsToBeSet){ 17 | for(var name in this._physicsToBeSet){ 18 | var collider = this.getCollider(name); 19 | var param = this._physicsToBeSet[name]; 20 | collider.createPhysics(param.density, param.friction, param.restitution, param.isSensor, param.catBits, param.maskBits); 21 | delete this._physicsToBeSet[name]; 22 | if(this._physicsColliders.indexOf(collider) == -1) this._physicsColliders.push(collider); 23 | } 24 | } 25 | }, 26 | onExit:function() 27 | { 28 | //remove physics 29 | for(var i = 0; i < this._physicsColliders.length; i++){ 30 | this._physicsColliders[i].destroyPhysics(); 31 | } 32 | this._physicsColliders = []; 33 | 34 | if(this._physicsBody){ 35 | flax.removePhysicsBody(this._physicsBody); 36 | this._physicsBody = null; 37 | } 38 | this._physicsBodyParam = null; 39 | }, 40 | getPhysicsBody:function(){ 41 | return this._physicsBody; 42 | }, 43 | createPhysics:function(type, fixedRotation, bullet){ 44 | if(type == null) type = Box2D.Dynamics.b2Body.b2_dynamicBody; 45 | this._physicsBodyParam = {type:type, fixedRotation:fixedRotation, bullet:bullet}; 46 | if(!this.parent) return null; 47 | if(this._physicsBody == null) { 48 | var def = new Box2D.Dynamics.b2BodyDef(); 49 | def.type = type; 50 | def.fixedRotation = fixedRotation; 51 | def.bullet = bullet; 52 | def.userData = this; 53 | var pos = flax.getPosition(this, true); 54 | def.position.Set(pos.x / PTM_RATIO, pos.y / PTM_RATIO); 55 | this._physicsBody = flax.getPhysicsWorld().CreateBody(def); 56 | this._physicsBody.__rotationOffset = this.rotation; 57 | } 58 | return this._physicsBody; 59 | }, 60 | destroyPhysics:function(){ 61 | this.removePhysicsShape(); 62 | }, 63 | addPhysicsShape:function(name, density, friction,restitution, isSensor, catBits, maskBits){ 64 | if(this._physicsBody == null) throw "Please createPhysics firstly!"; 65 | var collider = this.getCollider(name); 66 | if(collider == null) { 67 | cc.log("There is no collider named: "+name); 68 | return null; 69 | }else if(collider.physicsFixture){ 70 | return collider.physicsFixture; 71 | } 72 | var param = {density:density,friction:friction,restitution:restitution,isSensor:isSensor,catBits:catBits,maskBits:maskBits}; 73 | if(this.parent) { 74 | collider.setOwner(this); 75 | var fixture = collider.createPhysics(density, friction, restitution, isSensor, catBits, maskBits); 76 | if(this._physicsColliders.indexOf(collider) == -1) this._physicsColliders.push(collider); 77 | return fixture; 78 | } 79 | if(this._physicsToBeSet == null) this._physicsToBeSet = {}; 80 | if(this._physicsToBeSet[name] == null) this._physicsToBeSet[name] = param; 81 | return null; 82 | }, 83 | /** 84 | * Remove the physics of name, if not set name, remove all 85 | * */ 86 | removePhysicsShape:function(name){ 87 | var i = this._physicsColliders.length; 88 | while(i--){ 89 | var c = this._physicsColliders[i]; 90 | if(name == null || c.name == name){ 91 | c.destroyPhysics(); 92 | this._physicsColliders.splice(i, 1); 93 | } 94 | } 95 | if(this._physicsColliders.length == 0){ 96 | flax.removePhysicsBody(this._physicsBody); 97 | this._physicsBody = null; 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /src/flax/module/ScreenLayoutModule.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 15-5-10. 3 | */ 4 | var HLayoutType = { 5 | LEFT:0, 6 | CENTER:1, 7 | RIGHT:2 8 | } 9 | var VLayoutType = { 10 | BOTTOM:0, 11 | MIDDLE:1, 12 | TOP:2 13 | } 14 | 15 | flax.getLayoutPosition = function(target, hLayout, vLayout) 16 | { 17 | var rect = flax.getRect(target, true); 18 | var sCenter = cc.visibleRect.center; 19 | var anchorPos = target.getAnchorPointInPoints(); 20 | 21 | var x = 0; 22 | var y = 0; 23 | 24 | switch(hLayout){ 25 | case HLayoutType.LEFT: 26 | x = 0; 27 | break; 28 | case HLayoutType.CENTER: 29 | x = sCenter.x - rect.width/2; 30 | break; 31 | case HLayoutType.RIGHT: 32 | x = cc.visibleRect.right.x - rect.width; 33 | break; 34 | } 35 | switch(vLayout){ 36 | case VLayoutType.BOTTOM: 37 | y = 0; 38 | break; 39 | case VLayoutType.MIDDLE: 40 | y = sCenter.y - rect.height/2; 41 | break; 42 | case VLayoutType.TOP: 43 | y = cc.visibleRect.top.y - rect.height; 44 | break; 45 | } 46 | 47 | var scale = flax.getScale(target, true); 48 | var offsetX = !hLayout ? cc.visibleRect.bottomLeft.x : 0; 49 | var offsetY = !vLayout ? cc.visibleRect.bottomLeft.y : 0; 50 | var pos = cc.p(x + offsetX + anchorPos.x*scale.x, y + offsetY + anchorPos.y*scale.y); 51 | 52 | if(target.parent){ 53 | pos = target.parent.convertToNodeSpace(pos); 54 | } 55 | return pos; 56 | } 57 | 58 | flax.ScreenLayoutModule = { 59 | _isAutoLayout:false, 60 | _hlayout:null, 61 | _vlayout:null, 62 | _offsetX:0, 63 | _offsetY:0, 64 | onEnter:function() 65 | { 66 | flax.onDeviceRotate.add(this._updateLayout, this); 67 | flax.onScreenResize.add(this._updateLayout, this); 68 | }, 69 | onExit:function() 70 | { 71 | flax.onDeviceRotate.remove(this._updateLayout, this); 72 | flax.onScreenResize.remove(this._updateLayout, this); 73 | }, 74 | setLayoutOffset:function(offsetX, offsetY) 75 | { 76 | this._offsetX = offsetX; 77 | this._offsetY = offsetY; 78 | this._updateLayout(); 79 | }, 80 | /** 81 | * Set the layout 82 | * @param {HLayoutType} hLayout Layout type on horizontal direction 83 | * @param {VLayoutType} vLayout Layout type on vertical direction 84 | * */ 85 | setLayout:function(hLayout, vLayout) 86 | { 87 | this._isAutoLayout = false; 88 | this._hlayout = hLayout; 89 | this._vlayout = vLayout; 90 | var pos = flax.getLayoutPosition(this, hLayout, vLayout); 91 | pos.x += this._offsetX; 92 | pos.y += this._offsetY; 93 | this.setPosition(pos); 94 | }, 95 | /** 96 | * Auto layout on the screen according on the designed position. 97 | * In most situations, the object on the top-left will still on the top-left when screen size changed. 98 | * Note: This can be used only on the resolution policy of cc.ResolutionPolicy.NO_BORDER 99 | * */ 100 | autoLayout:function() 101 | { 102 | if(cc.view.getResolutionPolicy() != cc.ResolutionPolicy.NO_BORDER) return; 103 | 104 | this._isAutoLayout = true; 105 | 106 | var rect = flax.getRect(this, this.parent); 107 | var sCenter = cc.visibleRect.center; 108 | var anchorPos = this.getAnchorPointInPoints(); 109 | var offsetPlus = 0; 110 | 111 | var rateX = cc.visibleRect.width/flax.designedStageSize.width; 112 | if(rateX != 1.0){ 113 | var offsetX = this.x - sCenter.x; 114 | if(offsetX > 0) { 115 | offsetPlus = rect.width; 116 | } 117 | offsetX = rect.x + offsetPlus - sCenter.x; 118 | this.x = sCenter.x + offsetX*rateX + anchorPos.x*this.scaleX - offsetPlus + this._offsetX; 119 | } 120 | 121 | var rateY = cc.visibleRect.height/flax.designedStageSize.height; 122 | if(rateY != 1.0){ 123 | var offsetY = this.y - sCenter.y; 124 | offsetPlus = 0; 125 | if(offsetY > 0) { 126 | offsetPlus = rect.height; 127 | } 128 | offsetY = rect.y + offsetPlus - sCenter.y; 129 | this.y = sCenter.y + offsetY*rateY + anchorPos.y*this.scaleY - offsetPlus + this._offsetY; 130 | } 131 | }, 132 | _updateLayout:function(landscape) 133 | { 134 | if(this._isAutoLayout){ 135 | this.autoLayout(); 136 | }else if(this._hlayout != null && this._vlayout != null){ 137 | this.setLayout(this._hlayout, this._vlayout); 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /src/flax/module/TileMapModule.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by long on 15-3-21. 3 | */ 4 | flax.TileMapModule = { 5 | tx:0, 6 | ty:0, 7 | autoUpdateTileWhenMove:true, 8 | tileValue:TileValue.WALKABLE, 9 | _tileMap:null, 10 | _tileInited:false, 11 | 12 | onEnter:function() 13 | { 14 | if(this._tileMap && !this._tileInited) { 15 | this.updateTile(true); 16 | } 17 | }, 18 | onExit:function() 19 | { 20 | if(this._tileMap) this._tileMap.removeObject(this); 21 | this._tileMap = null; 22 | this._tileInited = false; 23 | }, 24 | onPosition:function() 25 | { 26 | if(this.autoUpdateTileWhenMove && this._tileMap){ 27 | this.updateTile(); 28 | } 29 | }, 30 | getTileMap:function() 31 | { 32 | return this._tileMap; 33 | }, 34 | setTileMap:function(map) 35 | { 36 | if(map && !(map instanceof flax.TileMap)) map = flax.getTileMap(map); 37 | if(this._tileMap == map) return; 38 | if(this._tileMap) this._tileMap.removeObject(this); 39 | this._tileMap = map; 40 | if(this._tileMap == null) return; 41 | 42 | if(this.parent) { 43 | this.updateTile(true); 44 | //todo 45 | // this._updateCollider(); 46 | } 47 | }, 48 | updateTile:function(forceUpdate){ 49 | if(!this._tileMap) return; 50 | var pos = this.getPosition(); 51 | if(this.parent) pos = this.parent.convertToWorldSpace(pos); 52 | var t = this._tileMap.getTileIndex(pos); 53 | this.setTile(t.x, t.y, forceUpdate); 54 | }, 55 | setTile:function(tx, ty, forceUpdate) 56 | { 57 | if (forceUpdate === true || tx != this.tx || ty != this.ty) { 58 | var oldTx = this.tx; 59 | var oldTy = this.ty; 60 | this.tx = tx; 61 | this.ty = ty; 62 | if(this._tileMap && this.parent) 63 | { 64 | this._tileMap.removeObject(this, oldTx, oldTy); 65 | if(this.parent) { 66 | this._tileMap.addObject(this); 67 | this._tileInited = true; 68 | } 69 | } 70 | }else { 71 | //update the zOrder sort in the tile 72 | // this._tileMap.updateLayout(tx, ty); 73 | } 74 | }, 75 | snapToTile:function(tx, ty, autoAdd) 76 | { 77 | this._tileMap.snapToTile(this,tx, ty, autoAdd); 78 | } 79 | }; -------------------------------------------------------------------------------- /src/flax/signal/Signal.js: -------------------------------------------------------------------------------- 1 | /*global SignalBinding:false*/ 2 | 3 | // Signal -------------------------------------------------------- 4 | //================================================================ 5 | 6 | //https://github.com/millermedeiros/js-signals/wiki/Examples 7 | 8 | function validateListener(listener, fnName) { 9 | if (typeof listener !== 'function') { 10 | throw new Error( 'listener is a required param of {fn}() and should be a Function.'.replace('{fn}', fnName) ); 11 | } 12 | } 13 | 14 | /** 15 | * Custom event broadcaster 16 | *
- inspired by Robert Penner's AS3 Signals. 17 | * @name Signal 18 | * @author Miller Medeiros 19 | * @constructor 20 | */ 21 | function Signal() { 22 | /** 23 | * @type Array. 24 | * @private 25 | */ 26 | this._bindings = []; 27 | this._prevParams = null; 28 | 29 | // enforce dispatch to aways work on same context (#47) 30 | var self = this; 31 | this.dispatch = function(){ 32 | Signal.prototype.dispatch.apply(self, arguments); 33 | }; 34 | } 35 | 36 | Signal.prototype = { 37 | 38 | /** 39 | * Signals Version Number 40 | * @type String 41 | * @const 42 | */ 43 | VERSION : '::VERSION_NUMBER::', 44 | 45 | /** 46 | * If Signal should keep record of previously dispatched parameters and 47 | * automatically execute listener during `add()`/`addOnce()` if Signal was 48 | * already dispatched before. 49 | * @type boolean 50 | */ 51 | memorize : false, 52 | 53 | /** 54 | * @type boolean 55 | * @private 56 | */ 57 | _shouldPropagate : true, 58 | 59 | /** 60 | * If Signal is active and should broadcast events. 61 | *

IMPORTANT: Setting this property during a dispatch will only affect the next dispatch, if you want to stop the propagation of a signal use `halt()` instead.

62 | * @type boolean 63 | */ 64 | actived : true, 65 | 66 | /** 67 | * @param {Function} listener 68 | * @param {boolean} isOnce 69 | * @param {Object} [listenerContext] 70 | * @param {Number} [priority] 71 | * @return {SignalBinding} 72 | * @private 73 | */ 74 | _registerListener : function (listener, isOnce, listenerContext, priority) { 75 | 76 | var prevIndex = this._indexOfListener(listener, listenerContext), 77 | binding; 78 | 79 | if (prevIndex !== -1) { 80 | binding = this._bindings[prevIndex]; 81 | if (binding.isOnce() !== isOnce) { 82 | throw new Error('You cannot add'+ (isOnce? '' : 'Once') +'() then add'+ (!isOnce? '' : 'Once') +'() the same listener without removing the relationship first.'); 83 | } 84 | } else { 85 | binding = new SignalBinding(this, listener, isOnce, listenerContext, priority); 86 | this._addBinding(binding); 87 | } 88 | 89 | if(this.memorize && this._prevParams){ 90 | binding.execute(this._prevParams); 91 | } 92 | 93 | return binding; 94 | }, 95 | 96 | /** 97 | * @param {SignalBinding} binding 98 | * @private 99 | */ 100 | _addBinding : function (binding) { 101 | //simplified insertion sort 102 | var n = this._bindings.length; 103 | do { --n; } while (this._bindings[n] && binding._priority <= this._bindings[n]._priority); 104 | this._bindings.splice(n + 1, 0, binding); 105 | }, 106 | 107 | /** 108 | * @param {Function} listener 109 | * @param {Object} context 110 | * @return {number} 111 | * @private 112 | */ 113 | _indexOfListener : function (listener, context) { 114 | var n = this._bindings.length, 115 | cur; 116 | while (n--) { 117 | cur = this._bindings[n]; 118 | if (cur._listener === listener && cur.context === context) { 119 | return n; 120 | } 121 | } 122 | return -1; 123 | }, 124 | 125 | /** 126 | * Check if listener was attached to Signal. 127 | * @param {Function} listener 128 | * @param {Object} [context] 129 | * @return {boolean} if Signal has the specified listener. 130 | */ 131 | has : function (listener, context) { 132 | return this._indexOfListener(listener, context) !== -1; 133 | }, 134 | 135 | /** 136 | * Add a listener to the signal. 137 | * @param {Function} listener Signal handler function. 138 | * @param {Object} [listenerContext] Context on which listener will be executed (object that should represent the `this` variable inside listener function). 139 | * @param {Number} [priority] The priority level of the event listener. Listeners with higher priority will be executed before listeners with lower priority. Listeners with same priority level will be executed at the same order as they were added. (default = 0) 140 | * @return {SignalBinding} An Object representing the binding between the Signal and listener. 141 | */ 142 | add : function (listener, listenerContext, priority) { 143 | validateListener(listener, 'add'); 144 | return this._registerListener(listener, false, listenerContext, priority); 145 | }, 146 | 147 | /** 148 | * Add listener to the signal that should be removed after first execution (will be executed only once). 149 | * @param {Function} listener Signal handler function. 150 | * @param {Object} [listenerContext] Context on which listener will be executed (object that should represent the `this` variable inside listener function). 151 | * @param {Number} [priority] The priority level of the event listener. Listeners with higher priority will be executed before listeners with lower priority. Listeners with same priority level will be executed at the same order as they were added. (default = 0) 152 | * @return {SignalBinding} An Object representing the binding between the Signal and listener. 153 | */ 154 | addOnce : function (listener, listenerContext, priority) { 155 | validateListener(listener, 'addOnce'); 156 | return this._registerListener(listener, true, listenerContext, priority); 157 | }, 158 | 159 | /** 160 | * Remove a single listener from the dispatch queue. 161 | * @param {Function} listener Handler function that should be removed. 162 | * @param {Object} [context] Execution context (since you can add the same handler multiple times if executing in a different context). 163 | * @return {Function} Listener handler function. 164 | */ 165 | remove : function (listener, context) { 166 | validateListener(listener, 'remove'); 167 | 168 | var i = this._indexOfListener(listener, context); 169 | if (i !== -1) { 170 | this._bindings[i]._destroy(); //no reason to a SignalBinding exist if it isn't attached to a signal 171 | this._bindings.splice(i, 1); 172 | } 173 | return listener; 174 | }, 175 | 176 | /** 177 | * Remove all listeners from the Signal. 178 | */ 179 | removeAll : function () { 180 | var n = this._bindings.length; 181 | while (n--) { 182 | this._bindings[n]._destroy(); 183 | } 184 | this._bindings.length = 0; 185 | }, 186 | 187 | /** 188 | * @return {number} Number of listeners attached to the Signal. 189 | */ 190 | getNumListeners : function () { 191 | return this._bindings.length; 192 | }, 193 | 194 | /** 195 | * Stop propagation of the event, blocking the dispatch to next listeners on the queue. 196 | *

IMPORTANT: should be called only during signal dispatch, calling it before/after dispatch won't affect signal broadcast.

197 | * @see Signal.prototype.disable 198 | */ 199 | halt : function () { 200 | this._shouldPropagate = false; 201 | }, 202 | 203 | /** 204 | * Dispatch/Broadcast Signal to all listeners added to the queue. 205 | * @param {...*} [params] Parameters that should be passed to each handler. 206 | */ 207 | dispatch : function (params) { 208 | if (! this.actived) { 209 | return; 210 | } 211 | 212 | var paramsArr = Array.prototype.slice.call(arguments), 213 | n = this._bindings.length, 214 | bindings; 215 | 216 | if (this.memorize) { 217 | this._prevParams = paramsArr; 218 | } 219 | if (! n) { 220 | //should come after memorize 221 | return; 222 | } 223 | 224 | bindings = this._bindings.slice(); //clone array in case add/remove items during dispatch 225 | this._shouldPropagate = true; //in case `halt` was called before dispatch or during the previous dispatch. 226 | 227 | //execute all callbacks until end of the list or until a callback returns `false` or stops propagation 228 | //reverse loop since listeners with higher priority will be added at the end of the list 229 | do { n--; } while (bindings[n] && this._shouldPropagate && bindings[n].execute(paramsArr) !== false); 230 | }, 231 | 232 | /** 233 | * Forget memorized arguments. 234 | * @see Signal.memorize 235 | */ 236 | forget : function(){ 237 | this._prevParams = null; 238 | }, 239 | 240 | /** 241 | * Remove all bindings from signal and destroy any reference to external objects (destroy Signal object). 242 | *

IMPORTANT: calling any method on the signal instance after calling dispose will throw errors.

243 | */ 244 | dispose : function () { 245 | this.removeAll(); 246 | delete this._bindings; 247 | delete this._prevParams; 248 | }, 249 | 250 | /** 251 | * @return {string} String representation of the object. 252 | */ 253 | toString : function () { 254 | return '[Signal active:'+ this.actived +' numListeners:'+ this.getNumListeners() +']'; 255 | } 256 | 257 | }; 258 | 259 | 260 | // Namespace ----------------------------------------------------- 261 | //================================================================ 262 | 263 | /** 264 | * Signals namespace 265 | * @namespace 266 | * @name signals 267 | */ 268 | var signals = Signal; 269 | 270 | /** 271 | * Custom event broadcaster 272 | * @see Signal 273 | */ 274 | // alias for backwards compatibility (see #gh-44) 275 | signals.Signal = Signal; 276 | 277 | -------------------------------------------------------------------------------- /src/flax/signal/SignalBinding.js: -------------------------------------------------------------------------------- 1 | // SignalBinding ------------------------------------------------- 2 | //================================================================ 3 | 4 | /** 5 | * Object that represents a binding between a Signal and a listener function. 6 | *
- This is an internal constructor and shouldn't be called by regular users. 7 | *
- inspired by Joa Ebert AS3 SignalBinding and Robert Penner's Slot classes. 8 | * @author Miller Medeiros 9 | * @constructor 10 | * @internal 11 | * @name SignalBinding 12 | * @param {Signal} signal Reference to Signal object that listener is currently bound to. 13 | * @param {Function} listener Handler function bound to the signal. 14 | * @param {boolean} isOnce If binding should be executed just once. 15 | * @param {Object} [listenerContext] Context on which listener will be executed (object that should represent the `this` variable inside listener function). 16 | * @param {Number} [priority] The priority level of the event listener. (default = 0). 17 | */ 18 | function SignalBinding(signal, listener, isOnce, listenerContext, priority) { 19 | 20 | /** 21 | * Handler function bound to the signal. 22 | * @type Function 23 | * @private 24 | */ 25 | this._listener = listener; 26 | 27 | /** 28 | * If binding should be executed just once. 29 | * @type boolean 30 | * @private 31 | */ 32 | this._isOnce = isOnce; 33 | 34 | /** 35 | * Context on which listener will be executed (object that should represent the `this` variable inside listener function). 36 | * @memberOf SignalBinding.prototype 37 | * @name context 38 | * @type Object|undefined|null 39 | */ 40 | this.context = listenerContext; 41 | 42 | /** 43 | * Reference to Signal object that listener is currently bound to. 44 | * @type Signal 45 | * @private 46 | */ 47 | this._signal = signal; 48 | 49 | /** 50 | * Listener priority 51 | * @type Number 52 | * @private 53 | */ 54 | this._priority = priority || 0; 55 | } 56 | 57 | SignalBinding.prototype = { 58 | 59 | /** 60 | * If binding is active and should be executed. 61 | * @type boolean 62 | */ 63 | actived : true, 64 | 65 | /** 66 | * Default parameters passed to listener during `Signal.dispatch` and `SignalBinding.execute`. (curried parameters) 67 | * @type Array|null 68 | */ 69 | params : null, 70 | 71 | /** 72 | * Call listener passing arbitrary parameters. 73 | *

If binding was added using `Signal.addOnce()` it will be automatically removed from signal dispatch queue, this method is used internally for the signal dispatch.

74 | * @param {Array} [paramsArr] Array of parameters that should be passed to the listener 75 | * @return {*} Value returned by the listener. 76 | */ 77 | execute : function (paramsArr) { 78 | var handlerReturn, params; 79 | if (this.actived && !!this._listener) { 80 | params = this.params? this.params.concat(paramsArr) : paramsArr; 81 | handlerReturn = this._listener.apply(this.context, params); 82 | if (this._isOnce) { 83 | this.detach(); 84 | } 85 | } 86 | return handlerReturn; 87 | }, 88 | 89 | /** 90 | * Detach binding from signal. 91 | * - alias to: mySignal.remove(myBinding.getListener()); 92 | * @return {Function|null} Handler function bound to the signal or `null` if binding was previously detached. 93 | */ 94 | detach : function () { 95 | return this.isBound()? this._signal.remove(this._listener, this.context) : null; 96 | }, 97 | 98 | /** 99 | * @return {Boolean} `true` if binding is still bound to the signal and have a listener. 100 | */ 101 | isBound : function () { 102 | return (!!this._signal && !!this._listener); 103 | }, 104 | 105 | /** 106 | * @return {boolean} If SignalBinding will only be executed once. 107 | */ 108 | isOnce : function () { 109 | return this._isOnce; 110 | }, 111 | 112 | /** 113 | * @return {Function} Handler function bound to the signal. 114 | */ 115 | getListener : function () { 116 | return this._listener; 117 | }, 118 | 119 | /** 120 | * @return {Signal} Signal that listener is currently bound to. 121 | */ 122 | getSignal : function () { 123 | return this._signal; 124 | }, 125 | 126 | /** 127 | * Delete instance properties 128 | * @private 129 | */ 130 | _destroy : function () { 131 | delete this._signal; 132 | delete this._listener; 133 | delete this.context; 134 | }, 135 | 136 | /** 137 | * @return {string} String representation of the object. 138 | */ 139 | toString : function () { 140 | return '[SignalBinding isOnce:' + this._isOnce +', isBound:'+ this.isBound() +', actived:' + this.actived + ']'; 141 | } 142 | 143 | }; 144 | -------------------------------------------------------------------------------- /src/flax/signal/wrapper.js: -------------------------------------------------------------------------------- 1 | /*jslint onevar:true, undef:true, newcap:true, regexp:true, bitwise:true, maxerr:50, indent:4, white:false, nomen:false, plusplus:false */ 2 | /*global define:false, require:false, exports:false, module:false, signals:false */ 3 | 4 | //::LICENSE::// 5 | (function(global){ 6 | 7 | //::SIGNAL_BINDING_JS::// 8 | 9 | //::SIGNAL_JS::// 10 | 11 | //exports to multiple environments 12 | if(typeof define === 'function' && define.amd){ //AMD 13 | define(function () { return signals; }); 14 | } else if (typeof module !== 'undefined' && module.exports){ //node 15 | module.exports = signals; 16 | } else { //browser 17 | //use string because of Google closure compiler ADVANCED_MODE 18 | /*jslint sub:true */ 19 | global['signals'] = signals; 20 | } 21 | 22 | }(this)); 23 | --------------------------------------------------------------------------------