├── .gitignore ├── src ├── version.js ├── Outro.js ├── builtinresource │ ├── __builtin_resource__.png │ ├── __builtin_resource__@atlas │ │ ├── ok.png │ │ ├── arrow.png │ │ ├── button.png │ │ ├── button2.png │ │ ├── circle.png │ │ ├── empty.png │ │ ├── slider.png │ │ ├── sliderbg.png │ │ └── sliderbg2.png │ ├── __builtin_resource__.png.meta │ └── __builtin_resource__.json ├── Intro.js ├── core │ ├── Signal.js │ ├── Plugin.js │ ├── PluginManager.js │ ├── NodePool.js │ ├── Storage.js │ ├── Log.js │ ├── PhaserGame.js │ ├── Stage.js │ ├── State.js │ ├── SoundManager.js │ ├── Debug.js │ ├── Camera.js │ ├── node │ │ └── NodeDisplay.js │ └── Input │ │ └── InputEvent.js ├── time │ ├── TimerEvent.js │ └── Time.js ├── hack │ ├── pixi │ │ ├── WebGLMaskManager.js │ │ ├── CanvasMaskManager.js │ │ ├── CanvasTinter.js │ │ ├── renderers │ │ │ ├── webgl │ │ │ │ └── WebGLRenderer.js │ │ │ └── canvas │ │ │ │ └── CanvasRenderer.js │ │ ├── PixiShader.js │ │ ├── WebGLSpriteBatch.js │ │ └── WebGLFastSpriteBatch.js │ ├── sound │ │ ├── Cache.js │ │ └── Loader.js │ ├── core │ │ ├── Game.js │ │ ├── StateManager.js │ │ └── Group.js │ ├── system │ │ └── Device.js │ ├── loader │ │ └── loader.js │ └── tilemap │ │ └── Tileset.js ├── components │ ├── NonexistScript.js │ ├── TweenTransform.js │ ├── TweenAlpha.js │ ├── TweenRotation.js │ ├── TweenScale.js │ ├── DropdownItem.js │ ├── TweenColor.js │ ├── VerticalLayout.js │ ├── HorizontalLayout.js │ ├── TweenProperty.js │ ├── TweenPosition.js │ ├── DebugViewer.js │ ├── AspectRatioFitter.js │ ├── Animator.js │ └── FilterGroup.js ├── geom │ ├── Matrix.js │ ├── Point.js │ ├── Polygon.js │ ├── Circle.js │ ├── Rectangle.js │ ├── Line.js │ ├── Ellipse.js │ └── RoundedRectangle.js ├── misc │ ├── UIState.js │ ├── Transition.js │ ├── ApplicationCache.js │ └── CanvasPool.js ├── filter │ ├── Gray.js │ ├── KeepSource.js │ ├── FilterTexture.js │ ├── UniformHelp.js │ ├── AlphaMask.js │ ├── Highlight.js │ ├── BlendTexture.js │ ├── BlurX.js │ ├── BlurY.js │ ├── GraphicsTexture.js │ └── Glow.js ├── loader │ ├── PhaserLoader.js │ ├── Texture.js │ ├── TextAsset.js │ ├── SoundAsset.js │ ├── Prefab.js │ ├── ActionAsset.js │ ├── ActionManagerAsset.js │ ├── Font.js │ ├── ExcelHashSheetIndex.js │ ├── ExcelAsset.js │ ├── Atlas.js │ └── ExcelSheet.js ├── serializer │ └── types │ │ ├── COLOR.js │ │ ├── NODE.js │ │ ├── PREFAB.js │ │ ├── Action.js │ │ ├── ActionManager.js │ │ ├── EXCEL.js │ │ ├── AUDIO.js │ │ ├── TextAsset.js │ │ ├── FONT.js │ │ ├── TEXTURE.js │ │ └── GEOM.js ├── action │ ├── AnimationKeyProp.js │ ├── ColorLinearProp.js │ ├── TextureKeyProp.js │ └── LinearProp.js ├── license.js ├── plugin │ └── CleanPIXISpriteRetainer.js ├── gameobjects │ ├── UIRoot.js │ ├── ObjectLayer.js │ └── Toggle.js └── core.js ├── tasks ├── clean.js └── uglify.js ├── Gruntfile.js ├── package.json ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | qc-core-debug.js 4 | qc-core.js 5 | nohup.out 6 | -------------------------------------------------------------------------------- /src/version.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by wudm on 9/10/15. 3 | */ 4 | 5 | this.qc = this.qc || {}; 6 | -------------------------------------------------------------------------------- /tasks/clean.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.config('clean', { 3 | build: ['build'] 4 | }); 5 | }; -------------------------------------------------------------------------------- /src/Outro.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | }).call(this, this, Object); 7 | -------------------------------------------------------------------------------- /src/builtinresource/__builtin_resource__.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiciengine/qiciengine-core/HEAD/src/builtinresource/__builtin_resource__.png -------------------------------------------------------------------------------- /src/Intro.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | (function(window, Object, undefined) { 7 | "use strict"; -------------------------------------------------------------------------------- /src/builtinresource/__builtin_resource__@atlas/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiciengine/qiciengine-core/HEAD/src/builtinresource/__builtin_resource__@atlas/ok.png -------------------------------------------------------------------------------- /src/builtinresource/__builtin_resource__@atlas/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiciengine/qiciengine-core/HEAD/src/builtinresource/__builtin_resource__@atlas/arrow.png -------------------------------------------------------------------------------- /src/builtinresource/__builtin_resource__@atlas/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiciengine/qiciengine-core/HEAD/src/builtinresource/__builtin_resource__@atlas/button.png -------------------------------------------------------------------------------- /src/builtinresource/__builtin_resource__@atlas/button2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiciengine/qiciengine-core/HEAD/src/builtinresource/__builtin_resource__@atlas/button2.png -------------------------------------------------------------------------------- /src/builtinresource/__builtin_resource__@atlas/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiciengine/qiciengine-core/HEAD/src/builtinresource/__builtin_resource__@atlas/circle.png -------------------------------------------------------------------------------- /src/builtinresource/__builtin_resource__@atlas/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiciengine/qiciengine-core/HEAD/src/builtinresource/__builtin_resource__@atlas/empty.png -------------------------------------------------------------------------------- /src/builtinresource/__builtin_resource__@atlas/slider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiciengine/qiciengine-core/HEAD/src/builtinresource/__builtin_resource__@atlas/slider.png -------------------------------------------------------------------------------- /src/builtinresource/__builtin_resource__.png.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": 1, 3 | "uuid": "__builtin_resource__", 4 | "padding":{ 5 | "button.png":[10,10,10,10] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/builtinresource/__builtin_resource__@atlas/sliderbg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiciengine/qiciengine-core/HEAD/src/builtinresource/__builtin_resource__@atlas/sliderbg.png -------------------------------------------------------------------------------- /src/builtinresource/__builtin_resource__@atlas/sliderbg2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiciengine/qiciengine-core/HEAD/src/builtinresource/__builtin_resource__@atlas/sliderbg2.png -------------------------------------------------------------------------------- /tasks/uglify.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.config('uglify.core', { 3 | src: 'build/qc-core-debug.js', 4 | dest: 'build/qc-core.js' 5 | }); 6 | }; -------------------------------------------------------------------------------- /src/core/Signal.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | // 直接使用吧 7 | qc.Signal = Phaser.Signal; 8 | qc.SignalBinding = Phaser.SignalBinding; 9 | -------------------------------------------------------------------------------- /src/time/TimerEvent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author luohj 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 定时器对象 8 | * 9 | * @class qc.TimerEvent 10 | */ 11 | qc.TimerEvent = Phaser.TimerEvent; 12 | -------------------------------------------------------------------------------- /src/hack/pixi/WebGLMaskManager.js: -------------------------------------------------------------------------------- 1 | // @hackpp PIXI.WebGLMaskManager 中 popMask和pushMask不匹配的问题 2 | PIXI.WebGLMaskManager.prototype.popMask = function(maskData, renderSession) 3 | { 4 | var gl = this.gl; 5 | if(!maskData._webGL[gl.id].data.length)return; 6 | renderSession.stencilManager.popStencil(maskData, maskData._webGL[gl.id].data[0], renderSession); 7 | }; -------------------------------------------------------------------------------- /src/core/Plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 自定义插件的基类模板 8 | * 9 | * @class qc.Plugin 10 | * @param {qc.Game} game 11 | * @param {any} owner - 谁来管理这个插件?通常为:qc.PluginManager 12 | * @constructor 13 | */ 14 | var Plugin = qc.Plugin = Phaser.Plugin; 15 | 16 | // 看起来没有需要额外定制的,直接使用(减少PluginManager的封装工作) 17 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | 3 | grunt.loadNpmTasks('grunt-contrib-clean'); 4 | grunt.loadNpmTasks('grunt-contrib-concat'); 5 | grunt.loadNpmTasks('grunt-contrib-uglify'); 6 | 7 | grunt.loadTasks('tasks'); 8 | 9 | grunt.registerTask('default', ['clean', 'concat']); 10 | grunt.registerTask('min', ['default', 'uglify']); 11 | }; 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/components/NonexistScript.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 脚本不存在时的替代品 8 | * @class qc.NonexistScript 9 | */ 10 | var NonexistScript = defineBehaviour('qc.NonexistScript', qc.Behaviour, function() { 11 | // 丢失的脚本类名 12 | this.script = ''; 13 | 14 | // 脚本数据 15 | this.data = {}; 16 | },{ 17 | }); 18 | NonexistScript.__hiddenInMenu = true; 19 | -------------------------------------------------------------------------------- /src/hack/sound/Cache.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author linyw 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | Phaser.Cache.prototype.getSound = function (key) { 7 | if (this._sounds[key]) 8 | { 9 | return this._sounds[key]; 10 | } 11 | else 12 | { 13 | // 关闭警告,qc.Sound构造函数未初始化key,导致audio tag下出警告提示 14 | //console.warn('Phaser.Cache.getSound: Invalid key: "' + key + '"'); 15 | return null; 16 | } 17 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "core", 3 | "version": "1.0.0", 4 | "description": "QICI Engine Core", 5 | "devDependencies": { 6 | "grunt": "^0.4.5", 7 | "grunt-contrib-clean": "^0.6.0", 8 | "grunt-contrib-concat": "^0.5.1", 9 | "grunt-contrib-uglify": "^0.8.1" 10 | }, 11 | "dependencies": { 12 | }, 13 | "scripts": { 14 | "install-grunt-cli": "npm install -g grunt-cli", 15 | "install-dev": "npm install --only=dev", 16 | "build": "grunt default" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/geom/Matrix.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | qc.Matrix = Phaser.Matrix; 6 | 7 | /** 8 | * 类名 9 | */ 10 | Object.defineProperty(qc.Matrix.prototype, 'class', { 11 | get : function() { return 'qc.Matrix'; } 12 | }); 13 | 14 | /** 15 | * 序列化 16 | */ 17 | qc.Matrix.prototype.toJson = function() { 18 | return this.toArray(); 19 | } 20 | 21 | /** 22 | * 反序列化 23 | */ 24 | qc.Matrix.prototype.fromJson = function(v) { 25 | this.fromArray(v); 26 | } 27 | -------------------------------------------------------------------------------- /src/geom/Point.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | qc.Point = Phaser.Point; 6 | 7 | /** 8 | * 类名 9 | */ 10 | Object.defineProperty(qc.Point.prototype, 'class', { 11 | get : function() { return 'qc.Point'; } 12 | }); 13 | 14 | /** 15 | * 序列化 16 | */ 17 | qc.Point.prototype.toJson = function() { 18 | return [this.x, this.y]; 19 | } 20 | 21 | /** 22 | * 反序列化 23 | */ 24 | qc.Point.prototype.fromJson = function(v) { 25 | this.x = v[0]; 26 | this.y = v[1]; 27 | } 28 | -------------------------------------------------------------------------------- /src/misc/UIState.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 组件的3种状态: 8 | * 普通、按下、不可交互 9 | * 10 | * @class qc.UIState 11 | */ 12 | qc.UIState = { 13 | /** 14 | * @property {number} NORMAL - 正常状态 15 | * @static 16 | */ 17 | NORMAL : 0, 18 | 19 | /** 20 | * @property {number} PRESSED - 按下状态 21 | * @static 22 | */ 23 | PRESSED : 1, 24 | 25 | /** 26 | * @property {number} DISABLED - 不可用 27 | * @static 28 | */ 29 | DISABLED : 2 30 | }; 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A free JavaScript game engine library for making HTML5 games. 2 | ======= 3 | 4 | ### How to build 5 | 6 | Here we use [npm-run-script](https://docs.npmjs.com/cli/run-script) to install dependent packages and build. 7 | ```sh 8 | npm run install-grunt-cli 9 | npm run install-dev 10 | npm run build 11 | ``` 12 | 13 | The commands above are defined in [package.json](package.json) 14 | ```js 15 | "scripts": { 16 | "install-grunt-cli": "npm install -g grunt-cli", 17 | "install-dev": "npm install --only=dev", 18 | "build": "grunt default" 19 | } 20 | ``` -------------------------------------------------------------------------------- /src/geom/Polygon.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | qc.Polygon = Phaser.Polygon; 6 | 7 | /** 8 | * 类名 9 | */ 10 | Object.defineProperty(qc.Polygon.prototype, 'class', { 11 | get : function() { return 'qc.Polygon'; } 12 | }); 13 | 14 | /** 15 | * 序列化 16 | */ 17 | qc.Polygon.prototype.toJson = function() { 18 | return [this.toNumberArray(), this.closed]; 19 | } 20 | 21 | /** 22 | * 反序列化 23 | */ 24 | qc.Polygon.prototype.fromJson = function(v) { 25 | this.setTo(v[0]); 26 | this.closed = v[1]; 27 | } 28 | -------------------------------------------------------------------------------- /src/hack/pixi/CanvasMaskManager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @hackpp 在安卓uc浏览器下,在mask中绘制大小大概大于70*70时,会影响下一个超过128*128大小的图形绘制 3 | */ 4 | PIXI.CanvasMaskManager.prototype.popMask = function(renderSession) 5 | { 6 | renderSession.context.restore(); 7 | if (qc.__IS_ANDROID_UC) { 8 | var tempCanvas = qc._tempCanvas; 9 | if (!tempCanvas) { 10 | tempCanvas = qc._tempCanvas = document.createElement('canvas'); 11 | tempCanvas.width = 128; 12 | tempCanvas.height = 128; 13 | } 14 | renderSession.context.drawImage(tempCanvas, 0, 0, 2, 2, -5, -5, 1, 1); 15 | } 16 | 17 | }; -------------------------------------------------------------------------------- /src/hack/pixi/CanvasTinter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author linyw 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * Phaser2.3的实现未考虑sprite.tintedTexture已有的对象进行复用, 8 | * Phaser2.4考虑了老对象并对创建Canvas进行了池化:sprite.tintedTexture || PIXI.CanvasPool.create(this); 9 | * 我们先复用老的sprite.tintedTexture,后续可再考虑池化 10 | */ 11 | PIXI.CanvasTinter.getTintedTexture = function(sprite, color) 12 | { 13 | var canvas = sprite.tintedTexture || document.createElement("canvas"); 14 | 15 | PIXI.CanvasTinter.tintMethod(sprite.texture, color, canvas); 16 | 17 | return canvas; 18 | }; -------------------------------------------------------------------------------- /src/geom/Circle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | qc.Circle = Phaser.Circle; 6 | 7 | /** 8 | * 类名 9 | */ 10 | Object.defineProperty(qc.Circle.prototype, 'class', { 11 | get : function() { return 'qc.Circle'; } 12 | }); 13 | 14 | /** 15 | * 序列化 16 | */ 17 | qc.Circle.prototype.toJson = function() { 18 | return [this.x, this.y, this.diameter]; 19 | } 20 | 21 | /** 22 | * 反序列化 23 | */ 24 | qc.Circle.prototype.fromJson = function(v) { 25 | this.x = v[0]; 26 | this.y = v[1]; 27 | this.diameter = v[2]; 28 | } 29 | -------------------------------------------------------------------------------- /src/geom/Rectangle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | qc.Rectangle = Phaser.Rectangle; 6 | 7 | /** 8 | * 类名 9 | */ 10 | Object.defineProperty(qc.Rectangle.prototype, 'class', { 11 | get : function() { return 'qc.Rectangle'; } 12 | }); 13 | 14 | /** 15 | * 序列化 16 | */ 17 | qc.Rectangle.prototype.toJson = function() { 18 | return [this.x, this.y, this.width, this.height]; 19 | } 20 | 21 | /** 22 | * 反序列化 23 | */ 24 | qc.Rectangle.prototype.fromJson = function(v) { 25 | this.setTo(v[0], v[1], v[2], v[3]); 26 | } 27 | -------------------------------------------------------------------------------- /src/geom/Line.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | qc.Line = Phaser.Line; 6 | 7 | /** 8 | * 类名 9 | */ 10 | Object.defineProperty(qc.Line.prototype, 'class', { 11 | get : function() { return 'qc.Line'; } 12 | }); 13 | 14 | /** 15 | * 序列化 16 | */ 17 | qc.Line.prototype.toJson = function() { 18 | return [this.start.x, this.start.y, this.end.x, this.end.y]; 19 | } 20 | 21 | /** 22 | * 反序列化 23 | */ 24 | qc.Line.prototype.fromJson = function(v) { 25 | this.start.setTo(v[0], v[1]); 26 | this.end.setTo(v[2], v[3]); 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/geom/Ellipse.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | qc.Ellipse = Phaser.Ellipse; 6 | 7 | /** 8 | * 类名 9 | */ 10 | Object.defineProperty(qc.Ellipse.prototype, 'class', { 11 | get : function() { return 'qc.Ellipse'; } 12 | }); 13 | 14 | /** 15 | * 序列化 16 | */ 17 | qc.Ellipse.prototype.toJson = function() { 18 | return [this.x, this.y, this.width, this.height]; 19 | } 20 | 21 | /** 22 | * 反序列化 23 | */ 24 | qc.Ellipse.prototype.fromJson = function(v) { 25 | this.x = v[0]; 26 | this.y = v[1]; 27 | this.width = v[2]; 28 | this.height = v[3]; 29 | } 30 | -------------------------------------------------------------------------------- /src/misc/Transition.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 组件的交互变换模式 8 | * 不切换、颜色混合、图片变换、自定义动作 9 | * @class qc.Transition 10 | */ 11 | qc.Transition = { 12 | /** 13 | * @property {number} NONE - 不需要有任何变换 14 | * @static 15 | */ 16 | NONE : 0, 17 | 18 | /** 19 | * @property {number} COLOR_TINT - 变换颜色 20 | * @static 21 | */ 22 | COLOR_TINT : 1, 23 | 24 | /** 25 | * @property {number} TEXTURE_SWAP - 使用图片变换 26 | * @static 27 | */ 28 | TEXTURE_SWAP : 2, 29 | 30 | /** 31 | * @property {number} ANIMATION - 使用自定义动画 32 | * @static 33 | */ 34 | ANIMATION : 3 35 | }; 36 | -------------------------------------------------------------------------------- /src/geom/RoundedRectangle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | qc.RoundedRectangle = Phaser.RoundedRectangle; 6 | 7 | /** 8 | * 类名 9 | */ 10 | Object.defineProperty(qc.RoundedRectangle.prototype, 'class', { 11 | get : function() { return 'qc.RoundedRectangle'; } 12 | }); 13 | 14 | /** 15 | * 序列化 16 | */ 17 | qc.RoundedRectangle.prototype.toJson = function() { 18 | return [this.x, this.y, this.width, this.height, this.radius]; 19 | } 20 | 21 | /** 22 | * 反序列化 23 | */ 24 | qc.RoundedRectangle.prototype.fromJson = function(v) { 25 | this.x = v[0]; 26 | this.y = v[1]; 27 | this.width = v[2]; 28 | this.height = v[3]; 29 | this.radius = v[4]; 30 | } 31 | -------------------------------------------------------------------------------- /src/hack/core/Game.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * hackpp 8 | * 游戏的主循环,改由qici发起 9 | */ 10 | Phaser.Game.prototype.update = function(time) { 11 | var t1 = Date.now(); 12 | this._qc.update(time); 13 | this._qc.debug.total += Date.now() - t1; 14 | }; 15 | 16 | // hack住设置渲染模式的代码,加入白名单功能 17 | var phaser_setUpRenderer = Phaser.Game.prototype.setUpRenderer; 18 | Phaser.Game.prototype.setUpRenderer = function() { 19 | if (this.device.webGL && !this.device.desktop && !this.device.iOS) { 20 | if (qc.isSupportWebGL && !qc.isSupportWebGL(this._qc)) { 21 | this.device.webGL = false; 22 | } 23 | } 24 | phaser_setUpRenderer.call(this); 25 | }; -------------------------------------------------------------------------------- /src/filter/Gray.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenqx 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 灰度化 8 | */ 9 | var Gray = defineFilter('qc.Filter.Gray', qc.Filter, function(game) { 10 | this.fragmentSrc = [ 11 | 12 | "precision mediump float;", 13 | "varying vec2 vTextureCoord;", 14 | "varying vec4 vColor;", 15 | "uniform sampler2D uSampler;", 16 | 17 | "void main(void) {", 18 | ' vec4 original = texture2D(uSampler, vTextureCoord);', 19 | ' float gray = original.r * 0.3 + original.g * 0.59 + original.b * 0.11;', 20 | ' gl_FragColor = original;', 21 | ' gl_FragColor.r = gray;', 22 | ' gl_FragColor.g = gray;', 23 | ' gl_FragColor.b = gray;', 24 | "}" 25 | ]; 26 | 27 | }, { 28 | 29 | }); -------------------------------------------------------------------------------- /src/loader/PhaserLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author wudm 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | 7 | // TODO: hack Phaser.Loader 中 fileComplete 结束回调后,上下文变化导致无法找到 game.cache 而报错 8 | /** 9 | * Called when a file/resources had been downloaded and needs to be processed further. 10 | * 11 | * @method Phaser.Loader#fileComplete 12 | * @private 13 | * @param {object} file - File loaded 14 | * @param {?XMLHttpRequest} xhr - XHR request, unspecified if loaded via other means (eg. tags) 15 | */ 16 | var phaserFileComplete = Phaser.Loader.prototype.fileComplete; 17 | Phaser.Loader.prototype.fileComplete = function (file, xhr) { 18 | // hack start 19 | // 上下文已经发生变化,不需要后续的行为 20 | if (!this.game.cache) return; 21 | // hack end 22 | 23 | // 返回原有函数进行继续处理 24 | phaserFileComplete.call(this, file, xhr); 25 | }; -------------------------------------------------------------------------------- /src/serializer/types/COLOR.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by luohj on 15/6/2. 3 | */ 4 | 5 | /** 6 | * Color元素序列化 7 | */ 8 | Serializer.prototype.saveColor = function(ob, json, context, key, value) { 9 | json[key] = this._saveColorItem(value); 10 | } 11 | 12 | /** 13 | * Color元素反序列化 14 | */ 15 | Serializer.prototype.restoreColor = function(ob, json, key, value) { 16 | ob[key] = this._restoreColorItem(value); 17 | } 18 | 19 | /** 20 | * 序列化qc.Color数组的一个元素 21 | * @private 22 | */ 23 | Serializer.prototype._saveColorItem = function(value) { 24 | if (!(value instanceof Color)) return null; 25 | return [Serializer.COLOR, value.toNumber(true)]; 26 | } 27 | 28 | /** 29 | * 反序列化Color数组的一个元素 30 | * @private 31 | */ 32 | Serializer.prototype._restoreColorItem = function(value) { 33 | if (!value) return null; 34 | 35 | return new Color(value[1]); 36 | } -------------------------------------------------------------------------------- /src/action/AnimationKeyProp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenx 3 | * @date 2016.4.9 4 | * copyright 2015 Qcplay All Rights Reserved. 5 | * 6 | * animation 类型的 action 属性处理类 7 | */ 8 | 9 | var AnimationKeyProp = qc.AnimationKeyProp = function(action, path, propertyId) { 10 | 11 | var self = this; 12 | qc.KeyProp.call(self, action, path, propertyId); 13 | }; 14 | AnimationKeyProp.prototype = Object.create(qc.KeyProp.prototype); 15 | AnimationKeyProp.prototype.constructor = AnimationKeyProp; 16 | 17 | // 更新目标对象属性值 18 | AnimationKeyProp.prototype.updateAttrib = function(target, attrib, value, attribArray) { 19 | var action = this.action; 20 | var speed = action.speed; 21 | while (action.parent) 22 | { 23 | speed *= action.parent.speed; 24 | action = action.parent; 25 | } 26 | 27 | target.playAnimation(value, speed); 28 | } 29 | -------------------------------------------------------------------------------- /src/filter/KeepSource.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenqx 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 为 shader处理 保持原图效果 8 | */ 9 | var KeepSource = defineFilter('qc.Filter.KeepSource', qc.Filter, function(game) { 10 | this.fragmentSrc = [ 11 | 12 | "precision mediump float;", 13 | "varying vec2 vTextureCoord;", 14 | "varying vec4 vColor;", 15 | 'varying vec2 vMaskCoord;', 16 | 'varying vec4 vMaskLimit;', 17 | 18 | "uniform sampler2D uSampler;", 19 | "uniform sampler2D uSourceSampler;", 20 | 21 | "void main(void) {", 22 | ' vec4 original = texture2D(uSampler, vTextureCoord);', 23 | ' vec4 add = texture2D(uSourceSampler, vTextureCoord);', 24 | ' gl_FragColor = add.a * add + (1.0 - add.a) * original;', 25 | "}" 26 | 27 | ]; 28 | 29 | }, { 30 | 31 | }); -------------------------------------------------------------------------------- /src/loader/Texture.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * Describe a texture 8 | * 9 | * @class qc.Atlas 10 | * @constructor 11 | */ 12 | var Texture = qc.Texture = function(atlas, frame) { 13 | var self = this; 14 | self.atlas = atlas; 15 | self.frame = frame || 0; 16 | }; 17 | Texture.prototype.constructor = Texture; 18 | 19 | Object.defineProperties(Texture.prototype, { 20 | /** 21 | * @property {Array} padding - The Nine-Patch: [left, top, right, bottom] 22 | * @readonly 23 | */ 24 | padding: { 25 | get: function() { 26 | return this.atlas.getPadding(this.frame); 27 | } 28 | }, 29 | 30 | /** 31 | * @property {string} class - The class name 32 | * @internal 33 | */ 34 | class: { 35 | get : function() { return 'qc.Texture'; } 36 | } 37 | }); 38 | -------------------------------------------------------------------------------- /src/serializer/types/NODE.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 节点元素序列化 8 | */ 9 | Serializer.prototype.saveNode = function(ob, json, context, key, value) { 10 | json[key] = this._saveNodeItem(value, context); 11 | } 12 | 13 | /** 14 | * 节点元素反序列化 15 | */ 16 | Serializer.prototype.restoreNode = function(ob, json, key, value) { 17 | // 场景内其他节点,先只记录其标识符 18 | ob['__BUILTIN_NODE__' + key] = value[1]; 19 | } 20 | 21 | /** 22 | * 反序列化多个节点 23 | */ 24 | Serializer.prototype.restoreNodes = function(ob, json, key, value) { 25 | // 场景内其他节点,先只记录其标识符 26 | ob['__BUILTIN_NODE_ARRAY__' + key] = value[1]; 27 | } 28 | 29 | /** 30 | * 序列化数组的一个元素 31 | * @private 32 | */ 33 | Serializer.prototype._saveNodeItem = function(value, context) { 34 | if (!(value instanceof qc.Node)) return null; 35 | 36 | return [Serializer.NODE, value.uuid]; 37 | } 38 | -------------------------------------------------------------------------------- /src/misc/ApplicationCache.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenx 3 | * @date 2015.12.13 4 | * copyright 2015 Qcplay All Rights Reserved. 5 | */ 6 | 7 | /** 8 | * applicatioin cache 事件处理 9 | */ 10 | 11 | var appCache = window.applicationCache; 12 | if (!!appCache) 13 | { 14 | var logEvent = function(e) { 15 | //console.log('applicationCache', e); 16 | } 17 | 18 | var logError = function(e) { 19 | //console.log("applicationCache error " + e); 20 | }; 21 | 22 | appCache.addEventListener('cached', logEvent, false); 23 | appCache.addEventListener('checking', logEvent, false); 24 | appCache.addEventListener('downloading', logEvent, false); 25 | appCache.addEventListener('error', logError, false); 26 | appCache.addEventListener('noupdate', logEvent, false); 27 | appCache.addEventListener('obsolete', logEvent, false); 28 | appCache.addEventListener('progress', logEvent, false); 29 | appCache.addEventListener('updateready', logEvent, false); 30 | } 31 | -------------------------------------------------------------------------------- /src/serializer/types/PREFAB.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 预制元素序列化 8 | */ 9 | Serializer.prototype.savePrefab = function(ob, json, context, key, value) { 10 | json[key] = this._savePrefabItem(value, context); 11 | } 12 | 13 | /** 14 | * 预制元素反序列化 15 | */ 16 | Serializer.prototype.restorePrefab = function(ob, json, key, value) { 17 | ob[key] = this._restorePrefabItem(value); 18 | } 19 | 20 | /** 21 | * 序列化数组的一个元素 22 | * @private 23 | */ 24 | Serializer.prototype._savePrefabItem = function(value, context) { 25 | if (!(value instanceof Prefab)) return null; 26 | 27 | // 记录资源依赖 28 | context.dependences.push({ 29 | key : value.uuid, 30 | uuid : value.uuid 31 | }); 32 | return [Serializer.PREFAB, value.uuid]; 33 | } 34 | 35 | /** 36 | * 反序列化数组的一个元素 37 | * @private 38 | */ 39 | Serializer.prototype._restorePrefabItem = function(value) { 40 | if (!value) return null; 41 | 42 | var ob = this.game.assets.findByUUID(value[1]); 43 | return ob instanceof Prefab ? ob : null; 44 | } 45 | -------------------------------------------------------------------------------- /src/license.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 3 | * associated documentation files (the “Software”), to deal in the Software without restriction, 4 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 5 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 6 | * subject to the following conditions: 7 | * 8 | * The above copyright notice and this permission notice shall be included in all copies or 9 | * substantial portions of the Software. 10 | * 11 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 12 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 13 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 14 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 15 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 | */ -------------------------------------------------------------------------------- /src/hack/core/StateManager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenx 3 | * @date 2015.11.9 4 | * copyright 2015 Qcplay All Rights Reserved. 5 | */ 6 | 7 | /** 8 | * @hackpp 替换掉场景加载完毕的判定,需要等待资源解析完毕以后才能认为加载成功了 9 | */ 10 | Phaser.StateManager.prototype.loadComplete = function () { 11 | var self = this; 12 | if (self._created === true) return; 13 | var game = self.game._qc; 14 | 15 | if (game.assets.parsing || game.state.pendLoadComplete) { 16 | game.timer.add(15, function() { 17 | self.loadComplete(); 18 | }); 19 | return; 20 | } 21 | 22 | if (self._created === false && self.onCreateCallback) 23 | { 24 | self._created = true; 25 | self.onCreateCallback.call(self.callbackContext, self.game); 26 | } 27 | else 28 | { 29 | self._created = true; 30 | } 31 | }; 32 | 33 | var oldClearCurrentState = Phaser.StateManager.prototype.clearCurrentState; 34 | Phaser.StateManager.prototype.clearCurrentState = function() { 35 | oldClearCurrentState.call(this); 36 | this.game.world.displayChanged(qc.DisplayChangeStatus.SIZE); 37 | }; 38 | -------------------------------------------------------------------------------- /src/hack/system/Device.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author linyw 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | 7 | var oldDeviceInitialize = Phaser.Device._initialize; 8 | 9 | Phaser.Device._initialize = function () { 10 | oldDeviceInitialize.call(this); 11 | 12 | var ua = window.navigator.userAgent; 13 | 14 | // 判断是否为UCBrowser浏览器 15 | this.UCBrowser = /UCBrowser/.test(ua); 16 | 17 | // 判断iOS版本号 18 | if (this.iOS) 19 | { 20 | (navigator.appVersion).match(/OS (\d+)/); 21 | this.iOSVersion = parseInt(RegExp.$1, 10); 22 | } 23 | 24 | // 获取AppleWebkit类型和版本号 25 | var appleWebKit = /AppleWebKit\/([0-9\.]+)/; 26 | var result = appleWebKit.exec(navigator.userAgent); 27 | if (result && result.length > 0) { 28 | this.AppleWebKit = true; 29 | this.AppleWebKitVersion = result[1].split('.'); 30 | } 31 | else { 32 | this.AppleWebKit = false; 33 | } 34 | 35 | this.supportStencil = !this.AppleWebKit || this.AppleWebKitVersion[0] > 534; 36 | 37 | if (this.android && this.UCBrowser) { 38 | qc.__IS_ANDROID_UC = true; 39 | } 40 | }; -------------------------------------------------------------------------------- /src/serializer/types/Action.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenx 3 | * @date 2015.12.29 4 | * copyright 2015 Qcplay All Rights Reserved. 5 | */ 6 | 7 | /** 8 | * action 序列化 9 | */ 10 | Serializer.prototype.saveAction = function(ob, json, context, key, value) { 11 | json[key] = this._saveActionItem(value, context); 12 | } 13 | 14 | /** 15 | * action 反序列化 16 | */ 17 | Serializer.prototype.restoreAction = function(ob, json, key, value) { 18 | ob[key] = this._restoreActionItem(value); 19 | } 20 | 21 | /** 22 | * 序列化数组的一个元素 23 | * @private 24 | */ 25 | Serializer.prototype._saveActionItem = function(value, context) { 26 | if (!(value instanceof qc.ActionAsset)) return null; 27 | 28 | // 记录资源依赖 29 | context.dependences.push({ 30 | key : value.key, 31 | uuid : value.uuid 32 | }); 33 | return [Serializer.ACTION, value.uuid]; 34 | } 35 | 36 | /** 37 | * 反序列化数组的一个元素 38 | * @private 39 | */ 40 | Serializer.prototype._restoreActionItem = function(value) { 41 | if (!value) return null; 42 | 43 | var ob = this.game.assets.findByUUID(value[1]); 44 | return ob instanceof qc.ActionAsset ? ob : null; 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 QICI Engine 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/action/ColorLinearProp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenx 3 | * @date 2015.1.2 4 | * copyright 2015 Qcplay All Rights Reserved. 5 | * 6 | * color 线性渐变类型的 action 属性处理类 7 | */ 8 | 9 | var ColorLinearProp = qc.ColorLinearProp = function(action, path, propertyId) { 10 | 11 | var self = this; 12 | qc.LinearProp.call(self, action, path, propertyId); 13 | }; 14 | ColorLinearProp.prototype = Object.create(qc.LinearProp.prototype); 15 | ColorLinearProp.prototype.constructor = ColorLinearProp; 16 | 17 | // 计算两点间的线性插值的 color 18 | ColorLinearProp.prototype.calcValue = function(from, to, factor) { 19 | if (!from || !to) 20 | return qc.Color.white; 21 | 22 | var _from = from.rgb, _to = to.rgb; 23 | var currColor = [ 24 | Phaser.Math.clamp(Math.round(_from[0] + factor * (_to[0] - _from[0])), 0, 255), 25 | Phaser.Math.clamp(Math.round(_from[1] + factor * (_to[1] - _from[1])), 0, 255), 26 | Phaser.Math.clamp(Math.round(_from[2] + factor * (_to[2] - _from[2])), 0, 255), 27 | Phaser.Math.clamp(from.alpha + factor * (to.alpha - from.alpha), 0, 1) 28 | ]; 29 | var color = new Color(currColor); 30 | 31 | return color; 32 | } 33 | -------------------------------------------------------------------------------- /src/plugin/CleanPIXISpriteRetainer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author wudm 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 负责处理PIXI renderer 中 spriteBatch 对 sprite 的失效引用 8 | * 该引用会导致内存泄漏 9 | * @param game 10 | * @param parent 11 | * @constructor 12 | * @internal 13 | */ 14 | 15 | qc.CleanPIXISpriteRetainer = function(game, parent) { 16 | this._frameCount = 0; 17 | this.game = game; 18 | } 19 | qc.CleanPIXISpriteRetainer.prototype = { 20 | postRender : function() { 21 | this._frameCount++; 22 | if (this._frameCount < 100) 23 | // 100 帧再统一处理一次 24 | return; 25 | 26 | this._frameCount = 0; 27 | var renderer = this.game.phaser.renderer; 28 | if (!(renderer instanceof PIXI.WebGLRenderer)) 29 | // 非 WebGL 模式不处理 30 | return; 31 | 32 | // 执行具体的消除引用行为 33 | var sprites = renderer.spriteBatch.sprites; 34 | var batchSize = renderer.spriteBatch.currentBatchSize; 35 | var maxLen = sprites.length; 36 | for (var i = batchSize; i < maxLen; i++) { 37 | sprites[i] = null; 38 | } 39 | } 40 | }; 41 | qc.CleanPIXISpriteRetainer.prototype.constructor = qc.CleanPIXISpriteRetainer; 42 | -------------------------------------------------------------------------------- /src/serializer/types/ActionManager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenx 3 | * @date 2015.12.29 4 | * copyright 2015 Qcplay All Rights Reserved. 5 | */ 6 | 7 | /** 8 | * action manager 序列化 9 | */ 10 | Serializer.prototype.saveActionManager = function(ob, json, context, key, value) { 11 | json[key] = this._saveActionManagerItem(value, context); 12 | } 13 | 14 | /** 15 | * action manager 反序列化 16 | */ 17 | Serializer.prototype.restoreActionManager = function(ob, json, key, value) { 18 | ob[key] = this._restoreActionManagerItem(value); 19 | } 20 | 21 | /** 22 | * 序列化数组的一个元素 23 | * @private 24 | */ 25 | Serializer.prototype._saveActionManagerItem = function(value, context) { 26 | if (!(value instanceof qc.ActionManagerAsset)) return null; 27 | 28 | // 记录资源依赖 29 | context.dependences.push({ 30 | key : value.key, 31 | uuid : value.uuid 32 | }); 33 | return [Serializer.ACTIONMANAGER, value.uuid]; 34 | } 35 | 36 | /** 37 | * 反序列化数组的一个元素 38 | * @private 39 | */ 40 | Serializer.prototype._restoreActionManagerItem = function(value) { 41 | if (!value) return null; 42 | 43 | var ob = this.game.assets.findByUUID(value[1]); 44 | return ob instanceof qc.ActionManagerAsset ? ob : null; 45 | } 46 | -------------------------------------------------------------------------------- /src/loader/TextAsset.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 文本资源的描述 8 | * 9 | * @class qc.TextAsset 10 | * @constructor 11 | * @internal 12 | */ 13 | var TextAsset = qc.TextAsset = function(key, url, data, meta) { 14 | /** 15 | * @property {string} key - 图集的标志 16 | * @readonly 17 | */ 18 | this.key = url; 19 | 20 | /** 21 | * @property {string} url - 资源的网址 22 | * @readonly 23 | */ 24 | this.url = url; 25 | 26 | /** 27 | * @property {object} meta - meta数据 28 | * @readonly 29 | */ 30 | this.meta = meta; 31 | 32 | /** 33 | * @property {string} text - 文本信息 34 | * @readonly 35 | */ 36 | this.text = data; 37 | } 38 | TextAsset.prototype.constructor = TextAsset; 39 | 40 | Object.defineProperties(TextAsset.prototype, { 41 | /** 42 | * @property {string} uuid - 资源唯一标识符 43 | * @readonly 44 | */ 45 | uuid : { 46 | get : function() { return this.meta.uuid; } 47 | } 48 | }); 49 | 50 | /** 51 | * 释放文本资源 52 | * @param game 53 | * @internal 54 | */ 55 | TextAsset.prototype.unload = function(game) { 56 | game.assets._cache.removeText(this.key); 57 | }; 58 | 59 | -------------------------------------------------------------------------------- /src/builtinresource/__builtin_resource__.json: -------------------------------------------------------------------------------- 1 | {"frames": { 2 | 3 | "button.png": 4 | { 5 | "frame": {"x":2,"y":2,"w":32,"h":32}, 6 | "rotated": false, 7 | "trimmed": false, 8 | "spriteSourceSize": {"x":0,"y":0,"w":32,"h":32}, 9 | "sourceSize": {"w":32,"h":32} 10 | }, 11 | "circle.png": 12 | { 13 | "frame": {"x":36,"y":2,"w":30,"h":30}, 14 | "rotated": false, 15 | "trimmed": false, 16 | "spriteSourceSize": {"x":0,"y":0,"w":30,"h":30}, 17 | "sourceSize": {"w":30,"h":30} 18 | }, 19 | "empty.png": 20 | { 21 | "frame": {"x":68,"y":2,"w":16,"h":16}, 22 | "rotated": false, 23 | "trimmed": false, 24 | "spriteSourceSize": {"x":0,"y":0,"w":16,"h":16}, 25 | "sourceSize": {"w":16,"h":16} 26 | }, 27 | "on.png": 28 | { 29 | "frame": {"x":86,"y":2,"w":32,"h":32}, 30 | "rotated": false, 31 | "trimmed": false, 32 | "spriteSourceSize": {"x":0,"y":0,"w":32,"h":32}, 33 | "sourceSize": {"w":32,"h":32} 34 | }}, 35 | "meta": { 36 | "app": "http://www.codeandweb.com/texturepacker", 37 | "version": "1.0", 38 | "image": "__builtin_resource__.png", 39 | "format": "RGBA8888", 40 | "size": {"w":120,"h":36}, 41 | "scale": "1", 42 | "smartupdate": "$TexturePacker:SmartUpdate:5a6dad042624373f19cc4824f7ab3e55:38c8b508791708994c405cc65b26ea10:0fc6de014878564ccb36199b61187e38$" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/serializer/types/EXCEL.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenqx 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * Excel资源序列化 8 | */ 9 | Serializer.prototype.saveExcelAsset = function(ob, json, context, key, value) { 10 | json[key] = this._saveExcelAssetItem(value, context); 11 | }; 12 | 13 | /** 14 | * Excel元素反序列化 15 | */ 16 | Serializer.prototype.restoreExcelAsset = function(ob, json, key, value) { 17 | ob[key] = this._restoreExcelAssetItem(value); 18 | }; 19 | 20 | /** 21 | * 序列化数组的一个Excel资源 22 | * @private 23 | */ 24 | Serializer.prototype._saveExcelAssetItem = function(value, context) { 25 | if (!(value instanceof qc.ExcelAsset)) return null; 26 | 27 | // 记录资源依赖 28 | context.dependences.push({ 29 | key : value.key, 30 | uuid : value.uuid 31 | }); 32 | 33 | return [Serializer.EXCELASSET, value.key, value.uuid]; 34 | }; 35 | 36 | /** 37 | * 反序列化数组的一个Excel资源 38 | * @private 39 | */ 40 | Serializer.prototype._restoreExcelAssetItem = function(value) { 41 | if (!value) return null; 42 | 43 | var asset = this.game.assets.find(value[1]); 44 | if (!asset) 45 | asset = this.game.assets.findByUUID(value[2]); 46 | if (!asset) { 47 | return null; 48 | } 49 | 50 | return asset instanceof qc.ExcelAsset ? asset : null; 51 | }; 52 | -------------------------------------------------------------------------------- /src/serializer/types/AUDIO.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 音效元素序列化 8 | */ 9 | Serializer.prototype.saveAudio = function(ob, json, context, key, value) { 10 | json[key] = this._saveAudioItem(value, context); 11 | } 12 | 13 | /** 14 | * 音效元素反序列化 15 | */ 16 | Serializer.prototype.restoreAudio = function(ob, json, key, value) { 17 | ob[key] = this._restoreAudioItem(value); 18 | } 19 | 20 | /** 21 | * 序列化数组的一个元素 22 | * @private 23 | */ 24 | Serializer.prototype._saveAudioItem = function(value, context) { 25 | if (!(value instanceof qc.SoundAsset)) return null; 26 | 27 | // 记录资源依赖 28 | context.dependences.push({ 29 | key : value.key, 30 | uuid : value.uuid 31 | }); 32 | 33 | return [Serializer.AUDIO, value.key, value.uuid]; 34 | } 35 | 36 | /** 37 | * 反序列化数组的一个元素 38 | * @private 39 | */ 40 | Serializer.prototype._restoreAudioItem = function(value) { 41 | if (!value) return null; 42 | 43 | var asset = this.game.assets.find(value[1]); 44 | if (!asset) 45 | asset = this.game.assets.findByUUID(value[2]); 46 | if (!asset) { 47 | console.error('音频资源尚未载入, 无法反序列化.', value[1]); 48 | return null; 49 | } 50 | 51 | return asset instanceof qc.SoundAsset ? asset : null; 52 | } 53 | -------------------------------------------------------------------------------- /src/filter/FilterTexture.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenqx 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | /** 6 | * 着色器使用的贴图 7 | */ 8 | var FilterTexture = qc.Filter.FilterTexture = function(game) { 9 | this._image = new qc.UIImage(game, null, false); 10 | this._image.parent.removeChild(this._image); 11 | }; 12 | 13 | FilterTexture.prototype = {}; 14 | FilterTexture.prototype.constructor = FilterTexture; 15 | 16 | Object.defineProperties(FilterTexture.prototype, { 17 | /** 18 | * @property {qc.Atlas} texture - 获取or设置当前的图片 19 | */ 20 | texture : { 21 | get : function() { 22 | return this._image.texture; 23 | }, 24 | set : function(v) { 25 | this._image.texture = v; 26 | } 27 | }, 28 | 29 | /** 30 | * @property {int|string} frame - 获取or设置当前的图片帧,一般是图集才会用到该属性(可以为数字或别名) 31 | */ 32 | frame : { 33 | get: function () { 34 | return this._image.frame; 35 | }, 36 | 37 | set: function (value) { 38 | this._image.frame = value; 39 | } 40 | }, 41 | 42 | /** 43 | * @property {PIXI.Texture} filterTexture - 用于着色器使用的贴图 44 | */ 45 | filterTexture : { 46 | get : function() { 47 | return this._image.phaser.texture; 48 | } 49 | } 50 | }); -------------------------------------------------------------------------------- /src/loader/SoundAsset.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 声音资源的描述 8 | * 9 | * @class qc.SoundAsset 10 | * @constructor 11 | * @internal 12 | */ 13 | var SoundAsset = qc.SoundAsset = function(key, url, sound, meta) { 14 | /** 15 | * @property {string} key - 直接使用网址作为唯一标识 16 | * @readonly 17 | */ 18 | this.key = url; 19 | 20 | /** 21 | * @property {string} url - 资源的网址 22 | * @readonly 23 | */ 24 | this.url = url; 25 | 26 | /** 27 | * @property {object} meta - meta数据 28 | * @readonly 29 | */ 30 | this.meta = meta; 31 | 32 | /** 33 | * @property {object} sound - 声音信息 34 | * @readonly 35 | */ 36 | this.sound = sound; 37 | }; 38 | SoundAsset.prototype.constructor = SoundAsset; 39 | 40 | Object.defineProperties(SoundAsset.prototype, { 41 | /** 42 | * @property {string} uuid - 资源唯一标识符 43 | * @readonly 44 | */ 45 | uuid : { 46 | get : function() { return this.meta.uuid; } 47 | } 48 | }); 49 | 50 | /** 51 | * 释放声音资源 52 | * @param game 53 | * @internal 54 | */ 55 | SoundAsset.prototype.unload = function(game) { 56 | if (window.__wx) { 57 | // 微信需要销毁音频实例 58 | this.sound.destroy(); 59 | } 60 | game.assets._cache.removeSound(this.key); 61 | }; 62 | -------------------------------------------------------------------------------- /src/serializer/types/TextAsset.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author linyw 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 文本资源序列化 8 | */ 9 | Serializer.prototype.saveTextAsset = function(ob, json, context, key, value) { 10 | json[key] = this._saveTextAssetItem(value, context); 11 | }; 12 | 13 | /** 14 | * 文本元素反序列化 15 | */ 16 | Serializer.prototype.restoreTextAsset = function(ob, json, key, value) { 17 | ob[key] = this._restoreTextAssetItem(value); 18 | }; 19 | 20 | /** 21 | * 序列化数组的一个文本资源 22 | * @private 23 | */ 24 | Serializer.prototype._saveTextAssetItem = function(value, context) { 25 | if (!(value instanceof qc.TextAsset)) return null; 26 | 27 | // 记录资源依赖 28 | context.dependences.push({ 29 | key : value.key, 30 | uuid : value.uuid 31 | }); 32 | 33 | return [Serializer.TEXTASSET, value.key, value.uuid]; 34 | }; 35 | 36 | /** 37 | * 反序列化数组的一个文本资源 38 | * @private 39 | */ 40 | Serializer.prototype._restoreTextAssetItem = function(value) { 41 | if (!value) return null; 42 | 43 | var asset = this.game.assets.find(value[1]); 44 | if (!asset) 45 | asset = this.game.assets.findByUUID(value[2]); 46 | if (!asset) { 47 | console.error('文本资源尚未载入, 无法反序列化.', value[1]); 48 | return null; 49 | } 50 | 51 | return asset instanceof qc.TextAsset ? asset : null; 52 | }; 53 | -------------------------------------------------------------------------------- /src/filter/UniformHelp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenqx 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 同步数据的辅助类 8 | * @param type {string} - Filter Uniform Type 9 | * @param value {*|func} - 需要同步的值或者函数 10 | */ 11 | var UniformHelp = qc.Filter.UniformHelp = function(type, value) { 12 | /** 13 | * @property {string} _type - 同步类型 14 | * @private 15 | */ 16 | this._type = type; 17 | /** 18 | * @property {*} _value - 同步的值 19 | * @private 20 | */ 21 | this._value = value; 22 | /** 23 | * @property {boolean} _valueIsFunc - 值是否为函数 24 | * @private 25 | */ 26 | this._valueIsFunc = (typeof this._value === 'function'); 27 | }; 28 | UniformHelp.prototype = {}; 29 | UniformHelp.prototype.constructor = UniformHelp; 30 | 31 | Object.defineProperties(UniformHelp.prototype, { 32 | /** 33 | * @property {string} type - 同步的类型 34 | * @readonly 35 | */ 36 | type : { 37 | get : function() { return this._type; } 38 | }, 39 | /** 40 | * @property {*} value - 同步的值 41 | * @readonly 42 | */ 43 | value : { 44 | get : function() { 45 | if (this._valueIsFunc) { 46 | return this._value(); 47 | } 48 | else { 49 | return this._value; 50 | } 51 | } 52 | } 53 | }); 54 | 55 | -------------------------------------------------------------------------------- /src/hack/pixi/renderers/webgl/WebGLRenderer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Renders the stage to its webGL view 3 | * 4 | * @method render 5 | * @param stage {Stage} the Stage element to be rendered 6 | */ 7 | PIXI.WebGLRenderer.prototype.render = function(stage) 8 | { 9 | // no point rendering if our context has been blown up! 10 | if (this.contextLost) return; 11 | 12 | // if rendering a new stage clear the batches.. 13 | if (this.__stage !== stage) 14 | { 15 | // TODO make this work 16 | // dont think this is needed any more? 17 | this.__stage = stage; 18 | } 19 | 20 | // 干掉这行 21 | // update the scene graph 22 | //stage.updateTransform(); 23 | 24 | var gl = this.gl; 25 | 26 | // -- Does this need to be set every frame? -- // 27 | gl.viewport(0, 0, this.width, this.height); 28 | 29 | // make sure we are bound to the main frame buffer 30 | gl.bindFramebuffer(gl.FRAMEBUFFER, null); 31 | 32 | if (this.clearBeforeRender) 33 | { 34 | if (this.transparent) 35 | { 36 | gl.clearColor(0, 0, 0, 0); 37 | } 38 | else 39 | { 40 | gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], 1); 41 | } 42 | 43 | gl.clear (gl.COLOR_BUFFER_BIT); 44 | } 45 | 46 | this.renderDisplayObject( stage, this.projection ); 47 | }; -------------------------------------------------------------------------------- /src/serializer/types/FONT.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author luohj 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 字体元素序列化 8 | */ 9 | Serializer.prototype.saveFont = function(ob, json, context, key, value) { 10 | json[key] = this._saveFontItem(value, context); 11 | } 12 | 13 | /** 14 | * 字体元素反序列化 15 | */ 16 | Serializer.prototype.restoreFont = function(ob, json, key, value) { 17 | ob[key] = this._restoreFontItem(value); 18 | } 19 | 20 | /** 21 | * 序列化数组的一个元素 22 | * @private 23 | */ 24 | Serializer.prototype._saveFontItem = function(value, context) { 25 | if (value instanceof qc.Font) { 26 | var font = value; 27 | } 28 | 29 | if (font && font instanceof qc.Font) { 30 | // 记录资源依赖 31 | context.dependences.push({ 32 | key : font.key, 33 | uuid : font.uuid 34 | }); 35 | var uuid = font.uuid; 36 | value = font.key; 37 | } 38 | return [Serializer.FONT, value, uuid]; 39 | } 40 | 41 | /** 42 | * 反序列化数组的一个元素 43 | * @private 44 | */ 45 | Serializer.prototype._restoreFontItem = function(value, self) { 46 | if (!value) return null; 47 | 48 | self = self || this; 49 | var asset = self.game.assets.find(value[1]); 50 | if (!asset) 51 | asset = self.game.assets.findByUUID(value[2]); 52 | if (!asset) { 53 | asset = value[1]; 54 | } 55 | 56 | return asset; 57 | } -------------------------------------------------------------------------------- /src/serializer/types/TEXTURE.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 图集元素序列化 8 | */ 9 | Serializer.prototype.saveTexture = function(ob, json, context, key, value) { 10 | json[key] = this._saveTextureItem(value, context); 11 | } 12 | 13 | /** 14 | * 图集元素反序列化 15 | */ 16 | Serializer.prototype.restoreTexture = function(ob, json, key, value) { 17 | ob[key] = this._restoreTextureItem(value); 18 | } 19 | 20 | /** 21 | * 序列化数组的一个元素 22 | * @private 23 | */ 24 | Serializer.prototype._saveTextureItem = function(value, context) { 25 | if (!(value instanceof qc.Texture)) return null; 26 | 27 | // 记录资源依赖 28 | var atlas = value.atlas; 29 | context.dependences.push({ 30 | key : atlas.key, 31 | uuid : atlas.uuid 32 | }); 33 | return [Serializer.TEXTURE, atlas.key, atlas.uuid, value.frame]; 34 | } 35 | 36 | /** 37 | * 反序列化数组的一个元素 38 | * @private 39 | */ 40 | Serializer.prototype._restoreTextureItem = function(value) { 41 | if (!value) return null; 42 | 43 | var atlas = this.game.assets.find(value[1]); 44 | if (!atlas) 45 | atlas = this.game.assets.findByUUID(value[2]); 46 | if (!atlas) { 47 | console.error('贴图资源尚未载入,无法反序列化。', value[1]); 48 | return null; 49 | } 50 | if (!(atlas instanceof qc.Atlas)) return null; 51 | 52 | return new qc.Texture(atlas, value[3]); 53 | } 54 | -------------------------------------------------------------------------------- /src/action/TextureKeyProp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenx 3 | * @date 2015.1.28 4 | * copyright 2015 Qcplay All Rights Reserved. 5 | * 6 | * texture 类型的 action 属性处理类 7 | */ 8 | 9 | var TextureKeyProp = qc.TextureKeyProp = function(action, path, propertyId) { 10 | 11 | var self = this; 12 | qc.KeyProp.call(self, action, path, propertyId); 13 | }; 14 | TextureKeyProp.prototype = Object.create(qc.KeyProp.prototype); 15 | TextureKeyProp.prototype.constructor = TextureKeyProp; 16 | 17 | // 更新目标对象属性值 18 | TextureKeyProp.prototype.updateAttrib = function(target, attrib, value, attribArray) { 19 | if (!value) 20 | { 21 | var texture = this.action.game.assets.find('__builtin_resource__'); 22 | var frame = texture ? texture.frameNames[0] : 0; 23 | value = [texture, frame]; 24 | } 25 | var texture = value[0], frame = value[1]; 26 | var targetValue = texture ? new qc.Texture(texture, frame) : null; 27 | if (!attribArray) 28 | target[attrib] = targetValue; 29 | else 30 | { 31 | var len = attribArray.length; 32 | if (len === 2 && target[attribArray[0]]) 33 | target[attribArray[0]][attribArray[1]] = targetValue; 34 | else if (len > 2) 35 | { 36 | var o = target; 37 | for (var i = 0; i < len - 1; i++) 38 | { 39 | o = o[attribArray[i]]; 40 | if (!o) 41 | break; 42 | } 43 | if (o) 44 | o[attribArray[len - 1]] = targetValue; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/hack/loader/loader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author wudm 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * hack phaser transformUrl 方法,如果 url 已经是 http 开头就不需要再加上 baseURL 8 | * Transforms the asset URL. The default implementation prepends the baseURL. 9 | * 10 | * @method Phaser.Loader#transformUrl 11 | * @protected 12 | */ 13 | Phaser.Loader.prototype.transformUrl = function (url) { 14 | if (/^http(s|):\/\//i.test(url)) 15 | return url; 16 | else 17 | return this.baseURL + url; 18 | }; 19 | 20 | /** 21 | * Informs the loader that the given file resource has been fetched and processed; 22 | * or such a request has failed. 23 | * 24 | * @method Phaser.Loader#asyncComplete 25 | * @private 26 | * @param {object} file 27 | * @param {string} [error=''] - The error message, if any. No message implies no error. 28 | */ 29 | Phaser.Loader.prototype.asyncComplete = function (file, errorMessage) { 30 | 31 | if (typeof errorMessage === 'undefined') { errorMessage = ''; } 32 | 33 | file.loaded = true; 34 | file.error = !!errorMessage; 35 | 36 | // 增加返回错误码的判断 37 | if (!window.__wx && 38 | file.requestObject && 39 | file.requestObject.status !== 200 && 40 | file.requestObject.status !== 304) { 41 | file.error = true; 42 | } 43 | 44 | if (errorMessage) { 45 | file.errorMessage = errorMessage; 46 | 47 | console.warn('Phaser.Loader - ' + file.type + '[' + file.key + ']' + ': ' + errorMessage); 48 | // debugger; 49 | } 50 | 51 | this.processLoadQueue(); 52 | 53 | }; 54 | -------------------------------------------------------------------------------- /src/filter/AlphaMask.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by qcplay on 7/9/15. 3 | */ 4 | var BlendTexture = defineFilter('qc.Filter.AlphaMask', qc.Filter, function(game) { 5 | this.otherTexture = null; 6 | this.vertexSrc = [ 7 | 'attribute vec2 aVertexPosition;', 8 | 'attribute vec2 aTextureCoord;', 9 | 'attribute vec2 aOtherTextureCoord;', 10 | 'attribute vec4 aColor;', 11 | 12 | 'uniform vec2 projectionVector;', 13 | 'uniform vec2 offsetVector;', 14 | 15 | 'varying vec2 vTextureCoord;', 16 | 'varying vec2 vOtherTextureCoord;', 17 | 'varying vec4 vColor;', 18 | 19 | 'const vec2 center = vec2(-1.0, 1.0);', 20 | 21 | 'void main(void) {', 22 | ' gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);', 23 | ' vTextureCoord = aTextureCoord;', 24 | ' vOtherTextureCoord = aOtherTextureCoord;', 25 | ' vColor = vec4(aColor.rgb * aColor.a, aColor.a);', 26 | '}' 27 | ]; 28 | this.fragmentSrc = [ 29 | 30 | 'precision mediump float;', 31 | 'varying vec2 vTextureCoord;', 32 | 'varying vec2 vOtherTextureCoord;', 33 | 'varying vec4 vColor;', 34 | 35 | 'uniform sampler2D uSampler;', 36 | 'uniform sampler2D otherTexture;', 37 | 38 | 'void main(void) {', 39 | ' vec4 original = texture2D(uSampler, vTextureCoord);', 40 | ' vec4 add = texture2D(otherTexture, vOtherTextureCoord);', 41 | ' gl_FragColor = add.a * original;', 42 | '}' 43 | 44 | ]; 45 | },{ 46 | otherTexture : qc.Filter.SAMPLER2D 47 | }); -------------------------------------------------------------------------------- /src/filter/Highlight.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenqx 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 灰度化 8 | */ 9 | var Highlight = defineFilter('qc.Filter.Highlight', qc.Filter, function(game) { 10 | this.vertexSrc = [ 11 | 'attribute vec2 aVertexPosition;', 12 | 'attribute vec2 aTextureCoord;', 13 | 'attribute vec4 aColor;', 14 | 15 | 'uniform vec2 projectionVector;', 16 | 'uniform vec2 offsetVector;', 17 | "uniform float light;", 18 | "uniform vec3 lightColor;", 19 | 20 | 'varying vec2 vTextureCoord;', 21 | 'varying vec4 vColor;', 22 | 'varying vec4 vLight;', 23 | 24 | 'const vec2 center = vec2(-1.0, 1.0);', 25 | 26 | 'void main(void) {', 27 | ' gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);', 28 | ' vTextureCoord = aTextureCoord;', 29 | ' vColor = vec4(aColor.rgb * aColor.a, aColor.a);', 30 | ' vLight = light * vec4(lightColor, 0.0);', 31 | '}' 32 | ]; 33 | this.fragmentSrc = [ 34 | "precision mediump float;", 35 | "varying vec2 vTextureCoord;", 36 | "varying vec4 vColor;", 37 | 'varying vec4 vLight;', 38 | 39 | "uniform sampler2D uSampler;", 40 | 41 | 42 | "void main(void) {", 43 | ' vec4 original = texture2D(uSampler, vTextureCoord);', 44 | ' gl_FragColor = original + original.a * vLight;', 45 | "}" 46 | ]; 47 | this.light = 0.5; 48 | this.lightColor = [1, 1, 1]; 49 | 50 | // 指定 lightColor 属性的自定义显示类型 51 | this.registerCustomInspector('lightColor', qc.Color); 52 | }, { 53 | light : qc.Filter.F1, 54 | lightColor : qc.Filter.F3V 55 | }); -------------------------------------------------------------------------------- /src/filter/BlendTexture.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by qcplay on 7/9/15. 3 | */ 4 | var BlendTexture = defineFilter('qc.Filter.BlendTexture', qc.Filter, function(game) { 5 | this.mixing = 0.5; 6 | this.otherTexture = null; 7 | this.vertexSrc = [ 8 | 'attribute vec2 aVertexPosition;', 9 | 'attribute vec2 aTextureCoord;', 10 | 'attribute vec2 aOtherTextureCoord;', 11 | 'attribute vec4 aColor;', 12 | 13 | 'uniform vec2 projectionVector;', 14 | 'uniform vec2 offsetVector;', 15 | 16 | 'varying vec2 vTextureCoord;', 17 | 'varying vec2 vOtherTextureCoord;', 18 | 'varying vec4 vColor;', 19 | 20 | 'const vec2 center = vec2(-1.0, 1.0);', 21 | 22 | 'void main(void) {', 23 | ' gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);', 24 | ' vTextureCoord = aTextureCoord;', 25 | ' vOtherTextureCoord = aOtherTextureCoord;', 26 | ' vColor = vec4(aColor.rgb * aColor.a, aColor.a);', 27 | '}' 28 | ]; 29 | this.fragmentSrc = [ 30 | 31 | 'precision mediump float;', 32 | 'varying vec2 vTextureCoord;', 33 | 'varying vec2 vOtherTextureCoord;', 34 | 'varying vec4 vColor;', 35 | 36 | 'uniform sampler2D uSampler;', 37 | 'uniform sampler2D otherTexture;', 38 | 'uniform float mixing;', 39 | 40 | 'void main(void) {', 41 | ' vec4 original = texture2D(uSampler, vTextureCoord);', 42 | ' vec4 add = texture2D(otherTexture, vOtherTextureCoord);', 43 | ' gl_FragColor = mixing * add + (1.0 - mixing) * original;', 44 | '}' 45 | 46 | ]; 47 | },{ 48 | otherTexture : qc.Filter.SAMPLER2D, 49 | mixing : qc.Filter.F1 50 | }); -------------------------------------------------------------------------------- /src/hack/pixi/renderers/canvas/CanvasRenderer.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Renders the Stage to this canvas view 4 | * 5 | * @method render 6 | * @param stage {Stage} the Stage element to be rendered 7 | */ 8 | PIXI.CanvasRenderer.prototype.render = function(stage) 9 | { 10 | // remove this line 11 | // stage.updateTransform(); 12 | 13 | this.context.setTransform(1,0,0,1,0,0); 14 | 15 | this.context.globalAlpha = 1; 16 | 17 | this.renderSession.drawCount = 0; 18 | this.renderSession.currentBlendMode = PIXI.blendModes.NORMAL; 19 | this.context.globalCompositeOperation = PIXI.blendModesCanvas[PIXI.blendModes.NORMAL]; 20 | 21 | if (this.dirtyRectangle.enable) { 22 | if (!this.dirtyRectangle.updateDirtyRegion(this.context, this.resolution, stage)) 23 | { 24 | this.context.fillStyle = 'rgba(0, 0, 0, 0)'; 25 | this.context.fillRect(0, 0, 1, 1); 26 | this.dirtyRectangle.showDirtyRectangle(this.context, this.resolution); 27 | return; 28 | } 29 | } 30 | else if (navigator.isCocoonJS && this.view.screencanvas) 31 | { 32 | this.context.fillStyle = "black"; 33 | this.context.clear(); 34 | } 35 | 36 | if (this.clearBeforeRender) 37 | { 38 | if (this.transparent) 39 | { 40 | this.context.clearRect(0, 0, this.width, this.height); 41 | } 42 | else 43 | { 44 | this.context.fillStyle = stage.backgroundColorString; 45 | this.context.fillRect(0, 0, this.width , this.height); 46 | } 47 | } 48 | 49 | this.renderDisplayObject(stage); 50 | 51 | if (this.dirtyRectangle.enable) { 52 | this.dirtyRectangle.restore(this.context); 53 | this.dirtyRectangle.showDirtyRectangle(this.context, this.resolution); 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /src/serializer/types/GEOM.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 给定的元素是不是几何类型 8 | * @param v 9 | * @returns {boolean} 10 | */ 11 | Serializer.prototype.isGeom = function(v) { 12 | return v instanceof qc.Circle || 13 | v instanceof qc.Ellipse || 14 | v instanceof qc.Line || 15 | v instanceof qc.Matrix || 16 | v instanceof qc.Polygon || 17 | v instanceof qc.Rectangle || 18 | v instanceof qc.RoundedRectangle || 19 | v instanceof qc.Point; 20 | } 21 | 22 | /** 23 | * 几何元素序列化 24 | */ 25 | Serializer.prototype.saveGeom = function(ob, json, context, key, value) { 26 | json[key] = this._saveGeomItem(value, context); 27 | } 28 | 29 | /** 30 | * 几何元素反序列化 31 | */ 32 | Serializer.prototype.restoreGeom = function(ob, json, key, value) { 33 | ob[key] = this._restoreGeomItem(value); 34 | } 35 | 36 | /** 37 | * 序列化数组的一个元素 38 | * @private 39 | */ 40 | Serializer.prototype._saveGeomItem = function(value, context) { 41 | var type = Serializer.GEOM; 42 | if (value instanceof qc.Point) 43 | type = Serializer.POINT; 44 | else if (value instanceof qc.Rectangle) 45 | type = Serializer.RECTANGLE; 46 | else if (value instanceof qc.Circle) 47 | type = Serializer.CIRCLE; 48 | else if (value instanceof qc.Ellipse) 49 | type = Serializer.ELLIPSE; 50 | 51 | if (value) 52 | return [type, value.class, value.toJson()]; 53 | else 54 | return null; 55 | } 56 | 57 | /** 58 | * 反序列化数组的一个元素 59 | * @private 60 | */ 61 | Serializer.prototype._restoreGeomItem = function(value) { 62 | if (!value) return null; 63 | 64 | // 第二个元素指明是哪个类(类名) 65 | var func = qc.Util.findClass(value[1]); 66 | var geom = new func(); 67 | geom.fromJson(value[2]); 68 | return geom; 69 | } 70 | -------------------------------------------------------------------------------- /src/loader/Prefab.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 预制资源(包含场景)的描述 8 | * 9 | * @class qc.Prefab 10 | * @constructor 11 | * @internal 12 | */ 13 | var Prefab = qc.Prefab = function(key, url, data, meta) { 14 | /** 15 | * @property {string} key - 预制的标志 16 | * @readonly 17 | */ 18 | this.key = key; 19 | 20 | /** 21 | * @property {string} url - 资源的网址 22 | * @readonly 23 | */ 24 | this.url = url; 25 | 26 | /** 27 | * @property {object} meta - meta数据 28 | * @readonly 29 | */ 30 | this.meta = meta; 31 | 32 | /** 33 | * @property {object} json - 预制的数据 34 | * @internal 35 | */ 36 | this.json = data; 37 | }; 38 | Prefab.prototype.constructor = Prefab; 39 | 40 | Object.defineProperties(Prefab.prototype, { 41 | /** 42 | * @property {string} uuid - 资源唯一标识符 43 | * @readonly 44 | */ 45 | uuid : { 46 | get : function() { return this.meta.uuid; } 47 | }, 48 | 49 | /** 50 | * @property {object} dependences - 本资源依赖于其他哪些资源? 51 | */ 52 | dependences : { 53 | get : function() { 54 | return this.json.dependences; 55 | } 56 | } 57 | }); 58 | 59 | /** 60 | * 当前是不是还有依赖的资源没有加载成功? 61 | */ 62 | Prefab.prototype.hasUnloadedDependence = function(game) { 63 | for (var i in this.dependences) { 64 | var data = this.dependences[i]; 65 | if (data.ok) continue; 66 | if (data.uuid === this.uuid) continue; 67 | var asset = game.assets.find(data.uuid); 68 | if (!asset) 69 | // 还有资源没有加载进来 70 | return true; 71 | 72 | if (asset.hasUnloadedDependence && 73 | asset.hasUnloadedDependence(game)) 74 | return true; 75 | 76 | // 标记此资源已经加载了 77 | data.ok = true; 78 | } 79 | return false; 80 | }; 81 | -------------------------------------------------------------------------------- /src/core/PluginManager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 管理运行所有的自定义系统插件 8 | * 9 | * @class qc.PluginManager 10 | * @param {Phaser.PluginManager} phaser 11 | * @constructor 12 | * @internal 13 | */ 14 | var PluginManager = qc.PluginManager = function(phaser) { 15 | // 建立下关联 16 | phaser._qc = this; 17 | this.phaser = phaser; 18 | } 19 | PluginManager.prototype = {}; 20 | PluginManager.prototype.constructor = PluginManager; 21 | 22 | Object.defineProperties(PluginManager.prototype, { 23 | /** 24 | * @property {qc.Game} game 25 | * @readonly 26 | */ 27 | 'game' : { 28 | get : function() { return this.phaser.game._qc; } 29 | }, 30 | 31 | /** 32 | * @property {qc.Plugin[]} plugins - 所有的插件列表 33 | * @readonly 34 | */ 35 | 'plugins' : { 36 | get : function() { return this.phaser.plugins; } 37 | } 38 | }); 39 | 40 | /** 41 | * 添加一个插件 42 | * 43 | * @method qc.PluginManager#add 44 | * @param {object|qc.Plugin} plugin - 待添加的插件 45 | * @pram {...*} parameter - 额外参数,在调用插件的init时原样传入 46 | */ 47 | PluginManager.prototype.add = function(plugin) { 48 | var plugin = this.phaser.add.apply(this.phaser, arguments); 49 | plugin.game = this.game; 50 | return plugin; 51 | } 52 | 53 | /** 54 | * 移除一个插件 55 | * 56 | * @method qc.PluginManager#remove 57 | * @param {qc.Plugin} plugin - 待移除的插件 58 | */ 59 | PluginManager.prototype.remove = function(plugin) { 60 | this.phaser.remove(plugin); 61 | } 62 | 63 | /** 64 | * 移除所有的插件 65 | * 66 | * @method qc.PluginManager#removeAll 67 | */ 68 | PluginManager.prototype.removeAll = function() { 69 | this.phaser.removeAll(); 70 | } 71 | 72 | /** 73 | * 析构插件管理器 74 | * 75 | * @method qc.PluginManager#destroy 76 | */ 77 | PluginManager.prototype.destroy = function() { 78 | this.phaser.destroy(); 79 | delete this.phaser; 80 | } 81 | -------------------------------------------------------------------------------- /src/filter/BlurX.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A horizontal blur filter by Mat Groves http://matgroves.com/ @Doormat23 3 | */ 4 | var BlurX = defineFilter('qc.Filter.BlurX', qc.Filter, function(game) { 5 | this.fragmentSrc = [ 6 | 7 | "precision mediump float;", 8 | "varying vec2 vTextureCoord;", 9 | "varying vec4 vColor;", 10 | "uniform float blur;", 11 | "uniform sampler2D uSampler;", 12 | "uniform vec2 pixelSize;", 13 | 14 | "void main(void) {", 15 | 16 | "vec4 sum = vec4(0.0);", 17 | 18 | "sum += texture2D(uSampler, vec2(vTextureCoord.x - 4.0*blur*pixelSize.x, vTextureCoord.y)) * 0.05;", 19 | "sum += texture2D(uSampler, vec2(vTextureCoord.x - 3.0*blur*pixelSize.x, vTextureCoord.y)) * 0.09;", 20 | "sum += texture2D(uSampler, vec2(vTextureCoord.x - 2.0*blur*pixelSize.x, vTextureCoord.y)) * 0.12;", 21 | "sum += texture2D(uSampler, vec2(vTextureCoord.x - blur*pixelSize.x, vTextureCoord.y)) * 0.15;", 22 | "sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y)) * 0.16;", 23 | "sum += texture2D(uSampler, vec2(vTextureCoord.x + blur*pixelSize.x, vTextureCoord.y)) * 0.15;", 24 | "sum += texture2D(uSampler, vec2(vTextureCoord.x + 2.0*blur*pixelSize.x, vTextureCoord.y)) * 0.12;", 25 | "sum += texture2D(uSampler, vec2(vTextureCoord.x + 3.0*blur*pixelSize.x, vTextureCoord.y)) * 0.09;", 26 | "sum += texture2D(uSampler, vec2(vTextureCoord.x + 4.0*blur*pixelSize.x, vTextureCoord.y)) * 0.05;", 27 | "gl_FragColor = sum;", 28 | 29 | "}" 30 | ]; 31 | 32 | this.blur = 1; 33 | },{ 34 | blur : qc.Filter.F1 35 | }); 36 | 37 | Object.defineProperty(BlurX.prototype, 'blur', { 38 | 39 | get: function() { 40 | return this._blur; 41 | }, 42 | 43 | set: function(value) { 44 | this.dirty = true; 45 | this._blur = value; 46 | this.padding = Math.max(0, value); 47 | } 48 | 49 | }); 50 | -------------------------------------------------------------------------------- /src/gameobjects/UIRoot.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * UIRoot is always at the left-top of screen. 8 | * The component 'qc.ScaleAdapter' is attached by default, in order to scale with device resolution. 9 | * 10 | * @class qc.UIRoot 11 | * @extends qc.Node 12 | * @param {Phaser.Game} game - A reference to the currently running game. 13 | * @constructor 14 | * @internal 15 | */ 16 | var UIRoot = qc.UIRoot = function(game, uuid) { 17 | // Inherit from qc.Node 18 | qc.Node.call(this, new Phaser.Group(game.phaser, null), null, uuid); 19 | this.name = "UIRoot"; 20 | 21 | // Attach the component 'qc.ScaleAdapter' by default. 22 | var restore = uuid !== undefined; 23 | if (!restore) { 24 | var s = this.addScript('qc.ScaleAdapter'); 25 | s.referenceResolution = new qc.Point(640, 960); 26 | s.manualType = qc.ScaleAdapter.EXPAND; 27 | s.fullTarget = true; 28 | } 29 | 30 | // Set transform 31 | this.setAnchor(new qc.Point(0, 0), new qc.Point(0, 0)); 32 | this.pivotX = 0; 33 | this.pivotY = 0; 34 | var worldScale = this.getWorldScale(); 35 | this.setTransformToWorld(0, 0, worldScale.x, worldScale.y, 36 | this.getWorldRotation()); 37 | }; 38 | UIRoot.prototype = Object.create(qc.Node.prototype); 39 | UIRoot.prototype.constructor = UIRoot; 40 | 41 | Object.defineProperties(UIRoot.prototype, { 42 | /** 43 | * @property {string} class - The class name 44 | * @readonly 45 | * @internal 46 | */ 47 | class : { 48 | get : function() { return 'qc.UIRoot' } 49 | } 50 | }); 51 | 52 | /** 53 | * The core postUpdate - as called by World. 54 | * @method qc.UIRoot#postUpdate 55 | * @protected 56 | */ 57 | UIRoot.prototype.postUpdate = function() { 58 | // Because the world size = screen size & camera is fixed, so UIRoot is always at the origin 59 | this.x = 0; 60 | this.y = 0; 61 | }; 62 | -------------------------------------------------------------------------------- /src/filter/BlurY.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A vertical blur filter by Mat Groves http://matgroves.com/ @Doormat23 3 | */ 4 | var BlurY = defineFilter('qc.Filter.BlurY', qc.Filter, function(game) { 5 | this.fragmentSrc = [ 6 | 7 | "precision mediump float;", 8 | "varying vec2 vTextureCoord;", 9 | "varying vec4 vColor;", 10 | "uniform float blur;", 11 | "uniform sampler2D uSampler;", 12 | "uniform vec2 pixelSize;", 13 | 14 | "void main(void) {", 15 | 16 | "vec4 sum = vec4(0.0);", 17 | 18 | "sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - 4.0*blur*pixelSize.y)) * 0.05;", 19 | "sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - 3.0*blur*pixelSize.y)) * 0.09;", 20 | "sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - 2.0*blur*pixelSize.y)) * 0.12;", 21 | "sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - blur*pixelSize.y)) * 0.15;", 22 | "sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y)) * 0.16;", 23 | "sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + blur*pixelSize.y)) * 0.15;", 24 | "sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + 2.0*blur*pixelSize.y)) * 0.12;", 25 | "sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + 3.0*blur*pixelSize.y)) * 0.09;", 26 | "sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + 4.0*blur*pixelSize.y)) * 0.05;", 27 | 28 | "gl_FragColor = sum;", 29 | 30 | "}" 31 | 32 | ]; 33 | 34 | this.blur = 1; 35 | }, { 36 | blur : qc.Filter.F1 37 | }); 38 | 39 | Object.defineProperty(BlurY.prototype, 'blur', { 40 | 41 | get: function() { 42 | return this._blur; 43 | }, 44 | 45 | set: function(value) { 46 | this.dirty = true; 47 | this._blur = value; 48 | this.padding = Math.max(0, value); 49 | } 50 | 51 | }); 52 | -------------------------------------------------------------------------------- /src/loader/ActionAsset.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenx 3 | * @date 2015.12.23 4 | * copyright 2015 Qcplay All Rights Reserved. 5 | * 6 | */ 7 | 8 | /** 9 | * action资源的描述 10 | * 11 | * @class qc.ActionAsset 12 | * @constructor 13 | * @internal 14 | */ 15 | var ActionAsset = qc.ActionAsset = function(key, url, data, meta) { 16 | /** 17 | * @property {string} key - 资源的标志 18 | * @readonly 19 | */ 20 | this.key = url; 21 | 22 | /** 23 | * @property {string} url - 资源的网址 24 | * @readonly 25 | */ 26 | this.url = url; 27 | 28 | /** 29 | * @property {object} meta - meta数据 30 | * @readonly 31 | */ 32 | this.meta = meta; 33 | 34 | /** 35 | * @property {object} json - 资源的数据 36 | * @internal 37 | */ 38 | this.json = data; 39 | }; 40 | ActionAsset.prototype.constructor = ActionAsset; 41 | 42 | Object.defineProperties(ActionAsset.prototype, { 43 | /** 44 | * @property {string} uuid - 资源唯一标识符 45 | * @readonly 46 | */ 47 | uuid : { 48 | get : function() { return this.meta.uuid; } 49 | }, 50 | 51 | /** 52 | * @property {object} dependences - 本资源依赖于其他哪些资源? 53 | */ 54 | dependences : { 55 | get : function() { 56 | return this.json.dependences; 57 | } 58 | } 59 | }); 60 | 61 | /** 62 | * 当前是不是还有依赖的资源没有加载成功? 63 | */ 64 | ActionAsset.prototype.hasUnloadedDependence = function(game) { 65 | for (var i in this.dependences) { 66 | var data = this.dependences[i]; 67 | if (data.ok) continue; 68 | if (data.uuid === this.uuid) continue; 69 | var asset = game.assets.find(data.uuid); 70 | if (!asset) 71 | // 还有资源没有加载进来 72 | return true; 73 | 74 | if (asset.hasUnloadedDependence && 75 | asset.hasUnloadedDependence(game)) 76 | return true; 77 | 78 | // 标记此资源已经加载了 79 | data.ok = true; 80 | } 81 | return false; 82 | }; 83 | -------------------------------------------------------------------------------- /src/components/TweenTransform.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author lijh 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 位置动画组件,起始位置和目标位置由两个Node决定,无须指定绝对位置 8 | * @class qc.TweenTransform 9 | */ 10 | var TweenTransform = defineBehaviour('qc.TweenTransform', qc.Tween, function() { 11 | var self = this; 12 | 13 | // 默认情况下不可用 14 | self.enable = false; 15 | 16 | // 起始位置的本地坐标 17 | self.localFrom = new qc.Point(); 18 | 19 | // 目标位置的本地坐标 20 | self.localTo = new qc.Point(); 21 | },{ 22 | from : qc.Serializer.NODE, 23 | to : qc.Serializer.NODE 24 | }); 25 | 26 | // 菜单上的显示 27 | TweenTransform.__menu = 'Tween/TweenTransform'; 28 | 29 | Object.defineProperties(TweenTransform.prototype, { 30 | /** 31 | * @property {qc.Node} from - 起始位置 32 | */ 33 | from : { 34 | get : function() { 35 | return this._from; 36 | }, 37 | set : function(v) { 38 | this._from = v; 39 | 40 | if (v) { 41 | var worldFrom = this._from.getWorldPosition(); 42 | this.localFrom = this.gameObject.parent.toLocal(worldFrom); 43 | } 44 | } 45 | }, 46 | 47 | /** 48 | * @property {qc.Node} to - 终点位置 49 | */ 50 | to : { 51 | get : function() { 52 | return this._to; 53 | }, 54 | set : function(v) { 55 | this._to = v; 56 | 57 | if (v) { 58 | var worldTo = this._to.getWorldPosition(); 59 | this.localTo = this.gameObject.parent.toLocal(worldTo); 60 | } 61 | } 62 | } 63 | }); 64 | 65 | // 帧调度: 驱动位置 66 | TweenTransform.prototype.onUpdate = function(factor, isFinished) { 67 | if (!this._from || !this._to) 68 | return; 69 | 70 | var self = this; 71 | 72 | self.gameObject.x = self.localFrom.x + factor * (self.localTo.x - self.localFrom.x); 73 | self.gameObject.y = self.localFrom.y + factor * (self.localTo.y - self.localFrom.y); 74 | }; 75 | -------------------------------------------------------------------------------- /src/components/TweenAlpha.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 淡入淡出动画组件 8 | * @class qc.TweenAlpha 9 | */ 10 | var TweenAlpha = defineBehaviour('qc.TweenAlpha', qc.Tween, function() { 11 | var self = this; 12 | 13 | /** 14 | * @property {number} from - 起始的透明度 15 | */ 16 | self.from = 0; 17 | 18 | /** 19 | * @property {number} to - 最终的透明度 20 | */ 21 | self.to = 1; 22 | 23 | // 默认情况下不可用 24 | self.enable = false; 25 | },{ 26 | from : qc.Serializer.NUMBER, 27 | to : qc.Serializer.NUMBER 28 | }); 29 | 30 | // 菜单上的显示 31 | TweenAlpha.__menu = 'Tween/TweenAlpha'; 32 | 33 | // 帧调度: 驱动位置 34 | TweenAlpha.prototype.onUpdate = function(factor, isFinished) { 35 | var self = this; 36 | var _from = self.from, _to = self.to; 37 | self.gameObject.alpha = Phaser.Math.clamp(_from + factor * (_to - _from), 0, 1) 38 | }; 39 | 40 | /** 41 | * 将开始状态设成当前状态 42 | */ 43 | TweenAlpha.prototype.setStartToCurrValue = function() { 44 | this.gameObject.alpha = this.from; 45 | }; 46 | 47 | /** 48 | * 将结束状态设成当前状态 49 | */ 50 | TweenAlpha.prototype.setEndToCurrValue = function() { 51 | this.gameObject.alpha = this.to; 52 | }; 53 | 54 | /** 55 | * 将当前状态设为开始状态 56 | */ 57 | TweenAlpha.prototype.setCurrToStartValue = function() { 58 | this.from = this.gameObject.alpha; 59 | }; 60 | 61 | /** 62 | * 将当前状态设置为结束状态 63 | */ 64 | TweenAlpha.prototype.setCurrToEndValue = function() { 65 | this.to = this.gameObject.alpha; 66 | }; 67 | /** 68 | * 开始透明化 69 | * @param node {qc.Node} - 需要改变的节点 70 | * @param duration {number} - 经历的时间 71 | * @param alpha {number} - 最终透明度 72 | * @returns {qc.TweenAlpha} 73 | */ 74 | TweenAlpha.begin = function(node, duration, alpha) { 75 | var tween = qc.Tween.begin('qc.TweenAlpha', node, duration); 76 | tween.from = node.alpha; 77 | tween.to = alpha; 78 | if (duration <= 0) { 79 | tween.sample(1, true); 80 | tween.enable = false; 81 | } 82 | return tween; 83 | }; 84 | -------------------------------------------------------------------------------- /src/loader/ActionManagerAsset.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenx 3 | * @date 2015.12.23 4 | * copyright 2015 Qcplay All Rights Reserved. 5 | * 6 | */ 7 | 8 | /** 9 | * action manager资源的描述 10 | * 11 | * @class qc.ActionManagerAsset 12 | * @constructor 13 | * @internal 14 | */ 15 | var ActionManagerAsset = qc.ActionManagerAsset = function(key, url, data, meta) { 16 | /** 17 | * @property {string} key - 资源的标志 18 | * @readonly 19 | */ 20 | this.key = url; 21 | 22 | /** 23 | * @property {string} url - 资源的网址 24 | * @readonly 25 | */ 26 | this.url = url; 27 | 28 | /** 29 | * @property {object} meta - meta数据 30 | * @readonly 31 | */ 32 | this.meta = meta; 33 | 34 | /** 35 | * @property {object} json - 资源的数据 36 | * @internal 37 | */ 38 | this.json = data; 39 | }; 40 | ActionManagerAsset.prototype.constructor = ActionManagerAsset; 41 | 42 | Object.defineProperties(ActionManagerAsset.prototype, { 43 | /** 44 | * @property {string} uuid - 资源唯一标识符 45 | * @readonly 46 | */ 47 | uuid : { 48 | get : function() { return this.meta.uuid; } 49 | }, 50 | 51 | /** 52 | * @property {object} dependences - 本资源依赖于其他哪些资源? 53 | */ 54 | dependences : { 55 | get : function() { 56 | return this.json.dependences; 57 | } 58 | } 59 | }); 60 | 61 | /** 62 | * 当前是不是还有依赖的资源没有加载成功? 63 | */ 64 | ActionManagerAsset.prototype.hasUnloadedDependence = function(game) { 65 | for (var i in this.dependences) { 66 | var data = this.dependences[i]; 67 | if (data.ok) continue; 68 | if (data.uuid === this.uuid) continue; 69 | var asset = game.assets.find(data.uuid); 70 | if (!asset) 71 | // 还有资源没有加载进来 72 | return true; 73 | 74 | if (asset.hasUnloadedDependence && 75 | asset.hasUnloadedDependence(game)) 76 | return true; 77 | 78 | // 标记此资源已经加载了 79 | data.ok = true; 80 | } 81 | return false; 82 | }; 83 | -------------------------------------------------------------------------------- /src/loader/Font.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 字体的描述 8 | * 9 | * @class qc.Font 10 | * @constructor 11 | * @internal 12 | */ 13 | var Font = qc.Font = function(key, url, image, xml, meta) { 14 | /** 15 | * @property {string} key - 字体的标志 16 | * @readonly 17 | */ 18 | this.key = key; 19 | 20 | /** 21 | * @property {string} url - 资源的网址 22 | * @readonly 23 | */ 24 | this.url = url; 25 | 26 | /** 27 | * @property {object} meta - meta数据 28 | * @readonly 29 | */ 30 | this.meta = meta; 31 | 32 | /** 33 | * @property {object} xml - 字体的数据 34 | * @readonly 35 | */ 36 | this.xml = xml; 37 | 38 | /** 39 | * @property {image} image - 字体图片 40 | * @readonly 41 | */ 42 | this.image = image; 43 | 44 | /** 45 | * @property {array} _fontUrl - webFont的地址 46 | * @private 47 | */ 48 | this._fontUrl; 49 | 50 | /** 51 | * 字体类型 52 | * @private 53 | */ 54 | this._fontFamily = qc.UIText.SYSTEMFONT; 55 | }; 56 | 57 | Font.prototype.constructor = Font; 58 | 59 | Object.defineProperties(Font.prototype, { 60 | /** 61 | * @property {string} uuid - 资源唯一标识符 62 | * @readonly 63 | */ 64 | uuid : { 65 | get : function() { return this.meta.uuid; } 66 | }, 67 | 68 | /** 69 | * @property {number} xSpacing 70 | * @readonly 71 | */ 72 | xSpacing : { 73 | get : function() { 74 | return this.meta.xSpacing; 75 | } 76 | }, 77 | 78 | /** 79 | * @property {number} ySpacing 80 | * @readonly 81 | */ 82 | ySpacing : { 83 | get : function() { 84 | return this.meta.ySpacing; 85 | } 86 | } 87 | }); 88 | 89 | /** 90 | * 释放字体资源 91 | * @param game 92 | * @internal 93 | */ 94 | Font.prototype.unload = function(game) { 95 | game.assets._cache.removeBitmapData(this.key); 96 | game.assets._cache.removeBitmapFont(this.key); 97 | }; 98 | -------------------------------------------------------------------------------- /src/components/TweenRotation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 旋转动画组件 8 | * @class qc.TweenAlpha 9 | */ 10 | var TweenRotation = defineBehaviour('qc.TweenRotation', qc.Tween, function() { 11 | var self = this; 12 | 13 | /** 14 | * @property {number} from - 起始的弧度 15 | */ 16 | self.from = 0; 17 | 18 | /** 19 | * @property {number} to - 最终的弧度 20 | */ 21 | self.to = 1; 22 | 23 | // 默认情况下不可用 24 | self.enable = false; 25 | },{ 26 | from : qc.Serializer.NUMBER, 27 | to : qc.Serializer.NUMBER 28 | }); 29 | 30 | // 菜单上的显示 31 | TweenRotation.__menu = 'Tween/TweenRotation'; 32 | 33 | // 帧调度: 驱动动画 34 | TweenRotation.prototype.onUpdate = function(factor, isFinished) { 35 | var self = this; 36 | var _from = self.from, _to = self.to; 37 | self.gameObject.rotation = _from + factor * (_to - _from); 38 | }; 39 | 40 | /** 41 | * 将开始状态设成当前状态 42 | */ 43 | TweenRotation.prototype.setStartToCurrValue = function() { 44 | this.gameObject.rotation = this.from; 45 | }; 46 | 47 | /** 48 | * 将结束状态设成当前状态 49 | */ 50 | TweenRotation.prototype.setEndToCurrValue = function() { 51 | this.gameObject.rotation = this.to; 52 | }; 53 | 54 | /** 55 | * 将当前状态设为开始状态 56 | */ 57 | TweenRotation.prototype.setCurrToStartValue = function() { 58 | this.from = this.gameObject.rotation; 59 | }; 60 | 61 | /** 62 | * 将当前状态设置为结束状态 63 | */ 64 | TweenRotation.prototype.setCurrToEndValue = function() { 65 | this.to = this.gameObject.rotation; 66 | }; 67 | 68 | /** 69 | * 开始旋转 70 | * @param node {qc.Node} - 需要旋转的节点 71 | * @param duration {number} - 变色的时间 72 | * @param rotation {number} - 最终旋转角度 73 | * @returns {qc.TweenAlpha} 74 | */ 75 | TweenRotation.begin = function(node, duration, rotation) { 76 | var tween = qc.Tween.begin('qc.TweenRotation', node, duration); 77 | tween.from = node.rotation; 78 | tween.to = rotation; 79 | if (duration <= 0) { 80 | tween.sample(1, true); 81 | tween.enable = false; 82 | } 83 | return tween; 84 | }; -------------------------------------------------------------------------------- /src/hack/sound/Loader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author linyw 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 解决Android下AudioTag类型声音对象第一时间无法获取正确duration值问题 8 | */ 9 | Phaser.Loader.prototype.loadAudioTag = function (file) { 10 | 11 | var _this = this; 12 | 13 | if (this.game.sound.touchLocked) 14 | { 15 | // If audio is locked we can't do this yet, so need to queue this load request. Bum. 16 | file.data = new Audio(); 17 | file.data.name = file.key; 18 | file.data.preload = 'auto'; 19 | file.data.src = file.localPath || this.transformUrl(file.url, file); 20 | 21 | this.fileComplete(file); 22 | } 23 | else 24 | { 25 | file.data = new Audio(); 26 | file.data.name = file.key; 27 | 28 | var playThroughEvent = function () { 29 | file.data.removeEventListener('canplaythrough', playThroughEvent, false); 30 | file.data.removeEventListener('stalled', onStalled, false); 31 | file.data.onerror = null; 32 | // Why does this cycle through games? 33 | Phaser.GAMES[_this.game.id].load.fileComplete(file); 34 | }; 35 | file.data.onerror = function () { 36 | file.data.removeEventListener('canplaythrough', playThroughEvent, false); 37 | file.data.removeEventListener('stalled', onStalled, false); 38 | file.data.onerror = null; 39 | _this.fileError(file); 40 | }; 41 | var onStalled = function() { 42 | file.data.removeEventListener('canplaythrough', playThroughEvent, false); 43 | file.data.removeEventListener('stalled', onStalled, false); 44 | file.data.onerror = null; 45 | _this.fileError(file); 46 | }; 47 | 48 | file.data.preload = 'auto'; 49 | file.data.src = file.localPath || this.transformUrl(file.url, file); 50 | file.data.addEventListener('canplaythrough', playThroughEvent, false); 51 | file.data.addEventListener('stalled', onStalled, false); 52 | 53 | // 屏蔽load()调用,改行代码会导致Android下很多浏览器第一时间无法获取正确duration值 54 | //file.data.load(); 55 | } 56 | 57 | }; 58 | -------------------------------------------------------------------------------- /src/core/NodePool.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 游戏对象池管理 8 | * 9 | * @class qc.NodePool 10 | * @constructor 11 | * @internal 12 | */ 13 | var NodePool = qc.NodePool = function(game) { 14 | this._game = game; 15 | this._nodes = {}; 16 | this._nameUuidMap = {}; 17 | } 18 | NodePool.prototype = {}; 19 | NodePool.prototype.constructor = NodePool; 20 | 21 | Object.defineProperties(NodePool.prototype, { 22 | /** 23 | * @property {qc.Game} game - 游戏实例的引用 24 | * @readonly 25 | */ 26 | game : { 27 | get : function() { return this._game; } 28 | } 29 | }); 30 | 31 | /** 32 | * 添加一个对象 33 | * @method qc.NodePool#add 34 | */ 35 | NodePool.prototype.add = function(uuid, node) { 36 | if (this._nodes[uuid]) { 37 | this.game.log.error('uuid {0} already exists', uuid); 38 | } 39 | this._nodes[uuid] = node; 40 | if (node.uniqueName && !this._nameUuidMap[node.uniqueName]) 41 | this._nameUuidMap[node.uniqueName] = uuid; 42 | } 43 | 44 | /** 45 | * 移除一个对象 46 | * @method qc.NodePool@remove 47 | */ 48 | NodePool.prototype.remove = function(uuid) { 49 | if (this._nodes[uuid]) 50 | { 51 | if (this._nodes[uuid].uniqueName) 52 | delete this._nameUuidMap[this._nodes[uuid].uniqueName]; 53 | delete this._nodes[uuid]; 54 | } 55 | } 56 | 57 | /** 58 | * 查找对象 59 | * @method qc.NodePool#find 60 | */ 61 | NodePool.prototype.find = function(uuid) { 62 | if (this._nodes[uuid]) 63 | return this._nodes[uuid]; 64 | } 65 | 66 | /** 67 | * 根据唯一名字查找对象 68 | * @method qc.NodePool#findByName 69 | */ 70 | NodePool.prototype.findByName = function(uniqueName) { 71 | var uuid = this._nameUuidMap[uniqueName]; 72 | if (uuid) 73 | return this._nodes[uuid]; 74 | } 75 | 76 | /** 77 | * 移除 name 与 uuid 的映射 78 | * @method qc.NodePool#removeName 79 | */ 80 | NodePool.prototype.removeName = function(uniqueName) { 81 | delete this._nameUuidMap[uniqueName]; 82 | } 83 | 84 | /** 85 | * 增加 name 与 uuid 的映射 86 | * @method qc.NodePool#addName 87 | */ 88 | NodePool.prototype.addName = function(uniqueName, uuid) { 89 | this._nameUuidMap[uniqueName] = uuid; 90 | } 91 | -------------------------------------------------------------------------------- /src/filter/GraphicsTexture.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenqx 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | /** 6 | * 着色器使用的绘制贴图 7 | */ 8 | 9 | var GraphicsTexture = qc.Filter.GraphicsTexture = function(game, width, height, render, resolution) { 10 | var self = this; 11 | 12 | /** 13 | * 游戏对象 14 | * @type {qc.Game} 15 | */ 16 | self.game = game; 17 | 18 | /** 19 | * 使用的贴图 20 | * @type {qc.RenderTexture} 21 | */ 22 | self._texture = new qc.RenderTexture(width || 100, height || 100, render || self.game.phaser.render, null, resolution || self.game.resolution); 23 | 24 | /** 25 | * Graphics在Texture中呈现时的偏移 26 | * @type {qc.Point} 27 | */ 28 | self.offset = new qc.Point(0, 0); 29 | 30 | /** 31 | * 绘制对象 32 | * @type {PIXI.Graphics} 33 | */ 34 | self._graphics = self.game.phaser.add.graphics(0, 0); 35 | if (self._graphics.parent) { 36 | self._graphics.parent.remove(self._graphics); 37 | } 38 | }; 39 | 40 | GraphicsTexture.prototype = {}; 41 | GraphicsTexture.prototype.constructor = GraphicsTexture; 42 | 43 | Object.defineProperties(GraphicsTexture.prototype, { 44 | /** 45 | * @property {PIXI.Graphics} graphics - 用来绘制图元的绘制对象 46 | * @readonly 47 | */ 48 | graphics : { 49 | get : function() { 50 | return this._graphics; 51 | } 52 | }, 53 | 54 | /** 55 | * @property {PIXI.Texture} filterTexture - 用于着色器使用的贴图 56 | */ 57 | filterTexture : { 58 | get : function() { 59 | return this._texture; 60 | } 61 | } 62 | }); 63 | 64 | /** 65 | * 更新贴图 66 | */ 67 | GraphicsTexture.prototype.updateTexture = function() { 68 | var self = this, 69 | texture = self._texture, 70 | g = self._graphics; 71 | if (g.dirty) { 72 | texture.directRenderWebGL(g, self.offset, true); 73 | } 74 | }; 75 | 76 | /** 77 | * 修改贴图的大小 78 | * @param {number} width - 贴图的宽 79 | * @param {number} height - 贴图的高 80 | */ 81 | GraphicsTexture.prototype.resize = function(width, height) { 82 | width = width <= 1 ? 1 : width; 83 | height = height <= 1 ? 1 : height; 84 | this._texture.resize(width, height, true); 85 | }; 86 | -------------------------------------------------------------------------------- /src/loader/ExcelHashSheetIndex.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenqx 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | /** 6 | * 表格类数据的hash类索引 7 | * @class qc.ExcelHashSheetIndex 8 | * @param excelSheet {qc.ExcelSheet} - 表格数据 9 | * @param hashKey {string} - 用来排序的列名 10 | * @param unique {boolean} - 键值是否唯一,唯一时,获取数据时获取的是所在行的值,否则获取的为行数组 11 | * @constructor 12 | * @internal 13 | */ 14 | var ExcelHashSheetIndex = qc.ExcelHashSheetIndex = function(excelSheet, hashKey, unique) { 15 | // 创建索引数据 16 | this._buildIndex(excelSheet, hashKey, unique); 17 | }; 18 | ExcelHashSheetIndex.prototype = {}; 19 | ExcelHashSheetIndex.prototype.constructor = ExcelHashSheetIndex; 20 | 21 | Object.defineProperties(ExcelHashSheetIndex.prototype, { 22 | /** 23 | * @property {[string]} columns - 存储排序的列信息 24 | * 优先按设定的key顺序,之后按原有columns的顺序 25 | * @readonly 26 | */ 27 | columns : { 28 | get : function() { return this._cols.slice(0); } 29 | }, 30 | 31 | /** 32 | * @property {[{}]} rows - 当前索引下的行数据 33 | * @readonly 34 | */ 35 | rows : { 36 | get : function() { return this._rows; } 37 | }, 38 | 39 | /** 40 | * @property {[string]} keys - 所有的键值 41 | * @readonly 42 | */ 43 | keys : { 44 | get : function() { return this._keys; } 45 | } 46 | }); 47 | /** 48 | * 创建索引数据 49 | * @param excelSheet {qc.ExcelSheet} - 表格数据 50 | * @param hashKey {string} - 用来排序的列名 51 | * @param unique {boolean} - 键值是否唯一,唯一时,获取数据时获取的是所在行的值,否则获取的为行数组 52 | * @private 53 | */ 54 | ExcelHashSheetIndex.prototype._buildIndex = function(excelSheet, hashKey, unique) { 55 | var rows = excelSheet.rows; 56 | this._rows = rows; 57 | this._cols = excelSheet.columns.slice(0); 58 | this._keys = []; 59 | var len = rows.length, i = -1; 60 | while (++i < len) { 61 | var row = rows[i]; 62 | var keyValue = row[hashKey]; 63 | if (unique) { 64 | this[keyValue] = row; 65 | this._keys.push(keyValue); 66 | } 67 | else { 68 | if (keyValue in this) { 69 | this[keyValue].push(row); 70 | } 71 | else { 72 | this[keyValue] = [row]; 73 | this._keys.push(keyValue); 74 | } 75 | } 76 | } 77 | }; 78 | -------------------------------------------------------------------------------- /src/time/Time.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author luohj 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 时间 8 | * 9 | * @class qc.Time 10 | * @param {qc.Game} game - A reference to the currently running game. 11 | * @constructor 12 | * @internal 13 | */ 14 | var Time = qc.Time = function(game) { 15 | this.phaser = game.phaser.time; 16 | this.phaser._qc = this; 17 | 18 | this.onFrameRateChanged = new qc.Signal(); 19 | } 20 | Time.prototype.constructor = Time; 21 | 22 | Object.defineProperties(Time.prototype, { 23 | 24 | 'game' : { 25 | get : function() { return this.phaser.game._qc; } 26 | }, 27 | 28 | /** 29 | * 现在的时间戳 (1970-01-01午夜到现在的时间间隔,用毫秒表述) 30 | * @property {number} now 31 | * @return {number} 32 | */ 33 | 'now' : { get : function() { return Date.now(); } }, 34 | 35 | /** 36 | * @property fixedTime {number} - 这是以毫秒秒计自游戏开始的时间 37 | */ 38 | 'fixedTime' : { get : function() { return this.phaser.totalElapsedSeconds() * 1000 ; } }, 39 | 40 | /** 41 | * @property scaleTime {number} - 自游戏开始后经历的时间,受timeScale影响 42 | */ 43 | 'scaledTime' : { 44 | get : function() { 45 | return this.phaser._totalEscapeTime || 0; 46 | } 47 | }, 48 | /** 49 | * 传递时间的缩放。这可以用于减慢运动效果。 50 | * - 1.0 = normal speed 51 | * - 2.0 = half speed 52 | * @property {number} timeScale 53 | */ 54 | 'timeScale' : { 55 | get : function() { return this.phaser.slowMotion; }, 56 | set : function(v) { 57 | if (v <= 0) v = 0.000001; 58 | this.phaser.slowMotion = v; 59 | } 60 | }, 61 | 62 | /** 63 | * @property {number} frameRate - 游戏运行的帧率 64 | */ 65 | 'frameRate' : { 66 | get : function() { return this.phaser.desiredFps; }, 67 | set : function(v) { 68 | this.phaser.desiredFps = v; 69 | this.onFrameRateChanged.dispatch(v); 70 | } 71 | }, 72 | 73 | /** 74 | * @property {number} deltaTime - 最后一帧到当前帧的时间间隔(单位:毫秒) 75 | */ 76 | 'deltaTime' : { get : function() { return this.phaser.frameDeltaTime; } } 77 | }); 78 | 79 | Time.prototype.applyFrameRate = function(v) { 80 | var frameRate = this.game.device.desktop ? v.desktop : v.mobile; 81 | this.frameRate = frameRate; 82 | }; 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/misc/CanvasPool.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author wudm 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 全局统一的 canvas 缓存处理 8 | */ 9 | 10 | qc.CanvasPool = { 11 | // canvas 池描述 12 | pool : {}, 13 | unused : [], 14 | cookie : 19870101, 15 | 16 | // 入口,获取一个闲置的可用的 canvas 17 | get : function(key) { 18 | var pool = qc.CanvasPool.pool; 19 | var canvas = pool[key]; 20 | var isDirty = false; 21 | 22 | if (!canvas) { 23 | // 无效的 canvas 对象 24 | isDirty = true; 25 | 26 | // 当前 unused 中是否有元素可用,可用就拿来用,否则抛弃 27 | var unused = qc.CanvasPool.unused; 28 | if (unused.length) 29 | pool[key] = canvas = unused.pop(); 30 | else 31 | pool[key] = canvas = Phaser.Canvas.create(1, 1); 32 | } 33 | 34 | // 记录本帧该 canvas 有被调度过 35 | canvas._cookie = qc.CanvasPool.cookie; 36 | return { canvas : canvas, dirty : isDirty }; 37 | }, 38 | 39 | // 统计池子使用情况,目前主要用于 debug 40 | stat : function() { 41 | var count = 0; 42 | var totalSize = 0; 43 | var pool = qc.CanvasPool.pool; 44 | 45 | for (var key in pool) { 46 | var canvas = pool[key]; 47 | if (!canvas) continue; 48 | 49 | count++; 50 | totalSize += canvas.width * canvas.height; 51 | } 52 | 53 | console.info('当前Canvas使用中:' + count + ',总像素为:' + totalSize + 54 | ',未使用的Canvas数量:' + qc.CanvasPool.unused.length); 55 | }, 56 | 57 | // 心跳,驱动回收 58 | postRender : function() { 59 | var self = qc.CanvasPool; 60 | var cookie = self.cookie; 61 | self.cookie = cookie + 1; 62 | 63 | var pool = self.pool; 64 | var unused = self.unused; 65 | 66 | // 当帧没有被调度到的 canvas 就直接回收 67 | // 判定当前是否有被调度的标准是 canvas._cookie 是上次的 render cookie 68 | var keys = Object.keys(pool); 69 | for (var i = 0, len = keys.length; i < len; i++) { 70 | var key = keys[i]; 71 | var canvas = pool[key]; 72 | if (canvas._cookie !== cookie) { 73 | // 没有用到,释放空间,再回收掉 74 | delete pool[key]; 75 | canvas.width = 1; 76 | canvas.height = 1; 77 | unused.push(canvas); 78 | } 79 | } 80 | } 81 | }; -------------------------------------------------------------------------------- /src/hack/tilemap/Tileset.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author linyw 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * https://github.com/bjorn/tiled/issues/925 8 | * but I did it this way so that margin could be used as purely a starting offset. 9 | * Just that now the name is a little confusing.. 10 | * 11 | * Tiled编辑器(http://www.mapeditor.org/)的margin仅代表左上角的偏移, 12 | * Phaser解析为常规理解的上下左右都预留空间,以下函数做修正保持和Tiled编辑器一致 13 | */ 14 | Phaser.Tileset.prototype.updateTileData = function (imageWidth, imageHeight) { 15 | imageWidth -= this.tileMargin; 16 | imageHeight -= this.tileMargin; 17 | 18 | // May be fractional values 19 | var rowCount; 20 | var colCount; 21 | if (imageHeight > this.tileHeight) { 22 | rowCount = (imageHeight - this.tileHeight) / (this.tileHeight + this.tileSpacing) + 1; 23 | } else { 24 | rowCount = imageHeight / this.tileHeight; 25 | } 26 | if (imageWidth > this.tileWidth) { 27 | colCount = (imageWidth - this.tileWidth) / (this.tileWidth + this.tileSpacing) + 1; 28 | } else { 29 | colCount = imageWidth / this.tileWidth; 30 | } 31 | 32 | if (rowCount % 1 !== 0 || colCount % 1 !== 0) 33 | { 34 | // console.warn("Phaser.Tileset - image tile area is not an even multiple of tile size", rowCount, colCount); 35 | } 36 | 37 | // In Tiled a tileset image that is not an even multiple of the tile dimensions 38 | // is truncated - hence the floor when calculating the rows/columns. 39 | rowCount = Math.floor(rowCount); 40 | colCount = Math.floor(colCount); 41 | 42 | if ((this.rows && this.rows !== rowCount) || (this.columns && this.columns !== colCount)) 43 | { 44 | console.warn("Phaser.Tileset - actual and expected number of tile rows and columns differ"); 45 | } 46 | 47 | this.rows = rowCount; 48 | this.columns = colCount; 49 | this.total = rowCount * colCount; 50 | 51 | this.drawCoords.length = 0; 52 | 53 | var tx = this.tileMargin; 54 | var ty = this.tileMargin; 55 | 56 | for (var y = 0; y < this.rows; y++) 57 | { 58 | for (var x = 0; x < this.columns; x++) 59 | { 60 | this.drawCoords.push(tx); 61 | this.drawCoords.push(ty); 62 | tx += this.tileWidth + this.tileSpacing; 63 | } 64 | 65 | tx = this.tileMargin; 66 | ty += this.tileHeight + this.tileSpacing; 67 | } 68 | 69 | }; -------------------------------------------------------------------------------- /src/components/TweenScale.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */; 5 | 6 | /** 7 | * 缩放动画组件 8 | * @class qc.TweenAlpha 9 | */ 10 | var TweenScale = defineBehaviour('qc.TweenScale', qc.Tween, function() { 11 | var self = this; 12 | 13 | /** 14 | * @property {qc.Point} from - 起始的缩放信息 15 | */ 16 | self.from = new qc.Point(0, 0); 17 | 18 | /** 19 | * @property {qc.Point} to - 最终的缩放信息 20 | */ 21 | self.to = new qc.Point(1, 1); 22 | 23 | // 默认情况下不可用 24 | self.enable = false; 25 | },{ 26 | from : qc.Serializer.POINT, 27 | to : qc.Serializer.POINT 28 | }); 29 | 30 | // 菜单上的显示 31 | TweenScale.__menu = 'Tween/TweenScale'; 32 | 33 | // 帧调度: 驱动动画 34 | TweenScale.prototype.onUpdate = function(factor, isFinished) { 35 | var self = this; 36 | var _from = self.from, _to = self.to; 37 | var scale = new qc.Point( 38 | _from.x + factor * (_to.x - _from.x), 39 | _from.y + factor * (_to.y - _from.y) 40 | ); 41 | 42 | self.gameObject.scaleX = scale.x; 43 | self.gameObject.scaleY = scale.y; 44 | }; 45 | 46 | /** 47 | * 将开始状态设成当前状态 48 | */ 49 | TweenScale.prototype.setStartToCurrValue = function() { 50 | this.gameObject.scaleX = this.from.x; 51 | this.gameObject.scaleY = this.from.y; 52 | }; 53 | 54 | /** 55 | * 将结束状态设成当前状态 56 | */ 57 | TweenScale.prototype.setEndToCurrValue = function() { 58 | this.gameObject.scaleX = this.to.x; 59 | this.gameObject.scaleY = this.to.y; 60 | }; 61 | 62 | /** 63 | * 将当前状态设为开始状态 64 | */ 65 | TweenScale.prototype.setCurrToStartValue = function() { 66 | this.from = new qc.Point(this.gameObject.scaleX, this.gameObject.scaleY); 67 | }; 68 | 69 | /** 70 | * 将当前状态设置为结束状态 71 | */ 72 | TweenScale.prototype.setCurrToEndValue = function() { 73 | this.to = new qc.Point(this.gameObject.scaleX, this.gameObject.scaleY); 74 | }; 75 | 76 | /** 77 | * 开始缩放 78 | * @param node {qc.Node} - 需要缩放的节点 79 | * @param duration {number} - 经历的时间 80 | * @param scale {qc.Point} - 最终缩放 81 | * @returns {qc.TweenScale} 82 | */ 83 | TweenScale.begin = function(node, duration, scale) { 84 | var tween = qc.Tween.begin('qc.TweenScale', node, duration); 85 | tween.from = new qc.Point(node.scaleX, node.scaleY); 86 | tween.to = scale.clone(); 87 | if (duration <= 0) { 88 | tween.sample(1, true); 89 | tween.enable = false; 90 | } 91 | return tween; 92 | }; 93 | -------------------------------------------------------------------------------- /src/hack/pixi/PixiShader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @hack 添加原图参数 3 | */ 4 | /** 5 | * Initialises the shader. 6 | * 7 | * @method init 8 | */ 9 | PIXI.PixiShader.prototype.init = function() 10 | { 11 | var gl = this.gl; 12 | 13 | var program = PIXI.compileProgram(gl, this.vertexSrc || PIXI.PixiShader.defaultVertexSrc, this.fragmentSrc); 14 | 15 | gl.useProgram(program); 16 | 17 | // get and store the uniforms for the shader 18 | this.uSampler = gl.getUniformLocation(program, 'uSampler'); 19 | // modify by chenqx, 用来传递 Shader 处理之前的原图 20 | this.uSourceSampler = gl.getUniformLocation(program, 'uSourceSampler'); 21 | // modify end 22 | this.projectionVector = gl.getUniformLocation(program, 'projectionVector'); 23 | this.offsetVector = gl.getUniformLocation(program, 'offsetVector'); 24 | this.dimensions = gl.getUniformLocation(program, 'dimensions'); 25 | this.pixelSize = gl.getUniformLocation(program, 'pixelSize'); 26 | 27 | // get and store the attributes 28 | this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition'); 29 | this.aTextureCoord = gl.getAttribLocation(program, 'aTextureCoord'); 30 | this.colorAttribute = gl.getAttribLocation(program, 'aColor'); 31 | 32 | // Begin worst hack eva // 33 | 34 | // WHY??? ONLY on my chrome pixel the line above returns -1 when using filters? 35 | // maybe its something to do with the current state of the gl context. 36 | // I'm convinced this is a bug in the chrome browser as there is NO reason why this should be returning -1 especially as it only manifests on my chrome pixel 37 | // If theres any webGL people that know why could happen please help :) 38 | if(this.colorAttribute === -1) 39 | { 40 | this.colorAttribute = 2; 41 | } 42 | 43 | this.attributes = [this.aVertexPosition, this.aTextureCoord, this.colorAttribute]; 44 | 45 | if (this.extraAttribute) { 46 | for (var idx in this.extraAttribute) { 47 | var key = this.extraAttribute[idx].name; 48 | this[key] = gl.getAttribLocation(program, key); 49 | this.attributes.push(this[key]); 50 | } 51 | } 52 | // End worst hack eva // 53 | 54 | // add those custom shaders! 55 | for (var key in this.uniforms) 56 | { 57 | // get the uniform locations.. 58 | this.uniforms[key].uniformLocation = gl.getUniformLocation(program, key); 59 | } 60 | 61 | this.initUniforms(); 62 | 63 | this.program = program; 64 | }; 65 | -------------------------------------------------------------------------------- /src/core/Storage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 本地数据保存 8 | * 9 | * @class qc.Storage 10 | * @constructor 11 | * @internal 12 | */ 13 | var Storage = qc.Storage = function(game) { 14 | this.game = game; 15 | this._data = {}; 16 | this.timerMap = {}; 17 | }; 18 | 19 | Storage.prototype = {}; 20 | Storage.prototype.constructor = Storage; 21 | 22 | Object.defineProperties(Storage.prototype, { 23 | /** 24 | * 本地数据存储标志符 25 | */ 26 | key : { 27 | get : function() { 28 | return this.game.localStorageID; 29 | } 30 | } 31 | }); 32 | 33 | /** 34 | * 还原出所有的数据 35 | */ 36 | Storage.prototype.restore = function() { 37 | }; 38 | 39 | /** 40 | * 保存所有数据 41 | */ 42 | Storage.prototype.save = function() { 43 | }; 44 | 45 | /** 46 | * 保存一条记录 47 | */ 48 | Storage.prototype.set = function(k, v) { 49 | var key = this.key + "_" + k; 50 | this._data[key] = v; 51 | 52 | // 写缓存 53 | var str = JSON.stringify(v); 54 | if (!window.__wx) 55 | window.localStorage.setItem(key, str); 56 | else 57 | wx.setStorage({key: key, data: str}); 58 | }; 59 | 60 | /** 61 | * 保存一条记录,延时写入缓顾存 62 | */ 63 | Storage.prototype.delaySet = function(k, v, delay) { 64 | if (this.timerMap[k]) 65 | return; 66 | 67 | var key = this.key + "_" + k; 68 | this._data[key] = v; 69 | 70 | var self = this; 71 | this.timerMap[k] = this.game.timer.add(delay, function() { 72 | delete self.timerMap[k]; 73 | self.set(k, v); 74 | }); 75 | }; 76 | 77 | /** 78 | * 删除一条记录 79 | */ 80 | Storage.prototype.del = function(k) { 81 | var key = this.key + "_" + k; 82 | if (this._data[key]) 83 | delete this._data[key]; 84 | 85 | if (!window.__wx) 86 | window.localStorage.removeItem(key); 87 | else 88 | wx.removeStorageSync(key); 89 | }; 90 | 91 | /** 92 | * 检索一条记录 93 | */ 94 | Storage.prototype.get = function(k) { 95 | var key = this.key + "_" + k; 96 | if (this._data[key]) 97 | return this._data[key]; 98 | 99 | var str; 100 | if (!window.__wx) 101 | str = window.localStorage.getItem(key); 102 | else 103 | str = wx.getStorageSync(key); 104 | var v; 105 | if (str) { 106 | v = JSON.parse(str); 107 | this._data[key] = v; 108 | } 109 | return v; 110 | }; 111 | -------------------------------------------------------------------------------- /src/components/DropdownItem.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2016 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * For qc.Dropdown. Only Text or Texture is supported. 8 | * @class qc.DropdownItem 9 | */ 10 | var DropdownItem = defineBehaviour('qc.DropdownItem', qc.Behaviour, function() { 11 | var self = this; 12 | 13 | /** 14 | * @property {qc.Dropdown} dropdown - The Dropdown reference. 15 | * @protected 16 | */ 17 | self.dropdown = null; 18 | },{ 19 | checkBackground: qc.Serializer.NODE, 20 | checkMark: qc.Serializer.NODE, 21 | text: qc.Serializer.NODE, 22 | image: qc.Serializer.NODE 23 | }); 24 | DropdownItem.__menu = 'UI/DropdownItem'; 25 | 26 | Object.defineProperties(DropdownItem.prototype, { 27 | /** 28 | * @property {int} index - The index of dropdown items. 29 | */ 30 | index: { 31 | get: function() { return this._index; }, 32 | set: function(v) { 33 | if (this._index === v) return; 34 | this._index = v; 35 | this.redraw(); 36 | } 37 | } 38 | }); 39 | 40 | /** 41 | * When the mouse is pressed down, change the background texture 42 | */ 43 | DropdownItem.prototype.onDown = function() { 44 | if (this.checkBackground) this.checkBackground.visible = true; 45 | }; 46 | 47 | /** 48 | * When the mouse is pressed down, reset the background texture 49 | */ 50 | DropdownItem.prototype.onUp = function() { 51 | if (this.checkBackground) this.checkBackground.visible = false; 52 | }; 53 | 54 | /** 55 | * Select the item if click 56 | */ 57 | DropdownItem.prototype.onClick = function() { 58 | var self = this; 59 | if (self.index === self.dropdown.value) return; 60 | 61 | // Select this 62 | self.dropdown.value = self.index; 63 | self.dropdown.hide(); 64 | }; 65 | 66 | /** 67 | * Redraw the item. 68 | * @internal 69 | */ 70 | DropdownItem.prototype.redraw = function() { 71 | var self = this, 72 | o = self.gameObject, 73 | v = self.dropdown.options[self.index]; 74 | 75 | if (typeof v === 'string') { 76 | if (self.image) self.image.visible = false; 77 | self.text.visible = true; 78 | self.text.text = v; 79 | } 80 | else { 81 | if (self.text) self.text.visible = false; 82 | self.image.visible = true; 83 | self.image.texture = v; 84 | } 85 | 86 | if (self.checkMark) { 87 | self.checkMark.visible = self.index === self.dropdown.value; 88 | } 89 | o.anchoredY = self.index * o.height; 90 | if (self.checkBackground) self.checkBackground.visible = false; 91 | }; 92 | -------------------------------------------------------------------------------- /src/core.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | // 如果已经定义过qc.VERSION变量,则代表js重复加载执行,直接return不再重复定义 7 | if (window.qc && window.qc.Node) { 8 | return; 9 | } 10 | 11 | /** 12 | * 深拷贝 13 | * @param object 将要被深拷贝的对象 14 | */ 15 | var deepCopy = function(object) { 16 | var copied = []; 17 | 18 | var contains = function(arr, obj) { 19 | for (var i in arr) 20 | { 21 | if (arr[i] == obj) 22 | return true; 23 | } 24 | 25 | return false; 26 | }; 27 | 28 | var copyImp = function(obj) { 29 | if (typeof(obj) !== 'object' || obj === null) 30 | return obj; 31 | else if (contains(copied, obj)) 32 | return obj; 33 | 34 | copied.push(obj); 35 | 36 | var newObject = {}; 37 | if (obj.constructor === Array) { 38 | newObject = []; 39 | } 40 | 41 | for (var i in obj) { 42 | // 过滤从上级原形继承的属性 43 | if (! obj.hasOwnProperty(i)) 44 | continue; 45 | 46 | newObject[i] = copyImp(obj[i]); 47 | } 48 | 49 | return newObject; 50 | }; 51 | 52 | return copyImp(object); 53 | }; 54 | 55 | /** 56 | * 混合注入属性 57 | * @param object 将要被注入属性的对象 58 | * @param properties 需要注入的属性 59 | * @param keepExist 是否保留已经定义过的属性,默认为false 60 | */ 61 | var mixin = function(object, properties, keepExist) { 62 | for (var name in properties) { 63 | if (!keepExist || object[name] === undefined) { 64 | object[name] = properties[name]; 65 | } 66 | } 67 | return object; 68 | }; 69 | 70 | if (!window.qc){ 71 | window.qc = {}; 72 | } 73 | var qc = window.qc, 74 | Phaser = window.Phaser, 75 | PIXI = window.PIXI; 76 | 77 | mixin(qc, { 78 | // 版本 79 | PHASER_VERSION: Phaser.VERSION, 80 | 81 | // 多个游戏实例时使用 82 | GAMES: Phaser.GAMES, 83 | 84 | // 渲染方式 85 | AUTO: Phaser.AUTO, 86 | CANVAS: Phaser.CANVAS, 87 | WEBGL: Phaser.WEBGL, 88 | HEADLESS: Phaser.HEADLESS, 89 | 90 | // 方向 91 | NONE: Phaser.NONE, 92 | LEFT: Phaser.LEFT, 93 | RIGHT: Phaser.RIGHT, 94 | UP: Phaser.UP, 95 | DOWN: Phaser.DOWN, 96 | 97 | /** 98 | * 缩放模式 99 | * 100 | * @property {Object} scaleModes 101 | * @property {Number} scaleModes.DEFAULT = LINEAR 102 | * @property {Number} scaleModes.LINEAR Smooth scaling 103 | * @property {Number} scaleModes.NEAREST Pixelating scaling 104 | */ 105 | scaleModes: Phaser.scaleModes 106 | }); 107 | -------------------------------------------------------------------------------- /src/components/TweenColor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 颜色渐变动画 8 | * @class qc.TweenAlpha 9 | */ 10 | var TweenColor = defineBehaviour('qc.TweenColor', qc.Tween, function() { 11 | var self = this; 12 | 13 | /** 14 | * @property {qc.Color} from - 起始的颜色值 15 | */ 16 | self.from = Color.black; 17 | 18 | /** 19 | * @property {qc.Color} to - 最终的颜色值 20 | */ 21 | self.to = Color.white; 22 | 23 | // 默认情况下不可用 24 | self.enable = false; 25 | },{ 26 | from : qc.Serializer.COLOR, 27 | to : qc.Serializer.COLOR 28 | }); 29 | 30 | // 菜单上的显示 31 | TweenColor.__menu = 'Tween/TweenColor'; 32 | 33 | /** 34 | * 处理对应的变化逻辑 35 | * @param factor {number} - 形变的因子 36 | * @param isFinished {boolean} - 是否已经结束 37 | */ 38 | TweenColor.prototype.onUpdate = function(factor, isFinished) { 39 | var self = this; 40 | var _from = self.from.rgb, _to = self.to.rgb; 41 | var currColor = [ 42 | Phaser.Math.clamp(Math.round(_from[0] + factor * (_to[0] - _from[0])), 0, 255), 43 | Phaser.Math.clamp(Math.round(_from[1] + factor * (_to[1] - _from[1])), 0, 255), 44 | Phaser.Math.clamp(Math.round(_from[2] + factor * (_to[2] - _from[2])), 0, 255), 45 | Phaser.Math.clamp(self.from.alpha + factor * (self.to.alpha - self.from.alpha), 0, 1) 46 | ]; 47 | var color = new Color(currColor); 48 | self.gameObject.colorTint = color; 49 | }; 50 | 51 | /** 52 | * 将开始状态设成当前状态 53 | */ 54 | TweenColor.prototype.setStartToCurrValue = function() { 55 | this.gameObject.colorTint = new Color(this.from.toString()); 56 | }; 57 | 58 | /** 59 | * 将结束状态设成当前状态 60 | */ 61 | TweenColor.prototype.setEndToCurrValue = function() { 62 | this.gameObject.colorTint = new Color(this.to.toString()); 63 | }; 64 | 65 | /** 66 | * 将当前状态设为开始状态 67 | */ 68 | TweenColor.prototype.setCurrToStartValue = function() { 69 | this.from = new Color(this.gameObject.colorTint.toString()); 70 | }; 71 | 72 | /** 73 | * 将当前状态设置为结束状态 74 | */ 75 | TweenColor.prototype.setCurrToEndValue = function() { 76 | this.to = new Color(this.gameObject.colorTint.toString()); 77 | }; 78 | 79 | /** 80 | * 开始变色 81 | * @param node {qc.Node} - 需要变色的节点 82 | * @param duration {number} - 变色的时间 83 | * @param color {qc.Color} - 最终颜色 84 | * @returns {qc.TweenColor} 85 | */ 86 | TweenColor.begin = function(node, duration, color) { 87 | var tween = qc.Tween.begin('qc.TweenColor', node, duration); 88 | tween.from = new Color(node.colorTint.toString()); 89 | tween.to = color; 90 | if (duration <= 0) { 91 | tween.sample(1, true); 92 | tween.enable = false; 93 | } 94 | return tween; 95 | }; 96 | -------------------------------------------------------------------------------- /src/components/VerticalLayout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenqx 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | /** 6 | * 垂直布局 7 | * 拓展TableLayout 8 | */ 9 | var VerticalLayout = defineBehaviour('qc.VerticalLayout', qc.TableLayout, function() { 10 | // 初始化参数 11 | this.style = qc.TableLayout.STYLE_RESIZE_ELEMENT; 12 | this.constraint = qc.TableLayout.CONSTRAINT_FIX_COLUMN_COUNT; 13 | this.contentSizeProvider = qc.TableLayout.USE_RECTTRANSFORM; 14 | this.stride = 1; 15 | this.startCorner = qc.TableLayout.CORNER_TOP_LEFT; 16 | this.startAxis = qc.TableLayout.AXIS_VERTICAL; 17 | },{ 18 | childForceExpandWidth : qc.Serializer.NUMBER, 19 | childForceExpandHeight : qc.Serializer.NUMBER 20 | }); 21 | 22 | // 菜单上的显示 23 | VerticalLayout.__menu = 'UI/Layout/VerticalLayout'; 24 | 25 | Object.defineProperties(VerticalLayout.prototype, { 26 | /** 27 | * @property {number} spacing - 布局间距 28 | */ 29 | spacing : { 30 | get : function() { return this.spacingY; }, 31 | set : function(value) { this.spacingY = value; } 32 | }, 33 | 34 | /** 35 | * @property {number} childForceExpandWidth - 是否强制拉伸宽度 36 | */ 37 | childForceExpandWidth : { 38 | get : function() { return !!this._childForceExpandWidth; }, 39 | set : function(value) { 40 | if (this._childForceExpandWidth === value) { 41 | return; 42 | } 43 | this._childForceExpandWidth = value; 44 | this.rebuildTable(); 45 | } 46 | }, 47 | 48 | /** 49 | * @property {number} childForceExpandWidth - 是否强制拉伸高度 50 | */ 51 | childForceExpandHeight : { 52 | get : function() { return !!this._childForceExpandHeight; }, 53 | set : function(value) { 54 | if (this._childForceExpandHeight === value) { 55 | return; 56 | } 57 | this._childForceExpandHeight = value; 58 | this.rebuildTable(); 59 | } 60 | } 61 | }); 62 | 63 | /** 64 | * 获取在某一轴线上的默认布局系数 65 | * @override 66 | * @private 67 | */ 68 | VerticalLayout.prototype._getDefaultLayout = function(axis){ 69 | if (axis === 'y') { 70 | return {min : 0, 71 | preferred : 0, 72 | flexible : this.childForceExpandHeight ? 1 : 0, 73 | extra : 0}; 74 | } 75 | else { 76 | return {min : 0, 77 | preferred : this.childForceExpandWidth ? this.gameObject.rect.width : -1, 78 | flexible : 0, 79 | extra : 0}; 80 | } 81 | 82 | }; 83 | 84 | /** 85 | * 获取在某一节点的布局系数 86 | * @param node {qc.Node} - 节点 87 | * @returns {*|LayoutElement} 88 | * @override 89 | */ 90 | VerticalLayout.prototype.getCellLayout = function(node) { 91 | var layout = qc.LayoutElement.getLayoutElement(node); 92 | this.childForceExpandWidth && (layout.flexibleWidth = 1); 93 | this.childForceExpandHeight && (layout.flexibleHeight = 1); 94 | return layout; 95 | }; -------------------------------------------------------------------------------- /src/components/HorizontalLayout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenqx 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | /** 6 | * 水平布局 7 | * 拓展TableLayout 8 | */ 9 | var HorizontalLayout = defineBehaviour('qc.HorizontalLayout', qc.TableLayout, function() { 10 | // 初始化参数 11 | this.style = qc.TableLayout.STYLE_RESIZE_ELEMENT; 12 | this.constraint = qc.TableLayout.CONSTRAINT_FIX_ROW_COUNT; 13 | this.contentSizeProvider = qc.TableLayout.USE_RECTTRANSFORM; 14 | this.stride = 1; 15 | this.startCorner = qc.TableLayout.CORNER_TOP_LEFT; 16 | this.startAxis = qc.TableLayout.AXIS_HORIZONTAL; 17 | },{ 18 | childForceExpandWidth : qc.Serializer.NUMBER, 19 | childForceExpandHeight : qc.Serializer.NUMBER 20 | }); 21 | 22 | // 菜单上的显示 23 | HorizontalLayout.__menu = 'UI/Layout/HorizontalLayout'; 24 | 25 | Object.defineProperties(HorizontalLayout.prototype, { 26 | /** 27 | * @property {number} spacing - 布局间距 28 | */ 29 | spacing : { 30 | get : function() { return this.spacingX; }, 31 | set : function(value) { this.spacingX = value; } 32 | }, 33 | 34 | /** 35 | * @property {number} childForceExpandWidth - 是否强制拉伸宽度 36 | */ 37 | childForceExpandWidth : { 38 | get : function() { return !!this._childForceExpandWidth; }, 39 | set : function(value) { 40 | if (this._childForceExpandWidth === value) { 41 | return; 42 | } 43 | this._childForceExpandWidth = value; 44 | this.rebuildTable(); 45 | } 46 | }, 47 | 48 | /** 49 | * @property {number} childForceExpandWidth - 是否强制拉伸高度 50 | */ 51 | childForceExpandHeight : { 52 | get : function() { return !!this._childForceExpandHeight; }, 53 | set : function(value) { 54 | if (this._childForceExpandHeight === value) { 55 | return; 56 | } 57 | this._childForceExpandHeight = value; 58 | this.rebuildTable(); 59 | } 60 | } 61 | }); 62 | 63 | /** 64 | * 获取在某一轴线上的默认布局系数 65 | * @override 66 | * @private 67 | */ 68 | HorizontalLayout.prototype._getDefaultLayout = function(axis){ 69 | if (axis === 'x') { 70 | return {min : 0, 71 | preferred : 0, 72 | flexible : this.childForceExpandWidth ? 1 : 0, 73 | extra : 0}; 74 | } 75 | else { 76 | return {min : 0, 77 | preferred : this.childForceExpandHeight ? this.gameObject.rect.height : -1, 78 | flexible : 1, 79 | extra : 0}; 80 | } 81 | 82 | }; 83 | 84 | /** 85 | * 获取在某一节点的布局系数 86 | * @param node {qc.Node} - 节点 87 | * @returns {*|LayoutElement} 88 | * @override 89 | */ 90 | HorizontalLayout.prototype.getCellLayout = function(node) { 91 | var layout = qc.LayoutElement.getLayoutElement(node); 92 | this.childForceExpandWidth && (layout.flexibleWidth = 1); 93 | this.childForceExpandHeight && (layout.flexibleHeight = 1); 94 | return layout; 95 | }; -------------------------------------------------------------------------------- /src/core/Log.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 日志系统 8 | * @class qc.Log 9 | */ 10 | var Log = qc.Log = function(game) { 11 | var self = this; 12 | self.game = game; 13 | 14 | /** 15 | * @property {boolean} 是否开启trace打印 16 | */ 17 | self.enableTrace = false; 18 | }; 19 | 20 | /* 21 | * 普通打印日志 22 | * @param arguments 23 | */ 24 | Log.prototype.trace = function() { 25 | // 有配置远程日志服务器地址,则发送日志到远程服务器 26 | if (this.game.remoteLogUrl) 27 | { 28 | var content = qc.Util.formatString.apply(null, arguments); 29 | console.log(content); 30 | var time = new Date(); 31 | var timeStr = time.getHours()+':'+time.getMinutes()+':'+time.getSeconds()+':'+time.getMilliseconds(); 32 | qc.AssetUtil.post(this.game.remoteLogUrl + '/remoteLog', timeStr + ' ' + content, function(r){}); 33 | } 34 | else if (this.enableTrace) 35 | { 36 | var content = qc.Util.formatString.apply(null, arguments); 37 | console.log(content); 38 | } 39 | }; 40 | 41 | /** 42 | * 重要的打印日志 43 | * @param arguments 44 | */ 45 | Log.prototype.important = function() { 46 | var content = qc.Util.formatString.apply(null, arguments); 47 | if (!window.__wx) 48 | console.log('%c' + content, 'color:green'); 49 | else 50 | console.log(content); 51 | 52 | // 有配置远程日志服务器地址,则发送日志到远程服务器 53 | if (this.game.remoteLogUrl) 54 | { 55 | var time = new Date(); 56 | var timeStr = time.getHours()+':'+time.getMinutes()+':'+time.getSeconds()+':'+time.getMilliseconds(); 57 | qc.AssetUtil.post(this.game.remoteLogUrl + '/remoteLog', timeStr + ' ' + content, function(r){}); 58 | } 59 | }; 60 | 61 | /** 62 | * 错误日志 63 | * @param arguments 64 | */ 65 | Log.prototype.error = function() { 66 | var content = qc.Util.formatString.apply(null, arguments); 67 | if (!window.__wx) 68 | console.log('%c' + content, 'color:red'); 69 | else 70 | console.log(content); 71 | 72 | // 打印错误堆栈 73 | var errorStack; 74 | for (var i = 1; i < arguments.length; i++) { 75 | if (arguments[i] && arguments[i].stack) { 76 | errorStack = arguments[i].stack; 77 | console.error(errorStack); 78 | 79 | break; 80 | } 81 | } 82 | 83 | // 有配置远程日志服务器地址,则发送日志到远程服务器 84 | if (this.game.remoteLogUrl) 85 | qc.AssetUtil.post(this.game.remoteLogUrl + '/remoteLog', Date.now() + ' ' + errorStack ? errorStack : content, function(r){}); 86 | 87 | if (!errorStack && !window.__wx) 88 | console.trace(); 89 | }; 90 | 91 | /** 92 | * 远程回复 93 | * @param arguments 94 | */ 95 | Log.prototype.remoteReply = function() { 96 | var content = qc.Util.formatString.apply(null, arguments); 97 | console.log('%c' + content, 'color:green'); 98 | qc.AssetUtil.post(this.game.remoteLogUrl + '/remoteLog', content, function(r){}); 99 | }; 100 | -------------------------------------------------------------------------------- /src/gameobjects/ObjectLayer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author linyw 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | var ObjectLayer = qc.ObjectLayer = function(game, parent, uuid) { 7 | qc.Node.call(this, new Phaser.Group(game.phaser, null), parent, uuid); 8 | 9 | // 初始化默认的名字 10 | this.name = 'ObjectLayer'; 11 | 12 | this.setAnchor(new qc.Point(0, 0), new qc.Point(1, 1)); 13 | this.setStretch(0, 0, 0, 0); 14 | }; 15 | 16 | ObjectLayer.prototype = Object.create(qc.Node.prototype); 17 | ObjectLayer.prototype.constructor = ObjectLayer; 18 | 19 | ObjectLayer.prototype._tilemap = null; 20 | ObjectLayer.prototype._layerIndex = -1; 21 | ObjectLayer.prototype._scrollXRatio = 1; 22 | ObjectLayer.prototype._scrollYRatio = 1; 23 | 24 | /** 25 | * 获取需要被序列化的信息描述 26 | */ 27 | ObjectLayer.prototype.getMeta = function() { 28 | var json = qc.Node.prototype.getMeta.call(this); 29 | 30 | // 增加TileLayer需要序列化的内容 31 | json.tilemap = Serializer.NODE; 32 | json.layerIndex = Serializer.INT; 33 | json.scrollXRatio = Serializer.NUMBER; 34 | json.scrollYRatio = Serializer.NUMBER; 35 | 36 | return json; 37 | }; 38 | 39 | 40 | /** 41 | * 更新 42 | */ 43 | ObjectLayer.prototype.update = function() { 44 | if (this._tilemap && this._tilemap._destroy) { 45 | this._tilemap = null; 46 | } 47 | var tilemap = this._tilemap; 48 | 49 | if (tilemap) { 50 | this.x = tilemap.scrollX * this.scrollXRatio; 51 | this.y = tilemap.scrollY * this.scrollXRatio; 52 | } 53 | }; 54 | 55 | Object.defineProperties(ObjectLayer.prototype, { 56 | 57 | tilemap: { 58 | get: function() { 59 | if (this._tilemap && this._tilemap._destroy) { 60 | this._tilemap = null; 61 | } 62 | return this._tilemap; 63 | }, 64 | set: function(value) { 65 | if (value && !(value instanceof Tilemap)) { 66 | return; 67 | } 68 | this._tilemap = value; 69 | } 70 | }, 71 | 72 | layerIndex: { 73 | get: function() { 74 | return this._layerIndex; 75 | }, 76 | set: function(value) { 77 | this._layerIndex = value; 78 | } 79 | }, 80 | 81 | /** 82 | * 水平滚动速率 83 | */ 84 | scrollXRatio: { 85 | get: function() { 86 | return this._scrollXRatio; 87 | }, 88 | set: function(value) { 89 | this._scrollXRatio = value; 90 | } 91 | }, 92 | 93 | /** 94 | * 垂直滚动速率 95 | */ 96 | scrollYRatio: { 97 | get: function() { 98 | return this._scrollYRatio; 99 | }, 100 | set: function(value) { 101 | this._scrollYRatio = value; 102 | } 103 | }, 104 | 105 | /** 106 | * @property {string} class - 类名 107 | * @internal 108 | * @readonly 109 | */ 110 | class : { 111 | get : function() { return 'qc.ObjectLayer'; } 112 | } 113 | }); -------------------------------------------------------------------------------- /src/components/TweenProperty.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 属性变化 8 | * @class qc.TweenProperty 9 | */ 10 | var TweenProperty = defineBehaviour('qc.TweenProperty', qc.Tween, function() { 11 | var self = this; 12 | 13 | /** 14 | * @property {number} from - 起始的数值 15 | */ 16 | self.from = 0; 17 | 18 | /** 19 | * @property {number} to - 最终的数值 20 | */ 21 | self.to = 1; 22 | 23 | /** 24 | * @property {string} property - 对象的属性 25 | */ 26 | self.property = ''; 27 | 28 | // 默认情况下不可用 29 | self.enable = false; 30 | },{ 31 | from : qc.Serializer.NUMBER, 32 | to : qc.Serializer.NUMBER, 33 | property: qc.Serializer.STRING 34 | }); 35 | 36 | // 菜单上的显示 37 | TweenProperty.__menu = 'Tween/TweenProperty'; 38 | 39 | Object.defineProperties(TweenProperty.prototype, { 40 | property: { 41 | get: function() { return this._property; }, 42 | set: function(v) { 43 | if (v === this._property) return; 44 | 45 | // 记录对象和最后一级的属性 46 | var arr = v.split('.'); 47 | var o = this.gameObject; 48 | for (var i = 0; i < arr.length - 1; i++) { 49 | o = o[arr[i]]; 50 | if (!o) { 51 | this.game.log.important('The property({0}) non-exist.', v); 52 | return; 53 | } 54 | } 55 | this._ob = o; 56 | this._attrib = arr[arr.length - 1]; 57 | this._property = v; 58 | } 59 | } 60 | }); 61 | 62 | // 帧调度 63 | TweenProperty.prototype.onUpdate = function(factor, isFinished) { 64 | var self = this; 65 | var _from = self.from, _to = self.to; 66 | 67 | self._ob[self._attrib] = _from + factor * (_to - _from); 68 | }; 69 | 70 | /** 71 | * 将开始状态设成当前状态 72 | */ 73 | TweenProperty.prototype.setStartToCurrValue = function() { 74 | this._ob[this._attrib] = this.from; 75 | }; 76 | 77 | /** 78 | * 将结束状态设成当前状态 79 | */ 80 | TweenProperty.prototype.setEndToCurrValue = function() { 81 | this._ob[this._attrib] = this.to; 82 | }; 83 | 84 | /** 85 | * 将当前状态设为开始状态 86 | */ 87 | TweenProperty.prototype.setCurrToStartValue = function() { 88 | this.from = this._ob[this._attrib]; 89 | }; 90 | 91 | /** 92 | * 将当前状态设置为结束状态 93 | */ 94 | TweenProperty.prototype.setCurrToEndValue = function() { 95 | this.to = this._ob[this._attrib]; 96 | }; 97 | /** 98 | * 开始变化 99 | * @param node {qc.Node} - 需要改变的节点 100 | * @param duration {number} - 经历的时间 101 | * @param vallue {number} - 最终值 102 | * @returns {qc.TweenProperty} 103 | */ 104 | TweenProperty.begin = function(node, duration, value) { 105 | var tween = qc.Tween.begin('qc.TweenProperty', node, duration); 106 | tween.from = this._ob[this._attrib]; 107 | tween.to = value; 108 | if (duration <= 0) { 109 | tween.sample(1, true); 110 | tween.enable = false; 111 | } 112 | return tween; 113 | }; 114 | -------------------------------------------------------------------------------- /src/components/TweenPosition.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 位置动画组件 8 | * @class qc.TweenPosition 9 | */ 10 | var TweenPosition = defineBehaviour('qc.TweenPosition', qc.Tween, function() { 11 | var self = this; 12 | 13 | /** 14 | * @property {qc.Point} from - 起始点 15 | */ 16 | self.from = new qc.Point(0, 0); 17 | 18 | /** 19 | * @property {qc.Point} to - 终点 20 | */ 21 | self.to = new qc.Point(0, 0); 22 | 23 | /** 24 | * @property {number} moveAxis - 当前改变位置的类型 25 | */ 26 | self.moveAxis = TweenPosition.BOTH; 27 | 28 | // 默认情况下不可用 29 | self.enable = false; 30 | },{ 31 | from : qc.Serializer.POINT, 32 | to : qc.Serializer.POINT, 33 | moveAxis : qc.Serializer.NUMBER 34 | }); 35 | 36 | // 菜单上的显示 37 | TweenPosition.__menu = 'Tween/TweenPosition'; 38 | 39 | // 帧调度: 驱动位置 40 | TweenPosition.prototype.onUpdate = function(factor, isFinished) { 41 | var self = this; 42 | var _from = self.from, _to = self.to; 43 | ((self.moveAxis & TweenPosition.ONLY_X) !== 0) && (self.gameObject.x = _from.x + factor * (_to.x - _from.x)); 44 | ((self.moveAxis & TweenPosition.ONLY_Y) !== 0) && (self.gameObject.y = _from.y + factor * (_to.y - _from.y)); 45 | }; 46 | 47 | /** 48 | * 将开始位置设成当前位置 49 | */ 50 | TweenPosition.prototype.setStartToCurrValue = function() { 51 | ((this.moveAxis & TweenPosition.ONLY_X) !== 0) && (this.gameObject.x = this.from.x); 52 | ((this.moveAxis & TweenPosition.ONLY_Y) !== 0) && (this.gameObject.y = this.from.y); 53 | }; 54 | 55 | /** 56 | * 将结束位置设成当前位置 57 | */ 58 | TweenPosition.prototype.setEndToCurrValue = function() { 59 | ((this.moveAxis & TweenPosition.ONLY_X) !== 0) && (this.gameObject.x = this.to.x); 60 | ((this.moveAxis & TweenPosition.ONLY_Y) !== 0) && (this.gameObject.y = this.to.y); 61 | }; 62 | 63 | /** 64 | * 将当前位置设为开始位置 65 | */ 66 | TweenPosition.prototype.setCurrToStartValue = function() { 67 | this.from = new qc.Point(this.gameObject.x, this.gameObject.y); 68 | }; 69 | 70 | /** 71 | * 将当前位置设置为结束位置 72 | */ 73 | TweenPosition.prototype.setCurrToEndValue = function() { 74 | this.to = new qc.Point(this.gameObject.x, this.gameObject.y); 75 | }; 76 | 77 | /** 78 | * 开始缩放 79 | * @param node {qc.Node} - 需要移动的节点 80 | * @param duration {number} - 经历的时间 81 | * @param position {qc.Point} - 需要移动到的点 82 | * @returns {qc.TweenPosition} 83 | */ 84 | TweenPosition.begin = function(node, duration, position) { 85 | var tween = qc.Tween.begin('qc.TweenPosition', node, duration); 86 | tween.from = new qc.Point(node.x, node.y); 87 | tween.to = position.clone(); 88 | if (duration <= 0) { 89 | tween.sample(1, true); 90 | tween.enable = false; 91 | } 92 | return tween; 93 | }; 94 | 95 | /** 96 | * x,y 轴位置都进行改变 97 | * @constant 98 | * @type {number} 99 | */ 100 | TweenPosition.BOTH = 255; 101 | /** 102 | * 只改变 x 轴位置 103 | * @constant 104 | * @type {number} 105 | */ 106 | TweenPosition.ONLY_X = 1; 107 | /** 108 | * 只改变 y 轴位置 109 | * @constant 110 | * @type {number} 111 | */ 112 | TweenPosition.ONLY_Y = 2; 113 | 114 | -------------------------------------------------------------------------------- /src/hack/pixi/WebGLSpriteBatch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by chenqx on 8/5/15. 3 | * @hack 添加三角形绘制提交方式 4 | */ 5 | /** 6 | * 以四边形填充 7 | * @constant 8 | * @type {number} 9 | */ 10 | qc.BATCH_QUAD = 0; 11 | /** 12 | * 以三角形填充 13 | * @constant 14 | * @type {number} 15 | */ 16 | qc.BATCH_TRIANGLES = 1; 17 | 18 | 19 | var oldWebGLSpriteBatchSetContext = PIXI.WebGLSpriteBatch.prototype.setContext; 20 | PIXI.WebGLSpriteBatch.prototype.setContext = function(gl) { 21 | oldWebGLSpriteBatchSetContext.call(this, gl); 22 | this.quadSize = this.size; 23 | this.triangleSize = 300; 24 | this.batchIndexNumber = 6; 25 | var triangleIndicesNum = this.triangleSize * 3; 26 | this.triangleIndices = new PIXI.Uint16Array(triangleIndicesNum); 27 | for (var i = 0; i < triangleIndicesNum; ++i) { 28 | this.triangleIndices[i] = i; 29 | } 30 | this._batchType = qc.BATCH_QUAD; 31 | this.quadIndexBuffer = this.indexBuffer; 32 | this.triangleIndexBuffer = gl.createBuffer(); 33 | 34 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.triangleIndexBuffer); 35 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.triangleIndices, gl.STATIC_DRAW); 36 | }; 37 | 38 | var oldWebGLSpriteBatchDestroy = PIXI.WebGLSpriteBatch.prototype.destroy; 39 | PIXI.WebGLSpriteBatch.prototype.destroy = function() { 40 | this.triangleIndices = null; 41 | this.gl.deleteBuffer(this.triangleIndexBuffer); 42 | oldWebGLSpriteBatchDestroy.call(this); 43 | } 44 | 45 | Object.defineProperties(PIXI.WebGLSpriteBatch.prototype,{ 46 | batchType : { 47 | get : function() { return this._batchType; }, 48 | set : function(v) { 49 | if (v === this._batchType) { 50 | return; 51 | } 52 | this.stop(); 53 | // 切换IndexBuffer,Size 54 | if (v === qc.BATCH_TRIANGLES) { 55 | this.size = this.triangleSize; 56 | this.indexBuffer = this.triangleIndexBuffer; 57 | this._batchType = v; 58 | this.batchIndexNumber = 3; 59 | } 60 | else { 61 | this.size = this.quadSize; 62 | this.indexBuffer = this.quadIndexBuffer; 63 | this._batchType = v; 64 | this.batchIndexNumber = 6; 65 | } 66 | this.start(); 67 | } 68 | } 69 | }); 70 | 71 | /** 72 | * @method renderBatch 73 | * @param texture {Texture} 74 | * @param size {Number} 75 | * @param startIndex {Number} 76 | */ 77 | PIXI.WebGLSpriteBatch.prototype.renderBatch = function(texture, size, startIndex) 78 | { 79 | if(size === 0)return; 80 | 81 | var gl = this.gl; 82 | 83 | // check if a texture is dirty.. 84 | if(texture._dirty[gl.id]) 85 | { 86 | this.renderSession.renderer.updateTexture(texture); 87 | } 88 | else 89 | { 90 | // bind the current texture 91 | gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); 92 | } 93 | //gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.batchIndexNumber === 3 ? this.triangleIndexBuffer : this.indexBuffer); 94 | // now draw those suckas! 95 | gl.drawElements(gl.TRIANGLES, size * this.batchIndexNumber, gl.UNSIGNED_SHORT, startIndex * this.batchIndexNumber * 2); 96 | 97 | // increment the draw count 98 | this.renderSession.drawCount++; 99 | }; -------------------------------------------------------------------------------- /src/hack/pixi/WebGLFastSpriteBatch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by chenqx on 8/5/15. 3 | * @hack 添加三角形绘制提交方式 4 | */ 5 | var oldWebGLFastSpriteBatchSetContext = PIXI.WebGLFastSpriteBatch.prototype.setContext; 6 | PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl) { 7 | oldWebGLFastSpriteBatchSetContext.call(this, gl); 8 | this.quadSize = this.size; 9 | this.triangleSize = 300; 10 | this.batchIndexNumber = 6; 11 | var triangleIndicesNum = this.triangleSize * 3; 12 | this.triangleIndices = new PIXI.Uint16Array(triangleIndicesNum); 13 | for (var i = 0; i < triangleIndicesNum; ++i) { 14 | this.triangleIndices[i] = i; 15 | } 16 | this._batchType = qc.BATCH_QUAD; 17 | this.quadIndexBuffer = this.indexBuffer; 18 | this.triangleIndexBuffer = gl.createBuffer(); 19 | 20 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.triangleIndexBuffer); 21 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.triangleIndices, gl.STATIC_DRAW); 22 | }; 23 | 24 | var oldWebGLFastSpriteBatchDestroy = PIXI.WebGLFastSpriteBatch.prototype.destroy; 25 | PIXI.WebGLFastSpriteBatch.prototype.destroy = function() { 26 | this.triangleIndices = null; 27 | this.gl.deleteBuffer(this.triangleIndexBuffer); 28 | oldWebGLFastSpriteBatchDestroy.call(this); 29 | } 30 | 31 | Object.defineProperties(PIXI.WebGLFastSpriteBatch.prototype,{ 32 | batchType : { 33 | get : function() { return this._batchType; }, 34 | set : function(v) { 35 | if (v === this._batchType) { 36 | return; 37 | } 38 | this.stop(); 39 | // 切换IndexBuffer,Size 40 | if (v === qc.BATCH_TRIANGLES) { 41 | this.size = this.triangleSize; 42 | this.indexBuffer = this.triangleIndexBuffer; 43 | this._batchType = v; 44 | this.batchIndexNumber = 3; 45 | } 46 | else { 47 | this.size = this.quadSize; 48 | this.indexBuffer = this.quadIndexBuffer; 49 | this._batchType = v; 50 | this.batchIndexNumber = 6; 51 | } 52 | this.start(); 53 | } 54 | } 55 | }); 56 | 57 | PIXI.WebGLFastSpriteBatch.prototype.flush = function() 58 | { 59 | // If the batch is length 0 then return as there is nothing to draw 60 | if (this.currentBatchSize===0)return; 61 | 62 | var gl = this.gl; 63 | 64 | // bind the current texture 65 | 66 | if(!this.currentBaseTexture._glTextures[gl.id])this.renderSession.renderer.updateTexture(this.currentBaseTexture, gl); 67 | 68 | gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); 69 | 70 | // upload the verts to the buffer 71 | 72 | if(this.currentBatchSize > ( this.size * 0.5 ) ) 73 | { 74 | gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); 75 | } 76 | else 77 | { 78 | var view = this.vertices.subarray(0, this.currentBatchSize * 4 * this.vertSize); 79 | 80 | gl.bufferSubData(gl.ARRAY_BUFFER, 0, view); 81 | } 82 | //gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.batchIndexNumber === 3 ? this.triangleIndexBuffer : this.indexBuffer); 83 | // now draw those suckas! 84 | gl.drawElements(gl.TRIANGLES, this.currentBatchSize * this.batchIndexNumber, gl.UNSIGNED_SHORT, 0); 85 | 86 | // then reset the batch! 87 | this.currentBatchSize = 0; 88 | 89 | // increment the draw count 90 | this.renderSession.drawCount++; 91 | }; -------------------------------------------------------------------------------- /src/loader/ExcelAsset.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenqx 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 表格资源 8 | * 9 | * @class qc.ExcelAsset 10 | * @constructor 11 | * @internal 12 | */ 13 | var ExcelAsset = qc.ExcelAsset = function(key, url, data, meta) { 14 | /** 15 | * @property {string} key - 图集的标志 16 | * @readonly 17 | */ 18 | this.key = url; 19 | 20 | /** 21 | * @property {string} url - 资源的网址 22 | * @readonly 23 | */ 24 | this.url = url; 25 | 26 | /** 27 | * @property {{}} meta - meta数据 28 | * @private 29 | */ 30 | this._meta = meta; 31 | 32 | /** 33 | * @property {{}} _data - 原始表格数据 34 | * @private 35 | */ 36 | this._data = typeof data === 'string' ? JSON.parse(data) : data; 37 | 38 | /** 39 | * @property {{}} _tables - 整理后的表格数据 40 | * @private 41 | */ 42 | this._sheets = {}; 43 | 44 | // 构建表格数据 45 | this._makeSheetData(); 46 | }; 47 | ExcelAsset.prototype.constructor = ExcelAsset; 48 | 49 | Object.defineProperties(ExcelAsset.prototype, { 50 | /** 51 | * @property {string} uuid - 资源唯一标识符 52 | * @readonly 53 | */ 54 | uuid : { 55 | get : function() { return this.meta.uuid; } 56 | }, 57 | 58 | /** 59 | * @property {[string]} sheetsName - 获取所有的表名 60 | * @readonly 61 | */ 62 | sheetsName : { 63 | get : function() { return this._sheets ? Object.keys(this._sheets) : []; } 64 | }, 65 | 66 | /** 67 | * @property {{}} - sheets - 获取所有表数据 68 | * @readonly 69 | */ 70 | sheets : { 71 | get : function() { return this._sheets; } 72 | }, 73 | 74 | /** 75 | * @property {{}} meta - 元数据 76 | * @readonly 77 | */ 78 | meta : { 79 | get : function() { return this._meta; } 80 | } 81 | }); 82 | 83 | /** 84 | * 生成表格数据 85 | * @private 86 | */ 87 | ExcelAsset.prototype._makeSheetData = function() { 88 | var sheetsName = this._data ? Object.keys(this._data) : []; 89 | for (var i = 0; i < sheetsName.length; i++) { 90 | var sheetName = sheetsName[i]; 91 | var rows = this._data[sheetName].rows; 92 | var cols = this._data[sheetName].cols; 93 | var primaryKey = this._meta[sheetName] ? (this._meta[sheetName].primaryKey || []) : []; 94 | var sheetData = new qc.ExcelSheet(cols, rows, primaryKey); 95 | this._sheets[sheetName] = sheetData; 96 | } 97 | }; 98 | 99 | /** 100 | * 通过名字获取一个表格的所有数据 101 | * @param name {string} - 表单名字 102 | */ 103 | ExcelAsset.prototype.findSheet = function(name) { 104 | return this.sheets[name]; 105 | }; 106 | 107 | /** 108 | * 释放excel资源 109 | * @param game 110 | * @internal 111 | */ 112 | ExcelAsset.prototype.unload = function(game) { 113 | // do nothing 114 | }; 115 | 116 | /** 117 | * Excel的日期时间与javascript时间起点间的差值 118 | * @type {number} 119 | * @constant 120 | * @private 121 | */ 122 | ExcelAsset._EXCEL_DATE_OFF = -2208988800000; // new Date('1900-1-1') - new Date('1970-1-1'); 123 | 124 | /** 125 | * 当前时区的偏移毫秒数 126 | * @type {number} 127 | * @constant 128 | * @private 129 | */ 130 | ExcelAsset._TIMEZONE_OFF = new Date().getTimezoneOffset() * 60 * 1000; 131 | 132 | /** 133 | * excel的日期类型是从1900年开始,使用时需要进行转化 134 | * @param number {Number} - excel的时间数值 135 | * @return {Date} - javascript的时间 136 | */ 137 | ExcelAsset.parseToDate = function(number) { 138 | return new Date(ExcelAsset._EXCEL_DATE_OFF + number * 86400000 + ExcelAsset._TIMEZONE_OFF); 139 | }; 140 | -------------------------------------------------------------------------------- /src/core/PhaserGame.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author wudm 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | 7 | /** 8 | * Called by the Stage visibility handler. 9 | * 10 | * @method Phaser.Game#gamePaused 11 | * @param {object} event - The DOM event that caused the game to pause, if any. 12 | * @protected 13 | */ 14 | Phaser.Game.prototype.gamePaused = function (event) { 15 | 16 | // If the game is already paused it was done via game code, so don't re-pause it 17 | if (!this._paused) 18 | { 19 | this._paused = true; 20 | this.time.gamePaused(); 21 | this.sound.setMute(); 22 | this.onPause.dispatch(event); 23 | 24 | // Avoids Cordova iOS crash event: https://github.com/photonstorm/phaser/issues/1800 25 | if (this.device.cordova && this.device.iOS) 26 | { 27 | this.lockRender = true; 28 | } 29 | } 30 | 31 | }; 32 | 33 | /** 34 | * Called by the Stage visibility handler. 35 | * 36 | * @method Phaser.Game#gameResumed 37 | * @param {object} event - The DOM event that caused the game to pause, if any. 38 | * @protected 39 | */ 40 | Phaser.Game.prototype.gameResumed = function (event) { 41 | 42 | // Game is paused, but wasn't paused via code, so resume it 43 | if (this._paused && !this._codePaused) 44 | { 45 | this._paused = false; 46 | this.time.gameResumed(); 47 | this.input.reset(); 48 | this.sound.unsetMute(); 49 | this.onResume.dispatch(event); 50 | 51 | // Avoids Cordova iOS crash event: https://github.com/photonstorm/phaser/issues/1800 52 | if (this.device.cordova && this.device.iOS) 53 | { 54 | this.lockRender = false; 55 | } 56 | } 57 | 58 | }; 59 | 60 | // TODO: hack Phaser.Game 中 parseConfig 方法,其 antialias 默认值为 true,且判断是写成 61 | // if (config['antialias']) ... 导致我们 config 中的 antialias 设置为 false 不被接受 62 | /** 63 | * Parses a Game configuration object. 64 | * 65 | * @method Phaser.Game#parseConfig 66 | * @protected 67 | */ 68 | var phaserGameParseConfig = Phaser.Game.prototype.parseConfig; 69 | Phaser.Game.prototype.parseConfig = function(config) { 70 | // 返回原有函数进行继续处理 71 | phaserGameParseConfig.call(this, config); 72 | 73 | // hack start 74 | // 设置 antialias 75 | if ('antialias' in config) { 76 | this.antialias = !!config['antialias']; 77 | } 78 | // hack end 79 | }; 80 | 81 | // hack Phaser.RequestAnimationFrame 82 | // 原版中主循环调度没有捕获错误,这里加上 83 | var phaser_updateSetTimeout = Phaser.RequestAnimationFrame.prototype.updateSetTimeout; 84 | Phaser.RequestAnimationFrame.prototype.updateSetTimeout = function() { 85 | try { 86 | phaser_updateSetTimeout.call(this); 87 | } 88 | catch (e) { 89 | this.game._qc.log.error('Error:{0}', e); 90 | } 91 | }; 92 | var phaser_updateRAF = Phaser.RequestAnimationFrame.prototype.updateRAF; 93 | Phaser.RequestAnimationFrame.prototype.updateRAF = function(rafTime) { 94 | try { 95 | phaser_updateRAF.call(this, rafTime); 96 | } 97 | catch (e) { 98 | this.game._qc.log.error('Error:{0}', e); 99 | } 100 | }; 101 | 102 | // 用来提供实际每帧的间隔 103 | Phaser.Game.prototype.updateFrameDelta = function(fixedFrameDelta) { 104 | var self = this, 105 | time = self.time; 106 | var currTime = time.time; 107 | var diff = self.__lastFrameTime ? (currTime - self.__lastFrameTime) : fixedFrameDelta; 108 | self.__lastFrameTime = currTime; 109 | time.frameDeltaTime = diff / time.slowMotion; 110 | time._totalEscapeTime = time.frameDeltaTime + (time._totalEscapeTime || 0); 111 | }; 112 | -------------------------------------------------------------------------------- /src/core/Stage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 舞台,控制所有游戏元素的根节点。 8 | * 9 | * @class qc.Stage 10 | * @param {Phaser.Stage} phaser 11 | * @internal 12 | * @constructor 13 | */ 14 | var Stage = qc.Stage = function(phaser) { 15 | this.phaser = phaser; 16 | phaser._qc = this; 17 | }; 18 | 19 | Stage.prototype = {}; 20 | Stage.prototype.constructor = Stage; 21 | 22 | Object.defineProperties(Stage.prototype, { 23 | /** 24 | * @proeprty {qc.Game} game 25 | * @readonly 26 | */ 27 | 'game' : { 28 | get : function() { return this.phaser.game._qc; } 29 | }, 30 | 31 | /** 32 | * @property {String} name - 舞台标识 33 | * @default '_stage_root' 34 | */ 35 | 'name' : { 36 | get : function() { return this.phaser.name; }, 37 | set : function(v) { this.phaser.name = v; } 38 | }, 39 | 40 | /** 41 | * property {boolean} runInBackground - 是不是在后台运行 42 | * @default true 43 | */ 44 | runInBackground : { 45 | get : function() { return this.phaser.disableVisibilityChange; }, 46 | set : function(v) { this.phaser.disableVisibilityChange = v; } 47 | }, 48 | 49 | 50 | /** 51 | * 背景颜色 52 | * @property {qc.Color} backgroundColor 53 | */ 54 | 'backgroundColor' : { 55 | get : function() { return new Color(this.phaser.backgroundColor); }, 56 | set : function(value) { 57 | value = value || Color.background; 58 | if (!(value instanceof Color)) 59 | throw new Error('Expected qc.Color'); 60 | this.phaser.backgroundColor = value.toNumber(); 61 | } 62 | }, 63 | 64 | /** 65 | * @property {number} x 66 | * 本地X坐标,永远为0 67 | * @readonly 68 | * @override 69 | */ 70 | 'x': { 71 | get: function() { 72 | return 0; 73 | } 74 | }, 75 | 76 | /** 77 | * @property {number} x 78 | * 本地X坐标,永远为0 79 | * @readonly 80 | * @override 81 | */ 82 | 'y': { 83 | get: function() { 84 | return 0; 85 | } 86 | }, 87 | 88 | /** 89 | * @property {qc.Rectangle} rect - 矩形框(相对于父亲节点) 90 | * @readonly 91 | * @override 92 | */ 93 | 'rect' : { 94 | get : function() { 95 | return new qc.Rectangle(0, 0, this.game.width, this.game.height); 96 | } 97 | }, 98 | 99 | /** 100 | * @property {number} pivotX - 节点自身的原点X位置 101 | * @override 102 | * @readonly 103 | */ 104 | pivotX : { 105 | get : function() { return 0; }, 106 | set : function(v) { throw new Error('pivotX cannot be modified'); } 107 | }, 108 | 109 | /** 110 | * @property {number} pivotY - 节点自身的原点Y位置 111 | * @override 112 | * @readonly 113 | */ 114 | pivotY : { 115 | get : function() { return 0; }, 116 | set : function(v) { throw new Error('pivotY cannot be modified'); } 117 | }, 118 | 119 | /** 120 | * @property {qc.Matrix} worldTransform - 自身在世界的变形矩阵 121 | * @protected 122 | * @readonly 123 | */ 124 | worldTransform : { 125 | get : function() { 126 | return this.phaser.worldTransform; 127 | } 128 | } 129 | }); 130 | 131 | /** 132 | * 更新列表中所有的transforms 133 | * 134 | * @method qc.Stage#updateTransform 135 | */ 136 | Stage.prototype.updateTransform = function() { 137 | this.phaser.updateTransform(); 138 | } 139 | 140 | /** 141 | * 销毁舞台 142 | * 143 | * @method qc.Stage#destroy 144 | */ 145 | Stage.prototype.destroy = function() { 146 | this.phaser.destroy(); 147 | delete this.phaser; 148 | } 149 | -------------------------------------------------------------------------------- /src/components/DebugViewer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 调试信息查看器 8 | * @class qc.DebugViewer 9 | */ 10 | var DebugViewer = defineBehaviour('qc.DebugViewer', qc.Behaviour, function() { 11 | var self = this; 12 | 13 | // 调度次数,开始计算的时间点等 14 | self.count = 1; 15 | self.now = self.game.time.now; 16 | self.runInEditor = true; 17 | 18 | // 多久统计1次,单位为秒 19 | self.duration = 1; 20 | 21 | // 默认不显示详细信息 22 | self.detail = false; 23 | }, 24 | { 25 | debugOn: qc.Serializer.BOOLEAN, 26 | duration: qc.Serializer.NUMBER, 27 | detail: qc.Serializer.BOOLEAN 28 | } 29 | ); 30 | 31 | // 菜单上的显示 32 | DebugViewer.__menu = 'Debug/DebugViewer'; 33 | 34 | Object.defineProperties(DebugViewer.prototype, { 35 | /** 36 | * @property {boolean} debugOn - 调试开关是否开启 37 | */ 38 | debugOn: { 39 | get: function() { return this.game.debug.on; }, 40 | set: function(v) { this.game.debug.on = v; } 41 | } 42 | }); 43 | 44 | DebugViewer.prototype.postUpdate = function() { 45 | var debug = this.game.debug; 46 | var now = this.game.time.now; 47 | if (now - this.now >= this.duration * 1000) { 48 | // 超过1s,进行计算 49 | var frame = this.count * 1000 / (now - this.now); 50 | var preUpdate = (debug.preUpdate / this.count).toFixed(1); 51 | var update = (debug.update / this.count).toFixed(1); 52 | var postUpdate = (debug.postUpdate / this.count).toFixed(1); 53 | var logic = (debug.logic / this.count).toFixed(1); 54 | var render = (debug.render / this.count).toFixed(1); 55 | var total = (debug.total / this.count).toFixed(1); 56 | 57 | var drawCalls = this.game.phaser.renderer.renderSession.drawCount; 58 | if (drawCalls == null) { 59 | drawCalls = '(N/A)'; 60 | } 61 | 62 | var wtCalcCount = this.game.phaser._calcTransformCount; 63 | 64 | var text = 65 | 'FPS: ' + frame.toFixed(1) + '\n' + 66 | 'Draw Calls: ' + drawCalls + '\n' + 67 | 'Total: ' + total + ' ms\n' + 68 | 'Logic: ' + logic + ' ms\n' + 69 | 'Render: ' + render + ' ms\n' + 70 | 'PreUpdate: ' + preUpdate + ' ms\n' + 71 | 'Update: ' + update + ' ms\n' + 72 | 'PostUpdate: ' + postUpdate + ' ms\n' + 73 | 'TransformCalc: ' + wtCalcCount + ''; 74 | 75 | if (this.detail) { 76 | var renderType = 'Canvas'; 77 | if (this.game.phaser.renderType === Phaser.WEBGL) 78 | { 79 | renderType = 'WebGL'; 80 | } 81 | else if (this.game.phaser.renderType == Phaser.HEADLESS) 82 | { 83 | renderType = 'Headless'; 84 | } 85 | text += '\n------------\n' + 86 | 'resolution=' + this.game.phaser.resolution + '\n' + 87 | 'devicePixelRatio=' + window.devicePixelRatio + '\n' + 88 | 'size=' + this.game.width + '*' + this.game.height + '\n' + 89 | 'renderType=' + renderType + '\n' + 90 | 'antialias=' + this.game.antialias; 91 | } 92 | 93 | if (this.gameObject instanceof qc.UIText) 94 | this.gameObject.text = text; 95 | else if (this.gameObject instanceof qc.Dom) { 96 | text = text.replace(/\n/g, '
'); 97 | this.gameObject.innerHTML = text; 98 | } 99 | 100 | // 重置下 101 | this.count = 1; 102 | this.now = now; 103 | debug.total = 0; 104 | debug.logic = 0; 105 | debug.preUpdate = 0; 106 | debug.update = 0; 107 | debug.postUpdate = 0; 108 | debug.render = 0; 109 | } 110 | else { 111 | this.count++; 112 | } 113 | }; 114 | -------------------------------------------------------------------------------- /src/components/AspectRatioFitter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * Resizes a RectTransform to fit a specified aspect ratio. 8 | * @class qc.AspectRatioFitter 9 | */ 10 | var AspectRatioFitter = defineBehaviour('qc.AspectRatioFitter', qc.Behaviour, function() { 11 | var self = this; 12 | self.mode = AspectRatioFitter.NONE; 13 | self.ratio = 1; 14 | 15 | self.runInEditor = true; 16 | }, { 17 | mode : qc.Serializer.NUMBER, 18 | ratio : qc.Serializer.NUMBER 19 | }); 20 | AspectRatioFitter.__menu = 'UI/AspectRatioFitter'; 21 | 22 | Object.defineProperties(AspectRatioFitter.prototype,{ 23 | /** 24 | * @property {number} mode - mode to resize the node: 25 | * AspectRatioFitter.NONE 26 | * AspectRatioFitter.WIDTH_CONTROLS_HEIGHT 27 | * AspectRatioFitter.HEIGHT_CONTROLS_WIDTH 28 | * AspectRatioFitter.FIT_IN_PARENT 29 | * AspectRatioFitter.ENVELOPE_PARENT 30 | */ 31 | mode : { 32 | get : function() { return this._mode || AspectRatioFitter.NONE; }, 33 | set : function(v) { 34 | if (this.mode === v) return; 35 | this._mode = v; 36 | this._reset(); 37 | } 38 | }, 39 | 40 | /** 41 | * @property {number} ratio - ratio = width/height 42 | */ 43 | ratio : { 44 | get : function() { return this._ratio || 1; }, 45 | set : function(v) { 46 | if (v <= 0) v = 0.001; 47 | if (this.ratio === v) return; 48 | this._ratio = v; 49 | this._reset(); 50 | } 51 | } 52 | }); 53 | 54 | /** 55 | * Four modes to resize the node 56 | * @type {number} 57 | */ 58 | AspectRatioFitter.NONE = 0; 59 | AspectRatioFitter.WIDTH_CONTROLS_HEIGHT = 1; 60 | AspectRatioFitter.HEIGHT_CONTROLS_WIDTH = 2; 61 | AspectRatioFitter.FIT_IN_PARENT = 3; 62 | AspectRatioFitter.ENVELOPE_PARENT = 4; 63 | 64 | /** 65 | * When the target node is initialized, resize it immediately 66 | */ 67 | AspectRatioFitter.prototype.awake = function() { 68 | var self = this; 69 | self._reset(); 70 | 71 | // When the target node transform is changed, resize it. 72 | var node = self.gameObject; 73 | self.addListener(node.onRelayout, function() { 74 | self._reset(); 75 | }); 76 | }; 77 | /** 78 | * Resize width and height of the target node by AspectRatioFitter mode. 79 | * @private 80 | */ 81 | AspectRatioFitter.prototype._reset = function() { 82 | var self = this; 83 | if (self.mode === AspectRatioFitter.NONE) return; 84 | var node = self.gameObject; 85 | 86 | if (self.mode === AspectRatioFitter.WIDTH_CONTROLS_HEIGHT) { 87 | node.height = node.width / self.ratio; 88 | return; 89 | } 90 | if (self.mode === AspectRatioFitter.HEIGHT_CONTROLS_WIDTH) { 91 | node.width = node.height * self.ratio; 92 | return; 93 | } 94 | 95 | // Resize by parent's rect 96 | var rect = node.parent.rect; 97 | node.setAnchor(new qc.Point(0, 0), new qc.Point(1, 1)); 98 | if (self.mode === AspectRatioFitter.FIT_IN_PARENT) { 99 | var w = rect.width; 100 | var h = w / self.ratio; 101 | if (h > rect.height) { 102 | h = rect.height; 103 | w = h * self.ratio; 104 | } 105 | node.setStretch((rect.width - w) / 2, (rect.width - w) / 2, 106 | (rect.height - h) / 2, (rect.height - h) / 2); 107 | return; 108 | } 109 | 110 | if (self.mode === AspectRatioFitter.ENVELOPE_PARENT) { 111 | var w = rect.width; 112 | var h = w / self.ratio; 113 | if (h < rect.height) { 114 | h = rect.height; 115 | w = h * self.ratio; 116 | } 117 | node.setStretch((rect.width - w) / 2, (rect.width - w) / 2, 118 | (rect.height - h) / 2, (rect.height - h) / 2); 119 | return; 120 | } 121 | }; 122 | -------------------------------------------------------------------------------- /src/filter/Glow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author lijh 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | * https://github.com/pixijs/pixi-extra-filters/blob/master/src/filters/glow/GlowFilter.js 5 | */ 6 | 7 | /** 8 | * 外发光 9 | */ 10 | var Glow = defineFilter('qc.Filter.Glow', qc.Filter, function(game) { 11 | this.distance = 40; 12 | this.outerStrength = 1.5; 13 | this.innerStrength = 1; 14 | this.glowColor = [1, 0, 0]; 15 | 16 | this.pixelWidth = 1 / game.phaser.renderer.width; 17 | this.pixelHeight = 1 / game.phaser.renderer.height; 18 | 19 | this._updateFragmentSrc(); 20 | 21 | // 指定 glowColor 属性的自定义显示类型 22 | this.registerCustomInspector('glowColor', qc.Color); 23 | }, { 24 | distance: qc.Filter.F1, 25 | outerStrength: qc.Filter.F1, 26 | innerStrength: qc.Filter.F1, 27 | glowColor: qc.Filter.F3V 28 | }); 29 | 30 | Object.defineProperty(Glow.prototype, 'distance', { 31 | get: function() { 32 | return this._distance; 33 | }, 34 | set: function(value) { 35 | this._distance = value; 36 | this._updateFragmentSrc(); 37 | 38 | // 清空shader,之后会重新生成 39 | this.shaders = []; 40 | } 41 | }); 42 | 43 | /** 44 | * 更新片段着色器 45 | */ 46 | Glow.prototype._updateFragmentSrc = function() { 47 | this.fragmentSrc = [ 48 | 'precision mediump float;', 49 | 'varying vec2 vTextureCoord;', 50 | 'uniform sampler2D texture;', 51 | 'uniform float distance;', 52 | 'uniform float outerStrength;', 53 | 'uniform float innerStrength;', 54 | 'uniform vec3 glowColor;', 55 | 'uniform float pixelWidth;', 56 | 'uniform float pixelHeight;', 57 | 'vec2 px = vec2(' + this.pixelWidth + ', ' + this.pixelHeight + ');', 58 | 'void main(void) {', 59 | ' const float PI = 3.14159265358979323846264;', 60 | ' vec4 ownColor = texture2D(texture, vTextureCoord);', 61 | ' vec4 curColor;', 62 | ' float totalAlpha = 0.;', 63 | ' float maxTotalAlpha = 0.;', 64 | ' float offset = 0.;', 65 | ' for (float curDistance = 0.; curDistance <= ' + this.distance.toFixed(7) + '; curDistance++) {', 66 | ' offset = curDistance - distance / 2.;', 67 | 68 | ' curColor = texture2D(texture, vec2(vTextureCoord.x + offset * px.x, vTextureCoord.y));', 69 | ' totalAlpha += (distance - curDistance) * curColor.a;', 70 | ' maxTotalAlpha += (distance - curDistance);', 71 | 72 | ' curColor = texture2D(texture, vec2(vTextureCoord.x, vTextureCoord.y + offset * px.y));', 73 | ' totalAlpha += (distance - curDistance) * curColor.a;', 74 | ' maxTotalAlpha += (distance - curDistance);', 75 | 76 | ' curColor = texture2D(texture, vec2(vTextureCoord.x + cos(PI * 0.25) * offset * px.x, vTextureCoord.y + sin(PI * 0.25) * offset * px.y));', 77 | ' totalAlpha += (distance - curDistance) * curColor.a;', 78 | ' maxTotalAlpha += (distance - curDistance);', 79 | 80 | ' curColor = texture2D(texture, vec2(vTextureCoord.x + cos(PI * 0.75) * offset * px.x, vTextureCoord.y + sin(PI * 0.75) * offset * px.y));', 81 | ' totalAlpha += (distance - curDistance) * curColor.a;', 82 | ' maxTotalAlpha += (distance - curDistance);', 83 | ' }', 84 | ' maxTotalAlpha = max(maxTotalAlpha, 0.0001);', 85 | 86 | ' ownColor.a = max(ownColor.a, 0.0001);', 87 | ' ownColor.rgb = ownColor.rgb / ownColor.a;', 88 | ' float outerGlowAlpha = (totalAlpha / maxTotalAlpha) * outerStrength * (1. - ownColor.a);', 89 | ' float innerGlowAlpha = ((maxTotalAlpha - totalAlpha) / maxTotalAlpha) * innerStrength * ownColor.a;', 90 | ' float resultAlpha = (ownColor.a + outerGlowAlpha);', 91 | ' gl_FragColor = vec4(mix(mix(ownColor.rgb, glowColor, innerGlowAlpha / ownColor.a), glowColor.rgb, outerGlowAlpha / resultAlpha) * resultAlpha, resultAlpha);', 92 | '}' 93 | ]; 94 | }; -------------------------------------------------------------------------------- /src/core/State.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 场景的基类 8 | * 同时提供了一些常用功能的快速访问接口 9 | * 10 | * @class qc.State 11 | * @constructor 12 | */ 13 | var State = qc.State = function() { 14 | // 建立代理对象的关联 15 | var phaser = new Phaser.State(); 16 | this.phaser = phaser; 17 | phaser._qc = this; 18 | } 19 | State.prototype = {}; 20 | State.prototype.constructor = State; 21 | 22 | Object.defineProperties(State.prototype, { 23 | /** 24 | * @property {qc.Game} game - 游戏实例的引用 25 | * @readonly 26 | */ 27 | 'game' : { 28 | get : function() { return this.phaser.game; } 29 | }, 30 | 31 | /** 32 | * @property {String} key - 场景的唯一标识符 33 | */ 34 | 'key' : { 35 | get : function() { return this.phaser.key; }, 36 | set : function(v) { this.phaser.key = v; } 37 | }, 38 | 39 | /** 40 | * @property {qc.GameObjectFactory} add 41 | */ 42 | 'add' : { 43 | get : function() { return this.phaser.add._qc; }, 44 | set : function(v) { 45 | this.phaser.add = v.phaser; 46 | v.phaser._qc = v; 47 | } 48 | }, 49 | 50 | /** 51 | * @property {qc.GameObjectCreator} make 52 | */ 53 | 'make' : { 54 | get : function() { return this.phaser.make._qc; }, 55 | set : function(v) { 56 | this.phaser.make = v.phaser; 57 | v.phaser._qc = v; 58 | } 59 | }, 60 | 61 | /** 62 | * @property {qc.Camera} camera 63 | */ 64 | 'camera' : { 65 | get : function() { return this.phaser.camera._qc; }, 66 | set : function(v) { 67 | this.phaser.camera = v.phaser; 68 | v.phaser._qc = v; 69 | } 70 | }, 71 | 72 | /** 73 | * @property {qc.Assets} assets - 资源管理接口 74 | */ 75 | 'assets' : { 76 | get : function() { return this._assets; }, 77 | set : function(v) { this._assets = v; } 78 | }, 79 | 80 | /** 81 | * @property {qc.Input} input - 输入管理 82 | */ 83 | 'input' : { 84 | get : function() { return this.phaser.input._qc; }, 85 | set : function(v) { 86 | this.phaser.input = v.phaser; 87 | v.phaser._qc = v; 88 | } 89 | }, 90 | 91 | /** 92 | * @property {qc.Math} math - 数学相关运算库 93 | */ 94 | 'math' : { 95 | get : function() { return this.phaser.math._qc; }, 96 | set : function(v) { 97 | this.phaser.math = v.phaser; 98 | v.phaser._qc = v; 99 | } 100 | }, 101 | 102 | /** 103 | * @property {qc.Time} time - 时间管理 104 | */ 105 | 'time' : { 106 | get : function() { return this.phaser.time._qc; }, 107 | set : function(v) { 108 | this.phaser.time = v.phaser; 109 | v.phaser._qc = v; 110 | } 111 | }, 112 | 113 | /** 114 | * @property {qc.TweenManager} tweens - 动画组件 115 | */ 116 | 'tweens' : { 117 | get : function() { return this.phaser.tweens._qc; }, 118 | set : function(v) { 119 | this.phaser.tweens = v.phaser; 120 | v.phaser._qc = v; 121 | } 122 | }, 123 | 124 | /** 125 | * @property {qc.World} world - 对应的游戏世界 126 | */ 127 | 'world' : { 128 | get : function() { 129 | if (!this.phaser.world) return null; 130 | return this.phaser.world._qc; 131 | }, 132 | set : function(v) { 133 | this.phaser.world = v.phaser; 134 | v.phaser._qc = v; 135 | } 136 | }, 137 | 138 | /** 139 | * @property {qc.Physics} physics - 使用的物理系统 140 | */ 141 | 'physics' : { 142 | get : function() { return this.phaser.physics._qc; }, 143 | set : function(v) { 144 | this.phaser.physics = v.phaser; 145 | v.phaser._qc = v; 146 | } 147 | } 148 | }); 149 | -------------------------------------------------------------------------------- /src/hack/core/Group.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * hackpp 8 | * 覆盖掉原来phaser的帧调度 9 | */ 10 | 11 | /** 12 | * The core preUpdate - as called by World. 13 | * @method Phaser.Group#preUpdate 14 | * @protected 15 | */ 16 | Phaser.Group.prototype.preUpdate = function () { 17 | var qc = this._qc; 18 | if (qc && qc.static) return true; 19 | 20 | if (qc) { 21 | if (qc.preUpdate) qc.preUpdate(); 22 | 23 | // 脚本调度 24 | var scripts = qc.scripts; 25 | var i = scripts.length; 26 | while (i--) { 27 | var script = scripts[i]; 28 | if (!script || !script._enable || !script.__hadUpdateOrRender || !script.preUpdate) continue; 29 | 30 | // 如果当前处于editor模式,并且本脚本没有说明是在editor模式下运行,就不要调度了 31 | if (qc.game.device.editor === true && script.runInEditor !== true) continue; 32 | 33 | // 调度之 34 | script.preUpdate(); 35 | 36 | // 节点在脚本中析构了,就不继续调度了 37 | if (!this.visible) return; 38 | } 39 | } 40 | var children = this.children; 41 | var i = children.length; 42 | while (i--) 43 | { 44 | if (!children[i]) continue; 45 | if (children[i].visible) { 46 | children[i].preUpdate(); 47 | } 48 | else { 49 | children[i].renderOrderID = -1; 50 | } 51 | } 52 | 53 | return true; 54 | }; 55 | 56 | /** 57 | * The core update - as called by World. 58 | * @method Phaser.Group#update 59 | * @protected 60 | */ 61 | Phaser.Group.prototype.update = function () { 62 | var qc = this._qc; 63 | if (qc && qc.static) return true; 64 | 65 | if (qc) { 66 | if (qc.update) qc.update(); 67 | 68 | // 脚本调度 69 | var scripts = qc.scripts; 70 | var i = scripts.length; 71 | while (i--) { 72 | var script = scripts[i]; 73 | if (!script || !script._enable || !script.__hadUpdateOrRender || !script.update) continue; 74 | 75 | // 如果当前处于editor模式,并且本脚本没有说明是在editor模式下运行,就不要调度了 76 | if (qc.game.device.editor === true && script.runInEditor !== true) continue; 77 | 78 | // 调度之 79 | script.update(); 80 | 81 | // 节点在脚本中析构了,就不继续调度了 82 | if (!this.visible) return; 83 | } 84 | } 85 | 86 | var children = this.children; 87 | var i = children.length; 88 | while (i--) 89 | { 90 | if (children[i] && children[i].visible) 91 | children[i].update(); 92 | } 93 | }; 94 | 95 | /** 96 | * The core postUpdate - as called by World. 97 | * @method Phaser.Group#postUpdate 98 | * @protected 99 | */ 100 | Phaser.Group.prototype.postUpdate = function () { 101 | // Fixed to Camera? 102 | if (this.fixedToCamera) 103 | { 104 | this.x = this.game.camera.view.x + this.cameraOffset.x; 105 | this.y = this.game.camera.view.y + this.cameraOffset.y; 106 | } 107 | 108 | var qc = this._qc; 109 | if (qc && qc.static) return; 110 | 111 | if (qc) { 112 | if (qc.postUpdate) qc.postUpdate(); 113 | 114 | // 脚本调度 115 | var scripts = qc.scripts; 116 | var i = scripts.length; 117 | while (i--) { 118 | var script = scripts[i]; 119 | if (!script || !script._enable || !script.__hadUpdateOrRender || !script.postUpdate) continue; 120 | 121 | // 如果当前处于editor模式,并且本脚本没有说明是在editor模式下运行,就不要调度了 122 | if (qc.game.device.editor === true && script.runInEditor !== true) continue; 123 | 124 | // 调度之 125 | script.postUpdate(); 126 | 127 | // 节点在脚本中析构了,就不继续调度了 128 | if (!this.visible) return; 129 | } 130 | } 131 | 132 | var children = this.children; 133 | var i = children.length; 134 | while (i--) 135 | { 136 | if (children[i] && children[i].visible) 137 | children[i].postUpdate(); 138 | } 139 | }; 140 | -------------------------------------------------------------------------------- /src/components/Animator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenx 3 | * @date 2015.12.23 4 | * copyright 2015 Qcplay All Rights Reserved. 5 | * 6 | * Animator 脚本组件 7 | */ 8 | 9 | // qc.ActionManager类定义 10 | var Animator = defineBehaviour('qc.Animator', qc.Behaviour, function() { 11 | var self = this; 12 | 13 | // Animator 资源映射(包含 action 和 actionManager 两种资源) 14 | self.animatorMap = {}; 15 | self.animatorList = []; 16 | 17 | // 记录 action 或 actionManager 资源列表 18 | self.animators = null; 19 | 20 | self.runInEditor = true; 21 | },{ 22 | animators : qc.Serializer.ANIMATORS 23 | }); 24 | 25 | // 菜单上的显示 26 | Animator.__menu = 'Action/Animator'; 27 | 28 | Object.defineProperties(Animator.prototype, { 29 | // 设置 animators,解析 animators 资源,创建 action 或 actionManager 对象映射 30 | animators : { 31 | get : function() { return this._animators; }, 32 | set : function(v) { 33 | for (var i = 0; i < this.animatorList.length; i++) 34 | { 35 | var animator = this.animatorList[i]; 36 | if (animator) 37 | animator.destroy(); 38 | } 39 | this.animatorMap = {}; 40 | this.animatorList = []; 41 | 42 | this._animators = v; 43 | if (!v) 44 | return; 45 | 46 | for (var i = 0; i < v.length; i++) 47 | { 48 | var asset = v[i]; 49 | if (!asset) 50 | continue; 51 | 52 | // 还原出 action 或 actionManager 对象 53 | if (asset instanceof qc.ActionManagerAsset) 54 | this.animatorList[i] = qc.ActionManager.restoreBundle(asset, this.game, !this.game.serializer.isRestoring); 55 | else if (asset instanceof qc.ActionAsset) 56 | this.animatorList[i] = qc.Action.restoreBundle(asset, this.game, !this.game.serializer.isRestoring); 57 | 58 | if (!this.animatorList[i].targetLocked) 59 | // 对象不锁定目标,则将脚本挂载对象作为 animator 的目标对象 60 | this.animatorList[i].targetObject = this.gameObject; 61 | 62 | var name = this.animatorList[i].name; 63 | if (this.animatorMap[name]) 64 | this.gameObject.game.log.error('Exist duplicate action\'s name: {0}', name); 65 | this.animatorMap[name] = this.animatorList[i]; 66 | } 67 | } 68 | }, 69 | }); 70 | 71 | // 初始化 72 | Animator.prototype.awake = function() { 73 | 74 | if (this.animatorList.length < 1) 75 | return; 76 | 77 | for (var i = 0; i < this.animatorList.length; i++) 78 | if (this.animatorList[i]) 79 | this.animatorList[i].awake(); 80 | }; 81 | 82 | // 帧调度 83 | Animator.prototype.update = function() { 84 | 85 | for (var i = 0; i < this.animatorList.length; i++) 86 | { 87 | var animator = this.animatorList[i]; 88 | if (!animator || !animator.isRunning) 89 | continue; 90 | 91 | // 更新 action 92 | animator.update(); 93 | } 94 | }; 95 | 96 | // 根据名字取得 action 对象 97 | Animator.prototype.getAction = function(nameOrIndex) { 98 | return this.animatorMap[nameOrIndex] || this.animatorList[nameOrIndex]; 99 | } 100 | 101 | // 开始播放 102 | Animator.prototype.play = function(nameOrIndex, targetObject, fromBegin) { 103 | 104 | nameOrIndex = nameOrIndex || 0; 105 | var animator = this.getAction(nameOrIndex); 106 | if (!animator) 107 | return; 108 | 109 | targetObject = targetObject || this.gameObject; 110 | fromBegin = typeof(fromBegin) === 'boolean' ? fromBegin : true; 111 | animator.playAction(targetObject, fromBegin); 112 | }; 113 | 114 | // 停止播放 115 | Animator.prototype.stop = function(nameOrIndex) { 116 | nameOrIndex = nameOrIndex || 0; 117 | var animator = this.getAction(nameOrIndex); 118 | if (!animator) 119 | return; 120 | 121 | animator.stop(); 122 | } 123 | 124 | // 移除组件 125 | Animator.prototype.destroy = function() { 126 | this.animators = null; 127 | qc.Behaviour.prototype.destroy.call(this); 128 | }; 129 | -------------------------------------------------------------------------------- /src/loader/Atlas.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 图集资源的描述 8 | * 9 | * @class qc.Atlas 10 | * @constructor 11 | * @internal 12 | */ 13 | var Atlas = qc.Atlas = function(key, url, data, meta, ani) { 14 | /** 15 | * @property {string} key - 图集的标志,直接使用资源的网址 16 | * @readonly 17 | */ 18 | this.key = url; 19 | 20 | /** 21 | * @property {string} url - 资源的网址 22 | * @readonly 23 | */ 24 | this.url = url; 25 | 26 | /** 27 | * @property {object} meta - meta数据 28 | * @readonly 29 | */ 30 | this.meta = meta; 31 | 32 | /** 33 | * @property {object} animation - 动作信息 34 | * @readonly 35 | */ 36 | this.animation = undefined; 37 | 38 | /** 39 | * @property {object} json - 图集的atlas数据 40 | * @internal 41 | */ 42 | this.json = undefined; 43 | 44 | /** 45 | * @property {Image} img - 图集对应的图片 46 | */ 47 | this.img = undefined; 48 | 49 | // 记录图集的数据 50 | this._data = data; 51 | 52 | // 解析动作信息 53 | if (ani) { 54 | this.animation = { 55 | type : meta.animationType, 56 | data : ani 57 | } 58 | } 59 | }; 60 | Atlas.prototype.constructor = Atlas; 61 | 62 | Object.defineProperties(Atlas.prototype, { 63 | /** 64 | * @property {number} count - 图片的数量 65 | * @readonly 66 | */ 67 | 'count' : { 68 | get : function() { return this._data.frameData.total; } 69 | }, 70 | 71 | /** 72 | * @property {Array} frames - 所有的图片信息 73 | * @readonly 74 | */ 75 | 'frames' : { 76 | get : function() { 77 | return this._data.frameData._frames; 78 | } 79 | }, 80 | 81 | /** 82 | * @property {Array} frameNames - 图片的名字列表 83 | * @readonly 84 | */ 85 | frameNames : { 86 | get : function() { 87 | var frames = this.frames; 88 | if (!frames || frames.length < 1) return [0]; 89 | var list = []; 90 | for (var i in frames) { 91 | list.push(frames[i].name); 92 | } 93 | return list; 94 | } 95 | }, 96 | 97 | /** 98 | * @property {string} uuid - 资源唯一标识符 99 | * @readonly 100 | */ 101 | uuid : { 102 | get : function() { return this.meta.uuid; } 103 | }, 104 | 105 | /** 106 | * @property {string} class - 类的名字 107 | * @internal 108 | */ 109 | class : { 110 | get : function() { return 'qc.Atlas'; } 111 | } 112 | }); 113 | 114 | /** 115 | * 根据名字或位置取得某个图片 116 | * 117 | * @method qc.Atlas#getFrame 118 | * @param frame {string|number} - 帧的位置或名字 119 | */ 120 | Atlas.prototype.getFrame = function(frame) { 121 | if (typeof frame === 'number') 122 | return this._data.frameData.getFrame(frame); 123 | return this._data.frameData.getFrameByName(frame); 124 | }; 125 | 126 | /** 127 | * Get the texture from atlas 128 | * @method qc.Atlas#getTexture 129 | * @param frame {string|number} - The name or index of the texture 130 | */ 131 | Atlas.prototype.getTexture = function(frame) { 132 | return new qc.Texture(this, frame); 133 | }; 134 | 135 | /** 136 | * 取得某个图片的9宫格信息 137 | * @param {string|undefined} frame 138 | * @return [left, top, right, bottom] 139 | */ 140 | Atlas.prototype.getPadding = function(frame) { 141 | if (!this.meta || !this.meta.padding) return [0, 0, 0, 0]; 142 | 143 | // 只有一个图片时,固定返回padding的内容 144 | if (this.count == 1) { 145 | var keys = Object.keys(this.meta.padding); 146 | frame = keys.length > 0 ? keys[0] : 0; 147 | } 148 | 149 | if (frame === undefined) frame = 0; 150 | var padding = this.meta.padding[frame]; 151 | if (padding) { 152 | // 确保为数字 153 | padding[0] *= 1; 154 | padding[1] *= 1; 155 | padding[2] *= 1; 156 | padding[3] *= 1; 157 | } 158 | return padding || [0, 0, 0, 0]; 159 | }; 160 | 161 | /** 162 | * 释放本资源信息 163 | * @internal 164 | */ 165 | Atlas.prototype.unload = function(game) { 166 | game.assets._cache.removeImage(this.key, false); 167 | 168 | delete PIXI.TextureCache[this.key]; 169 | delete PIXI.BaseTextureCache[this.key]; 170 | }; 171 | -------------------------------------------------------------------------------- /src/core/SoundManager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author luohj 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 声音管理器 8 | * 9 | * @class qc.SoundManager 10 | * @param {qc.Game} game - A reference to the currently running game. 11 | * @constructor 12 | * @internal 13 | */ 14 | var SoundManager = qc.SoundManager = function(game) { 15 | this.game = game; 16 | this.phaser = game.phaser.sound; 17 | this.phaser._qc = this; 18 | 19 | var self = this; 20 | game.onStart.add(function() { 21 | self._boot(); 22 | }); 23 | 24 | // 由编辑器生成的 sound duration 数据 25 | this._soundDurationMap = window.soundDurationMap || {}; 26 | }; 27 | SoundManager.prototype.constructor = SoundManager; 28 | 29 | // 初始化声音处理 30 | SoundManager.prototype._boot = function() { 31 | var phaserSound = this.phaser; 32 | var input = this.game.input; 33 | 34 | if (!window.__wx && !phaserSound.game.device.cocoonJS && phaserSound.game.device.iOS || (window['PhaserGlobal'] && window['PhaserGlobal'].fakeiOSTouchLock)) 35 | { 36 | input.touch.callbackContext = phaserSound; 37 | 38 | // iOS9下必须在touchEnd进行unlock 39 | // https://github.com/photonstorm/phaser/commit/f64fc42f3e28c8f02562234ad8d09fd9d49fd24a 40 | if (phaserSound.game.device.iOSVersion > 8) { 41 | input.touch.touchEndCallback = phaserSound.unlock; 42 | } 43 | else { 44 | input.touch.touchStartCallback = phaserSound.unlock; 45 | } 46 | 47 | input.mouse.callbackContext = phaserSound; 48 | input.mouse.mouseDownCallback = phaserSound.unlock; 49 | phaserSound.touchLocked = true; 50 | } 51 | else 52 | { 53 | phaserSound.touchLocked = false; 54 | } 55 | }; 56 | 57 | Object.defineProperties(SoundManager.prototype, { 58 | /** 59 | * 静音设置:ture 为 静音 false为非静音 60 | * @property {boolean} mute 61 | */ 62 | 'mute' : { 63 | get : function() { return this.phaser.mute; }, 64 | set : function(v) { this.phaser.mute = v; } 65 | }, 66 | 67 | /** 68 | * 音量设置 69 | * @property {number} volume 70 | */ 71 | 'volume' : { 72 | get : function() { return this.phaser.volume; }, 73 | set : function(v) { 74 | this.phaser.volume = v; 75 | } 76 | }, 77 | 78 | /** 79 | * 声音模式 -- 使用 web audio 80 | */ 81 | 'usingWebAudio' : { 82 | get : function() { return this.phaser.usingWebAudio; } 83 | }, 84 | 85 | /** 86 | * 声音模式 -- 使用 audio tag 87 | */ 88 | 'usingAudioTag' : { 89 | get : function() { return this.phaser.usingAudioTag; } 90 | }, 91 | 92 | /** 93 | * 是否支持mp3播放 94 | */ 95 | mp3Support: { 96 | get: function() { 97 | return this.game.phaser.device.mp3; 98 | } 99 | }, 100 | 101 | /** 102 | * 是否支持ogg播放 103 | */ 104 | oggSupport: { 105 | get: function() { 106 | return (this.game.phaser.device.ogg || this.game.phaser.device.opus); 107 | } 108 | }, 109 | 110 | /** 111 | * 是否支持web audio播放 112 | */ 113 | webAudioSupport: { 114 | get: function() { 115 | return this.game.phaser.sound.usingWebAudio; 116 | } 117 | } 118 | }); 119 | 120 | /** 121 | * 获取声音对应的声音长度 122 | */ 123 | SoundManager.prototype._getAudioTagDurationInConfig = function(soundPhaser) { 124 | var url = soundPhaser.key; 125 | if (!/\.bin$/i.test(url)) 126 | url = url + '.bin'; 127 | return this._soundDurationMap[url] || soundPhaser._sound.duration; 128 | }; 129 | 130 | /** 131 | * 获取声音文件对应的浏览器支持格式的 url 132 | */ 133 | SoundManager.prototype.tryGetUrl = function(url) { 134 | var newUrl = url; 135 | 136 | if (newUrl.indexOf('.mp3.bin') > 0) { 137 | if (!this.mp3Support) { 138 | newUrl = newUrl.replace('.mp3.bin', '.ogg.bin'); 139 | } 140 | } 141 | else if (newUrl.indexOf('.ogg.bin') > 0) { 142 | if (!this.oggSupport) { 143 | newUrl = newUrl.replace('.ogg.bin', '.mp3.bin'); 144 | } 145 | } 146 | 147 | if (!this.webAudioSupport) { 148 | newUrl = newUrl.replace('.bin', ''); 149 | } 150 | 151 | // 返回结果 152 | return newUrl; 153 | }; 154 | -------------------------------------------------------------------------------- /src/loader/ExcelSheet.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenqx 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 表格类数据 8 | * @class qc.ExcelSheet 9 | * @constructor 10 | * @internal 11 | */ 12 | var ExcelSheet = qc.ExcelSheet = function(cols, rows, primaryKey) { 13 | // 保存相关信息 14 | this._cols = cols || []; 15 | this._rows = rows || []; 16 | 17 | // 普通索引数据 18 | this._indexes = {}; 19 | this._primaryKey = primaryKey; 20 | this._buildPrimaryIndex(); 21 | }; 22 | ExcelSheet.prototype.constructor = ExcelSheet; 23 | 24 | Object.defineProperties(ExcelSheet.prototype, { 25 | /** 26 | * @property {[string]} columns - 获取所有的列名 27 | * @readonly 28 | */ 29 | columns : { 30 | get : function() { return this._cols; } 31 | }, 32 | 33 | /** 34 | * @property {[object]} rows - 获取所有的行 35 | * @readonly 36 | */ 37 | rows : { 38 | get : function() { return this._rows; } 39 | } 40 | }); 41 | 42 | /** 43 | * 创建主索引数据 44 | * @private 45 | */ 46 | ExcelSheet.prototype._buildPrimaryIndex = function() { 47 | this.addSortIndex('primary', this._primaryKey); 48 | }; 49 | 50 | /** 51 | * 添加一个索引数据 52 | * @param name {string} - 索引的别名 53 | * @param keys {...string} - 行排序比较的列顺序,未指明的按原有顺序 54 | * @return {qc.ExcelSortSheetIndex} 55 | */ 56 | ExcelSheet.prototype.addSortIndex = function(name) { 57 | var self = this; 58 | var keys = Array.prototype.slice.call(arguments,1); 59 | var index; 60 | if (Array.isArray(keys[0])) { 61 | index = new qc.ExcelSortSheetIndex(this, keys[0]); 62 | } 63 | else { 64 | index = new qc.ExcelSortSheetIndex(this, keys); 65 | } 66 | this._indexes[name] = index; 67 | return index; 68 | }; 69 | 70 | /** 71 | * 使用指定列名创建一个hash索引,创建后,可以直接通过值获取数据 72 | * @param name {string} - 索引的别名 73 | * @param columnName {string} - 需要作为hash键值的列名 74 | * @param unique {boolean} - 键值是否唯一 75 | * @return {qc.ExcelHashSheetIndex} 76 | */ 77 | ExcelSheet.prototype.addHashIndex = function(name, columnName, unique) { 78 | var index = new qc.ExcelHashSheetIndex(this, columnName, unique === undefined || unique); 79 | this._indexes[name] = index; 80 | return index; 81 | }; 82 | 83 | /** 84 | * 获取一个已经设定好的索引 85 | * @param name {string} - 索引别名 86 | * @return {qc.ExcelSortSheetIndex | qc.ExcelHashSheetIndex} 87 | */ 88 | ExcelSheet.prototype.getIndex = function(name) { 89 | return this._indexes[name]; 90 | }; 91 | 92 | /** 93 | * 获取主索引,默认为第一列的索引 94 | * @returns {qc.ExcelSortSheetIndex} 95 | */ 96 | ExcelSheet.prototype.getPrimary = function() { 97 | return this.getIndex('primary'); 98 | }; 99 | 100 | /** 101 | * 遍历查找满足条件的第一个数据 102 | * @param func {function} - 需要查找的条件 103 | * @return {number} - 找到的行号 104 | * @private 105 | */ 106 | ExcelSheet.prototype.find = function(func) { 107 | var rows = this._rows; 108 | var len = rows.length; 109 | var i = -1; 110 | while (++i < len) { 111 | if (func(rows[i])) { 112 | return i; 113 | } 114 | } 115 | return -1; 116 | }; 117 | 118 | /** 119 | * 遍历查找满足条件的最后一个数据 120 | * @param func {function} - 需要查找的条件 121 | * @return {number} - 找到的行号 122 | * @private 123 | */ 124 | ExcelSheet.prototype.findLast = function(func) { 125 | var rows = this._rows; 126 | var i = rows.length; 127 | while (i-- > 0) { 128 | if (func(rows[i])) { 129 | return i; 130 | } 131 | } 132 | return -1; 133 | }; 134 | 135 | /** 136 | * 遍历查找所有满足条件的数据 137 | * @param func {function} - 需要查找的条件 138 | * @return {[number]} - 找到的行号 139 | * @private 140 | */ 141 | ExcelSheet.prototype.matches = function(func) { 142 | var rows = this._rows; 143 | var len = rows.length; 144 | var i = -1; 145 | var ret = []; 146 | while (++i < len) { 147 | if (func(rows[i])) { 148 | ret.push(i); 149 | } 150 | } 151 | return ret; 152 | }; 153 | 154 | /** 155 | * 将一列的数据转化为日期类型 156 | * @param column {string} - 列名 157 | */ 158 | ExcelSheet.prototype.parseColumnToData = function(column) { 159 | var rows = this._rows; 160 | var len = rows.length; 161 | var i = -1; 162 | var ret = []; 163 | while (++i < len) { 164 | if (column in rows[i]) { 165 | rows[i][column] = ExcelAsset.parseToDate(rows[i][column]); 166 | } 167 | } 168 | return ret; 169 | }; -------------------------------------------------------------------------------- /src/core/Debug.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 调试接口的支持 8 | * 9 | * @class qc.Debug 10 | * @constructor 11 | * @internal 12 | */ 13 | var Debug = qc.Debug = function(game) { 14 | var self = this; 15 | self._game = game; 16 | 17 | /** 18 | * @property {boolean} on - 当前是否开启debug模式 19 | * @default false 20 | */ 21 | self.on = false; 22 | 23 | /** 24 | * @property {number} animation - 动作驱动的耗时 25 | */ 26 | self.animation = 0; 27 | 28 | /** 29 | * 帧调度的耗时分布 30 | * @type {number} 31 | */ 32 | self.total = 0; 33 | self.logic = 0; 34 | self.render = 0; 35 | self.preUpdate = 0; 36 | self.update = 0; 37 | self.postUpdate = 0; 38 | 39 | // 远程调试分配的 clientId 40 | self.clientId = 0; 41 | }; 42 | 43 | Debug.prototype = {}; 44 | Debug.prototype.constructor = Debug; 45 | 46 | Object.defineProperties(Debug.prototype, { 47 | /** 48 | * @property {qc.Game} game - 游戏实例的引用 49 | * @readonly 50 | */ 51 | game : { 52 | get : function() { return this._game; } 53 | }, 54 | 55 | /** 56 | * @property {boolean} on - 调试模式是否开启 57 | */ 58 | on : { 59 | get: function() { return this._on || false; }, 60 | set: function(v) { 61 | this._on = v; 62 | if (v) { 63 | // debug模式下开启trace功能 64 | this.game.log.enableTrace = true; 65 | } 66 | } 67 | }, 68 | 69 | /** 70 | * @property {string} remoteLogUrl - 是否开启 poll 交互指令 71 | */ 72 | remoteLogUrl : { 73 | set : function(v) { 74 | if (this.pollTimer) 75 | { 76 | this.game.timer.remove(this.pollTimer); 77 | this.pollTimer = null; 78 | } 79 | 80 | if (typeof(v) !== 'string') 81 | return; 82 | 83 | var self = this; 84 | this.pollTimer = this.game.timer.loop(1000, function(game){ 85 | if (self.isPolling) 86 | return; 87 | 88 | var str = ':queryCmd:' + self.clientId; 89 | try { 90 | self.isPolling = true; 91 | qc.AssetUtil.post(game.remoteLogUrl + '/remoteLog', str, function(res){ 92 | self.isPolling = false; 93 | 94 | if (res === '200 OK') 95 | return; 96 | 97 | var match = res.match(/^id:(.*)/); 98 | if (match) 99 | { 100 | self.clientId = match[1]; 101 | document.title = '(' + match[1] + ')' + document.title; 102 | return; 103 | } 104 | 105 | var cmdList; 106 | try { 107 | cmdList = JSON.parse(res); 108 | } 109 | catch (e) 110 | { 111 | cmdList = []; 112 | } 113 | for (var i = 0; i < cmdList.length; i++) 114 | { 115 | try { 116 | var ret; 117 | if (!window.__wx) 118 | ret = eval(cmdList[i]); 119 | else { 120 | ret = qc.Util.formatString.apply(null, ["{0}", cmdList[i]]); 121 | } 122 | game.log.remoteReply(ret); 123 | } 124 | catch(e) 125 | { 126 | game.log.remoteReply(e.stack); 127 | } 128 | } 129 | }, function(xhr) { 130 | console.log('queryCmd post error.'); 131 | self.isPolling = false; 132 | }); 133 | } 134 | catch(e) 135 | { 136 | self.isPolling = false; 137 | } 138 | }, null, this.game); 139 | } 140 | } 141 | }); 142 | -------------------------------------------------------------------------------- /src/core/Camera.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 相机 8 | * 9 | * @class qc.Camera 10 | * @constructor 11 | * @internal 12 | */ 13 | var Camera = qc.Camera = function(phaser) { 14 | this.phaser = phaser; 15 | phaser._qc = this; 16 | 17 | // 该参数Phaser的默认值为true,会导致相机偏移自动取整, 18 | // 意义不大且会影响编辑工具滚轮缩放,因此默认将其关闭为false。 19 | phaser.roundPx = false; 20 | } 21 | Camera.prototype = {}; 22 | Camera.prototype.constructor = Camera; 23 | 24 | Object.defineProperties(Camera.prototype, { 25 | /** 26 | * @property {qc.Game} game 27 | * @readonly 28 | */ 29 | 'game' : { 30 | get : function() { return this.phaser.game._qc; } 31 | }, 32 | 33 | /** 34 | * @prooperty {qc.World} world 35 | * @readonly 36 | */ 37 | 'world' : { 38 | get : function() { return this.phaser.world._qc; } 39 | }, 40 | 41 | /** 42 | * @property {number} id - 相机标识(以后多相机可能会用到) 43 | * @readonly 44 | */ 45 | 'id' : { 46 | get : function() { return this.phaser.id; } 47 | }, 48 | 49 | /** 50 | * @property {qc.Rectangle} view - 相机的视野 51 | * @readonly 52 | */ 53 | 'view' : { 54 | get : function() { return this.phaser.view; } 55 | }, 56 | 57 | /** 58 | * @property {qc.Point} postion - 设置相机的位置 59 | */ 60 | 'position' : { 61 | get : function() { return this.phaser.position; }, 62 | set : function(v) { this.phaser.position = v; } 63 | }, 64 | 65 | /** 66 | * @property {qc.Point} size - 设置相机的视野大小 67 | */ 68 | 'size' : { 69 | get : function() { return new qc.Point(this.view.width, this.view.height); }, 70 | set : function(v) { this.setSize(v.x, v.y); } 71 | }, 72 | 73 | /** 74 | * @property {number} x - 相机的X坐标 75 | */ 76 | 'x' : { 77 | get : function() { return this.phaser.x; }, 78 | set : function(v) { this.phaser.x = v; } 79 | }, 80 | 81 | /** 82 | * @property {number} y - 相机的Y坐标 83 | */ 84 | 'y' : { 85 | get : function() { return this.phaser.y; }, 86 | set : function(v) { this.phaser.y = v; } 87 | }, 88 | 89 | /** 90 | * @property {number} width - 相机的视野宽度 91 | */ 92 | 'width' : { 93 | get : function() { return this.phaser.width; }, 94 | set : function(v) { this.phaser.width = v; } 95 | }, 96 | 97 | /** 98 | * @property {number} height - 相机的视野高度 99 | */ 100 | 'height' : { 101 | get : function() { return this.phaser.height; }, 102 | set : function(v) { this.phaser.height = v; } 103 | }, 104 | 105 | /** 106 | * @property {qc.Rectangle} bounds 107 | */ 108 | 'bounds' : { 109 | get : function() { return this.phaser.bounds; }, 110 | set : function(v) { this.phaser.bounds = v; } 111 | }, 112 | 113 | /** 114 | * @property {boolean} visible - 相机是否可见 115 | */ 116 | 'visible' : { 117 | get : function() { return this.phaser.visible; }, 118 | set : function(v) { this.phaser.visible = v; } 119 | }, 120 | 121 | /** 122 | * @property {qc.Node} target - 相机跟踪的目标节点 123 | * @readonly 124 | */ 125 | 'target' : { 126 | get : function() { return this.phaser.target; } 127 | } 128 | }); 129 | 130 | /** 131 | * 相机跟随目标的方式 132 | * @constant 133 | * @type {number} 134 | */ 135 | Camera.FOLLOW_LOCKON = Phaser.Camera.FOLLOW_LOCKON; 136 | Camera.FOLLOW_PLATFORMER = Phaser.Camera.FOLLOW_PLATFORMER; 137 | Camera.FOLLOW_TOPDOWN = Phaser.Camera.FOLLOW_TOPDOWN; 138 | Camera.FOLLOW_TOPDOWN_TIGHT = Phaser.Camera.FOLLOW_TOPDOWN_TIGHT; 139 | 140 | /** 141 | * 跟随目标 142 | * 143 | * @method qc.Camera#follow 144 | * @param {qc.Node} target - 如果设置为null,则停止跟随 145 | * @param {number} [style] - 跟随目标的方式 146 | */ 147 | Camera.prototype.follow = function(target, style) { 148 | if (target === null) 149 | this.phaser.unfollow(); 150 | else 151 | this.phaser.follow(target, style); 152 | } 153 | 154 | /** 155 | * 相机聚焦到某个点 156 | * @method qc.Camera#focusOn 157 | * @param {number} x 158 | * @param {number} y 159 | */ 160 | Camera.prototype.focusOn = function(x, y) { 161 | this.phaser.focusOnXY(x, y); 162 | } 163 | 164 | /** 165 | * 重置相机的位置、不跟随等 166 | * @method qc.Camera#reset 167 | */ 168 | Camera.prototype.reset = function() { 169 | this.phaser.reset(); 170 | } -------------------------------------------------------------------------------- /src/action/LinearProp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenx 3 | * @date 2015.1.2 4 | * copyright 2015 Qcplay All Rights Reserved. 5 | * 6 | * 线性渐变类型的 action 属性处理类 7 | */ 8 | 9 | var LinearProp = qc.LinearProp = function(action, path, propertyId) { 10 | 11 | var self = this; 12 | qc.KeyProp.call(self, action, path, propertyId); 13 | }; 14 | LinearProp.prototype = Object.create(qc.KeyProp.prototype); 15 | LinearProp.prototype.constructor = LinearProp; 16 | 17 | // 计算两点间的线性插值 18 | LinearProp.prototype.calcValue = function(from, to, factor) { 19 | return from + factor * (to - from); 20 | } 21 | 22 | // 取得指定时间对应的值 23 | LinearProp.prototype.getValue = function(attrib, time) { 24 | var prop = this.propMap[attrib]; 25 | if (prop[1].length === 0) 26 | return null; 27 | 28 | if (time <= prop[1][0][0]) 29 | return prop[1][0][1]; 30 | 31 | for (var i = 0; i < prop[1].length; i++) 32 | { 33 | if (prop[1][i][0] < time) 34 | continue; 35 | 36 | i = i > 0 ? i - 1 : 0; 37 | var factor = (time - prop[1][i][0]) / (prop[1][i+1][0] - prop[1][i][0]); 38 | return this.calcValue(prop[1][i][1], prop[1][i+1][1], factor); 39 | } 40 | 41 | return prop[1][prop[1].length - 1][1]; 42 | } 43 | 44 | // 更新目标对象属性值 45 | LinearProp.prototype.updateAttrib = function(target, attrib, value, attribArray) { 46 | if (!attribArray) 47 | target[attrib] = value; 48 | else 49 | { 50 | var len = attribArray.length; 51 | if (len === 2 && target[attribArray[0]]) 52 | target[attribArray[0]][attribArray[1]] = value; 53 | else if (len > 2) 54 | { 55 | var o = target; 56 | for (var i = 0; i < len - 1; i++) 57 | { 58 | o = o[attribArray[i]]; 59 | if (!o) 60 | break; 61 | } 62 | if (o) 63 | o[attribArray[len - 1]] = value; 64 | } 65 | } 66 | } 67 | 68 | // 帧调度 69 | LinearProp.prototype.update = function(target, elapsedTime, isBegin, inEditor, forceUpdate) { 70 | if (isBegin) 71 | this.keyIndexMap = {}; 72 | 73 | for (var attrib in this.propMap) 74 | { 75 | var keyIndex = this.keyIndexMap[attrib] || 0; 76 | var prop = this.propMap[attrib]; 77 | if (prop[1].length === 0) 78 | continue; 79 | 80 | if (keyIndex >= prop[1].length) 81 | { 82 | this.keyIndexMap[attrib] = prop[1].length - 1; 83 | keyIndex = prop[1].length - 1; 84 | } 85 | 86 | if (prop[1][keyIndex][0] <= elapsedTime) 87 | { 88 | // 当前帧向后查找 89 | for (var i = keyIndex; i < prop[1].length; i++) 90 | { 91 | if (i === prop[1].length - 1) 92 | { 93 | // 最后一帧 94 | if (i !== keyIndex) 95 | { 96 | this.updateAttrib(target, attrib, prop[1][i][1], prop[2]); 97 | this.keyIndexMap[attrib] = i; 98 | } 99 | } 100 | else if (prop[1][i][0] <= elapsedTime && prop[1][i+1][0] > elapsedTime) 101 | { 102 | // 当前时间在第 i 和 第 i + 1 帧之间,线性取值 103 | var factor = (elapsedTime - prop[1][i][0]) / (prop[1][i+1][0] - prop[1][i][0]); 104 | if (prop[1][i][1] && prop[1][i+1][1]) 105 | { 106 | var value = this.calcValue(prop[1][i][1], prop[1][i+1][1], factor); 107 | this.updateAttrib(target, attrib, value, prop[2]); 108 | } 109 | this.keyIndexMap[attrib] = i; 110 | break; 111 | } 112 | } 113 | } 114 | else 115 | { 116 | if (prop[1][0][0] > elapsedTime) 117 | { 118 | this.keyIndexMap[attrib] = 0; 119 | continue; 120 | } 121 | 122 | // 从头到当前帧进行查找 123 | for (var i = 0; i < keyIndex; i++) 124 | { 125 | if (prop[1][i][0] <= elapsedTime && prop[1][i+1][0] > elapsedTime) 126 | { 127 | // 当前时间在第 i 和 第 i + 1 帧之间,线性取值 128 | var factor = (elapsedTime - prop[1][i][0]) / (prop[1][i+1][0] - prop[1][i][0]); 129 | if (prop[1][i][1] && prop[1][i+1][1]) 130 | { 131 | var value = this.calcValue(prop[1][i][1], prop[1][i+1][1], factor); 132 | this.updateAttrib(target, attrib, value, prop[2]); 133 | } 134 | this.keyIndexMap[attrib] = i; 135 | break; 136 | } 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/components/FilterGroup.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by qcplay on 7/8/15. 3 | */ 4 | 5 | /** 6 | * 着色器支持管理类 7 | * 用来控制值节点的着色器操作 8 | */ 9 | 10 | var FilterGroup = defineBehaviour('qc.FilterGroup', qc.Behaviour, function() { 11 | /** 12 | * @property {[qc.Filter]} _filters - 当前使用的着色器 13 | * @private 14 | */ 15 | this._filters = []; 16 | }, { 17 | filters : Serializer.FILTERS, 18 | inherited : Serializer.BOOLEAN 19 | }); 20 | 21 | // 菜单上的显示 22 | FilterGroup.__menu = 'UI/FilterGroup'; 23 | 24 | Object.defineProperties(FilterGroup.prototype,{ 25 | /** 26 | * @property {qc.Filter} filters - 当前使用的所有着色器 27 | */ 28 | filters : { 29 | get : function() { return this._filters; }, 30 | set : function(v) { 31 | this._filters = v; 32 | this.refresh(); 33 | } 34 | }, 35 | 36 | /** 37 | * @property {boolean} inherited - 是否被子节点继承 38 | */ 39 | inherited : { 40 | get : function() { 41 | return !(this.gameObject && this.gameObject.filterSelf); 42 | }, 43 | set : function(v) { 44 | this.gameObject && (this.gameObject.filterSelf = !v); 45 | } 46 | } 47 | }); 48 | 49 | /** 50 | * 禁用 51 | */ 52 | FilterGroup.prototype.onDisable = function() { 53 | if (!this.gameObject || this.gameObject._destroy) 54 | return; 55 | this.refresh(); 56 | }; 57 | 58 | /** 59 | * 启用 60 | */ 61 | FilterGroup.prototype.onEnable = function() { 62 | if (!this.gameObject || this.gameObject._destroy) 63 | return; 64 | this.refresh(); 65 | }; 66 | 67 | /** 68 | * 销毁 69 | */ 70 | FilterGroup.prototype.onDestroy = function() { 71 | if (!this.gameObject || this.gameObject._destroy) 72 | return; 73 | this.gameObject.phaser && (this.gameObject.phaser.filters = null); 74 | }; 75 | 76 | /** 77 | * 刷新当前着色器状态 78 | */ 79 | FilterGroup.prototype.refresh = function() { 80 | if (!this.gameObject || this.gameObject._destroy) { 81 | return; 82 | } 83 | if (!this.enable) { 84 | this.gameObject.phaser.filters = null; 85 | } 86 | else if (this.enable) { 87 | this.gameObject.phaser.filters = this.filters && this.filters.length > 0 ? this.filters : null; 88 | } 89 | }; 90 | 91 | /** 92 | * 根据类型查找着色器 93 | * @param cls {string|qc.Filter} - 需要查找的着色器类名 94 | * @return {[qc.Filter]} 95 | */ 96 | FilterGroup.prototype.findFilter = function(cls) { 97 | if (typeof cls === 'string') 98 | cls = qc.Util.findClass(cls); 99 | var filters = []; 100 | for (var c in this.filters) { 101 | if (this.filters[c] instanceof cls) { 102 | filters.push(this.filters[c]); 103 | } 104 | } 105 | return filters; 106 | }; 107 | 108 | /** 109 | * 移除一个指定位置的着色器 110 | * @param filter {number} 111 | */ 112 | FilterGroup.prototype.removeFilterAt = function(idx) { 113 | if (idx < 0 || idx >= this.filters.length) { 114 | return; 115 | } 116 | var filter = this.filters.splice(idx, 1); 117 | this.refresh(); 118 | return filter; 119 | }; 120 | 121 | /** 122 | * 根据类型或者对象删除着色器 123 | * @param obj {string|qc.Filter|object} - 需要删除的着色器 124 | */ 125 | FilterGroup.prototype.removeFilter = function(obj) { 126 | if (typeof obj === 'string') { 127 | obj = qc.Util.findClass(obj); 128 | } 129 | var remove = []; 130 | var idx = this.filters.length; 131 | if (typeof obj === 'function') { 132 | while (idx-- > 0) { 133 | if (this.filters[idx] instanceof obj) { 134 | remove.push(this.filters.splice(idx, 1)); 135 | } 136 | } 137 | } 138 | else { 139 | while (idx-- > 0) { 140 | if (this.filters[idx] === obj) { 141 | remove.push(this.filters.splice(idx, 1)); 142 | } 143 | } 144 | } 145 | this.refresh(); 146 | return remove; 147 | }; 148 | 149 | /** 150 | * 添加一个着色器 151 | * @param obj {string|qc.Filter|object} - 需要添加着色器类或者对象 152 | * @param idx {null|number} - 需要添加到的位置 153 | */ 154 | FilterGroup.prototype.addFilter = function(obj, idx) { 155 | if (typeof obj === 'string') { 156 | obj = qc.Util.findClass(obj); 157 | if (typeof obj !== 'function') { 158 | return null; 159 | } 160 | } 161 | 162 | if (typeof obj === 'function') { 163 | obj = new obj(this.game); 164 | } 165 | else { 166 | var idx = this.filters.length; 167 | while (idx-- > 0) { 168 | if (this.filters[idx] === obj) { 169 | // 已存在该对象 170 | return; 171 | } 172 | } 173 | } 174 | 175 | if (isNaN(idx) || idx < 0 || idx > this.filters.length) { 176 | this.filters.push(obj); 177 | } 178 | else { 179 | this.filters.splice(idx, 0, obj); 180 | } 181 | 182 | this.refresh(); 183 | return obj; 184 | }; -------------------------------------------------------------------------------- /src/core/node/NodeDisplay.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenqx 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | /** 6 | * 拓展 Node 的绘制属性 7 | */ 8 | /** 9 | * 生成一张缓存图片 10 | * @param resolution {Number} - 生成的截图的解析度 11 | * @param scaleMode {Number} - {{#crossLink "qc/scaleModes:property"}}qc.scaleModes{{/crossLink}} 12 | * @param offX {Number} - 生成截图对于实际绘制区域的 x 轴偏移 13 | * @param offY {Number} - 生成截图对于实际绘制区域的 y 轴偏移 14 | * @param width {Number} - 生成截图的宽度 15 | * @param height {Number} - 生成截图的高度 16 | * @return {qc.RenderTexture} 17 | */ 18 | Node.prototype.generateTexture = function(resolution, scaleMode, offX, offY, width, height) { 19 | if (!this.phaser) { 20 | return new qc.RenderTexture(0, 0, renderer, scaleMode, resolution); 21 | } 22 | var bounds = this.localBounds; 23 | bounds.x += offX || 0; 24 | bounds.y += offY || 0; 25 | isNaN(width) || (bounds.width = width); 26 | isNaN(height) || (bounds.height = height); 27 | 28 | var renderTexture = new qc.RenderTexture(bounds.width | 0, bounds.height | 0, null, scaleMode, resolution); 29 | 30 | PIXI.DisplayObject._tempMatrix.tx = -bounds.x; 31 | PIXI.DisplayObject._tempMatrix.ty = -bounds.y; 32 | 33 | renderTexture.render(this.phaser, PIXI.DisplayObject._tempMatrix); 34 | 35 | return renderTexture; 36 | }; 37 | 38 | // 用于渲染用的临时矩阵 39 | Node._snapTempMatrix = new PIXI.Matrix(); 40 | 41 | /** 42 | * 生成一张缓存的 RenderTexture 43 | * @param srcBounds {qc.Rectangle} - 绘制源的绘制区域,默认当前 Node 自身在屏幕中的最终宽高 44 | * @param dstWidth {number} - 绘制目标的宽,默认为 srcBound 的宽 45 | * @param dstHeight {number} - 绘制目标的高,默认为 srcBound 的高 46 | * @param resolution {Number} - 生成的截图的解析度,默认选择当前游戏的 resolution 47 | * @return {qc.RenderTexture} 48 | */ 49 | Node.prototype._snapshotAsRenderTexture = function(srcBounds, dstWidth, dstHeight, resolution) { 50 | // 无效的绘制参数 51 | if (!this.phaser) { 52 | return new qc.RenderTexture(0, 0); 53 | } 54 | 55 | // 计算源的绘制区域 56 | var bounds = srcBounds; 57 | var worldScale = this.getWorldScale(); 58 | 59 | if (!bounds) { 60 | bounds = qc.Bounds.getBounds(this); 61 | } 62 | 63 | dstWidth = dstWidth || (bounds.width * worldScale.x); 64 | dstHeight = dstHeight || (bounds.height * worldScale.y); 65 | 66 | var drawScaleX = dstWidth / bounds.width; 67 | var drawScaleY = dstHeight / bounds.height; 68 | 69 | resolution = resolution || this.game.resolution; 70 | 71 | // 目标节点绘制矩阵(只保留缩放,加入偏移,还需要考虑目标画布大小导致的缩放) 72 | Node._snapTempMatrix.a = drawScaleX; 73 | Node._snapTempMatrix.d = drawScaleY; 74 | Node._snapTempMatrix.tx = -bounds.x * drawScaleX; 75 | Node._snapTempMatrix.ty = -bounds.y * drawScaleY; 76 | 77 | var phaserGame = this.game.phaser; 78 | 79 | var renderTexture = new qc.RenderTexture(1, 1, phaserGame.renderer, phaserGame.scale.scaleMode, resolution); 80 | renderTexture.resize(dstWidth, dstHeight, true); 81 | 82 | // 绘制工作开始吧 83 | renderTexture.render(this.phaser, Node._snapTempMatrix); 84 | 85 | return renderTexture; 86 | }; 87 | 88 | /** 89 | * 生成一张缓存的 image 对象 90 | * @param srcBounds {qc.Rectangle} - 绘制源的绘制区域,默认当前 Node 自身在屏幕中的最终宽高 91 | * @param dstWidth {number} - 绘制目标的宽,默认为 srcBound 的宽 92 | * @param dstHeight {number} - 绘制目标的高,默认为 srcBound 的高 93 | * @param resolution {Number} - 生成的截图的解析度,默认选择当前游戏的 resolution 94 | * @param loadedCallback {function} - Image 成功 loaded 后的回调 95 | * @return {qc.RenderTexture} 96 | */ 97 | Node.prototype.snapshotAsImage = function(srcBounds, dstWidth, dstHeight, resolution, loadedCallback) { 98 | var renderTexture = this._snapshotAsRenderTexture(srcBounds, dstWidth, dstHeight, resolution); 99 | var base64 = renderTexture.getBase64(); 100 | 101 | // 可以删除 102 | renderTexture.destroy(true); 103 | 104 | // 生成贴图对象 105 | var img = new Image(); 106 | img.src = base64; 107 | 108 | if (loadedCallback) { 109 | // 关注图片生成 110 | img.onload = function() { 111 | loadedCallback(img); 112 | }; 113 | } 114 | 115 | return img; 116 | }; 117 | 118 | /** 119 | * 生成一张缓存的 atlas 对象,可以直接作为 UIImage 的使用 120 | * @param key {qc.Rectangle} - atlas key,后续可以用 assets.find 来获取到资源 121 | * @param srcBounds {qc.Rectangle} - 绘制源的绘制区域,默认当前 Node 自身在屏幕中的最终宽高 122 | * @param dstWidth {number} - 绘制目标的宽,默认为 srcBound 的宽 123 | * @param dstHeight {number} - 绘制目标的高,默认为 srcBound 的高 124 | * @param resolution {Number} - 生成的截图的解析度,默认选择当前游戏的 resolution 125 | * @return {qc.RenderTexture} 126 | */ 127 | Node.prototype.snapshotAsAtlas = function(key, srcBounds, dstWidth, dstHeight, resolution) { 128 | // 获取 render texture 129 | var renderTexture = this._snapshotAsRenderTexture(srcBounds, dstWidth, dstHeight, resolution); 130 | 131 | // 需要删除之前缓存中记录的 key 132 | var cache = this.game.assets._cache; 133 | if (cache.checkImageKey(key)) cache.removeImage(key, false); 134 | 135 | // 加入到游戏中 136 | var atlas = qc.AssetUtil.addAtlasFromImage(this.game, key, key, renderTexture.getCanvas()); 137 | 138 | return atlas; 139 | }; 140 | -------------------------------------------------------------------------------- /src/gameobjects/Toggle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author weism 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 开关对象 8 | * 9 | * @class qc.Toggle 10 | * @param {qc.Game} game 11 | * @constructor 12 | * @internal 13 | */ 14 | var Toggle = qc.Toggle = function(game, parent, uuid) { 15 | qc.Node.call(this, new Phaser.Group(game.phaser, null), parent, uuid); 16 | 17 | // 初始化默认的名字 18 | this.name = 'Toggle'; 19 | this.interactive = true; 20 | 21 | /** 22 | * @property {qc.Signal} onStateChange - 状态发生变化的事件 23 | */ 24 | this.onStateChange = new qc.Signal(); 25 | 26 | /** 27 | * @property {qc.Signal} onValueChange - 开关选中状态变化产生的事件 28 | */ 29 | this.onValueChange = new qc.Signal(); 30 | 31 | /** 32 | * @property {qc.Signal} canValueChange - 是否允许这次开关状态的改变 33 | */ 34 | this.canValueChange = new qc.Signal(); 35 | 36 | var restore = uuid !== undefined; 37 | if (restore !== true) { 38 | /** 39 | * @property {qc.UIImage} background - 背景图片 40 | * @readonly 41 | */ 42 | this.background = game.add.image(this); 43 | this.background.name = 'Background'; 44 | this.background.interactive = false; 45 | this.background.width = 80; 46 | this.background.height = 80; 47 | 48 | /** 49 | * @property {qc.UIImange} checkMark - 选中标记图片 50 | * @readonly 51 | */ 52 | this.checkMark = game.add.image(this.background); 53 | this.checkMark.name = 'CheckMark'; 54 | this.checkMark.interactive = false; 55 | 56 | /** 57 | * @property {qc.Text} text - 挂载在开关上的文本组件 58 | * @readonly 59 | */ 60 | this.text = game.add.text(this); 61 | this.text.text = 'Button'; 62 | this.text.name = 'Text'; 63 | this.text.interactive = false; 64 | 65 | // 我的初始状态为默认状态 66 | this.on = false; 67 | this.state = qc.UIState.NORMAL; 68 | 69 | // 大小应该等于“我”的大小,位置居中 70 | this.checkMark.pivotX = 0.5; 71 | this.checkMark.pivotY = 0.5; 72 | this.checkMark.setAnchor(new qc.Point(0.5, 0.5), new qc.Point(0.5, 0.5)); 73 | this.checkMark.anchoredX = 0; 74 | this.checkMark.anchoredY = 0; 75 | this.checkMark.width = 50; 76 | this.checkMark.height = 50; 77 | this.text.x = this.background.width + 5; 78 | this.text.height = this.background.height; 79 | 80 | // 挂载交互效果脚本 81 | var behaviour = this.addScript('qc.TransitionBehaviour'); 82 | behaviour.target = this.background; 83 | behaviour.transition = qc.Transition.TEXTURE_SWAP; 84 | } 85 | 86 | // 关注按钮按下和松开的回调,切换按钮状态 87 | var self = this; 88 | this.onDown.add(function() { 89 | if (self.state !== qc.UIState.DISABLED) 90 | self.state = qc.UIState.PRESSED; 91 | }); 92 | this.onUp.add(function() { 93 | if (self.state === qc.UIState.PRESSED) 94 | self.state = qc.UIState.NORMAL; 95 | }); 96 | 97 | // 点击时切换开关状态 98 | this.onClick.add(function() { 99 | self.on = !self.on; 100 | self.checkMark.visible = self.on; 101 | }); 102 | }; 103 | Toggle.prototype = Object.create(qc.Node.prototype); 104 | Toggle.prototype.constructor = Toggle; 105 | 106 | Object.defineProperties(Toggle.prototype, { 107 | /** 108 | * @property {boolean} on - 开关的开启状态 109 | */ 110 | on : { 111 | get : function() { return !!this._on; }, 112 | set : function(v) { 113 | var old = this.on; 114 | 115 | // 是否允许这次修改 116 | var option = {}; 117 | this.canValueChange.dispatch(this, v, old, option); 118 | if (option.ignore) return; 119 | 120 | this._on = v; 121 | this.checkMark.visible = v; 122 | if (old !== v) 123 | this.onValueChange.dispatch(this); 124 | } 125 | }, 126 | 127 | /** 128 | * @property {number} state - 开关的状态 129 | */ 130 | state : { 131 | get : function() { return this._state || qc.UIState.NORMAL; }, 132 | set : function(v) { 133 | if (this.state === v) return; 134 | this._state = v; 135 | this.onStateChange.dispatch(); 136 | } 137 | }, 138 | 139 | /** 140 | * @property {string} class - 类名字 141 | * @readonly 142 | * @internal 143 | */ 144 | class : { 145 | get : function() { return 'qc.Toggle' } 146 | } 147 | }); 148 | 149 | /** 150 | * 需要序列化的字段和类型 151 | * 部分有依赖关系的字段需要特殊处理 152 | * @internal 153 | */ 154 | Toggle.prototype.getMeta = function() { 155 | var s = qc.Serializer; 156 | var json = qc.Node.prototype.getMeta.call(this); 157 | 158 | // 增加Button需要序列化的内容 159 | json.background = s.NODE; 160 | json.checkMark = s.NODE; 161 | json.text = s.NODE; 162 | json.on = _CUSTOM_FIELD('on', s.BOOLEAN); 163 | json.state = _CUSTOM_FIELD('state', s.NUMBER); 164 | return json; 165 | } 166 | -------------------------------------------------------------------------------- /src/core/Input/InputEvent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author chenqx 3 | * copyright 2015 Qcplay All Rights Reserved. 4 | */ 5 | 6 | /** 7 | * 基本交互的操作的事件 8 | * @class qc.BaseInputEvent 9 | * @param {qc.Key|qc.Pointer|object} source - 事件产生的源 10 | * @constructor 11 | */ 12 | var BaseInputEvent = qc.BaseInputEvent = function(source) { 13 | /** 14 | * @property {qc.Key|qc.Pointer|object} source - 事件产生的源 15 | */ 16 | this.source = source; 17 | 18 | /** 19 | * @property {boolean} effect 20 | */ 21 | this.effect = true; 22 | }; 23 | BaseInputEvent.prototype = {}; 24 | BaseInputEvent.prototype.constructor = BaseInputEvent; 25 | 26 | /** 27 | * 滚轮滚动事件 28 | * @class qc.WheelEvent 29 | * @param {number} deltaX - 在x轴上滚动的距离 30 | * @param {number} deltaY - 在y轴上滚动的距离 31 | * @constructor 32 | */ 33 | var WheelEvent = qc.WheelEvent = function(deltaX, deltaY) { 34 | // 继承至BaseInputEvent 35 | BaseInputEvent.call(this, {deltaX: deltaX, deltaY: deltaY}); 36 | }; 37 | WheelEvent.prototype = Object.create(BaseInputEvent.prototype); 38 | WheelEvent.prototype.constructor = WheelEvent; 39 | 40 | Object.defineProperties(WheelEvent.prototype, { 41 | /** 42 | * @property {number} deltaX - 获取x轴上滚动的距离 43 | * @readonly 44 | */ 45 | deltaX: { 46 | get: function() { return this.source.deltaX; } 47 | }, 48 | 49 | /** 50 | * @property {number} deltaY - 获取y轴上滚动的距离 51 | * @readonly 52 | */ 53 | deltaY: { 54 | get: function() { return this.source.deltaY; } 55 | } 56 | }); 57 | 58 | /** 59 | * 光标移动事件 60 | * @class qc.CursorMoveEvent 61 | * @param {number} x - 光标移动到的x轴坐标 62 | * @param {number} y - 光标移动到的y轴坐标 63 | * @constructor 64 | */ 65 | var CursorMoveEvent = qc.CursorMoveEvent = function(x, y) { 66 | // 继承至BaseInputEvent 67 | BaseInputEvent.call(this, {x: x, y: y}); 68 | }; 69 | CursorMoveEvent.prototype = Object.create(BaseInputEvent.prototype); 70 | CursorMoveEvent.prototype.constructor = CursorMoveEvent; 71 | 72 | Object.defineProperties(CursorMoveEvent.prototype, { 73 | /** 74 | * @property {number} x - 获取光标的x轴坐标 75 | * @readonly 76 | */ 77 | x: { 78 | get: function() { return this.source.x; } 79 | }, 80 | 81 | /** 82 | * @property {number} y - 获取光标的y轴坐标 83 | * @readonly 84 | */ 85 | y: { 86 | get: function() { return this.source.y; } 87 | } 88 | }); 89 | 90 | /** 91 | * 点击移动事件 92 | * @class qc.PointerEvent 93 | * @param {qc.Pointer} source - 点击事件的源 94 | * @constructor 95 | */ 96 | var PointerEvent = qc.PointerEvent = function(source) { 97 | // 继承至BaseInputEvent 98 | BaseInputEvent.call(this, source); 99 | }; 100 | PointerEvent.prototype = Object.create(BaseInputEvent.prototype); 101 | PointerEvent.prototype.constructor = PointerEvent; 102 | 103 | /** 104 | * 点击事件 105 | */ 106 | var ClickEvent = qc.ClickEvent = function(source) { 107 | // 继承至PointerEvent 108 | PointerEvent.call(this, source); 109 | this.isTap = false; 110 | this.isDoubleTap = false; 111 | this.isDoubleClick = false; 112 | }; 113 | ClickEvent.prototype = Object.create(PointerEvent.prototype); 114 | ClickEvent.prototype.constructor = ClickEvent; 115 | 116 | /** 117 | * 拖拽开始事件 118 | * @class qc.DragDropEvent 119 | * @param {qc.Pointer} source - 产生拖拽的点击事件 120 | * @construct 121 | */ 122 | var DragStartEvent = qc.DragStartEvent = function(source) { 123 | // 继承至PointerEvent 124 | PointerEvent.call(this, source); 125 | 126 | /** 127 | * @property {boolean} started - 是否开始拖拽 128 | */ 129 | this.started = true; 130 | }; 131 | DragStartEvent.prototype = Object.create(PointerEvent.prototype); 132 | DragStartEvent.prototype.constructor = DragStartEvent; 133 | 134 | /** 135 | * 拖拽事件 136 | * @class qc.DragDropEvent 137 | * @param {qc.Pointer} source - 产生拖拽的点击事件 138 | * @construct 139 | */ 140 | var DragEvent = qc.DragEvent = function(source) { 141 | // 继承至PointerEvent 142 | PointerEvent.call(this, source); 143 | }; 144 | DragEvent.prototype = Object.create(PointerEvent.prototype); 145 | DragEvent.prototype.constructor = DragEvent; 146 | 147 | /** 148 | * 拖拽结束的事件 149 | * @class qc.DragEndEvent 150 | * @param {qc.Pointer} source - 产生拖拽的点击事件 151 | * @param {*} result - 拖拽到接收方的处理结果 152 | * @construct 153 | */ 154 | var DragEndEvent = qc.DragEndEvent = function(source, result) { 155 | // 继承至PointerEvent 156 | PointerEvent.call(this, source); 157 | 158 | /** 159 | * @property {*} result - 拖拽处理的结果 160 | */ 161 | this.result = result; 162 | }; 163 | DragEndEvent.prototype = Object.create(PointerEvent.prototype); 164 | DragEndEvent.prototype.constructor = DragEndEvent; 165 | 166 | /** 167 | * 拖拽放下事件 168 | * @class qc.DropEvent 169 | * @param {qc.Pointer} source - 产生拖拽的点击事件 170 | * @param {qc.Node} dragging - 被拖拽的节点 171 | * @construct 172 | */ 173 | var DropEvent = qc.DropEvent = function(source, dragging) { 174 | // 继承至PointerEvent 175 | PointerEvent.call(this, source); 176 | /** 177 | * @property {qc.Node} dragging - 被拖拽的节点 178 | */ 179 | this.dragging = dragging; 180 | 181 | /** 182 | * @property {*} result - 记录拖拽放下的处理结果 183 | */ 184 | this.result = null; 185 | }; 186 | DropEvent.prototype = Object.create(PointerEvent.prototype); 187 | DropEvent.prototype.constructor = DropEvent; --------------------------------------------------------------------------------